aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore7
-rw-r--r--Config.in210
-rw-r--r--Makefile105
-rw-r--r--Makefile.custom22
-rw-r--r--Makefile.flags16
-rw-r--r--README1
-rw-r--r--README.md41
-rw-r--r--applets/.gitignore3
-rw-r--r--applets/applet_tables.c9
-rwxr-xr-xapplets/usage_compressed2
-rw-r--r--archival/ar.c23
-rw-r--r--archival/bbunzip.c2
-rw-r--r--archival/cpio.c6
-rw-r--r--archival/dpkg.c29
-rw-r--r--archival/libarchive/Kbuild.src2
-rw-r--r--archival/libarchive/decompress_gunzip.c6
-rw-r--r--archival/libarchive/get_header_tar.c5
-rw-r--r--archival/libarchive/open_transformer.c7
-rw-r--r--archival/libarchive/unpack_ar_archive.c8
-rw-r--r--archival/libarchive/unsafe_symlink_target.c8
-rw-r--r--archival/rpm.c16
-rw-r--r--archival/tar.c28
-rw-r--r--archival/unzip.c5
-rw-r--r--configs/make32_defconfig1238
-rw-r--r--configs/make64_defconfig1238
-rw-r--r--configs/mingw32_defconfig1256
-rw-r--r--configs/mingw64_defconfig1256
-rw-r--r--configs/mingw64a_defconfig1256
-rw-r--r--configs/mingw64u_defconfig1256
-rw-r--r--console-tools/reset.c16
-rw-r--r--coreutils/dd.c78
-rw-r--r--coreutils/du.c2
-rw-r--r--coreutils/expr.c2
-rw-r--r--coreutils/factor.c4
-rw-r--r--coreutils/id.c20
-rw-r--r--coreutils/ls.c85
-rw-r--r--coreutils/nproc.c17
-rw-r--r--coreutils/od_bloaty.c7
-rw-r--r--coreutils/printf.c68
-rw-r--r--coreutils/shred.c10
-rw-r--r--coreutils/shuf.c2
-rw-r--r--coreutils/sort.c5
-rw-r--r--coreutils/split.c8
-rw-r--r--coreutils/stat.c5
-rw-r--r--coreutils/sum.c4
-rw-r--r--coreutils/test.c4
-rw-r--r--coreutils/timeout.c73
-rw-r--r--debianutils/pipe_progress.c5
-rw-r--r--debianutils/which.c49
-rw-r--r--e2fsprogs/chattr.c58
-rw-r--r--e2fsprogs/e2fs_lib.c79
-rw-r--r--e2fsprogs/e2fs_lib.h17
-rw-r--r--e2fsprogs/lsattr.c45
-rw-r--r--editors/awk.c41
-rw-r--r--editors/diff.c48
-rw-r--r--editors/sed.c21
-rw-r--r--editors/vi.c193
-rw-r--r--examples/mswin-build/README26
-rwxr-xr-xexamples/mswin-build/mkprerelease84
-rwxr-xr-xexamples/mswin-build/mkrelease104
-rw-r--r--findutils/find.c12
-rw-r--r--findutils/xargs.c268
-rw-r--r--include/.gitignore1
-rw-r--r--include/bb_archive.h14
-rw-r--r--include/libbb.h169
-rw-r--r--include/mingw.h671
-rw-r--r--include/platform.h45
-rw-r--r--include/unicode.h19
-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
-rw-r--r--loginutils/su.c1
-rw-r--r--loginutils/suw32.c169
-rw-r--r--miscutils/bbconfig.c1
-rw-r--r--miscutils/bc.c18
-rw-r--r--miscutils/dc.c2
-rw-r--r--miscutils/drop.c220
-rw-r--r--miscutils/iconv.c1771
-rw-r--r--miscutils/inotifyd.c211
-rw-r--r--miscutils/jn.c37
-rw-r--r--miscutils/less.c99
-rw-r--r--miscutils/make.c3382
-rw-r--r--miscutils/man.c31
-rw-r--r--miscutils/time.c51
-rw-r--r--miscutils/ts.c8
-rw-r--r--networking/ftpgetput.c6
-rw-r--r--networking/httpd.c297
-rw-r--r--networking/nc.c12
-rw-r--r--networking/ssl_client.c21
-rw-r--r--networking/tls.c2
-rw-r--r--networking/wget.c53
-rw-r--r--procps/free.c9
-rw-r--r--procps/iostat.c2
-rw-r--r--procps/kill.c2
-rw-r--r--procps/mpstat.c2
-rw-r--r--procps/pgrep.c55
-rw-r--r--procps/ps.c16
-rw-r--r--procps/smemcap.c1
-rw-r--r--procps/watch.c7
-rw-r--r--scripts/Kbuild.include10
-rw-r--r--scripts/Makefile.build17
-rw-r--r--scripts/Makefile.host23
-rw-r--r--scripts/basic/.gitignore3
-rw-r--r--scripts/basic/docproc.c15
-rw-r--r--scripts/basic/fixdep.c67
-rw-r--r--scripts/basic/split-include.c24
-rwxr-xr-xscripts/bloat-o-meter25
-rwxr-xr-xscripts/embedded_scripts6
-rw-r--r--scripts/kconfig/.gitignore1
-rw-r--r--scripts/kconfig/Makefile14
-rw-r--r--scripts/kconfig/conf.c15
-rw-r--r--scripts/kconfig/confdata.c9
-rw-r--r--scripts/kconfig/libcurses/Kbuild.src51
-rw-r--r--scripts/kconfig/libcurses/README.md20
-rw-r--r--scripts/kconfig/libcurses/acs437.h35
-rw-r--r--scripts/kconfig/libcurses/acsuni.h35
-rw-r--r--scripts/kconfig/libcurses/addch.c408
-rw-r--r--scripts/kconfig/libcurses/addstr.c239
-rw-r--r--scripts/kconfig/libcurses/attr.c409
-rw-r--r--scripts/kconfig/libcurses/beep.c74
-rw-r--r--scripts/kconfig/libcurses/bkgd.c226
-rw-r--r--scripts/kconfig/libcurses/border.c414
-rw-r--r--scripts/kconfig/libcurses/clear.c159
-rw-r--r--scripts/kconfig/libcurses/color.c362
-rw-r--r--scripts/kconfig/libcurses/curses.h1440
-rw-r--r--scripts/kconfig/libcurses/curspriv.h133
-rw-r--r--scripts/kconfig/libcurses/getch.c589
-rw-r--r--scripts/kconfig/libcurses/getyx.c142
-rw-r--r--scripts/kconfig/libcurses/inch.c126
-rw-r--r--scripts/kconfig/libcurses/initscr.c431
-rw-r--r--scripts/kconfig/libcurses/inopts.c408
-rw-r--r--scripts/kconfig/libcurses/kernel.c297
-rw-r--r--scripts/kconfig/libcurses/move.c77
-rw-r--r--scripts/kconfig/libcurses/outopts.c260
-rw-r--r--scripts/kconfig/libcurses/overlay.c214
-rw-r--r--scripts/kconfig/libcurses/pad.c274
-rw-r--r--scripts/kconfig/libcurses/pdcclip.c149
-rw-r--r--scripts/kconfig/libcurses/pdcdisp.c329
-rw-r--r--scripts/kconfig/libcurses/pdcgetsc.c42
-rw-r--r--scripts/kconfig/libcurses/pdckbd.c693
-rw-r--r--scripts/kconfig/libcurses/pdcscrn.c686
-rw-r--r--scripts/kconfig/libcurses/pdcsetsc.c130
-rw-r--r--scripts/kconfig/libcurses/pdcutil.c26
-rw-r--r--scripts/kconfig/libcurses/pdcwin.h27
-rw-r--r--scripts/kconfig/libcurses/printw.c129
-rw-r--r--scripts/kconfig/libcurses/refresh.c287
-rw-r--r--scripts/kconfig/libcurses/scroll.c101
-rw-r--r--scripts/kconfig/libcurses/slk.c671
-rw-r--r--scripts/kconfig/libcurses/touch.c208
-rw-r--r--scripts/kconfig/libcurses/window.c637
-rw-r--r--scripts/kconfig/lkc.h6
-rwxr-xr-xscripts/kconfig/lxdialog/check-lxdialog.sh8
-rw-r--r--scripts/kconfig/lxdialog/dialog.h1
-rw-r--r--scripts/kconfig/lxdialog/util.c3
-rw-r--r--scripts/kconfig/mconf.c242
-rw-r--r--scripts/kconfig/symbol.c31
-rw-r--r--scripts/kconfig/zconf.hash.c_shipped60
-rw-r--r--scripts/kconfig/zconf.tab.c_shipped1
-rwxr-xr-xscripts/mk_mingw64u_defconfig38
-rwxr-xr-xscripts/mkconfigs4
-rwxr-xr-xscripts/mkwcwidth169
-rwxr-xr-xscripts/trylink8
-rw-r--r--shell/Kbuild.src1
-rw-r--r--shell/ash.c2789
-rw-r--r--shell/math.h2
-rw-r--r--shell/random.c11
-rw-r--r--shell/random.h3
-rw-r--r--shell/shell_common.c73
-rwxr-xr-xtestsuite/awk.tests14
-rwxr-xr-xtestsuite/busybox.tests19
-rwxr-xr-xtestsuite/diff.tests63
-rwxr-xr-xtestsuite/env.tests71
-rwxr-xr-xtestsuite/make.tests765
-rwxr-xr-xtestsuite/runtest18
-rwxr-xr-xtestsuite/sh.tests118
-rw-r--r--util-linux/getopt.c5
-rw-r--r--util-linux/more.c22
-rw-r--r--util-linux/rev.c4
-rw-r--r--win32/Kbuild34
-rw-r--r--win32/arpa/inet.h0
-rw-r--r--win32/dirent.c106
-rw-r--r--win32/dirent.h20
-rw-r--r--win32/dirname.c287
-rw-r--r--win32/env.c117
-rw-r--r--win32/fnmatch.c525
-rw-r--r--win32/fnmatch.h84
-rw-r--r--win32/fsync.c75
-rw-r--r--win32/glob.c343
-rw-r--r--win32/glob.h89
-rw-r--r--win32/grp.h0
-rw-r--r--win32/inet_pton.c95
-rw-r--r--win32/ioctl.c46
-rw-r--r--win32/isaac.c192
-rw-r--r--win32/lazyload.h27
-rw-r--r--win32/match_class.c7
-rw-r--r--win32/match_class.h11
-rw-r--r--win32/mingw.c2540
-rw-r--r--win32/mntent.c94
-rw-r--r--win32/mntent.h33
-rw-r--r--win32/net.c146
-rw-r--r--win32/net/if.h0
-rw-r--r--win32/netdb.h0
-rw-r--r--win32/netinet/in.h0
-rw-r--r--win32/paths.h0
-rw-r--r--win32/poll.c656
-rw-r--r--win32/poll.h53
-rw-r--r--win32/popen.c316
-rw-r--r--win32/process.c955
-rw-r--r--win32/pwd.h0
-rw-r--r--win32/regcomp.c3936
-rw-r--r--win32/regex.c90
-rw-r--r--win32/regex.h582
-rw-r--r--win32/regex_internal.c1744
-rw-r--r--win32/regex_internal.h810
-rw-r--r--win32/regexec.c4369
-rw-r--r--win32/resources/COPYING_CCBYSA37
-rw-r--r--win32/resources/Kbuild.src29
-rw-r--r--win32/resources/README9
-rw-r--r--win32/resources/app.manifest24
-rw-r--r--win32/resources/aterm.icobin0 -> 15086 bytes
-rw-r--r--win32/resources/dummy.c0
-rw-r--r--win32/resources/resources.rc45
-rw-r--r--win32/resources/sterm.icobin0 -> 15086 bytes
-rw-r--r--win32/resources/utf8.manifest30
-rw-r--r--win32/sched.h1
-rw-r--r--win32/select.c592
-rw-r--r--win32/sh_random.c59
-rw-r--r--win32/statfs.c70
-rw-r--r--win32/strndup.c36
-rw-r--r--win32/strptime.c603
-rw-r--r--win32/strverscmp.c62
-rw-r--r--win32/sys/inotify.h0
-rw-r--r--win32/sys/ioctl.h0
-rw-r--r--win32/sys/mman.h0
-rw-r--r--win32/sys/resource.h11
-rw-r--r--win32/sys/select.h0
-rw-r--r--win32/sys/socket.h0
-rw-r--r--win32/sys/statfs.h22
-rw-r--r--win32/sys/statvfs.h3
-rw-r--r--win32/sys/syscall.h0
-rw-r--r--win32/sys/sysmacros.h0
-rw-r--r--win32/sys/times.h0
-rw-r--r--win32/sys/un.h0
-rw-r--r--win32/sys/utsname.h66
-rw-r--r--win32/sys/wait.h0
-rw-r--r--win32/system.c22
-rw-r--r--win32/termios.c128
-rw-r--r--win32/termios.h31
-rw-r--r--win32/timegm.c133
-rw-r--r--win32/uname.c47
-rw-r--r--win32/winansi.c1608
289 files changed, 56005 insertions, 271 deletions
diff --git a/.gitignore b/.gitignore
index becd9bf6d..9055b745e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,7 +18,9 @@ Config.in
18# Normal output 18# Normal output
19# 19#
20/busybox 20/busybox
21/busybox.exe
21/busybox_old 22/busybox_old
23/busybox_old.exe
22/busybox_unstripped* 24/busybox_unstripped*
23 25
24# 26#
@@ -61,3 +63,8 @@ TAGS
61# user-supplied scripts 63# user-supplied scripts
62# 64#
63/embed 65/embed
66
67#
68# release description for tarball
69#
70.frp_describe
diff --git a/Config.in b/Config.in
index ad0cd1e26..f6159b30b 100644
--- a/Config.in
+++ b/Config.in
@@ -9,6 +9,20 @@ config HAVE_DOT_CONFIG
9 bool 9 bool
10 default y 10 default y
11 11
12choice
13 prompt "Target platform"
14 default PLATFORM_POSIX
15 help
16 Target platform you are building busybox for
17
18config PLATFORM_POSIX
19 bool "POSIX"
20
21config PLATFORM_MINGW32
22 bool "MS Windows (MinGW port)"
23
24endchoice
25
12menu "Settings" 26menu "Settings"
13 27
14config DESKTOP 28config DESKTOP
@@ -368,6 +382,190 @@ config FEATURE_SYSLOG
368 #This option is auto-selected when you select any applet which may 382 #This option is auto-selected when you select any applet which may
369 #send its output to syslog. You do not need to select it manually. 383 #send its output to syslog. You do not need to select it manually.
370 384
385comment 'Settings for MINGW32'
386
387config GLOBBING
388 bool "Allow busybox.exe to expand wildcards"
389 default y
390 depends on PLATFORM_MINGW32
391 help
392 In Microsoft Windows expansion of wildcards on the command line
393 ('globbing') is handled by the C runtime while the BusyBox shell
394 does its own wildcard expansion. In most circumstances BusyBox
395 will do the right thing. If it doesn't or if you don't need to
396 use BusyBox applets from the Windows Command Prompt you can stop
397 busybox.exe from expanding wildcards by setting this to 'N'.
398
399choice
400 prompt "Random number generator"
401 default FEATURE_PRNG_SHELL
402 depends on PLATFORM_MINGW32
403 help
404 BusyBox on Microsoft Windows uses a pseudo-random number
405 generator to emulate the Linux /dev/urandom device. There
406 are two options:
407 - The shell's built-in PRNG.
408 - Bob Jenkins' ISAAC. This is intended to be a secure PRNG. It's
409 slightly faster than the shell's PRNG but is larger both in terms
410 of code and runtime memory.
411
412config FEATURE_PRNG_SHELL
413 bool "Use shell PRNG"
414
415config FEATURE_PRNG_ISAAC
416 bool "Use ISAAC PRNG"
417
418endchoice
419
420config FEATURE_RESOURCES
421 bool "Include resources in binary"
422 default y
423 depends on PLATFORM_MINGW32
424 help
425 Microsoft Windows applications can contain non-executable resources
426 of various sorts.
427
428config FEATURE_VERSIONINFO
429 bool "Include version information in binary (1.0 kb)"
430 default y
431 depends on FEATURE_RESOURCES
432 help
433 Include version information in the application.
434
435choice
436 prompt "Manifest"
437 default FEATURE_APP_MANIFEST
438 depends on FEATURE_RESOURCES
439 help
440 Manifest to include in resources.
441
442config FEATURE_TOOLCHAIN_MANIFEST
443 bool "Toolchain default"
444 help
445 Include the default application manifest provided by the build
446 toolchain, if any. Enable this if your build toolchain includes
447 a suitable manifest.
448
449config FEATURE_APP_MANIFEST
450 bool "Application"
451 help
452 Include a manifest which declares privileges required by the
453 application and supported versions of Windows.
454
455config FEATURE_UTF8_MANIFEST
456 bool "UTF-8"
457 help
458 Include a manifest which sets the process code page to UTF-8.
459 This also includes details from the standard application manifest.
460 Users who enable this may also wish to enable FEATURE_UTF8_INPUT
461 and/or FEATURE_UTF8_OUTPUT.
462
463endchoice
464
465config FEATURE_ICON
466 bool "Include application icon in binary"
467 default y
468 depends on FEATURE_RESOURCES
469 help
470 Microsoft Windows applications can contain icons which are used in
471 various places in the user interface. Each icon adds 15 Kbytes to
472 the size of the binary.
473
474choice
475 prompt "Application icon"
476 default FEATURE_ICON_ALL
477 depends on FEATURE_ICON
478
479config FEATURE_ICON_ATERM
480 bool "Adwaita terminal"
481
482config FEATURE_ICON_STERM
483 bool "Adwaita terminal (symbolic)"
484
485config FEATURE_ICON_ALL
486 bool "All available icons"
487
488endchoice
489
490config FEATURE_EURO
491 bool "Support the euro currency symbol"
492 default y
493 depends on PLATFORM_MINGW32
494 help
495 Support the entry and display of the euro currency symbol. This
496 requires the OEM code page to be 858. If the OEM code page of
497 the console is 850 when BusyBox starts it's changed to 858.
498
499config FEATURE_UTF8_INPUT
500 bool "Allow UTF8 console input (0.8 kb)"
501 default n
502 depends on PLATFORM_MINGW32
503 help
504 Allow characters entered in the console to be encoded as UTF8.
505 This may be useful in conjunction with the UTF8 manifest which
506 is supported in Window 10 and 11.
507
508config FEATURE_UTF8_OUTPUT
509 bool "Allow UTF8 console output"
510 default n
511 depends on PLATFORM_MINGW32 && FEATURE_UTF8_MANIFEST
512 help
513 Print UTF8 output correctly even if the console (output) codepage
514 is not UTF8.
515 This may be useful in conjunction with the UTF8 manifest which
516 is supported in Window 10 and 11.
517
518config TERMINAL_MODE
519 int "Default setting for terminal mode"
520 default 5
521 range 0 5
522 depends on PLATFORM_MINGW32
523 help
524 Set the default input/output modes of the Windows console/terminal.
525 Possible values are:
526
527 0 Force console mode.
528 1 Force virtual terminal mode for output.
529 2 Force virtual terminal mode for input.
530 3 Force virtual terminal mode for input and output.
531
532 4 Support virtual terminal input if enabled. Don't alter mode.
533 5 Support virtual terminal input if enabled. Set virtual terminal
534 mode for output, if possible.
535
536 Values 0-3 are for testing only. The default is 5. The environment
537 variable BB_TERMINAL_MODE overrides this.
538
539config FEATURE_IMPROVED_COLOUR_MAPPING
540 bool "More accurate colour mapping for ANSI emulation (0.6 kb)"
541 default y
542 depends on PLATFORM_MINGW32
543 help
544 Use a more accurate technique to map RGB colours to the standard
545 Windows console colours.
546
547config FEATURE_EXTRA_FILE_DATA
548 bool "Read additional file metadata (2.7 kb)"
549 default y
550 depends on PLATFORM_MINGW32
551 help
552 Read additional file metadata: device id, inode number and number
553 of hard links. This may slow down some file operations but it
554 permits extra features such as warning of attempts to copy a file
555 onto itself or to store a tar archive in itself. Also try to
556 determine the ownership of files so that, for example, 'ls' can
557 distinguish files belonging to the current user.
558
559config OVERRIDE_APPLETS
560 string "Override applets"
561 default ""
562 depends on PLATFORM_MINGW32 && (FEATURE_PREFER_APPLETS || FEATURE_SH_STANDALONE)
563 help
564 A list of applets to be ignored in standalone shell mode. The
565 format is the same as that used by the BB_OVERRIDE_APPLETS
566 environment variable. BB_OVERRIDE_APPLETS is checked first, if it
567 allows the applet and this list is non-empty it is checked too.
568
371comment 'Build Options' 569comment 'Build Options'
372 570
373config STATIC 571config STATIC
@@ -491,6 +689,18 @@ config CROSS_COMPILER_PREFIX
491 689
492 Native builds leave this empty. 690 Native builds leave this empty.
493 691
692config HOST_COMPILER
693 string "Host compiler"
694 default "gcc"
695 help
696 Name of the compiler to use for host binaries.
697
698config CROSS_COMPILER
699 string "Cross compiler"
700 default "gcc"
701 help
702 Name of the compiler to use for cross compilation.
703
494config SYSROOT 704config SYSROOT
495 string "Path to sysroot" 705 string "Path to sysroot"
496 default "" 706 default ""
diff --git a/Makefile b/Makefile
index 9550c391a..ae870ecb7 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,10 @@ SUBLEVEL = 0
4EXTRAVERSION = .git 4EXTRAVERSION = .git
5NAME = Unnamed 5NAME = Unnamed
6 6
7# Colon is used as a separator in makefiles. Strip any drive prefix
8# from the current directory to avoid confusion.
9CURDIR := $(lastword $(subst :, ,$(CURDIR)))
10
7# *DOCUMENTATION* 11# *DOCUMENTATION*
8# To see a list of typical targets execute "make help" 12# To see a list of typical targets execute "make help"
9# More info can be located in ./README 13# More info can be located in ./README
@@ -192,6 +196,28 @@ ARCH ?= $(SUBARCH)
192# Architecture as present in compile.h 196# Architecture as present in compile.h
193UTS_MACHINE := $(ARCH) 197UTS_MACHINE := $(ARCH)
194 198
199HOST_COMPILER ?=
200ifeq ($(HOST_COMPILER),)
201HOST_COMPILER := $(shell grep ^CONFIG_HOST_COMPILER= .config 2>/dev/null)
202HOST_COMPILER := $(subst CONFIG_HOST_COMPILER=,,$(HOST_COMPILER))
203HOST_COMPILER := $(subst ",,$(HOST_COMPILER))
204#")
205endif
206ifeq ($(HOST_COMPILER),)
207HOST_COMPILER := gcc
208endif
209
210CROSS_COMPILER ?=
211ifeq ($(CROSS_COMPILER),)
212CROSS_COMPILER := $(shell grep ^CONFIG_CROSS_COMPILER= .config 2>/dev/null)
213CROSS_COMPILER := $(subst CONFIG_CROSS_COMPILER=,,$(CROSS_COMPILER))
214CROSS_COMPILER := $(subst ",,$(CROSS_COMPILER))
215#")
216endif
217ifeq ($(CROSS_COMPILER),)
218CROSS_COMPILER := gcc
219endif
220
195# SHELL used by kbuild 221# SHELL used by kbuild
196CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ 222CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
197 else if [ -x /bin/bash ]; then echo /bin/bash; \ 223 else if [ -x /bin/bash ]; then echo /bin/bash; \
@@ -260,8 +286,15 @@ endif
260 286
261# If the user is running make -s (silent mode), suppress echoing of 287# If the user is running make -s (silent mode), suppress echoing of
262# commands 288# commands
289# make-4.0 (and later) keep single letter options in the 1st word of MAKEFLAGS.
290
291ifeq ($(filter 3.%,$(MAKE_VERSION)),)
292short-opts := $(firstword -$(MAKEFLAGS))
293else
294short-opts := $(filter-out --%,$(MAKEFLAGS))
295endif
263 296
264ifneq ($(findstring s,$(MAKEFLAGS)),) 297ifneq ($(findstring s,$(short-opts)),)
265 quiet=silent_ 298 quiet=silent_
266endif 299endif
267 300
@@ -271,7 +304,7 @@ export quiet Q KBUILD_VERBOSE
271# Look for make include files relative to root of kernel src 304# Look for make include files relative to root of kernel src
272MAKEFLAGS += --include-dir=$(srctree) 305MAKEFLAGS += --include-dir=$(srctree)
273 306
274HOSTCC = gcc 307HOSTCC = $(HOST_COMPILER)
275HOSTCXX = g++ 308HOSTCXX = g++
276HOSTCFLAGS := 309HOSTCFLAGS :=
277HOSTCXXFLAGS := 310HOSTCXXFLAGS :=
@@ -289,7 +322,7 @@ MAKEFLAGS += -rR
289# Make variables (CC, etc...) 322# Make variables (CC, etc...)
290 323
291AS = $(CROSS_COMPILE)as 324AS = $(CROSS_COMPILE)as
292CC = $(CROSS_COMPILE)gcc 325CC = $(CROSS_COMPILE)$(CROSS_COMPILER)
293LD = $(CC) -nostdlib 326LD = $(CC) -nostdlib
294CPP = $(CC) -E 327CPP = $(CC) -E
295AR = $(CROSS_COMPILE)ar 328AR = $(CROSS_COMPILE)ar
@@ -297,6 +330,7 @@ NM = $(CROSS_COMPILE)nm
297STRIP = $(CROSS_COMPILE)strip 330STRIP = $(CROSS_COMPILE)strip
298OBJCOPY = $(CROSS_COMPILE)objcopy 331OBJCOPY = $(CROSS_COMPILE)objcopy
299OBJDUMP = $(CROSS_COMPILE)objdump 332OBJDUMP = $(CROSS_COMPILE)objdump
333WINDRES = $(CROSS_COMPILE)windres
300PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config 334PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config
301AWK = awk 335AWK = awk
302GENKSYMS = scripts/genksyms/genksyms 336GENKSYMS = scripts/genksyms/genksyms
@@ -305,6 +339,15 @@ KALLSYMS = scripts/kallsyms
305PERL = perl 339PERL = perl
306CHECK = sparse 340CHECK = sparse
307 341
342# Handle MSYS2 weirdness
343ifneq ($(CROSS_COMPILE),)
344ifeq ($(shell _= command -v $(AR)),)
345AR := $(CROSS_COMPILE)gcc-ar
346STRIP := strip
347WINDRES := windres
348endif
349endif
350
308CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise $(CF) 351CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise $(CF)
309MODFLAGS = -DMODULE 352MODFLAGS = -DMODULE
310CFLAGS_MODULE = $(MODFLAGS) 353CFLAGS_MODULE = $(MODFLAGS)
@@ -312,6 +355,7 @@ AFLAGS_MODULE = $(MODFLAGS)
312LDFLAGS_MODULE = -r 355LDFLAGS_MODULE = -r
313CFLAGS_KERNEL = 356CFLAGS_KERNEL =
314AFLAGS_KERNEL = 357AFLAGS_KERNEL =
358EXEEXT =
315 359
316 360
317# Use LINUXINCLUDE when you must reference the include/ directory. 361# Use LINUXINCLUDE when you must reference the include/ directory.
@@ -324,13 +368,43 @@ AFLAGS := $(AFLAGS)
324LDFLAGS := $(LDFLAGS) 368LDFLAGS := $(LDFLAGS)
325LDLIBS := 369LDLIBS :=
326 370
371CONFIG_PLATFORM_MINGW32 ?=
372ifeq ($(CONFIG_PLATFORM_MINGW32),)
373CONFIG_PLATFORM_MINGW32 := $(shell grep ^CONFIG_PLATFORM_MINGW32= .config 2>/dev/null)
374CONFIG_PLATFORM_MINGW32 := $(subst CONFIG_PLATFORM_MINGW32=,,$(CONFIG_PLATFORM_MINGW32))
375CONFIG_PLATFORM_MINGW32 := $(subst ",,$(CONFIG_PLATFORM_MINGW32))
376#")
377endif
378
379# Try various methods to get a more specific EXTRAVERSION, but only
380# for MINGW32 platform and if EXTRAVERSION is default '.git'
381ifeq ($(CONFIG_PLATFORM_MINGW32)$(EXTRAVERSION),y.git)
382# Ask git
383extraversion := $(shell cd $(srctree) && git describe --match FRP 2>/dev/null)
384ifeq ($(strip $(extraversion)),)
385# That didn't work, look for a .frp_describe file
386extraversion := $(shell grep '^FRP-' $(srctree)/.frp_describe 2>/dev/null)
387ifeq ($(strip $(extraversion)),)
388# That didn't work either, look at name of source directory
389e1 := $(shell basename $(srctree) | grep '^busybox-w32-FRP-')
390ifneq ($(strip $(e1)),)
391extraversion := $(subst busybox-w32-,,$(e1))
392endif
393endif
394endif
395
396ifneq ($(strip $(extraversion)),)
397EXTRAVERSION := .$(subst FRP,git,$(extraversion))
398endif
399endif
400
327# Read KERNELRELEASE from .kernelrelease (if it exists) 401# Read KERNELRELEASE from .kernelrelease (if it exists)
328KERNELRELEASE = $(shell cat .kernelrelease 2> /dev/null) 402KERNELRELEASE = $(shell cat .kernelrelease 2> /dev/null)
329KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) 403KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
330 404
331export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION \ 405export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION \
332 ARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \ 406 ARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
333 CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE \ 407 CPP AR NM STRIP OBJCOPY OBJDUMP WINDRES MAKE AWK GENKSYMS PERL UTS_MACHINE \
334 HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS 408 HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
335 409
336export CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS 410export CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
@@ -462,6 +536,7 @@ scripts_basic: include/autoconf.h
462# Objects we will link into busybox / subdirs we need to visit 536# Objects we will link into busybox / subdirs we need to visit
463core-y := \ 537core-y := \
464 applets/ \ 538 applets/ \
539 win32/resources/ \
465 540
466libs-y := \ 541libs-y := \
467 archival/ \ 542 archival/ \
@@ -492,6 +567,7 @@ libs-y := \
492 sysklogd/ \ 567 sysklogd/ \
493 util-linux/ \ 568 util-linux/ \
494 util-linux/volume_id/ \ 569 util-linux/volume_id/ \
570 win32/ \
495 571
496endif # KBUILD_EXTMOD 572endif # KBUILD_EXTMOD
497 573
@@ -532,7 +608,7 @@ endif
532# command line. 608# command line.
533# This allow a user to issue only 'make' to build a kernel including modules 609# This allow a user to issue only 'make' to build a kernel including modules
534# Defaults busybox but it is usually overridden in the arch makefile 610# Defaults busybox but it is usually overridden in the arch makefile
535all: busybox doc 611all: busybox$(EXEEXT) doc
536 612
537# arch Makefile may override CC so keep this after arch Makefile is included 613# arch Makefile may override CC so keep this after arch Makefile is included
538#bbox# NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) 614#bbox# NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
@@ -715,16 +791,16 @@ debug_kallsyms: .tmp_map$(last_kallsyms)
715endif # ifdef CONFIG_KALLSYMS 791endif # ifdef CONFIG_KALLSYMS
716 792
717# busybox image - including updated kernel symbols 793# busybox image - including updated kernel symbols
718busybox_unstripped: $(busybox-all) FORCE 794busybox_unstripped$(EXEEXT): $(busybox-all) FORCE
719 $(call if_changed_rule,busybox__) 795 $(call if_changed_rule,busybox__)
720 $(Q)rm -f .old_version 796 $(Q)rm -f .old_version
721 797
722busybox: busybox_unstripped 798busybox$(EXEEXT): busybox_unstripped$(EXEEXT)
723ifeq ($(SKIP_STRIP),y) 799ifeq ($(SKIP_STRIP),y)
724 $(Q)cp $< $@ 800 $(Q)cp $< $@
725else 801else
726 $(Q)$(STRIP) -s --remove-section=.note --remove-section=.comment \ 802 $(Q)$(STRIP) -s --remove-section=.note --remove-section=.comment \
727 busybox_unstripped -o $@ 803 busybox_unstripped$(EXEEXT) -o $@
728# strip is confused by PIE executable and does not set exec bits 804# strip is confused by PIE executable and does not set exec bits
729 $(Q)chmod a+x $@ 805 $(Q)chmod a+x $@
730endif 806endif
@@ -816,7 +892,7 @@ endif
816# prepare2 creates a makefile if using a separate output directory 892# prepare2 creates a makefile if using a separate output directory
817prepare2: prepare3 outputmakefile 893prepare2: prepare3 outputmakefile
818 894
819prepare1: prepare2 include/config/MARKER 895prepare1: prepare2 include/config/MARKER include/BB_VER.h
820ifneq ($(KBUILD_MODULES),) 896ifneq ($(KBUILD_MODULES),)
821 $(Q)mkdir -p $(MODVERDIR) 897 $(Q)mkdir -p $(MODVERDIR)
822 $(Q)rm -f $(MODVERDIR)/* 898 $(Q)rm -f $(MODVERDIR)/*
@@ -880,6 +956,13 @@ define filechk_version.h
880 ) 956 )
881endef 957endef
882 958
959define filechk_BB_VER.h
960 (echo \#define BB_VER \"$(KERNELRELEASE)\";)
961endef
962
963include/BB_VER.h: $(srctree)/Makefile .config .kernelrelease FORCE
964 $(call filechk,BB_VER.h)
965
883# --------------------------------------------------------------------------- 966# ---------------------------------------------------------------------------
884 967
885PHONY += depend dep 968PHONY += depend dep
@@ -966,7 +1049,7 @@ endif # CONFIG_MODULES
966 1049
967# Directories & files removed with 'make clean' 1050# Directories & files removed with 'make clean'
968CLEAN_DIRS += $(MODVERDIR) _install 0_lib 1051CLEAN_DIRS += $(MODVERDIR) _install 0_lib
969CLEAN_FILES += busybox busybox_unstripped* busybox.links \ 1052CLEAN_FILES += busybox$(EXEEXT) busybox_unstripped* busybox.links \
970 busybox*.suid busybox*.nosuid \ 1053 busybox*.suid busybox*.nosuid \
971 System.map .kernelrelease \ 1054 System.map .kernelrelease \
972 .tmp_kallsyms* .tmp_version .tmp_busybox* .tmp_System.map 1055 .tmp_kallsyms* .tmp_version .tmp_busybox* .tmp_System.map
@@ -975,6 +1058,7 @@ CLEAN_FILES += busybox busybox_unstripped* busybox.links \
975MRPROPER_DIRS += include/config include2 1058MRPROPER_DIRS += include/config include2
976MRPROPER_FILES += .config .config.old include/asm .version .old_version \ 1059MRPROPER_FILES += .config .config.old include/asm .version .old_version \
977 include/NUM_APPLETS.h \ 1060 include/NUM_APPLETS.h \
1061 include/BB_VER.h \
978 include/common_bufsiz.h \ 1062 include/common_bufsiz.h \
979 include/autoconf.h \ 1063 include/autoconf.h \
980 include/bbconfigopts.h \ 1064 include/bbconfigopts.h \
@@ -985,6 +1069,7 @@ MRPROPER_FILES += .config .config.old include/asm .version .old_version \
985 include/applets.h \ 1069 include/applets.h \
986 include/usage.h \ 1070 include/usage.h \
987 applets/usage \ 1071 applets/usage \
1072 win32/resources/busybox-w32.manifest \
988 .kernelrelease Module.symvers tags TAGS cscope* \ 1073 .kernelrelease Module.symvers tags TAGS cscope* \
989 busybox_old 1074 busybox_old
990 1075
diff --git a/Makefile.custom b/Makefile.custom
index 6f679c4e1..e2f6d1c2f 100644
--- a/Makefile.custom
+++ b/Makefile.custom
@@ -104,29 +104,29 @@ checkhelp:
104 $(patsubst %,$(srctree)/%,$(wildcard $(patsubst %,%/Config.in,$(busybox-dirs) ./))) 104 $(patsubst %,$(srctree)/%,$(wildcard $(patsubst %,%/Config.in,$(busybox-dirs) ./)))
105 105
106.PHONY: sizes 106.PHONY: sizes
107sizes: busybox_unstripped 107sizes: busybox_unstripped$(EXEEXT)
108 $(NM) --size-sort $(<) 108 $(NM) --size-sort $(<)
109 109
110.PHONY: bloatcheck 110.PHONY: bloatcheck
111bloatcheck: busybox_old busybox_unstripped 111bloatcheck: busybox_old$(EXEEXT) busybox_unstripped$(EXEEXT)
112 @$(srctree)/scripts/bloat-o-meter busybox_old busybox_unstripped 112 @$(srctree)/scripts/bloat-o-meter busybox_old$(EXEEXT) busybox_unstripped$(EXEEXT)
113 @$(CROSS_COMPILE)size busybox_old busybox_unstripped 113 @$(CROSS_COMPILE)size busybox_old$(EXEEXT) busybox_unstripped$(EXEEXT)
114 114
115.PHONY: baseline 115.PHONY: baseline
116baseline: busybox_unstripped 116baseline: busybox_unstripped$(EXEEXT)
117 @mv busybox_unstripped busybox_old 117 @mv busybox_unstripped$(EXEEXT) busybox_old$(EXEEXT)
118 118
119.PHONY: objsizes 119.PHONY: objsizes
120objsizes: busybox_unstripped 120objsizes: busybox_unstripped$(EXEEXT)
121 $(srctree)/scripts/objsizes 121 $(srctree)/scripts/objsizes
122 122
123.PHONY: stksizes 123.PHONY: stksizes
124stksizes: busybox_unstripped 124stksizes: busybox_unstripped$(EXEEXT)
125 $(CROSS_COMPILE)objdump -d busybox_unstripped | $(srctree)/scripts/checkstack.pl $(ARCH) | uniq 125 $(CROSS_COMPILE)objdump -d busybox_unstripped$(EXEEXT) | $(srctree)/scripts/checkstack.pl $(ARCH) | uniq
126 126
127.PHONY: bigdata 127.PHONY: bigdata
128bigdata: busybox_unstripped 128bigdata: busybox_unstripped$(EXEEXT)
129 $(CROSS_COMPILE)nm --size-sort busybox_unstripped | grep -vi ' [trw] ' 129 $(CROSS_COMPILE)nm --size-sort busybox_unstripped$(EXEEXT) | grep -vi ' [trw] '
130 130
131# Documentation Targets 131# Documentation Targets
132.PHONY: doc 132.PHONY: doc
diff --git a/Makefile.flags b/Makefile.flags
index 97cb4dca2..f24fd9475 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -16,7 +16,8 @@ CPPFLAGS += \
16 -D_GNU_SOURCE -DNDEBUG \ 16 -D_GNU_SOURCE -DNDEBUG \
17 $(if $(CONFIG_LFS),-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) \ 17 $(if $(CONFIG_LFS),-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) \
18 $(if $(CONFIG_TIME64),-D_TIME_BITS=64) \ 18 $(if $(CONFIG_TIME64),-D_TIME_BITS=64) \
19 -DBB_VER=$(squote)$(quote)$(BB_VER)$(quote)$(squote) 19 -DMINGW_VER=$(squote)$(quote)$(MINGW_VER)$(quote)$(squote) \
20 $(if $(CONFIG_PLATFORM_MINGW32),,-DBB_VER=$(squote)$(quote)$(BB_VER)$(quote)$(squote))
20 21
21CFLAGS += $(call cc-option,-Wall,) 22CFLAGS += $(call cc-option,-Wall,)
22CFLAGS += $(call cc-option,-Wshadow,) 23CFLAGS += $(call cc-option,-Wshadow,)
@@ -146,6 +147,18 @@ CFLAGS += --sysroot=$(CONFIG_SYSROOT)
146export SYSROOT=$(CONFIG_SYSROOT) 147export SYSROOT=$(CONFIG_SYSROOT)
147endif 148endif
148 149
150ifeq ($(CONFIG_PLATFORM_MINGW32),y)
151CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy -fno-builtin-stpncpy -fno-ident -fno-builtin-strndup
152# this seems to be necessary for setjmp/longjmp to work with clang
153ifeq ($(lastword $(subst -, ,$(CC))),clang)
154CFLAGS += $(call cc-option,-fsjlj-exceptions,)
155endif
156
157EXEEXT = .exe
158LDLIBS += ws2_32
159endif
160
161ifneq ($(CONFIG_PLATFORM_MINGW32),y)
149# libm may be needed for dc, awk, ntpd 162# libm may be needed for dc, awk, ntpd
150LDLIBS += m 163LDLIBS += m
151# Android has no separate crypt library 164# Android has no separate crypt library
@@ -161,6 +174,7 @@ endif
161ifeq ($(RT_AVAILABLE),y) 174ifeq ($(RT_AVAILABLE),y)
162LDLIBS += rt 175LDLIBS += rt
163endif 176endif
177endif
164 178
165# libpam may use libpthread, libdl and/or libaudit. 179# libpam may use libpthread, libdl and/or libaudit.
166# On some platforms that requires an explicit -lpthread, -ldl, -laudit. 180# On some platforms that requires an explicit -lpthread, -ldl, -laudit.
diff --git a/README b/README
index ada5935b9..9936e6cc3 100644
--- a/README
+++ b/README
@@ -1,3 +1,4 @@
1Please see README.md for Windows-specific info.
1Please see the LICENSE file for details on copying and usage. 2Please see the LICENSE file for details on copying and usage.
2Please refer to the INSTALL file for instructions on how to build. 3Please refer to the INSTALL file for instructions on how to build.
3 4
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..2de1f89aa
--- /dev/null
+++ b/README.md
@@ -0,0 +1,41 @@
1### Status
2
3Things may work for you, or may not. Things may never work because of huge differences between Linux and Windows. Or things may work in future, if you report the problem on [GitHub](https://github.com/rmyorston/busybox-w32) or [GitLab](https://gitlab.com/rmyorston/busybox-w32). If you don't have an account on one of those or you'd prefer to communicate privately you can email [rmy@pobox.com](mailto:rmy@pobox.com).
4
5Additional information is available from the [BusyBox for Windows](https://frippery.org/busybox/index.html) web page. In particular:
6
7- There are [downloads](https://frippery.org/busybox/index.html#downloads) of precompiled binaries for i686, x86_64 and aarch64.
8- Release notes for the [current](https://frippery.org/busybox/release-notes/current.html) and [previous](https://frippery.org/busybox/release-notes/index.html) releases are available.
9
10### Building
11
12You need a MinGW toolchain and a POSIX environment. I cross-compile on Linux. On Fedora the following should pull in everything required:
13
14`dnf install gcc make ncurses-devel perl-Pod-Html`
15
16`dnf install mingw64-gcc` (for a 64-bit build)
17
18`dnf install mingw32-gcc` (for a 32-bit build)
19
20On Microsoft Windows you can install [w64devkit](https://github.com/skeeto/w64devkit/releases). Get the `-i686` variant for a 32-bit build. Unzip the file and run `w64devkit/w64devkit.exe`.
21
22On either Linux or Windows the commands `make mingw64_defconfig` or `make mingw32_defconfig` will pick up the default configuration. You can then customize your build with `make menuconfig` or by editing `.config`, if you know what you're doing.
23
24Then just `make`.
25
26See the [Building busybox-w32](https://frippery.org/busybox/build.html) web page for additional information.
27
28### Hints
29
30 - Use forward slashes in paths: Windows doesn't mind and the shell will be happier.
31 - Windows paths are different from Unix ([more detail](https://frippery.org/busybox/paths.html)):
32 * Absolute paths: `c:/path` or `//host/share/path`
33 * Relative to current directory of other drive: `c:path`
34 * Relative to current root (drive or share): `/path`
35 * Relative to current directory of current root (drive or share): `path`
36 - Handling of users, groups and permissions is totally bogus. The system only admits to knowing about the current user and employs various heuristics to synthesise uid, gid and permission values.
37 - Some crufty old Windows code (Windows XP, cmd.exe) doesn't like forward slashes in environment variables. The -X shell option prevents busybox-w32 from changing backslashes to forward slashes. If Windows programs don't run from the shell it's worth trying it.
38 - If you want to install 32-bit BusyBox in a system directory on a 64-bit version of Windows you should put it in `C:\Windows\SysWOW64`, not `C:\Windows\System32` as you might expect. On 64-bit systems the latter is for 64-bit binaries.
39 - The system tries to detect the best way to handle the terminal being used. If this doesn't work you can try setting the environment variable `BB_TERMINAL_MODE=1` to force the use of literal ANSI escapes or `BB_TERMINAL_MODE=0` to emulate them using the Windows console API.
40 - busybox-w32 prefers built-in applets to external programs when running commands. This preference can be overridden by setting the environment variable `BB_OVERRIDE_APPLETS` to a space-separated list of applet names. Thus, to use an external `make` in preference to the built-in applet set `BB_OVERRIDE_APPLETS="make"`.
41 - It's possible to obtain pseudo-random numbers using `if=/dev/urandom` as the input file to `dd`. The same emulation of `/dev/urandom` is used internally by the `shred` utility and to support https in `wget`. Serious users of random numbers may, of course, wish to make alternative arrangements.
diff --git a/applets/.gitignore b/applets/.gitignore
index 459938d67..970bb90a9 100644
--- a/applets/.gitignore
+++ b/applets/.gitignore
@@ -1,3 +1,6 @@
1/applet_tables 1/applet_tables
2/usage 2/usage
3/usage_pod 3/usage_pod
4/applet_tables.exe
5/usage.exe
6/usage_pod.exe
diff --git a/applets/applet_tables.c b/applets/applet_tables.c
index 66ef7e4ac..fe26a5109 100644
--- a/applets/applet_tables.c
+++ b/applets/applet_tables.c
@@ -103,6 +103,9 @@ int main(int argc, char **argv)
103 if (i < 0) 103 if (i < 0)
104 return 1; 104 return 1;
105 dup2(i, 1); 105 dup2(i, 1);
106#ifdef __MINGW32__
107 close(i);
108#endif
106 109
107 /* Keep in sync with include/busybox.h! */ 110 /* Keep in sync with include/busybox.h! */
108 111
@@ -236,8 +239,14 @@ int main(int argc, char **argv)
236 239
237 if (fclose(stdout)) 240 if (fclose(stdout))
238 return 1; 241 return 1;
242#ifdef __MINGW32__
243 unlink(argv[1]);
244#endif
239 if (rename(tmp1, argv[1])) 245 if (rename(tmp1, argv[1]))
240 return 1; 246 return 1;
247#ifdef __MINGW32__
248 unlink(argv[2]);
249#endif
241 if (rename(tmp2, argv[2])) 250 if (rename(tmp2, argv[2]))
242 return 1; 251 return 1;
243 return 0; 252 return 0;
diff --git a/applets/usage_compressed b/applets/usage_compressed
index 36fc2a007..94d70f33b 100755
--- a/applets/usage_compressed
+++ b/applets/usage_compressed
@@ -16,6 +16,7 @@ if test $? != 0; then
16 exit 1 16 exit 1
17fi 17fi
18 18
19(
19exec >"$target.$$" 20exec >"$target.$$"
20 21
21echo '#define UNPACKED_USAGE "" \' 22echo '#define UNPACKED_USAGE "" \'
@@ -58,5 +59,6 @@ echo '#define PACKED_USAGE \'
58 -e 's/\(...\)/0\1,/g' \ 59 -e 's/\(...\)/0\1,/g' \
59 -e 's/$/ \\/' 60 -e 's/$/ \\/'
60echo '' 61echo ''
62)
61 63
62mv -- "$target.$$" "$target" 64mv -- "$target.$$" "$target"
diff --git a/archival/ar.c b/archival/ar.c
index 320cbae72..16bb33227 100644
--- a/archival/ar.c
+++ b/archival/ar.c
@@ -30,12 +30,12 @@
30//config:config FEATURE_AR_LONG_FILENAMES 30//config:config FEATURE_AR_LONG_FILENAMES
31//config: bool "Support long filenames (not needed for debs)" 31//config: bool "Support long filenames (not needed for debs)"
32//config: default y 32//config: default y
33//config: depends on AR 33//config: depends on AR || MAKE || PDPMAKE
34//config: help 34//config: help
35//config: By default the ar format can only store the first 15 characters 35//config: By default the ar format can only store the first 15 characters
36//config: of the filename, this option removes that limitation. 36//config: of the filename, this option removes that limitation.
37//config: It supports the GNU ar long filename method which moves multiple long 37//config: It supports the GNU ar long filename method which moves multiple long
38//config: filenames into a the data section of a new ar entry. 38//config: filenames into the data section of a new ar entry.
39//config: 39//config:
40//config:config FEATURE_AR_CREATE 40//config:config FEATURE_AR_CREATE
41//config: bool "Support archive creation" 41//config: bool "Support archive creation"
@@ -153,6 +153,9 @@ static int write_ar_archive(archive_handle_t *handle)
153{ 153{
154 struct stat st; 154 struct stat st;
155 archive_handle_t *out_handle; 155 archive_handle_t *out_handle;
156#if ENABLE_PLATFORM_MINGW32
157 char *temp_fn = NULL;
158#endif
156 159
157 xfstat(handle->src_fd, &st, handle->ar__name); 160 xfstat(handle->src_fd, &st, handle->ar__name);
158 161
@@ -161,8 +164,14 @@ static int write_ar_archive(archive_handle_t *handle)
161 */ 164 */
162 if (st.st_size != 0) { 165 if (st.st_size != 0) {
163 out_handle = init_handle(); 166 out_handle = init_handle();
167#if !ENABLE_PLATFORM_MINGW32
164 xunlink(handle->ar__name); 168 xunlink(handle->ar__name);
165 out_handle->src_fd = xopen(handle->ar__name, O_WRONLY | O_CREAT | O_TRUNC); 169 out_handle->src_fd = xopen(handle->ar__name, O_WRONLY | O_CREAT | O_TRUNC);
170#else
171 /* can't unlink open file, create temporary output file */
172 temp_fn = xasprintf("%sXXXXXX", handle->ar__name);
173 out_handle->src_fd = xmkstemp(temp_fn);
174#endif
166 out_handle->accept = handle->accept; 175 out_handle->accept = handle->accept;
167 } else { 176 } else {
168 out_handle = handle; 177 out_handle = handle;
@@ -184,12 +193,20 @@ static int write_ar_archive(archive_handle_t *handle)
184 continue; 193 continue;
185 194
186 /* optional, since we exit right after we return */ 195 /* optional, since we exit right after we return */
187 if (ENABLE_FEATURE_CLEAN_UP) { 196 if (ENABLE_FEATURE_CLEAN_UP || ENABLE_PLATFORM_MINGW32) {
188 close(handle->src_fd); 197 close(handle->src_fd);
189 if (out_handle->src_fd != handle->src_fd) 198 if (out_handle->src_fd != handle->src_fd)
190 close(out_handle->src_fd); 199 close(out_handle->src_fd);
191 } 200 }
192 201
202#if ENABLE_PLATFORM_MINGW32
203 if (temp_fn != NULL) {
204 xrename(temp_fn, handle->ar__name);
205 if (ENABLE_FEATURE_CLEAN_UP)
206 free(temp_fn);
207 }
208#endif
209
193 return EXIT_SUCCESS; 210 return EXIT_SUCCESS;
194} 211}
195#endif /* FEATURE_AR_CREATE */ 212#endif /* FEATURE_AR_CREATE */
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index b7944a62a..fb5deb0ce 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -178,6 +178,8 @@ int FAST_FUNC bbunpack(char **argv,
178 if (option_mask32 & BBUNPK_OPT_KEEP) /* ... unless -k */ 178 if (option_mask32 & BBUNPK_OPT_KEEP) /* ... unless -k */
179 del = NULL; 179 del = NULL;
180 } 180 }
181 if (ENABLE_PLATFORM_MINGW32)
182 xclose(STDIN_FILENO);
181 if (del) 183 if (del)
182 xunlink(del); 184 xunlink(del);
183 free_name: 185 free_name:
diff --git a/archival/cpio.c b/archival/cpio.c
index f0d990048..167931bdb 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -49,7 +49,7 @@
49//config:config FEATURE_CPIO_RENUMBER_INODES 49//config:config FEATURE_CPIO_RENUMBER_INODES
50//config: bool "Support --renumber-inodes like GNU cpio" 50//config: bool "Support --renumber-inodes like GNU cpio"
51//config: default y 51//config: default y
52//config: depends on FEATURE_CPIO_O && LONG_OPTS 52//config: depends on FEATURE_CPIO_O && LONG_OPTS && (PLATFORM_POSIX || FEATURE_EXTRA_FILE_DATA)
53//config: help 53//config: help
54//config: Optionally renumber inodes when creating archives. 54//config: Optionally renumber inodes when creating archives.
55 55
@@ -275,6 +275,7 @@ static NOINLINE int cpio_o(void)
275 if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode))) 275 if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
276 st.st_size = 0; /* paranoia */ 276 st.st_size = 0; /* paranoia */
277 277
278#if ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA
278 /* Store hardlinks for later processing, dont output them */ 279 /* Store hardlinks for later processing, dont output them */
279 if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) { 280 if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
280 struct name_s *n; 281 struct name_s *n;
@@ -310,6 +311,7 @@ static NOINLINE int cpio_o(void)
310 free(line); 311 free(line);
311 continue; 312 continue;
312 } 313 }
314#endif
313#if ENABLE_FEATURE_CPIO_RENUMBER_INODES 315#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
314 else if (option_mask32 & OPT_RENUMBER_INODES) { 316 else if (option_mask32 & OPT_RENUMBER_INODES) {
315 st.st_ino = ++G.next_inode; 317 st.st_ino = ++G.next_inode;
@@ -345,10 +347,12 @@ static NOINLINE int cpio_o(void)
345 } 347 }
346 } 348 }
347 349
350#if ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA
348#if ENABLE_FEATURE_CPIO_IGNORE_DEVNO 351#if ENABLE_FEATURE_CPIO_IGNORE_DEVNO
349 if (option_mask32 & OPT_IGNORE_DEVNO) 352 if (option_mask32 & OPT_IGNORE_DEVNO)
350 st.st_dev = st.st_rdev = 0; 353 st.st_dev = st.st_rdev = 0;
351#endif 354#endif
355#endif
352 356
353 bytes += printf("070701" 357 bytes += printf("070701"
354 "%08X%08X%08X%08X%08X%08X%08X" 358 "%08X%08X%08X%08X%08X%08X%08X"
diff --git a/archival/dpkg.c b/archival/dpkg.c
index 8031956e9..a6a8333a8 100644
--- a/archival/dpkg.c
+++ b/archival/dpkg.c
@@ -149,6 +149,11 @@ enum edge_type_e {
149 EDGE_RECOMMENDS = 13, 149 EDGE_RECOMMENDS = 13,
150 EDGE_ENHANCES = 15 150 EDGE_ENHANCES = 15
151}; 151};
152#if ENABLE_PLATFORM_MINGW32
153#undef VER_EQUAL
154#undef VER_LESS
155#undef VER_LESS_EQUAL
156#endif
152enum operator_e { 157enum operator_e {
153 VER_NULL = 0, 158 VER_NULL = 0,
154 VER_EQUAL = 1, 159 VER_EQUAL = 1,
@@ -1770,6 +1775,10 @@ int dpkg_main(int argc UNUSED_PARAM, char **argv)
1770 int state_status; 1775 int state_status;
1771 int status_num; 1776 int status_num;
1772 int i; 1777 int i;
1778#if ENABLE_PLATFORM_MINGW32
1779 char **ptr, *path;
1780 int fd;
1781#endif
1773#if ENABLE_LONG_OPTS 1782#if ENABLE_LONG_OPTS
1774 static const char dpkg_longopts[] ALIGN1 = 1783 static const char dpkg_longopts[] ALIGN1 =
1775// FIXME: we use -C non-compatibly, should be: 1784// FIXME: we use -C non-compatibly, should be:
@@ -1814,6 +1823,26 @@ int dpkg_main(int argc UNUSED_PARAM, char **argv)
1814 bb_show_usage(); 1823 bb_show_usage();
1815 } 1824 }
1816 1825
1826#if ENABLE_PLATFORM_MINGW32
1827 if (opt & OPT_install) {
1828 /* add system drive prefix to filenames, if necessary */
1829 for (ptr = argv; *ptr; ++ptr) {
1830 *ptr = xabsolute_path(*ptr);
1831 }
1832 }
1833
1834 chdir_system_drive();
1835
1836 /* initialise data store */
1837 path = xstrdup("/var/lib/dpkg/info");
1838 bb_make_directory(path, -1, FILEUTILS_RECUR);
1839 free(path);
1840
1841 fd = open("/var/lib/dpkg/status", O_RDWR|O_CREAT, 0666);
1842 if (fd >= 0)
1843 xclose(fd);
1844#endif
1845
1817/* puts("(Reading database ... xxxxx files and directories installed.)"); */ 1846/* puts("(Reading database ... xxxxx files and directories installed.)"); */
1818 index_status_file("/var/lib/dpkg/status"); 1847 index_status_file("/var/lib/dpkg/status");
1819 1848
diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src
index d2f284b08..1b1dabbf5 100644
--- a/archival/libarchive/Kbuild.src
+++ b/archival/libarchive/Kbuild.src
@@ -47,6 +47,8 @@ lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES)
47 47
48lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o 48lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o
49lib-$(CONFIG_CPIO) += get_header_cpio.o 49lib-$(CONFIG_CPIO) += get_header_cpio.o
50lib-$(CONFIG_MAKE) += get_header_ar.o unpack_ar_archive.o
51lib-$(CONFIG_PDPMAKE) += get_header_ar.o unpack_ar_archive.o
50lib-$(CONFIG_TAR) += get_header_tar.o unsafe_prefix.o 52lib-$(CONFIG_TAR) += get_header_tar.o unsafe_prefix.o
51lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o 53lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o
52lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o 54lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o
diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c
index d051ecb81..d2f7a9309 100644
--- a/archival/libarchive/decompress_gunzip.c
+++ b/archival/libarchive/decompress_gunzip.c
@@ -1137,6 +1137,9 @@ static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY)
1137 return res; 1137 return res;
1138} 1138}
1139 1139
1140#if ENABLE_PLATFORM_MINGW32 && __GNUC__
1141#pragma pack(2)
1142#endif
1140static int check_header_gzip(STATE_PARAM transformer_state_t *xstate) 1143static int check_header_gzip(STATE_PARAM transformer_state_t *xstate)
1141{ 1144{
1142 union { 1145 union {
@@ -1208,6 +1211,9 @@ static int check_header_gzip(STATE_PARAM transformer_state_t *xstate)
1208 } 1211 }
1209 return 1; 1212 return 1;
1210} 1213}
1214#if ENABLE_PLATFORM_MINGW32 && __GNUC__
1215#pragma pack()
1216#endif
1211 1217
1212IF_DESKTOP(long long) int FAST_FUNC 1218IF_DESKTOP(long long) int FAST_FUNC
1213unpack_gz_stream(transformer_state_t *xstate) 1219unpack_gz_stream(transformer_state_t *xstate)
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c
index cc6f3f0ad..5fd5a7980 100644
--- a/archival/libarchive/get_header_tar.c
+++ b/archival/libarchive/get_header_tar.c
@@ -239,8 +239,13 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
239 /* Check header has valid magic, "ustar" is for the proper tar, 239 /* Check header has valid magic, "ustar" is for the proper tar,
240 * five NULs are for the old tar format */ 240 * five NULs are for the old tar format */
241 if (!is_prefixed_with(tar.magic, "ustar") 241 if (!is_prefixed_with(tar.magic, "ustar")
242#if !ENABLE_PLATFORM_MINGW32
242 && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY 243 && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
243 || memcmp(tar.magic, "\0\0\0\0", 5) != 0) 244 || memcmp(tar.magic, "\0\0\0\0", 5) != 0)
245#else
246 && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
247 || memcmp(tar.magic, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) != 0)
248#endif
244 ) { 249 ) {
245#if ENABLE_FEATURE_TAR_AUTODETECT 250#if ENABLE_FEATURE_TAR_AUTODETECT
246 autodetect: 251 autodetect:
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index 44715ef25..3d202ad26 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -64,6 +64,7 @@ ssize_t FAST_FUNC xtransformer_write(transformer_state_t *xstate, const void *bu
64 return nwrote; 64 return nwrote;
65} 65}
66 66
67#if !ENABLE_PLATFORM_MINGW32
67void check_errors_in_children(int signo) 68void check_errors_in_children(int signo)
68{ 69{
69 int status; 70 int status;
@@ -150,6 +151,12 @@ void FAST_FUNC fork_transformer(int fd, const char *transform_prog)
150 close(fd_pipe.wr); /* don't want to write to the child */ 151 close(fd_pipe.wr); /* don't want to write to the child */
151 xmove_fd(fd_pipe.rd, fd); 152 xmove_fd(fd_pipe.rd, fd);
152} 153}
154#else /* ENABLE_PLATFORM_MINGW */
155void FAST_FUNC fork_transformer(int fd, const char *transform_prog)
156{
157 mingw_fork_compressor(fd, transform_prog, "r");
158}
159#endif
153 160
154 161
155#if SEAMLESS_COMPRESSION 162#if SEAMLESS_COMPRESSION
diff --git a/archival/libarchive/unpack_ar_archive.c b/archival/libarchive/unpack_ar_archive.c
index 125d424c9..923a0b2ab 100644
--- a/archival/libarchive/unpack_ar_archive.c
+++ b/archival/libarchive/unpack_ar_archive.c
@@ -16,6 +16,10 @@ void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive)
16 } 16 }
17 ar_archive->offset += AR_MAGIC_LEN; 17 ar_archive->offset += AR_MAGIC_LEN;
18 18
19 while (get_header_ar(ar_archive) == EXIT_SUCCESS) 19 while (get_header_ar(ar_archive) == EXIT_SUCCESS) {
20 continue; 20#if ENABLE_MAKE
21 free(ar_archive->file_header->name);
22 ar_archive->file_header->name = NULL;
23#endif
24 }
21} 25}
diff --git a/archival/libarchive/unsafe_symlink_target.c b/archival/libarchive/unsafe_symlink_target.c
index f8dc8033d..d9100f30f 100644
--- a/archival/libarchive/unsafe_symlink_target.c
+++ b/archival/libarchive/unsafe_symlink_target.c
@@ -10,18 +10,26 @@ void FAST_FUNC create_or_remember_link(llist_t **link_placeholders,
10 const char *linkname, 10 const char *linkname,
11 int hard_link) 11 int hard_link)
12{ 12{
13#if ENABLE_PLATFORM_MINGW32
14 /* defer reporting error if symlink(2) fails on Windows */
15 if (hard_link || target[0] == '/' || strstr(target, "..") ||
16 symlink(target, linkname) != 0) {
17#else
13 if (hard_link || target[0] == '/' || strstr(target, "..")) { 18 if (hard_link || target[0] == '/' || strstr(target, "..")) {
19#endif
14 llist_add_to_end(link_placeholders, 20 llist_add_to_end(link_placeholders,
15 xasprintf("%c%s%c%s", hard_link, linkname, '\0', target) 21 xasprintf("%c%s%c%s", hard_link, linkname, '\0', target)
16 ); 22 );
17 return; 23 return;
18 } 24 }
25#if !ENABLE_PLATFORM_MINGW32
19 if (symlink(target, linkname) != 0) { 26 if (symlink(target, linkname) != 0) {
20 /* shared message */ 27 /* shared message */
21 bb_perror_msg_and_die("can't create %slink '%s' to '%s'", 28 bb_perror_msg_and_die("can't create %slink '%s' to '%s'",
22 "sym", linkname, target 29 "sym", linkname, target
23 ); 30 );
24 } 31 }
32#endif
25} 33}
26 34
27void FAST_FUNC create_links_from_list(llist_t *list) 35void FAST_FUNC create_links_from_list(llist_t *list)
diff --git a/archival/rpm.c b/archival/rpm.c
index af8db99a6..d83c33137 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -142,6 +142,7 @@ static int rpm_gettags(const char *filename)
142 } 142 }
143 G.mytags = tags; 143 G.mytags = tags;
144 144
145#if !ENABLE_PLATFORM_MINGW32
145 /* Map the store */ 146 /* Map the store */
146 storepos = (storepos + G_pagesize) & -(int)G_pagesize; 147 storepos = (storepos + G_pagesize) & -(int)G_pagesize;
147 /* remember size for munmap */ 148 /* remember size for munmap */
@@ -150,6 +151,14 @@ static int rpm_gettags(const char *filename)
150 G.map = mmap_read(fd, storepos); 151 G.map = mmap_read(fd, storepos);
151 if (G.map == MAP_FAILED) 152 if (G.map == MAP_FAILED)
152 bb_perror_msg_and_die("mmap '%s'", filename); 153 bb_perror_msg_and_die("mmap '%s'", filename);
154#else
155# undef munmap
156# define munmap(p, l) free(p)
157 /* Allocate memory for the store */
158 G.map = xmalloc(storepos);
159 xlseek(fd, 0, SEEK_SET);
160 full_read(fd, G.map, storepos);
161#endif
153 162
154 return fd; 163 return fd;
155} 164}
@@ -240,6 +249,7 @@ static void fileaction_dobackup(char *filename, int fileref)
240 } 249 }
241} 250}
242 251
252#if !ENABLE_PLATFORM_MINGW32
243static void fileaction_setowngrp(char *filename, int fileref) 253static void fileaction_setowngrp(char *filename, int fileref)
244{ 254{
245 /* real rpm warns: "user foo does not exist - using <you>" */ 255 /* real rpm warns: "user foo does not exist - using <you>" */
@@ -249,6 +259,7 @@ static void fileaction_setowngrp(char *filename, int fileref)
249 int gid = gr ? gr->gr_gid : getgid(); 259 int gid = gr ? gr->gr_gid : getgid();
250 chown(filename, uid, gid); 260 chown(filename, uid, gid);
251} 261}
262#endif
252 263
253static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref)) 264static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref))
254{ 265{
@@ -296,6 +307,9 @@ static void extract_cpio(int fd, const char *source_rpm)
296 307
297 if (source_rpm != NULL) { 308 if (source_rpm != NULL) {
298 /* Binary rpm (it was built from some SRPM), install to root */ 309 /* Binary rpm (it was built from some SRPM), install to root */
310#if ENABLE_PLATFORM_MINGW32
311 if (chdir_system_drive())
312#endif
299 xchdir("/"); 313 xchdir("/");
300 } /* else: SRPM, install to current dir */ 314 } /* else: SRPM, install to current dir */
301 315
@@ -410,8 +424,10 @@ int rpm_main(int argc, char **argv)
410 loop_through_files(TAG_BASENAMES, fileaction_dobackup); 424 loop_through_files(TAG_BASENAMES, fileaction_dobackup);
411 /* Extact the archive */ 425 /* Extact the archive */
412 extract_cpio(rpm_fd, source_rpm); 426 extract_cpio(rpm_fd, source_rpm);
427#if !ENABLE_PLATFORM_MINGW32
413 /* Set the correct file uid/gid's */ 428 /* Set the correct file uid/gid's */
414 loop_through_files(TAG_BASENAMES, fileaction_setowngrp); 429 loop_through_files(TAG_BASENAMES, fileaction_setowngrp);
430#endif
415 } 431 }
416 else 432 else
417 if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) { 433 if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) {
diff --git a/archival/tar.c b/archival/tar.c
index d6ca6c1e0..23ea02b5d 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -119,6 +119,9 @@
119#include "libbb.h" 119#include "libbb.h"
120#include "common_bufsiz.h" 120#include "common_bufsiz.h"
121#include "bb_archive.h" 121#include "bb_archive.h"
122#if ENABLE_PLATFORM_MINGW32
123# include "BB_VER.h"
124#endif
122/* FIXME: Stop using this non-standard feature */ 125/* FIXME: Stop using this non-standard feature */
123#ifndef FNM_LEADING_DIR 126#ifndef FNM_LEADING_DIR
124# define FNM_LEADING_DIR 0 127# define FNM_LEADING_DIR 0
@@ -161,11 +164,13 @@ typedef struct TarBallInfo {
161# endif 164# endif
162 HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ 165 HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */
163 HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ 166 HardLinkInfo *hlInfo; /* Hard Link Info for the current file */
167#if ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA
164//TODO: save only st_dev + st_ino 168//TODO: save only st_dev + st_ino
165 struct stat tarFileStatBuf; /* Stat info for the tarball, letting 169 struct stat tarFileStatBuf; /* Stat info for the tarball, letting
166 * us know the inode and device that the 170 * us know the inode and device that the
167 * tarball lives, so we can avoid trying 171 * tarball lives, so we can avoid trying
168 * to include the tarball into itself */ 172 * to include the tarball into itself */
173#endif
169} TarBallInfo; 174} TarBallInfo;
170 175
171/* A nice enum with all the possible tar file content types */ 176/* A nice enum with all the possible tar file content types */
@@ -506,15 +511,21 @@ static int FAST_FUNC writeFileToTarball(struct recursive_state *state,
506 } 511 }
507 } 512 }
508 513
514#if ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA
509 /* It is a bad idea to store the archive we are in the process of creating, 515 /* It is a bad idea to store the archive we are in the process of creating,
510 * so check the device and inode to be sure that this particular file isn't 516 * so check the device and inode to be sure that this particular file isn't
511 * the new tarball */ 517 * the new tarball */
512 if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev 518 if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev
513 && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino 519 && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino
520# if ENABLE_FEATURE_EXTRA_FILE_DATA
521 /* ignore invalid inode numbers */
522 && statbuf->st_ino != 0
523# endif
514 ) { 524 ) {
515 bb_error_msg("%s: file is the archive; skipping", fileName); 525 bb_error_msg("%s: file is the archive; skipping", fileName);
516 return TRUE; 526 return TRUE;
517 } 527 }
528#endif
518 529
519# if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS 530# if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
520 if (strlen(header_name) >= NAME_SIZE) { 531 if (strlen(header_name) >= NAME_SIZE) {
@@ -568,7 +579,7 @@ static int FAST_FUNC writeFileToTarball(struct recursive_state *state,
568 return TRUE; 579 return TRUE;
569} 580}
570 581
571# if SEAMLESS_COMPRESSION 582# if SEAMLESS_COMPRESSION && !ENABLE_PLATFORM_MINGW32
572/* Don't inline: vfork scares gcc and pessimizes code */ 583/* Don't inline: vfork scares gcc and pessimizes code */
573static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) 584static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
574{ 585{
@@ -645,6 +656,10 @@ static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
645} 656}
646# endif /* SEAMLESS_COMPRESSION */ 657# endif /* SEAMLESS_COMPRESSION */
647 658
659# if ENABLE_PLATFORM_MINGW32
660# define vfork_compressor(f, g) mingw_fork_compressor((f), (g), "w")
661# endif
662
648 663
649# if !SEAMLESS_COMPRESSION 664# if !SEAMLESS_COMPRESSION
650/* Do not pass gzip flag to writeTarFile() */ 665/* Do not pass gzip flag to writeTarFile() */
@@ -659,16 +674,21 @@ static NOINLINE int writeTarFile(
659 const char *gzip) 674 const char *gzip)
660{ 675{
661 int errorFlag = FALSE; 676 int errorFlag = FALSE;
677# if SEAMLESS_COMPRESSION && ENABLE_PLATFORM_MINGW32
678 pid_t pid = 0;
679# endif
662 680
663 /*tbInfo->hlInfoHead = NULL; - already is */ 681 /*tbInfo->hlInfoHead = NULL; - already is */
664 682
683# if ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA
665 /* Store the stat info for the tarball's file, so 684 /* Store the stat info for the tarball's file, so
666 * can avoid including the tarball into itself.... */ 685 * can avoid including the tarball into itself.... */
667 xfstat(tbInfo->tarFd, &tbInfo->tarFileStatBuf, "can't stat tar file"); 686 xfstat(tbInfo->tarFd, &tbInfo->tarFileStatBuf, "can't stat tar file");
687# endif
668 688
669# if SEAMLESS_COMPRESSION 689# if SEAMLESS_COMPRESSION
670 if (gzip) 690 if (gzip)
671 vfork_compressor(tbInfo->tarFd, gzip); 691 IF_PLATFORM_MINGW32(pid = )vfork_compressor(tbInfo->tarFd, gzip);
672# endif 692# endif
673 693
674 /* Read the directory/files and iterate over them one at a time */ 694 /* Read the directory/files and iterate over them one at a time */
@@ -702,7 +722,11 @@ static NOINLINE int writeTarFile(
702# if SEAMLESS_COMPRESSION 722# if SEAMLESS_COMPRESSION
703 if (gzip) { 723 if (gzip) {
704 int status; 724 int status;
725# if !ENABLE_PLATFORM_MINGW32
705 if (safe_waitpid(-1, &status, 0) == -1) 726 if (safe_waitpid(-1, &status, 0) == -1)
727# else
728 if (safe_waitpid(pid, &status, 0) == -1)
729# endif
706 bb_simple_perror_msg("waitpid"); 730 bb_simple_perror_msg("waitpid");
707 else if (!WIFEXITED(status) || WEXITSTATUS(status)) 731 else if (!WIFEXITED(status) || WEXITSTATUS(status))
708 /* gzip was killed or has exited with nonzero! */ 732 /* gzip was killed or has exited with nonzero! */
diff --git a/archival/unzip.c b/archival/unzip.c
index 71a302915..7b945c250 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -72,6 +72,9 @@
72 72
73#include "libbb.h" 73#include "libbb.h"
74#include "bb_archive.h" 74#include "bb_archive.h"
75#if ENABLE_PLATFORM_MINGW32 && __GNUC__
76#pragma pack(2)
77#endif
75 78
76#if 0 79#if 0
77# define dbg(...) bb_error_msg(__VA_ARGS__) 80# define dbg(...) bb_error_msg(__VA_ARGS__)
@@ -634,7 +637,7 @@ int unzip_main(int argc, char **argv)
634 } 637 }
635 } 638 }
636 639
637#ifndef __GLIBC__ 640#if !defined(__GLIBC__) && !ENABLE_PLATFORM_MINGW32
638 /* 641 /*
639 * This code is needed for non-GNU getopt 642 * This code is needed for non-GNU getopt
640 * which doesn't understand "-" in option string. 643 * which doesn't understand "-" in option string.
diff --git a/configs/make32_defconfig b/configs/make32_defconfig
new file mode 100644
index 000000000..428c16a4e
--- /dev/null
+++ b/configs/make32_defconfig
@@ -0,0 +1,1238 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.37.0.git
4# Wed Sep 20 08:30:38 2023
5#
6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set
8CONFIG_PLATFORM_MINGW32=y
9
10#
11# Settings
12#
13CONFIG_DESKTOP=y
14# CONFIG_EXTRA_COMPAT is not set
15# CONFIG_FEDORA_COMPAT is not set
16# CONFIG_INCLUDE_SUSv2 is not set
17CONFIG_LONG_OPTS=y
18CONFIG_SHOW_USAGE=y
19CONFIG_FEATURE_VERBOSE_USAGE=y
20CONFIG_FEATURE_COMPRESS_USAGE=y
21CONFIG_LFS=y
22CONFIG_TIME64=y
23# CONFIG_PAM is not set
24# CONFIG_FEATURE_DEVPTS is not set
25# CONFIG_FEATURE_UTMP is not set
26# CONFIG_FEATURE_WTMP is not set
27# CONFIG_FEATURE_PIDFILE is not set
28CONFIG_PID_FILE_PATH=""
29# CONFIG_BUSYBOX is not set
30# CONFIG_FEATURE_SHOW_SCRIPT is not set
31# CONFIG_FEATURE_INSTALLER is not set
32# CONFIG_INSTALL_NO_USR is not set
33# CONFIG_FEATURE_SUID is not set
34# CONFIG_FEATURE_SUID_CONFIG is not set
35# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
36CONFIG_FEATURE_PREFER_APPLETS=y
37CONFIG_BUSYBOX_EXEC_PATH=""
38# CONFIG_SELINUX is not set
39# CONFIG_FEATURE_CLEAN_UP is not set
40# CONFIG_FEATURE_SYSLOG_INFO is not set
41# CONFIG_FEATURE_SYSLOG is not set
42
43#
44# Settings for MINGW32
45#
46CONFIG_GLOBBING=y
47CONFIG_FEATURE_PRNG_SHELL=y
48# CONFIG_FEATURE_PRNG_ISAAC is not set
49# CONFIG_FEATURE_RESOURCES is not set
50# CONFIG_FEATURE_VERSIONINFO is not set
51# CONFIG_FEATURE_TOOLCHAIN_MANIFEST is not set
52CONFIG_FEATURE_APP_MANIFEST=y
53# CONFIG_FEATURE_UTF8_MANIFEST is not set
54# CONFIG_FEATURE_ICON is not set
55# CONFIG_FEATURE_ICON_ATERM is not set
56# CONFIG_FEATURE_ICON_STERM is not set
57# CONFIG_FEATURE_ICON_ALL is not set
58# CONFIG_FEATURE_EURO is not set
59# CONFIG_FEATURE_UTF8_INPUT is not set
60# CONFIG_FEATURE_UTF8_OUTPUT is not set
61CONFIG_TERMINAL_MODE=5
62# CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING is not set
63CONFIG_FEATURE_EXTRA_FILE_DATA=y
64
65#
66# Build Options
67#
68# CONFIG_STATIC is not set
69# CONFIG_PIE is not set
70# CONFIG_NOMMU is not set
71# CONFIG_BUILD_LIBBUSYBOX is not set
72# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set
73# CONFIG_FEATURE_INDIVIDUAL is not set
74# CONFIG_FEATURE_SHARED_BUSYBOX is not set
75CONFIG_CROSS_COMPILER_PREFIX="i686-w64-mingw32-"
76CONFIG_SYSROOT=""
77CONFIG_EXTRA_CFLAGS=""
78CONFIG_EXTRA_LDFLAGS=""
79CONFIG_EXTRA_LDLIBS=""
80CONFIG_USE_PORTABLE_CODE=y
81CONFIG_STACK_OPTIMIZATION_386=y
82CONFIG_STATIC_LIBGCC=y
83
84#
85# Installation Options ("make install" behavior)
86#
87CONFIG_INSTALL_APPLET_SYMLINKS=y
88# CONFIG_INSTALL_APPLET_HARDLINKS is not set
89# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
90# CONFIG_INSTALL_APPLET_DONT is not set
91# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
92# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
93# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
94CONFIG_PREFIX=""
95
96#
97# Debugging Options
98#
99# CONFIG_DEBUG is not set
100# CONFIG_DEBUG_PESSIMIZE is not set
101# CONFIG_DEBUG_SANITIZE is not set
102# CONFIG_UNIT_TEST is not set
103# CONFIG_WERROR is not set
104# CONFIG_WARN_SIMPLE_MSG is not set
105CONFIG_NO_DEBUG_LIB=y
106# CONFIG_DMALLOC is not set
107# CONFIG_EFENCE is not set
108
109#
110# Library Tuning
111#
112# CONFIG_FEATURE_USE_BSS_TAIL is not set
113CONFIG_FLOAT_DURATION=y
114# CONFIG_FEATURE_RTMINMAX is not set
115# CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS is not set
116CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
117# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
118# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
119CONFIG_PASSWORD_MINLEN=6
120CONFIG_MD5_SMALL=1
121CONFIG_SHA1_SMALL=3
122# CONFIG_SHA1_HWACCEL is not set
123# CONFIG_SHA256_HWACCEL is not set
124CONFIG_SHA3_SMALL=1
125CONFIG_FEATURE_NON_POSIX_CP=y
126# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
127# CONFIG_FEATURE_USE_SENDFILE is not set
128CONFIG_FEATURE_COPYBUF_KB=4
129# CONFIG_MONOTONIC_SYSCALL is not set
130# CONFIG_IOCTL_HEX2STR_ERROR is not set
131# CONFIG_FEATURE_EDITING is not set
132CONFIG_FEATURE_EDITING_MAX_LEN=0
133# CONFIG_FEATURE_EDITING_VI is not set
134CONFIG_FEATURE_EDITING_HISTORY=0
135# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set
136# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
137# CONFIG_FEATURE_REVERSE_SEARCH is not set
138# CONFIG_FEATURE_TAB_COMPLETION is not set
139# CONFIG_FEATURE_USERNAME_COMPLETION is not set
140# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set
141# CONFIG_FEATURE_EDITING_WINCH is not set
142# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
143# CONFIG_LOCALE_SUPPORT is not set
144# CONFIG_UNICODE_SUPPORT is not set
145# CONFIG_UNICODE_USING_LOCALE is not set
146# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
147CONFIG_SUBST_WCHAR=0
148CONFIG_LAST_SUPPORTED_WCHAR=0
149# CONFIG_UNICODE_COMBINING_WCHARS is not set
150# CONFIG_UNICODE_WIDE_WCHARS is not set
151# CONFIG_UNICODE_BIDI_SUPPORT is not set
152# CONFIG_UNICODE_NEUTRAL_TABLE is not set
153# CONFIG_UNICODE_PRESERVE_BROKEN is not set
154# CONFIG_LOOP_CONFIGURE is not set
155# CONFIG_NO_LOOP_CONFIGURE is not set
156CONFIG_TRY_LOOP_CONFIGURE=y
157
158#
159# Applets
160#
161
162#
163# Archival Utilities
164#
165# CONFIG_FEATURE_SEAMLESS_XZ is not set
166# CONFIG_FEATURE_SEAMLESS_LZMA is not set
167# CONFIG_FEATURE_SEAMLESS_BZ2 is not set
168# CONFIG_FEATURE_SEAMLESS_GZ is not set
169# CONFIG_FEATURE_SEAMLESS_Z is not set
170# CONFIG_AR is not set
171CONFIG_FEATURE_AR_LONG_FILENAMES=y
172# CONFIG_FEATURE_AR_CREATE is not set
173# CONFIG_UNCOMPRESS is not set
174# CONFIG_GUNZIP is not set
175# CONFIG_ZCAT is not set
176# CONFIG_FEATURE_GUNZIP_LONG_OPTIONS is not set
177# CONFIG_BUNZIP2 is not set
178# CONFIG_BZCAT is not set
179# CONFIG_UNLZMA is not set
180# CONFIG_LZCAT is not set
181# CONFIG_LZMA is not set
182# CONFIG_UNXZ is not set
183# CONFIG_XZCAT is not set
184# CONFIG_XZ is not set
185# CONFIG_BZIP2 is not set
186CONFIG_BZIP2_SMALL=0
187# CONFIG_FEATURE_BZIP2_DECOMPRESS is not set
188# CONFIG_CPIO is not set
189# CONFIG_FEATURE_CPIO_O is not set
190# CONFIG_FEATURE_CPIO_P is not set
191# CONFIG_FEATURE_CPIO_IGNORE_DEVNO is not set
192# CONFIG_FEATURE_CPIO_RENUMBER_INODES is not set
193# CONFIG_DPKG is not set
194# CONFIG_DPKG_DEB is not set
195# CONFIG_GZIP is not set
196# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set
197CONFIG_GZIP_FAST=0
198# CONFIG_FEATURE_GZIP_LEVELS is not set
199# CONFIG_FEATURE_GZIP_DECOMPRESS is not set
200# CONFIG_LZOP is not set
201# CONFIG_UNLZOP is not set
202# CONFIG_LZOPCAT is not set
203# CONFIG_LZOP_COMPR_HIGH is not set
204# CONFIG_RPM is not set
205# CONFIG_RPM2CPIO is not set
206# CONFIG_TAR is not set
207# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set
208# CONFIG_FEATURE_TAR_CREATE is not set
209# CONFIG_FEATURE_TAR_AUTODETECT is not set
210# CONFIG_FEATURE_TAR_FROM is not set
211# CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY is not set
212# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
213# CONFIG_FEATURE_TAR_GNU_EXTENSIONS is not set
214# CONFIG_FEATURE_TAR_TO_COMMAND is not set
215# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
216# CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set
217# CONFIG_FEATURE_TAR_SELINUX is not set
218# CONFIG_UNZIP is not set
219# CONFIG_FEATURE_UNZIP_CDF is not set
220# CONFIG_FEATURE_UNZIP_BZIP2 is not set
221# CONFIG_FEATURE_UNZIP_LZMA is not set
222# CONFIG_FEATURE_UNZIP_XZ is not set
223# CONFIG_FEATURE_LZMA_FAST is not set
224
225#
226# Coreutils
227#
228CONFIG_FEATURE_VERBOSE=y
229
230#
231# Common options for date and touch
232#
233# CONFIG_FEATURE_TIMEZONE is not set
234# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
235# CONFIG_FEATURE_HUMAN_READABLE is not set
236# CONFIG_BASENAME is not set
237# CONFIG_CAT is not set
238# CONFIG_FEATURE_CATN is not set
239# CONFIG_FEATURE_CATV is not set
240# CONFIG_CHGRP is not set
241# CONFIG_CHMOD is not set
242# CONFIG_CHOWN is not set
243# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
244# CONFIG_CHROOT is not set
245# CONFIG_CKSUM is not set
246# CONFIG_CRC32 is not set
247# CONFIG_COMM is not set
248# CONFIG_CP is not set
249# CONFIG_FEATURE_CP_LONG_OPTIONS is not set
250# CONFIG_FEATURE_CP_REFLINK is not set
251# CONFIG_CUT is not set
252# CONFIG_FEATURE_CUT_REGEX is not set
253# CONFIG_DATE is not set
254# CONFIG_FEATURE_DATE_ISOFMT is not set
255# CONFIG_FEATURE_DATE_NANO is not set
256# CONFIG_FEATURE_DATE_COMPAT is not set
257# CONFIG_DD is not set
258# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
259# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
260# CONFIG_FEATURE_DD_IBS_OBS is not set
261# CONFIG_FEATURE_DD_STATUS is not set
262# CONFIG_DF is not set
263# CONFIG_FEATURE_DF_FANCY is not set
264# CONFIG_FEATURE_SKIP_ROOTFS is not set
265# CONFIG_DIRNAME is not set
266# CONFIG_DOS2UNIX is not set
267# CONFIG_UNIX2DOS is not set
268# CONFIG_DU is not set
269# CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K is not set
270# CONFIG_ECHO is not set
271CONFIG_FEATURE_FANCY_ECHO=y
272# CONFIG_ENV is not set
273# CONFIG_EXPAND is not set
274# CONFIG_UNEXPAND is not set
275# CONFIG_EXPR is not set
276# CONFIG_EXPR_MATH_SUPPORT_64 is not set
277# CONFIG_FACTOR is not set
278# CONFIG_FALSE is not set
279# CONFIG_FOLD is not set
280# CONFIG_HEAD is not set
281# CONFIG_FEATURE_FANCY_HEAD is not set
282# CONFIG_HOSTID is not set
283# CONFIG_ID is not set
284# CONFIG_GROUPS is not set
285# CONFIG_INSTALL is not set
286# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
287# CONFIG_LINK is not set
288# CONFIG_LN is not set
289# CONFIG_LOGNAME is not set
290# CONFIG_LS is not set
291# CONFIG_FEATURE_LS_FILETYPES is not set
292# CONFIG_FEATURE_LS_FOLLOWLINKS is not set
293# CONFIG_FEATURE_LS_RECURSIVE is not set
294# CONFIG_FEATURE_LS_WIDTH is not set
295# CONFIG_FEATURE_LS_SORTFILES is not set
296# CONFIG_FEATURE_LS_TIMESTAMPS is not set
297# CONFIG_FEATURE_LS_USERNAME is not set
298# CONFIG_FEATURE_LS_COLOR is not set
299# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set
300# CONFIG_MD5SUM is not set
301# CONFIG_SHA1SUM is not set
302# CONFIG_SHA256SUM is not set
303# CONFIG_SHA512SUM is not set
304# CONFIG_SHA3SUM is not set
305# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set
306# CONFIG_MKDIR is not set
307# CONFIG_MKFIFO is not set
308# CONFIG_MKNOD is not set
309# CONFIG_MKTEMP is not set
310# CONFIG_MV is not set
311# CONFIG_NICE is not set
312# CONFIG_NL is not set
313# CONFIG_NOHUP is not set
314# CONFIG_NPROC is not set
315# CONFIG_OD is not set
316# CONFIG_PASTE is not set
317# CONFIG_PRINTENV is not set
318# CONFIG_PRINTF is not set
319# CONFIG_PWD is not set
320# CONFIG_READLINK is not set
321# CONFIG_FEATURE_READLINK_FOLLOW is not set
322# CONFIG_REALPATH is not set
323# CONFIG_RM is not set
324# CONFIG_RMDIR is not set
325# CONFIG_SEQ is not set
326# CONFIG_SHRED is not set
327# CONFIG_SHUF is not set
328# CONFIG_SLEEP is not set
329# CONFIG_FEATURE_FANCY_SLEEP is not set
330# CONFIG_SORT is not set
331# CONFIG_FEATURE_SORT_BIG is not set
332# CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set
333# CONFIG_SPLIT is not set
334# CONFIG_FEATURE_SPLIT_FANCY is not set
335# CONFIG_STAT is not set
336# CONFIG_FEATURE_STAT_FORMAT is not set
337# CONFIG_FEATURE_STAT_FILESYSTEM is not set
338# CONFIG_STTY is not set
339# CONFIG_SUM is not set
340# CONFIG_SYNC is not set
341# CONFIG_FEATURE_SYNC_FANCY is not set
342# CONFIG_FSYNC is not set
343# CONFIG_TAC is not set
344# CONFIG_TAIL is not set
345# CONFIG_FEATURE_FANCY_TAIL is not set
346# CONFIG_TEE is not set
347# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set
348# CONFIG_TEST is not set
349# CONFIG_TEST1 is not set
350# CONFIG_TEST2 is not set
351CONFIG_FEATURE_TEST_64=y
352# CONFIG_TIMEOUT is not set
353# CONFIG_TOUCH is not set
354# CONFIG_FEATURE_TOUCH_SUSV3 is not set
355# CONFIG_TR is not set
356# CONFIG_FEATURE_TR_CLASSES is not set
357# CONFIG_FEATURE_TR_EQUIV is not set
358# CONFIG_TRUE is not set
359# CONFIG_TRUNCATE is not set
360# CONFIG_TSORT is not set
361# CONFIG_TTY is not set
362# CONFIG_UNAME is not set
363CONFIG_UNAME_OSNAME=""
364# CONFIG_BB_ARCH is not set
365# CONFIG_UNIQ is not set
366# CONFIG_UNLINK is not set
367# CONFIG_USLEEP is not set
368# CONFIG_UUDECODE is not set
369# CONFIG_BASE32 is not set
370# CONFIG_BASE64 is not set
371# CONFIG_UUENCODE is not set
372# CONFIG_WC is not set
373# CONFIG_FEATURE_WC_LARGE is not set
374# CONFIG_WHO is not set
375# CONFIG_W is not set
376# CONFIG_USERS is not set
377# CONFIG_WHOAMI is not set
378# CONFIG_YES is not set
379
380#
381# Console Utilities
382#
383# CONFIG_CHVT is not set
384# CONFIG_CLEAR is not set
385# CONFIG_DEALLOCVT is not set
386# CONFIG_DUMPKMAP is not set
387# CONFIG_FGCONSOLE is not set
388# CONFIG_KBD_MODE is not set
389# CONFIG_LOADFONT is not set
390# CONFIG_SETFONT is not set
391# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
392CONFIG_DEFAULT_SETFONT_DIR=""
393# CONFIG_FEATURE_LOADFONT_PSF2 is not set
394# CONFIG_FEATURE_LOADFONT_RAW is not set
395# CONFIG_LOADKMAP is not set
396# CONFIG_OPENVT is not set
397# CONFIG_RESET is not set
398# CONFIG_RESIZE is not set
399# CONFIG_FEATURE_RESIZE_PRINT is not set
400# CONFIG_SETCONSOLE is not set
401# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
402# CONFIG_SETKEYCODES is not set
403# CONFIG_SETLOGCONS is not set
404# CONFIG_SHOWKEY is not set
405
406#
407# Debian Utilities
408#
409# CONFIG_PIPE_PROGRESS is not set
410# CONFIG_RUN_PARTS is not set
411# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
412# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
413# CONFIG_START_STOP_DAEMON is not set
414# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
415# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
416# CONFIG_WHICH is not set
417
418#
419# klibc-utils
420#
421# CONFIG_MINIPS is not set
422# CONFIG_NUKE is not set
423# CONFIG_RESUME is not set
424# CONFIG_RUN_INIT is not set
425
426#
427# Editors
428#
429# CONFIG_AWK is not set
430# CONFIG_FEATURE_AWK_LIBM is not set
431# CONFIG_FEATURE_AWK_GNU_EXTENSIONS is not set
432# CONFIG_CMP is not set
433# CONFIG_DIFF is not set
434# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set
435# CONFIG_FEATURE_DIFF_DIR is not set
436# CONFIG_ED is not set
437# CONFIG_PATCH is not set
438# CONFIG_SED is not set
439# CONFIG_VI is not set
440CONFIG_FEATURE_VI_MAX_LEN=0
441# CONFIG_FEATURE_VI_8BIT is not set
442# CONFIG_FEATURE_VI_COLON is not set
443# CONFIG_FEATURE_VI_COLON_EXPAND is not set
444# CONFIG_FEATURE_VI_YANKMARK is not set
445# CONFIG_FEATURE_VI_SEARCH is not set
446# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
447# CONFIG_FEATURE_VI_USE_SIGNALS is not set
448# CONFIG_FEATURE_VI_DOT_CMD is not set
449# CONFIG_FEATURE_VI_READONLY is not set
450# CONFIG_FEATURE_VI_SETOPTS is not set
451# CONFIG_FEATURE_VI_FILE_FORMAT is not set
452# CONFIG_FEATURE_VI_SET is not set
453# CONFIG_FEATURE_VI_WIN_RESIZE is not set
454# CONFIG_FEATURE_VI_ASK_TERMINAL is not set
455# CONFIG_FEATURE_VI_UNDO is not set
456# CONFIG_FEATURE_VI_UNDO_QUEUE is not set
457CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=0
458# CONFIG_FEATURE_VI_VERBOSE_STATUS is not set
459# CONFIG_FEATURE_ALLOW_EXEC is not set
460
461#
462# Finding Utilities
463#
464# CONFIG_FIND is not set
465# CONFIG_FEATURE_FIND_PRINT0 is not set
466# CONFIG_FEATURE_FIND_MTIME is not set
467# CONFIG_FEATURE_FIND_ATIME is not set
468# CONFIG_FEATURE_FIND_CTIME is not set
469# CONFIG_FEATURE_FIND_MMIN is not set
470# CONFIG_FEATURE_FIND_AMIN is not set
471# CONFIG_FEATURE_FIND_CMIN is not set
472# CONFIG_FEATURE_FIND_PERM is not set
473# CONFIG_FEATURE_FIND_TYPE is not set
474# CONFIG_FEATURE_FIND_EXECUTABLE is not set
475# CONFIG_FEATURE_FIND_XDEV is not set
476# CONFIG_FEATURE_FIND_MAXDEPTH is not set
477# CONFIG_FEATURE_FIND_NEWER is not set
478# CONFIG_FEATURE_FIND_INUM is not set
479# CONFIG_FEATURE_FIND_SAMEFILE is not set
480# CONFIG_FEATURE_FIND_EXEC is not set
481# CONFIG_FEATURE_FIND_EXEC_PLUS is not set
482# CONFIG_FEATURE_FIND_EXEC_OK is not set
483# CONFIG_FEATURE_FIND_USER is not set
484# CONFIG_FEATURE_FIND_GROUP is not set
485# CONFIG_FEATURE_FIND_NOT is not set
486# CONFIG_FEATURE_FIND_DEPTH is not set
487# CONFIG_FEATURE_FIND_PAREN is not set
488# CONFIG_FEATURE_FIND_SIZE is not set
489# CONFIG_FEATURE_FIND_PRUNE is not set
490# CONFIG_FEATURE_FIND_QUIT is not set
491# CONFIG_FEATURE_FIND_DELETE is not set
492# CONFIG_FEATURE_FIND_EMPTY is not set
493# CONFIG_FEATURE_FIND_PATH is not set
494# CONFIG_FEATURE_FIND_REGEX is not set
495# CONFIG_FEATURE_FIND_CONTEXT is not set
496# CONFIG_FEATURE_FIND_LINKS is not set
497# CONFIG_GREP is not set
498# CONFIG_EGREP is not set
499# CONFIG_FGREP is not set
500# CONFIG_FEATURE_GREP_CONTEXT is not set
501# CONFIG_XARGS is not set
502# CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION is not set
503# CONFIG_FEATURE_XARGS_SUPPORT_QUOTES is not set
504# CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT is not set
505# CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM is not set
506# CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR is not set
507# CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL is not set
508# CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE is not set
509
510#
511# Init Utilities
512#
513# CONFIG_BOOTCHARTD is not set
514# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
515# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
516# CONFIG_HALT is not set
517# CONFIG_POWEROFF is not set
518# CONFIG_REBOOT is not set
519# CONFIG_FEATURE_WAIT_FOR_INIT is not set
520# CONFIG_FEATURE_CALL_TELINIT is not set
521CONFIG_TELINIT_PATH=""
522# CONFIG_INIT is not set
523# CONFIG_LINUXRC is not set
524# CONFIG_FEATURE_USE_INITTAB is not set
525# CONFIG_FEATURE_KILL_REMOVED is not set
526CONFIG_FEATURE_KILL_DELAY=0
527# CONFIG_FEATURE_INIT_SCTTY is not set
528# CONFIG_FEATURE_INIT_SYSLOG is not set
529# CONFIG_FEATURE_INIT_QUIET is not set
530# CONFIG_FEATURE_INIT_COREDUMPS is not set
531CONFIG_INIT_TERMINAL_TYPE=""
532# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
533
534#
535# Login/Password Management Utilities
536#
537# CONFIG_FEATURE_SHADOWPASSWDS is not set
538# CONFIG_USE_BB_PWD_GRP is not set
539# CONFIG_USE_BB_SHADOW is not set
540# CONFIG_USE_BB_CRYPT is not set
541# CONFIG_USE_BB_CRYPT_SHA is not set
542# CONFIG_ADD_SHELL is not set
543# CONFIG_REMOVE_SHELL is not set
544# CONFIG_ADDGROUP is not set
545# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
546# CONFIG_ADDUSER is not set
547# CONFIG_FEATURE_CHECK_NAMES is not set
548CONFIG_LAST_ID=0
549CONFIG_FIRST_SYSTEM_ID=0
550CONFIG_LAST_SYSTEM_ID=0
551# CONFIG_CHPASSWD is not set
552CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
553# CONFIG_CRYPTPW is not set
554# CONFIG_MKPASSWD is not set
555# CONFIG_DELUSER is not set
556# CONFIG_DELGROUP is not set
557# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
558# CONFIG_GETTY is not set
559# CONFIG_LOGIN is not set
560# CONFIG_LOGIN_SESSION_AS_CHILD is not set
561# CONFIG_LOGIN_SCRIPTS is not set
562# CONFIG_FEATURE_NOLOGIN is not set
563# CONFIG_FEATURE_SECURETTY is not set
564# CONFIG_PASSWD is not set
565# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
566# CONFIG_SU is not set
567# CONFIG_FEATURE_SU_SYSLOG is not set
568# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
569# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set
570# CONFIG_SULOGIN is not set
571# CONFIG_SUW32 is not set
572# CONFIG_VLOCK is not set
573
574#
575# Linux Ext2 FS Progs
576#
577# CONFIG_CHATTR is not set
578# CONFIG_FSCK is not set
579# CONFIG_LSATTR is not set
580# CONFIG_TUNE2FS is not set
581
582#
583# Linux Module Utilities
584#
585# CONFIG_MODPROBE_SMALL is not set
586# CONFIG_DEPMOD is not set
587# CONFIG_INSMOD is not set
588# CONFIG_LSMOD is not set
589# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
590# CONFIG_MODINFO is not set
591# CONFIG_MODPROBE is not set
592# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
593# CONFIG_RMMOD is not set
594
595#
596# Options common to multiple modutils
597#
598# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set
599# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
600# CONFIG_FEATURE_2_4_MODULES is not set
601# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
602# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
603# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
604# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
605# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
606# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
607# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
608# CONFIG_FEATURE_MODUTILS_ALIAS is not set
609# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
610CONFIG_DEFAULT_MODULES_DIR=""
611CONFIG_DEFAULT_DEPMOD_FILE=""
612
613#
614# Linux System Utilities
615#
616# CONFIG_ACPID is not set
617# CONFIG_FEATURE_ACPID_COMPAT is not set
618# CONFIG_BLKDISCARD is not set
619# CONFIG_BLKID is not set
620# CONFIG_FEATURE_BLKID_TYPE is not set
621# CONFIG_BLOCKDEV is not set
622# CONFIG_CAL is not set
623# CONFIG_CHRT is not set
624# CONFIG_DMESG is not set
625# CONFIG_FEATURE_DMESG_PRETTY is not set
626# CONFIG_EJECT is not set
627# CONFIG_FEATURE_EJECT_SCSI is not set
628# CONFIG_FALLOCATE is not set
629# CONFIG_FATATTR is not set
630# CONFIG_FBSET is not set
631# CONFIG_FEATURE_FBSET_FANCY is not set
632# CONFIG_FEATURE_FBSET_READMODE is not set
633# CONFIG_FDFORMAT is not set
634# CONFIG_FDISK is not set
635# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
636# CONFIG_FEATURE_FDISK_WRITABLE is not set
637# CONFIG_FEATURE_AIX_LABEL is not set
638# CONFIG_FEATURE_SGI_LABEL is not set
639# CONFIG_FEATURE_SUN_LABEL is not set
640# CONFIG_FEATURE_OSF_LABEL is not set
641# CONFIG_FEATURE_GPT_LABEL is not set
642# CONFIG_FEATURE_FDISK_ADVANCED is not set
643# CONFIG_FINDFS is not set
644# CONFIG_FLOCK is not set
645# CONFIG_FDFLUSH is not set
646# CONFIG_FREERAMDISK is not set
647# CONFIG_FSCK_MINIX is not set
648# CONFIG_FSFREEZE is not set
649# CONFIG_FSTRIM is not set
650# CONFIG_GETOPT is not set
651# CONFIG_FEATURE_GETOPT_LONG is not set
652# CONFIG_HEXDUMP is not set
653# CONFIG_HD is not set
654# CONFIG_XXD is not set
655# CONFIG_HWCLOCK is not set
656# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
657# CONFIG_IONICE is not set
658# CONFIG_IPCRM is not set
659# CONFIG_IPCS is not set
660# CONFIG_LAST is not set
661# CONFIG_FEATURE_LAST_FANCY is not set
662# CONFIG_LOSETUP is not set
663# CONFIG_LSPCI is not set
664# CONFIG_LSUSB is not set
665# CONFIG_MDEV is not set
666# CONFIG_FEATURE_MDEV_CONF is not set
667# CONFIG_FEATURE_MDEV_RENAME is not set
668# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
669# CONFIG_FEATURE_MDEV_EXEC is not set
670# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
671# CONFIG_FEATURE_MDEV_DAEMON is not set
672# CONFIG_MESG is not set
673# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
674# CONFIG_MKE2FS is not set
675# CONFIG_MKFS_EXT2 is not set
676# CONFIG_MKFS_MINIX is not set
677# CONFIG_FEATURE_MINIX2 is not set
678# CONFIG_MKFS_REISER is not set
679# CONFIG_MKDOSFS is not set
680# CONFIG_MKFS_VFAT is not set
681# CONFIG_MKSWAP is not set
682# CONFIG_FEATURE_MKSWAP_UUID is not set
683# CONFIG_MORE is not set
684# CONFIG_MOUNT is not set
685# CONFIG_FEATURE_MOUNT_FAKE is not set
686# CONFIG_FEATURE_MOUNT_VERBOSE is not set
687# CONFIG_FEATURE_MOUNT_HELPERS is not set
688# CONFIG_FEATURE_MOUNT_LABEL is not set
689# CONFIG_FEATURE_MOUNT_NFS is not set
690# CONFIG_FEATURE_MOUNT_CIFS is not set
691# CONFIG_FEATURE_MOUNT_FLAGS is not set
692# CONFIG_FEATURE_MOUNT_FSTAB is not set
693# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
694# CONFIG_MOUNTPOINT is not set
695# CONFIG_NOLOGIN is not set
696# CONFIG_NOLOGIN_DEPENDENCIES is not set
697# CONFIG_NSENTER is not set
698# CONFIG_PIVOT_ROOT is not set
699# CONFIG_RDATE is not set
700# CONFIG_RDEV is not set
701# CONFIG_READPROFILE is not set
702# CONFIG_RENICE is not set
703# CONFIG_REV is not set
704# CONFIG_RTCWAKE is not set
705# CONFIG_SCRIPT is not set
706# CONFIG_SCRIPTREPLAY is not set
707# CONFIG_SETARCH is not set
708# CONFIG_LINUX32 is not set
709# CONFIG_LINUX64 is not set
710# CONFIG_SETPRIV is not set
711# CONFIG_FEATURE_SETPRIV_DUMP is not set
712# CONFIG_FEATURE_SETPRIV_CAPABILITIES is not set
713# CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES is not set
714# CONFIG_SETSID is not set
715# CONFIG_SWAPON is not set
716# CONFIG_FEATURE_SWAPON_DISCARD is not set
717# CONFIG_FEATURE_SWAPON_PRI is not set
718# CONFIG_SWAPOFF is not set
719# CONFIG_FEATURE_SWAPONOFF_LABEL is not set
720# CONFIG_SWITCH_ROOT is not set
721# CONFIG_TASKSET is not set
722# CONFIG_FEATURE_TASKSET_FANCY is not set
723# CONFIG_FEATURE_TASKSET_CPULIST is not set
724# CONFIG_UEVENT is not set
725# CONFIG_UMOUNT is not set
726# CONFIG_FEATURE_UMOUNT_ALL is not set
727# CONFIG_UNSHARE is not set
728# CONFIG_WALL is not set
729# CONFIG_FEATURE_MOUNT_LOOP is not set
730# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
731# CONFIG_FEATURE_MTAB_SUPPORT is not set
732# CONFIG_VOLUMEID is not set
733# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
734# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
735# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
736# CONFIG_FEATURE_VOLUMEID_EROFS is not set
737# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
738# CONFIG_FEATURE_VOLUMEID_EXT is not set
739# CONFIG_FEATURE_VOLUMEID_F2FS is not set
740# CONFIG_FEATURE_VOLUMEID_FAT is not set
741# CONFIG_FEATURE_VOLUMEID_HFS is not set
742# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
743# CONFIG_FEATURE_VOLUMEID_JFS is not set
744# CONFIG_FEATURE_VOLUMEID_LFS is not set
745# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
746# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
747# CONFIG_FEATURE_VOLUMEID_LUKS is not set
748# CONFIG_FEATURE_VOLUMEID_MINIX is not set
749# CONFIG_FEATURE_VOLUMEID_NILFS is not set
750# CONFIG_FEATURE_VOLUMEID_NTFS is not set
751# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
752# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
753# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
754# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
755# CONFIG_FEATURE_VOLUMEID_SYSV is not set
756# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
757# CONFIG_FEATURE_VOLUMEID_UDF is not set
758# CONFIG_FEATURE_VOLUMEID_XFS is not set
759
760#
761# Miscellaneous Utilities
762#
763# CONFIG_ADJTIMEX is not set
764# CONFIG_ASCII is not set
765# CONFIG_BBCONFIG is not set
766# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
767# CONFIG_BC is not set
768# CONFIG_DC is not set
769# CONFIG_FEATURE_DC_BIG is not set
770# CONFIG_FEATURE_DC_LIBM is not set
771# CONFIG_FEATURE_BC_INTERACTIVE is not set
772# CONFIG_FEATURE_BC_LONG_OPTIONS is not set
773# CONFIG_BEEP is not set
774CONFIG_FEATURE_BEEP_FREQ=0
775CONFIG_FEATURE_BEEP_LENGTH_MS=0
776# CONFIG_CHAT is not set
777# CONFIG_FEATURE_CHAT_NOFAIL is not set
778# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
779# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
780# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
781# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
782# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
783# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
784# CONFIG_CONSPY is not set
785# CONFIG_CROND is not set
786# CONFIG_FEATURE_CROND_D is not set
787# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
788# CONFIG_FEATURE_CROND_SPECIAL_TIMES is not set
789CONFIG_FEATURE_CROND_DIR=""
790# CONFIG_CRONTAB is not set
791# CONFIG_DEVFSD is not set
792# CONFIG_DEVFSD_MODLOAD is not set
793# CONFIG_DEVFSD_FG_NP is not set
794# CONFIG_DEVFSD_VERBOSE is not set
795# CONFIG_FEATURE_DEVFS is not set
796# CONFIG_DEVMEM is not set
797# CONFIG_DROP is not set
798# CONFIG_CDROP is not set
799# CONFIG_PDROP is not set
800# CONFIG_FBSPLASH is not set
801# CONFIG_FLASH_ERASEALL is not set
802# CONFIG_FLASH_LOCK is not set
803# CONFIG_FLASH_UNLOCK is not set
804# CONFIG_FLASHCP is not set
805# CONFIG_GETFATTR is not set
806# CONFIG_HDPARM is not set
807# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
808# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
809# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
810# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
811# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
812# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
813# CONFIG_HEXEDIT is not set
814# CONFIG_I2CGET is not set
815# CONFIG_I2CSET is not set
816# CONFIG_I2CDUMP is not set
817# CONFIG_I2CDETECT is not set
818# CONFIG_I2CTRANSFER is not set
819# CONFIG_ICONV is not set
820# CONFIG_INOTIFYD is not set
821# CONFIG_JN is not set
822# CONFIG_LESS is not set
823CONFIG_FEATURE_LESS_MAXLINES=0
824# CONFIG_FEATURE_LESS_BRACKETS is not set
825# CONFIG_FEATURE_LESS_FLAGS is not set
826# CONFIG_FEATURE_LESS_TRUNCATE is not set
827# CONFIG_FEATURE_LESS_MARKS is not set
828# CONFIG_FEATURE_LESS_REGEXP is not set
829# CONFIG_FEATURE_LESS_WINCH is not set
830# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
831# CONFIG_FEATURE_LESS_DASHCMD is not set
832# CONFIG_FEATURE_LESS_LINENUMS is not set
833# CONFIG_FEATURE_LESS_RAW is not set
834# CONFIG_FEATURE_LESS_ENV is not set
835# CONFIG_LSSCSI is not set
836CONFIG_MAKE=y
837CONFIG_PDPMAKE=y
838CONFIG_FEATURE_MAKE_POSIX=y
839# CONFIG_MAKEDEVS is not set
840# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
841# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
842# CONFIG_MAN is not set
843# CONFIG_MICROCOM is not set
844# CONFIG_MIM is not set
845# CONFIG_MT is not set
846# CONFIG_NANDWRITE is not set
847# CONFIG_NANDDUMP is not set
848# CONFIG_PARTPROBE is not set
849# CONFIG_RAIDAUTORUN is not set
850# CONFIG_READAHEAD is not set
851# CONFIG_RFKILL is not set
852# CONFIG_RUNLEVEL is not set
853# CONFIG_RX is not set
854# CONFIG_SEEDRNG is not set
855# CONFIG_SETFATTR is not set
856# CONFIG_SETSERIAL is not set
857# CONFIG_STRINGS is not set
858# CONFIG_TIME is not set
859# CONFIG_TREE is not set
860# CONFIG_TS is not set
861# CONFIG_TTYSIZE is not set
862# CONFIG_UBIATTACH is not set
863# CONFIG_UBIDETACH is not set
864# CONFIG_UBIMKVOL is not set
865# CONFIG_UBIRMVOL is not set
866# CONFIG_UBIRSVOL is not set
867# CONFIG_UBIUPDATEVOL is not set
868# CONFIG_UBIRENAME is not set
869# CONFIG_VOLNAME is not set
870# CONFIG_WATCHDOG is not set
871# CONFIG_FEATURE_WATCHDOG_OPEN_TWICE is not set
872
873#
874# Networking Utilities
875#
876# CONFIG_FEATURE_IPV6 is not set
877# CONFIG_FEATURE_UNIX_LOCAL is not set
878# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set
879# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
880# CONFIG_FEATURE_ETC_NETWORKS is not set
881# CONFIG_FEATURE_ETC_SERVICES is not set
882# CONFIG_FEATURE_HWIB is not set
883# CONFIG_FEATURE_TLS_SHA1 is not set
884# CONFIG_ARP is not set
885# CONFIG_ARPING is not set
886# CONFIG_BRCTL is not set
887# CONFIG_FEATURE_BRCTL_FANCY is not set
888# CONFIG_FEATURE_BRCTL_SHOW is not set
889# CONFIG_DNSD is not set
890# CONFIG_ETHER_WAKE is not set
891# CONFIG_FTPD is not set
892# CONFIG_FEATURE_FTPD_WRITE is not set
893# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
894# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
895# CONFIG_FTPGET is not set
896# CONFIG_FTPPUT is not set
897# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set
898# CONFIG_HOSTNAME is not set
899# CONFIG_DNSDOMAINNAME is not set
900# CONFIG_HTTPD is not set
901CONFIG_FEATURE_HTTPD_PORT_DEFAULT=0
902# CONFIG_FEATURE_HTTPD_RANGES is not set
903# CONFIG_FEATURE_HTTPD_SETUID is not set
904# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
905# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
906# CONFIG_FEATURE_HTTPD_CGI is not set
907# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
908# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
909# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
910# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
911# CONFIG_FEATURE_HTTPD_PROXY is not set
912# CONFIG_FEATURE_HTTPD_GZIP is not set
913# CONFIG_FEATURE_HTTPD_ETAG is not set
914# CONFIG_FEATURE_HTTPD_LAST_MODIFIED is not set
915# CONFIG_FEATURE_HTTPD_DATE is not set
916# CONFIG_FEATURE_HTTPD_ACL_IP is not set
917# CONFIG_IFCONFIG is not set
918# CONFIG_FEATURE_IFCONFIG_STATUS is not set
919# CONFIG_FEATURE_IFCONFIG_SLIP is not set
920# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
921# CONFIG_FEATURE_IFCONFIG_HW is not set
922# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
923# CONFIG_IFENSLAVE is not set
924# CONFIG_IFPLUGD is not set
925# CONFIG_IFUP is not set
926# CONFIG_IFDOWN is not set
927CONFIG_IFUPDOWN_IFSTATE_PATH=""
928# CONFIG_FEATURE_IFUPDOWN_IP is not set
929# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
930# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
931# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
932# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
933# CONFIG_INETD is not set
934# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
935# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
936# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
937# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
938# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
939# CONFIG_FEATURE_INETD_RPC is not set
940# CONFIG_IP is not set
941# CONFIG_IPADDR is not set
942# CONFIG_IPLINK is not set
943# CONFIG_IPROUTE is not set
944# CONFIG_IPTUNNEL is not set
945# CONFIG_IPRULE is not set
946# CONFIG_IPNEIGH is not set
947# CONFIG_FEATURE_IP_ADDRESS is not set
948# CONFIG_FEATURE_IP_LINK is not set
949# CONFIG_FEATURE_IP_ROUTE is not set
950CONFIG_FEATURE_IP_ROUTE_DIR=""
951# CONFIG_FEATURE_IP_TUNNEL is not set
952# CONFIG_FEATURE_IP_RULE is not set
953# CONFIG_FEATURE_IP_NEIGH is not set
954# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
955# CONFIG_IPCALC is not set
956# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set
957# CONFIG_FEATURE_IPCALC_FANCY is not set
958# CONFIG_FAKEIDENTD is not set
959# CONFIG_NAMEIF is not set
960# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
961# CONFIG_NBDCLIENT is not set
962# CONFIG_NC is not set
963# CONFIG_NETCAT is not set
964# CONFIG_NC_SERVER is not set
965# CONFIG_NC_EXTRA is not set
966# CONFIG_NC_110_COMPAT is not set
967# CONFIG_NETSTAT is not set
968# CONFIG_FEATURE_NETSTAT_WIDE is not set
969# CONFIG_FEATURE_NETSTAT_PRG is not set
970# CONFIG_NSLOOKUP is not set
971# CONFIG_FEATURE_NSLOOKUP_BIG is not set
972# CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS is not set
973# CONFIG_NTPD is not set
974# CONFIG_FEATURE_NTPD_SERVER is not set
975# CONFIG_FEATURE_NTPD_CONF is not set
976# CONFIG_FEATURE_NTP_AUTH is not set
977# CONFIG_PING is not set
978# CONFIG_PING6 is not set
979# CONFIG_FEATURE_FANCY_PING is not set
980# CONFIG_PSCAN is not set
981# CONFIG_ROUTE is not set
982# CONFIG_SLATTACH is not set
983# CONFIG_SSL_CLIENT is not set
984# CONFIG_TC is not set
985# CONFIG_FEATURE_TC_INGRESS is not set
986# CONFIG_TCPSVD is not set
987# CONFIG_UDPSVD is not set
988# CONFIG_TELNET is not set
989# CONFIG_FEATURE_TELNET_TTYPE is not set
990# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
991# CONFIG_FEATURE_TELNET_WIDTH is not set
992# CONFIG_TELNETD is not set
993# CONFIG_FEATURE_TELNETD_STANDALONE is not set
994CONFIG_FEATURE_TELNETD_PORT_DEFAULT=0
995# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
996# CONFIG_TFTP is not set
997# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
998# CONFIG_FEATURE_TFTP_HPA_COMPAT is not set
999# CONFIG_TFTPD is not set
1000# CONFIG_FEATURE_TFTP_GET is not set
1001# CONFIG_FEATURE_TFTP_PUT is not set
1002# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
1003# CONFIG_TFTP_DEBUG is not set
1004# CONFIG_TLS is not set
1005# CONFIG_TRACEROUTE is not set
1006# CONFIG_TRACEROUTE6 is not set
1007# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
1008# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
1009# CONFIG_TUNCTL is not set
1010# CONFIG_FEATURE_TUNCTL_UG is not set
1011# CONFIG_VCONFIG is not set
1012# CONFIG_WGET is not set
1013# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set
1014# CONFIG_FEATURE_WGET_STATUSBAR is not set
1015# CONFIG_FEATURE_WGET_FTP is not set
1016# CONFIG_FEATURE_WGET_AUTHENTICATION is not set
1017# CONFIG_FEATURE_WGET_TIMEOUT is not set
1018# CONFIG_FEATURE_WGET_HTTPS is not set
1019# CONFIG_FEATURE_WGET_OPENSSL is not set
1020# CONFIG_WHOIS is not set
1021# CONFIG_ZCIP is not set
1022# CONFIG_UDHCPD is not set
1023# CONFIG_FEATURE_UDHCPD_BOOTP is not set
1024# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
1025# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
1026CONFIG_DHCPD_LEASES_FILE=""
1027# CONFIG_DUMPLEASES is not set
1028# CONFIG_DHCPRELAY is not set
1029# CONFIG_UDHCPC is not set
1030# CONFIG_FEATURE_UDHCPC_ARPING is not set
1031# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
1032CONFIG_UDHCPC_DEFAULT_SCRIPT=""
1033CONFIG_UDHCPC6_DEFAULT_SCRIPT=""
1034# CONFIG_UDHCPC6 is not set
1035# CONFIG_FEATURE_UDHCPC6_RFC3646 is not set
1036# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set
1037# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set
1038# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set
1039CONFIG_UDHCPC_DEFAULT_INTERFACE=""
1040# CONFIG_FEATURE_UDHCP_PORT is not set
1041CONFIG_UDHCP_DEBUG=0
1042CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
1043# CONFIG_FEATURE_UDHCP_RFC3397 is not set
1044# CONFIG_FEATURE_UDHCP_8021Q is not set
1045CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
1046
1047#
1048# Print Utilities
1049#
1050# CONFIG_LPD is not set
1051# CONFIG_LPR is not set
1052# CONFIG_LPQ is not set
1053
1054#
1055# Mail Utilities
1056#
1057CONFIG_FEATURE_MIME_CHARSET=""
1058# CONFIG_MAKEMIME is not set
1059# CONFIG_POPMAILDIR is not set
1060# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
1061# CONFIG_REFORMIME is not set
1062# CONFIG_FEATURE_REFORMIME_COMPAT is not set
1063# CONFIG_SENDMAIL is not set
1064
1065#
1066# Process Utilities
1067#
1068# CONFIG_FEATURE_FAST_TOP is not set
1069# CONFIG_FEATURE_SHOW_THREADS is not set
1070# CONFIG_FREE is not set
1071# CONFIG_FUSER is not set
1072# CONFIG_IOSTAT is not set
1073# CONFIG_KILL is not set
1074# CONFIG_KILLALL is not set
1075# CONFIG_KILLALL5 is not set
1076# CONFIG_LSOF is not set
1077# CONFIG_MPSTAT is not set
1078# CONFIG_NMETER is not set
1079# CONFIG_PGREP is not set
1080# CONFIG_PKILL is not set
1081# CONFIG_PIDOF is not set
1082# CONFIG_FEATURE_PIDOF_SINGLE is not set
1083# CONFIG_FEATURE_PIDOF_OMIT is not set
1084# CONFIG_PMAP is not set
1085# CONFIG_POWERTOP is not set
1086# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set
1087# CONFIG_PS is not set
1088# CONFIG_FEATURE_PS_WIDE is not set
1089# CONFIG_FEATURE_PS_LONG is not set
1090# CONFIG_FEATURE_PS_TIME is not set
1091# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
1092# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
1093# CONFIG_PSTREE is not set
1094# CONFIG_PWDX is not set
1095# CONFIG_SMEMCAP is not set
1096# CONFIG_BB_SYSCTL is not set
1097# CONFIG_TOP is not set
1098# CONFIG_FEATURE_TOP_INTERACTIVE is not set
1099# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
1100# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
1101# CONFIG_FEATURE_TOP_SMP_CPU is not set
1102# CONFIG_FEATURE_TOP_DECIMALS is not set
1103# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
1104# CONFIG_FEATURE_TOPMEM is not set
1105# CONFIG_UPTIME is not set
1106# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
1107# CONFIG_WATCH is not set
1108
1109#
1110# Runit Utilities
1111#
1112# CONFIG_CHPST is not set
1113# CONFIG_SETUIDGID is not set
1114# CONFIG_ENVUIDGID is not set
1115# CONFIG_ENVDIR is not set
1116# CONFIG_SOFTLIMIT is not set
1117# CONFIG_RUNSV is not set
1118# CONFIG_RUNSVDIR is not set
1119# CONFIG_FEATURE_RUNSVDIR_LOG is not set
1120# CONFIG_SV is not set
1121CONFIG_SV_DEFAULT_SERVICE_DIR=""
1122# CONFIG_SVC is not set
1123# CONFIG_SVOK is not set
1124# CONFIG_SVLOGD is not set
1125# CONFIG_CHCON is not set
1126# CONFIG_GETENFORCE is not set
1127# CONFIG_GETSEBOOL is not set
1128# CONFIG_LOAD_POLICY is not set
1129# CONFIG_MATCHPATHCON is not set
1130# CONFIG_RUNCON is not set
1131# CONFIG_SELINUXENABLED is not set
1132# CONFIG_SESTATUS is not set
1133# CONFIG_SETENFORCE is not set
1134# CONFIG_SETFILES is not set
1135# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
1136# CONFIG_RESTORECON is not set
1137# CONFIG_SETSEBOOL is not set
1138
1139#
1140# Shells
1141#
1142CONFIG_SH_IS_ASH=y
1143# CONFIG_SH_IS_HUSH is not set
1144# CONFIG_SH_IS_NONE is not set
1145# CONFIG_BASH_IS_ASH is not set
1146# CONFIG_BASH_IS_HUSH is not set
1147CONFIG_BASH_IS_NONE=y
1148CONFIG_SHELL_ASH=y
1149CONFIG_ASH=y
1150CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
1151CONFIG_ASH_INTERNAL_GLOB=y
1152CONFIG_ASH_BASH_COMPAT=y
1153# CONFIG_ASH_BASH_SOURCE_CURDIR is not set
1154CONFIG_ASH_BASH_NOT_FOUND_HOOK=y
1155CONFIG_ASH_JOB_CONTROL=y
1156CONFIG_ASH_ALIAS=y
1157CONFIG_ASH_RANDOM_SUPPORT=y
1158CONFIG_ASH_EXPAND_PRMT=y
1159CONFIG_ASH_IDLE_TIMEOUT=y
1160CONFIG_ASH_MAIL=y
1161CONFIG_ASH_ECHO=y
1162CONFIG_ASH_PRINTF=y
1163CONFIG_ASH_TEST=y
1164CONFIG_ASH_HELP=y
1165CONFIG_ASH_GETOPTS=y
1166CONFIG_ASH_CMDCMD=y
1167CONFIG_ASH_NOCONSOLE=y
1168CONFIG_ASH_GLOB_OPTIONS=y
1169# CONFIG_CTTYHACK is not set
1170# CONFIG_HUSH is not set
1171# CONFIG_SHELL_HUSH is not set
1172# CONFIG_HUSH_BASH_COMPAT is not set
1173# CONFIG_HUSH_BRACE_EXPANSION is not set
1174# CONFIG_HUSH_BASH_SOURCE_CURDIR is not set
1175# CONFIG_HUSH_LINENO_VAR is not set
1176# CONFIG_HUSH_INTERACTIVE is not set
1177# CONFIG_HUSH_SAVEHISTORY is not set
1178# CONFIG_HUSH_JOB is not set
1179# CONFIG_HUSH_TICK is not set
1180# CONFIG_HUSH_IF is not set
1181# CONFIG_HUSH_LOOPS is not set
1182# CONFIG_HUSH_CASE is not set
1183# CONFIG_HUSH_FUNCTIONS is not set
1184# CONFIG_HUSH_LOCAL is not set
1185# CONFIG_HUSH_RANDOM_SUPPORT is not set
1186# CONFIG_HUSH_MODE_X is not set
1187# CONFIG_HUSH_ECHO is not set
1188# CONFIG_HUSH_PRINTF is not set
1189# CONFIG_HUSH_TEST is not set
1190# CONFIG_HUSH_HELP is not set
1191# CONFIG_HUSH_EXPORT is not set
1192# CONFIG_HUSH_EXPORT_N is not set
1193# CONFIG_HUSH_READONLY is not set
1194# CONFIG_HUSH_KILL is not set
1195# CONFIG_HUSH_WAIT is not set
1196# CONFIG_HUSH_COMMAND is not set
1197# CONFIG_HUSH_TRAP is not set
1198# CONFIG_HUSH_TYPE is not set
1199# CONFIG_HUSH_TIMES is not set
1200# CONFIG_HUSH_READ is not set
1201# CONFIG_HUSH_SET is not set
1202# CONFIG_HUSH_UNSET is not set
1203# CONFIG_HUSH_ULIMIT is not set
1204# CONFIG_HUSH_UMASK is not set
1205# CONFIG_HUSH_GETOPTS is not set
1206# CONFIG_HUSH_MEMLEAK is not set
1207
1208#
1209# Options common to all shells
1210#
1211CONFIG_FEATURE_SH_MATH=y
1212CONFIG_FEATURE_SH_MATH_64=y
1213CONFIG_FEATURE_SH_MATH_BASE=y
1214CONFIG_FEATURE_SH_EXTRA_QUIET=y
1215# CONFIG_FEATURE_SH_STANDALONE is not set
1216# CONFIG_FEATURE_SH_NOFORK is not set
1217CONFIG_FEATURE_SH_READ_FRAC=y
1218CONFIG_FEATURE_SH_HISTFILESIZE=y
1219# CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS is not set
1220
1221#
1222# System Logging Utilities
1223#
1224# CONFIG_KLOGD is not set
1225# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
1226# CONFIG_LOGGER is not set
1227# CONFIG_LOGREAD is not set
1228# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1229# CONFIG_SYSLOGD is not set
1230# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1231# CONFIG_FEATURE_REMOTE_LOG is not set
1232# CONFIG_FEATURE_SYSLOGD_DUP is not set
1233# CONFIG_FEATURE_SYSLOGD_CFG is not set
1234# CONFIG_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS is not set
1235CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1236# CONFIG_FEATURE_IPC_SYSLOG is not set
1237CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1238# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/configs/make64_defconfig b/configs/make64_defconfig
new file mode 100644
index 000000000..c69f1e5fb
--- /dev/null
+++ b/configs/make64_defconfig
@@ -0,0 +1,1238 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.37.0.git
4# Wed Sep 20 08:30:38 2023
5#
6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set
8CONFIG_PLATFORM_MINGW32=y
9
10#
11# Settings
12#
13CONFIG_DESKTOP=y
14# CONFIG_EXTRA_COMPAT is not set
15# CONFIG_FEDORA_COMPAT is not set
16# CONFIG_INCLUDE_SUSv2 is not set
17CONFIG_LONG_OPTS=y
18CONFIG_SHOW_USAGE=y
19CONFIG_FEATURE_VERBOSE_USAGE=y
20CONFIG_FEATURE_COMPRESS_USAGE=y
21CONFIG_LFS=y
22CONFIG_TIME64=y
23# CONFIG_PAM is not set
24# CONFIG_FEATURE_DEVPTS is not set
25# CONFIG_FEATURE_UTMP is not set
26# CONFIG_FEATURE_WTMP is not set
27# CONFIG_FEATURE_PIDFILE is not set
28CONFIG_PID_FILE_PATH=""
29# CONFIG_BUSYBOX is not set
30# CONFIG_FEATURE_SHOW_SCRIPT is not set
31# CONFIG_FEATURE_INSTALLER is not set
32# CONFIG_INSTALL_NO_USR is not set
33# CONFIG_FEATURE_SUID is not set
34# CONFIG_FEATURE_SUID_CONFIG is not set
35# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
36CONFIG_FEATURE_PREFER_APPLETS=y
37CONFIG_BUSYBOX_EXEC_PATH=""
38# CONFIG_SELINUX is not set
39# CONFIG_FEATURE_CLEAN_UP is not set
40# CONFIG_FEATURE_SYSLOG_INFO is not set
41# CONFIG_FEATURE_SYSLOG is not set
42
43#
44# Settings for MINGW32
45#
46CONFIG_GLOBBING=y
47CONFIG_FEATURE_PRNG_SHELL=y
48# CONFIG_FEATURE_PRNG_ISAAC is not set
49# CONFIG_FEATURE_RESOURCES is not set
50# CONFIG_FEATURE_VERSIONINFO is not set
51# CONFIG_FEATURE_TOOLCHAIN_MANIFEST is not set
52CONFIG_FEATURE_APP_MANIFEST=y
53# CONFIG_FEATURE_UTF8_MANIFEST is not set
54# CONFIG_FEATURE_ICON is not set
55# CONFIG_FEATURE_ICON_ATERM is not set
56# CONFIG_FEATURE_ICON_STERM is not set
57# CONFIG_FEATURE_ICON_ALL is not set
58# CONFIG_FEATURE_EURO is not set
59# CONFIG_FEATURE_UTF8_INPUT is not set
60# CONFIG_FEATURE_UTF8_OUTPUT is not set
61CONFIG_TERMINAL_MODE=5
62# CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING is not set
63CONFIG_FEATURE_EXTRA_FILE_DATA=y
64
65#
66# Build Options
67#
68# CONFIG_STATIC is not set
69# CONFIG_PIE is not set
70# CONFIG_NOMMU is not set
71# CONFIG_BUILD_LIBBUSYBOX is not set
72# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set
73# CONFIG_FEATURE_INDIVIDUAL is not set
74# CONFIG_FEATURE_SHARED_BUSYBOX is not set
75CONFIG_CROSS_COMPILER_PREFIX="x86_64-w64-mingw32-"
76CONFIG_SYSROOT=""
77CONFIG_EXTRA_CFLAGS=""
78CONFIG_EXTRA_LDFLAGS=""
79CONFIG_EXTRA_LDLIBS=""
80CONFIG_USE_PORTABLE_CODE=y
81CONFIG_STACK_OPTIMIZATION_386=y
82CONFIG_STATIC_LIBGCC=y
83
84#
85# Installation Options ("make install" behavior)
86#
87CONFIG_INSTALL_APPLET_SYMLINKS=y
88# CONFIG_INSTALL_APPLET_HARDLINKS is not set
89# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
90# CONFIG_INSTALL_APPLET_DONT is not set
91# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
92# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
93# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
94CONFIG_PREFIX=""
95
96#
97# Debugging Options
98#
99# CONFIG_DEBUG is not set
100# CONFIG_DEBUG_PESSIMIZE is not set
101# CONFIG_DEBUG_SANITIZE is not set
102# CONFIG_UNIT_TEST is not set
103# CONFIG_WERROR is not set
104# CONFIG_WARN_SIMPLE_MSG is not set
105CONFIG_NO_DEBUG_LIB=y
106# CONFIG_DMALLOC is not set
107# CONFIG_EFENCE is not set
108
109#
110# Library Tuning
111#
112# CONFIG_FEATURE_USE_BSS_TAIL is not set
113CONFIG_FLOAT_DURATION=y
114# CONFIG_FEATURE_RTMINMAX is not set
115# CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS is not set
116CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
117# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
118# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
119CONFIG_PASSWORD_MINLEN=6
120CONFIG_MD5_SMALL=1
121CONFIG_SHA1_SMALL=3
122# CONFIG_SHA1_HWACCEL is not set
123# CONFIG_SHA256_HWACCEL is not set
124CONFIG_SHA3_SMALL=1
125CONFIG_FEATURE_NON_POSIX_CP=y
126# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
127# CONFIG_FEATURE_USE_SENDFILE is not set
128CONFIG_FEATURE_COPYBUF_KB=4
129# CONFIG_MONOTONIC_SYSCALL is not set
130# CONFIG_IOCTL_HEX2STR_ERROR is not set
131# CONFIG_FEATURE_EDITING is not set
132CONFIG_FEATURE_EDITING_MAX_LEN=0
133# CONFIG_FEATURE_EDITING_VI is not set
134CONFIG_FEATURE_EDITING_HISTORY=0
135# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set
136# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
137# CONFIG_FEATURE_REVERSE_SEARCH is not set
138# CONFIG_FEATURE_TAB_COMPLETION is not set
139# CONFIG_FEATURE_USERNAME_COMPLETION is not set
140# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set
141# CONFIG_FEATURE_EDITING_WINCH is not set
142# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
143# CONFIG_LOCALE_SUPPORT is not set
144# CONFIG_UNICODE_SUPPORT is not set
145# CONFIG_UNICODE_USING_LOCALE is not set
146# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
147CONFIG_SUBST_WCHAR=0
148CONFIG_LAST_SUPPORTED_WCHAR=0
149# CONFIG_UNICODE_COMBINING_WCHARS is not set
150# CONFIG_UNICODE_WIDE_WCHARS is not set
151# CONFIG_UNICODE_BIDI_SUPPORT is not set
152# CONFIG_UNICODE_NEUTRAL_TABLE is not set
153# CONFIG_UNICODE_PRESERVE_BROKEN is not set
154# CONFIG_LOOP_CONFIGURE is not set
155# CONFIG_NO_LOOP_CONFIGURE is not set
156CONFIG_TRY_LOOP_CONFIGURE=y
157
158#
159# Applets
160#
161
162#
163# Archival Utilities
164#
165# CONFIG_FEATURE_SEAMLESS_XZ is not set
166# CONFIG_FEATURE_SEAMLESS_LZMA is not set
167# CONFIG_FEATURE_SEAMLESS_BZ2 is not set
168# CONFIG_FEATURE_SEAMLESS_GZ is not set
169# CONFIG_FEATURE_SEAMLESS_Z is not set
170# CONFIG_AR is not set
171CONFIG_FEATURE_AR_LONG_FILENAMES=y
172# CONFIG_FEATURE_AR_CREATE is not set
173# CONFIG_UNCOMPRESS is not set
174# CONFIG_GUNZIP is not set
175# CONFIG_ZCAT is not set
176# CONFIG_FEATURE_GUNZIP_LONG_OPTIONS is not set
177# CONFIG_BUNZIP2 is not set
178# CONFIG_BZCAT is not set
179# CONFIG_UNLZMA is not set
180# CONFIG_LZCAT is not set
181# CONFIG_LZMA is not set
182# CONFIG_UNXZ is not set
183# CONFIG_XZCAT is not set
184# CONFIG_XZ is not set
185# CONFIG_BZIP2 is not set
186CONFIG_BZIP2_SMALL=0
187# CONFIG_FEATURE_BZIP2_DECOMPRESS is not set
188# CONFIG_CPIO is not set
189# CONFIG_FEATURE_CPIO_O is not set
190# CONFIG_FEATURE_CPIO_P is not set
191# CONFIG_FEATURE_CPIO_IGNORE_DEVNO is not set
192# CONFIG_FEATURE_CPIO_RENUMBER_INODES is not set
193# CONFIG_DPKG is not set
194# CONFIG_DPKG_DEB is not set
195# CONFIG_GZIP is not set
196# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set
197CONFIG_GZIP_FAST=0
198# CONFIG_FEATURE_GZIP_LEVELS is not set
199# CONFIG_FEATURE_GZIP_DECOMPRESS is not set
200# CONFIG_LZOP is not set
201# CONFIG_UNLZOP is not set
202# CONFIG_LZOPCAT is not set
203# CONFIG_LZOP_COMPR_HIGH is not set
204# CONFIG_RPM is not set
205# CONFIG_RPM2CPIO is not set
206# CONFIG_TAR is not set
207# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set
208# CONFIG_FEATURE_TAR_CREATE is not set
209# CONFIG_FEATURE_TAR_AUTODETECT is not set
210# CONFIG_FEATURE_TAR_FROM is not set
211# CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY is not set
212# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
213# CONFIG_FEATURE_TAR_GNU_EXTENSIONS is not set
214# CONFIG_FEATURE_TAR_TO_COMMAND is not set
215# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
216# CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set
217# CONFIG_FEATURE_TAR_SELINUX is not set
218# CONFIG_UNZIP is not set
219# CONFIG_FEATURE_UNZIP_CDF is not set
220# CONFIG_FEATURE_UNZIP_BZIP2 is not set
221# CONFIG_FEATURE_UNZIP_LZMA is not set
222# CONFIG_FEATURE_UNZIP_XZ is not set
223# CONFIG_FEATURE_LZMA_FAST is not set
224
225#
226# Coreutils
227#
228CONFIG_FEATURE_VERBOSE=y
229
230#
231# Common options for date and touch
232#
233# CONFIG_FEATURE_TIMEZONE is not set
234# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
235# CONFIG_FEATURE_HUMAN_READABLE is not set
236# CONFIG_BASENAME is not set
237# CONFIG_CAT is not set
238# CONFIG_FEATURE_CATN is not set
239# CONFIG_FEATURE_CATV is not set
240# CONFIG_CHGRP is not set
241# CONFIG_CHMOD is not set
242# CONFIG_CHOWN is not set
243# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
244# CONFIG_CHROOT is not set
245# CONFIG_CKSUM is not set
246# CONFIG_CRC32 is not set
247# CONFIG_COMM is not set
248# CONFIG_CP is not set
249# CONFIG_FEATURE_CP_LONG_OPTIONS is not set
250# CONFIG_FEATURE_CP_REFLINK is not set
251# CONFIG_CUT is not set
252# CONFIG_FEATURE_CUT_REGEX is not set
253# CONFIG_DATE is not set
254# CONFIG_FEATURE_DATE_ISOFMT is not set
255# CONFIG_FEATURE_DATE_NANO is not set
256# CONFIG_FEATURE_DATE_COMPAT is not set
257# CONFIG_DD is not set
258# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
259# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
260# CONFIG_FEATURE_DD_IBS_OBS is not set
261# CONFIG_FEATURE_DD_STATUS is not set
262# CONFIG_DF is not set
263# CONFIG_FEATURE_DF_FANCY is not set
264# CONFIG_FEATURE_SKIP_ROOTFS is not set
265# CONFIG_DIRNAME is not set
266# CONFIG_DOS2UNIX is not set
267# CONFIG_UNIX2DOS is not set
268# CONFIG_DU is not set
269# CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K is not set
270# CONFIG_ECHO is not set
271CONFIG_FEATURE_FANCY_ECHO=y
272# CONFIG_ENV is not set
273# CONFIG_EXPAND is not set
274# CONFIG_UNEXPAND is not set
275# CONFIG_EXPR is not set
276# CONFIG_EXPR_MATH_SUPPORT_64 is not set
277# CONFIG_FACTOR is not set
278# CONFIG_FALSE is not set
279# CONFIG_FOLD is not set
280# CONFIG_HEAD is not set
281# CONFIG_FEATURE_FANCY_HEAD is not set
282# CONFIG_HOSTID is not set
283# CONFIG_ID is not set
284# CONFIG_GROUPS is not set
285# CONFIG_INSTALL is not set
286# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
287# CONFIG_LINK is not set
288# CONFIG_LN is not set
289# CONFIG_LOGNAME is not set
290# CONFIG_LS is not set
291# CONFIG_FEATURE_LS_FILETYPES is not set
292# CONFIG_FEATURE_LS_FOLLOWLINKS is not set
293# CONFIG_FEATURE_LS_RECURSIVE is not set
294# CONFIG_FEATURE_LS_WIDTH is not set
295# CONFIG_FEATURE_LS_SORTFILES is not set
296# CONFIG_FEATURE_LS_TIMESTAMPS is not set
297# CONFIG_FEATURE_LS_USERNAME is not set
298# CONFIG_FEATURE_LS_COLOR is not set
299# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set
300# CONFIG_MD5SUM is not set
301# CONFIG_SHA1SUM is not set
302# CONFIG_SHA256SUM is not set
303# CONFIG_SHA512SUM is not set
304# CONFIG_SHA3SUM is not set
305# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set
306# CONFIG_MKDIR is not set
307# CONFIG_MKFIFO is not set
308# CONFIG_MKNOD is not set
309# CONFIG_MKTEMP is not set
310# CONFIG_MV is not set
311# CONFIG_NICE is not set
312# CONFIG_NL is not set
313# CONFIG_NOHUP is not set
314# CONFIG_NPROC is not set
315# CONFIG_OD is not set
316# CONFIG_PASTE is not set
317# CONFIG_PRINTENV is not set
318# CONFIG_PRINTF is not set
319# CONFIG_PWD is not set
320# CONFIG_READLINK is not set
321# CONFIG_FEATURE_READLINK_FOLLOW is not set
322# CONFIG_REALPATH is not set
323# CONFIG_RM is not set
324# CONFIG_RMDIR is not set
325# CONFIG_SEQ is not set
326# CONFIG_SHRED is not set
327# CONFIG_SHUF is not set
328# CONFIG_SLEEP is not set
329# CONFIG_FEATURE_FANCY_SLEEP is not set
330# CONFIG_SORT is not set
331# CONFIG_FEATURE_SORT_BIG is not set
332# CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set
333# CONFIG_SPLIT is not set
334# CONFIG_FEATURE_SPLIT_FANCY is not set
335# CONFIG_STAT is not set
336# CONFIG_FEATURE_STAT_FORMAT is not set
337# CONFIG_FEATURE_STAT_FILESYSTEM is not set
338# CONFIG_STTY is not set
339# CONFIG_SUM is not set
340# CONFIG_SYNC is not set
341# CONFIG_FEATURE_SYNC_FANCY is not set
342# CONFIG_FSYNC is not set
343# CONFIG_TAC is not set
344# CONFIG_TAIL is not set
345# CONFIG_FEATURE_FANCY_TAIL is not set
346# CONFIG_TEE is not set
347# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set
348# CONFIG_TEST is not set
349# CONFIG_TEST1 is not set
350# CONFIG_TEST2 is not set
351CONFIG_FEATURE_TEST_64=y
352# CONFIG_TIMEOUT is not set
353# CONFIG_TOUCH is not set
354# CONFIG_FEATURE_TOUCH_SUSV3 is not set
355# CONFIG_TR is not set
356# CONFIG_FEATURE_TR_CLASSES is not set
357# CONFIG_FEATURE_TR_EQUIV is not set
358# CONFIG_TRUE is not set
359# CONFIG_TRUNCATE is not set
360# CONFIG_TSORT is not set
361# CONFIG_TTY is not set
362# CONFIG_UNAME is not set
363CONFIG_UNAME_OSNAME=""
364# CONFIG_BB_ARCH is not set
365# CONFIG_UNIQ is not set
366# CONFIG_UNLINK is not set
367# CONFIG_USLEEP is not set
368# CONFIG_UUDECODE is not set
369# CONFIG_BASE32 is not set
370# CONFIG_BASE64 is not set
371# CONFIG_UUENCODE is not set
372# CONFIG_WC is not set
373# CONFIG_FEATURE_WC_LARGE is not set
374# CONFIG_WHO is not set
375# CONFIG_W is not set
376# CONFIG_USERS is not set
377# CONFIG_WHOAMI is not set
378# CONFIG_YES is not set
379
380#
381# Console Utilities
382#
383# CONFIG_CHVT is not set
384# CONFIG_CLEAR is not set
385# CONFIG_DEALLOCVT is not set
386# CONFIG_DUMPKMAP is not set
387# CONFIG_FGCONSOLE is not set
388# CONFIG_KBD_MODE is not set
389# CONFIG_LOADFONT is not set
390# CONFIG_SETFONT is not set
391# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
392CONFIG_DEFAULT_SETFONT_DIR=""
393# CONFIG_FEATURE_LOADFONT_PSF2 is not set
394# CONFIG_FEATURE_LOADFONT_RAW is not set
395# CONFIG_LOADKMAP is not set
396# CONFIG_OPENVT is not set
397# CONFIG_RESET is not set
398# CONFIG_RESIZE is not set
399# CONFIG_FEATURE_RESIZE_PRINT is not set
400# CONFIG_SETCONSOLE is not set
401# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
402# CONFIG_SETKEYCODES is not set
403# CONFIG_SETLOGCONS is not set
404# CONFIG_SHOWKEY is not set
405
406#
407# Debian Utilities
408#
409# CONFIG_PIPE_PROGRESS is not set
410# CONFIG_RUN_PARTS is not set
411# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
412# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
413# CONFIG_START_STOP_DAEMON is not set
414# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
415# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
416# CONFIG_WHICH is not set
417
418#
419# klibc-utils
420#
421# CONFIG_MINIPS is not set
422# CONFIG_NUKE is not set
423# CONFIG_RESUME is not set
424# CONFIG_RUN_INIT is not set
425
426#
427# Editors
428#
429# CONFIG_AWK is not set
430# CONFIG_FEATURE_AWK_LIBM is not set
431# CONFIG_FEATURE_AWK_GNU_EXTENSIONS is not set
432# CONFIG_CMP is not set
433# CONFIG_DIFF is not set
434# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set
435# CONFIG_FEATURE_DIFF_DIR is not set
436# CONFIG_ED is not set
437# CONFIG_PATCH is not set
438# CONFIG_SED is not set
439# CONFIG_VI is not set
440CONFIG_FEATURE_VI_MAX_LEN=0
441# CONFIG_FEATURE_VI_8BIT is not set
442# CONFIG_FEATURE_VI_COLON is not set
443# CONFIG_FEATURE_VI_COLON_EXPAND is not set
444# CONFIG_FEATURE_VI_YANKMARK is not set
445# CONFIG_FEATURE_VI_SEARCH is not set
446# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
447# CONFIG_FEATURE_VI_USE_SIGNALS is not set
448# CONFIG_FEATURE_VI_DOT_CMD is not set
449# CONFIG_FEATURE_VI_READONLY is not set
450# CONFIG_FEATURE_VI_SETOPTS is not set
451# CONFIG_FEATURE_VI_FILE_FORMAT is not set
452# CONFIG_FEATURE_VI_SET is not set
453# CONFIG_FEATURE_VI_WIN_RESIZE is not set
454# CONFIG_FEATURE_VI_ASK_TERMINAL is not set
455# CONFIG_FEATURE_VI_UNDO is not set
456# CONFIG_FEATURE_VI_UNDO_QUEUE is not set
457CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=0
458# CONFIG_FEATURE_VI_VERBOSE_STATUS is not set
459# CONFIG_FEATURE_ALLOW_EXEC is not set
460
461#
462# Finding Utilities
463#
464# CONFIG_FIND is not set
465# CONFIG_FEATURE_FIND_PRINT0 is not set
466# CONFIG_FEATURE_FIND_MTIME is not set
467# CONFIG_FEATURE_FIND_ATIME is not set
468# CONFIG_FEATURE_FIND_CTIME is not set
469# CONFIG_FEATURE_FIND_MMIN is not set
470# CONFIG_FEATURE_FIND_AMIN is not set
471# CONFIG_FEATURE_FIND_CMIN is not set
472# CONFIG_FEATURE_FIND_PERM is not set
473# CONFIG_FEATURE_FIND_TYPE is not set
474# CONFIG_FEATURE_FIND_EXECUTABLE is not set
475# CONFIG_FEATURE_FIND_XDEV is not set
476# CONFIG_FEATURE_FIND_MAXDEPTH is not set
477# CONFIG_FEATURE_FIND_NEWER is not set
478# CONFIG_FEATURE_FIND_INUM is not set
479# CONFIG_FEATURE_FIND_SAMEFILE is not set
480# CONFIG_FEATURE_FIND_EXEC is not set
481# CONFIG_FEATURE_FIND_EXEC_PLUS is not set
482# CONFIG_FEATURE_FIND_EXEC_OK is not set
483# CONFIG_FEATURE_FIND_USER is not set
484# CONFIG_FEATURE_FIND_GROUP is not set
485# CONFIG_FEATURE_FIND_NOT is not set
486# CONFIG_FEATURE_FIND_DEPTH is not set
487# CONFIG_FEATURE_FIND_PAREN is not set
488# CONFIG_FEATURE_FIND_SIZE is not set
489# CONFIG_FEATURE_FIND_PRUNE is not set
490# CONFIG_FEATURE_FIND_QUIT is not set
491# CONFIG_FEATURE_FIND_DELETE is not set
492# CONFIG_FEATURE_FIND_EMPTY is not set
493# CONFIG_FEATURE_FIND_PATH is not set
494# CONFIG_FEATURE_FIND_REGEX is not set
495# CONFIG_FEATURE_FIND_CONTEXT is not set
496# CONFIG_FEATURE_FIND_LINKS is not set
497# CONFIG_GREP is not set
498# CONFIG_EGREP is not set
499# CONFIG_FGREP is not set
500# CONFIG_FEATURE_GREP_CONTEXT is not set
501# CONFIG_XARGS is not set
502# CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION is not set
503# CONFIG_FEATURE_XARGS_SUPPORT_QUOTES is not set
504# CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT is not set
505# CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM is not set
506# CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR is not set
507# CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL is not set
508# CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE is not set
509
510#
511# Init Utilities
512#
513# CONFIG_BOOTCHARTD is not set
514# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
515# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
516# CONFIG_HALT is not set
517# CONFIG_POWEROFF is not set
518# CONFIG_REBOOT is not set
519# CONFIG_FEATURE_WAIT_FOR_INIT is not set
520# CONFIG_FEATURE_CALL_TELINIT is not set
521CONFIG_TELINIT_PATH=""
522# CONFIG_INIT is not set
523# CONFIG_LINUXRC is not set
524# CONFIG_FEATURE_USE_INITTAB is not set
525# CONFIG_FEATURE_KILL_REMOVED is not set
526CONFIG_FEATURE_KILL_DELAY=0
527# CONFIG_FEATURE_INIT_SCTTY is not set
528# CONFIG_FEATURE_INIT_SYSLOG is not set
529# CONFIG_FEATURE_INIT_QUIET is not set
530# CONFIG_FEATURE_INIT_COREDUMPS is not set
531CONFIG_INIT_TERMINAL_TYPE=""
532# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
533
534#
535# Login/Password Management Utilities
536#
537# CONFIG_FEATURE_SHADOWPASSWDS is not set
538# CONFIG_USE_BB_PWD_GRP is not set
539# CONFIG_USE_BB_SHADOW is not set
540# CONFIG_USE_BB_CRYPT is not set
541# CONFIG_USE_BB_CRYPT_SHA is not set
542# CONFIG_ADD_SHELL is not set
543# CONFIG_REMOVE_SHELL is not set
544# CONFIG_ADDGROUP is not set
545# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
546# CONFIG_ADDUSER is not set
547# CONFIG_FEATURE_CHECK_NAMES is not set
548CONFIG_LAST_ID=0
549CONFIG_FIRST_SYSTEM_ID=0
550CONFIG_LAST_SYSTEM_ID=0
551# CONFIG_CHPASSWD is not set
552CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
553# CONFIG_CRYPTPW is not set
554# CONFIG_MKPASSWD is not set
555# CONFIG_DELUSER is not set
556# CONFIG_DELGROUP is not set
557# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
558# CONFIG_GETTY is not set
559# CONFIG_LOGIN is not set
560# CONFIG_LOGIN_SESSION_AS_CHILD is not set
561# CONFIG_LOGIN_SCRIPTS is not set
562# CONFIG_FEATURE_NOLOGIN is not set
563# CONFIG_FEATURE_SECURETTY is not set
564# CONFIG_PASSWD is not set
565# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
566# CONFIG_SU is not set
567# CONFIG_FEATURE_SU_SYSLOG is not set
568# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
569# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set
570# CONFIG_SULOGIN is not set
571# CONFIG_SUW32 is not set
572# CONFIG_VLOCK is not set
573
574#
575# Linux Ext2 FS Progs
576#
577# CONFIG_CHATTR is not set
578# CONFIG_FSCK is not set
579# CONFIG_LSATTR is not set
580# CONFIG_TUNE2FS is not set
581
582#
583# Linux Module Utilities
584#
585# CONFIG_MODPROBE_SMALL is not set
586# CONFIG_DEPMOD is not set
587# CONFIG_INSMOD is not set
588# CONFIG_LSMOD is not set
589# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
590# CONFIG_MODINFO is not set
591# CONFIG_MODPROBE is not set
592# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
593# CONFIG_RMMOD is not set
594
595#
596# Options common to multiple modutils
597#
598# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set
599# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
600# CONFIG_FEATURE_2_4_MODULES is not set
601# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
602# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
603# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
604# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
605# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
606# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
607# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
608# CONFIG_FEATURE_MODUTILS_ALIAS is not set
609# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
610CONFIG_DEFAULT_MODULES_DIR=""
611CONFIG_DEFAULT_DEPMOD_FILE=""
612
613#
614# Linux System Utilities
615#
616# CONFIG_ACPID is not set
617# CONFIG_FEATURE_ACPID_COMPAT is not set
618# CONFIG_BLKDISCARD is not set
619# CONFIG_BLKID is not set
620# CONFIG_FEATURE_BLKID_TYPE is not set
621# CONFIG_BLOCKDEV is not set
622# CONFIG_CAL is not set
623# CONFIG_CHRT is not set
624# CONFIG_DMESG is not set
625# CONFIG_FEATURE_DMESG_PRETTY is not set
626# CONFIG_EJECT is not set
627# CONFIG_FEATURE_EJECT_SCSI is not set
628# CONFIG_FALLOCATE is not set
629# CONFIG_FATATTR is not set
630# CONFIG_FBSET is not set
631# CONFIG_FEATURE_FBSET_FANCY is not set
632# CONFIG_FEATURE_FBSET_READMODE is not set
633# CONFIG_FDFORMAT is not set
634# CONFIG_FDISK is not set
635# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
636# CONFIG_FEATURE_FDISK_WRITABLE is not set
637# CONFIG_FEATURE_AIX_LABEL is not set
638# CONFIG_FEATURE_SGI_LABEL is not set
639# CONFIG_FEATURE_SUN_LABEL is not set
640# CONFIG_FEATURE_OSF_LABEL is not set
641# CONFIG_FEATURE_GPT_LABEL is not set
642# CONFIG_FEATURE_FDISK_ADVANCED is not set
643# CONFIG_FINDFS is not set
644# CONFIG_FLOCK is not set
645# CONFIG_FDFLUSH is not set
646# CONFIG_FREERAMDISK is not set
647# CONFIG_FSCK_MINIX is not set
648# CONFIG_FSFREEZE is not set
649# CONFIG_FSTRIM is not set
650# CONFIG_GETOPT is not set
651# CONFIG_FEATURE_GETOPT_LONG is not set
652# CONFIG_HEXDUMP is not set
653# CONFIG_HD is not set
654# CONFIG_XXD is not set
655# CONFIG_HWCLOCK is not set
656# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
657# CONFIG_IONICE is not set
658# CONFIG_IPCRM is not set
659# CONFIG_IPCS is not set
660# CONFIG_LAST is not set
661# CONFIG_FEATURE_LAST_FANCY is not set
662# CONFIG_LOSETUP is not set
663# CONFIG_LSPCI is not set
664# CONFIG_LSUSB is not set
665# CONFIG_MDEV is not set
666# CONFIG_FEATURE_MDEV_CONF is not set
667# CONFIG_FEATURE_MDEV_RENAME is not set
668# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
669# CONFIG_FEATURE_MDEV_EXEC is not set
670# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
671# CONFIG_FEATURE_MDEV_DAEMON is not set
672# CONFIG_MESG is not set
673# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
674# CONFIG_MKE2FS is not set
675# CONFIG_MKFS_EXT2 is not set
676# CONFIG_MKFS_MINIX is not set
677# CONFIG_FEATURE_MINIX2 is not set
678# CONFIG_MKFS_REISER is not set
679# CONFIG_MKDOSFS is not set
680# CONFIG_MKFS_VFAT is not set
681# CONFIG_MKSWAP is not set
682# CONFIG_FEATURE_MKSWAP_UUID is not set
683# CONFIG_MORE is not set
684# CONFIG_MOUNT is not set
685# CONFIG_FEATURE_MOUNT_FAKE is not set
686# CONFIG_FEATURE_MOUNT_VERBOSE is not set
687# CONFIG_FEATURE_MOUNT_HELPERS is not set
688# CONFIG_FEATURE_MOUNT_LABEL is not set
689# CONFIG_FEATURE_MOUNT_NFS is not set
690# CONFIG_FEATURE_MOUNT_CIFS is not set
691# CONFIG_FEATURE_MOUNT_FLAGS is not set
692# CONFIG_FEATURE_MOUNT_FSTAB is not set
693# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
694# CONFIG_MOUNTPOINT is not set
695# CONFIG_NOLOGIN is not set
696# CONFIG_NOLOGIN_DEPENDENCIES is not set
697# CONFIG_NSENTER is not set
698# CONFIG_PIVOT_ROOT is not set
699# CONFIG_RDATE is not set
700# CONFIG_RDEV is not set
701# CONFIG_READPROFILE is not set
702# CONFIG_RENICE is not set
703# CONFIG_REV is not set
704# CONFIG_RTCWAKE is not set
705# CONFIG_SCRIPT is not set
706# CONFIG_SCRIPTREPLAY is not set
707# CONFIG_SETARCH is not set
708# CONFIG_LINUX32 is not set
709# CONFIG_LINUX64 is not set
710# CONFIG_SETPRIV is not set
711# CONFIG_FEATURE_SETPRIV_DUMP is not set
712# CONFIG_FEATURE_SETPRIV_CAPABILITIES is not set
713# CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES is not set
714# CONFIG_SETSID is not set
715# CONFIG_SWAPON is not set
716# CONFIG_FEATURE_SWAPON_DISCARD is not set
717# CONFIG_FEATURE_SWAPON_PRI is not set
718# CONFIG_SWAPOFF is not set
719# CONFIG_FEATURE_SWAPONOFF_LABEL is not set
720# CONFIG_SWITCH_ROOT is not set
721# CONFIG_TASKSET is not set
722# CONFIG_FEATURE_TASKSET_FANCY is not set
723# CONFIG_FEATURE_TASKSET_CPULIST is not set
724# CONFIG_UEVENT is not set
725# CONFIG_UMOUNT is not set
726# CONFIG_FEATURE_UMOUNT_ALL is not set
727# CONFIG_UNSHARE is not set
728# CONFIG_WALL is not set
729# CONFIG_FEATURE_MOUNT_LOOP is not set
730# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
731# CONFIG_FEATURE_MTAB_SUPPORT is not set
732# CONFIG_VOLUMEID is not set
733# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
734# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
735# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
736# CONFIG_FEATURE_VOLUMEID_EROFS is not set
737# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
738# CONFIG_FEATURE_VOLUMEID_EXT is not set
739# CONFIG_FEATURE_VOLUMEID_F2FS is not set
740# CONFIG_FEATURE_VOLUMEID_FAT is not set
741# CONFIG_FEATURE_VOLUMEID_HFS is not set
742# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
743# CONFIG_FEATURE_VOLUMEID_JFS is not set
744# CONFIG_FEATURE_VOLUMEID_LFS is not set
745# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
746# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
747# CONFIG_FEATURE_VOLUMEID_LUKS is not set
748# CONFIG_FEATURE_VOLUMEID_MINIX is not set
749# CONFIG_FEATURE_VOLUMEID_NILFS is not set
750# CONFIG_FEATURE_VOLUMEID_NTFS is not set
751# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
752# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
753# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
754# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
755# CONFIG_FEATURE_VOLUMEID_SYSV is not set
756# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
757# CONFIG_FEATURE_VOLUMEID_UDF is not set
758# CONFIG_FEATURE_VOLUMEID_XFS is not set
759
760#
761# Miscellaneous Utilities
762#
763# CONFIG_ADJTIMEX is not set
764# CONFIG_ASCII is not set
765# CONFIG_BBCONFIG is not set
766# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
767# CONFIG_BC is not set
768# CONFIG_DC is not set
769# CONFIG_FEATURE_DC_BIG is not set
770# CONFIG_FEATURE_DC_LIBM is not set
771# CONFIG_FEATURE_BC_INTERACTIVE is not set
772# CONFIG_FEATURE_BC_LONG_OPTIONS is not set
773# CONFIG_BEEP is not set
774CONFIG_FEATURE_BEEP_FREQ=0
775CONFIG_FEATURE_BEEP_LENGTH_MS=0
776# CONFIG_CHAT is not set
777# CONFIG_FEATURE_CHAT_NOFAIL is not set
778# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
779# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
780# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
781# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
782# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
783# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
784# CONFIG_CONSPY is not set
785# CONFIG_CROND is not set
786# CONFIG_FEATURE_CROND_D is not set
787# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
788# CONFIG_FEATURE_CROND_SPECIAL_TIMES is not set
789CONFIG_FEATURE_CROND_DIR=""
790# CONFIG_CRONTAB is not set
791# CONFIG_DEVFSD is not set
792# CONFIG_DEVFSD_MODLOAD is not set
793# CONFIG_DEVFSD_FG_NP is not set
794# CONFIG_DEVFSD_VERBOSE is not set
795# CONFIG_FEATURE_DEVFS is not set
796# CONFIG_DEVMEM is not set
797# CONFIG_DROP is not set
798# CONFIG_CDROP is not set
799# CONFIG_PDROP is not set
800# CONFIG_FBSPLASH is not set
801# CONFIG_FLASH_ERASEALL is not set
802# CONFIG_FLASH_LOCK is not set
803# CONFIG_FLASH_UNLOCK is not set
804# CONFIG_FLASHCP is not set
805# CONFIG_GETFATTR is not set
806# CONFIG_HDPARM is not set
807# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
808# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
809# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
810# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
811# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
812# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
813# CONFIG_HEXEDIT is not set
814# CONFIG_I2CGET is not set
815# CONFIG_I2CSET is not set
816# CONFIG_I2CDUMP is not set
817# CONFIG_I2CDETECT is not set
818# CONFIG_I2CTRANSFER is not set
819# CONFIG_ICONV is not set
820# CONFIG_INOTIFYD is not set
821# CONFIG_JN is not set
822# CONFIG_LESS is not set
823CONFIG_FEATURE_LESS_MAXLINES=0
824# CONFIG_FEATURE_LESS_BRACKETS is not set
825# CONFIG_FEATURE_LESS_FLAGS is not set
826# CONFIG_FEATURE_LESS_TRUNCATE is not set
827# CONFIG_FEATURE_LESS_MARKS is not set
828# CONFIG_FEATURE_LESS_REGEXP is not set
829# CONFIG_FEATURE_LESS_WINCH is not set
830# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
831# CONFIG_FEATURE_LESS_DASHCMD is not set
832# CONFIG_FEATURE_LESS_LINENUMS is not set
833# CONFIG_FEATURE_LESS_RAW is not set
834# CONFIG_FEATURE_LESS_ENV is not set
835# CONFIG_LSSCSI is not set
836CONFIG_MAKE=y
837CONFIG_PDPMAKE=y
838CONFIG_FEATURE_MAKE_POSIX=y
839# CONFIG_MAKEDEVS is not set
840# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
841# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
842# CONFIG_MAN is not set
843# CONFIG_MICROCOM is not set
844# CONFIG_MIM is not set
845# CONFIG_MT is not set
846# CONFIG_NANDWRITE is not set
847# CONFIG_NANDDUMP is not set
848# CONFIG_PARTPROBE is not set
849# CONFIG_RAIDAUTORUN is not set
850# CONFIG_READAHEAD is not set
851# CONFIG_RFKILL is not set
852# CONFIG_RUNLEVEL is not set
853# CONFIG_RX is not set
854# CONFIG_SEEDRNG is not set
855# CONFIG_SETFATTR is not set
856# CONFIG_SETSERIAL is not set
857# CONFIG_STRINGS is not set
858# CONFIG_TIME is not set
859# CONFIG_TREE is not set
860# CONFIG_TS is not set
861# CONFIG_TTYSIZE is not set
862# CONFIG_UBIATTACH is not set
863# CONFIG_UBIDETACH is not set
864# CONFIG_UBIMKVOL is not set
865# CONFIG_UBIRMVOL is not set
866# CONFIG_UBIRSVOL is not set
867# CONFIG_UBIUPDATEVOL is not set
868# CONFIG_UBIRENAME is not set
869# CONFIG_VOLNAME is not set
870# CONFIG_WATCHDOG is not set
871# CONFIG_FEATURE_WATCHDOG_OPEN_TWICE is not set
872
873#
874# Networking Utilities
875#
876# CONFIG_FEATURE_IPV6 is not set
877# CONFIG_FEATURE_UNIX_LOCAL is not set
878# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set
879# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
880# CONFIG_FEATURE_ETC_NETWORKS is not set
881# CONFIG_FEATURE_ETC_SERVICES is not set
882# CONFIG_FEATURE_HWIB is not set
883# CONFIG_FEATURE_TLS_SHA1 is not set
884# CONFIG_ARP is not set
885# CONFIG_ARPING is not set
886# CONFIG_BRCTL is not set
887# CONFIG_FEATURE_BRCTL_FANCY is not set
888# CONFIG_FEATURE_BRCTL_SHOW is not set
889# CONFIG_DNSD is not set
890# CONFIG_ETHER_WAKE is not set
891# CONFIG_FTPD is not set
892# CONFIG_FEATURE_FTPD_WRITE is not set
893# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
894# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
895# CONFIG_FTPGET is not set
896# CONFIG_FTPPUT is not set
897# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set
898# CONFIG_HOSTNAME is not set
899# CONFIG_DNSDOMAINNAME is not set
900# CONFIG_HTTPD is not set
901CONFIG_FEATURE_HTTPD_PORT_DEFAULT=0
902# CONFIG_FEATURE_HTTPD_RANGES is not set
903# CONFIG_FEATURE_HTTPD_SETUID is not set
904# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
905# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
906# CONFIG_FEATURE_HTTPD_CGI is not set
907# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
908# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
909# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
910# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
911# CONFIG_FEATURE_HTTPD_PROXY is not set
912# CONFIG_FEATURE_HTTPD_GZIP is not set
913# CONFIG_FEATURE_HTTPD_ETAG is not set
914# CONFIG_FEATURE_HTTPD_LAST_MODIFIED is not set
915# CONFIG_FEATURE_HTTPD_DATE is not set
916# CONFIG_FEATURE_HTTPD_ACL_IP is not set
917# CONFIG_IFCONFIG is not set
918# CONFIG_FEATURE_IFCONFIG_STATUS is not set
919# CONFIG_FEATURE_IFCONFIG_SLIP is not set
920# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
921# CONFIG_FEATURE_IFCONFIG_HW is not set
922# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
923# CONFIG_IFENSLAVE is not set
924# CONFIG_IFPLUGD is not set
925# CONFIG_IFUP is not set
926# CONFIG_IFDOWN is not set
927CONFIG_IFUPDOWN_IFSTATE_PATH=""
928# CONFIG_FEATURE_IFUPDOWN_IP is not set
929# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
930# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
931# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
932# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
933# CONFIG_INETD is not set
934# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
935# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
936# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
937# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
938# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
939# CONFIG_FEATURE_INETD_RPC is not set
940# CONFIG_IP is not set
941# CONFIG_IPADDR is not set
942# CONFIG_IPLINK is not set
943# CONFIG_IPROUTE is not set
944# CONFIG_IPTUNNEL is not set
945# CONFIG_IPRULE is not set
946# CONFIG_IPNEIGH is not set
947# CONFIG_FEATURE_IP_ADDRESS is not set
948# CONFIG_FEATURE_IP_LINK is not set
949# CONFIG_FEATURE_IP_ROUTE is not set
950CONFIG_FEATURE_IP_ROUTE_DIR=""
951# CONFIG_FEATURE_IP_TUNNEL is not set
952# CONFIG_FEATURE_IP_RULE is not set
953# CONFIG_FEATURE_IP_NEIGH is not set
954# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
955# CONFIG_IPCALC is not set
956# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set
957# CONFIG_FEATURE_IPCALC_FANCY is not set
958# CONFIG_FAKEIDENTD is not set
959# CONFIG_NAMEIF is not set
960# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
961# CONFIG_NBDCLIENT is not set
962# CONFIG_NC is not set
963# CONFIG_NETCAT is not set
964# CONFIG_NC_SERVER is not set
965# CONFIG_NC_EXTRA is not set
966# CONFIG_NC_110_COMPAT is not set
967# CONFIG_NETSTAT is not set
968# CONFIG_FEATURE_NETSTAT_WIDE is not set
969# CONFIG_FEATURE_NETSTAT_PRG is not set
970# CONFIG_NSLOOKUP is not set
971# CONFIG_FEATURE_NSLOOKUP_BIG is not set
972# CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS is not set
973# CONFIG_NTPD is not set
974# CONFIG_FEATURE_NTPD_SERVER is not set
975# CONFIG_FEATURE_NTPD_CONF is not set
976# CONFIG_FEATURE_NTP_AUTH is not set
977# CONFIG_PING is not set
978# CONFIG_PING6 is not set
979# CONFIG_FEATURE_FANCY_PING is not set
980# CONFIG_PSCAN is not set
981# CONFIG_ROUTE is not set
982# CONFIG_SLATTACH is not set
983# CONFIG_SSL_CLIENT is not set
984# CONFIG_TC is not set
985# CONFIG_FEATURE_TC_INGRESS is not set
986# CONFIG_TCPSVD is not set
987# CONFIG_UDPSVD is not set
988# CONFIG_TELNET is not set
989# CONFIG_FEATURE_TELNET_TTYPE is not set
990# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
991# CONFIG_FEATURE_TELNET_WIDTH is not set
992# CONFIG_TELNETD is not set
993# CONFIG_FEATURE_TELNETD_STANDALONE is not set
994CONFIG_FEATURE_TELNETD_PORT_DEFAULT=0
995# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
996# CONFIG_TFTP is not set
997# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
998# CONFIG_FEATURE_TFTP_HPA_COMPAT is not set
999# CONFIG_TFTPD is not set
1000# CONFIG_FEATURE_TFTP_GET is not set
1001# CONFIG_FEATURE_TFTP_PUT is not set
1002# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
1003# CONFIG_TFTP_DEBUG is not set
1004# CONFIG_TLS is not set
1005# CONFIG_TRACEROUTE is not set
1006# CONFIG_TRACEROUTE6 is not set
1007# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
1008# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
1009# CONFIG_TUNCTL is not set
1010# CONFIG_FEATURE_TUNCTL_UG is not set
1011# CONFIG_VCONFIG is not set
1012# CONFIG_WGET is not set
1013# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set
1014# CONFIG_FEATURE_WGET_STATUSBAR is not set
1015# CONFIG_FEATURE_WGET_FTP is not set
1016# CONFIG_FEATURE_WGET_AUTHENTICATION is not set
1017# CONFIG_FEATURE_WGET_TIMEOUT is not set
1018# CONFIG_FEATURE_WGET_HTTPS is not set
1019# CONFIG_FEATURE_WGET_OPENSSL is not set
1020# CONFIG_WHOIS is not set
1021# CONFIG_ZCIP is not set
1022# CONFIG_UDHCPD is not set
1023# CONFIG_FEATURE_UDHCPD_BOOTP is not set
1024# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
1025# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
1026CONFIG_DHCPD_LEASES_FILE=""
1027# CONFIG_DUMPLEASES is not set
1028# CONFIG_DHCPRELAY is not set
1029# CONFIG_UDHCPC is not set
1030# CONFIG_FEATURE_UDHCPC_ARPING is not set
1031# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
1032CONFIG_UDHCPC_DEFAULT_SCRIPT=""
1033CONFIG_UDHCPC6_DEFAULT_SCRIPT=""
1034# CONFIG_UDHCPC6 is not set
1035# CONFIG_FEATURE_UDHCPC6_RFC3646 is not set
1036# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set
1037# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set
1038# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set
1039CONFIG_UDHCPC_DEFAULT_INTERFACE=""
1040# CONFIG_FEATURE_UDHCP_PORT is not set
1041CONFIG_UDHCP_DEBUG=0
1042CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
1043# CONFIG_FEATURE_UDHCP_RFC3397 is not set
1044# CONFIG_FEATURE_UDHCP_8021Q is not set
1045CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
1046
1047#
1048# Print Utilities
1049#
1050# CONFIG_LPD is not set
1051# CONFIG_LPR is not set
1052# CONFIG_LPQ is not set
1053
1054#
1055# Mail Utilities
1056#
1057CONFIG_FEATURE_MIME_CHARSET=""
1058# CONFIG_MAKEMIME is not set
1059# CONFIG_POPMAILDIR is not set
1060# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
1061# CONFIG_REFORMIME is not set
1062# CONFIG_FEATURE_REFORMIME_COMPAT is not set
1063# CONFIG_SENDMAIL is not set
1064
1065#
1066# Process Utilities
1067#
1068# CONFIG_FEATURE_FAST_TOP is not set
1069# CONFIG_FEATURE_SHOW_THREADS is not set
1070# CONFIG_FREE is not set
1071# CONFIG_FUSER is not set
1072# CONFIG_IOSTAT is not set
1073# CONFIG_KILL is not set
1074# CONFIG_KILLALL is not set
1075# CONFIG_KILLALL5 is not set
1076# CONFIG_LSOF is not set
1077# CONFIG_MPSTAT is not set
1078# CONFIG_NMETER is not set
1079# CONFIG_PGREP is not set
1080# CONFIG_PKILL is not set
1081# CONFIG_PIDOF is not set
1082# CONFIG_FEATURE_PIDOF_SINGLE is not set
1083# CONFIG_FEATURE_PIDOF_OMIT is not set
1084# CONFIG_PMAP is not set
1085# CONFIG_POWERTOP is not set
1086# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set
1087# CONFIG_PS is not set
1088# CONFIG_FEATURE_PS_WIDE is not set
1089# CONFIG_FEATURE_PS_LONG is not set
1090# CONFIG_FEATURE_PS_TIME is not set
1091# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
1092# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
1093# CONFIG_PSTREE is not set
1094# CONFIG_PWDX is not set
1095# CONFIG_SMEMCAP is not set
1096# CONFIG_BB_SYSCTL is not set
1097# CONFIG_TOP is not set
1098# CONFIG_FEATURE_TOP_INTERACTIVE is not set
1099# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
1100# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
1101# CONFIG_FEATURE_TOP_SMP_CPU is not set
1102# CONFIG_FEATURE_TOP_DECIMALS is not set
1103# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
1104# CONFIG_FEATURE_TOPMEM is not set
1105# CONFIG_UPTIME is not set
1106# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
1107# CONFIG_WATCH is not set
1108
1109#
1110# Runit Utilities
1111#
1112# CONFIG_CHPST is not set
1113# CONFIG_SETUIDGID is not set
1114# CONFIG_ENVUIDGID is not set
1115# CONFIG_ENVDIR is not set
1116# CONFIG_SOFTLIMIT is not set
1117# CONFIG_RUNSV is not set
1118# CONFIG_RUNSVDIR is not set
1119# CONFIG_FEATURE_RUNSVDIR_LOG is not set
1120# CONFIG_SV is not set
1121CONFIG_SV_DEFAULT_SERVICE_DIR=""
1122# CONFIG_SVC is not set
1123# CONFIG_SVOK is not set
1124# CONFIG_SVLOGD is not set
1125# CONFIG_CHCON is not set
1126# CONFIG_GETENFORCE is not set
1127# CONFIG_GETSEBOOL is not set
1128# CONFIG_LOAD_POLICY is not set
1129# CONFIG_MATCHPATHCON is not set
1130# CONFIG_RUNCON is not set
1131# CONFIG_SELINUXENABLED is not set
1132# CONFIG_SESTATUS is not set
1133# CONFIG_SETENFORCE is not set
1134# CONFIG_SETFILES is not set
1135# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
1136# CONFIG_RESTORECON is not set
1137# CONFIG_SETSEBOOL is not set
1138
1139#
1140# Shells
1141#
1142CONFIG_SH_IS_ASH=y
1143# CONFIG_SH_IS_HUSH is not set
1144# CONFIG_SH_IS_NONE is not set
1145# CONFIG_BASH_IS_ASH is not set
1146# CONFIG_BASH_IS_HUSH is not set
1147CONFIG_BASH_IS_NONE=y
1148CONFIG_SHELL_ASH=y
1149CONFIG_ASH=y
1150CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
1151CONFIG_ASH_INTERNAL_GLOB=y
1152CONFIG_ASH_BASH_COMPAT=y
1153# CONFIG_ASH_BASH_SOURCE_CURDIR is not set
1154CONFIG_ASH_BASH_NOT_FOUND_HOOK=y
1155CONFIG_ASH_JOB_CONTROL=y
1156CONFIG_ASH_ALIAS=y
1157CONFIG_ASH_RANDOM_SUPPORT=y
1158CONFIG_ASH_EXPAND_PRMT=y
1159CONFIG_ASH_IDLE_TIMEOUT=y
1160CONFIG_ASH_MAIL=y
1161CONFIG_ASH_ECHO=y
1162CONFIG_ASH_PRINTF=y
1163CONFIG_ASH_TEST=y
1164CONFIG_ASH_HELP=y
1165CONFIG_ASH_GETOPTS=y
1166CONFIG_ASH_CMDCMD=y
1167CONFIG_ASH_NOCONSOLE=y
1168CONFIG_ASH_GLOB_OPTIONS=y
1169# CONFIG_CTTYHACK is not set
1170# CONFIG_HUSH is not set
1171# CONFIG_SHELL_HUSH is not set
1172# CONFIG_HUSH_BASH_COMPAT is not set
1173# CONFIG_HUSH_BRACE_EXPANSION is not set
1174# CONFIG_HUSH_BASH_SOURCE_CURDIR is not set
1175# CONFIG_HUSH_LINENO_VAR is not set
1176# CONFIG_HUSH_INTERACTIVE is not set
1177# CONFIG_HUSH_SAVEHISTORY is not set
1178# CONFIG_HUSH_JOB is not set
1179# CONFIG_HUSH_TICK is not set
1180# CONFIG_HUSH_IF is not set
1181# CONFIG_HUSH_LOOPS is not set
1182# CONFIG_HUSH_CASE is not set
1183# CONFIG_HUSH_FUNCTIONS is not set
1184# CONFIG_HUSH_LOCAL is not set
1185# CONFIG_HUSH_RANDOM_SUPPORT is not set
1186# CONFIG_HUSH_MODE_X is not set
1187# CONFIG_HUSH_ECHO is not set
1188# CONFIG_HUSH_PRINTF is not set
1189# CONFIG_HUSH_TEST is not set
1190# CONFIG_HUSH_HELP is not set
1191# CONFIG_HUSH_EXPORT is not set
1192# CONFIG_HUSH_EXPORT_N is not set
1193# CONFIG_HUSH_READONLY is not set
1194# CONFIG_HUSH_KILL is not set
1195# CONFIG_HUSH_WAIT is not set
1196# CONFIG_HUSH_COMMAND is not set
1197# CONFIG_HUSH_TRAP is not set
1198# CONFIG_HUSH_TYPE is not set
1199# CONFIG_HUSH_TIMES is not set
1200# CONFIG_HUSH_READ is not set
1201# CONFIG_HUSH_SET is not set
1202# CONFIG_HUSH_UNSET is not set
1203# CONFIG_HUSH_ULIMIT is not set
1204# CONFIG_HUSH_UMASK is not set
1205# CONFIG_HUSH_GETOPTS is not set
1206# CONFIG_HUSH_MEMLEAK is not set
1207
1208#
1209# Options common to all shells
1210#
1211CONFIG_FEATURE_SH_MATH=y
1212CONFIG_FEATURE_SH_MATH_64=y
1213CONFIG_FEATURE_SH_MATH_BASE=y
1214CONFIG_FEATURE_SH_EXTRA_QUIET=y
1215# CONFIG_FEATURE_SH_STANDALONE is not set
1216# CONFIG_FEATURE_SH_NOFORK is not set
1217CONFIG_FEATURE_SH_READ_FRAC=y
1218CONFIG_FEATURE_SH_HISTFILESIZE=y
1219# CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS is not set
1220
1221#
1222# System Logging Utilities
1223#
1224# CONFIG_KLOGD is not set
1225# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
1226# CONFIG_LOGGER is not set
1227# CONFIG_LOGREAD is not set
1228# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1229# CONFIG_SYSLOGD is not set
1230# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1231# CONFIG_FEATURE_REMOTE_LOG is not set
1232# CONFIG_FEATURE_SYSLOGD_DUP is not set
1233# CONFIG_FEATURE_SYSLOGD_CFG is not set
1234# CONFIG_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS is not set
1235CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1236# CONFIG_FEATURE_IPC_SYSLOG is not set
1237CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1238# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig
new file mode 100644
index 000000000..6f6bdb14b
--- /dev/null
+++ b/configs/mingw32_defconfig
@@ -0,0 +1,1256 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.37.0.git
4# Fri Jun 14 12:24:50 2024
5#
6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set
8CONFIG_PLATFORM_MINGW32=y
9
10#
11# Settings
12#
13CONFIG_DESKTOP=y
14# CONFIG_EXTRA_COMPAT is not set
15# CONFIG_FEDORA_COMPAT is not set
16# CONFIG_INCLUDE_SUSv2 is not set
17CONFIG_LONG_OPTS=y
18CONFIG_SHOW_USAGE=y
19CONFIG_FEATURE_VERBOSE_USAGE=y
20CONFIG_FEATURE_COMPRESS_USAGE=y
21CONFIG_LFS=y
22CONFIG_TIME64=y
23# CONFIG_PAM is not set
24# CONFIG_FEATURE_DEVPTS is not set
25# CONFIG_FEATURE_UTMP is not set
26# CONFIG_FEATURE_WTMP is not set
27# CONFIG_FEATURE_PIDFILE is not set
28CONFIG_PID_FILE_PATH=""
29CONFIG_BUSYBOX=y
30CONFIG_FEATURE_SHOW_SCRIPT=y
31CONFIG_FEATURE_INSTALLER=y
32# CONFIG_INSTALL_NO_USR is not set
33# CONFIG_FEATURE_SUID is not set
34# CONFIG_FEATURE_SUID_CONFIG is not set
35# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
36CONFIG_FEATURE_PREFER_APPLETS=y
37CONFIG_BUSYBOX_EXEC_PATH=""
38# CONFIG_SELINUX is not set
39# CONFIG_FEATURE_CLEAN_UP is not set
40# CONFIG_FEATURE_SYSLOG_INFO is not set
41# CONFIG_FEATURE_SYSLOG is not set
42
43#
44# Settings for MINGW32
45#
46CONFIG_GLOBBING=y
47CONFIG_FEATURE_PRNG_SHELL=y
48# CONFIG_FEATURE_PRNG_ISAAC is not set
49CONFIG_FEATURE_RESOURCES=y
50CONFIG_FEATURE_VERSIONINFO=y
51# CONFIG_FEATURE_TOOLCHAIN_MANIFEST is not set
52CONFIG_FEATURE_APP_MANIFEST=y
53# CONFIG_FEATURE_UTF8_MANIFEST is not set
54CONFIG_FEATURE_ICON=y
55# CONFIG_FEATURE_ICON_ATERM is not set
56# CONFIG_FEATURE_ICON_STERM is not set
57CONFIG_FEATURE_ICON_ALL=y
58CONFIG_FEATURE_EURO=y
59# CONFIG_FEATURE_UTF8_INPUT is not set
60# CONFIG_FEATURE_UTF8_OUTPUT is not set
61CONFIG_TERMINAL_MODE=5
62CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y
63CONFIG_FEATURE_EXTRA_FILE_DATA=y
64CONFIG_OVERRIDE_APPLETS=""
65
66#
67# Build Options
68#
69# CONFIG_STATIC is not set
70# CONFIG_PIE is not set
71# CONFIG_NOMMU is not set
72# CONFIG_BUILD_LIBBUSYBOX is not set
73# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set
74# CONFIG_FEATURE_INDIVIDUAL is not set
75# CONFIG_FEATURE_SHARED_BUSYBOX is not set
76CONFIG_CROSS_COMPILER_PREFIX="i686-w64-mingw32-"
77CONFIG_HOST_COMPILER="gcc"
78CONFIG_CROSS_COMPILER="gcc"
79CONFIG_SYSROOT=""
80CONFIG_EXTRA_CFLAGS=""
81CONFIG_EXTRA_LDFLAGS=""
82CONFIG_EXTRA_LDLIBS=""
83CONFIG_USE_PORTABLE_CODE=y
84CONFIG_STACK_OPTIMIZATION_386=y
85CONFIG_STATIC_LIBGCC=y
86
87#
88# Installation Options ("make install" behavior)
89#
90CONFIG_INSTALL_APPLET_SYMLINKS=y
91# CONFIG_INSTALL_APPLET_HARDLINKS is not set
92# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
93# CONFIG_INSTALL_APPLET_DONT is not set
94# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
95# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
96# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
97CONFIG_PREFIX=""
98
99#
100# Debugging Options
101#
102# CONFIG_DEBUG is not set
103# CONFIG_DEBUG_PESSIMIZE is not set
104# CONFIG_DEBUG_SANITIZE is not set
105# CONFIG_UNIT_TEST is not set
106# CONFIG_WERROR is not set
107# CONFIG_WARN_SIMPLE_MSG is not set
108CONFIG_NO_DEBUG_LIB=y
109# CONFIG_DMALLOC is not set
110# CONFIG_EFENCE is not set
111
112#
113# Library Tuning
114#
115# CONFIG_FEATURE_USE_BSS_TAIL is not set
116CONFIG_FLOAT_DURATION=y
117# CONFIG_FEATURE_RTMINMAX is not set
118# CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS is not set
119CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
120# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
121# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
122CONFIG_PASSWORD_MINLEN=6
123CONFIG_MD5_SMALL=1
124CONFIG_SHA1_SMALL=3
125# CONFIG_SHA1_HWACCEL is not set
126# CONFIG_SHA256_HWACCEL is not set
127CONFIG_SHA3_SMALL=1
128CONFIG_FEATURE_NON_POSIX_CP=y
129# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
130# CONFIG_FEATURE_USE_SENDFILE is not set
131CONFIG_FEATURE_COPYBUF_KB=4
132# CONFIG_MONOTONIC_SYSCALL is not set
133# CONFIG_IOCTL_HEX2STR_ERROR is not set
134CONFIG_FEATURE_EDITING=y
135CONFIG_FEATURE_EDITING_MAX_LEN=8192
136CONFIG_FEATURE_EDITING_VI=y
137CONFIG_FEATURE_EDITING_HISTORY=1023
138CONFIG_FEATURE_EDITING_HISTORY_DEFAULT=384
139CONFIG_FEATURE_EDITING_SAVEHISTORY=y
140# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
141CONFIG_FEATURE_REVERSE_SEARCH=y
142CONFIG_FEATURE_TAB_COMPLETION=y
143CONFIG_FEATURE_USERNAME_COMPLETION=y
144CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
145# CONFIG_FEATURE_EDITING_WINCH is not set
146# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
147# CONFIG_LOCALE_SUPPORT is not set
148# CONFIG_UNICODE_SUPPORT is not set
149# CONFIG_UNICODE_USING_LOCALE is not set
150# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
151CONFIG_SUBST_WCHAR=0
152CONFIG_LAST_SUPPORTED_WCHAR=0
153# CONFIG_UNICODE_COMBINING_WCHARS is not set
154# CONFIG_UNICODE_WIDE_WCHARS is not set
155# CONFIG_UNICODE_BIDI_SUPPORT is not set
156# CONFIG_UNICODE_NEUTRAL_TABLE is not set
157# CONFIG_UNICODE_PRESERVE_BROKEN is not set
158# CONFIG_LOOP_CONFIGURE is not set
159# CONFIG_NO_LOOP_CONFIGURE is not set
160CONFIG_TRY_LOOP_CONFIGURE=y
161
162#
163# Applets
164#
165
166#
167# Archival Utilities
168#
169CONFIG_FEATURE_SEAMLESS_XZ=y
170CONFIG_FEATURE_SEAMLESS_LZMA=y
171CONFIG_FEATURE_SEAMLESS_BZ2=y
172CONFIG_FEATURE_SEAMLESS_GZ=y
173CONFIG_FEATURE_SEAMLESS_Z=y
174CONFIG_AR=y
175CONFIG_FEATURE_AR_LONG_FILENAMES=y
176CONFIG_FEATURE_AR_CREATE=y
177CONFIG_UNCOMPRESS=y
178CONFIG_GUNZIP=y
179CONFIG_ZCAT=y
180CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y
181CONFIG_BUNZIP2=y
182CONFIG_BZCAT=y
183CONFIG_UNLZMA=y
184CONFIG_LZCAT=y
185CONFIG_LZMA=y
186CONFIG_UNXZ=y
187CONFIG_XZCAT=y
188CONFIG_XZ=y
189CONFIG_BZIP2=y
190CONFIG_BZIP2_SMALL=8
191CONFIG_FEATURE_BZIP2_DECOMPRESS=y
192CONFIG_CPIO=y
193CONFIG_FEATURE_CPIO_O=y
194# CONFIG_FEATURE_CPIO_P is not set
195CONFIG_FEATURE_CPIO_IGNORE_DEVNO=y
196CONFIG_FEATURE_CPIO_RENUMBER_INODES=y
197CONFIG_DPKG=y
198CONFIG_DPKG_DEB=y
199CONFIG_GZIP=y
200CONFIG_FEATURE_GZIP_LONG_OPTIONS=y
201CONFIG_GZIP_FAST=2
202CONFIG_FEATURE_GZIP_LEVELS=y
203CONFIG_FEATURE_GZIP_DECOMPRESS=y
204CONFIG_LZOP=y
205CONFIG_UNLZOP=y
206CONFIG_LZOPCAT=y
207# CONFIG_LZOP_COMPR_HIGH is not set
208CONFIG_RPM=y
209CONFIG_RPM2CPIO=y
210CONFIG_TAR=y
211CONFIG_FEATURE_TAR_LONG_OPTIONS=y
212CONFIG_FEATURE_TAR_CREATE=y
213CONFIG_FEATURE_TAR_AUTODETECT=y
214CONFIG_FEATURE_TAR_FROM=y
215CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
216# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
217CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
218# CONFIG_FEATURE_TAR_TO_COMMAND is not set
219# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
220CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
221# CONFIG_FEATURE_TAR_SELINUX is not set
222CONFIG_UNZIP=y
223CONFIG_FEATURE_UNZIP_CDF=y
224CONFIG_FEATURE_UNZIP_BZIP2=y
225CONFIG_FEATURE_UNZIP_LZMA=y
226CONFIG_FEATURE_UNZIP_XZ=y
227CONFIG_FEATURE_LZMA_FAST=y
228
229#
230# Coreutils
231#
232CONFIG_FEATURE_VERBOSE=y
233
234#
235# Common options for date and touch
236#
237CONFIG_FEATURE_TIMEZONE=y
238
239#
240# Common options for cp and mv
241#
242# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
243
244#
245# Common options for df, du, ls
246#
247CONFIG_FEATURE_HUMAN_READABLE=y
248CONFIG_BASENAME=y
249CONFIG_CAT=y
250CONFIG_FEATURE_CATN=y
251CONFIG_FEATURE_CATV=y
252# CONFIG_CHGRP is not set
253CONFIG_CHMOD=y
254# CONFIG_CHOWN is not set
255# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
256# CONFIG_CHROOT is not set
257CONFIG_CKSUM=y
258CONFIG_CRC32=y
259CONFIG_COMM=y
260CONFIG_CP=y
261CONFIG_FEATURE_CP_LONG_OPTIONS=y
262# CONFIG_FEATURE_CP_REFLINK is not set
263CONFIG_CUT=y
264CONFIG_FEATURE_CUT_REGEX=y
265CONFIG_DATE=y
266CONFIG_FEATURE_DATE_ISOFMT=y
267CONFIG_FEATURE_DATE_NANO=y
268CONFIG_FEATURE_DATE_COMPAT=y
269CONFIG_DD=y
270# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
271# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
272CONFIG_FEATURE_DD_IBS_OBS=y
273CONFIG_FEATURE_DD_STATUS=y
274CONFIG_DF=y
275# CONFIG_FEATURE_DF_FANCY is not set
276# CONFIG_FEATURE_SKIP_ROOTFS is not set
277CONFIG_DIRNAME=y
278CONFIG_DOS2UNIX=y
279CONFIG_UNIX2DOS=y
280CONFIG_DU=y
281CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
282CONFIG_ECHO=y
283CONFIG_FEATURE_FANCY_ECHO=y
284CONFIG_ENV=y
285CONFIG_EXPAND=y
286CONFIG_UNEXPAND=y
287CONFIG_EXPR=y
288CONFIG_EXPR_MATH_SUPPORT_64=y
289CONFIG_FACTOR=y
290CONFIG_FALSE=y
291CONFIG_FOLD=y
292CONFIG_HEAD=y
293CONFIG_FEATURE_FANCY_HEAD=y
294# CONFIG_HOSTID is not set
295CONFIG_ID=y
296CONFIG_GROUPS=y
297CONFIG_INSTALL=y
298CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y
299CONFIG_LINK=y
300CONFIG_LN=y
301CONFIG_LOGNAME=y
302CONFIG_LS=y
303CONFIG_FEATURE_LS_FILETYPES=y
304CONFIG_FEATURE_LS_FOLLOWLINKS=y
305CONFIG_FEATURE_LS_RECURSIVE=y
306CONFIG_FEATURE_LS_WIDTH=y
307CONFIG_FEATURE_LS_SORTFILES=y
308CONFIG_FEATURE_LS_TIMESTAMPS=y
309CONFIG_FEATURE_LS_USERNAME=y
310CONFIG_FEATURE_LS_COLOR=y
311CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
312CONFIG_MD5SUM=y
313CONFIG_SHA1SUM=y
314CONFIG_SHA256SUM=y
315CONFIG_SHA512SUM=y
316CONFIG_SHA3SUM=y
317
318#
319# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
320#
321CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
322CONFIG_MKDIR=y
323# CONFIG_MKFIFO is not set
324# CONFIG_MKNOD is not set
325CONFIG_MKTEMP=y
326CONFIG_MV=y
327# CONFIG_NICE is not set
328CONFIG_NL=y
329# CONFIG_NOHUP is not set
330CONFIG_NPROC=y
331CONFIG_OD=y
332CONFIG_PASTE=y
333CONFIG_PRINTENV=y
334CONFIG_PRINTF=y
335CONFIG_PWD=y
336CONFIG_READLINK=y
337CONFIG_FEATURE_READLINK_FOLLOW=y
338CONFIG_REALPATH=y
339CONFIG_RM=y
340CONFIG_RMDIR=y
341CONFIG_SEQ=y
342CONFIG_SHRED=y
343CONFIG_SHUF=y
344CONFIG_SLEEP=y
345CONFIG_FEATURE_FANCY_SLEEP=y
346CONFIG_SORT=y
347CONFIG_FEATURE_SORT_BIG=y
348# CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set
349CONFIG_SPLIT=y
350CONFIG_FEATURE_SPLIT_FANCY=y
351CONFIG_STAT=y
352CONFIG_FEATURE_STAT_FORMAT=y
353CONFIG_FEATURE_STAT_FILESYSTEM=y
354# CONFIG_STTY is not set
355CONFIG_SUM=y
356CONFIG_SYNC=y
357# CONFIG_FEATURE_SYNC_FANCY is not set
358CONFIG_FSYNC=y
359CONFIG_TAC=y
360CONFIG_TAIL=y
361CONFIG_FEATURE_FANCY_TAIL=y
362CONFIG_TEE=y
363CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
364CONFIG_TEST=y
365CONFIG_TEST1=y
366CONFIG_TEST2=y
367CONFIG_FEATURE_TEST_64=y
368CONFIG_TIMEOUT=y
369CONFIG_TOUCH=y
370CONFIG_FEATURE_TOUCH_SUSV3=y
371CONFIG_TR=y
372CONFIG_FEATURE_TR_CLASSES=y
373CONFIG_FEATURE_TR_EQUIV=y
374CONFIG_TRUE=y
375CONFIG_TRUNCATE=y
376CONFIG_TSORT=y
377# CONFIG_TTY is not set
378CONFIG_UNAME=y
379CONFIG_UNAME_OSNAME="MS/Windows"
380CONFIG_BB_ARCH=y
381CONFIG_UNIQ=y
382CONFIG_UNLINK=y
383CONFIG_USLEEP=y
384CONFIG_UUDECODE=y
385CONFIG_BASE32=y
386CONFIG_BASE64=y
387CONFIG_UUENCODE=y
388CONFIG_WC=y
389CONFIG_FEATURE_WC_LARGE=y
390# CONFIG_WHO is not set
391# CONFIG_W is not set
392# CONFIG_USERS is not set
393CONFIG_WHOAMI=y
394CONFIG_YES=y
395
396#
397# Console Utilities
398#
399# CONFIG_CHVT is not set
400CONFIG_CLEAR=y
401# CONFIG_DEALLOCVT is not set
402# CONFIG_DUMPKMAP is not set
403# CONFIG_FGCONSOLE is not set
404# CONFIG_KBD_MODE is not set
405# CONFIG_LOADFONT is not set
406# CONFIG_SETFONT is not set
407# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
408CONFIG_DEFAULT_SETFONT_DIR=""
409# CONFIG_FEATURE_LOADFONT_PSF2 is not set
410# CONFIG_FEATURE_LOADFONT_RAW is not set
411# CONFIG_LOADKMAP is not set
412# CONFIG_OPENVT is not set
413CONFIG_RESET=y
414# CONFIG_RESIZE is not set
415# CONFIG_FEATURE_RESIZE_PRINT is not set
416# CONFIG_SETCONSOLE is not set
417# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
418# CONFIG_SETKEYCODES is not set
419# CONFIG_SETLOGCONS is not set
420# CONFIG_SHOWKEY is not set
421
422#
423# Debian Utilities
424#
425CONFIG_PIPE_PROGRESS=y
426# CONFIG_RUN_PARTS is not set
427# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
428# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
429# CONFIG_START_STOP_DAEMON is not set
430# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
431# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
432CONFIG_WHICH=y
433
434#
435# klibc-utils
436#
437# CONFIG_MINIPS is not set
438# CONFIG_NUKE is not set
439# CONFIG_RESUME is not set
440# CONFIG_RUN_INIT is not set
441
442#
443# Editors
444#
445CONFIG_AWK=y
446CONFIG_FEATURE_AWK_LIBM=y
447CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
448CONFIG_CMP=y
449CONFIG_DIFF=y
450CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
451CONFIG_FEATURE_DIFF_DIR=y
452CONFIG_ED=y
453CONFIG_PATCH=y
454CONFIG_SED=y
455CONFIG_VI=y
456CONFIG_FEATURE_VI_MAX_LEN=4096
457CONFIG_FEATURE_VI_8BIT=y
458CONFIG_FEATURE_VI_COLON=y
459CONFIG_FEATURE_VI_COLON_EXPAND=y
460CONFIG_FEATURE_VI_YANKMARK=y
461CONFIG_FEATURE_VI_SEARCH=y
462CONFIG_FEATURE_VI_REGEX_SEARCH=y
463# CONFIG_FEATURE_VI_USE_SIGNALS is not set
464CONFIG_FEATURE_VI_DOT_CMD=y
465CONFIG_FEATURE_VI_READONLY=y
466CONFIG_FEATURE_VI_SETOPTS=y
467CONFIG_FEATURE_VI_FILE_FORMAT=y
468CONFIG_FEATURE_VI_SET=y
469CONFIG_FEATURE_VI_WIN_RESIZE=y
470# CONFIG_FEATURE_VI_ASK_TERMINAL is not set
471CONFIG_FEATURE_VI_UNDO=y
472CONFIG_FEATURE_VI_UNDO_QUEUE=y
473CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
474CONFIG_FEATURE_VI_VERBOSE_STATUS=y
475CONFIG_FEATURE_ALLOW_EXEC=y
476
477#
478# Finding Utilities
479#
480CONFIG_FIND=y
481CONFIG_FEATURE_FIND_PRINT0=y
482CONFIG_FEATURE_FIND_MTIME=y
483CONFIG_FEATURE_FIND_ATIME=y
484CONFIG_FEATURE_FIND_CTIME=y
485CONFIG_FEATURE_FIND_MMIN=y
486CONFIG_FEATURE_FIND_AMIN=y
487CONFIG_FEATURE_FIND_CMIN=y
488CONFIG_FEATURE_FIND_PERM=y
489CONFIG_FEATURE_FIND_TYPE=y
490CONFIG_FEATURE_FIND_EXECUTABLE=y
491CONFIG_FEATURE_FIND_XDEV=y
492CONFIG_FEATURE_FIND_MAXDEPTH=y
493CONFIG_FEATURE_FIND_NEWER=y
494CONFIG_FEATURE_FIND_INUM=y
495CONFIG_FEATURE_FIND_SAMEFILE=y
496CONFIG_FEATURE_FIND_EXEC=y
497CONFIG_FEATURE_FIND_EXEC_PLUS=y
498CONFIG_FEATURE_FIND_EXEC_OK=y
499# CONFIG_FEATURE_FIND_USER is not set
500# CONFIG_FEATURE_FIND_GROUP is not set
501CONFIG_FEATURE_FIND_NOT=y
502CONFIG_FEATURE_FIND_DEPTH=y
503CONFIG_FEATURE_FIND_PAREN=y
504CONFIG_FEATURE_FIND_SIZE=y
505CONFIG_FEATURE_FIND_PRUNE=y
506CONFIG_FEATURE_FIND_QUIT=y
507CONFIG_FEATURE_FIND_DELETE=y
508CONFIG_FEATURE_FIND_EMPTY=y
509CONFIG_FEATURE_FIND_PATH=y
510CONFIG_FEATURE_FIND_REGEX=y
511# CONFIG_FEATURE_FIND_CONTEXT is not set
512CONFIG_FEATURE_FIND_LINKS=y
513CONFIG_GREP=y
514CONFIG_EGREP=y
515CONFIG_FGREP=y
516CONFIG_FEATURE_GREP_CONTEXT=y
517CONFIG_XARGS=y
518CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
519CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
520CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
521CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
522CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
523CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y
524CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y
525
526#
527# Init Utilities
528#
529# CONFIG_BOOTCHARTD is not set
530# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
531# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
532# CONFIG_HALT is not set
533# CONFIG_POWEROFF is not set
534# CONFIG_REBOOT is not set
535# CONFIG_FEATURE_WAIT_FOR_INIT is not set
536# CONFIG_FEATURE_CALL_TELINIT is not set
537CONFIG_TELINIT_PATH=""
538# CONFIG_INIT is not set
539# CONFIG_LINUXRC is not set
540# CONFIG_FEATURE_USE_INITTAB is not set
541# CONFIG_FEATURE_KILL_REMOVED is not set
542CONFIG_FEATURE_KILL_DELAY=0
543# CONFIG_FEATURE_INIT_SCTTY is not set
544# CONFIG_FEATURE_INIT_SYSLOG is not set
545# CONFIG_FEATURE_INIT_QUIET is not set
546# CONFIG_FEATURE_INIT_COREDUMPS is not set
547CONFIG_INIT_TERMINAL_TYPE=""
548# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
549
550#
551# Login/Password Management Utilities
552#
553# CONFIG_FEATURE_SHADOWPASSWDS is not set
554# CONFIG_USE_BB_PWD_GRP is not set
555# CONFIG_USE_BB_SHADOW is not set
556# CONFIG_USE_BB_CRYPT is not set
557# CONFIG_USE_BB_CRYPT_SHA is not set
558# CONFIG_ADD_SHELL is not set
559# CONFIG_REMOVE_SHELL is not set
560# CONFIG_ADDGROUP is not set
561# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
562# CONFIG_ADDUSER is not set
563# CONFIG_FEATURE_CHECK_NAMES is not set
564CONFIG_LAST_ID=0
565CONFIG_FIRST_SYSTEM_ID=0
566CONFIG_LAST_SYSTEM_ID=0
567# CONFIG_CHPASSWD is not set
568CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
569# CONFIG_CRYPTPW is not set
570# CONFIG_MKPASSWD is not set
571# CONFIG_DELUSER is not set
572# CONFIG_DELGROUP is not set
573# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
574# CONFIG_GETTY is not set
575# CONFIG_LOGIN is not set
576# CONFIG_LOGIN_SESSION_AS_CHILD is not set
577# CONFIG_LOGIN_SCRIPTS is not set
578# CONFIG_FEATURE_NOLOGIN is not set
579# CONFIG_FEATURE_SECURETTY is not set
580# CONFIG_PASSWD is not set
581# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
582# CONFIG_SU is not set
583# CONFIG_FEATURE_SU_SYSLOG is not set
584# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
585# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set
586# CONFIG_SULOGIN is not set
587CONFIG_SUW32=y
588# CONFIG_VLOCK is not set
589
590#
591# Linux Ext2 FS Progs
592#
593CONFIG_CHATTR=y
594# CONFIG_FSCK is not set
595CONFIG_LSATTR=y
596# CONFIG_TUNE2FS is not set
597
598#
599# Linux Module Utilities
600#
601# CONFIG_MODPROBE_SMALL is not set
602# CONFIG_DEPMOD is not set
603# CONFIG_INSMOD is not set
604# CONFIG_LSMOD is not set
605# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
606# CONFIG_MODINFO is not set
607# CONFIG_MODPROBE is not set
608# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
609# CONFIG_RMMOD is not set
610
611#
612# Options common to multiple modutils
613#
614# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set
615# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
616# CONFIG_FEATURE_2_4_MODULES is not set
617# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
618# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
619# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
620# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
621# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
622# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
623# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
624# CONFIG_FEATURE_MODUTILS_ALIAS is not set
625# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
626CONFIG_DEFAULT_MODULES_DIR=""
627CONFIG_DEFAULT_DEPMOD_FILE=""
628
629#
630# Linux System Utilities
631#
632# CONFIG_ACPID is not set
633# CONFIG_FEATURE_ACPID_COMPAT is not set
634# CONFIG_BLKDISCARD is not set
635# CONFIG_BLKID is not set
636# CONFIG_FEATURE_BLKID_TYPE is not set
637# CONFIG_BLOCKDEV is not set
638CONFIG_CAL=y
639# CONFIG_CHRT is not set
640# CONFIG_DMESG is not set
641# CONFIG_FEATURE_DMESG_PRETTY is not set
642# CONFIG_EJECT is not set
643# CONFIG_FEATURE_EJECT_SCSI is not set
644# CONFIG_FALLOCATE is not set
645# CONFIG_FATATTR is not set
646# CONFIG_FBSET is not set
647# CONFIG_FEATURE_FBSET_FANCY is not set
648# CONFIG_FEATURE_FBSET_READMODE is not set
649# CONFIG_FDFORMAT is not set
650# CONFIG_FDISK is not set
651# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
652# CONFIG_FEATURE_FDISK_WRITABLE is not set
653# CONFIG_FEATURE_AIX_LABEL is not set
654# CONFIG_FEATURE_SGI_LABEL is not set
655# CONFIG_FEATURE_SUN_LABEL is not set
656# CONFIG_FEATURE_OSF_LABEL is not set
657# CONFIG_FEATURE_GPT_LABEL is not set
658# CONFIG_FEATURE_FDISK_ADVANCED is not set
659# CONFIG_FINDFS is not set
660# CONFIG_FLOCK is not set
661# CONFIG_FDFLUSH is not set
662# CONFIG_FREERAMDISK is not set
663# CONFIG_FSCK_MINIX is not set
664# CONFIG_FSFREEZE is not set
665# CONFIG_FSTRIM is not set
666CONFIG_GETOPT=y
667CONFIG_FEATURE_GETOPT_LONG=y
668CONFIG_HEXDUMP=y
669CONFIG_HD=y
670CONFIG_XXD=y
671# CONFIG_HWCLOCK is not set
672# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
673# CONFIG_IONICE is not set
674# CONFIG_IPCRM is not set
675# CONFIG_IPCS is not set
676# CONFIG_LAST is not set
677# CONFIG_FEATURE_LAST_FANCY is not set
678# CONFIG_LOSETUP is not set
679# CONFIG_LSPCI is not set
680# CONFIG_LSUSB is not set
681# CONFIG_MDEV is not set
682# CONFIG_FEATURE_MDEV_CONF is not set
683# CONFIG_FEATURE_MDEV_RENAME is not set
684# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
685# CONFIG_FEATURE_MDEV_EXEC is not set
686# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
687# CONFIG_FEATURE_MDEV_DAEMON is not set
688# CONFIG_MESG is not set
689# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
690# CONFIG_MKE2FS is not set
691# CONFIG_MKFS_EXT2 is not set
692# CONFIG_MKFS_MINIX is not set
693# CONFIG_FEATURE_MINIX2 is not set
694# CONFIG_MKFS_REISER is not set
695# CONFIG_MKDOSFS is not set
696# CONFIG_MKFS_VFAT is not set
697# CONFIG_MKSWAP is not set
698# CONFIG_FEATURE_MKSWAP_UUID is not set
699# CONFIG_MORE is not set
700# CONFIG_MOUNT is not set
701# CONFIG_FEATURE_MOUNT_FAKE is not set
702# CONFIG_FEATURE_MOUNT_VERBOSE is not set
703# CONFIG_FEATURE_MOUNT_HELPERS is not set
704# CONFIG_FEATURE_MOUNT_LABEL is not set
705# CONFIG_FEATURE_MOUNT_NFS is not set
706# CONFIG_FEATURE_MOUNT_CIFS is not set
707# CONFIG_FEATURE_MOUNT_FLAGS is not set
708# CONFIG_FEATURE_MOUNT_FSTAB is not set
709# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
710# CONFIG_MOUNTPOINT is not set
711# CONFIG_NOLOGIN is not set
712# CONFIG_NOLOGIN_DEPENDENCIES is not set
713# CONFIG_NSENTER is not set
714# CONFIG_PIVOT_ROOT is not set
715# CONFIG_RDATE is not set
716# CONFIG_RDEV is not set
717# CONFIG_READPROFILE is not set
718# CONFIG_RENICE is not set
719CONFIG_REV=y
720# CONFIG_RTCWAKE is not set
721# CONFIG_SCRIPT is not set
722# CONFIG_SCRIPTREPLAY is not set
723# CONFIG_SETARCH is not set
724# CONFIG_LINUX32 is not set
725# CONFIG_LINUX64 is not set
726# CONFIG_SETPRIV is not set
727# CONFIG_FEATURE_SETPRIV_DUMP is not set
728# CONFIG_FEATURE_SETPRIV_CAPABILITIES is not set
729# CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES is not set
730# CONFIG_SETSID is not set
731# CONFIG_SWAPON is not set
732# CONFIG_FEATURE_SWAPON_DISCARD is not set
733# CONFIG_FEATURE_SWAPON_PRI is not set
734# CONFIG_SWAPOFF is not set
735# CONFIG_FEATURE_SWAPONOFF_LABEL is not set
736# CONFIG_SWITCH_ROOT is not set
737# CONFIG_TASKSET is not set
738# CONFIG_FEATURE_TASKSET_FANCY is not set
739# CONFIG_FEATURE_TASKSET_CPULIST is not set
740# CONFIG_UEVENT is not set
741# CONFIG_UMOUNT is not set
742# CONFIG_FEATURE_UMOUNT_ALL is not set
743# CONFIG_UNSHARE is not set
744# CONFIG_WALL is not set
745# CONFIG_FEATURE_MOUNT_LOOP is not set
746# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
747# CONFIG_FEATURE_MTAB_SUPPORT is not set
748# CONFIG_VOLUMEID is not set
749# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
750# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
751# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
752# CONFIG_FEATURE_VOLUMEID_EROFS is not set
753# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
754# CONFIG_FEATURE_VOLUMEID_EXT is not set
755# CONFIG_FEATURE_VOLUMEID_F2FS is not set
756# CONFIG_FEATURE_VOLUMEID_FAT is not set
757# CONFIG_FEATURE_VOLUMEID_HFS is not set
758# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
759# CONFIG_FEATURE_VOLUMEID_JFS is not set
760# CONFIG_FEATURE_VOLUMEID_LFS is not set
761# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
762# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
763# CONFIG_FEATURE_VOLUMEID_LUKS is not set
764# CONFIG_FEATURE_VOLUMEID_MINIX is not set
765# CONFIG_FEATURE_VOLUMEID_NILFS is not set
766# CONFIG_FEATURE_VOLUMEID_NTFS is not set
767# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
768# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
769# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
770# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
771# CONFIG_FEATURE_VOLUMEID_SYSV is not set
772# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
773# CONFIG_FEATURE_VOLUMEID_UDF is not set
774# CONFIG_FEATURE_VOLUMEID_XFS is not set
775
776#
777# Miscellaneous Utilities
778#
779# CONFIG_ADJTIMEX is not set
780CONFIG_ASCII=y
781# CONFIG_BBCONFIG is not set
782# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
783CONFIG_BC=y
784CONFIG_DC=y
785CONFIG_FEATURE_DC_BIG=y
786# CONFIG_FEATURE_DC_LIBM is not set
787CONFIG_FEATURE_BC_INTERACTIVE=y
788CONFIG_FEATURE_BC_LONG_OPTIONS=y
789# CONFIG_BEEP is not set
790CONFIG_FEATURE_BEEP_FREQ=0
791CONFIG_FEATURE_BEEP_LENGTH_MS=0
792# CONFIG_CHAT is not set
793# CONFIG_FEATURE_CHAT_NOFAIL is not set
794# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
795# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
796# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
797# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
798# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
799# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
800# CONFIG_CONSPY is not set
801# CONFIG_CROND is not set
802# CONFIG_FEATURE_CROND_D is not set
803# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
804# CONFIG_FEATURE_CROND_SPECIAL_TIMES is not set
805CONFIG_FEATURE_CROND_DIR=""
806# CONFIG_CRONTAB is not set
807# CONFIG_DEVFSD is not set
808# CONFIG_DEVFSD_MODLOAD is not set
809# CONFIG_DEVFSD_FG_NP is not set
810# CONFIG_DEVFSD_VERBOSE is not set
811# CONFIG_FEATURE_DEVFS is not set
812# CONFIG_DEVMEM is not set
813CONFIG_DROP=y
814CONFIG_CDROP=y
815CONFIG_PDROP=y
816# CONFIG_FBSPLASH is not set
817# CONFIG_FLASH_ERASEALL is not set
818# CONFIG_FLASH_LOCK is not set
819# CONFIG_FLASH_UNLOCK is not set
820# CONFIG_FLASHCP is not set
821# CONFIG_GETFATTR is not set
822# CONFIG_HDPARM is not set
823# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
824# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
825# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
826# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
827# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
828# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
829# CONFIG_HEXEDIT is not set
830# CONFIG_I2CGET is not set
831# CONFIG_I2CSET is not set
832# CONFIG_I2CDUMP is not set
833# CONFIG_I2CDETECT is not set
834# CONFIG_I2CTRANSFER is not set
835CONFIG_ICONV=y
836CONFIG_INOTIFYD=y
837CONFIG_JN=y
838CONFIG_LESS=y
839CONFIG_FEATURE_LESS_MAXLINES=9999999
840CONFIG_FEATURE_LESS_BRACKETS=y
841CONFIG_FEATURE_LESS_FLAGS=y
842CONFIG_FEATURE_LESS_TRUNCATE=y
843CONFIG_FEATURE_LESS_MARKS=y
844CONFIG_FEATURE_LESS_REGEXP=y
845# CONFIG_FEATURE_LESS_WINCH is not set
846# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
847CONFIG_FEATURE_LESS_DASHCMD=y
848CONFIG_FEATURE_LESS_LINENUMS=y
849CONFIG_FEATURE_LESS_RAW=y
850CONFIG_FEATURE_LESS_ENV=y
851# CONFIG_LSSCSI is not set
852CONFIG_MAKE=y
853CONFIG_PDPMAKE=y
854CONFIG_FEATURE_MAKE_POSIX=y
855# CONFIG_FEATURE_MAKE_POSIX_2017 is not set
856CONFIG_FEATURE_MAKE_POSIX_2024=y
857# CONFIG_MAKEDEVS is not set
858# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
859# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
860CONFIG_MAN=y
861# CONFIG_MICROCOM is not set
862# CONFIG_MIM is not set
863# CONFIG_MT is not set
864# CONFIG_NANDWRITE is not set
865# CONFIG_NANDDUMP is not set
866# CONFIG_PARTPROBE is not set
867# CONFIG_RAIDAUTORUN is not set
868# CONFIG_READAHEAD is not set
869# CONFIG_RFKILL is not set
870# CONFIG_RUNLEVEL is not set
871# CONFIG_RX is not set
872# CONFIG_SEEDRNG is not set
873# CONFIG_SETFATTR is not set
874# CONFIG_SETSERIAL is not set
875CONFIG_STRINGS=y
876CONFIG_TIME=y
877# CONFIG_TREE is not set
878CONFIG_TS=y
879CONFIG_TTYSIZE=y
880# CONFIG_UBIATTACH is not set
881# CONFIG_UBIDETACH is not set
882# CONFIG_UBIMKVOL is not set
883# CONFIG_UBIRMVOL is not set
884# CONFIG_UBIRSVOL is not set
885# CONFIG_UBIUPDATEVOL is not set
886# CONFIG_UBIRENAME is not set
887# CONFIG_VOLNAME is not set
888# CONFIG_WATCHDOG is not set
889# CONFIG_FEATURE_WATCHDOG_OPEN_TWICE is not set
890
891#
892# Networking Utilities
893#
894CONFIG_FEATURE_IPV6=y
895# CONFIG_FEATURE_UNIX_LOCAL is not set
896CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
897# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
898# CONFIG_FEATURE_ETC_NETWORKS is not set
899# CONFIG_FEATURE_ETC_SERVICES is not set
900# CONFIG_FEATURE_HWIB is not set
901# CONFIG_FEATURE_TLS_SHA1 is not set
902# CONFIG_ARP is not set
903# CONFIG_ARPING is not set
904# CONFIG_BRCTL is not set
905# CONFIG_FEATURE_BRCTL_FANCY is not set
906# CONFIG_FEATURE_BRCTL_SHOW is not set
907# CONFIG_DNSD is not set
908# CONFIG_ETHER_WAKE is not set
909# CONFIG_FTPD is not set
910# CONFIG_FEATURE_FTPD_WRITE is not set
911# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
912# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
913CONFIG_FTPGET=y
914CONFIG_FTPPUT=y
915CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
916# CONFIG_HOSTNAME is not set
917# CONFIG_DNSDOMAINNAME is not set
918CONFIG_HTTPD=y
919CONFIG_FEATURE_HTTPD_PORT_DEFAULT=80
920CONFIG_FEATURE_HTTPD_RANGES=y
921# CONFIG_FEATURE_HTTPD_SETUID is not set
922CONFIG_FEATURE_HTTPD_BASIC_AUTH=y
923# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
924CONFIG_FEATURE_HTTPD_CGI=y
925CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y
926# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
927CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y
928CONFIG_FEATURE_HTTPD_ERROR_PAGES=y
929# CONFIG_FEATURE_HTTPD_PROXY is not set
930CONFIG_FEATURE_HTTPD_GZIP=y
931CONFIG_FEATURE_HTTPD_ETAG=y
932CONFIG_FEATURE_HTTPD_LAST_MODIFIED=y
933CONFIG_FEATURE_HTTPD_DATE=y
934CONFIG_FEATURE_HTTPD_ACL_IP=y
935# CONFIG_IFCONFIG is not set
936# CONFIG_FEATURE_IFCONFIG_STATUS is not set
937# CONFIG_FEATURE_IFCONFIG_SLIP is not set
938# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
939# CONFIG_FEATURE_IFCONFIG_HW is not set
940# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
941# CONFIG_IFENSLAVE is not set
942# CONFIG_IFPLUGD is not set
943# CONFIG_IFUP is not set
944# CONFIG_IFDOWN is not set
945CONFIG_IFUPDOWN_IFSTATE_PATH=""
946# CONFIG_FEATURE_IFUPDOWN_IP is not set
947# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
948# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
949# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
950# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
951# CONFIG_INETD is not set
952# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
953# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
954# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
955# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
956# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
957# CONFIG_FEATURE_INETD_RPC is not set
958# CONFIG_IP is not set
959# CONFIG_IPADDR is not set
960# CONFIG_IPLINK is not set
961# CONFIG_IPROUTE is not set
962# CONFIG_IPTUNNEL is not set
963# CONFIG_IPRULE is not set
964# CONFIG_IPNEIGH is not set
965# CONFIG_FEATURE_IP_ADDRESS is not set
966# CONFIG_FEATURE_IP_LINK is not set
967# CONFIG_FEATURE_IP_ROUTE is not set
968CONFIG_FEATURE_IP_ROUTE_DIR=""
969# CONFIG_FEATURE_IP_TUNNEL is not set
970# CONFIG_FEATURE_IP_RULE is not set
971# CONFIG_FEATURE_IP_NEIGH is not set
972# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
973CONFIG_IPCALC=y
974CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y
975CONFIG_FEATURE_IPCALC_FANCY=y
976# CONFIG_FAKEIDENTD is not set
977# CONFIG_NAMEIF is not set
978# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
979# CONFIG_NBDCLIENT is not set
980CONFIG_NC=y
981# CONFIG_NETCAT is not set
982CONFIG_NC_SERVER=y
983# CONFIG_NC_EXTRA is not set
984# CONFIG_NC_110_COMPAT is not set
985# CONFIG_NETSTAT is not set
986# CONFIG_FEATURE_NETSTAT_WIDE is not set
987# CONFIG_FEATURE_NETSTAT_PRG is not set
988# CONFIG_NSLOOKUP is not set
989# CONFIG_FEATURE_NSLOOKUP_BIG is not set
990# CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS is not set
991# CONFIG_NTPD is not set
992# CONFIG_FEATURE_NTPD_SERVER is not set
993# CONFIG_FEATURE_NTPD_CONF is not set
994# CONFIG_FEATURE_NTP_AUTH is not set
995# CONFIG_PING is not set
996# CONFIG_PING6 is not set
997# CONFIG_FEATURE_FANCY_PING is not set
998# CONFIG_PSCAN is not set
999# CONFIG_ROUTE is not set
1000# CONFIG_SLATTACH is not set
1001CONFIG_SSL_CLIENT=y
1002# CONFIG_TC is not set
1003# CONFIG_FEATURE_TC_INGRESS is not set
1004# CONFIG_TCPSVD is not set
1005# CONFIG_UDPSVD is not set
1006# CONFIG_TELNET is not set
1007# CONFIG_FEATURE_TELNET_TTYPE is not set
1008# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
1009# CONFIG_FEATURE_TELNET_WIDTH is not set
1010# CONFIG_TELNETD is not set
1011# CONFIG_FEATURE_TELNETD_STANDALONE is not set
1012CONFIG_FEATURE_TELNETD_PORT_DEFAULT=0
1013# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
1014# CONFIG_TFTP is not set
1015# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
1016# CONFIG_FEATURE_TFTP_HPA_COMPAT is not set
1017# CONFIG_TFTPD is not set
1018# CONFIG_FEATURE_TFTP_GET is not set
1019# CONFIG_FEATURE_TFTP_PUT is not set
1020# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
1021# CONFIG_TFTP_DEBUG is not set
1022CONFIG_TLS=y
1023# CONFIG_TRACEROUTE is not set
1024# CONFIG_TRACEROUTE6 is not set
1025# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
1026# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
1027# CONFIG_TUNCTL is not set
1028# CONFIG_FEATURE_TUNCTL_UG is not set
1029# CONFIG_VCONFIG is not set
1030CONFIG_WGET=y
1031CONFIG_FEATURE_WGET_LONG_OPTIONS=y
1032CONFIG_FEATURE_WGET_STATUSBAR=y
1033CONFIG_FEATURE_WGET_FTP=y
1034CONFIG_FEATURE_WGET_AUTHENTICATION=y
1035# CONFIG_FEATURE_WGET_TIMEOUT is not set
1036CONFIG_FEATURE_WGET_HTTPS=y
1037# CONFIG_FEATURE_WGET_OPENSSL is not set
1038CONFIG_WHOIS=y
1039# CONFIG_ZCIP is not set
1040# CONFIG_UDHCPD is not set
1041# CONFIG_FEATURE_UDHCPD_BOOTP is not set
1042# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
1043# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
1044CONFIG_DHCPD_LEASES_FILE=""
1045# CONFIG_DUMPLEASES is not set
1046# CONFIG_DHCPRELAY is not set
1047# CONFIG_UDHCPC is not set
1048# CONFIG_FEATURE_UDHCPC_ARPING is not set
1049# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
1050CONFIG_UDHCPC_DEFAULT_SCRIPT=""
1051CONFIG_UDHCPC6_DEFAULT_SCRIPT=""
1052# CONFIG_UDHCPC6 is not set
1053# CONFIG_FEATURE_UDHCPC6_RFC3646 is not set
1054# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set
1055# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set
1056# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set
1057CONFIG_UDHCPC_DEFAULT_INTERFACE=""
1058# CONFIG_FEATURE_UDHCP_PORT is not set
1059CONFIG_UDHCP_DEBUG=0
1060CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
1061# CONFIG_FEATURE_UDHCP_RFC3397 is not set
1062# CONFIG_FEATURE_UDHCP_8021Q is not set
1063CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
1064
1065#
1066# Print Utilities
1067#
1068# CONFIG_LPD is not set
1069# CONFIG_LPR is not set
1070# CONFIG_LPQ is not set
1071
1072#
1073# Mail Utilities
1074#
1075CONFIG_FEATURE_MIME_CHARSET=""
1076# CONFIG_MAKEMIME is not set
1077# CONFIG_POPMAILDIR is not set
1078# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
1079# CONFIG_REFORMIME is not set
1080# CONFIG_FEATURE_REFORMIME_COMPAT is not set
1081# CONFIG_SENDMAIL is not set
1082
1083#
1084# Process Utilities
1085#
1086# CONFIG_FEATURE_FAST_TOP is not set
1087# CONFIG_FEATURE_SHOW_THREADS is not set
1088CONFIG_FREE=y
1089# CONFIG_FUSER is not set
1090# CONFIG_IOSTAT is not set
1091CONFIG_KILL=y
1092CONFIG_KILLALL=y
1093# CONFIG_KILLALL5 is not set
1094# CONFIG_LSOF is not set
1095# CONFIG_MPSTAT is not set
1096# CONFIG_NMETER is not set
1097CONFIG_PGREP=y
1098CONFIG_PKILL=y
1099CONFIG_PIDOF=y
1100CONFIG_FEATURE_PIDOF_SINGLE=y
1101CONFIG_FEATURE_PIDOF_OMIT=y
1102# CONFIG_PMAP is not set
1103# CONFIG_POWERTOP is not set
1104# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set
1105CONFIG_PS=y
1106# CONFIG_FEATURE_PS_WIDE is not set
1107# CONFIG_FEATURE_PS_LONG is not set
1108CONFIG_FEATURE_PS_TIME=y
1109# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
1110# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
1111# CONFIG_PSTREE is not set
1112# CONFIG_PWDX is not set
1113# CONFIG_SMEMCAP is not set
1114# CONFIG_BB_SYSCTL is not set
1115# CONFIG_TOP is not set
1116# CONFIG_FEATURE_TOP_INTERACTIVE is not set
1117# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
1118# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
1119# CONFIG_FEATURE_TOP_SMP_CPU is not set
1120# CONFIG_FEATURE_TOP_DECIMALS is not set
1121# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
1122# CONFIG_FEATURE_TOPMEM is not set
1123CONFIG_UPTIME=y
1124# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
1125CONFIG_WATCH=y
1126
1127#
1128# Runit Utilities
1129#
1130# CONFIG_CHPST is not set
1131# CONFIG_SETUIDGID is not set
1132# CONFIG_ENVUIDGID is not set
1133# CONFIG_ENVDIR is not set
1134# CONFIG_SOFTLIMIT is not set
1135# CONFIG_RUNSV is not set
1136# CONFIG_RUNSVDIR is not set
1137# CONFIG_FEATURE_RUNSVDIR_LOG is not set
1138# CONFIG_SV is not set
1139CONFIG_SV_DEFAULT_SERVICE_DIR=""
1140# CONFIG_SVC is not set
1141# CONFIG_SVOK is not set
1142# CONFIG_SVLOGD is not set
1143# CONFIG_CHCON is not set
1144# CONFIG_GETENFORCE is not set
1145# CONFIG_GETSEBOOL is not set
1146# CONFIG_LOAD_POLICY is not set
1147# CONFIG_MATCHPATHCON is not set
1148# CONFIG_RUNCON is not set
1149# CONFIG_SELINUXENABLED is not set
1150# CONFIG_SESTATUS is not set
1151# CONFIG_SETENFORCE is not set
1152# CONFIG_SETFILES is not set
1153# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
1154# CONFIG_RESTORECON is not set
1155# CONFIG_SETSEBOOL is not set
1156
1157#
1158# Shells
1159#
1160CONFIG_SH_IS_ASH=y
1161# CONFIG_SH_IS_HUSH is not set
1162# CONFIG_SH_IS_NONE is not set
1163CONFIG_BASH_IS_ASH=y
1164# CONFIG_BASH_IS_HUSH is not set
1165# CONFIG_BASH_IS_NONE is not set
1166CONFIG_SHELL_ASH=y
1167CONFIG_ASH=y
1168# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set
1169CONFIG_ASH_INTERNAL_GLOB=y
1170CONFIG_ASH_BASH_COMPAT=y
1171# CONFIG_ASH_BASH_SOURCE_CURDIR is not set
1172CONFIG_ASH_BASH_NOT_FOUND_HOOK=y
1173CONFIG_ASH_JOB_CONTROL=y
1174CONFIG_ASH_ALIAS=y
1175CONFIG_ASH_RANDOM_SUPPORT=y
1176CONFIG_ASH_EXPAND_PRMT=y
1177# CONFIG_ASH_IDLE_TIMEOUT is not set
1178# CONFIG_ASH_MAIL is not set
1179CONFIG_ASH_ECHO=y
1180CONFIG_ASH_PRINTF=y
1181CONFIG_ASH_TEST=y
1182CONFIG_ASH_HELP=y
1183CONFIG_ASH_GETOPTS=y
1184CONFIG_ASH_CMDCMD=y
1185CONFIG_ASH_NOCONSOLE=y
1186CONFIG_ASH_GLOB_OPTIONS=y
1187# CONFIG_CTTYHACK is not set
1188# CONFIG_HUSH is not set
1189# CONFIG_SHELL_HUSH is not set
1190# CONFIG_HUSH_BASH_COMPAT is not set
1191# CONFIG_HUSH_BRACE_EXPANSION is not set
1192# CONFIG_HUSH_BASH_SOURCE_CURDIR is not set
1193# CONFIG_HUSH_LINENO_VAR is not set
1194# CONFIG_HUSH_INTERACTIVE is not set
1195# CONFIG_HUSH_SAVEHISTORY is not set
1196# CONFIG_HUSH_JOB is not set
1197# CONFIG_HUSH_TICK is not set
1198# CONFIG_HUSH_IF is not set
1199# CONFIG_HUSH_LOOPS is not set
1200# CONFIG_HUSH_CASE is not set
1201# CONFIG_HUSH_FUNCTIONS is not set
1202# CONFIG_HUSH_LOCAL is not set
1203# CONFIG_HUSH_RANDOM_SUPPORT is not set
1204# CONFIG_HUSH_MODE_X is not set
1205# CONFIG_HUSH_ECHO is not set
1206# CONFIG_HUSH_PRINTF is not set
1207# CONFIG_HUSH_TEST is not set
1208# CONFIG_HUSH_HELP is not set
1209# CONFIG_HUSH_EXPORT is not set
1210# CONFIG_HUSH_EXPORT_N is not set
1211# CONFIG_HUSH_READONLY is not set
1212# CONFIG_HUSH_KILL is not set
1213# CONFIG_HUSH_WAIT is not set
1214# CONFIG_HUSH_COMMAND is not set
1215# CONFIG_HUSH_TRAP is not set
1216# CONFIG_HUSH_TYPE is not set
1217# CONFIG_HUSH_TIMES is not set
1218# CONFIG_HUSH_READ is not set
1219# CONFIG_HUSH_SET is not set
1220# CONFIG_HUSH_UNSET is not set
1221# CONFIG_HUSH_ULIMIT is not set
1222# CONFIG_HUSH_UMASK is not set
1223# CONFIG_HUSH_GETOPTS is not set
1224# CONFIG_HUSH_MEMLEAK is not set
1225
1226#
1227# Options common to all shells
1228#
1229CONFIG_FEATURE_SH_MATH=y
1230CONFIG_FEATURE_SH_MATH_64=y
1231CONFIG_FEATURE_SH_MATH_BASE=y
1232CONFIG_FEATURE_SH_EXTRA_QUIET=y
1233CONFIG_FEATURE_SH_STANDALONE=y
1234CONFIG_FEATURE_SH_NOFORK=y
1235CONFIG_FEATURE_SH_READ_FRAC=y
1236CONFIG_FEATURE_SH_HISTFILESIZE=y
1237CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS=y
1238
1239#
1240# System Logging Utilities
1241#
1242# CONFIG_KLOGD is not set
1243# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
1244# CONFIG_LOGGER is not set
1245# CONFIG_LOGREAD is not set
1246# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1247# CONFIG_SYSLOGD is not set
1248# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1249# CONFIG_FEATURE_REMOTE_LOG is not set
1250# CONFIG_FEATURE_SYSLOGD_DUP is not set
1251# CONFIG_FEATURE_SYSLOGD_CFG is not set
1252# CONFIG_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS is not set
1253CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1254# CONFIG_FEATURE_IPC_SYSLOG is not set
1255CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1256# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig
new file mode 100644
index 000000000..fbd2bc6e3
--- /dev/null
+++ b/configs/mingw64_defconfig
@@ -0,0 +1,1256 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.37.0.git
4# Fri Jun 14 12:24:50 2024
5#
6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set
8CONFIG_PLATFORM_MINGW32=y
9
10#
11# Settings
12#
13CONFIG_DESKTOP=y
14# CONFIG_EXTRA_COMPAT is not set
15# CONFIG_FEDORA_COMPAT is not set
16# CONFIG_INCLUDE_SUSv2 is not set
17CONFIG_LONG_OPTS=y
18CONFIG_SHOW_USAGE=y
19CONFIG_FEATURE_VERBOSE_USAGE=y
20CONFIG_FEATURE_COMPRESS_USAGE=y
21CONFIG_LFS=y
22CONFIG_TIME64=y
23# CONFIG_PAM is not set
24# CONFIG_FEATURE_DEVPTS is not set
25# CONFIG_FEATURE_UTMP is not set
26# CONFIG_FEATURE_WTMP is not set
27# CONFIG_FEATURE_PIDFILE is not set
28CONFIG_PID_FILE_PATH=""
29CONFIG_BUSYBOX=y
30CONFIG_FEATURE_SHOW_SCRIPT=y
31CONFIG_FEATURE_INSTALLER=y
32# CONFIG_INSTALL_NO_USR is not set
33# CONFIG_FEATURE_SUID is not set
34# CONFIG_FEATURE_SUID_CONFIG is not set
35# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
36CONFIG_FEATURE_PREFER_APPLETS=y
37CONFIG_BUSYBOX_EXEC_PATH=""
38# CONFIG_SELINUX is not set
39# CONFIG_FEATURE_CLEAN_UP is not set
40# CONFIG_FEATURE_SYSLOG_INFO is not set
41# CONFIG_FEATURE_SYSLOG is not set
42
43#
44# Settings for MINGW32
45#
46CONFIG_GLOBBING=y
47CONFIG_FEATURE_PRNG_SHELL=y
48# CONFIG_FEATURE_PRNG_ISAAC is not set
49CONFIG_FEATURE_RESOURCES=y
50CONFIG_FEATURE_VERSIONINFO=y
51# CONFIG_FEATURE_TOOLCHAIN_MANIFEST is not set
52CONFIG_FEATURE_APP_MANIFEST=y
53# CONFIG_FEATURE_UTF8_MANIFEST is not set
54CONFIG_FEATURE_ICON=y
55# CONFIG_FEATURE_ICON_ATERM is not set
56# CONFIG_FEATURE_ICON_STERM is not set
57CONFIG_FEATURE_ICON_ALL=y
58CONFIG_FEATURE_EURO=y
59# CONFIG_FEATURE_UTF8_INPUT is not set
60# CONFIG_FEATURE_UTF8_OUTPUT is not set
61CONFIG_TERMINAL_MODE=5
62CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y
63CONFIG_FEATURE_EXTRA_FILE_DATA=y
64CONFIG_OVERRIDE_APPLETS=""
65
66#
67# Build Options
68#
69# CONFIG_STATIC is not set
70# CONFIG_PIE is not set
71# CONFIG_NOMMU is not set
72# CONFIG_BUILD_LIBBUSYBOX is not set
73# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set
74# CONFIG_FEATURE_INDIVIDUAL is not set
75# CONFIG_FEATURE_SHARED_BUSYBOX is not set
76CONFIG_CROSS_COMPILER_PREFIX="x86_64-w64-mingw32-"
77CONFIG_HOST_COMPILER="gcc"
78CONFIG_CROSS_COMPILER="gcc"
79CONFIG_SYSROOT=""
80CONFIG_EXTRA_CFLAGS=""
81CONFIG_EXTRA_LDFLAGS=""
82CONFIG_EXTRA_LDLIBS=""
83CONFIG_USE_PORTABLE_CODE=y
84CONFIG_STACK_OPTIMIZATION_386=y
85CONFIG_STATIC_LIBGCC=y
86
87#
88# Installation Options ("make install" behavior)
89#
90CONFIG_INSTALL_APPLET_SYMLINKS=y
91# CONFIG_INSTALL_APPLET_HARDLINKS is not set
92# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
93# CONFIG_INSTALL_APPLET_DONT is not set
94# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
95# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
96# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
97CONFIG_PREFIX=""
98
99#
100# Debugging Options
101#
102# CONFIG_DEBUG is not set
103# CONFIG_DEBUG_PESSIMIZE is not set
104# CONFIG_DEBUG_SANITIZE is not set
105# CONFIG_UNIT_TEST is not set
106# CONFIG_WERROR is not set
107# CONFIG_WARN_SIMPLE_MSG is not set
108CONFIG_NO_DEBUG_LIB=y
109# CONFIG_DMALLOC is not set
110# CONFIG_EFENCE is not set
111
112#
113# Library Tuning
114#
115# CONFIG_FEATURE_USE_BSS_TAIL is not set
116CONFIG_FLOAT_DURATION=y
117# CONFIG_FEATURE_RTMINMAX is not set
118# CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS is not set
119CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
120# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
121# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
122CONFIG_PASSWORD_MINLEN=6
123CONFIG_MD5_SMALL=1
124CONFIG_SHA1_SMALL=3
125# CONFIG_SHA1_HWACCEL is not set
126# CONFIG_SHA256_HWACCEL is not set
127CONFIG_SHA3_SMALL=1
128CONFIG_FEATURE_NON_POSIX_CP=y
129# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
130# CONFIG_FEATURE_USE_SENDFILE is not set
131CONFIG_FEATURE_COPYBUF_KB=4
132# CONFIG_MONOTONIC_SYSCALL is not set
133# CONFIG_IOCTL_HEX2STR_ERROR is not set
134CONFIG_FEATURE_EDITING=y
135CONFIG_FEATURE_EDITING_MAX_LEN=8192
136CONFIG_FEATURE_EDITING_VI=y
137CONFIG_FEATURE_EDITING_HISTORY=1023
138CONFIG_FEATURE_EDITING_HISTORY_DEFAULT=384
139CONFIG_FEATURE_EDITING_SAVEHISTORY=y
140# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
141CONFIG_FEATURE_REVERSE_SEARCH=y
142CONFIG_FEATURE_TAB_COMPLETION=y
143CONFIG_FEATURE_USERNAME_COMPLETION=y
144CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
145# CONFIG_FEATURE_EDITING_WINCH is not set
146# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
147# CONFIG_LOCALE_SUPPORT is not set
148# CONFIG_UNICODE_SUPPORT is not set
149# CONFIG_UNICODE_USING_LOCALE is not set
150# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
151CONFIG_SUBST_WCHAR=0
152CONFIG_LAST_SUPPORTED_WCHAR=0
153# CONFIG_UNICODE_COMBINING_WCHARS is not set
154# CONFIG_UNICODE_WIDE_WCHARS is not set
155# CONFIG_UNICODE_BIDI_SUPPORT is not set
156# CONFIG_UNICODE_NEUTRAL_TABLE is not set
157# CONFIG_UNICODE_PRESERVE_BROKEN is not set
158# CONFIG_LOOP_CONFIGURE is not set
159# CONFIG_NO_LOOP_CONFIGURE is not set
160CONFIG_TRY_LOOP_CONFIGURE=y
161
162#
163# Applets
164#
165
166#
167# Archival Utilities
168#
169CONFIG_FEATURE_SEAMLESS_XZ=y
170CONFIG_FEATURE_SEAMLESS_LZMA=y
171CONFIG_FEATURE_SEAMLESS_BZ2=y
172CONFIG_FEATURE_SEAMLESS_GZ=y
173CONFIG_FEATURE_SEAMLESS_Z=y
174CONFIG_AR=y
175CONFIG_FEATURE_AR_LONG_FILENAMES=y
176CONFIG_FEATURE_AR_CREATE=y
177CONFIG_UNCOMPRESS=y
178CONFIG_GUNZIP=y
179CONFIG_ZCAT=y
180CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y
181CONFIG_BUNZIP2=y
182CONFIG_BZCAT=y
183CONFIG_UNLZMA=y
184CONFIG_LZCAT=y
185CONFIG_LZMA=y
186CONFIG_UNXZ=y
187CONFIG_XZCAT=y
188CONFIG_XZ=y
189CONFIG_BZIP2=y
190CONFIG_BZIP2_SMALL=8
191CONFIG_FEATURE_BZIP2_DECOMPRESS=y
192CONFIG_CPIO=y
193CONFIG_FEATURE_CPIO_O=y
194# CONFIG_FEATURE_CPIO_P is not set
195CONFIG_FEATURE_CPIO_IGNORE_DEVNO=y
196CONFIG_FEATURE_CPIO_RENUMBER_INODES=y
197CONFIG_DPKG=y
198CONFIG_DPKG_DEB=y
199CONFIG_GZIP=y
200CONFIG_FEATURE_GZIP_LONG_OPTIONS=y
201CONFIG_GZIP_FAST=2
202CONFIG_FEATURE_GZIP_LEVELS=y
203CONFIG_FEATURE_GZIP_DECOMPRESS=y
204CONFIG_LZOP=y
205CONFIG_UNLZOP=y
206CONFIG_LZOPCAT=y
207# CONFIG_LZOP_COMPR_HIGH is not set
208CONFIG_RPM=y
209CONFIG_RPM2CPIO=y
210CONFIG_TAR=y
211CONFIG_FEATURE_TAR_LONG_OPTIONS=y
212CONFIG_FEATURE_TAR_CREATE=y
213CONFIG_FEATURE_TAR_AUTODETECT=y
214CONFIG_FEATURE_TAR_FROM=y
215CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
216# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
217CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
218# CONFIG_FEATURE_TAR_TO_COMMAND is not set
219# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
220CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
221# CONFIG_FEATURE_TAR_SELINUX is not set
222CONFIG_UNZIP=y
223CONFIG_FEATURE_UNZIP_CDF=y
224CONFIG_FEATURE_UNZIP_BZIP2=y
225CONFIG_FEATURE_UNZIP_LZMA=y
226CONFIG_FEATURE_UNZIP_XZ=y
227CONFIG_FEATURE_LZMA_FAST=y
228
229#
230# Coreutils
231#
232CONFIG_FEATURE_VERBOSE=y
233
234#
235# Common options for date and touch
236#
237CONFIG_FEATURE_TIMEZONE=y
238
239#
240# Common options for cp and mv
241#
242# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
243
244#
245# Common options for df, du, ls
246#
247CONFIG_FEATURE_HUMAN_READABLE=y
248CONFIG_BASENAME=y
249CONFIG_CAT=y
250CONFIG_FEATURE_CATN=y
251CONFIG_FEATURE_CATV=y
252# CONFIG_CHGRP is not set
253CONFIG_CHMOD=y
254# CONFIG_CHOWN is not set
255# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
256# CONFIG_CHROOT is not set
257CONFIG_CKSUM=y
258CONFIG_CRC32=y
259CONFIG_COMM=y
260CONFIG_CP=y
261CONFIG_FEATURE_CP_LONG_OPTIONS=y
262# CONFIG_FEATURE_CP_REFLINK is not set
263CONFIG_CUT=y
264CONFIG_FEATURE_CUT_REGEX=y
265CONFIG_DATE=y
266CONFIG_FEATURE_DATE_ISOFMT=y
267CONFIG_FEATURE_DATE_NANO=y
268CONFIG_FEATURE_DATE_COMPAT=y
269CONFIG_DD=y
270# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
271# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
272CONFIG_FEATURE_DD_IBS_OBS=y
273CONFIG_FEATURE_DD_STATUS=y
274CONFIG_DF=y
275# CONFIG_FEATURE_DF_FANCY is not set
276# CONFIG_FEATURE_SKIP_ROOTFS is not set
277CONFIG_DIRNAME=y
278CONFIG_DOS2UNIX=y
279CONFIG_UNIX2DOS=y
280CONFIG_DU=y
281CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
282CONFIG_ECHO=y
283CONFIG_FEATURE_FANCY_ECHO=y
284CONFIG_ENV=y
285CONFIG_EXPAND=y
286CONFIG_UNEXPAND=y
287CONFIG_EXPR=y
288CONFIG_EXPR_MATH_SUPPORT_64=y
289CONFIG_FACTOR=y
290CONFIG_FALSE=y
291CONFIG_FOLD=y
292CONFIG_HEAD=y
293CONFIG_FEATURE_FANCY_HEAD=y
294# CONFIG_HOSTID is not set
295CONFIG_ID=y
296CONFIG_GROUPS=y
297CONFIG_INSTALL=y
298CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y
299CONFIG_LINK=y
300CONFIG_LN=y
301CONFIG_LOGNAME=y
302CONFIG_LS=y
303CONFIG_FEATURE_LS_FILETYPES=y
304CONFIG_FEATURE_LS_FOLLOWLINKS=y
305CONFIG_FEATURE_LS_RECURSIVE=y
306CONFIG_FEATURE_LS_WIDTH=y
307CONFIG_FEATURE_LS_SORTFILES=y
308CONFIG_FEATURE_LS_TIMESTAMPS=y
309CONFIG_FEATURE_LS_USERNAME=y
310CONFIG_FEATURE_LS_COLOR=y
311CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
312CONFIG_MD5SUM=y
313CONFIG_SHA1SUM=y
314CONFIG_SHA256SUM=y
315CONFIG_SHA512SUM=y
316CONFIG_SHA3SUM=y
317
318#
319# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
320#
321CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
322CONFIG_MKDIR=y
323# CONFIG_MKFIFO is not set
324# CONFIG_MKNOD is not set
325CONFIG_MKTEMP=y
326CONFIG_MV=y
327# CONFIG_NICE is not set
328CONFIG_NL=y
329# CONFIG_NOHUP is not set
330CONFIG_NPROC=y
331CONFIG_OD=y
332CONFIG_PASTE=y
333CONFIG_PRINTENV=y
334CONFIG_PRINTF=y
335CONFIG_PWD=y
336CONFIG_READLINK=y
337CONFIG_FEATURE_READLINK_FOLLOW=y
338CONFIG_REALPATH=y
339CONFIG_RM=y
340CONFIG_RMDIR=y
341CONFIG_SEQ=y
342CONFIG_SHRED=y
343CONFIG_SHUF=y
344CONFIG_SLEEP=y
345CONFIG_FEATURE_FANCY_SLEEP=y
346CONFIG_SORT=y
347CONFIG_FEATURE_SORT_BIG=y
348# CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set
349CONFIG_SPLIT=y
350CONFIG_FEATURE_SPLIT_FANCY=y
351CONFIG_STAT=y
352CONFIG_FEATURE_STAT_FORMAT=y
353CONFIG_FEATURE_STAT_FILESYSTEM=y
354# CONFIG_STTY is not set
355CONFIG_SUM=y
356CONFIG_SYNC=y
357# CONFIG_FEATURE_SYNC_FANCY is not set
358CONFIG_FSYNC=y
359CONFIG_TAC=y
360CONFIG_TAIL=y
361CONFIG_FEATURE_FANCY_TAIL=y
362CONFIG_TEE=y
363CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
364CONFIG_TEST=y
365CONFIG_TEST1=y
366CONFIG_TEST2=y
367CONFIG_FEATURE_TEST_64=y
368CONFIG_TIMEOUT=y
369CONFIG_TOUCH=y
370CONFIG_FEATURE_TOUCH_SUSV3=y
371CONFIG_TR=y
372CONFIG_FEATURE_TR_CLASSES=y
373CONFIG_FEATURE_TR_EQUIV=y
374CONFIG_TRUE=y
375CONFIG_TRUNCATE=y
376CONFIG_TSORT=y
377# CONFIG_TTY is not set
378CONFIG_UNAME=y
379CONFIG_UNAME_OSNAME="MS/Windows"
380CONFIG_BB_ARCH=y
381CONFIG_UNIQ=y
382CONFIG_UNLINK=y
383CONFIG_USLEEP=y
384CONFIG_UUDECODE=y
385CONFIG_BASE32=y
386CONFIG_BASE64=y
387CONFIG_UUENCODE=y
388CONFIG_WC=y
389CONFIG_FEATURE_WC_LARGE=y
390# CONFIG_WHO is not set
391# CONFIG_W is not set
392# CONFIG_USERS is not set
393CONFIG_WHOAMI=y
394CONFIG_YES=y
395
396#
397# Console Utilities
398#
399# CONFIG_CHVT is not set
400CONFIG_CLEAR=y
401# CONFIG_DEALLOCVT is not set
402# CONFIG_DUMPKMAP is not set
403# CONFIG_FGCONSOLE is not set
404# CONFIG_KBD_MODE is not set
405# CONFIG_LOADFONT is not set
406# CONFIG_SETFONT is not set
407# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
408CONFIG_DEFAULT_SETFONT_DIR=""
409# CONFIG_FEATURE_LOADFONT_PSF2 is not set
410# CONFIG_FEATURE_LOADFONT_RAW is not set
411# CONFIG_LOADKMAP is not set
412# CONFIG_OPENVT is not set
413CONFIG_RESET=y
414# CONFIG_RESIZE is not set
415# CONFIG_FEATURE_RESIZE_PRINT is not set
416# CONFIG_SETCONSOLE is not set
417# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
418# CONFIG_SETKEYCODES is not set
419# CONFIG_SETLOGCONS is not set
420# CONFIG_SHOWKEY is not set
421
422#
423# Debian Utilities
424#
425CONFIG_PIPE_PROGRESS=y
426# CONFIG_RUN_PARTS is not set
427# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
428# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
429# CONFIG_START_STOP_DAEMON is not set
430# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
431# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
432CONFIG_WHICH=y
433
434#
435# klibc-utils
436#
437# CONFIG_MINIPS is not set
438# CONFIG_NUKE is not set
439# CONFIG_RESUME is not set
440# CONFIG_RUN_INIT is not set
441
442#
443# Editors
444#
445CONFIG_AWK=y
446CONFIG_FEATURE_AWK_LIBM=y
447CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
448CONFIG_CMP=y
449CONFIG_DIFF=y
450CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
451CONFIG_FEATURE_DIFF_DIR=y
452CONFIG_ED=y
453CONFIG_PATCH=y
454CONFIG_SED=y
455CONFIG_VI=y
456CONFIG_FEATURE_VI_MAX_LEN=4096
457CONFIG_FEATURE_VI_8BIT=y
458CONFIG_FEATURE_VI_COLON=y
459CONFIG_FEATURE_VI_COLON_EXPAND=y
460CONFIG_FEATURE_VI_YANKMARK=y
461CONFIG_FEATURE_VI_SEARCH=y
462CONFIG_FEATURE_VI_REGEX_SEARCH=y
463# CONFIG_FEATURE_VI_USE_SIGNALS is not set
464CONFIG_FEATURE_VI_DOT_CMD=y
465CONFIG_FEATURE_VI_READONLY=y
466CONFIG_FEATURE_VI_SETOPTS=y
467CONFIG_FEATURE_VI_FILE_FORMAT=y
468CONFIG_FEATURE_VI_SET=y
469CONFIG_FEATURE_VI_WIN_RESIZE=y
470# CONFIG_FEATURE_VI_ASK_TERMINAL is not set
471CONFIG_FEATURE_VI_UNDO=y
472CONFIG_FEATURE_VI_UNDO_QUEUE=y
473CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
474CONFIG_FEATURE_VI_VERBOSE_STATUS=y
475CONFIG_FEATURE_ALLOW_EXEC=y
476
477#
478# Finding Utilities
479#
480CONFIG_FIND=y
481CONFIG_FEATURE_FIND_PRINT0=y
482CONFIG_FEATURE_FIND_MTIME=y
483CONFIG_FEATURE_FIND_ATIME=y
484CONFIG_FEATURE_FIND_CTIME=y
485CONFIG_FEATURE_FIND_MMIN=y
486CONFIG_FEATURE_FIND_AMIN=y
487CONFIG_FEATURE_FIND_CMIN=y
488CONFIG_FEATURE_FIND_PERM=y
489CONFIG_FEATURE_FIND_TYPE=y
490CONFIG_FEATURE_FIND_EXECUTABLE=y
491CONFIG_FEATURE_FIND_XDEV=y
492CONFIG_FEATURE_FIND_MAXDEPTH=y
493CONFIG_FEATURE_FIND_NEWER=y
494CONFIG_FEATURE_FIND_INUM=y
495CONFIG_FEATURE_FIND_SAMEFILE=y
496CONFIG_FEATURE_FIND_EXEC=y
497CONFIG_FEATURE_FIND_EXEC_PLUS=y
498CONFIG_FEATURE_FIND_EXEC_OK=y
499# CONFIG_FEATURE_FIND_USER is not set
500# CONFIG_FEATURE_FIND_GROUP is not set
501CONFIG_FEATURE_FIND_NOT=y
502CONFIG_FEATURE_FIND_DEPTH=y
503CONFIG_FEATURE_FIND_PAREN=y
504CONFIG_FEATURE_FIND_SIZE=y
505CONFIG_FEATURE_FIND_PRUNE=y
506CONFIG_FEATURE_FIND_QUIT=y
507CONFIG_FEATURE_FIND_DELETE=y
508CONFIG_FEATURE_FIND_EMPTY=y
509CONFIG_FEATURE_FIND_PATH=y
510CONFIG_FEATURE_FIND_REGEX=y
511# CONFIG_FEATURE_FIND_CONTEXT is not set
512CONFIG_FEATURE_FIND_LINKS=y
513CONFIG_GREP=y
514CONFIG_EGREP=y
515CONFIG_FGREP=y
516CONFIG_FEATURE_GREP_CONTEXT=y
517CONFIG_XARGS=y
518CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
519CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
520CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
521CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
522CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
523CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y
524CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y
525
526#
527# Init Utilities
528#
529# CONFIG_BOOTCHARTD is not set
530# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
531# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
532# CONFIG_HALT is not set
533# CONFIG_POWEROFF is not set
534# CONFIG_REBOOT is not set
535# CONFIG_FEATURE_WAIT_FOR_INIT is not set
536# CONFIG_FEATURE_CALL_TELINIT is not set
537CONFIG_TELINIT_PATH=""
538# CONFIG_INIT is not set
539# CONFIG_LINUXRC is not set
540# CONFIG_FEATURE_USE_INITTAB is not set
541# CONFIG_FEATURE_KILL_REMOVED is not set
542CONFIG_FEATURE_KILL_DELAY=0
543# CONFIG_FEATURE_INIT_SCTTY is not set
544# CONFIG_FEATURE_INIT_SYSLOG is not set
545# CONFIG_FEATURE_INIT_QUIET is not set
546# CONFIG_FEATURE_INIT_COREDUMPS is not set
547CONFIG_INIT_TERMINAL_TYPE=""
548# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
549
550#
551# Login/Password Management Utilities
552#
553# CONFIG_FEATURE_SHADOWPASSWDS is not set
554# CONFIG_USE_BB_PWD_GRP is not set
555# CONFIG_USE_BB_SHADOW is not set
556# CONFIG_USE_BB_CRYPT is not set
557# CONFIG_USE_BB_CRYPT_SHA is not set
558# CONFIG_ADD_SHELL is not set
559# CONFIG_REMOVE_SHELL is not set
560# CONFIG_ADDGROUP is not set
561# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
562# CONFIG_ADDUSER is not set
563# CONFIG_FEATURE_CHECK_NAMES is not set
564CONFIG_LAST_ID=0
565CONFIG_FIRST_SYSTEM_ID=0
566CONFIG_LAST_SYSTEM_ID=0
567# CONFIG_CHPASSWD is not set
568CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
569# CONFIG_CRYPTPW is not set
570# CONFIG_MKPASSWD is not set
571# CONFIG_DELUSER is not set
572# CONFIG_DELGROUP is not set
573# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
574# CONFIG_GETTY is not set
575# CONFIG_LOGIN is not set
576# CONFIG_LOGIN_SESSION_AS_CHILD is not set
577# CONFIG_LOGIN_SCRIPTS is not set
578# CONFIG_FEATURE_NOLOGIN is not set
579# CONFIG_FEATURE_SECURETTY is not set
580# CONFIG_PASSWD is not set
581# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
582# CONFIG_SU is not set
583# CONFIG_FEATURE_SU_SYSLOG is not set
584# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
585# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set
586# CONFIG_SULOGIN is not set
587CONFIG_SUW32=y
588# CONFIG_VLOCK is not set
589
590#
591# Linux Ext2 FS Progs
592#
593CONFIG_CHATTR=y
594# CONFIG_FSCK is not set
595CONFIG_LSATTR=y
596# CONFIG_TUNE2FS is not set
597
598#
599# Linux Module Utilities
600#
601# CONFIG_MODPROBE_SMALL is not set
602# CONFIG_DEPMOD is not set
603# CONFIG_INSMOD is not set
604# CONFIG_LSMOD is not set
605# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
606# CONFIG_MODINFO is not set
607# CONFIG_MODPROBE is not set
608# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
609# CONFIG_RMMOD is not set
610
611#
612# Options common to multiple modutils
613#
614# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set
615# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
616# CONFIG_FEATURE_2_4_MODULES is not set
617# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
618# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
619# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
620# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
621# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
622# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
623# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
624# CONFIG_FEATURE_MODUTILS_ALIAS is not set
625# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
626CONFIG_DEFAULT_MODULES_DIR=""
627CONFIG_DEFAULT_DEPMOD_FILE=""
628
629#
630# Linux System Utilities
631#
632# CONFIG_ACPID is not set
633# CONFIG_FEATURE_ACPID_COMPAT is not set
634# CONFIG_BLKDISCARD is not set
635# CONFIG_BLKID is not set
636# CONFIG_FEATURE_BLKID_TYPE is not set
637# CONFIG_BLOCKDEV is not set
638CONFIG_CAL=y
639# CONFIG_CHRT is not set
640# CONFIG_DMESG is not set
641# CONFIG_FEATURE_DMESG_PRETTY is not set
642# CONFIG_EJECT is not set
643# CONFIG_FEATURE_EJECT_SCSI is not set
644# CONFIG_FALLOCATE is not set
645# CONFIG_FATATTR is not set
646# CONFIG_FBSET is not set
647# CONFIG_FEATURE_FBSET_FANCY is not set
648# CONFIG_FEATURE_FBSET_READMODE is not set
649# CONFIG_FDFORMAT is not set
650# CONFIG_FDISK is not set
651# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
652# CONFIG_FEATURE_FDISK_WRITABLE is not set
653# CONFIG_FEATURE_AIX_LABEL is not set
654# CONFIG_FEATURE_SGI_LABEL is not set
655# CONFIG_FEATURE_SUN_LABEL is not set
656# CONFIG_FEATURE_OSF_LABEL is not set
657# CONFIG_FEATURE_GPT_LABEL is not set
658# CONFIG_FEATURE_FDISK_ADVANCED is not set
659# CONFIG_FINDFS is not set
660# CONFIG_FLOCK is not set
661# CONFIG_FDFLUSH is not set
662# CONFIG_FREERAMDISK is not set
663# CONFIG_FSCK_MINIX is not set
664# CONFIG_FSFREEZE is not set
665# CONFIG_FSTRIM is not set
666CONFIG_GETOPT=y
667CONFIG_FEATURE_GETOPT_LONG=y
668CONFIG_HEXDUMP=y
669CONFIG_HD=y
670CONFIG_XXD=y
671# CONFIG_HWCLOCK is not set
672# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
673# CONFIG_IONICE is not set
674# CONFIG_IPCRM is not set
675# CONFIG_IPCS is not set
676# CONFIG_LAST is not set
677# CONFIG_FEATURE_LAST_FANCY is not set
678# CONFIG_LOSETUP is not set
679# CONFIG_LSPCI is not set
680# CONFIG_LSUSB is not set
681# CONFIG_MDEV is not set
682# CONFIG_FEATURE_MDEV_CONF is not set
683# CONFIG_FEATURE_MDEV_RENAME is not set
684# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
685# CONFIG_FEATURE_MDEV_EXEC is not set
686# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
687# CONFIG_FEATURE_MDEV_DAEMON is not set
688# CONFIG_MESG is not set
689# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
690# CONFIG_MKE2FS is not set
691# CONFIG_MKFS_EXT2 is not set
692# CONFIG_MKFS_MINIX is not set
693# CONFIG_FEATURE_MINIX2 is not set
694# CONFIG_MKFS_REISER is not set
695# CONFIG_MKDOSFS is not set
696# CONFIG_MKFS_VFAT is not set
697# CONFIG_MKSWAP is not set
698# CONFIG_FEATURE_MKSWAP_UUID is not set
699# CONFIG_MORE is not set
700# CONFIG_MOUNT is not set
701# CONFIG_FEATURE_MOUNT_FAKE is not set
702# CONFIG_FEATURE_MOUNT_VERBOSE is not set
703# CONFIG_FEATURE_MOUNT_HELPERS is not set
704# CONFIG_FEATURE_MOUNT_LABEL is not set
705# CONFIG_FEATURE_MOUNT_NFS is not set
706# CONFIG_FEATURE_MOUNT_CIFS is not set
707# CONFIG_FEATURE_MOUNT_FLAGS is not set
708# CONFIG_FEATURE_MOUNT_FSTAB is not set
709# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
710# CONFIG_MOUNTPOINT is not set
711# CONFIG_NOLOGIN is not set
712# CONFIG_NOLOGIN_DEPENDENCIES is not set
713# CONFIG_NSENTER is not set
714# CONFIG_PIVOT_ROOT is not set
715# CONFIG_RDATE is not set
716# CONFIG_RDEV is not set
717# CONFIG_READPROFILE is not set
718# CONFIG_RENICE is not set
719CONFIG_REV=y
720# CONFIG_RTCWAKE is not set
721# CONFIG_SCRIPT is not set
722# CONFIG_SCRIPTREPLAY is not set
723# CONFIG_SETARCH is not set
724# CONFIG_LINUX32 is not set
725# CONFIG_LINUX64 is not set
726# CONFIG_SETPRIV is not set
727# CONFIG_FEATURE_SETPRIV_DUMP is not set
728# CONFIG_FEATURE_SETPRIV_CAPABILITIES is not set
729# CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES is not set
730# CONFIG_SETSID is not set
731# CONFIG_SWAPON is not set
732# CONFIG_FEATURE_SWAPON_DISCARD is not set
733# CONFIG_FEATURE_SWAPON_PRI is not set
734# CONFIG_SWAPOFF is not set
735# CONFIG_FEATURE_SWAPONOFF_LABEL is not set
736# CONFIG_SWITCH_ROOT is not set
737# CONFIG_TASKSET is not set
738# CONFIG_FEATURE_TASKSET_FANCY is not set
739# CONFIG_FEATURE_TASKSET_CPULIST is not set
740# CONFIG_UEVENT is not set
741# CONFIG_UMOUNT is not set
742# CONFIG_FEATURE_UMOUNT_ALL is not set
743# CONFIG_UNSHARE is not set
744# CONFIG_WALL is not set
745# CONFIG_FEATURE_MOUNT_LOOP is not set
746# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
747# CONFIG_FEATURE_MTAB_SUPPORT is not set
748# CONFIG_VOLUMEID is not set
749# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
750# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
751# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
752# CONFIG_FEATURE_VOLUMEID_EROFS is not set
753# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
754# CONFIG_FEATURE_VOLUMEID_EXT is not set
755# CONFIG_FEATURE_VOLUMEID_F2FS is not set
756# CONFIG_FEATURE_VOLUMEID_FAT is not set
757# CONFIG_FEATURE_VOLUMEID_HFS is not set
758# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
759# CONFIG_FEATURE_VOLUMEID_JFS is not set
760# CONFIG_FEATURE_VOLUMEID_LFS is not set
761# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
762# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
763# CONFIG_FEATURE_VOLUMEID_LUKS is not set
764# CONFIG_FEATURE_VOLUMEID_MINIX is not set
765# CONFIG_FEATURE_VOLUMEID_NILFS is not set
766# CONFIG_FEATURE_VOLUMEID_NTFS is not set
767# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
768# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
769# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
770# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
771# CONFIG_FEATURE_VOLUMEID_SYSV is not set
772# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
773# CONFIG_FEATURE_VOLUMEID_UDF is not set
774# CONFIG_FEATURE_VOLUMEID_XFS is not set
775
776#
777# Miscellaneous Utilities
778#
779# CONFIG_ADJTIMEX is not set
780CONFIG_ASCII=y
781# CONFIG_BBCONFIG is not set
782# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
783CONFIG_BC=y
784CONFIG_DC=y
785CONFIG_FEATURE_DC_BIG=y
786# CONFIG_FEATURE_DC_LIBM is not set
787CONFIG_FEATURE_BC_INTERACTIVE=y
788CONFIG_FEATURE_BC_LONG_OPTIONS=y
789# CONFIG_BEEP is not set
790CONFIG_FEATURE_BEEP_FREQ=0
791CONFIG_FEATURE_BEEP_LENGTH_MS=0
792# CONFIG_CHAT is not set
793# CONFIG_FEATURE_CHAT_NOFAIL is not set
794# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
795# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
796# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
797# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
798# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
799# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
800# CONFIG_CONSPY is not set
801# CONFIG_CROND is not set
802# CONFIG_FEATURE_CROND_D is not set
803# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
804# CONFIG_FEATURE_CROND_SPECIAL_TIMES is not set
805CONFIG_FEATURE_CROND_DIR=""
806# CONFIG_CRONTAB is not set
807# CONFIG_DEVFSD is not set
808# CONFIG_DEVFSD_MODLOAD is not set
809# CONFIG_DEVFSD_FG_NP is not set
810# CONFIG_DEVFSD_VERBOSE is not set
811# CONFIG_FEATURE_DEVFS is not set
812# CONFIG_DEVMEM is not set
813CONFIG_DROP=y
814CONFIG_CDROP=y
815CONFIG_PDROP=y
816# CONFIG_FBSPLASH is not set
817# CONFIG_FLASH_ERASEALL is not set
818# CONFIG_FLASH_LOCK is not set
819# CONFIG_FLASH_UNLOCK is not set
820# CONFIG_FLASHCP is not set
821# CONFIG_GETFATTR is not set
822# CONFIG_HDPARM is not set
823# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
824# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
825# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
826# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
827# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
828# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
829# CONFIG_HEXEDIT is not set
830# CONFIG_I2CGET is not set
831# CONFIG_I2CSET is not set
832# CONFIG_I2CDUMP is not set
833# CONFIG_I2CDETECT is not set
834# CONFIG_I2CTRANSFER is not set
835CONFIG_ICONV=y
836CONFIG_INOTIFYD=y
837CONFIG_JN=y
838CONFIG_LESS=y
839CONFIG_FEATURE_LESS_MAXLINES=9999999
840CONFIG_FEATURE_LESS_BRACKETS=y
841CONFIG_FEATURE_LESS_FLAGS=y
842CONFIG_FEATURE_LESS_TRUNCATE=y
843CONFIG_FEATURE_LESS_MARKS=y
844CONFIG_FEATURE_LESS_REGEXP=y
845# CONFIG_FEATURE_LESS_WINCH is not set
846# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
847CONFIG_FEATURE_LESS_DASHCMD=y
848CONFIG_FEATURE_LESS_LINENUMS=y
849CONFIG_FEATURE_LESS_RAW=y
850CONFIG_FEATURE_LESS_ENV=y
851# CONFIG_LSSCSI is not set
852CONFIG_MAKE=y
853CONFIG_PDPMAKE=y
854CONFIG_FEATURE_MAKE_POSIX=y
855# CONFIG_FEATURE_MAKE_POSIX_2017 is not set
856CONFIG_FEATURE_MAKE_POSIX_2024=y
857# CONFIG_MAKEDEVS is not set
858# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
859# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
860CONFIG_MAN=y
861# CONFIG_MICROCOM is not set
862# CONFIG_MIM is not set
863# CONFIG_MT is not set
864# CONFIG_NANDWRITE is not set
865# CONFIG_NANDDUMP is not set
866# CONFIG_PARTPROBE is not set
867# CONFIG_RAIDAUTORUN is not set
868# CONFIG_READAHEAD is not set
869# CONFIG_RFKILL is not set
870# CONFIG_RUNLEVEL is not set
871# CONFIG_RX is not set
872# CONFIG_SEEDRNG is not set
873# CONFIG_SETFATTR is not set
874# CONFIG_SETSERIAL is not set
875CONFIG_STRINGS=y
876CONFIG_TIME=y
877# CONFIG_TREE is not set
878CONFIG_TS=y
879CONFIG_TTYSIZE=y
880# CONFIG_UBIATTACH is not set
881# CONFIG_UBIDETACH is not set
882# CONFIG_UBIMKVOL is not set
883# CONFIG_UBIRMVOL is not set
884# CONFIG_UBIRSVOL is not set
885# CONFIG_UBIUPDATEVOL is not set
886# CONFIG_UBIRENAME is not set
887# CONFIG_VOLNAME is not set
888# CONFIG_WATCHDOG is not set
889# CONFIG_FEATURE_WATCHDOG_OPEN_TWICE is not set
890
891#
892# Networking Utilities
893#
894CONFIG_FEATURE_IPV6=y
895# CONFIG_FEATURE_UNIX_LOCAL is not set
896CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
897# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
898# CONFIG_FEATURE_ETC_NETWORKS is not set
899# CONFIG_FEATURE_ETC_SERVICES is not set
900# CONFIG_FEATURE_HWIB is not set
901# CONFIG_FEATURE_TLS_SHA1 is not set
902# CONFIG_ARP is not set
903# CONFIG_ARPING is not set
904# CONFIG_BRCTL is not set
905# CONFIG_FEATURE_BRCTL_FANCY is not set
906# CONFIG_FEATURE_BRCTL_SHOW is not set
907# CONFIG_DNSD is not set
908# CONFIG_ETHER_WAKE is not set
909# CONFIG_FTPD is not set
910# CONFIG_FEATURE_FTPD_WRITE is not set
911# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
912# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
913CONFIG_FTPGET=y
914CONFIG_FTPPUT=y
915CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
916# CONFIG_HOSTNAME is not set
917# CONFIG_DNSDOMAINNAME is not set
918CONFIG_HTTPD=y
919CONFIG_FEATURE_HTTPD_PORT_DEFAULT=80
920CONFIG_FEATURE_HTTPD_RANGES=y
921# CONFIG_FEATURE_HTTPD_SETUID is not set
922CONFIG_FEATURE_HTTPD_BASIC_AUTH=y
923# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
924CONFIG_FEATURE_HTTPD_CGI=y
925CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y
926# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
927CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y
928CONFIG_FEATURE_HTTPD_ERROR_PAGES=y
929# CONFIG_FEATURE_HTTPD_PROXY is not set
930CONFIG_FEATURE_HTTPD_GZIP=y
931CONFIG_FEATURE_HTTPD_ETAG=y
932CONFIG_FEATURE_HTTPD_LAST_MODIFIED=y
933CONFIG_FEATURE_HTTPD_DATE=y
934CONFIG_FEATURE_HTTPD_ACL_IP=y
935# CONFIG_IFCONFIG is not set
936# CONFIG_FEATURE_IFCONFIG_STATUS is not set
937# CONFIG_FEATURE_IFCONFIG_SLIP is not set
938# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
939# CONFIG_FEATURE_IFCONFIG_HW is not set
940# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
941# CONFIG_IFENSLAVE is not set
942# CONFIG_IFPLUGD is not set
943# CONFIG_IFUP is not set
944# CONFIG_IFDOWN is not set
945CONFIG_IFUPDOWN_IFSTATE_PATH=""
946# CONFIG_FEATURE_IFUPDOWN_IP is not set
947# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
948# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
949# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
950# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
951# CONFIG_INETD is not set
952# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
953# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
954# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
955# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
956# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
957# CONFIG_FEATURE_INETD_RPC is not set
958# CONFIG_IP is not set
959# CONFIG_IPADDR is not set
960# CONFIG_IPLINK is not set
961# CONFIG_IPROUTE is not set
962# CONFIG_IPTUNNEL is not set
963# CONFIG_IPRULE is not set
964# CONFIG_IPNEIGH is not set
965# CONFIG_FEATURE_IP_ADDRESS is not set
966# CONFIG_FEATURE_IP_LINK is not set
967# CONFIG_FEATURE_IP_ROUTE is not set
968CONFIG_FEATURE_IP_ROUTE_DIR=""
969# CONFIG_FEATURE_IP_TUNNEL is not set
970# CONFIG_FEATURE_IP_RULE is not set
971# CONFIG_FEATURE_IP_NEIGH is not set
972# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
973CONFIG_IPCALC=y
974CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y
975CONFIG_FEATURE_IPCALC_FANCY=y
976# CONFIG_FAKEIDENTD is not set
977# CONFIG_NAMEIF is not set
978# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
979# CONFIG_NBDCLIENT is not set
980CONFIG_NC=y
981# CONFIG_NETCAT is not set
982CONFIG_NC_SERVER=y
983# CONFIG_NC_EXTRA is not set
984# CONFIG_NC_110_COMPAT is not set
985# CONFIG_NETSTAT is not set
986# CONFIG_FEATURE_NETSTAT_WIDE is not set
987# CONFIG_FEATURE_NETSTAT_PRG is not set
988# CONFIG_NSLOOKUP is not set
989# CONFIG_FEATURE_NSLOOKUP_BIG is not set
990# CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS is not set
991# CONFIG_NTPD is not set
992# CONFIG_FEATURE_NTPD_SERVER is not set
993# CONFIG_FEATURE_NTPD_CONF is not set
994# CONFIG_FEATURE_NTP_AUTH is not set
995# CONFIG_PING is not set
996# CONFIG_PING6 is not set
997# CONFIG_FEATURE_FANCY_PING is not set
998# CONFIG_PSCAN is not set
999# CONFIG_ROUTE is not set
1000# CONFIG_SLATTACH is not set
1001CONFIG_SSL_CLIENT=y
1002# CONFIG_TC is not set
1003# CONFIG_FEATURE_TC_INGRESS is not set
1004# CONFIG_TCPSVD is not set
1005# CONFIG_UDPSVD is not set
1006# CONFIG_TELNET is not set
1007# CONFIG_FEATURE_TELNET_TTYPE is not set
1008# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
1009# CONFIG_FEATURE_TELNET_WIDTH is not set
1010# CONFIG_TELNETD is not set
1011# CONFIG_FEATURE_TELNETD_STANDALONE is not set
1012CONFIG_FEATURE_TELNETD_PORT_DEFAULT=0
1013# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
1014# CONFIG_TFTP is not set
1015# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
1016# CONFIG_FEATURE_TFTP_HPA_COMPAT is not set
1017# CONFIG_TFTPD is not set
1018# CONFIG_FEATURE_TFTP_GET is not set
1019# CONFIG_FEATURE_TFTP_PUT is not set
1020# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
1021# CONFIG_TFTP_DEBUG is not set
1022CONFIG_TLS=y
1023# CONFIG_TRACEROUTE is not set
1024# CONFIG_TRACEROUTE6 is not set
1025# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
1026# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
1027# CONFIG_TUNCTL is not set
1028# CONFIG_FEATURE_TUNCTL_UG is not set
1029# CONFIG_VCONFIG is not set
1030CONFIG_WGET=y
1031CONFIG_FEATURE_WGET_LONG_OPTIONS=y
1032CONFIG_FEATURE_WGET_STATUSBAR=y
1033CONFIG_FEATURE_WGET_FTP=y
1034CONFIG_FEATURE_WGET_AUTHENTICATION=y
1035# CONFIG_FEATURE_WGET_TIMEOUT is not set
1036CONFIG_FEATURE_WGET_HTTPS=y
1037# CONFIG_FEATURE_WGET_OPENSSL is not set
1038CONFIG_WHOIS=y
1039# CONFIG_ZCIP is not set
1040# CONFIG_UDHCPD is not set
1041# CONFIG_FEATURE_UDHCPD_BOOTP is not set
1042# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
1043# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
1044CONFIG_DHCPD_LEASES_FILE=""
1045# CONFIG_DUMPLEASES is not set
1046# CONFIG_DHCPRELAY is not set
1047# CONFIG_UDHCPC is not set
1048# CONFIG_FEATURE_UDHCPC_ARPING is not set
1049# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
1050CONFIG_UDHCPC_DEFAULT_SCRIPT=""
1051CONFIG_UDHCPC6_DEFAULT_SCRIPT=""
1052# CONFIG_UDHCPC6 is not set
1053# CONFIG_FEATURE_UDHCPC6_RFC3646 is not set
1054# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set
1055# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set
1056# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set
1057CONFIG_UDHCPC_DEFAULT_INTERFACE=""
1058# CONFIG_FEATURE_UDHCP_PORT is not set
1059CONFIG_UDHCP_DEBUG=0
1060CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
1061# CONFIG_FEATURE_UDHCP_RFC3397 is not set
1062# CONFIG_FEATURE_UDHCP_8021Q is not set
1063CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
1064
1065#
1066# Print Utilities
1067#
1068# CONFIG_LPD is not set
1069# CONFIG_LPR is not set
1070# CONFIG_LPQ is not set
1071
1072#
1073# Mail Utilities
1074#
1075CONFIG_FEATURE_MIME_CHARSET=""
1076# CONFIG_MAKEMIME is not set
1077# CONFIG_POPMAILDIR is not set
1078# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
1079# CONFIG_REFORMIME is not set
1080# CONFIG_FEATURE_REFORMIME_COMPAT is not set
1081# CONFIG_SENDMAIL is not set
1082
1083#
1084# Process Utilities
1085#
1086# CONFIG_FEATURE_FAST_TOP is not set
1087# CONFIG_FEATURE_SHOW_THREADS is not set
1088CONFIG_FREE=y
1089# CONFIG_FUSER is not set
1090# CONFIG_IOSTAT is not set
1091CONFIG_KILL=y
1092CONFIG_KILLALL=y
1093# CONFIG_KILLALL5 is not set
1094# CONFIG_LSOF is not set
1095# CONFIG_MPSTAT is not set
1096# CONFIG_NMETER is not set
1097CONFIG_PGREP=y
1098CONFIG_PKILL=y
1099CONFIG_PIDOF=y
1100CONFIG_FEATURE_PIDOF_SINGLE=y
1101CONFIG_FEATURE_PIDOF_OMIT=y
1102# CONFIG_PMAP is not set
1103# CONFIG_POWERTOP is not set
1104# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set
1105CONFIG_PS=y
1106# CONFIG_FEATURE_PS_WIDE is not set
1107# CONFIG_FEATURE_PS_LONG is not set
1108CONFIG_FEATURE_PS_TIME=y
1109# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
1110# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
1111# CONFIG_PSTREE is not set
1112# CONFIG_PWDX is not set
1113# CONFIG_SMEMCAP is not set
1114# CONFIG_BB_SYSCTL is not set
1115# CONFIG_TOP is not set
1116# CONFIG_FEATURE_TOP_INTERACTIVE is not set
1117# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
1118# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
1119# CONFIG_FEATURE_TOP_SMP_CPU is not set
1120# CONFIG_FEATURE_TOP_DECIMALS is not set
1121# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
1122# CONFIG_FEATURE_TOPMEM is not set
1123CONFIG_UPTIME=y
1124# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
1125CONFIG_WATCH=y
1126
1127#
1128# Runit Utilities
1129#
1130# CONFIG_CHPST is not set
1131# CONFIG_SETUIDGID is not set
1132# CONFIG_ENVUIDGID is not set
1133# CONFIG_ENVDIR is not set
1134# CONFIG_SOFTLIMIT is not set
1135# CONFIG_RUNSV is not set
1136# CONFIG_RUNSVDIR is not set
1137# CONFIG_FEATURE_RUNSVDIR_LOG is not set
1138# CONFIG_SV is not set
1139CONFIG_SV_DEFAULT_SERVICE_DIR=""
1140# CONFIG_SVC is not set
1141# CONFIG_SVOK is not set
1142# CONFIG_SVLOGD is not set
1143# CONFIG_CHCON is not set
1144# CONFIG_GETENFORCE is not set
1145# CONFIG_GETSEBOOL is not set
1146# CONFIG_LOAD_POLICY is not set
1147# CONFIG_MATCHPATHCON is not set
1148# CONFIG_RUNCON is not set
1149# CONFIG_SELINUXENABLED is not set
1150# CONFIG_SESTATUS is not set
1151# CONFIG_SETENFORCE is not set
1152# CONFIG_SETFILES is not set
1153# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
1154# CONFIG_RESTORECON is not set
1155# CONFIG_SETSEBOOL is not set
1156
1157#
1158# Shells
1159#
1160CONFIG_SH_IS_ASH=y
1161# CONFIG_SH_IS_HUSH is not set
1162# CONFIG_SH_IS_NONE is not set
1163CONFIG_BASH_IS_ASH=y
1164# CONFIG_BASH_IS_HUSH is not set
1165# CONFIG_BASH_IS_NONE is not set
1166CONFIG_SHELL_ASH=y
1167CONFIG_ASH=y
1168# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set
1169CONFIG_ASH_INTERNAL_GLOB=y
1170CONFIG_ASH_BASH_COMPAT=y
1171# CONFIG_ASH_BASH_SOURCE_CURDIR is not set
1172CONFIG_ASH_BASH_NOT_FOUND_HOOK=y
1173CONFIG_ASH_JOB_CONTROL=y
1174CONFIG_ASH_ALIAS=y
1175CONFIG_ASH_RANDOM_SUPPORT=y
1176CONFIG_ASH_EXPAND_PRMT=y
1177# CONFIG_ASH_IDLE_TIMEOUT is not set
1178# CONFIG_ASH_MAIL is not set
1179CONFIG_ASH_ECHO=y
1180CONFIG_ASH_PRINTF=y
1181CONFIG_ASH_TEST=y
1182CONFIG_ASH_HELP=y
1183CONFIG_ASH_GETOPTS=y
1184CONFIG_ASH_CMDCMD=y
1185CONFIG_ASH_NOCONSOLE=y
1186CONFIG_ASH_GLOB_OPTIONS=y
1187# CONFIG_CTTYHACK is not set
1188# CONFIG_HUSH is not set
1189# CONFIG_SHELL_HUSH is not set
1190# CONFIG_HUSH_BASH_COMPAT is not set
1191# CONFIG_HUSH_BRACE_EXPANSION is not set
1192# CONFIG_HUSH_BASH_SOURCE_CURDIR is not set
1193# CONFIG_HUSH_LINENO_VAR is not set
1194# CONFIG_HUSH_INTERACTIVE is not set
1195# CONFIG_HUSH_SAVEHISTORY is not set
1196# CONFIG_HUSH_JOB is not set
1197# CONFIG_HUSH_TICK is not set
1198# CONFIG_HUSH_IF is not set
1199# CONFIG_HUSH_LOOPS is not set
1200# CONFIG_HUSH_CASE is not set
1201# CONFIG_HUSH_FUNCTIONS is not set
1202# CONFIG_HUSH_LOCAL is not set
1203# CONFIG_HUSH_RANDOM_SUPPORT is not set
1204# CONFIG_HUSH_MODE_X is not set
1205# CONFIG_HUSH_ECHO is not set
1206# CONFIG_HUSH_PRINTF is not set
1207# CONFIG_HUSH_TEST is not set
1208# CONFIG_HUSH_HELP is not set
1209# CONFIG_HUSH_EXPORT is not set
1210# CONFIG_HUSH_EXPORT_N is not set
1211# CONFIG_HUSH_READONLY is not set
1212# CONFIG_HUSH_KILL is not set
1213# CONFIG_HUSH_WAIT is not set
1214# CONFIG_HUSH_COMMAND is not set
1215# CONFIG_HUSH_TRAP is not set
1216# CONFIG_HUSH_TYPE is not set
1217# CONFIG_HUSH_TIMES is not set
1218# CONFIG_HUSH_READ is not set
1219# CONFIG_HUSH_SET is not set
1220# CONFIG_HUSH_UNSET is not set
1221# CONFIG_HUSH_ULIMIT is not set
1222# CONFIG_HUSH_UMASK is not set
1223# CONFIG_HUSH_GETOPTS is not set
1224# CONFIG_HUSH_MEMLEAK is not set
1225
1226#
1227# Options common to all shells
1228#
1229CONFIG_FEATURE_SH_MATH=y
1230CONFIG_FEATURE_SH_MATH_64=y
1231CONFIG_FEATURE_SH_MATH_BASE=y
1232CONFIG_FEATURE_SH_EXTRA_QUIET=y
1233CONFIG_FEATURE_SH_STANDALONE=y
1234CONFIG_FEATURE_SH_NOFORK=y
1235CONFIG_FEATURE_SH_READ_FRAC=y
1236CONFIG_FEATURE_SH_HISTFILESIZE=y
1237CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS=y
1238
1239#
1240# System Logging Utilities
1241#
1242# CONFIG_KLOGD is not set
1243# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
1244# CONFIG_LOGGER is not set
1245# CONFIG_LOGREAD is not set
1246# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1247# CONFIG_SYSLOGD is not set
1248# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1249# CONFIG_FEATURE_REMOTE_LOG is not set
1250# CONFIG_FEATURE_SYSLOGD_DUP is not set
1251# CONFIG_FEATURE_SYSLOGD_CFG is not set
1252# CONFIG_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS is not set
1253CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1254# CONFIG_FEATURE_IPC_SYSLOG is not set
1255CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1256# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/configs/mingw64a_defconfig b/configs/mingw64a_defconfig
new file mode 100644
index 000000000..e9a88bf62
--- /dev/null
+++ b/configs/mingw64a_defconfig
@@ -0,0 +1,1256 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.37.0.git
4# Fri Jun 14 12:24:50 2024
5#
6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set
8CONFIG_PLATFORM_MINGW32=y
9
10#
11# Settings
12#
13CONFIG_DESKTOP=y
14# CONFIG_EXTRA_COMPAT is not set
15# CONFIG_FEDORA_COMPAT is not set
16# CONFIG_INCLUDE_SUSv2 is not set
17CONFIG_LONG_OPTS=y
18CONFIG_SHOW_USAGE=y
19CONFIG_FEATURE_VERBOSE_USAGE=y
20CONFIG_FEATURE_COMPRESS_USAGE=y
21CONFIG_LFS=y
22CONFIG_TIME64=y
23# CONFIG_PAM is not set
24# CONFIG_FEATURE_DEVPTS is not set
25# CONFIG_FEATURE_UTMP is not set
26# CONFIG_FEATURE_WTMP is not set
27# CONFIG_FEATURE_PIDFILE is not set
28CONFIG_PID_FILE_PATH=""
29CONFIG_BUSYBOX=y
30CONFIG_FEATURE_SHOW_SCRIPT=y
31CONFIG_FEATURE_INSTALLER=y
32# CONFIG_INSTALL_NO_USR is not set
33# CONFIG_FEATURE_SUID is not set
34# CONFIG_FEATURE_SUID_CONFIG is not set
35# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
36CONFIG_FEATURE_PREFER_APPLETS=y
37CONFIG_BUSYBOX_EXEC_PATH=""
38# CONFIG_SELINUX is not set
39# CONFIG_FEATURE_CLEAN_UP is not set
40# CONFIG_FEATURE_SYSLOG_INFO is not set
41# CONFIG_FEATURE_SYSLOG is not set
42
43#
44# Settings for MINGW32
45#
46CONFIG_GLOBBING=y
47CONFIG_FEATURE_PRNG_SHELL=y
48# CONFIG_FEATURE_PRNG_ISAAC is not set
49CONFIG_FEATURE_RESOURCES=y
50CONFIG_FEATURE_VERSIONINFO=y
51# CONFIG_FEATURE_TOOLCHAIN_MANIFEST is not set
52CONFIG_FEATURE_APP_MANIFEST=y
53# CONFIG_FEATURE_UTF8_MANIFEST is not set
54CONFIG_FEATURE_ICON=y
55# CONFIG_FEATURE_ICON_ATERM is not set
56# CONFIG_FEATURE_ICON_STERM is not set
57CONFIG_FEATURE_ICON_ALL=y
58CONFIG_FEATURE_EURO=y
59# CONFIG_FEATURE_UTF8_INPUT is not set
60# CONFIG_FEATURE_UTF8_OUTPUT is not set
61CONFIG_TERMINAL_MODE=5
62CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y
63CONFIG_FEATURE_EXTRA_FILE_DATA=y
64CONFIG_OVERRIDE_APPLETS=""
65
66#
67# Build Options
68#
69# CONFIG_STATIC is not set
70# CONFIG_PIE is not set
71# CONFIG_NOMMU is not set
72# CONFIG_BUILD_LIBBUSYBOX is not set
73# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set
74# CONFIG_FEATURE_INDIVIDUAL is not set
75# CONFIG_FEATURE_SHARED_BUSYBOX is not set
76CONFIG_CROSS_COMPILER_PREFIX="aarch64-w64-mingw32-"
77CONFIG_HOST_COMPILER="clang"
78CONFIG_CROSS_COMPILER="clang"
79CONFIG_SYSROOT=""
80CONFIG_EXTRA_CFLAGS=""
81CONFIG_EXTRA_LDFLAGS=""
82CONFIG_EXTRA_LDLIBS=""
83CONFIG_USE_PORTABLE_CODE=y
84CONFIG_STACK_OPTIMIZATION_386=y
85# CONFIG_STATIC_LIBGCC is not set
86
87#
88# Installation Options ("make install" behavior)
89#
90CONFIG_INSTALL_APPLET_SYMLINKS=y
91# CONFIG_INSTALL_APPLET_HARDLINKS is not set
92# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
93# CONFIG_INSTALL_APPLET_DONT is not set
94# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
95# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
96# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
97CONFIG_PREFIX=""
98
99#
100# Debugging Options
101#
102# CONFIG_DEBUG is not set
103# CONFIG_DEBUG_PESSIMIZE is not set
104# CONFIG_DEBUG_SANITIZE is not set
105# CONFIG_UNIT_TEST is not set
106# CONFIG_WERROR is not set
107# CONFIG_WARN_SIMPLE_MSG is not set
108CONFIG_NO_DEBUG_LIB=y
109# CONFIG_DMALLOC is not set
110# CONFIG_EFENCE is not set
111
112#
113# Library Tuning
114#
115# CONFIG_FEATURE_USE_BSS_TAIL is not set
116CONFIG_FLOAT_DURATION=y
117# CONFIG_FEATURE_RTMINMAX is not set
118# CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS is not set
119CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
120# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
121# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
122CONFIG_PASSWORD_MINLEN=6
123CONFIG_MD5_SMALL=1
124CONFIG_SHA1_SMALL=3
125# CONFIG_SHA1_HWACCEL is not set
126# CONFIG_SHA256_HWACCEL is not set
127CONFIG_SHA3_SMALL=1
128CONFIG_FEATURE_NON_POSIX_CP=y
129# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
130# CONFIG_FEATURE_USE_SENDFILE is not set
131CONFIG_FEATURE_COPYBUF_KB=4
132# CONFIG_MONOTONIC_SYSCALL is not set
133# CONFIG_IOCTL_HEX2STR_ERROR is not set
134CONFIG_FEATURE_EDITING=y
135CONFIG_FEATURE_EDITING_MAX_LEN=8192
136CONFIG_FEATURE_EDITING_VI=y
137CONFIG_FEATURE_EDITING_HISTORY=1023
138CONFIG_FEATURE_EDITING_HISTORY_DEFAULT=384
139CONFIG_FEATURE_EDITING_SAVEHISTORY=y
140# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
141CONFIG_FEATURE_REVERSE_SEARCH=y
142CONFIG_FEATURE_TAB_COMPLETION=y
143CONFIG_FEATURE_USERNAME_COMPLETION=y
144CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
145# CONFIG_FEATURE_EDITING_WINCH is not set
146# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
147# CONFIG_LOCALE_SUPPORT is not set
148# CONFIG_UNICODE_SUPPORT is not set
149# CONFIG_UNICODE_USING_LOCALE is not set
150# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
151CONFIG_SUBST_WCHAR=0
152CONFIG_LAST_SUPPORTED_WCHAR=0
153# CONFIG_UNICODE_COMBINING_WCHARS is not set
154# CONFIG_UNICODE_WIDE_WCHARS is not set
155# CONFIG_UNICODE_BIDI_SUPPORT is not set
156# CONFIG_UNICODE_NEUTRAL_TABLE is not set
157# CONFIG_UNICODE_PRESERVE_BROKEN is not set
158# CONFIG_LOOP_CONFIGURE is not set
159# CONFIG_NO_LOOP_CONFIGURE is not set
160CONFIG_TRY_LOOP_CONFIGURE=y
161
162#
163# Applets
164#
165
166#
167# Archival Utilities
168#
169CONFIG_FEATURE_SEAMLESS_XZ=y
170CONFIG_FEATURE_SEAMLESS_LZMA=y
171CONFIG_FEATURE_SEAMLESS_BZ2=y
172CONFIG_FEATURE_SEAMLESS_GZ=y
173CONFIG_FEATURE_SEAMLESS_Z=y
174CONFIG_AR=y
175CONFIG_FEATURE_AR_LONG_FILENAMES=y
176CONFIG_FEATURE_AR_CREATE=y
177CONFIG_UNCOMPRESS=y
178CONFIG_GUNZIP=y
179CONFIG_ZCAT=y
180CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y
181CONFIG_BUNZIP2=y
182CONFIG_BZCAT=y
183CONFIG_UNLZMA=y
184CONFIG_LZCAT=y
185CONFIG_LZMA=y
186CONFIG_UNXZ=y
187CONFIG_XZCAT=y
188CONFIG_XZ=y
189CONFIG_BZIP2=y
190CONFIG_BZIP2_SMALL=8
191CONFIG_FEATURE_BZIP2_DECOMPRESS=y
192CONFIG_CPIO=y
193CONFIG_FEATURE_CPIO_O=y
194# CONFIG_FEATURE_CPIO_P is not set
195CONFIG_FEATURE_CPIO_IGNORE_DEVNO=y
196CONFIG_FEATURE_CPIO_RENUMBER_INODES=y
197CONFIG_DPKG=y
198CONFIG_DPKG_DEB=y
199CONFIG_GZIP=y
200CONFIG_FEATURE_GZIP_LONG_OPTIONS=y
201CONFIG_GZIP_FAST=2
202CONFIG_FEATURE_GZIP_LEVELS=y
203CONFIG_FEATURE_GZIP_DECOMPRESS=y
204CONFIG_LZOP=y
205CONFIG_UNLZOP=y
206CONFIG_LZOPCAT=y
207# CONFIG_LZOP_COMPR_HIGH is not set
208CONFIG_RPM=y
209CONFIG_RPM2CPIO=y
210CONFIG_TAR=y
211CONFIG_FEATURE_TAR_LONG_OPTIONS=y
212CONFIG_FEATURE_TAR_CREATE=y
213CONFIG_FEATURE_TAR_AUTODETECT=y
214CONFIG_FEATURE_TAR_FROM=y
215CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
216# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
217CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
218# CONFIG_FEATURE_TAR_TO_COMMAND is not set
219# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
220CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
221# CONFIG_FEATURE_TAR_SELINUX is not set
222CONFIG_UNZIP=y
223CONFIG_FEATURE_UNZIP_CDF=y
224CONFIG_FEATURE_UNZIP_BZIP2=y
225CONFIG_FEATURE_UNZIP_LZMA=y
226CONFIG_FEATURE_UNZIP_XZ=y
227CONFIG_FEATURE_LZMA_FAST=y
228
229#
230# Coreutils
231#
232CONFIG_FEATURE_VERBOSE=y
233
234#
235# Common options for date and touch
236#
237CONFIG_FEATURE_TIMEZONE=y
238
239#
240# Common options for cp and mv
241#
242# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
243
244#
245# Common options for df, du, ls
246#
247CONFIG_FEATURE_HUMAN_READABLE=y
248CONFIG_BASENAME=y
249CONFIG_CAT=y
250CONFIG_FEATURE_CATN=y
251CONFIG_FEATURE_CATV=y
252# CONFIG_CHGRP is not set
253CONFIG_CHMOD=y
254# CONFIG_CHOWN is not set
255# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
256# CONFIG_CHROOT is not set
257CONFIG_CKSUM=y
258CONFIG_CRC32=y
259CONFIG_COMM=y
260CONFIG_CP=y
261CONFIG_FEATURE_CP_LONG_OPTIONS=y
262# CONFIG_FEATURE_CP_REFLINK is not set
263CONFIG_CUT=y
264CONFIG_FEATURE_CUT_REGEX=y
265CONFIG_DATE=y
266CONFIG_FEATURE_DATE_ISOFMT=y
267CONFIG_FEATURE_DATE_NANO=y
268CONFIG_FEATURE_DATE_COMPAT=y
269CONFIG_DD=y
270# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
271# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
272CONFIG_FEATURE_DD_IBS_OBS=y
273CONFIG_FEATURE_DD_STATUS=y
274CONFIG_DF=y
275# CONFIG_FEATURE_DF_FANCY is not set
276# CONFIG_FEATURE_SKIP_ROOTFS is not set
277CONFIG_DIRNAME=y
278CONFIG_DOS2UNIX=y
279CONFIG_UNIX2DOS=y
280CONFIG_DU=y
281CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
282CONFIG_ECHO=y
283CONFIG_FEATURE_FANCY_ECHO=y
284CONFIG_ENV=y
285CONFIG_EXPAND=y
286CONFIG_UNEXPAND=y
287CONFIG_EXPR=y
288CONFIG_EXPR_MATH_SUPPORT_64=y
289CONFIG_FACTOR=y
290CONFIG_FALSE=y
291CONFIG_FOLD=y
292CONFIG_HEAD=y
293CONFIG_FEATURE_FANCY_HEAD=y
294# CONFIG_HOSTID is not set
295CONFIG_ID=y
296CONFIG_GROUPS=y
297CONFIG_INSTALL=y
298CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y
299CONFIG_LINK=y
300CONFIG_LN=y
301CONFIG_LOGNAME=y
302CONFIG_LS=y
303CONFIG_FEATURE_LS_FILETYPES=y
304CONFIG_FEATURE_LS_FOLLOWLINKS=y
305CONFIG_FEATURE_LS_RECURSIVE=y
306CONFIG_FEATURE_LS_WIDTH=y
307CONFIG_FEATURE_LS_SORTFILES=y
308CONFIG_FEATURE_LS_TIMESTAMPS=y
309CONFIG_FEATURE_LS_USERNAME=y
310CONFIG_FEATURE_LS_COLOR=y
311CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
312CONFIG_MD5SUM=y
313CONFIG_SHA1SUM=y
314CONFIG_SHA256SUM=y
315CONFIG_SHA512SUM=y
316CONFIG_SHA3SUM=y
317
318#
319# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
320#
321CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
322CONFIG_MKDIR=y
323# CONFIG_MKFIFO is not set
324# CONFIG_MKNOD is not set
325CONFIG_MKTEMP=y
326CONFIG_MV=y
327# CONFIG_NICE is not set
328CONFIG_NL=y
329# CONFIG_NOHUP is not set
330CONFIG_NPROC=y
331CONFIG_OD=y
332CONFIG_PASTE=y
333CONFIG_PRINTENV=y
334CONFIG_PRINTF=y
335CONFIG_PWD=y
336CONFIG_READLINK=y
337CONFIG_FEATURE_READLINK_FOLLOW=y
338CONFIG_REALPATH=y
339CONFIG_RM=y
340CONFIG_RMDIR=y
341CONFIG_SEQ=y
342CONFIG_SHRED=y
343CONFIG_SHUF=y
344CONFIG_SLEEP=y
345CONFIG_FEATURE_FANCY_SLEEP=y
346CONFIG_SORT=y
347CONFIG_FEATURE_SORT_BIG=y
348# CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set
349CONFIG_SPLIT=y
350CONFIG_FEATURE_SPLIT_FANCY=y
351CONFIG_STAT=y
352CONFIG_FEATURE_STAT_FORMAT=y
353CONFIG_FEATURE_STAT_FILESYSTEM=y
354# CONFIG_STTY is not set
355CONFIG_SUM=y
356CONFIG_SYNC=y
357# CONFIG_FEATURE_SYNC_FANCY is not set
358CONFIG_FSYNC=y
359CONFIG_TAC=y
360CONFIG_TAIL=y
361CONFIG_FEATURE_FANCY_TAIL=y
362CONFIG_TEE=y
363CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
364CONFIG_TEST=y
365CONFIG_TEST1=y
366CONFIG_TEST2=y
367CONFIG_FEATURE_TEST_64=y
368CONFIG_TIMEOUT=y
369CONFIG_TOUCH=y
370CONFIG_FEATURE_TOUCH_SUSV3=y
371CONFIG_TR=y
372CONFIG_FEATURE_TR_CLASSES=y
373CONFIG_FEATURE_TR_EQUIV=y
374CONFIG_TRUE=y
375CONFIG_TRUNCATE=y
376CONFIG_TSORT=y
377# CONFIG_TTY is not set
378CONFIG_UNAME=y
379CONFIG_UNAME_OSNAME="MS/Windows"
380CONFIG_BB_ARCH=y
381CONFIG_UNIQ=y
382CONFIG_UNLINK=y
383CONFIG_USLEEP=y
384CONFIG_UUDECODE=y
385CONFIG_BASE32=y
386CONFIG_BASE64=y
387CONFIG_UUENCODE=y
388CONFIG_WC=y
389CONFIG_FEATURE_WC_LARGE=y
390# CONFIG_WHO is not set
391# CONFIG_W is not set
392# CONFIG_USERS is not set
393CONFIG_WHOAMI=y
394CONFIG_YES=y
395
396#
397# Console Utilities
398#
399# CONFIG_CHVT is not set
400CONFIG_CLEAR=y
401# CONFIG_DEALLOCVT is not set
402# CONFIG_DUMPKMAP is not set
403# CONFIG_FGCONSOLE is not set
404# CONFIG_KBD_MODE is not set
405# CONFIG_LOADFONT is not set
406# CONFIG_SETFONT is not set
407# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
408CONFIG_DEFAULT_SETFONT_DIR=""
409# CONFIG_FEATURE_LOADFONT_PSF2 is not set
410# CONFIG_FEATURE_LOADFONT_RAW is not set
411# CONFIG_LOADKMAP is not set
412# CONFIG_OPENVT is not set
413CONFIG_RESET=y
414# CONFIG_RESIZE is not set
415# CONFIG_FEATURE_RESIZE_PRINT is not set
416# CONFIG_SETCONSOLE is not set
417# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
418# CONFIG_SETKEYCODES is not set
419# CONFIG_SETLOGCONS is not set
420# CONFIG_SHOWKEY is not set
421
422#
423# Debian Utilities
424#
425CONFIG_PIPE_PROGRESS=y
426# CONFIG_RUN_PARTS is not set
427# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
428# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
429# CONFIG_START_STOP_DAEMON is not set
430# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
431# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
432CONFIG_WHICH=y
433
434#
435# klibc-utils
436#
437# CONFIG_MINIPS is not set
438# CONFIG_NUKE is not set
439# CONFIG_RESUME is not set
440# CONFIG_RUN_INIT is not set
441
442#
443# Editors
444#
445CONFIG_AWK=y
446CONFIG_FEATURE_AWK_LIBM=y
447CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
448CONFIG_CMP=y
449CONFIG_DIFF=y
450CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
451CONFIG_FEATURE_DIFF_DIR=y
452CONFIG_ED=y
453CONFIG_PATCH=y
454CONFIG_SED=y
455CONFIG_VI=y
456CONFIG_FEATURE_VI_MAX_LEN=4096
457CONFIG_FEATURE_VI_8BIT=y
458CONFIG_FEATURE_VI_COLON=y
459CONFIG_FEATURE_VI_COLON_EXPAND=y
460CONFIG_FEATURE_VI_YANKMARK=y
461CONFIG_FEATURE_VI_SEARCH=y
462CONFIG_FEATURE_VI_REGEX_SEARCH=y
463# CONFIG_FEATURE_VI_USE_SIGNALS is not set
464CONFIG_FEATURE_VI_DOT_CMD=y
465CONFIG_FEATURE_VI_READONLY=y
466CONFIG_FEATURE_VI_SETOPTS=y
467CONFIG_FEATURE_VI_FILE_FORMAT=y
468CONFIG_FEATURE_VI_SET=y
469CONFIG_FEATURE_VI_WIN_RESIZE=y
470# CONFIG_FEATURE_VI_ASK_TERMINAL is not set
471CONFIG_FEATURE_VI_UNDO=y
472CONFIG_FEATURE_VI_UNDO_QUEUE=y
473CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
474CONFIG_FEATURE_VI_VERBOSE_STATUS=y
475CONFIG_FEATURE_ALLOW_EXEC=y
476
477#
478# Finding Utilities
479#
480CONFIG_FIND=y
481CONFIG_FEATURE_FIND_PRINT0=y
482CONFIG_FEATURE_FIND_MTIME=y
483CONFIG_FEATURE_FIND_ATIME=y
484CONFIG_FEATURE_FIND_CTIME=y
485CONFIG_FEATURE_FIND_MMIN=y
486CONFIG_FEATURE_FIND_AMIN=y
487CONFIG_FEATURE_FIND_CMIN=y
488CONFIG_FEATURE_FIND_PERM=y
489CONFIG_FEATURE_FIND_TYPE=y
490CONFIG_FEATURE_FIND_EXECUTABLE=y
491CONFIG_FEATURE_FIND_XDEV=y
492CONFIG_FEATURE_FIND_MAXDEPTH=y
493CONFIG_FEATURE_FIND_NEWER=y
494CONFIG_FEATURE_FIND_INUM=y
495CONFIG_FEATURE_FIND_SAMEFILE=y
496CONFIG_FEATURE_FIND_EXEC=y
497CONFIG_FEATURE_FIND_EXEC_PLUS=y
498CONFIG_FEATURE_FIND_EXEC_OK=y
499# CONFIG_FEATURE_FIND_USER is not set
500# CONFIG_FEATURE_FIND_GROUP is not set
501CONFIG_FEATURE_FIND_NOT=y
502CONFIG_FEATURE_FIND_DEPTH=y
503CONFIG_FEATURE_FIND_PAREN=y
504CONFIG_FEATURE_FIND_SIZE=y
505CONFIG_FEATURE_FIND_PRUNE=y
506CONFIG_FEATURE_FIND_QUIT=y
507CONFIG_FEATURE_FIND_DELETE=y
508CONFIG_FEATURE_FIND_EMPTY=y
509CONFIG_FEATURE_FIND_PATH=y
510CONFIG_FEATURE_FIND_REGEX=y
511# CONFIG_FEATURE_FIND_CONTEXT is not set
512CONFIG_FEATURE_FIND_LINKS=y
513CONFIG_GREP=y
514CONFIG_EGREP=y
515CONFIG_FGREP=y
516CONFIG_FEATURE_GREP_CONTEXT=y
517CONFIG_XARGS=y
518CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
519CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
520CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
521CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
522CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
523CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y
524CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y
525
526#
527# Init Utilities
528#
529# CONFIG_BOOTCHARTD is not set
530# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
531# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
532# CONFIG_HALT is not set
533# CONFIG_POWEROFF is not set
534# CONFIG_REBOOT is not set
535# CONFIG_FEATURE_WAIT_FOR_INIT is not set
536# CONFIG_FEATURE_CALL_TELINIT is not set
537CONFIG_TELINIT_PATH=""
538# CONFIG_INIT is not set
539# CONFIG_LINUXRC is not set
540# CONFIG_FEATURE_USE_INITTAB is not set
541# CONFIG_FEATURE_KILL_REMOVED is not set
542CONFIG_FEATURE_KILL_DELAY=0
543# CONFIG_FEATURE_INIT_SCTTY is not set
544# CONFIG_FEATURE_INIT_SYSLOG is not set
545# CONFIG_FEATURE_INIT_QUIET is not set
546# CONFIG_FEATURE_INIT_COREDUMPS is not set
547CONFIG_INIT_TERMINAL_TYPE=""
548# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
549
550#
551# Login/Password Management Utilities
552#
553# CONFIG_FEATURE_SHADOWPASSWDS is not set
554# CONFIG_USE_BB_PWD_GRP is not set
555# CONFIG_USE_BB_SHADOW is not set
556# CONFIG_USE_BB_CRYPT is not set
557# CONFIG_USE_BB_CRYPT_SHA is not set
558# CONFIG_ADD_SHELL is not set
559# CONFIG_REMOVE_SHELL is not set
560# CONFIG_ADDGROUP is not set
561# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
562# CONFIG_ADDUSER is not set
563# CONFIG_FEATURE_CHECK_NAMES is not set
564CONFIG_LAST_ID=0
565CONFIG_FIRST_SYSTEM_ID=0
566CONFIG_LAST_SYSTEM_ID=0
567# CONFIG_CHPASSWD is not set
568CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
569# CONFIG_CRYPTPW is not set
570# CONFIG_MKPASSWD is not set
571# CONFIG_DELUSER is not set
572# CONFIG_DELGROUP is not set
573# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
574# CONFIG_GETTY is not set
575# CONFIG_LOGIN is not set
576# CONFIG_LOGIN_SESSION_AS_CHILD is not set
577# CONFIG_LOGIN_SCRIPTS is not set
578# CONFIG_FEATURE_NOLOGIN is not set
579# CONFIG_FEATURE_SECURETTY is not set
580# CONFIG_PASSWD is not set
581# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
582# CONFIG_SU is not set
583# CONFIG_FEATURE_SU_SYSLOG is not set
584# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
585# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set
586# CONFIG_SULOGIN is not set
587CONFIG_SUW32=y
588# CONFIG_VLOCK is not set
589
590#
591# Linux Ext2 FS Progs
592#
593CONFIG_CHATTR=y
594# CONFIG_FSCK is not set
595CONFIG_LSATTR=y
596# CONFIG_TUNE2FS is not set
597
598#
599# Linux Module Utilities
600#
601# CONFIG_MODPROBE_SMALL is not set
602# CONFIG_DEPMOD is not set
603# CONFIG_INSMOD is not set
604# CONFIG_LSMOD is not set
605# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
606# CONFIG_MODINFO is not set
607# CONFIG_MODPROBE is not set
608# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
609# CONFIG_RMMOD is not set
610
611#
612# Options common to multiple modutils
613#
614# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set
615# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
616# CONFIG_FEATURE_2_4_MODULES is not set
617# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
618# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
619# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
620# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
621# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
622# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
623# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
624# CONFIG_FEATURE_MODUTILS_ALIAS is not set
625# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
626CONFIG_DEFAULT_MODULES_DIR=""
627CONFIG_DEFAULT_DEPMOD_FILE=""
628
629#
630# Linux System Utilities
631#
632# CONFIG_ACPID is not set
633# CONFIG_FEATURE_ACPID_COMPAT is not set
634# CONFIG_BLKDISCARD is not set
635# CONFIG_BLKID is not set
636# CONFIG_FEATURE_BLKID_TYPE is not set
637# CONFIG_BLOCKDEV is not set
638CONFIG_CAL=y
639# CONFIG_CHRT is not set
640# CONFIG_DMESG is not set
641# CONFIG_FEATURE_DMESG_PRETTY is not set
642# CONFIG_EJECT is not set
643# CONFIG_FEATURE_EJECT_SCSI is not set
644# CONFIG_FALLOCATE is not set
645# CONFIG_FATATTR is not set
646# CONFIG_FBSET is not set
647# CONFIG_FEATURE_FBSET_FANCY is not set
648# CONFIG_FEATURE_FBSET_READMODE is not set
649# CONFIG_FDFORMAT is not set
650# CONFIG_FDISK is not set
651# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
652# CONFIG_FEATURE_FDISK_WRITABLE is not set
653# CONFIG_FEATURE_AIX_LABEL is not set
654# CONFIG_FEATURE_SGI_LABEL is not set
655# CONFIG_FEATURE_SUN_LABEL is not set
656# CONFIG_FEATURE_OSF_LABEL is not set
657# CONFIG_FEATURE_GPT_LABEL is not set
658# CONFIG_FEATURE_FDISK_ADVANCED is not set
659# CONFIG_FINDFS is not set
660# CONFIG_FLOCK is not set
661# CONFIG_FDFLUSH is not set
662# CONFIG_FREERAMDISK is not set
663# CONFIG_FSCK_MINIX is not set
664# CONFIG_FSFREEZE is not set
665# CONFIG_FSTRIM is not set
666CONFIG_GETOPT=y
667CONFIG_FEATURE_GETOPT_LONG=y
668CONFIG_HEXDUMP=y
669CONFIG_HD=y
670CONFIG_XXD=y
671# CONFIG_HWCLOCK is not set
672# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
673# CONFIG_IONICE is not set
674# CONFIG_IPCRM is not set
675# CONFIG_IPCS is not set
676# CONFIG_LAST is not set
677# CONFIG_FEATURE_LAST_FANCY is not set
678# CONFIG_LOSETUP is not set
679# CONFIG_LSPCI is not set
680# CONFIG_LSUSB is not set
681# CONFIG_MDEV is not set
682# CONFIG_FEATURE_MDEV_CONF is not set
683# CONFIG_FEATURE_MDEV_RENAME is not set
684# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
685# CONFIG_FEATURE_MDEV_EXEC is not set
686# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
687# CONFIG_FEATURE_MDEV_DAEMON is not set
688# CONFIG_MESG is not set
689# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
690# CONFIG_MKE2FS is not set
691# CONFIG_MKFS_EXT2 is not set
692# CONFIG_MKFS_MINIX is not set
693# CONFIG_FEATURE_MINIX2 is not set
694# CONFIG_MKFS_REISER is not set
695# CONFIG_MKDOSFS is not set
696# CONFIG_MKFS_VFAT is not set
697# CONFIG_MKSWAP is not set
698# CONFIG_FEATURE_MKSWAP_UUID is not set
699# CONFIG_MORE is not set
700# CONFIG_MOUNT is not set
701# CONFIG_FEATURE_MOUNT_FAKE is not set
702# CONFIG_FEATURE_MOUNT_VERBOSE is not set
703# CONFIG_FEATURE_MOUNT_HELPERS is not set
704# CONFIG_FEATURE_MOUNT_LABEL is not set
705# CONFIG_FEATURE_MOUNT_NFS is not set
706# CONFIG_FEATURE_MOUNT_CIFS is not set
707# CONFIG_FEATURE_MOUNT_FLAGS is not set
708# CONFIG_FEATURE_MOUNT_FSTAB is not set
709# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
710# CONFIG_MOUNTPOINT is not set
711# CONFIG_NOLOGIN is not set
712# CONFIG_NOLOGIN_DEPENDENCIES is not set
713# CONFIG_NSENTER is not set
714# CONFIG_PIVOT_ROOT is not set
715# CONFIG_RDATE is not set
716# CONFIG_RDEV is not set
717# CONFIG_READPROFILE is not set
718# CONFIG_RENICE is not set
719CONFIG_REV=y
720# CONFIG_RTCWAKE is not set
721# CONFIG_SCRIPT is not set
722# CONFIG_SCRIPTREPLAY is not set
723# CONFIG_SETARCH is not set
724# CONFIG_LINUX32 is not set
725# CONFIG_LINUX64 is not set
726# CONFIG_SETPRIV is not set
727# CONFIG_FEATURE_SETPRIV_DUMP is not set
728# CONFIG_FEATURE_SETPRIV_CAPABILITIES is not set
729# CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES is not set
730# CONFIG_SETSID is not set
731# CONFIG_SWAPON is not set
732# CONFIG_FEATURE_SWAPON_DISCARD is not set
733# CONFIG_FEATURE_SWAPON_PRI is not set
734# CONFIG_SWAPOFF is not set
735# CONFIG_FEATURE_SWAPONOFF_LABEL is not set
736# CONFIG_SWITCH_ROOT is not set
737# CONFIG_TASKSET is not set
738# CONFIG_FEATURE_TASKSET_FANCY is not set
739# CONFIG_FEATURE_TASKSET_CPULIST is not set
740# CONFIG_UEVENT is not set
741# CONFIG_UMOUNT is not set
742# CONFIG_FEATURE_UMOUNT_ALL is not set
743# CONFIG_UNSHARE is not set
744# CONFIG_WALL is not set
745# CONFIG_FEATURE_MOUNT_LOOP is not set
746# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
747# CONFIG_FEATURE_MTAB_SUPPORT is not set
748# CONFIG_VOLUMEID is not set
749# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
750# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
751# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
752# CONFIG_FEATURE_VOLUMEID_EROFS is not set
753# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
754# CONFIG_FEATURE_VOLUMEID_EXT is not set
755# CONFIG_FEATURE_VOLUMEID_F2FS is not set
756# CONFIG_FEATURE_VOLUMEID_FAT is not set
757# CONFIG_FEATURE_VOLUMEID_HFS is not set
758# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
759# CONFIG_FEATURE_VOLUMEID_JFS is not set
760# CONFIG_FEATURE_VOLUMEID_LFS is not set
761# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
762# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
763# CONFIG_FEATURE_VOLUMEID_LUKS is not set
764# CONFIG_FEATURE_VOLUMEID_MINIX is not set
765# CONFIG_FEATURE_VOLUMEID_NILFS is not set
766# CONFIG_FEATURE_VOLUMEID_NTFS is not set
767# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
768# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
769# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
770# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
771# CONFIG_FEATURE_VOLUMEID_SYSV is not set
772# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
773# CONFIG_FEATURE_VOLUMEID_UDF is not set
774# CONFIG_FEATURE_VOLUMEID_XFS is not set
775
776#
777# Miscellaneous Utilities
778#
779# CONFIG_ADJTIMEX is not set
780CONFIG_ASCII=y
781# CONFIG_BBCONFIG is not set
782# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
783CONFIG_BC=y
784CONFIG_DC=y
785CONFIG_FEATURE_DC_BIG=y
786# CONFIG_FEATURE_DC_LIBM is not set
787CONFIG_FEATURE_BC_INTERACTIVE=y
788CONFIG_FEATURE_BC_LONG_OPTIONS=y
789# CONFIG_BEEP is not set
790CONFIG_FEATURE_BEEP_FREQ=0
791CONFIG_FEATURE_BEEP_LENGTH_MS=0
792# CONFIG_CHAT is not set
793# CONFIG_FEATURE_CHAT_NOFAIL is not set
794# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
795# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
796# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
797# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
798# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
799# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
800# CONFIG_CONSPY is not set
801# CONFIG_CROND is not set
802# CONFIG_FEATURE_CROND_D is not set
803# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
804# CONFIG_FEATURE_CROND_SPECIAL_TIMES is not set
805CONFIG_FEATURE_CROND_DIR=""
806# CONFIG_CRONTAB is not set
807# CONFIG_DEVFSD is not set
808# CONFIG_DEVFSD_MODLOAD is not set
809# CONFIG_DEVFSD_FG_NP is not set
810# CONFIG_DEVFSD_VERBOSE is not set
811# CONFIG_FEATURE_DEVFS is not set
812# CONFIG_DEVMEM is not set
813CONFIG_DROP=y
814CONFIG_CDROP=y
815CONFIG_PDROP=y
816# CONFIG_FBSPLASH is not set
817# CONFIG_FLASH_ERASEALL is not set
818# CONFIG_FLASH_LOCK is not set
819# CONFIG_FLASH_UNLOCK is not set
820# CONFIG_FLASHCP is not set
821# CONFIG_GETFATTR is not set
822# CONFIG_HDPARM is not set
823# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
824# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
825# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
826# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
827# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
828# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
829# CONFIG_HEXEDIT is not set
830# CONFIG_I2CGET is not set
831# CONFIG_I2CSET is not set
832# CONFIG_I2CDUMP is not set
833# CONFIG_I2CDETECT is not set
834# CONFIG_I2CTRANSFER is not set
835CONFIG_ICONV=y
836CONFIG_INOTIFYD=y
837CONFIG_JN=y
838CONFIG_LESS=y
839CONFIG_FEATURE_LESS_MAXLINES=9999999
840CONFIG_FEATURE_LESS_BRACKETS=y
841CONFIG_FEATURE_LESS_FLAGS=y
842CONFIG_FEATURE_LESS_TRUNCATE=y
843CONFIG_FEATURE_LESS_MARKS=y
844CONFIG_FEATURE_LESS_REGEXP=y
845# CONFIG_FEATURE_LESS_WINCH is not set
846# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
847CONFIG_FEATURE_LESS_DASHCMD=y
848CONFIG_FEATURE_LESS_LINENUMS=y
849CONFIG_FEATURE_LESS_RAW=y
850CONFIG_FEATURE_LESS_ENV=y
851# CONFIG_LSSCSI is not set
852CONFIG_MAKE=y
853CONFIG_PDPMAKE=y
854CONFIG_FEATURE_MAKE_POSIX=y
855# CONFIG_FEATURE_MAKE_POSIX_2017 is not set
856CONFIG_FEATURE_MAKE_POSIX_2024=y
857# CONFIG_MAKEDEVS is not set
858# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
859# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
860CONFIG_MAN=y
861# CONFIG_MICROCOM is not set
862# CONFIG_MIM is not set
863# CONFIG_MT is not set
864# CONFIG_NANDWRITE is not set
865# CONFIG_NANDDUMP is not set
866# CONFIG_PARTPROBE is not set
867# CONFIG_RAIDAUTORUN is not set
868# CONFIG_READAHEAD is not set
869# CONFIG_RFKILL is not set
870# CONFIG_RUNLEVEL is not set
871# CONFIG_RX is not set
872# CONFIG_SEEDRNG is not set
873# CONFIG_SETFATTR is not set
874# CONFIG_SETSERIAL is not set
875CONFIG_STRINGS=y
876CONFIG_TIME=y
877# CONFIG_TREE is not set
878CONFIG_TS=y
879CONFIG_TTYSIZE=y
880# CONFIG_UBIATTACH is not set
881# CONFIG_UBIDETACH is not set
882# CONFIG_UBIMKVOL is not set
883# CONFIG_UBIRMVOL is not set
884# CONFIG_UBIRSVOL is not set
885# CONFIG_UBIUPDATEVOL is not set
886# CONFIG_UBIRENAME is not set
887# CONFIG_VOLNAME is not set
888# CONFIG_WATCHDOG is not set
889# CONFIG_FEATURE_WATCHDOG_OPEN_TWICE is not set
890
891#
892# Networking Utilities
893#
894CONFIG_FEATURE_IPV6=y
895# CONFIG_FEATURE_UNIX_LOCAL is not set
896CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
897# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
898# CONFIG_FEATURE_ETC_NETWORKS is not set
899# CONFIG_FEATURE_ETC_SERVICES is not set
900# CONFIG_FEATURE_HWIB is not set
901# CONFIG_FEATURE_TLS_SHA1 is not set
902# CONFIG_ARP is not set
903# CONFIG_ARPING is not set
904# CONFIG_BRCTL is not set
905# CONFIG_FEATURE_BRCTL_FANCY is not set
906# CONFIG_FEATURE_BRCTL_SHOW is not set
907# CONFIG_DNSD is not set
908# CONFIG_ETHER_WAKE is not set
909# CONFIG_FTPD is not set
910# CONFIG_FEATURE_FTPD_WRITE is not set
911# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
912# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
913CONFIG_FTPGET=y
914CONFIG_FTPPUT=y
915CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
916# CONFIG_HOSTNAME is not set
917# CONFIG_DNSDOMAINNAME is not set
918CONFIG_HTTPD=y
919CONFIG_FEATURE_HTTPD_PORT_DEFAULT=80
920CONFIG_FEATURE_HTTPD_RANGES=y
921# CONFIG_FEATURE_HTTPD_SETUID is not set
922CONFIG_FEATURE_HTTPD_BASIC_AUTH=y
923# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
924CONFIG_FEATURE_HTTPD_CGI=y
925CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y
926# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
927CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y
928CONFIG_FEATURE_HTTPD_ERROR_PAGES=y
929# CONFIG_FEATURE_HTTPD_PROXY is not set
930CONFIG_FEATURE_HTTPD_GZIP=y
931CONFIG_FEATURE_HTTPD_ETAG=y
932CONFIG_FEATURE_HTTPD_LAST_MODIFIED=y
933CONFIG_FEATURE_HTTPD_DATE=y
934CONFIG_FEATURE_HTTPD_ACL_IP=y
935# CONFIG_IFCONFIG is not set
936# CONFIG_FEATURE_IFCONFIG_STATUS is not set
937# CONFIG_FEATURE_IFCONFIG_SLIP is not set
938# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
939# CONFIG_FEATURE_IFCONFIG_HW is not set
940# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
941# CONFIG_IFENSLAVE is not set
942# CONFIG_IFPLUGD is not set
943# CONFIG_IFUP is not set
944# CONFIG_IFDOWN is not set
945CONFIG_IFUPDOWN_IFSTATE_PATH=""
946# CONFIG_FEATURE_IFUPDOWN_IP is not set
947# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
948# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
949# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
950# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
951# CONFIG_INETD is not set
952# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
953# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
954# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
955# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
956# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
957# CONFIG_FEATURE_INETD_RPC is not set
958# CONFIG_IP is not set
959# CONFIG_IPADDR is not set
960# CONFIG_IPLINK is not set
961# CONFIG_IPROUTE is not set
962# CONFIG_IPTUNNEL is not set
963# CONFIG_IPRULE is not set
964# CONFIG_IPNEIGH is not set
965# CONFIG_FEATURE_IP_ADDRESS is not set
966# CONFIG_FEATURE_IP_LINK is not set
967# CONFIG_FEATURE_IP_ROUTE is not set
968CONFIG_FEATURE_IP_ROUTE_DIR=""
969# CONFIG_FEATURE_IP_TUNNEL is not set
970# CONFIG_FEATURE_IP_RULE is not set
971# CONFIG_FEATURE_IP_NEIGH is not set
972# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
973CONFIG_IPCALC=y
974CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y
975CONFIG_FEATURE_IPCALC_FANCY=y
976# CONFIG_FAKEIDENTD is not set
977# CONFIG_NAMEIF is not set
978# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
979# CONFIG_NBDCLIENT is not set
980CONFIG_NC=y
981# CONFIG_NETCAT is not set
982CONFIG_NC_SERVER=y
983# CONFIG_NC_EXTRA is not set
984# CONFIG_NC_110_COMPAT is not set
985# CONFIG_NETSTAT is not set
986# CONFIG_FEATURE_NETSTAT_WIDE is not set
987# CONFIG_FEATURE_NETSTAT_PRG is not set
988# CONFIG_NSLOOKUP is not set
989# CONFIG_FEATURE_NSLOOKUP_BIG is not set
990# CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS is not set
991# CONFIG_NTPD is not set
992# CONFIG_FEATURE_NTPD_SERVER is not set
993# CONFIG_FEATURE_NTPD_CONF is not set
994# CONFIG_FEATURE_NTP_AUTH is not set
995# CONFIG_PING is not set
996# CONFIG_PING6 is not set
997# CONFIG_FEATURE_FANCY_PING is not set
998# CONFIG_PSCAN is not set
999# CONFIG_ROUTE is not set
1000# CONFIG_SLATTACH is not set
1001CONFIG_SSL_CLIENT=y
1002# CONFIG_TC is not set
1003# CONFIG_FEATURE_TC_INGRESS is not set
1004# CONFIG_TCPSVD is not set
1005# CONFIG_UDPSVD is not set
1006# CONFIG_TELNET is not set
1007# CONFIG_FEATURE_TELNET_TTYPE is not set
1008# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
1009# CONFIG_FEATURE_TELNET_WIDTH is not set
1010# CONFIG_TELNETD is not set
1011# CONFIG_FEATURE_TELNETD_STANDALONE is not set
1012CONFIG_FEATURE_TELNETD_PORT_DEFAULT=0
1013# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
1014# CONFIG_TFTP is not set
1015# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
1016# CONFIG_FEATURE_TFTP_HPA_COMPAT is not set
1017# CONFIG_TFTPD is not set
1018# CONFIG_FEATURE_TFTP_GET is not set
1019# CONFIG_FEATURE_TFTP_PUT is not set
1020# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
1021# CONFIG_TFTP_DEBUG is not set
1022CONFIG_TLS=y
1023# CONFIG_TRACEROUTE is not set
1024# CONFIG_TRACEROUTE6 is not set
1025# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
1026# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
1027# CONFIG_TUNCTL is not set
1028# CONFIG_FEATURE_TUNCTL_UG is not set
1029# CONFIG_VCONFIG is not set
1030CONFIG_WGET=y
1031CONFIG_FEATURE_WGET_LONG_OPTIONS=y
1032CONFIG_FEATURE_WGET_STATUSBAR=y
1033CONFIG_FEATURE_WGET_FTP=y
1034CONFIG_FEATURE_WGET_AUTHENTICATION=y
1035# CONFIG_FEATURE_WGET_TIMEOUT is not set
1036CONFIG_FEATURE_WGET_HTTPS=y
1037# CONFIG_FEATURE_WGET_OPENSSL is not set
1038CONFIG_WHOIS=y
1039# CONFIG_ZCIP is not set
1040# CONFIG_UDHCPD is not set
1041# CONFIG_FEATURE_UDHCPD_BOOTP is not set
1042# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
1043# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
1044CONFIG_DHCPD_LEASES_FILE=""
1045# CONFIG_DUMPLEASES is not set
1046# CONFIG_DHCPRELAY is not set
1047# CONFIG_UDHCPC is not set
1048# CONFIG_FEATURE_UDHCPC_ARPING is not set
1049# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
1050CONFIG_UDHCPC_DEFAULT_SCRIPT=""
1051CONFIG_UDHCPC6_DEFAULT_SCRIPT=""
1052# CONFIG_UDHCPC6 is not set
1053# CONFIG_FEATURE_UDHCPC6_RFC3646 is not set
1054# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set
1055# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set
1056# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set
1057CONFIG_UDHCPC_DEFAULT_INTERFACE=""
1058# CONFIG_FEATURE_UDHCP_PORT is not set
1059CONFIG_UDHCP_DEBUG=0
1060CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
1061# CONFIG_FEATURE_UDHCP_RFC3397 is not set
1062# CONFIG_FEATURE_UDHCP_8021Q is not set
1063CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
1064
1065#
1066# Print Utilities
1067#
1068# CONFIG_LPD is not set
1069# CONFIG_LPR is not set
1070# CONFIG_LPQ is not set
1071
1072#
1073# Mail Utilities
1074#
1075CONFIG_FEATURE_MIME_CHARSET=""
1076# CONFIG_MAKEMIME is not set
1077# CONFIG_POPMAILDIR is not set
1078# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
1079# CONFIG_REFORMIME is not set
1080# CONFIG_FEATURE_REFORMIME_COMPAT is not set
1081# CONFIG_SENDMAIL is not set
1082
1083#
1084# Process Utilities
1085#
1086# CONFIG_FEATURE_FAST_TOP is not set
1087# CONFIG_FEATURE_SHOW_THREADS is not set
1088CONFIG_FREE=y
1089# CONFIG_FUSER is not set
1090# CONFIG_IOSTAT is not set
1091CONFIG_KILL=y
1092CONFIG_KILLALL=y
1093# CONFIG_KILLALL5 is not set
1094# CONFIG_LSOF is not set
1095# CONFIG_MPSTAT is not set
1096# CONFIG_NMETER is not set
1097CONFIG_PGREP=y
1098CONFIG_PKILL=y
1099CONFIG_PIDOF=y
1100CONFIG_FEATURE_PIDOF_SINGLE=y
1101CONFIG_FEATURE_PIDOF_OMIT=y
1102# CONFIG_PMAP is not set
1103# CONFIG_POWERTOP is not set
1104# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set
1105CONFIG_PS=y
1106# CONFIG_FEATURE_PS_WIDE is not set
1107# CONFIG_FEATURE_PS_LONG is not set
1108CONFIG_FEATURE_PS_TIME=y
1109# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
1110# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
1111# CONFIG_PSTREE is not set
1112# CONFIG_PWDX is not set
1113# CONFIG_SMEMCAP is not set
1114# CONFIG_BB_SYSCTL is not set
1115# CONFIG_TOP is not set
1116# CONFIG_FEATURE_TOP_INTERACTIVE is not set
1117# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
1118# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
1119# CONFIG_FEATURE_TOP_SMP_CPU is not set
1120# CONFIG_FEATURE_TOP_DECIMALS is not set
1121# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
1122# CONFIG_FEATURE_TOPMEM is not set
1123CONFIG_UPTIME=y
1124# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
1125CONFIG_WATCH=y
1126
1127#
1128# Runit Utilities
1129#
1130# CONFIG_CHPST is not set
1131# CONFIG_SETUIDGID is not set
1132# CONFIG_ENVUIDGID is not set
1133# CONFIG_ENVDIR is not set
1134# CONFIG_SOFTLIMIT is not set
1135# CONFIG_RUNSV is not set
1136# CONFIG_RUNSVDIR is not set
1137# CONFIG_FEATURE_RUNSVDIR_LOG is not set
1138# CONFIG_SV is not set
1139CONFIG_SV_DEFAULT_SERVICE_DIR=""
1140# CONFIG_SVC is not set
1141# CONFIG_SVOK is not set
1142# CONFIG_SVLOGD is not set
1143# CONFIG_CHCON is not set
1144# CONFIG_GETENFORCE is not set
1145# CONFIG_GETSEBOOL is not set
1146# CONFIG_LOAD_POLICY is not set
1147# CONFIG_MATCHPATHCON is not set
1148# CONFIG_RUNCON is not set
1149# CONFIG_SELINUXENABLED is not set
1150# CONFIG_SESTATUS is not set
1151# CONFIG_SETENFORCE is not set
1152# CONFIG_SETFILES is not set
1153# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
1154# CONFIG_RESTORECON is not set
1155# CONFIG_SETSEBOOL is not set
1156
1157#
1158# Shells
1159#
1160CONFIG_SH_IS_ASH=y
1161# CONFIG_SH_IS_HUSH is not set
1162# CONFIG_SH_IS_NONE is not set
1163CONFIG_BASH_IS_ASH=y
1164# CONFIG_BASH_IS_HUSH is not set
1165# CONFIG_BASH_IS_NONE is not set
1166CONFIG_SHELL_ASH=y
1167CONFIG_ASH=y
1168# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set
1169CONFIG_ASH_INTERNAL_GLOB=y
1170CONFIG_ASH_BASH_COMPAT=y
1171# CONFIG_ASH_BASH_SOURCE_CURDIR is not set
1172CONFIG_ASH_BASH_NOT_FOUND_HOOK=y
1173CONFIG_ASH_JOB_CONTROL=y
1174CONFIG_ASH_ALIAS=y
1175CONFIG_ASH_RANDOM_SUPPORT=y
1176CONFIG_ASH_EXPAND_PRMT=y
1177# CONFIG_ASH_IDLE_TIMEOUT is not set
1178# CONFIG_ASH_MAIL is not set
1179CONFIG_ASH_ECHO=y
1180CONFIG_ASH_PRINTF=y
1181CONFIG_ASH_TEST=y
1182CONFIG_ASH_HELP=y
1183CONFIG_ASH_GETOPTS=y
1184CONFIG_ASH_CMDCMD=y
1185CONFIG_ASH_NOCONSOLE=y
1186CONFIG_ASH_GLOB_OPTIONS=y
1187# CONFIG_CTTYHACK is not set
1188# CONFIG_HUSH is not set
1189# CONFIG_SHELL_HUSH is not set
1190# CONFIG_HUSH_BASH_COMPAT is not set
1191# CONFIG_HUSH_BRACE_EXPANSION is not set
1192# CONFIG_HUSH_BASH_SOURCE_CURDIR is not set
1193# CONFIG_HUSH_LINENO_VAR is not set
1194# CONFIG_HUSH_INTERACTIVE is not set
1195# CONFIG_HUSH_SAVEHISTORY is not set
1196# CONFIG_HUSH_JOB is not set
1197# CONFIG_HUSH_TICK is not set
1198# CONFIG_HUSH_IF is not set
1199# CONFIG_HUSH_LOOPS is not set
1200# CONFIG_HUSH_CASE is not set
1201# CONFIG_HUSH_FUNCTIONS is not set
1202# CONFIG_HUSH_LOCAL is not set
1203# CONFIG_HUSH_RANDOM_SUPPORT is not set
1204# CONFIG_HUSH_MODE_X is not set
1205# CONFIG_HUSH_ECHO is not set
1206# CONFIG_HUSH_PRINTF is not set
1207# CONFIG_HUSH_TEST is not set
1208# CONFIG_HUSH_HELP is not set
1209# CONFIG_HUSH_EXPORT is not set
1210# CONFIG_HUSH_EXPORT_N is not set
1211# CONFIG_HUSH_READONLY is not set
1212# CONFIG_HUSH_KILL is not set
1213# CONFIG_HUSH_WAIT is not set
1214# CONFIG_HUSH_COMMAND is not set
1215# CONFIG_HUSH_TRAP is not set
1216# CONFIG_HUSH_TYPE is not set
1217# CONFIG_HUSH_TIMES is not set
1218# CONFIG_HUSH_READ is not set
1219# CONFIG_HUSH_SET is not set
1220# CONFIG_HUSH_UNSET is not set
1221# CONFIG_HUSH_ULIMIT is not set
1222# CONFIG_HUSH_UMASK is not set
1223# CONFIG_HUSH_GETOPTS is not set
1224# CONFIG_HUSH_MEMLEAK is not set
1225
1226#
1227# Options common to all shells
1228#
1229CONFIG_FEATURE_SH_MATH=y
1230CONFIG_FEATURE_SH_MATH_64=y
1231CONFIG_FEATURE_SH_MATH_BASE=y
1232CONFIG_FEATURE_SH_EXTRA_QUIET=y
1233CONFIG_FEATURE_SH_STANDALONE=y
1234CONFIG_FEATURE_SH_NOFORK=y
1235CONFIG_FEATURE_SH_READ_FRAC=y
1236CONFIG_FEATURE_SH_HISTFILESIZE=y
1237CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS=y
1238
1239#
1240# System Logging Utilities
1241#
1242# CONFIG_KLOGD is not set
1243# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
1244# CONFIG_LOGGER is not set
1245# CONFIG_LOGREAD is not set
1246# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1247# CONFIG_SYSLOGD is not set
1248# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1249# CONFIG_FEATURE_REMOTE_LOG is not set
1250# CONFIG_FEATURE_SYSLOGD_DUP is not set
1251# CONFIG_FEATURE_SYSLOGD_CFG is not set
1252# CONFIG_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS is not set
1253CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1254# CONFIG_FEATURE_IPC_SYSLOG is not set
1255CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1256# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/configs/mingw64u_defconfig b/configs/mingw64u_defconfig
new file mode 100644
index 000000000..61753699d
--- /dev/null
+++ b/configs/mingw64u_defconfig
@@ -0,0 +1,1256 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.37.0.git
4# Fri Jun 14 12:24:50 2024
5#
6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set
8CONFIG_PLATFORM_MINGW32=y
9
10#
11# Settings
12#
13CONFIG_DESKTOP=y
14# CONFIG_EXTRA_COMPAT is not set
15# CONFIG_FEDORA_COMPAT is not set
16# CONFIG_INCLUDE_SUSv2 is not set
17CONFIG_LONG_OPTS=y
18CONFIG_SHOW_USAGE=y
19CONFIG_FEATURE_VERBOSE_USAGE=y
20CONFIG_FEATURE_COMPRESS_USAGE=y
21CONFIG_LFS=y
22CONFIG_TIME64=y
23# CONFIG_PAM is not set
24# CONFIG_FEATURE_DEVPTS is not set
25# CONFIG_FEATURE_UTMP is not set
26# CONFIG_FEATURE_WTMP is not set
27# CONFIG_FEATURE_PIDFILE is not set
28CONFIG_PID_FILE_PATH=""
29CONFIG_BUSYBOX=y
30CONFIG_FEATURE_SHOW_SCRIPT=y
31CONFIG_FEATURE_INSTALLER=y
32# CONFIG_INSTALL_NO_USR is not set
33# CONFIG_FEATURE_SUID is not set
34# CONFIG_FEATURE_SUID_CONFIG is not set
35# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
36CONFIG_FEATURE_PREFER_APPLETS=y
37CONFIG_BUSYBOX_EXEC_PATH=""
38# CONFIG_SELINUX is not set
39# CONFIG_FEATURE_CLEAN_UP is not set
40# CONFIG_FEATURE_SYSLOG_INFO is not set
41# CONFIG_FEATURE_SYSLOG is not set
42
43#
44# Settings for MINGW32
45#
46CONFIG_GLOBBING=y
47CONFIG_FEATURE_PRNG_SHELL=y
48# CONFIG_FEATURE_PRNG_ISAAC is not set
49CONFIG_FEATURE_RESOURCES=y
50CONFIG_FEATURE_VERSIONINFO=y
51# CONFIG_FEATURE_TOOLCHAIN_MANIFEST is not set
52# CONFIG_FEATURE_APP_MANIFEST is not set
53CONFIG_FEATURE_UTF8_MANIFEST=y
54CONFIG_FEATURE_ICON=y
55# CONFIG_FEATURE_ICON_ATERM is not set
56# CONFIG_FEATURE_ICON_STERM is not set
57CONFIG_FEATURE_ICON_ALL=y
58CONFIG_FEATURE_EURO=y
59CONFIG_FEATURE_UTF8_INPUT=y
60CONFIG_FEATURE_UTF8_OUTPUT=y
61CONFIG_TERMINAL_MODE=5
62CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y
63CONFIG_FEATURE_EXTRA_FILE_DATA=y
64CONFIG_OVERRIDE_APPLETS=""
65
66#
67# Build Options
68#
69# CONFIG_STATIC is not set
70# CONFIG_PIE is not set
71# CONFIG_NOMMU is not set
72# CONFIG_BUILD_LIBBUSYBOX is not set
73# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set
74# CONFIG_FEATURE_INDIVIDUAL is not set
75# CONFIG_FEATURE_SHARED_BUSYBOX is not set
76CONFIG_CROSS_COMPILER_PREFIX="x86_64-w64-mingw32-"
77CONFIG_HOST_COMPILER="gcc"
78CONFIG_CROSS_COMPILER="gcc"
79CONFIG_SYSROOT=""
80CONFIG_EXTRA_CFLAGS=""
81CONFIG_EXTRA_LDFLAGS=""
82CONFIG_EXTRA_LDLIBS=""
83CONFIG_USE_PORTABLE_CODE=y
84CONFIG_STACK_OPTIMIZATION_386=y
85CONFIG_STATIC_LIBGCC=y
86
87#
88# Installation Options ("make install" behavior)
89#
90CONFIG_INSTALL_APPLET_SYMLINKS=y
91# CONFIG_INSTALL_APPLET_HARDLINKS is not set
92# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
93# CONFIG_INSTALL_APPLET_DONT is not set
94# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
95# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
96# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
97CONFIG_PREFIX=""
98
99#
100# Debugging Options
101#
102# CONFIG_DEBUG is not set
103# CONFIG_DEBUG_PESSIMIZE is not set
104# CONFIG_DEBUG_SANITIZE is not set
105# CONFIG_UNIT_TEST is not set
106# CONFIG_WERROR is not set
107# CONFIG_WARN_SIMPLE_MSG is not set
108CONFIG_NO_DEBUG_LIB=y
109# CONFIG_DMALLOC is not set
110# CONFIG_EFENCE is not set
111
112#
113# Library Tuning
114#
115# CONFIG_FEATURE_USE_BSS_TAIL is not set
116CONFIG_FLOAT_DURATION=y
117# CONFIG_FEATURE_RTMINMAX is not set
118# CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS is not set
119CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
120# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
121# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
122CONFIG_PASSWORD_MINLEN=6
123CONFIG_MD5_SMALL=1
124CONFIG_SHA1_SMALL=3
125# CONFIG_SHA1_HWACCEL is not set
126# CONFIG_SHA256_HWACCEL is not set
127CONFIG_SHA3_SMALL=1
128CONFIG_FEATURE_NON_POSIX_CP=y
129# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
130# CONFIG_FEATURE_USE_SENDFILE is not set
131CONFIG_FEATURE_COPYBUF_KB=4
132# CONFIG_MONOTONIC_SYSCALL is not set
133# CONFIG_IOCTL_HEX2STR_ERROR is not set
134CONFIG_FEATURE_EDITING=y
135CONFIG_FEATURE_EDITING_MAX_LEN=8192
136CONFIG_FEATURE_EDITING_VI=y
137CONFIG_FEATURE_EDITING_HISTORY=1023
138CONFIG_FEATURE_EDITING_HISTORY_DEFAULT=384
139CONFIG_FEATURE_EDITING_SAVEHISTORY=y
140# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
141CONFIG_FEATURE_REVERSE_SEARCH=y
142CONFIG_FEATURE_TAB_COMPLETION=y
143CONFIG_FEATURE_USERNAME_COMPLETION=y
144CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
145# CONFIG_FEATURE_EDITING_WINCH is not set
146# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
147# CONFIG_LOCALE_SUPPORT is not set
148CONFIG_UNICODE_SUPPORT=y
149# CONFIG_UNICODE_USING_LOCALE is not set
150CONFIG_FEATURE_CHECK_UNICODE_IN_ENV=y
151CONFIG_SUBST_WCHAR=63
152CONFIG_LAST_SUPPORTED_WCHAR=1114111
153CONFIG_UNICODE_COMBINING_WCHARS=y
154CONFIG_UNICODE_WIDE_WCHARS=y
155# CONFIG_UNICODE_BIDI_SUPPORT is not set
156# CONFIG_UNICODE_NEUTRAL_TABLE is not set
157# CONFIG_UNICODE_PRESERVE_BROKEN is not set
158# CONFIG_LOOP_CONFIGURE is not set
159# CONFIG_NO_LOOP_CONFIGURE is not set
160CONFIG_TRY_LOOP_CONFIGURE=y
161
162#
163# Applets
164#
165
166#
167# Archival Utilities
168#
169CONFIG_FEATURE_SEAMLESS_XZ=y
170CONFIG_FEATURE_SEAMLESS_LZMA=y
171CONFIG_FEATURE_SEAMLESS_BZ2=y
172CONFIG_FEATURE_SEAMLESS_GZ=y
173CONFIG_FEATURE_SEAMLESS_Z=y
174CONFIG_AR=y
175CONFIG_FEATURE_AR_LONG_FILENAMES=y
176CONFIG_FEATURE_AR_CREATE=y
177CONFIG_UNCOMPRESS=y
178CONFIG_GUNZIP=y
179CONFIG_ZCAT=y
180CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y
181CONFIG_BUNZIP2=y
182CONFIG_BZCAT=y
183CONFIG_UNLZMA=y
184CONFIG_LZCAT=y
185CONFIG_LZMA=y
186CONFIG_UNXZ=y
187CONFIG_XZCAT=y
188CONFIG_XZ=y
189CONFIG_BZIP2=y
190CONFIG_BZIP2_SMALL=8
191CONFIG_FEATURE_BZIP2_DECOMPRESS=y
192CONFIG_CPIO=y
193CONFIG_FEATURE_CPIO_O=y
194# CONFIG_FEATURE_CPIO_P is not set
195CONFIG_FEATURE_CPIO_IGNORE_DEVNO=y
196CONFIG_FEATURE_CPIO_RENUMBER_INODES=y
197CONFIG_DPKG=y
198CONFIG_DPKG_DEB=y
199CONFIG_GZIP=y
200CONFIG_FEATURE_GZIP_LONG_OPTIONS=y
201CONFIG_GZIP_FAST=2
202CONFIG_FEATURE_GZIP_LEVELS=y
203CONFIG_FEATURE_GZIP_DECOMPRESS=y
204CONFIG_LZOP=y
205CONFIG_UNLZOP=y
206CONFIG_LZOPCAT=y
207# CONFIG_LZOP_COMPR_HIGH is not set
208CONFIG_RPM=y
209CONFIG_RPM2CPIO=y
210CONFIG_TAR=y
211CONFIG_FEATURE_TAR_LONG_OPTIONS=y
212CONFIG_FEATURE_TAR_CREATE=y
213CONFIG_FEATURE_TAR_AUTODETECT=y
214CONFIG_FEATURE_TAR_FROM=y
215CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
216# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
217CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
218# CONFIG_FEATURE_TAR_TO_COMMAND is not set
219# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
220CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
221# CONFIG_FEATURE_TAR_SELINUX is not set
222CONFIG_UNZIP=y
223CONFIG_FEATURE_UNZIP_CDF=y
224CONFIG_FEATURE_UNZIP_BZIP2=y
225CONFIG_FEATURE_UNZIP_LZMA=y
226CONFIG_FEATURE_UNZIP_XZ=y
227CONFIG_FEATURE_LZMA_FAST=y
228
229#
230# Coreutils
231#
232CONFIG_FEATURE_VERBOSE=y
233
234#
235# Common options for date and touch
236#
237CONFIG_FEATURE_TIMEZONE=y
238
239#
240# Common options for cp and mv
241#
242# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
243
244#
245# Common options for df, du, ls
246#
247CONFIG_FEATURE_HUMAN_READABLE=y
248CONFIG_BASENAME=y
249CONFIG_CAT=y
250CONFIG_FEATURE_CATN=y
251CONFIG_FEATURE_CATV=y
252# CONFIG_CHGRP is not set
253CONFIG_CHMOD=y
254# CONFIG_CHOWN is not set
255# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
256# CONFIG_CHROOT is not set
257CONFIG_CKSUM=y
258CONFIG_CRC32=y
259CONFIG_COMM=y
260CONFIG_CP=y
261CONFIG_FEATURE_CP_LONG_OPTIONS=y
262# CONFIG_FEATURE_CP_REFLINK is not set
263CONFIG_CUT=y
264CONFIG_FEATURE_CUT_REGEX=y
265CONFIG_DATE=y
266CONFIG_FEATURE_DATE_ISOFMT=y
267CONFIG_FEATURE_DATE_NANO=y
268CONFIG_FEATURE_DATE_COMPAT=y
269CONFIG_DD=y
270# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
271# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
272CONFIG_FEATURE_DD_IBS_OBS=y
273CONFIG_FEATURE_DD_STATUS=y
274CONFIG_DF=y
275# CONFIG_FEATURE_DF_FANCY is not set
276# CONFIG_FEATURE_SKIP_ROOTFS is not set
277CONFIG_DIRNAME=y
278CONFIG_DOS2UNIX=y
279CONFIG_UNIX2DOS=y
280CONFIG_DU=y
281CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
282CONFIG_ECHO=y
283CONFIG_FEATURE_FANCY_ECHO=y
284CONFIG_ENV=y
285CONFIG_EXPAND=y
286CONFIG_UNEXPAND=y
287CONFIG_EXPR=y
288CONFIG_EXPR_MATH_SUPPORT_64=y
289CONFIG_FACTOR=y
290CONFIG_FALSE=y
291CONFIG_FOLD=y
292CONFIG_HEAD=y
293CONFIG_FEATURE_FANCY_HEAD=y
294# CONFIG_HOSTID is not set
295CONFIG_ID=y
296CONFIG_GROUPS=y
297CONFIG_INSTALL=y
298CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y
299CONFIG_LINK=y
300CONFIG_LN=y
301CONFIG_LOGNAME=y
302CONFIG_LS=y
303CONFIG_FEATURE_LS_FILETYPES=y
304CONFIG_FEATURE_LS_FOLLOWLINKS=y
305CONFIG_FEATURE_LS_RECURSIVE=y
306CONFIG_FEATURE_LS_WIDTH=y
307CONFIG_FEATURE_LS_SORTFILES=y
308CONFIG_FEATURE_LS_TIMESTAMPS=y
309CONFIG_FEATURE_LS_USERNAME=y
310CONFIG_FEATURE_LS_COLOR=y
311CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
312CONFIG_MD5SUM=y
313CONFIG_SHA1SUM=y
314CONFIG_SHA256SUM=y
315CONFIG_SHA512SUM=y
316CONFIG_SHA3SUM=y
317
318#
319# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
320#
321CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
322CONFIG_MKDIR=y
323# CONFIG_MKFIFO is not set
324# CONFIG_MKNOD is not set
325CONFIG_MKTEMP=y
326CONFIG_MV=y
327# CONFIG_NICE is not set
328CONFIG_NL=y
329# CONFIG_NOHUP is not set
330CONFIG_NPROC=y
331CONFIG_OD=y
332CONFIG_PASTE=y
333CONFIG_PRINTENV=y
334CONFIG_PRINTF=y
335CONFIG_PWD=y
336CONFIG_READLINK=y
337CONFIG_FEATURE_READLINK_FOLLOW=y
338CONFIG_REALPATH=y
339CONFIG_RM=y
340CONFIG_RMDIR=y
341CONFIG_SEQ=y
342CONFIG_SHRED=y
343CONFIG_SHUF=y
344CONFIG_SLEEP=y
345CONFIG_FEATURE_FANCY_SLEEP=y
346CONFIG_SORT=y
347CONFIG_FEATURE_SORT_BIG=y
348# CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set
349CONFIG_SPLIT=y
350CONFIG_FEATURE_SPLIT_FANCY=y
351CONFIG_STAT=y
352CONFIG_FEATURE_STAT_FORMAT=y
353CONFIG_FEATURE_STAT_FILESYSTEM=y
354# CONFIG_STTY is not set
355CONFIG_SUM=y
356CONFIG_SYNC=y
357# CONFIG_FEATURE_SYNC_FANCY is not set
358CONFIG_FSYNC=y
359CONFIG_TAC=y
360CONFIG_TAIL=y
361CONFIG_FEATURE_FANCY_TAIL=y
362CONFIG_TEE=y
363CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
364CONFIG_TEST=y
365CONFIG_TEST1=y
366CONFIG_TEST2=y
367CONFIG_FEATURE_TEST_64=y
368CONFIG_TIMEOUT=y
369CONFIG_TOUCH=y
370CONFIG_FEATURE_TOUCH_SUSV3=y
371CONFIG_TR=y
372CONFIG_FEATURE_TR_CLASSES=y
373CONFIG_FEATURE_TR_EQUIV=y
374CONFIG_TRUE=y
375CONFIG_TRUNCATE=y
376CONFIG_TSORT=y
377# CONFIG_TTY is not set
378CONFIG_UNAME=y
379CONFIG_UNAME_OSNAME="MS/Windows"
380CONFIG_BB_ARCH=y
381CONFIG_UNIQ=y
382CONFIG_UNLINK=y
383CONFIG_USLEEP=y
384CONFIG_UUDECODE=y
385CONFIG_BASE32=y
386CONFIG_BASE64=y
387CONFIG_UUENCODE=y
388CONFIG_WC=y
389CONFIG_FEATURE_WC_LARGE=y
390# CONFIG_WHO is not set
391# CONFIG_W is not set
392# CONFIG_USERS is not set
393CONFIG_WHOAMI=y
394CONFIG_YES=y
395
396#
397# Console Utilities
398#
399# CONFIG_CHVT is not set
400CONFIG_CLEAR=y
401# CONFIG_DEALLOCVT is not set
402# CONFIG_DUMPKMAP is not set
403# CONFIG_FGCONSOLE is not set
404# CONFIG_KBD_MODE is not set
405# CONFIG_LOADFONT is not set
406# CONFIG_SETFONT is not set
407# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
408CONFIG_DEFAULT_SETFONT_DIR=""
409# CONFIG_FEATURE_LOADFONT_PSF2 is not set
410# CONFIG_FEATURE_LOADFONT_RAW is not set
411# CONFIG_LOADKMAP is not set
412# CONFIG_OPENVT is not set
413CONFIG_RESET=y
414# CONFIG_RESIZE is not set
415# CONFIG_FEATURE_RESIZE_PRINT is not set
416# CONFIG_SETCONSOLE is not set
417# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
418# CONFIG_SETKEYCODES is not set
419# CONFIG_SETLOGCONS is not set
420# CONFIG_SHOWKEY is not set
421
422#
423# Debian Utilities
424#
425CONFIG_PIPE_PROGRESS=y
426# CONFIG_RUN_PARTS is not set
427# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
428# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
429# CONFIG_START_STOP_DAEMON is not set
430# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
431# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
432CONFIG_WHICH=y
433
434#
435# klibc-utils
436#
437# CONFIG_MINIPS is not set
438# CONFIG_NUKE is not set
439# CONFIG_RESUME is not set
440# CONFIG_RUN_INIT is not set
441
442#
443# Editors
444#
445CONFIG_AWK=y
446CONFIG_FEATURE_AWK_LIBM=y
447CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
448CONFIG_CMP=y
449CONFIG_DIFF=y
450CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
451CONFIG_FEATURE_DIFF_DIR=y
452CONFIG_ED=y
453CONFIG_PATCH=y
454CONFIG_SED=y
455CONFIG_VI=y
456CONFIG_FEATURE_VI_MAX_LEN=4096
457CONFIG_FEATURE_VI_8BIT=y
458CONFIG_FEATURE_VI_COLON=y
459CONFIG_FEATURE_VI_COLON_EXPAND=y
460CONFIG_FEATURE_VI_YANKMARK=y
461CONFIG_FEATURE_VI_SEARCH=y
462CONFIG_FEATURE_VI_REGEX_SEARCH=y
463# CONFIG_FEATURE_VI_USE_SIGNALS is not set
464CONFIG_FEATURE_VI_DOT_CMD=y
465CONFIG_FEATURE_VI_READONLY=y
466CONFIG_FEATURE_VI_SETOPTS=y
467CONFIG_FEATURE_VI_FILE_FORMAT=y
468CONFIG_FEATURE_VI_SET=y
469CONFIG_FEATURE_VI_WIN_RESIZE=y
470# CONFIG_FEATURE_VI_ASK_TERMINAL is not set
471CONFIG_FEATURE_VI_UNDO=y
472CONFIG_FEATURE_VI_UNDO_QUEUE=y
473CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
474CONFIG_FEATURE_VI_VERBOSE_STATUS=y
475CONFIG_FEATURE_ALLOW_EXEC=y
476
477#
478# Finding Utilities
479#
480CONFIG_FIND=y
481CONFIG_FEATURE_FIND_PRINT0=y
482CONFIG_FEATURE_FIND_MTIME=y
483CONFIG_FEATURE_FIND_ATIME=y
484CONFIG_FEATURE_FIND_CTIME=y
485CONFIG_FEATURE_FIND_MMIN=y
486CONFIG_FEATURE_FIND_AMIN=y
487CONFIG_FEATURE_FIND_CMIN=y
488CONFIG_FEATURE_FIND_PERM=y
489CONFIG_FEATURE_FIND_TYPE=y
490CONFIG_FEATURE_FIND_EXECUTABLE=y
491CONFIG_FEATURE_FIND_XDEV=y
492CONFIG_FEATURE_FIND_MAXDEPTH=y
493CONFIG_FEATURE_FIND_NEWER=y
494CONFIG_FEATURE_FIND_INUM=y
495CONFIG_FEATURE_FIND_SAMEFILE=y
496CONFIG_FEATURE_FIND_EXEC=y
497CONFIG_FEATURE_FIND_EXEC_PLUS=y
498CONFIG_FEATURE_FIND_EXEC_OK=y
499# CONFIG_FEATURE_FIND_USER is not set
500# CONFIG_FEATURE_FIND_GROUP is not set
501CONFIG_FEATURE_FIND_NOT=y
502CONFIG_FEATURE_FIND_DEPTH=y
503CONFIG_FEATURE_FIND_PAREN=y
504CONFIG_FEATURE_FIND_SIZE=y
505CONFIG_FEATURE_FIND_PRUNE=y
506CONFIG_FEATURE_FIND_QUIT=y
507CONFIG_FEATURE_FIND_DELETE=y
508CONFIG_FEATURE_FIND_EMPTY=y
509CONFIG_FEATURE_FIND_PATH=y
510CONFIG_FEATURE_FIND_REGEX=y
511# CONFIG_FEATURE_FIND_CONTEXT is not set
512CONFIG_FEATURE_FIND_LINKS=y
513CONFIG_GREP=y
514CONFIG_EGREP=y
515CONFIG_FGREP=y
516CONFIG_FEATURE_GREP_CONTEXT=y
517CONFIG_XARGS=y
518CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
519CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
520CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
521CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
522CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
523CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y
524CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y
525
526#
527# Init Utilities
528#
529# CONFIG_BOOTCHARTD is not set
530# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
531# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
532# CONFIG_HALT is not set
533# CONFIG_POWEROFF is not set
534# CONFIG_REBOOT is not set
535# CONFIG_FEATURE_WAIT_FOR_INIT is not set
536# CONFIG_FEATURE_CALL_TELINIT is not set
537CONFIG_TELINIT_PATH=""
538# CONFIG_INIT is not set
539# CONFIG_LINUXRC is not set
540# CONFIG_FEATURE_USE_INITTAB is not set
541# CONFIG_FEATURE_KILL_REMOVED is not set
542CONFIG_FEATURE_KILL_DELAY=0
543# CONFIG_FEATURE_INIT_SCTTY is not set
544# CONFIG_FEATURE_INIT_SYSLOG is not set
545# CONFIG_FEATURE_INIT_QUIET is not set
546# CONFIG_FEATURE_INIT_COREDUMPS is not set
547CONFIG_INIT_TERMINAL_TYPE=""
548# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
549
550#
551# Login/Password Management Utilities
552#
553# CONFIG_FEATURE_SHADOWPASSWDS is not set
554# CONFIG_USE_BB_PWD_GRP is not set
555# CONFIG_USE_BB_SHADOW is not set
556# CONFIG_USE_BB_CRYPT is not set
557# CONFIG_USE_BB_CRYPT_SHA is not set
558# CONFIG_ADD_SHELL is not set
559# CONFIG_REMOVE_SHELL is not set
560# CONFIG_ADDGROUP is not set
561# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
562# CONFIG_ADDUSER is not set
563# CONFIG_FEATURE_CHECK_NAMES is not set
564CONFIG_LAST_ID=0
565CONFIG_FIRST_SYSTEM_ID=0
566CONFIG_LAST_SYSTEM_ID=0
567# CONFIG_CHPASSWD is not set
568CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
569# CONFIG_CRYPTPW is not set
570# CONFIG_MKPASSWD is not set
571# CONFIG_DELUSER is not set
572# CONFIG_DELGROUP is not set
573# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
574# CONFIG_GETTY is not set
575# CONFIG_LOGIN is not set
576# CONFIG_LOGIN_SESSION_AS_CHILD is not set
577# CONFIG_LOGIN_SCRIPTS is not set
578# CONFIG_FEATURE_NOLOGIN is not set
579# CONFIG_FEATURE_SECURETTY is not set
580# CONFIG_PASSWD is not set
581# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
582# CONFIG_SU is not set
583# CONFIG_FEATURE_SU_SYSLOG is not set
584# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
585# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set
586# CONFIG_SULOGIN is not set
587CONFIG_SUW32=y
588# CONFIG_VLOCK is not set
589
590#
591# Linux Ext2 FS Progs
592#
593CONFIG_CHATTR=y
594# CONFIG_FSCK is not set
595CONFIG_LSATTR=y
596# CONFIG_TUNE2FS is not set
597
598#
599# Linux Module Utilities
600#
601# CONFIG_MODPROBE_SMALL is not set
602# CONFIG_DEPMOD is not set
603# CONFIG_INSMOD is not set
604# CONFIG_LSMOD is not set
605# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
606# CONFIG_MODINFO is not set
607# CONFIG_MODPROBE is not set
608# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
609# CONFIG_RMMOD is not set
610
611#
612# Options common to multiple modutils
613#
614# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set
615# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
616# CONFIG_FEATURE_2_4_MODULES is not set
617# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
618# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
619# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
620# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
621# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
622# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
623# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
624# CONFIG_FEATURE_MODUTILS_ALIAS is not set
625# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
626CONFIG_DEFAULT_MODULES_DIR=""
627CONFIG_DEFAULT_DEPMOD_FILE=""
628
629#
630# Linux System Utilities
631#
632# CONFIG_ACPID is not set
633# CONFIG_FEATURE_ACPID_COMPAT is not set
634# CONFIG_BLKDISCARD is not set
635# CONFIG_BLKID is not set
636# CONFIG_FEATURE_BLKID_TYPE is not set
637# CONFIG_BLOCKDEV is not set
638CONFIG_CAL=y
639# CONFIG_CHRT is not set
640# CONFIG_DMESG is not set
641# CONFIG_FEATURE_DMESG_PRETTY is not set
642# CONFIG_EJECT is not set
643# CONFIG_FEATURE_EJECT_SCSI is not set
644# CONFIG_FALLOCATE is not set
645# CONFIG_FATATTR is not set
646# CONFIG_FBSET is not set
647# CONFIG_FEATURE_FBSET_FANCY is not set
648# CONFIG_FEATURE_FBSET_READMODE is not set
649# CONFIG_FDFORMAT is not set
650# CONFIG_FDISK is not set
651# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
652# CONFIG_FEATURE_FDISK_WRITABLE is not set
653# CONFIG_FEATURE_AIX_LABEL is not set
654# CONFIG_FEATURE_SGI_LABEL is not set
655# CONFIG_FEATURE_SUN_LABEL is not set
656# CONFIG_FEATURE_OSF_LABEL is not set
657# CONFIG_FEATURE_GPT_LABEL is not set
658# CONFIG_FEATURE_FDISK_ADVANCED is not set
659# CONFIG_FINDFS is not set
660# CONFIG_FLOCK is not set
661# CONFIG_FDFLUSH is not set
662# CONFIG_FREERAMDISK is not set
663# CONFIG_FSCK_MINIX is not set
664# CONFIG_FSFREEZE is not set
665# CONFIG_FSTRIM is not set
666CONFIG_GETOPT=y
667CONFIG_FEATURE_GETOPT_LONG=y
668CONFIG_HEXDUMP=y
669CONFIG_HD=y
670CONFIG_XXD=y
671# CONFIG_HWCLOCK is not set
672# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
673# CONFIG_IONICE is not set
674# CONFIG_IPCRM is not set
675# CONFIG_IPCS is not set
676# CONFIG_LAST is not set
677# CONFIG_FEATURE_LAST_FANCY is not set
678# CONFIG_LOSETUP is not set
679# CONFIG_LSPCI is not set
680# CONFIG_LSUSB is not set
681# CONFIG_MDEV is not set
682# CONFIG_FEATURE_MDEV_CONF is not set
683# CONFIG_FEATURE_MDEV_RENAME is not set
684# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
685# CONFIG_FEATURE_MDEV_EXEC is not set
686# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
687# CONFIG_FEATURE_MDEV_DAEMON is not set
688# CONFIG_MESG is not set
689# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
690# CONFIG_MKE2FS is not set
691# CONFIG_MKFS_EXT2 is not set
692# CONFIG_MKFS_MINIX is not set
693# CONFIG_FEATURE_MINIX2 is not set
694# CONFIG_MKFS_REISER is not set
695# CONFIG_MKDOSFS is not set
696# CONFIG_MKFS_VFAT is not set
697# CONFIG_MKSWAP is not set
698# CONFIG_FEATURE_MKSWAP_UUID is not set
699# CONFIG_MORE is not set
700# CONFIG_MOUNT is not set
701# CONFIG_FEATURE_MOUNT_FAKE is not set
702# CONFIG_FEATURE_MOUNT_VERBOSE is not set
703# CONFIG_FEATURE_MOUNT_HELPERS is not set
704# CONFIG_FEATURE_MOUNT_LABEL is not set
705# CONFIG_FEATURE_MOUNT_NFS is not set
706# CONFIG_FEATURE_MOUNT_CIFS is not set
707# CONFIG_FEATURE_MOUNT_FLAGS is not set
708# CONFIG_FEATURE_MOUNT_FSTAB is not set
709# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
710# CONFIG_MOUNTPOINT is not set
711# CONFIG_NOLOGIN is not set
712# CONFIG_NOLOGIN_DEPENDENCIES is not set
713# CONFIG_NSENTER is not set
714# CONFIG_PIVOT_ROOT is not set
715# CONFIG_RDATE is not set
716# CONFIG_RDEV is not set
717# CONFIG_READPROFILE is not set
718# CONFIG_RENICE is not set
719CONFIG_REV=y
720# CONFIG_RTCWAKE is not set
721# CONFIG_SCRIPT is not set
722# CONFIG_SCRIPTREPLAY is not set
723# CONFIG_SETARCH is not set
724# CONFIG_LINUX32 is not set
725# CONFIG_LINUX64 is not set
726# CONFIG_SETPRIV is not set
727# CONFIG_FEATURE_SETPRIV_DUMP is not set
728# CONFIG_FEATURE_SETPRIV_CAPABILITIES is not set
729# CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES is not set
730# CONFIG_SETSID is not set
731# CONFIG_SWAPON is not set
732# CONFIG_FEATURE_SWAPON_DISCARD is not set
733# CONFIG_FEATURE_SWAPON_PRI is not set
734# CONFIG_SWAPOFF is not set
735# CONFIG_FEATURE_SWAPONOFF_LABEL is not set
736# CONFIG_SWITCH_ROOT is not set
737# CONFIG_TASKSET is not set
738# CONFIG_FEATURE_TASKSET_FANCY is not set
739# CONFIG_FEATURE_TASKSET_CPULIST is not set
740# CONFIG_UEVENT is not set
741# CONFIG_UMOUNT is not set
742# CONFIG_FEATURE_UMOUNT_ALL is not set
743# CONFIG_UNSHARE is not set
744# CONFIG_WALL is not set
745# CONFIG_FEATURE_MOUNT_LOOP is not set
746# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
747# CONFIG_FEATURE_MTAB_SUPPORT is not set
748# CONFIG_VOLUMEID is not set
749# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
750# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
751# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
752# CONFIG_FEATURE_VOLUMEID_EROFS is not set
753# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
754# CONFIG_FEATURE_VOLUMEID_EXT is not set
755# CONFIG_FEATURE_VOLUMEID_F2FS is not set
756# CONFIG_FEATURE_VOLUMEID_FAT is not set
757# CONFIG_FEATURE_VOLUMEID_HFS is not set
758# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
759# CONFIG_FEATURE_VOLUMEID_JFS is not set
760# CONFIG_FEATURE_VOLUMEID_LFS is not set
761# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
762# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
763# CONFIG_FEATURE_VOLUMEID_LUKS is not set
764# CONFIG_FEATURE_VOLUMEID_MINIX is not set
765# CONFIG_FEATURE_VOLUMEID_NILFS is not set
766# CONFIG_FEATURE_VOLUMEID_NTFS is not set
767# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
768# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
769# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
770# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
771# CONFIG_FEATURE_VOLUMEID_SYSV is not set
772# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
773# CONFIG_FEATURE_VOLUMEID_UDF is not set
774# CONFIG_FEATURE_VOLUMEID_XFS is not set
775
776#
777# Miscellaneous Utilities
778#
779# CONFIG_ADJTIMEX is not set
780CONFIG_ASCII=y
781# CONFIG_BBCONFIG is not set
782# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
783CONFIG_BC=y
784CONFIG_DC=y
785CONFIG_FEATURE_DC_BIG=y
786# CONFIG_FEATURE_DC_LIBM is not set
787CONFIG_FEATURE_BC_INTERACTIVE=y
788CONFIG_FEATURE_BC_LONG_OPTIONS=y
789# CONFIG_BEEP is not set
790CONFIG_FEATURE_BEEP_FREQ=0
791CONFIG_FEATURE_BEEP_LENGTH_MS=0
792# CONFIG_CHAT is not set
793# CONFIG_FEATURE_CHAT_NOFAIL is not set
794# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
795# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
796# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
797# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
798# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
799# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
800# CONFIG_CONSPY is not set
801# CONFIG_CROND is not set
802# CONFIG_FEATURE_CROND_D is not set
803# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
804# CONFIG_FEATURE_CROND_SPECIAL_TIMES is not set
805CONFIG_FEATURE_CROND_DIR=""
806# CONFIG_CRONTAB is not set
807# CONFIG_DEVFSD is not set
808# CONFIG_DEVFSD_MODLOAD is not set
809# CONFIG_DEVFSD_FG_NP is not set
810# CONFIG_DEVFSD_VERBOSE is not set
811# CONFIG_FEATURE_DEVFS is not set
812# CONFIG_DEVMEM is not set
813CONFIG_DROP=y
814CONFIG_CDROP=y
815CONFIG_PDROP=y
816# CONFIG_FBSPLASH is not set
817# CONFIG_FLASH_ERASEALL is not set
818# CONFIG_FLASH_LOCK is not set
819# CONFIG_FLASH_UNLOCK is not set
820# CONFIG_FLASHCP is not set
821# CONFIG_GETFATTR is not set
822# CONFIG_HDPARM is not set
823# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
824# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
825# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
826# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
827# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
828# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
829# CONFIG_HEXEDIT is not set
830# CONFIG_I2CGET is not set
831# CONFIG_I2CSET is not set
832# CONFIG_I2CDUMP is not set
833# CONFIG_I2CDETECT is not set
834# CONFIG_I2CTRANSFER is not set
835CONFIG_ICONV=y
836CONFIG_INOTIFYD=y
837CONFIG_JN=y
838CONFIG_LESS=y
839CONFIG_FEATURE_LESS_MAXLINES=9999999
840CONFIG_FEATURE_LESS_BRACKETS=y
841CONFIG_FEATURE_LESS_FLAGS=y
842CONFIG_FEATURE_LESS_TRUNCATE=y
843CONFIG_FEATURE_LESS_MARKS=y
844CONFIG_FEATURE_LESS_REGEXP=y
845# CONFIG_FEATURE_LESS_WINCH is not set
846# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
847CONFIG_FEATURE_LESS_DASHCMD=y
848CONFIG_FEATURE_LESS_LINENUMS=y
849CONFIG_FEATURE_LESS_RAW=y
850CONFIG_FEATURE_LESS_ENV=y
851# CONFIG_LSSCSI is not set
852CONFIG_MAKE=y
853CONFIG_PDPMAKE=y
854CONFIG_FEATURE_MAKE_POSIX=y
855# CONFIG_FEATURE_MAKE_POSIX_2017 is not set
856CONFIG_FEATURE_MAKE_POSIX_2024=y
857# CONFIG_MAKEDEVS is not set
858# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
859# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
860CONFIG_MAN=y
861# CONFIG_MICROCOM is not set
862# CONFIG_MIM is not set
863# CONFIG_MT is not set
864# CONFIG_NANDWRITE is not set
865# CONFIG_NANDDUMP is not set
866# CONFIG_PARTPROBE is not set
867# CONFIG_RAIDAUTORUN is not set
868# CONFIG_READAHEAD is not set
869# CONFIG_RFKILL is not set
870# CONFIG_RUNLEVEL is not set
871# CONFIG_RX is not set
872# CONFIG_SEEDRNG is not set
873# CONFIG_SETFATTR is not set
874# CONFIG_SETSERIAL is not set
875CONFIG_STRINGS=y
876CONFIG_TIME=y
877# CONFIG_TREE is not set
878CONFIG_TS=y
879CONFIG_TTYSIZE=y
880# CONFIG_UBIATTACH is not set
881# CONFIG_UBIDETACH is not set
882# CONFIG_UBIMKVOL is not set
883# CONFIG_UBIRMVOL is not set
884# CONFIG_UBIRSVOL is not set
885# CONFIG_UBIUPDATEVOL is not set
886# CONFIG_UBIRENAME is not set
887# CONFIG_VOLNAME is not set
888# CONFIG_WATCHDOG is not set
889# CONFIG_FEATURE_WATCHDOG_OPEN_TWICE is not set
890
891#
892# Networking Utilities
893#
894CONFIG_FEATURE_IPV6=y
895# CONFIG_FEATURE_UNIX_LOCAL is not set
896CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
897# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
898# CONFIG_FEATURE_ETC_NETWORKS is not set
899# CONFIG_FEATURE_ETC_SERVICES is not set
900# CONFIG_FEATURE_HWIB is not set
901# CONFIG_FEATURE_TLS_SHA1 is not set
902# CONFIG_ARP is not set
903# CONFIG_ARPING is not set
904# CONFIG_BRCTL is not set
905# CONFIG_FEATURE_BRCTL_FANCY is not set
906# CONFIG_FEATURE_BRCTL_SHOW is not set
907# CONFIG_DNSD is not set
908# CONFIG_ETHER_WAKE is not set
909# CONFIG_FTPD is not set
910# CONFIG_FEATURE_FTPD_WRITE is not set
911# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
912# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
913CONFIG_FTPGET=y
914CONFIG_FTPPUT=y
915CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
916# CONFIG_HOSTNAME is not set
917# CONFIG_DNSDOMAINNAME is not set
918CONFIG_HTTPD=y
919CONFIG_FEATURE_HTTPD_PORT_DEFAULT=80
920CONFIG_FEATURE_HTTPD_RANGES=y
921# CONFIG_FEATURE_HTTPD_SETUID is not set
922CONFIG_FEATURE_HTTPD_BASIC_AUTH=y
923# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
924CONFIG_FEATURE_HTTPD_CGI=y
925CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y
926# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
927CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y
928CONFIG_FEATURE_HTTPD_ERROR_PAGES=y
929# CONFIG_FEATURE_HTTPD_PROXY is not set
930CONFIG_FEATURE_HTTPD_GZIP=y
931CONFIG_FEATURE_HTTPD_ETAG=y
932CONFIG_FEATURE_HTTPD_LAST_MODIFIED=y
933CONFIG_FEATURE_HTTPD_DATE=y
934CONFIG_FEATURE_HTTPD_ACL_IP=y
935# CONFIG_IFCONFIG is not set
936# CONFIG_FEATURE_IFCONFIG_STATUS is not set
937# CONFIG_FEATURE_IFCONFIG_SLIP is not set
938# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
939# CONFIG_FEATURE_IFCONFIG_HW is not set
940# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
941# CONFIG_IFENSLAVE is not set
942# CONFIG_IFPLUGD is not set
943# CONFIG_IFUP is not set
944# CONFIG_IFDOWN is not set
945CONFIG_IFUPDOWN_IFSTATE_PATH=""
946# CONFIG_FEATURE_IFUPDOWN_IP is not set
947# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
948# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
949# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
950# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
951# CONFIG_INETD is not set
952# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
953# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
954# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
955# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
956# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
957# CONFIG_FEATURE_INETD_RPC is not set
958# CONFIG_IP is not set
959# CONFIG_IPADDR is not set
960# CONFIG_IPLINK is not set
961# CONFIG_IPROUTE is not set
962# CONFIG_IPTUNNEL is not set
963# CONFIG_IPRULE is not set
964# CONFIG_IPNEIGH is not set
965# CONFIG_FEATURE_IP_ADDRESS is not set
966# CONFIG_FEATURE_IP_LINK is not set
967# CONFIG_FEATURE_IP_ROUTE is not set
968CONFIG_FEATURE_IP_ROUTE_DIR=""
969# CONFIG_FEATURE_IP_TUNNEL is not set
970# CONFIG_FEATURE_IP_RULE is not set
971# CONFIG_FEATURE_IP_NEIGH is not set
972# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
973CONFIG_IPCALC=y
974CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y
975CONFIG_FEATURE_IPCALC_FANCY=y
976# CONFIG_FAKEIDENTD is not set
977# CONFIG_NAMEIF is not set
978# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
979# CONFIG_NBDCLIENT is not set
980CONFIG_NC=y
981# CONFIG_NETCAT is not set
982CONFIG_NC_SERVER=y
983# CONFIG_NC_EXTRA is not set
984# CONFIG_NC_110_COMPAT is not set
985# CONFIG_NETSTAT is not set
986# CONFIG_FEATURE_NETSTAT_WIDE is not set
987# CONFIG_FEATURE_NETSTAT_PRG is not set
988# CONFIG_NSLOOKUP is not set
989# CONFIG_FEATURE_NSLOOKUP_BIG is not set
990# CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS is not set
991# CONFIG_NTPD is not set
992# CONFIG_FEATURE_NTPD_SERVER is not set
993# CONFIG_FEATURE_NTPD_CONF is not set
994# CONFIG_FEATURE_NTP_AUTH is not set
995# CONFIG_PING is not set
996# CONFIG_PING6 is not set
997# CONFIG_FEATURE_FANCY_PING is not set
998# CONFIG_PSCAN is not set
999# CONFIG_ROUTE is not set
1000# CONFIG_SLATTACH is not set
1001CONFIG_SSL_CLIENT=y
1002# CONFIG_TC is not set
1003# CONFIG_FEATURE_TC_INGRESS is not set
1004# CONFIG_TCPSVD is not set
1005# CONFIG_UDPSVD is not set
1006# CONFIG_TELNET is not set
1007# CONFIG_FEATURE_TELNET_TTYPE is not set
1008# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
1009# CONFIG_FEATURE_TELNET_WIDTH is not set
1010# CONFIG_TELNETD is not set
1011# CONFIG_FEATURE_TELNETD_STANDALONE is not set
1012CONFIG_FEATURE_TELNETD_PORT_DEFAULT=0
1013# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
1014# CONFIG_TFTP is not set
1015# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
1016# CONFIG_FEATURE_TFTP_HPA_COMPAT is not set
1017# CONFIG_TFTPD is not set
1018# CONFIG_FEATURE_TFTP_GET is not set
1019# CONFIG_FEATURE_TFTP_PUT is not set
1020# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
1021# CONFIG_TFTP_DEBUG is not set
1022CONFIG_TLS=y
1023# CONFIG_TRACEROUTE is not set
1024# CONFIG_TRACEROUTE6 is not set
1025# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
1026# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
1027# CONFIG_TUNCTL is not set
1028# CONFIG_FEATURE_TUNCTL_UG is not set
1029# CONFIG_VCONFIG is not set
1030CONFIG_WGET=y
1031CONFIG_FEATURE_WGET_LONG_OPTIONS=y
1032CONFIG_FEATURE_WGET_STATUSBAR=y
1033CONFIG_FEATURE_WGET_FTP=y
1034CONFIG_FEATURE_WGET_AUTHENTICATION=y
1035# CONFIG_FEATURE_WGET_TIMEOUT is not set
1036CONFIG_FEATURE_WGET_HTTPS=y
1037# CONFIG_FEATURE_WGET_OPENSSL is not set
1038CONFIG_WHOIS=y
1039# CONFIG_ZCIP is not set
1040# CONFIG_UDHCPD is not set
1041# CONFIG_FEATURE_UDHCPD_BOOTP is not set
1042# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
1043# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
1044CONFIG_DHCPD_LEASES_FILE=""
1045# CONFIG_DUMPLEASES is not set
1046# CONFIG_DHCPRELAY is not set
1047# CONFIG_UDHCPC is not set
1048# CONFIG_FEATURE_UDHCPC_ARPING is not set
1049# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
1050CONFIG_UDHCPC_DEFAULT_SCRIPT=""
1051CONFIG_UDHCPC6_DEFAULT_SCRIPT=""
1052# CONFIG_UDHCPC6 is not set
1053# CONFIG_FEATURE_UDHCPC6_RFC3646 is not set
1054# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set
1055# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set
1056# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set
1057CONFIG_UDHCPC_DEFAULT_INTERFACE=""
1058# CONFIG_FEATURE_UDHCP_PORT is not set
1059CONFIG_UDHCP_DEBUG=0
1060CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
1061# CONFIG_FEATURE_UDHCP_RFC3397 is not set
1062# CONFIG_FEATURE_UDHCP_8021Q is not set
1063CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
1064
1065#
1066# Print Utilities
1067#
1068# CONFIG_LPD is not set
1069# CONFIG_LPR is not set
1070# CONFIG_LPQ is not set
1071
1072#
1073# Mail Utilities
1074#
1075CONFIG_FEATURE_MIME_CHARSET=""
1076# CONFIG_MAKEMIME is not set
1077# CONFIG_POPMAILDIR is not set
1078# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
1079# CONFIG_REFORMIME is not set
1080# CONFIG_FEATURE_REFORMIME_COMPAT is not set
1081# CONFIG_SENDMAIL is not set
1082
1083#
1084# Process Utilities
1085#
1086# CONFIG_FEATURE_FAST_TOP is not set
1087# CONFIG_FEATURE_SHOW_THREADS is not set
1088CONFIG_FREE=y
1089# CONFIG_FUSER is not set
1090# CONFIG_IOSTAT is not set
1091CONFIG_KILL=y
1092CONFIG_KILLALL=y
1093# CONFIG_KILLALL5 is not set
1094# CONFIG_LSOF is not set
1095# CONFIG_MPSTAT is not set
1096# CONFIG_NMETER is not set
1097CONFIG_PGREP=y
1098CONFIG_PKILL=y
1099CONFIG_PIDOF=y
1100CONFIG_FEATURE_PIDOF_SINGLE=y
1101CONFIG_FEATURE_PIDOF_OMIT=y
1102# CONFIG_PMAP is not set
1103# CONFIG_POWERTOP is not set
1104# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set
1105CONFIG_PS=y
1106# CONFIG_FEATURE_PS_WIDE is not set
1107# CONFIG_FEATURE_PS_LONG is not set
1108CONFIG_FEATURE_PS_TIME=y
1109# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
1110# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
1111# CONFIG_PSTREE is not set
1112# CONFIG_PWDX is not set
1113# CONFIG_SMEMCAP is not set
1114# CONFIG_BB_SYSCTL is not set
1115# CONFIG_TOP is not set
1116# CONFIG_FEATURE_TOP_INTERACTIVE is not set
1117# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
1118# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
1119# CONFIG_FEATURE_TOP_SMP_CPU is not set
1120# CONFIG_FEATURE_TOP_DECIMALS is not set
1121# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
1122# CONFIG_FEATURE_TOPMEM is not set
1123CONFIG_UPTIME=y
1124# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
1125CONFIG_WATCH=y
1126
1127#
1128# Runit Utilities
1129#
1130# CONFIG_CHPST is not set
1131# CONFIG_SETUIDGID is not set
1132# CONFIG_ENVUIDGID is not set
1133# CONFIG_ENVDIR is not set
1134# CONFIG_SOFTLIMIT is not set
1135# CONFIG_RUNSV is not set
1136# CONFIG_RUNSVDIR is not set
1137# CONFIG_FEATURE_RUNSVDIR_LOG is not set
1138# CONFIG_SV is not set
1139CONFIG_SV_DEFAULT_SERVICE_DIR=""
1140# CONFIG_SVC is not set
1141# CONFIG_SVOK is not set
1142# CONFIG_SVLOGD is not set
1143# CONFIG_CHCON is not set
1144# CONFIG_GETENFORCE is not set
1145# CONFIG_GETSEBOOL is not set
1146# CONFIG_LOAD_POLICY is not set
1147# CONFIG_MATCHPATHCON is not set
1148# CONFIG_RUNCON is not set
1149# CONFIG_SELINUXENABLED is not set
1150# CONFIG_SESTATUS is not set
1151# CONFIG_SETENFORCE is not set
1152# CONFIG_SETFILES is not set
1153# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
1154# CONFIG_RESTORECON is not set
1155# CONFIG_SETSEBOOL is not set
1156
1157#
1158# Shells
1159#
1160CONFIG_SH_IS_ASH=y
1161# CONFIG_SH_IS_HUSH is not set
1162# CONFIG_SH_IS_NONE is not set
1163CONFIG_BASH_IS_ASH=y
1164# CONFIG_BASH_IS_HUSH is not set
1165# CONFIG_BASH_IS_NONE is not set
1166CONFIG_SHELL_ASH=y
1167CONFIG_ASH=y
1168# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set
1169CONFIG_ASH_INTERNAL_GLOB=y
1170CONFIG_ASH_BASH_COMPAT=y
1171# CONFIG_ASH_BASH_SOURCE_CURDIR is not set
1172CONFIG_ASH_BASH_NOT_FOUND_HOOK=y
1173CONFIG_ASH_JOB_CONTROL=y
1174CONFIG_ASH_ALIAS=y
1175CONFIG_ASH_RANDOM_SUPPORT=y
1176CONFIG_ASH_EXPAND_PRMT=y
1177# CONFIG_ASH_IDLE_TIMEOUT is not set
1178# CONFIG_ASH_MAIL is not set
1179CONFIG_ASH_ECHO=y
1180CONFIG_ASH_PRINTF=y
1181CONFIG_ASH_TEST=y
1182CONFIG_ASH_HELP=y
1183CONFIG_ASH_GETOPTS=y
1184CONFIG_ASH_CMDCMD=y
1185CONFIG_ASH_NOCONSOLE=y
1186CONFIG_ASH_GLOB_OPTIONS=y
1187# CONFIG_CTTYHACK is not set
1188# CONFIG_HUSH is not set
1189# CONFIG_SHELL_HUSH is not set
1190# CONFIG_HUSH_BASH_COMPAT is not set
1191# CONFIG_HUSH_BRACE_EXPANSION is not set
1192# CONFIG_HUSH_BASH_SOURCE_CURDIR is not set
1193# CONFIG_HUSH_LINENO_VAR is not set
1194# CONFIG_HUSH_INTERACTIVE is not set
1195# CONFIG_HUSH_SAVEHISTORY is not set
1196# CONFIG_HUSH_JOB is not set
1197# CONFIG_HUSH_TICK is not set
1198# CONFIG_HUSH_IF is not set
1199# CONFIG_HUSH_LOOPS is not set
1200# CONFIG_HUSH_CASE is not set
1201# CONFIG_HUSH_FUNCTIONS is not set
1202# CONFIG_HUSH_LOCAL is not set
1203# CONFIG_HUSH_RANDOM_SUPPORT is not set
1204# CONFIG_HUSH_MODE_X is not set
1205# CONFIG_HUSH_ECHO is not set
1206# CONFIG_HUSH_PRINTF is not set
1207# CONFIG_HUSH_TEST is not set
1208# CONFIG_HUSH_HELP is not set
1209# CONFIG_HUSH_EXPORT is not set
1210# CONFIG_HUSH_EXPORT_N is not set
1211# CONFIG_HUSH_READONLY is not set
1212# CONFIG_HUSH_KILL is not set
1213# CONFIG_HUSH_WAIT is not set
1214# CONFIG_HUSH_COMMAND is not set
1215# CONFIG_HUSH_TRAP is not set
1216# CONFIG_HUSH_TYPE is not set
1217# CONFIG_HUSH_TIMES is not set
1218# CONFIG_HUSH_READ is not set
1219# CONFIG_HUSH_SET is not set
1220# CONFIG_HUSH_UNSET is not set
1221# CONFIG_HUSH_ULIMIT is not set
1222# CONFIG_HUSH_UMASK is not set
1223# CONFIG_HUSH_GETOPTS is not set
1224# CONFIG_HUSH_MEMLEAK is not set
1225
1226#
1227# Options common to all shells
1228#
1229CONFIG_FEATURE_SH_MATH=y
1230CONFIG_FEATURE_SH_MATH_64=y
1231CONFIG_FEATURE_SH_MATH_BASE=y
1232CONFIG_FEATURE_SH_EXTRA_QUIET=y
1233CONFIG_FEATURE_SH_STANDALONE=y
1234CONFIG_FEATURE_SH_NOFORK=y
1235CONFIG_FEATURE_SH_READ_FRAC=y
1236CONFIG_FEATURE_SH_HISTFILESIZE=y
1237CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS=y
1238
1239#
1240# System Logging Utilities
1241#
1242# CONFIG_KLOGD is not set
1243# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
1244# CONFIG_LOGGER is not set
1245# CONFIG_LOGREAD is not set
1246# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1247# CONFIG_SYSLOGD is not set
1248# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1249# CONFIG_FEATURE_REMOTE_LOG is not set
1250# CONFIG_FEATURE_SYSLOGD_DUP is not set
1251# CONFIG_FEATURE_SYSLOGD_CFG is not set
1252# CONFIG_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS is not set
1253CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1254# CONFIG_FEATURE_IPC_SYSLOG is not set
1255CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1256# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/console-tools/reset.c b/console-tools/reset.c
index 655a5ef7a..74fe3cb50 100644
--- a/console-tools/reset.c
+++ b/console-tools/reset.c
@@ -14,7 +14,11 @@
14//config: This program is used to reset the terminal screen, if it 14//config: This program is used to reset the terminal screen, if it
15//config: gets messed up. 15//config: gets messed up.
16 16
17//applet:IF_RESET(APPLET_NOEXEC(reset, reset, BB_DIR_USR_BIN, BB_SUID_DROP, reset)) 17// NOTE: For WIN32 this applet is NOFORK so we can change the screen
18// buffer for the current process.
19
20//applet:IF_PLATFORM_MINGW32(IF_RESET(APPLET_NOFORK(reset, reset, BB_DIR_USR_BIN, BB_SUID_DROP, reset)))
21//applet:IF_PLATFORM_POSIX(IF_RESET(APPLET_NOEXEC(reset, reset, BB_DIR_USR_BIN, BB_SUID_DROP, reset)))
18 22
19//kbuild:lib-$(CONFIG_RESET) += reset.o 23//kbuild:lib-$(CONFIG_RESET) += reset.o
20 24
@@ -36,6 +40,7 @@ int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
36int reset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 40int reset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
37int reset_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 41int reset_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
38{ 42{
43#if !ENABLE_PLATFORM_MINGW32
39 static const char *const args[] ALIGN_PTR = { 44 static const char *const args[] ALIGN_PTR = {
40 "stty", "sane", NULL 45 "stty", "sane", NULL
41 }; 46 };
@@ -61,5 +66,14 @@ int reset_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
61 execvp("stty", (char**)args); 66 execvp("stty", (char**)args);
62#endif 67#endif
63 } 68 }
69#else
70 if (isatty(STDOUT_FILENO)) {
71 // "ESC [ m" -- Reset all display attributes
72 // "ESC [ ? 1049 l" -- Use normal screen buffer
73 // reset_screen -- Reset cursor and clear screen buffer
74 full_write1_str(ESC"[m" ESC"[?1049l");
75 reset_screen();
76 }
77#endif
64 return EXIT_SUCCESS; 78 return EXIT_SUCCESS;
65} 79}
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 8bb782781..e6b88acf5 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -59,8 +59,13 @@
59//usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]" 59//usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]"
60//usage: IF_FEATURE_DD_IBS_OBS("\n" 60//usage: IF_FEATURE_DD_IBS_OBS("\n"
61//usage: " [conv=notrunc|noerror|sync|fsync]\n" 61//usage: " [conv=notrunc|noerror|sync|fsync]\n"
62//usage: IF_NOT_PLATFORM_MINGW32(
62//usage: " [iflag=skip_bytes|count_bytes|fullblock|direct] [oflag=seek_bytes|append|direct]" 63//usage: " [iflag=skip_bytes|count_bytes|fullblock|direct] [oflag=seek_bytes|append|direct]"
63//usage: ) 64//usage: )
65//usage: IF_PLATFORM_MINGW32(
66//usage: " [iflag=skip_bytes|count_bytes|fullblock] [oflag=seek_bytes|append]"
67//usage: )
68//usage: )
64//usage:#define dd_full_usage "\n\n" 69//usage:#define dd_full_usage "\n\n"
65//usage: "Copy a file with converting and formatting\n" 70//usage: "Copy a file with converting and formatting\n"
66//usage: "\n if=FILE Read from FILE instead of stdin" 71//usage: "\n if=FILE Read from FILE instead of stdin"
@@ -84,8 +89,10 @@
84//usage: "\n iflag=skip_bytes skip=N is in bytes" 89//usage: "\n iflag=skip_bytes skip=N is in bytes"
85//usage: "\n iflag=count_bytes count=N is in bytes" 90//usage: "\n iflag=count_bytes count=N is in bytes"
86//usage: "\n oflag=seek_bytes seek=N is in bytes" 91//usage: "\n oflag=seek_bytes seek=N is in bytes"
92//usage: IF_NOT_PLATFORM_MINGW32(
87//usage: "\n iflag=direct O_DIRECT input" 93//usage: "\n iflag=direct O_DIRECT input"
88//usage: "\n oflag=direct O_DIRECT output" 94//usage: "\n oflag=direct O_DIRECT output"
95//usage: )
89//usage: "\n iflag=fullblock Read full blocks" 96//usage: "\n iflag=fullblock Read full blocks"
90//usage: "\n oflag=append Open output in append mode" 97//usage: "\n oflag=append Open output in append mode"
91//usage: ) 98//usage: )
@@ -94,6 +101,9 @@
94//usage: "\n status=none Suppress all output" 101//usage: "\n status=none Suppress all output"
95//usage: ) 102//usage: )
96//usage: "\n" 103//usage: "\n"
104//usage: IF_PLATFORM_MINGW32(
105//usage: "\nif=/dev/zero and if=/dev/urandom are supported"
106//usage: )
97//usage: "\nN may be suffixed by c (1), w (2), b (512), kB (1000), k (1024), MB, M, GB, G" 107//usage: "\nN may be suffixed by c (1), w (2), b (512), kB (1000), k (1024), MB, M, GB, G"
98//usage: 108//usage:
99//usage:#define dd_example_usage 109//usage:#define dd_example_usage
@@ -104,6 +114,10 @@
104#include "libbb.h" 114#include "libbb.h"
105#include "common_bufsiz.h" 115#include "common_bufsiz.h"
106 116
117#if ENABLE_PLATFORM_MINGW32
118# undef O_DIRECT
119#endif
120
107/* This is a NOEXEC applet. Be very careful! */ 121/* This is a NOEXEC applet. Be very careful! */
108 122
109 123
@@ -141,13 +155,13 @@ enum {
141 FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, 155 FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS,
142 FLAG_COUNT_BYTES = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, 156 FLAG_COUNT_BYTES = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS,
143 FLAG_FULLBLOCK = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, 157 FLAG_FULLBLOCK = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS,
144 FLAG_IDIRECT = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS, 158 FLAG_IDIRECT = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS * ENABLE_PLATFORM_POSIX,
145 /* end of input flags */ 159 /* end of input flags */
146 /* start of output flags */ 160 /* start of output flags */
147 FLAG_OFLAG_SHIFT = 9, 161 FLAG_OFLAG_SHIFT = 9,
148 FLAG_SEEK_BYTES = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS, 162 FLAG_SEEK_BYTES = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS,
149 FLAG_APPEND = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS, 163 FLAG_APPEND = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS,
150 FLAG_ODIRECT = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS, 164 FLAG_ODIRECT = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS * ENABLE_PLATFORM_POSIX,
151 /* end of output flags */ 165 /* end of output flags */
152 FLAG_TWOBUFS = (1 << 12) * ENABLE_FEATURE_DD_IBS_OBS, 166 FLAG_TWOBUFS = (1 << 12) * ENABLE_FEATURE_DD_IBS_OBS,
153 FLAG_COUNT = 1 << 13, 167 FLAG_COUNT = 1 << 13,
@@ -220,7 +234,9 @@ static ssize_t dd_read(void *ibuf, size_t ibs)
220 ssize_t n; 234 ssize_t n;
221 235
222#if ENABLE_FEATURE_DD_IBS_OBS 236#if ENABLE_FEATURE_DD_IBS_OBS
237# if !ENABLE_PLATFORM_MINGW32
223 read_again: 238 read_again:
239# endif
224 if (G.flags & FLAG_FULLBLOCK) 240 if (G.flags & FLAG_FULLBLOCK)
225 n = full_read(ifd, ibuf, ibs); 241 n = full_read(ifd, ibuf, ibs);
226 else 242 else
@@ -240,7 +256,9 @@ static bool write_and_stats(const void *buf, size_t len, size_t obs,
240{ 256{
241 ssize_t n; 257 ssize_t n;
242 258
259#if !ENABLE_PLATFORM_MINGW32
243 IF_FEATURE_DD_IBS_OBS(write_again:) 260 IF_FEATURE_DD_IBS_OBS(write_again:)
261#endif
244 n = full_write(ofd, buf, len); 262 n = full_write(ofd, buf, len);
245#if ENABLE_FEATURE_DD_IBS_OBS 263#if ENABLE_FEATURE_DD_IBS_OBS
246# ifdef O_DIRECT 264# ifdef O_DIRECT
@@ -307,12 +325,25 @@ static int parse_comma_flags(char *val, const char *words, const char *error_in)
307 325
308static void *alloc_buf(size_t size) 326static void *alloc_buf(size_t size)
309{ 327{
328#if !ENABLE_PLATFORM_MINGW32
310 /* Important for "{i,o}flag=direct" - buffers must be page aligned */ 329 /* Important for "{i,o}flag=direct" - buffers must be page aligned */
311 if (size >= bb_getpagesize()) 330 if (size >= bb_getpagesize())
312 return xmmap_anon(size); 331 return xmmap_anon(size);
332#endif
313 return xmalloc(size); 333 return xmalloc(size);
314} 334}
315 335
336#if ENABLE_PLATFORM_MINGW32
337// Does 'path' refer to a physical drive in the win32 device namespace?
338static int is_drive_path(const char *path)
339{
340 char *s = auto_string(strdup(path));
341
342 bs_to_slash(s);
343 return strncasecmp(s, "//./PhysicalDrive", 17) == 0;
344}
345#endif
346
316int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 347int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
317int dd_main(int argc UNUSED_PARAM, char **argv) 348int dd_main(int argc UNUSED_PARAM, char **argv)
318{ 349{
@@ -326,9 +357,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
326 static const char conv_words[] ALIGN1 = 357 static const char conv_words[] ALIGN1 =
327 "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; 358 "notrunc\0""sync\0""noerror\0""fsync\0""swab\0";
328 static const char iflag_words[] ALIGN1 = 359 static const char iflag_words[] ALIGN1 =
329 "skip_bytes\0""count_bytes\0""fullblock\0""direct\0"; 360 "skip_bytes\0""count_bytes\0""fullblock\0"IF_PLATFORM_POSIX("direct\0");
330 static const char oflag_words[] ALIGN1 = 361 static const char oflag_words[] ALIGN1 =
331 "seek_bytes\0append\0""direct\0"; 362 "seek_bytes\0append\0"IF_PLATFORM_POSIX("direct\0");
332#endif 363#endif
333#if ENABLE_FEATURE_DD_STATUS 364#if ENABLE_FEATURE_DD_STATUS
334 static const char status_words[] ALIGN1 = 365 static const char status_words[] ALIGN1 =
@@ -429,11 +460,11 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
429#if ENABLE_FEATURE_DD_IBS_OBS 460#if ENABLE_FEATURE_DD_IBS_OBS
430 if (what == OP_ibs) { 461 if (what == OP_ibs) {
431 /* Must fit into positive ssize_t */ 462 /* Must fit into positive ssize_t */
432 ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes); 463 ibs = xatoul_range_sfx(val, 1, ULONG_MAX/2, cwbkMG_suffixes);
433 /*continue;*/ 464 /*continue;*/
434 } 465 }
435 if (what == OP_obs) { 466 if (what == OP_obs) {
436 obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes); 467 obs = xatoul_range_sfx(val, 1, ULONG_MAX/2, cwbkMG_suffixes);
437 /*continue;*/ 468 /*continue;*/
438 } 469 }
439 if (what == OP_conv) { 470 if (what == OP_conv) {
@@ -450,7 +481,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
450 } 481 }
451#endif 482#endif
452 if (what == OP_bs) { 483 if (what == OP_bs) {
453 ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes); 484 ibs = xatoul_range_sfx(val, 1, ULONG_MAX/2, cwbkMG_suffixes);
454 obs = ibs; 485 obs = ibs;
455 /*continue;*/ 486 /*continue;*/
456 } 487 }
@@ -515,7 +546,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
515# endif 546# endif
516 } 547 }
517#endif 548#endif
518 xmove_fd(xopen(infile, iflag), ifd); 549 xmove_fd(MINGW_SPECIAL(xopen)(infile, iflag), ifd);
550#if ENABLE_PLATFORM_MINGW32
551 update_special_fd(get_dev_type(infile), ifd);
552#endif
519 } else { 553 } else {
520 infile = bb_msg_standard_input; 554 infile = bb_msg_standard_input;
521 } 555 }
@@ -535,8 +569,35 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
535# endif 569# endif
536 } 570 }
537#endif 571#endif
572#if ENABLE_PLATFORM_MINGW32
573 if (is_drive_path(outfile)) {
574 // Turn off options not supported by Windows device files.
575 oflag &= ~(O_CREAT | O_TRUNC);
576 }
577#endif
538 xmove_fd(xopen(outfile, oflag), ofd); 578 xmove_fd(xopen(outfile, oflag), ofd);
539 579
580#if ENABLE_PLATFORM_MINGW32
581 {
582 off_t len = (off_t)seek * ((G.flags & FLAG_SEEK_BYTES) ? 1 : obs);
583 struct stat st;
584 int ret = fstat(ofd, &st);
585
586 if (ret == 0 && !(G.flags & FLAG_APPEND) && len > st.st_size)
587 make_sparse(ofd, st.st_size, len);
588
589 if (seek && !(G.flags & FLAG_NOTRUNC)) {
590 if (ftruncate(ofd, len) < 0) {
591 if (ret < 0
592 || S_ISREG(st.st_mode)
593 || S_ISDIR(st.st_mode)
594 ) {
595 goto die_outfile;
596 }
597 }
598 }
599 }
600#else
540 if (seek && !(G.flags & FLAG_NOTRUNC)) { 601 if (seek && !(G.flags & FLAG_NOTRUNC)) {
541 size_t blocksz = (G.flags & FLAG_SEEK_BYTES) ? 1 : obs; 602 size_t blocksz = (G.flags & FLAG_SEEK_BYTES) ? 1 : obs;
542 if (ftruncate(ofd, seek * blocksz) < 0) { 603 if (ftruncate(ofd, seek * blocksz) < 0) {
@@ -550,6 +611,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
550 } 611 }
551 } 612 }
552 } 613 }
614#endif
553 } else { 615 } else {
554 outfile = bb_msg_standard_output; 616 outfile = bb_msg_standard_output;
555 } 617 }
diff --git a/coreutils/du.c b/coreutils/du.c
index 4652b6300..338998fc9 100644
--- a/coreutils/du.c
+++ b/coreutils/du.c
@@ -137,7 +137,7 @@ static void print(unsigned long long size, const char *filename)
137 size >>= 10; 137 size >>= 10;
138 } 138 }
139 } 139 }
140 printf("%llu\t%s\n", size, filename); 140 printf("%"LL_FMT"u\t%s\n", size, filename);
141#endif 141#endif
142} 142}
143 143
diff --git a/coreutils/expr.c b/coreutils/expr.c
index 47ebe2fca..3f7e21871 100644
--- a/coreutils/expr.c
+++ b/coreutils/expr.c
@@ -84,7 +84,7 @@
84#if ENABLE_EXPR_MATH_SUPPORT_64 84#if ENABLE_EXPR_MATH_SUPPORT_64
85typedef int64_t arith_t; 85typedef int64_t arith_t;
86 86
87#define PF_REZ "ll" 87#define PF_REZ LL_FMT
88#define PF_REZ_TYPE (long long) 88#define PF_REZ_TYPE (long long)
89#define STRTOL(s, e, b) strtoll(s, e, b) 89#define STRTOL(s, e, b) strtoll(s, e, b)
90#else 90#else
diff --git a/coreutils/factor.c b/coreutils/factor.c
index 90e9ed761..9de5ea8eb 100644
--- a/coreutils/factor.c
+++ b/coreutils/factor.c
@@ -124,7 +124,7 @@ static NOINLINE void print_w(wide_t n)
124{ 124{
125 unsigned rep = square_count; 125 unsigned rep = square_count;
126 do 126 do
127 printf(" %llu", n); 127 printf(" %"LL_FMT"u", n);
128 while (--rep != 0); 128 while (--rep != 0);
129} 129}
130static NOINLINE void print_h(half_t n) 130static NOINLINE void print_h(half_t n)
@@ -226,7 +226,7 @@ static void factorize_numstr(const char *numstr)
226 N = bb_strtoull(numstr, NULL, 10); 226 N = bb_strtoull(numstr, NULL, 10);
227 if (errno) 227 if (errno)
228 bb_show_usage(); 228 bb_show_usage();
229 printf("%llu:", N); 229 printf("%"LL_FMT"u:", N);
230 square_count = 1; 230 square_count = 1;
231 factorize(N); 231 factorize(N);
232} 232}
diff --git a/coreutils/id.c b/coreutils/id.c
index a4f178bda..0e1286294 100644
--- a/coreutils/id.c
+++ b/coreutils/id.c
@@ -112,6 +112,7 @@ static int print_user(uid_t id, const char *prefix)
112 return print_common(id, uid2uname(id), prefix); 112 return print_common(id, uid2uname(id), prefix);
113} 113}
114 114
115#if !ENABLE_PLATFORM_MINGW32
115/* On error set *n < 0 and return >= 0 116/* On error set *n < 0 and return >= 0
116 * If *n is too small, update it and return < 0 117 * If *n is too small, update it and return < 0
117 * (ok to trash groups[] in both cases) 118 * (ok to trash groups[] in both cases)
@@ -142,6 +143,7 @@ static int get_groups(const char *username, gid_t rgid, gid_t *groups, int *n)
142 /* if *n >= 0, return -1 (got new *n), else return 0 (error): */ 143 /* if *n >= 0, return -1 (got new *n), else return 0 (error): */
143 return -(*n >= 0); 144 return -(*n >= 0);
144} 145}
146#endif
145 147
146int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 148int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
147int id_main(int argc UNUSED_PARAM, char **argv) 149int id_main(int argc UNUSED_PARAM, char **argv)
@@ -184,16 +186,26 @@ int id_main(int argc UNUSED_PARAM, char **argv)
184 euid = ruid = p->pw_uid; 186 euid = ruid = p->pw_uid;
185 egid = rgid = p->pw_gid; 187 egid = rgid = p->pw_gid;
186 } else { 188 } else {
189#if ENABLE_PLATFORM_MINGW32
190 // We don't distinguish real/effective ids on Windows.
191 euid = ruid = getuid();
192 egid = rgid = getegid();
193#else
187 egid = getegid(); 194 egid = getegid();
188 rgid = getgid(); 195 rgid = getgid();
189 euid = geteuid(); 196 euid = geteuid();
190 ruid = getuid(); 197 ruid = getuid();
198#endif
191 } 199 }
192 /* JUST_ALL_GROUPS ignores -r PRINT_REAL flag even if man page for */ 200 /* JUST_ALL_GROUPS ignores -r PRINT_REAL flag even if man page for */
193 /* id says: print the real ID instead of the effective ID, with -ugG */ 201 /* id says: print the real ID instead of the effective ID, with -ugG */
194 /* in fact in this case egid is always printed if egid != rgid */ 202 /* in fact in this case egid is always printed if egid != rgid */
195 if (!opt || (opt & JUST_ALL_GROUPS)) { 203 if (!opt || (opt & JUST_ALL_GROUPS)) {
204#if ENABLE_PLATFORM_MINGW32
205 gid_t groups[1];
206#else
196 gid_t *groups; 207 gid_t *groups;
208#endif
197 int n; 209 int n;
198 210
199 if (!opt) { 211 if (!opt) {
@@ -210,6 +222,11 @@ int id_main(int argc UNUSED_PARAM, char **argv)
210 if (egid != rgid) 222 if (egid != rgid)
211 status |= print_group(egid, " "); 223 status |= print_group(egid, " ");
212 } 224 }
225#if ENABLE_PLATFORM_MINGW32
226 // We only admit to having one group id on Windows.
227 n = 1;
228 groups[0] = rgid;
229#else
213 /* We are supplying largish buffer, trying 230 /* We are supplying largish buffer, trying
214 * to not run get_groups() twice. That might be slow 231 * to not run get_groups() twice. That might be slow
215 * ("user database in remote SQL server" case) */ 232 * ("user database in remote SQL server" case) */
@@ -220,6 +237,7 @@ int id_main(int argc UNUSED_PARAM, char **argv)
220 groups = xrealloc(groups, n * sizeof(groups[0])); 237 groups = xrealloc(groups, n * sizeof(groups[0]));
221 get_groups(username, rgid, groups, &n); 238 get_groups(username, rgid, groups, &n);
222 } 239 }
240#endif
223 if (n > 0) { 241 if (n > 0) {
224 /* Print the list */ 242 /* Print the list */
225 prefix = " groups="; 243 prefix = " groups=";
@@ -234,7 +252,7 @@ int id_main(int argc UNUSED_PARAM, char **argv)
234 bb_simple_error_msg_and_die("can't get groups"); 252 bb_simple_error_msg_and_die("can't get groups");
235 return EXIT_FAILURE; 253 return EXIT_FAILURE;
236 } 254 }
237 if (ENABLE_FEATURE_CLEAN_UP) 255 if (ENABLE_FEATURE_CLEAN_UP && !ENABLE_PLATFORM_MINGW32)
238 free(groups); 256 free(groups);
239#if ENABLE_SELINUX 257#if ENABLE_SELINUX
240 if (is_selinux_enabled()) { 258 if (is_selinux_enabled()) {
diff --git a/coreutils/ls.c b/coreutils/ls.c
index cc809b797..5d2e96a1e 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -109,8 +109,11 @@
109//usage:#define ls_full_usage "\n\n" 109//usage:#define ls_full_usage "\n\n"
110//usage: "List directory contents\n" 110//usage: "List directory contents\n"
111//usage: "\n -1 One column output" 111//usage: "\n -1 One column output"
112//usage: "\n -a Include names starting with ." 112//usage: "\n -a Include names starting with ." IF_PLATFORM_MINGW32(" and hidden files")
113//usage: "\n -A Like -a, but exclude . and .." 113//usage: "\n -A Like -a, but exclude . and .."
114//usage: IF_PLATFORM_MINGW32(
115//usage: "\n -aa,-AA Like -a,-A but omit hidden system files"
116//usage: )
114////usage: "\n -C List by columns" - don't show, this is a default anyway 117////usage: "\n -C List by columns" - don't show, this is a default anyway
115//usage: "\n -x List by lines" 118//usage: "\n -x List by lines"
116//usage: "\n -d List directory names, not contents" 119//usage: "\n -d List directory names, not contents"
@@ -316,6 +319,9 @@ struct dnode {
316 int dn_rdev_min; 319 int dn_rdev_min;
317// dev_t dn_dev; 320// dev_t dn_dev;
318// blksize_t dn_blksize; 321// blksize_t dn_blksize;
322#if ENABLE_PLATFORM_MINGW32
323 DWORD dn_attr;
324#endif
319}; 325};
320 326
321struct globals { 327struct globals {
@@ -337,6 +343,10 @@ struct globals {
337 /* Do time() just once. Saves one syscall per file for "ls -l" */ 343 /* Do time() just once. Saves one syscall per file for "ls -l" */
338 time_t current_time_t; 344 time_t current_time_t;
339#endif 345#endif
346#if ENABLE_PLATFORM_MINGW32
347 int a_count, A_count;
348# define HIDSYS (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)
349#endif
340} FIX_ALIASING; 350} FIX_ALIASING;
341#define G (*(struct globals*)bb_common_bufsiz1) 351#define G (*(struct globals*)bb_common_bufsiz1)
342#define INIT_G() do { \ 352#define INIT_G() do { \
@@ -497,7 +507,11 @@ static NOINLINE unsigned display_single(const struct dnode *dn)
497 lpath = xmalloc_readlink_or_warn(dn->fullname); 507 lpath = xmalloc_readlink_or_warn(dn->fullname);
498 508
499 if (opt & OPT_i) /* show inode# */ 509 if (opt & OPT_i) /* show inode# */
500 column += printf("%7llu ", (long long) dn->dn_ino); 510#if !ENABLE_FEATURE_EXTRA_FILE_DATA
511 column += printf("%7"LL_FMT"u ", (long long) dn->dn_ino);
512#else
513 column += printf("%19"LL_FMT"u ", (long long) dn->dn_ino);
514#endif
501 if (opt & OPT_s) { /* show allocated blocks */ 515 if (opt & OPT_s) { /* show allocated blocks */
502 if (opt & OPT_h) { 516 if (opt & OPT_h) {
503 column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ", 517 column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ",
@@ -659,7 +673,11 @@ static void display_files(struct dnode **dn, unsigned nfiles)
659 } 673 }
660 column_width += 2 674 column_width += 2
661 + ((option_mask32 & OPT_Z) ? 33 : 0) /* context width */ 675 + ((option_mask32 & OPT_Z) ? 33 : 0) /* context width */
676#if !ENABLE_FEATURE_EXTRA_FILE_DATA
662 + ((option_mask32 & OPT_i) ? 8 : 0) /* inode# width */ 677 + ((option_mask32 & OPT_i) ? 8 : 0) /* inode# width */
678#else
679 + ((option_mask32 & OPT_i) ? 20 : 0) /* inode# width */
680#endif
663 + ((option_mask32 & OPT_s) ? 5 : 0) /* "alloc block" width */ 681 + ((option_mask32 & OPT_s) ? 5 : 0) /* "alloc block" width */
664 ; 682 ;
665 ncols = (unsigned)G_terminal_width / column_width; 683 ncols = (unsigned)G_terminal_width / column_width;
@@ -740,6 +758,9 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f
740 758
741 /* cur->dstat = statbuf: */ 759 /* cur->dstat = statbuf: */
742 cur->dn_mode = statbuf.st_mode ; 760 cur->dn_mode = statbuf.st_mode ;
761#if ENABLE_PLATFORM_MINGW32
762 cur->dn_attr = statbuf.st_attr ;
763#endif
743 cur->dn_size = statbuf.st_size ; 764 cur->dn_size = statbuf.st_size ;
744#if ENABLE_FEATURE_LS_TIMESTAMPS || ENABLE_FEATURE_LS_SORTFILES 765#if ENABLE_FEATURE_LS_TIMESTAMPS || ENABLE_FEATURE_LS_SORTFILES
745 cur->dn_time = statbuf.st_mtime ; 766 cur->dn_time = statbuf.st_mtime ;
@@ -920,6 +941,15 @@ static void sort_and_display_files(struct dnode **dn, unsigned nfiles)
920# define sort_and_display_files(dn, nfiles) display_files(dn, nfiles) 941# define sort_and_display_files(dn, nfiles) display_files(dn, nfiles)
921#endif 942#endif
922 943
944#if ENABLE_PLATFORM_MINGW32
945static int hide_file(DWORD attr)
946{
947 return
948 ((attr & FILE_ATTRIBUTE_HIDDEN) && !(option_mask32 & (OPT_a|OPT_A))) ||
949 (((attr & HIDSYS) == HIDSYS) && MAX(G.a_count, G.A_count) > 1);
950}
951#endif
952
923/* Returns NULL-terminated malloced vector of pointers (or NULL) */ 953/* Returns NULL-terminated malloced vector of pointers (or NULL) */
924static struct dnode **scan_one_dir(const char *path, unsigned *nfiles_p) 954static struct dnode **scan_one_dir(const char *path, unsigned *nfiles_p)
925{ 955{
@@ -927,6 +957,9 @@ static struct dnode **scan_one_dir(const char *path, unsigned *nfiles_p)
927 struct dirent *entry; 957 struct dirent *entry;
928 DIR *dir; 958 DIR *dir;
929 unsigned i, nfiles; 959 unsigned i, nfiles;
960#if ENABLE_PLATFORM_MINGW32
961 struct stat statbuf;
962#endif
930 963
931 *nfiles_p = 0; 964 *nfiles_p = 0;
932 dir = warn_opendir(path); 965 dir = warn_opendir(path);
@@ -949,9 +982,29 @@ static struct dnode **scan_one_dir(const char *path, unsigned *nfiles_p)
949 continue; /* if only -A, skip . and .. but show other dotfiles */ 982 continue; /* if only -A, skip . and .. but show other dotfiles */
950 } 983 }
951 } 984 }
985#if ENABLE_PLATFORM_MINGW32
986 if (has_dos_drive_prefix(path) && path[2] == '\0')
987 fullname = xasprintf("%s%s", path, entry->d_name);
988 else
989#endif
952 fullname = concat_path_file(path, entry->d_name); 990 fullname = concat_path_file(path, entry->d_name);
991#if ENABLE_PLATFORM_MINGW32
992 /* When showing link targets we must first check the
993 * attributes of the link itself to see if it's hidden. */
994 if ((option_mask32 & OPT_L) && !lstat(fullname, &statbuf)) {
995 if (hide_file(statbuf.st_attr)) {
996 free(fullname);
997 continue;
998 }
999 }
1000#endif
953 cur = my_stat(fullname, bb_basename(fullname), 0); 1001 cur = my_stat(fullname, bb_basename(fullname), 0);
1002#if !ENABLE_PLATFORM_MINGW32
954 if (!cur) { 1003 if (!cur) {
1004#else
1005 if (!cur || hide_file(cur->dn_attr)) {
1006 /* skip invalid or hidden files */
1007#endif
955 free(fullname); 1008 free(fullname);
956 continue; 1009 continue;
957 } 1010 }
@@ -1060,6 +1113,18 @@ static void scan_and_display_dirs_recur(struct dnode **dn, int first)
1060 } 1113 }
1061} 1114}
1062 1115
1116#if ENABLE_PLATFORM_MINGW32
1117static char *fix_backslash(char *p)
1118{
1119 const char *flag = getenv("BB_FIX_BACKSLASH");
1120 int value = flag ? atoi(flag) : 0;
1121
1122 if (value == 1)
1123 bs_to_slash(p);
1124 return p;
1125}
1126#endif
1127
1063 1128
1064int ls_main(int argc UNUSED_PARAM, char **argv) 1129int ls_main(int argc UNUSED_PARAM, char **argv)
1065{ /* ^^^^^^^^^^^^^^^^^ note: if FTPD, argc can be wrong, see ftpd.c */ 1130{ /* ^^^^^^^^^^^^^^^^^ note: if FTPD, argc can be wrong, see ftpd.c */
@@ -1129,9 +1194,11 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1129 IF_FEATURE_LS_TIMESTAMPS(":c-u:u-c") /* mtime/atime */ 1194 IF_FEATURE_LS_TIMESTAMPS(":c-u:u-c") /* mtime/atime */
1130 /* -w NUM: */ 1195 /* -w NUM: */
1131 IF_FEATURE_LS_WIDTH(":w+") 1196 IF_FEATURE_LS_WIDTH(":w+")
1197 IF_PLATFORM_MINGW32(":aa:AA")
1132 , ls_longopts 1198 , ls_longopts
1133 IF_FEATURE_LS_WIDTH(, /*-T*/ NULL, /*-w*/ &G_terminal_width) 1199 IF_FEATURE_LS_WIDTH(, /*-T*/ NULL, /*-w*/ &G_terminal_width)
1134 IF_FEATURE_LS_COLOR(, &color_opt) 1200 IF_FEATURE_LS_COLOR(, &color_opt)
1201 IF_PLATFORM_MINGW32(, &G.a_count, &G.A_count)
1135 ); 1202 );
1136#if 0 /* option bits debug */ 1203#if 0 /* option bits debug */
1137 bb_error_msg("opt:0x%08x l:%x H:%x color:%x dirs:%x", opt, OPT_l, OPT_H, OPT_color, OPT_dirs_first); 1204 bb_error_msg("opt:0x%08x l:%x H:%x color:%x dirs:%x", opt, OPT_l, OPT_H, OPT_color, OPT_dirs_first);
@@ -1155,6 +1222,11 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1155 /* set G_show_color = 1/0 */ 1222 /* set G_show_color = 1/0 */
1156 if (ENABLE_FEATURE_LS_COLOR_IS_DEFAULT && !is_TERM_dumb()) { 1223 if (ENABLE_FEATURE_LS_COLOR_IS_DEFAULT && !is_TERM_dumb()) {
1157 char *p = getenv("LS_COLORS"); 1224 char *p = getenv("LS_COLORS");
1225# if ENABLE_PLATFORM_MINGW32
1226 /* No colour if unset or empty: https://no-color.org */
1227 char *no_c = getenv("NO_COLOR");
1228 if (!no_c || no_c[0] == '\0')
1229# endif
1158 /* LS_COLORS is unset, or (not empty && not "none") ? */ 1230 /* LS_COLORS is unset, or (not empty && not "none") ? */
1159 if (!p || (p[0] && strcmp(p, "none") != 0)) { 1231 if (!p || (p[0] && strcmp(p, "none") != 0)) {
1160 if (isatty(STDOUT_FILENO)) { 1232 if (isatty(STDOUT_FILENO)) {
@@ -1204,6 +1276,12 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1204 option_mask32 |= OPT_dirs_first; 1276 option_mask32 |= OPT_dirs_first;
1205 } 1277 }
1206 1278
1279#if ENABLE_FEATURE_EXTRA_FILE_DATA
1280 /* Enable accurate link counts for directories */
1281 if (opt & OPT_l)
1282 count_subdirs(NULL);
1283#endif
1284
1207 argv += optind; 1285 argv += optind;
1208 if (!argv[0]) 1286 if (!argv[0])
1209 *--argv = (char*)"."; 1287 *--argv = (char*)".";
@@ -1215,6 +1293,9 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1215 dn = NULL; 1293 dn = NULL;
1216 nfiles = 0; 1294 nfiles = 0;
1217 do { 1295 do {
1296#if ENABLE_PLATFORM_MINGW32
1297 *argv = fix_backslash(*argv);
1298#endif
1218 cur = my_stat(*argv, *argv, 1299 cur = my_stat(*argv, *argv,
1219 /* follow links on command line unless -l, -i, -s or -F: */ 1300 /* follow links on command line unless -l, -i, -s or -F: */
1220 !(option_mask32 & (OPT_l|OPT_i|OPT_s|OPT_F)) 1301 !(option_mask32 & (OPT_l|OPT_i|OPT_s|OPT_F))
diff --git a/coreutils/nproc.c b/coreutils/nproc.c
index df63bf57a..44408b5f5 100644
--- a/coreutils/nproc.c
+++ b/coreutils/nproc.c
@@ -28,6 +28,9 @@
28int nproc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 28int nproc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
29int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 29int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
30{ 30{
31#if ENABLE_PLATFORM_MINGW32
32 DWORD_PTR affinity, process_affinity, system_affinity;
33#endif
31 int count = 0; 34 int count = 0;
32#if ENABLE_LONG_OPTS 35#if ENABLE_LONG_OPTS
33 int ignore = 0; 36 int ignore = 0;
@@ -36,7 +39,10 @@ int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
36 "all\0" No_argument "\xff" 39 "all\0" No_argument "\xff"
37 , &ignore 40 , &ignore
38 ); 41 );
42#endif
39 43
44#if !ENABLE_PLATFORM_MINGW32
45#if ENABLE_LONG_OPTS
40 if (opts & (1 << 1)) { 46 if (opts & (1 << 1)) {
41 DIR *cpusd = opendir("/sys/devices/system/cpu"); 47 DIR *cpusd = opendir("/sys/devices/system/cpu");
42 if (cpusd) { 48 if (cpusd) {
@@ -61,6 +67,17 @@ int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
61 } 67 }
62 IF_FEATURE_CLEAN_UP(free(mask);) 68 IF_FEATURE_CLEAN_UP(free(mask);)
63 } 69 }
70#else /* ENABLE_PLATFORM_MINGW32 */
71 if (GetProcessAffinityMask(GetCurrentProcess(), &process_affinity,
72 &system_affinity)) {
73 affinity = IF_LONG_OPTS((opts & (1 << 1)) ? system_affinity :)
74 process_affinity;
75 while (affinity) {
76 count += affinity & 1;
77 affinity >>= 1;
78 }
79 }
80#endif /* ENABLE_PLATFORM_MINGW32 */
64 81
65 IF_LONG_OPTS(count -= ignore;) 82 IF_LONG_OPTS(count -= ignore;)
66 if (count <= 0) 83 if (count <= 0)
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c
index e886a4ed2..641d93503 100644
--- a/coreutils/od_bloaty.c
+++ b/coreutils/od_bloaty.c
@@ -110,6 +110,13 @@ typedef long long llong;
110# define LDBL_DIG DBL_DIG 110# define LDBL_DIG DBL_DIG
111#endif 111#endif
112 112
113#if ENABLE_PLATFORM_MINGW32
114/* symbol conflict */
115#define CHAR SIZE_CHAR
116#define SHORT SIZE_SHORT
117#define LONG SIZE_LONG
118#define INT SIZE_INT
119#endif
113enum size_spec { 120enum size_spec {
114 NO_SIZE, 121 NO_SIZE,
115 CHAR, 122 CHAR,
diff --git a/coreutils/printf.c b/coreutils/printf.c
index 4edcfa9b5..379c00cc6 100644
--- a/coreutils/printf.c
+++ b/coreutils/printf.c
@@ -152,6 +152,71 @@ static double my_xstrtod(const char *arg)
152 return result; 152 return result;
153} 153}
154 154
155#if ENABLE_PLATFORM_MINGW32
156static int buflen = 0;
157static int bufmax = 0;
158static char *buffer = NULL;
159
160static void my_flush(void)
161{
162 if (buffer)
163 full_write(STDOUT_FILENO, buffer, buflen);
164 free(buffer);
165 buffer = NULL;
166 buflen = bufmax = 0;
167}
168
169static void copy_to_buffer(const char *str, int len)
170{
171 char *newbuf;
172
173 if (buflen + len >= bufmax) {
174 bufmax += 256 + len;
175 if ((newbuf = realloc(buffer, bufmax)) == NULL) {
176 my_flush();
177 return;
178 }
179 buffer = newbuf;
180 }
181 memcpy(buffer + buflen, str, len);
182 buflen += len;
183
184 if (buflen > 40 && buffer[buflen-1] == '\n')
185 my_flush();
186}
187
188static int my_putchar(int ch)
189{
190 char str[1] = { (char)ch };
191 copy_to_buffer(str, 1);
192 return ch;
193}
194
195static int my_printf(const char *format, ...)
196{
197 va_list list;
198 char *str;
199 int len;
200
201 va_start(list, format);
202 len = vasprintf(&str, format, list);
203 va_end(list);
204
205 if (len >= 0) {
206 copy_to_buffer(str, len);
207 free(str);
208 }
209 return len;
210}
211
212#undef bb_putchar
213#undef putchar
214#undef printf
215#define bb_putchar(c) my_putchar(c)
216#define putchar(c) my_putchar(c)
217#define printf(...) my_printf(__VA_ARGS__)
218#endif
219
155/* Handles %b; return 1 if output is to be short-circuited by \c */ 220/* Handles %b; return 1 if output is to be short-circuited by \c */
156static int print_esc_string(const char *str) 221static int print_esc_string(const char *str)
157{ 222{
@@ -444,6 +509,9 @@ int printf_main(int argc UNUSED_PARAM, char **argv)
444 do { 509 do {
445 argv = argv2; 510 argv = argv2;
446 argv2 = print_formatted(format, argv, &conv_err); 511 argv2 = print_formatted(format, argv, &conv_err);
512#if ENABLE_PLATFORM_MINGW32
513 my_flush();
514#endif
447 } while (argv2 > argv && *argv2); 515 } while (argv2 > argv && *argv2);
448 516
449 /* coreutils compat (bash doesn't do this): 517 /* coreutils compat (bash doesn't do this):
diff --git a/coreutils/shred.c b/coreutils/shred.c
index 7c0be612a..9e53b4820 100644
--- a/coreutils/shred.c
+++ b/coreutils/shred.c
@@ -60,9 +60,9 @@ int shred_main(int argc UNUSED_PARAM, char **argv)
60 opt = getopt32(argv, "^" "fuzn:+vxs:" "\0" "-1"/*min 1 arg*/, &num_iter, &opt_s); 60 opt = getopt32(argv, "^" "fuzn:+vxs:" "\0" "-1"/*min 1 arg*/, &num_iter, &opt_s);
61 argv += optind; 61 argv += optind;
62 62
63 zero_fd = xopen("/dev/zero", O_RDONLY); 63 zero_fd = MINGW_SPECIAL(xopen)("/dev/zero", O_RDONLY);
64 if (num_iter != 0) 64 if (num_iter != 0)
65 rand_fd = xopen("/dev/urandom", O_RDONLY); 65 rand_fd = MINGW_SPECIAL(xopen)("/dev/urandom", O_RDONLY);
66 66
67 for (;;) { 67 for (;;) {
68 struct stat sb; 68 struct stat sb;
@@ -102,8 +102,14 @@ int shred_main(int argc UNUSED_PARAM, char **argv)
102 } 102 }
103 if (opt & OPT_u) { 103 if (opt & OPT_u) {
104 ftruncate(fd, 0); 104 ftruncate(fd, 0);
105#if ENABLE_PLATFORM_MINGW32
106 xclose(fd);
107#endif
105 xunlink(fname); 108 xunlink(fname);
106 } 109 }
110#if ENABLE_PLATFORM_MINGW32
111 else
112#endif
107 xclose(fd); 113 xclose(fd);
108 } 114 }
109 115
diff --git a/coreutils/shuf.c b/coreutils/shuf.c
index 0d23382a2..bd3f6840c 100644
--- a/coreutils/shuf.c
+++ b/coreutils/shuf.c
@@ -212,7 +212,7 @@ int shuf_main(int argc, char **argv)
212 printf("%.*s%0*llu%c", pfx_len, pfx, padding_width, lo + (uintptr_t)lines[i], eol); 212 printf("%.*s%0*llu%c", pfx_len, pfx, padding_width, lo + (uintptr_t)lines[i], eol);
213 else 213 else
214#endif 214#endif
215 printf("%llu%c", lo + (uintptr_t)lines[i], eol); 215 printf("%"LL_FMT"u%c", lo + (uintptr_t)lines[i], eol);
216 } else 216 } else
217 printf("%s%c", lines[i], eol); 217 printf("%s%c", lines[i], eol);
218 } 218 }
diff --git a/coreutils/sort.c b/coreutils/sort.c
index 2e952f81c..949948203 100644
--- a/coreutils/sort.c
+++ b/coreutils/sort.c
@@ -43,7 +43,12 @@
43 43
44//usage:#define sort_trivial_usage 44//usage:#define sort_trivial_usage
45//usage: "[-nru" 45//usage: "[-nru"
46//usage: IF_NOT_PLATFORM_MINGW32(
46//usage: IF_FEATURE_SORT_BIG("ghMcszbdfiokt] [-o FILE] [-k START[.OFS][OPTS][,END[.OFS][OPTS]] [-t CHAR") 47//usage: IF_FEATURE_SORT_BIG("ghMcszbdfiokt] [-o FILE] [-k START[.OFS][OPTS][,END[.OFS][OPTS]] [-t CHAR")
48//usage: )
49//usage: IF_PLATFORM_MINGW32(
50//usage: IF_FEATURE_SORT_BIG("ghMVcszbdfiokt] [-o FILE] [-k START[.OFS][OPTS][,END[.OFS][OPTS]] [-t CHAR")
51//usage: )
47//usage: "] [FILE]..." 52//usage: "] [FILE]..."
48//usage:#define sort_full_usage "\n\n" 53//usage:#define sort_full_usage "\n\n"
49//usage: "Sort lines of text\n" 54//usage: "Sort lines of text\n"
diff --git a/coreutils/split.c b/coreutils/split.c
index b6d1b9a7b..8d0e485d4 100644
--- a/coreutils/split.c
+++ b/coreutils/split.c
@@ -78,8 +78,10 @@ static char *next_file(char *old, unsigned suffix_len)
78 return old; 78 return old;
79} 79}
80 80
81#if !ENABLE_PLATFORM_MINGW32
81#define read_buffer bb_common_bufsiz1 82#define read_buffer bb_common_bufsiz1
82enum { READ_BUFFER_SIZE = COMMON_BUFSIZE - 1 }; 83enum { READ_BUFFER_SIZE = COMMON_BUFSIZE - 1 };
84#endif
83 85
84#define SPLIT_OPT_l (1<<0) 86#define SPLIT_OPT_l (1<<0)
85#define SPLIT_OPT_b (1<<1) 87#define SPLIT_OPT_b (1<<1)
@@ -97,8 +99,12 @@ int split_main(int argc UNUSED_PARAM, char **argv)
97 unsigned opt; 99 unsigned opt;
98 ssize_t bytes_read, to_write; 100 ssize_t bytes_read, to_write;
99 char *src; 101 char *src;
100 102#if ENABLE_PLATFORM_MINGW32
103 size_t READ_BUFFER_SIZE = 16*1024;
104 char *read_buffer = xmalloc(16*1024);
105#else
101 setup_common_bufsiz(); 106 setup_common_bufsiz();
107#endif
102 108
103 opt = getopt32(argv, "^" 109 opt = getopt32(argv, "^"
104 "l:b:a:+" /* -a N */ 110 "l:b:a:+" /* -a N */
diff --git a/coreutils/stat.c b/coreutils/stat.c
index 2c2909e7e..dc20c2356 100644
--- a/coreutils/stat.c
+++ b/coreutils/stat.c
@@ -190,6 +190,7 @@ FS_TYPE(0x012FF7B4, "xenix") \
190FS_TYPE(0x012FF7B5, "sysv4") \ 190FS_TYPE(0x012FF7B5, "sysv4") \
191FS_TYPE(0x012FF7B6, "sysv2") \ 191FS_TYPE(0x012FF7B6, "sysv2") \
192FS_TYPE(0x012FF7B7, "coh") \ 192FS_TYPE(0x012FF7B7, "coh") \
193IF_PLATFORM_MINGW32(FS_TYPE(0x15013346, "udf")) \
193FS_TYPE(0x00011954, "ufs") \ 194FS_TYPE(0x00011954, "ufs") \
194FS_TYPE(0x012FD16D, "xia") \ 195FS_TYPE(0x012FD16D, "xia") \
195FS_TYPE(0x5346544e, "ntfs") \ 196FS_TYPE(0x5346544e, "ntfs") \
@@ -784,6 +785,10 @@ int stat_main(int argc UNUSED_PARAM, char **argv)
784 selinux_or_die(); 785 selinux_or_die();
785 } 786 }
786#endif 787#endif
788#if ENABLE_FEATURE_EXTRA_FILE_DATA
789 /* Enable accurate link counts for directories */
790 count_subdirs(NULL);
791#endif
787 ok = 1; 792 ok = 1;
788 argv += optind; 793 argv += optind;
789 for (i = 0; argv[i]; ++i) 794 for (i = 0; argv[i]; ++i)
diff --git a/coreutils/sum.c b/coreutils/sum.c
index 78e69acc6..7c7cc6b6b 100644
--- a/coreutils/sum.c
+++ b/coreutils/sum.c
@@ -82,9 +82,9 @@ static unsigned sum_file(const char *file, unsigned type)
82 if (type >= SUM_SYSV) { 82 if (type >= SUM_SYSV) {
83 r = (s & 0xffff) + ((s & 0xffffffff) >> 16); 83 r = (s & 0xffff) + ((s & 0xffffffff) >> 16);
84 s = (r & 0xffff) + (r >> 16); 84 s = (r & 0xffff) + (r >> 16);
85 printf("%u %llu %s\n", s, (total_bytes + 511) / 512, file); 85 printf("%u %"LL_FMT"u %s\n", s, (total_bytes + 511) / 512, file);
86 } else 86 } else
87 printf("%05u %5llu %s\n", s, (total_bytes + 1023) / 1024, file); 87 printf("%05u %5"LL_FMT"u %s\n", s, (total_bytes + 1023) / 1024, file);
88 return 1; 88 return 1;
89#undef buf 89#undef buf
90} 90}
diff --git a/coreutils/test.c b/coreutils/test.c
index b63e33cc0..3d38ead00 100644
--- a/coreutils/test.c
+++ b/coreutils/test.c
@@ -1022,10 +1022,14 @@ int test_main(int argc, char **argv)
1022 1022
1023 info.euid = -1; 1023 info.euid = -1;
1024 info.egid = -1; 1024 info.egid = -1;
1025#if !ENABLE_PLATFORM_MINGW32
1025 info.ngroups = 0; 1026 info.ngroups = 0;
1026 info.supplementary_array = NULL; 1027 info.supplementary_array = NULL;
1028#endif
1027 r = test_main2(&info, argc, argv); 1029 r = test_main2(&info, argc, argv);
1030#if !ENABLE_PLATFORM_MINGW32
1028 free(info.supplementary_array); 1031 free(info.supplementary_array);
1032#endif
1029 1033
1030 return r; 1034 return r;
1031} 1035}
diff --git a/coreutils/timeout.c b/coreutils/timeout.c
index 84299a0a5..58f96192b 100644
--- a/coreutils/timeout.c
+++ b/coreutils/timeout.c
@@ -43,10 +43,35 @@
43//usage:#define timeout_full_usage "\n\n" 43//usage:#define timeout_full_usage "\n\n"
44//usage: "Run PROG. Send SIG to it if it is not gone in SECS seconds.\n" 44//usage: "Run PROG. Send SIG to it if it is not gone in SECS seconds.\n"
45//usage: "Default SIG: TERM." 45//usage: "Default SIG: TERM."
46//usage: IF_PLATFORM_MINGW32("\n")
46//usage: "If it still exists in KILL_SECS seconds, send KILL.\n" 47//usage: "If it still exists in KILL_SECS seconds, send KILL.\n"
47 48
48#include "libbb.h" 49#include "libbb.h"
49 50
51#if ENABLE_PLATFORM_MINGW32
52static HANDLE child = INVALID_HANDLE_VALUE;
53
54static void kill_child(void)
55{
56 if (child != INVALID_HANDLE_VALUE) {
57 pid_t pid = (pid_t)GetProcessId(child);
58 if (pid)
59 kill(pid, SIGTERM);
60 }
61}
62
63/* Return TRUE if child exits before timeout expires */
64static NOINLINE int timeout_wait(duration_t timeout, HANDLE proc, DWORD *status)
65{
66 DWORD t = (DWORD)(timeout * 1000);
67 if (WaitForSingleObject(proc, t) == WAIT_OBJECT_0) {
68 /* process is gone */
69 GetExitCodeProcess(proc, status);
70 return TRUE;
71 }
72 return FALSE;
73}
74#else
50static NOINLINE int timeout_wait(duration_t timeout, pid_t pid) 75static NOINLINE int timeout_wait(duration_t timeout, pid_t pid)
51{ 76{
52 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ 77 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
@@ -66,13 +91,19 @@ static NOINLINE int timeout_wait(duration_t timeout, pid_t pid)
66 } 91 }
67 return EXIT_FAILURE; 92 return EXIT_FAILURE;
68} 93}
94#endif
69 95
70int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 96int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
71int timeout_main(int argc UNUSED_PARAM, char **argv) 97int timeout_main(int argc UNUSED_PARAM, char **argv)
72{ 98{
73 int signo; 99 int signo;
100#if !ENABLE_PLATFORM_MINGW32
74 int status; 101 int status;
75 int parent = 0; 102 int parent = 0;
103#else
104 intptr_t ret;
105 DWORD status = EXIT_SUCCESS;
106#endif
76 duration_t timeout; 107 duration_t timeout;
77 duration_t kill_timeout; 108 duration_t kill_timeout;
78 pid_t pid; 109 pid_t pid;
@@ -82,15 +113,27 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
82 const char *opt_s = "TERM"; 113 const char *opt_s = "TERM";
83 char *opt_k = NULL; 114 char *opt_k = NULL;
84 115
116#if ENABLE_PLATFORM_MINGW32
117 xfunc_error_retval = 125;
118#endif
119
85 /* -p option is not documented, it is needed to support NOMMU. */ 120 /* -p option is not documented, it is needed to support NOMMU. */
86 121
87 /* -t SECONDS; -p PARENT_PID */ 122 /* -t SECONDS; -p PARENT_PID */
88 /* '+': stop at first non-option */ 123 /* '+': stop at first non-option */
124#if !ENABLE_PLATFORM_MINGW32
89 getopt32(argv, "+s:k:" USE_FOR_NOMMU("p:+"), &opt_s, &opt_k, &parent); 125 getopt32(argv, "+s:k:" USE_FOR_NOMMU("p:+"), &opt_s, &opt_k, &parent);
126#else
127 getopt32(argv, "+s:k:", &opt_s, &opt_k);
128#endif
90 /*argv += optind; - no, wait for bb_daemonize_or_rexec! */ 129 /*argv += optind; - no, wait for bb_daemonize_or_rexec! */
91 130
92 signo = get_signum(opt_s); 131 signo = get_signum(opt_s);
132#if !ENABLE_PLATFORM_MINGW32
93 if (signo < 0) 133 if (signo < 0)
134#else
135 if (!is_valid_signal(signo))
136#endif
94 bb_error_msg_and_die("unknown signal '%s'", opt_s); 137 bb_error_msg_and_die("unknown signal '%s'", opt_s);
95 138
96 kill_timeout = 0; 139 kill_timeout = 0;
@@ -103,6 +146,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
103 if (!argv[optind]) /* no PROG? */ 146 if (!argv[optind]) /* no PROG? */
104 bb_show_usage(); 147 bb_show_usage();
105 148
149#if !ENABLE_PLATFORM_MINGW32
106 /* We want to create a grandchild which will watch 150 /* We want to create a grandchild which will watch
107 * and kill the grandparent. Other methods: 151 * and kill the grandparent. Other methods:
108 * making parent watch child disrupts parent<->child link 152 * making parent watch child disrupts parent<->child link
@@ -155,4 +199,33 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
155 argv[1] = sv2; 199 argv[1] = sv2;
156#endif 200#endif
157 BB_EXECVP_or_die(argv); 201 BB_EXECVP_or_die(argv);
202#else /* ENABLE_PLATFORM_MINGW32 */
203 argv += optind;
204 if ((ret=mingw_spawn_proc((const char **)argv)) == -1) {
205 xfunc_error_retval = errno == EACCES ? 126 : 127;
206 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
207 }
208
209 child = (HANDLE)ret;
210 atexit(kill_child);
211 if (timeout_wait(timeout, child, &status))
212 goto finish;
213 status = signo == SIGKILL ? 137 : 124;
214
215 pid = (pid_t)GetProcessId(child);
216 if (pid) {
217 kill(pid, signo);
218
219 if (kill_timeout > 0) {
220 if (timeout_wait(kill_timeout, child, &status))
221 goto finish;
222 kill(pid, SIGKILL);
223 status = 137;
224 }
225 }
226 finish:
227 CloseHandle(child);
228 child = INVALID_HANDLE_VALUE;
229 return status;
230#endif
158} 231}
diff --git a/debianutils/pipe_progress.c b/debianutils/pipe_progress.c
index acd7402d7..850c4d34b 100644
--- a/debianutils/pipe_progress.c
+++ b/debianutils/pipe_progress.c
@@ -16,8 +16,11 @@
16 16
17//kbuild:lib-$(CONFIG_PIPE_PROGRESS) += pipe_progress.o 17//kbuild:lib-$(CONFIG_PIPE_PROGRESS) += pipe_progress.o
18 18
19//usage:#define pipe_progress_trivial_usage NOUSAGE_STR 19//usage:#define pipe_progress_trivial_usage IF_PLATFORM_POSIX(NOUSAGE_STR)
20//usage: IF_PLATFORM_MINGW32("")
20//usage:#define pipe_progress_full_usage "" 21//usage:#define pipe_progress_full_usage ""
22//usage: IF_PLATFORM_MINGW32("\n\n")
23//usage: IF_PLATFORM_MINGW32("Display a dot to indicate pipe activity")
21 24
22#include "libbb.h" 25#include "libbb.h"
23 26
diff --git a/debianutils/which.c b/debianutils/which.c
index a7d55a215..5d564e01d 100644
--- a/debianutils/which.c
+++ b/debianutils/which.c
@@ -12,7 +12,11 @@
12//config: which is used to find programs in your PATH and 12//config: which is used to find programs in your PATH and
13//config: print out their pathnames. 13//config: print out their pathnames.
14 14
15//applet:IF_WHICH(APPLET_NOFORK(which, which, BB_DIR_USR_BIN, BB_SUID_DROP, which)) 15// NOTE: For WIN32 this applet is NOEXEC as file_is_win32_exe() and
16// find_executable() both allocate memory.
17
18//applet:IF_PLATFORM_MINGW32(IF_WHICH(APPLET_NOEXEC(which, which, BB_DIR_USR_BIN, BB_SUID_DROP, which)))
19//applet:IF_PLATFORM_POSIX(IF_WHICH(APPLET_NOFORK(which, which, BB_DIR_USR_BIN, BB_SUID_DROP, which)))
16 20
17//kbuild:lib-$(CONFIG_WHICH) += which.o 21//kbuild:lib-$(CONFIG_WHICH) += which.o
18 22
@@ -33,6 +37,10 @@ int which_main(int argc UNUSED_PARAM, char **argv)
33{ 37{
34 const char *env_path; 38 const char *env_path;
35 int status = 0; 39 int status = 0;
40#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE
41 /* 'Which' in argv[0] indicates we were run from a standalone shell */
42 int sh_standalone = argv[0][0] == 'W';
43#endif
36 44
37 env_path = getenv("PATH"); 45 env_path = getenv("PATH");
38 if (!env_path) 46 if (!env_path)
@@ -44,21 +52,60 @@ int which_main(int argc UNUSED_PARAM, char **argv)
44 do { 52 do {
45 int missing = 1; 53 int missing = 1;
46 54
55#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE
56 if (sh_standalone && find_applet_by_name(*argv) >= 0) {
57 missing = 0;
58 puts(applet_to_exe(*argv));
59 if (!option_mask32) /* -a not set */
60 break;
61 }
62#endif
63
64#if !ENABLE_PLATFORM_MINGW32
47 /* If file contains a slash don't use PATH */ 65 /* If file contains a slash don't use PATH */
48 if (strchr(*argv, '/')) { 66 if (strchr(*argv, '/')) {
49 if (file_is_executable(*argv)) { 67 if (file_is_executable(*argv)) {
50 missing = 0; 68 missing = 0;
51 puts(*argv); 69 puts(*argv);
52 } 70 }
71#else
72 if (has_path(*argv)) {
73 char *path = file_is_win32_exe(*argv);
74
75 if (path) {
76 missing = 0;
77 puts(bs_to_slash(path));
78 }
79 else if (unix_path(*argv)) {
80 const char *name = bb_basename(*argv);
81# if ENABLE_FEATURE_SH_STANDALONE
82 if (sh_standalone && find_applet_by_name(name) >= 0) {
83 missing = 0;
84 puts(name);
85 } else
86# endif
87 {
88 argv[0] = (char *)name;
89 goto try_PATH;
90 }
91 }
92#endif
53 } else { 93 } else {
54 const char *path; 94 const char *path;
55 char *p; 95 char *p;
56 96
97#if ENABLE_PLATFORM_MINGW32
98 try_PATH:
99#endif
57 path = env_path; 100 path = env_path;
58 /* NOFORK NB: xmalloc inside find_executable(), must have no allocs above! */ 101 /* NOFORK NB: xmalloc inside find_executable(), must have no allocs above! */
59 while ((p = find_executable(*argv, &path)) != NULL) { 102 while ((p = find_executable(*argv, &path)) != NULL) {
60 missing = 0; 103 missing = 0;
104#if ENABLE_PLATFORM_MINGW32
105 puts(bs_to_slash(p));
106#else
61 puts(p); 107 puts(p);
108#endif
62 free(p); 109 free(p);
63 if (!option_mask32) /* -a not set */ 110 if (!option_mask32) /* -a not set */
64 break; 111 break;
diff --git a/e2fsprogs/chattr.c b/e2fsprogs/chattr.c
index 5dec3253b..d8f92137e 100644
--- a/e2fsprogs/chattr.c
+++ b/e2fsprogs/chattr.c
@@ -20,13 +20,26 @@
20//kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o 20//kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o
21 21
22//usage:#define chattr_trivial_usage 22//usage:#define chattr_trivial_usage
23//usage: IF_NOT_PLATFORM_MINGW32(
23//usage: "[-R] [-v VERSION] [-p PROJID] [-+=AacDdijsStTu] FILE..." 24//usage: "[-R] [-v VERSION] [-p PROJID] [-+=AacDdijsStTu] FILE..."
25//usage: )
26//usage: IF_PLATFORM_MINGW32(
27//usage: "[-R] [-+rhsatn] FILE..."
28//usage: )
24//usage:#define chattr_full_usage "\n\n" 29//usage:#define chattr_full_usage "\n\n"
30//usage: IF_NOT_PLATFORM_MINGW32(
25//usage: "Change ext2 file attributes\n" 31//usage: "Change ext2 file attributes\n"
32//usage: )
33//usage: IF_PLATFORM_MINGW32(
34//usage: "Change file attributes\n"
35//usage: )
26//usage: "\n -R Recurse" 36//usage: "\n -R Recurse"
37//usage: IF_NOT_PLATFORM_MINGW32(
27//usage: "\n -v NUM Set version/generation number" 38//usage: "\n -v NUM Set version/generation number"
28//usage: "\n -p NUM Set project number" 39//usage: "\n -p NUM Set project number"
40//usage: )
29//-V, -f accepted but ignored 41//-V, -f accepted but ignored
42//usage: IF_NOT_PLATFORM_MINGW32(
30//usage: "\nModifiers:" 43//usage: "\nModifiers:"
31//usage: "\n -,+,= Remove/add/set attributes" 44//usage: "\n -,+,= Remove/add/set attributes"
32//usage: "\nAttributes:" 45//usage: "\nAttributes:"
@@ -50,6 +63,16 @@
50//usage: "\n t Don't tail-merge with other files" 63//usage: "\n t Don't tail-merge with other files"
51//usage: "\n u Allow undelete" 64//usage: "\n u Allow undelete"
52//usage: "\n V Verity" 65//usage: "\n V Verity"
66//usage: )
67//usage: IF_PLATFORM_MINGW32(
68//usage: "\n -,+ Remove/add attributes"
69//usage: "\n r Read only"
70//usage: "\n h Hidden"
71//usage: "\n s System"
72//usage: "\n a Archive"
73//usage: "\n t Temporary"
74//usage: "\n n Not indexed"
75//usage: )
53 76
54#include "libbb.h" 77#include "libbb.h"
55#include "e2fs_lib.h" 78#include "e2fs_lib.h"
@@ -61,11 +84,15 @@
61#define OPT_SET_PROJ (1 << 4) 84#define OPT_SET_PROJ (1 << 4)
62 85
63struct globals { 86struct globals {
87#if !ENABLE_PLATFORM_MINGW32
64 unsigned version; 88 unsigned version;
89#endif
65 unsigned af; 90 unsigned af;
66 unsigned rf; 91 unsigned rf;
67 int flags; 92 int flags;
93#if !ENABLE_PLATFORM_MINGW32
68 uint32_t projid; 94 uint32_t projid;
95#endif
69 smallint recursive; 96 smallint recursive;
70}; 97};
71 98
@@ -89,11 +116,17 @@ static char** decode_arg(char **argv, struct globals *gp)
89 /* testcase: chattr =ae -R FILE should not complain "= is incompatible with - and +" */ 116 /* testcase: chattr =ae -R FILE should not complain "= is incompatible with - and +" */
90 /* (and should not read flags, with =FLAGS they can be just set directly) */ 117 /* (and should not read flags, with =FLAGS they can be just set directly) */
91 fl = &gp->rf; 118 fl = &gp->rf;
119#if ENABLE_PLATFORM_MINGW32
120 } else { /* if (opt == '+') */
121 gp->flags |= OPT_ADD;
122 }
123#else
92 } else if (opt == '+') { 124 } else if (opt == '+') {
93 gp->flags |= OPT_ADD; 125 gp->flags |= OPT_ADD;
94 } else { /* if (opt == '=') */ 126 } else { /* if (opt == '=') */
95 gp->flags |= OPT_SET; 127 gp->flags |= OPT_SET;
96 } 128 }
129#endif
97 130
98 while (*++arg) { 131 while (*++arg) {
99 if (opt == '-') { 132 if (opt == '-') {
@@ -106,6 +139,7 @@ static char** decode_arg(char **argv, struct globals *gp)
106 gp->recursive = 1; 139 gp->recursive = 1;
107 continue; 140 continue;
108 } 141 }
142#if !ENABLE_PLATFORM_MINGW32
109 if (*arg == 'V') { 143 if (*arg == 'V') {
110 /*"verbose and print program version" (nop for now) */; 144 /*"verbose and print program version" (nop for now) */;
111 continue; 145 continue;
@@ -128,6 +162,7 @@ static char** decode_arg(char **argv, struct globals *gp)
128 gp->flags |= OPT_SET_PROJ; 162 gp->flags |= OPT_SET_PROJ;
129 continue; 163 continue;
130 } 164 }
165#endif
131 /* not a known option, try as an attribute */ 166 /* not a known option, try as an attribute */
132 gp->flags |= OPT_REM; 167 gp->flags |= OPT_REM;
133 } 168 }
@@ -154,8 +189,10 @@ static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, vo
154 189
155static void change_attributes(const char *name, struct globals *gp) 190static void change_attributes(const char *name, struct globals *gp)
156{ 191{
192#if !ENABLE_PLATFORM_MINGW32
157 unsigned fsflags; 193 unsigned fsflags;
158 int fd; 194 int fd;
195#endif
159 struct stat st; 196 struct stat st;
160 197
161 if (lstat(name, &st) != 0) { 198 if (lstat(name, &st) != 0) {
@@ -170,6 +207,7 @@ static void change_attributes(const char *name, struct globals *gp)
170 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode)) 207 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
171 return; 208 return;
172 209
210#if !ENABLE_PLATFORM_MINGW32
173 /* There is no way to run needed ioctls on a symlink. 211 /* There is no way to run needed ioctls on a symlink.
174 * open(O_PATH | O_NOFOLLOW) _can_ be used to get a fd referring to the symlink, 212 * open(O_PATH | O_NOFOLLOW) _can_ be used to get a fd referring to the symlink,
175 * but ioctls fail on such a fd (tried on 4.12.0 kernel). 213 * but ioctls fail on such a fd (tried on 4.12.0 kernel).
@@ -221,6 +259,16 @@ static void change_attributes(const char *name, struct globals *gp)
221 skip_setflags: 259 skip_setflags:
222 close(fd); 260 close(fd);
223 } 261 }
262#else /* ENABLE_PLATFORM_MINGW32 */
263 /*if (gp->flags & OPT_REM) - not needed, rf is zero otherwise */
264 st.st_attr &= ~gp->rf;
265 /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */
266 st.st_attr |= gp->af;
267 if (!SetFileAttributes(name, st.st_attr & CHATTR_MASK)) {
268 errno = err_win_to_posix();
269 bb_perror_msg("setting flags on %s", name);
270 }
271#endif
224 272
225 if (gp->recursive && S_ISDIR(st.st_mode)) 273 if (gp->recursive && S_ISDIR(st.st_mode))
226 iterate_on_dir(name, chattr_dir_proc, gp); 274 iterate_on_dir(name, chattr_dir_proc, gp);
@@ -238,7 +286,11 @@ int chattr_main(int argc UNUSED_PARAM, char **argv)
238 char *arg = *++argv; 286 char *arg = *++argv;
239 if (!arg) 287 if (!arg)
240 bb_show_usage(); 288 bb_show_usage();
289#if ENABLE_PLATFORM_MINGW32
290 if (arg[0] != '-' && arg[0] != '+')
291#else
241 if (arg[0] != '-' && arg[0] != '+' && arg[0] != '=') 292 if (arg[0] != '-' && arg[0] != '+' && arg[0] != '=')
293#endif
242 break; 294 break;
243 295
244 argv = decode_arg(argv, &g); 296 argv = decode_arg(argv, &g);
@@ -246,12 +298,18 @@ int chattr_main(int argc UNUSED_PARAM, char **argv)
246 /* note: on loop exit, remaining argv[] is never empty */ 298 /* note: on loop exit, remaining argv[] is never empty */
247 299
248 /* run sanity checks on all the arguments given us */ 300 /* run sanity checks on all the arguments given us */
301#if !ENABLE_PLATFORM_MINGW32
249 if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM))) 302 if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM)))
250 bb_simple_error_msg_and_die("= is incompatible with - and +"); 303 bb_simple_error_msg_and_die("= is incompatible with - and +");
304#endif
251 if (g.rf & g.af) 305 if (g.rf & g.af)
252 bb_simple_error_msg_and_die("can't set and unset a flag"); 306 bb_simple_error_msg_and_die("can't set and unset a flag");
253 if (!g.flags) 307 if (!g.flags)
308#if ENABLE_PLATFORM_MINGW32
309 bb_simple_error_msg_and_die("must use - or +");
310#else
254 bb_simple_error_msg_and_die("must use -v, -p, =, - or +"); 311 bb_simple_error_msg_and_die("must use -v, -p, =, - or +");
312#endif
255 313
256 /* now run chattr on all the files passed to us */ 314 /* now run chattr on all the files passed to us */
257 do change_attributes(*argv, &g); while (*++argv); 315 do change_attributes(*argv, &g); while (*++argv);
diff --git a/e2fsprogs/e2fs_lib.c b/e2fsprogs/e2fs_lib.c
index 9b68d8901..4a4db1a13 100644
--- a/e2fsprogs/e2fs_lib.c
+++ b/e2fsprogs/e2fs_lib.c
@@ -8,6 +8,7 @@
8#include "libbb.h" 8#include "libbb.h"
9#include "e2fs_lib.h" 9#include "e2fs_lib.h"
10 10
11#if !ENABLE_PLATFORM_MINGW32
11/* Print file attributes on an ext2 file system */ 12/* Print file attributes on an ext2 file system */
12const uint32_t e2attr_flags_value[] ALIGN4 = { 13const uint32_t e2attr_flags_value[] ALIGN4 = {
13#ifdef ENABLE_COMPRESSION 14#ifdef ENABLE_COMPRESSION
@@ -70,11 +71,52 @@ static const char e2attr_flags_lname[] ALIGN1 =
70 "Project_Hierarchy" "\0" 71 "Project_Hierarchy" "\0"
71 "Verity" "\0" 72 "Verity" "\0"
72 /* Another trailing NUL is added by compiler */; 73 /* Another trailing NUL is added by compiler */;
74#else /* ENABLE_PLATFORM_MINGW32 */
75/* Print file attributes on a Windows file system */
76const uint32_t e2attr_flags_value[] = {
77 FILE_ATTRIBUTE_REPARSE_POINT,
78 FILE_ATTRIBUTE_OFFLINE,
79 FILE_ATTRIBUTE_ENCRYPTED,
80 FILE_ATTRIBUTE_COMPRESSED,
81 FILE_ATTRIBUTE_SPARSE_FILE,
82 FILE_ATTRIBUTE_READONLY,
83 FILE_ATTRIBUTE_HIDDEN,
84 FILE_ATTRIBUTE_SYSTEM,
85 FILE_ATTRIBUTE_ARCHIVE,
86 FILE_ATTRIBUTE_TEMPORARY,
87 FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
88};
89
90const char e2attr_flags_sname[] ALIGN1 =
91 "RoecSrhsatn";
92
93static const char e2attr_flags_lname[] ALIGN1 =
94 "Reparse_Point" "\0"
95 "Offline" "\0"
96 "Encrypted" "\0"
97 "Compressed" "\0"
98 "Sparse" "\0"
99 "Read_Only" "\0"
100 "Hidden" "\0"
101 "System" "\0"
102 "Archive" "\0"
103 "Temporary" "\0"
104 "Not_Indexed" "\0"
105 /* Another trailing NUL is added by compiler */;
106#endif
73 107
108#if !ENABLE_PLATFORM_MINGW32
74void print_e2flags_long(unsigned flags) 109void print_e2flags_long(unsigned flags)
110#else
111#define flags sb->st_attr
112void print_e2flags_long(struct stat *sb)
113#endif
75{ 114{
76 const uint32_t *fv; 115 const uint32_t *fv;
77 const char *fn; 116 const char *fn;
117#if ENABLE_PLATFORM_MINGW32
118 const char *ln;
119#endif
78 int first = 1; 120 int first = 1;
79 121
80 fv = e2attr_flags_value; 122 fv = e2attr_flags_value;
@@ -83,7 +125,25 @@ void print_e2flags_long(unsigned flags)
83 if (flags & *fv) { 125 if (flags & *fv) {
84 if (!first) 126 if (!first)
85 fputs(", ", stdout); 127 fputs(", ", stdout);
128#if ENABLE_PLATFORM_MINGW32
129 ln = fn;
130 if (*fv == FILE_ATTRIBUTE_REPARSE_POINT) {
131 switch (sb->st_tag) {
132 case IO_REPARSE_TAG_SYMLINK:
133 ln = "Symbolic_Link";
134 break;
135 case IO_REPARSE_TAG_MOUNT_POINT:
136 ln = "Junction";
137 break;
138 case IO_REPARSE_TAG_APPEXECLINK:
139 ln = "App_Exec_Link";
140 break;
141 }
142 }
143 fputs(ln, stdout);
144#else
86 fputs(fn, stdout); 145 fputs(fn, stdout);
146#endif
87 first = 0; 147 first = 0;
88 } 148 }
89 fv++; 149 fv++;
@@ -93,7 +153,11 @@ void print_e2flags_long(unsigned flags)
93 fputs("---", stdout); 153 fputs("---", stdout);
94} 154}
95 155
156#if !ENABLE_PLATFORM_MINGW32
96void print_e2flags(unsigned flags) 157void print_e2flags(unsigned flags)
158#else
159void print_e2flags(struct stat *sb)
160#endif
97{ 161{
98 const uint32_t *fv; 162 const uint32_t *fv;
99 const char *fn; 163 const char *fn;
@@ -104,6 +168,21 @@ void print_e2flags(unsigned flags)
104 char c = '-'; 168 char c = '-';
105 if (flags & *fv) 169 if (flags & *fv)
106 c = *fn; 170 c = *fn;
171#if ENABLE_PLATFORM_MINGW32
172 if (*fv == FILE_ATTRIBUTE_REPARSE_POINT) {
173 switch (sb->st_tag) {
174 case IO_REPARSE_TAG_SYMLINK:
175 c = 'l';
176 break;
177 case IO_REPARSE_TAG_MOUNT_POINT:
178 c = 'j';
179 break;
180 case IO_REPARSE_TAG_APPEXECLINK:
181 c = 'A';
182 break;
183 }
184 }
185#endif
107 putchar(c); 186 putchar(c);
108 fv++; 187 fv++;
109 fn++; 188 fn++;
diff --git a/e2fsprogs/e2fs_lib.h b/e2fsprogs/e2fs_lib.h
index bab447a94..5ce206ad6 100644
--- a/e2fsprogs/e2fs_lib.h
+++ b/e2fsprogs/e2fs_lib.h
@@ -11,15 +11,28 @@
11 11
12PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 12PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
13 13
14#if ENABLE_PLATFORM_MINGW32
15/* Only certain attributes can be set using SetFileAttributes() */
16#define CHATTR_MASK (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
17 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | \
18 FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
19
20/* Print file attributes on an NTFS file system */
21void print_e2flags_long(struct stat *sb);
22void print_e2flags(struct stat *sb);
23#else
24
14/* Print file attributes on an ext2 file system */ 25/* Print file attributes on an ext2 file system */
15void print_e2flags_long(unsigned flags); 26void print_e2flags_long(unsigned flags);
16void print_e2flags(unsigned flags); 27void print_e2flags(unsigned flags);
28#endif
17 29
18extern const uint32_t e2attr_flags_value[]; 30extern const uint32_t e2attr_flags_value[];
19extern const char e2attr_flags_sname[]; 31extern const char e2attr_flags_sname[];
20 32
21/* If you plan to ENABLE_COMPRESSION, see e2fs_lib.c and chattr.c - */ 33/* If you plan to ENABLE_COMPRESSION, see e2fs_lib.c and chattr.c - */
22/* make sure that chattr doesn't accept bad options! */ 34/* make sure that chattr doesn't accept bad options! */
35#if !ENABLE_PLATFORM_MINGW32
23#ifdef ENABLE_COMPRESSION 36#ifdef ENABLE_COMPRESSION
24#define e2attr_flags_value_chattr (&e2attr_flags_value[5]) 37#define e2attr_flags_value_chattr (&e2attr_flags_value[5])
25#define e2attr_flags_sname_chattr (&e2attr_flags_sname[5]) 38#define e2attr_flags_sname_chattr (&e2attr_flags_sname[5])
@@ -27,5 +40,9 @@ extern const char e2attr_flags_sname[];
27#define e2attr_flags_value_chattr (&e2attr_flags_value[1]) 40#define e2attr_flags_value_chattr (&e2attr_flags_value[1])
28#define e2attr_flags_sname_chattr (&e2attr_flags_sname[1]) 41#define e2attr_flags_sname_chattr (&e2attr_flags_sname[1])
29#endif 42#endif
43#else
44#define e2attr_flags_value_chattr (&e2attr_flags_value[5])
45#define e2attr_flags_sname_chattr (&e2attr_flags_sname[5])
46#endif
30 47
31POP_SAVED_FUNCTION_VISIBILITY 48POP_SAVED_FUNCTION_VISIBILITY
diff --git a/e2fsprogs/lsattr.c b/e2fsprogs/lsattr.c
index f678f72fb..427552f7a 100644
--- a/e2fsprogs/lsattr.c
+++ b/e2fsprogs/lsattr.c
@@ -21,16 +21,45 @@
21//kbuild:lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o 21//kbuild:lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o
22 22
23//usage:#define lsattr_trivial_usage 23//usage:#define lsattr_trivial_usage
24//usage: IF_NOT_PLATFORM_MINGW32(
24//usage: "[-Radlpv] [FILE]..." 25//usage: "[-Radlpv] [FILE]..."
26//usage: )
27//usage: IF_PLATFORM_MINGW32(
28//usage: "[-Radl] [FILE]..."
29//usage: )
25//usage:#define lsattr_full_usage "\n\n" 30//usage:#define lsattr_full_usage "\n\n"
31//usage: IF_NOT_PLATFORM_MINGW32(
26//usage: "List ext2 file attributes\n" 32//usage: "List ext2 file attributes\n"
33//usage: )
34//usage: IF_PLATFORM_MINGW32(
35//usage: "List file attributes\n"
36//usage: )
27//usage: "\n -R Recurse" 37//usage: "\n -R Recurse"
28//usage: "\n -a Include names starting with ." 38//usage: "\n -a Include names starting with ."
29//usage: "\n -d List directory names, not contents" 39//usage: "\n -d List directory names, not contents"
30// -a,-d text should match ls --help 40// -a,-d text should match ls --help
31//usage: "\n -l List long flag names" 41//usage: "\n -l List long flag names"
42//usage: IF_NOT_PLATFORM_MINGW32(
32//usage: "\n -p List project ID" 43//usage: "\n -p List project ID"
33//usage: "\n -v List version/generation number" 44//usage: "\n -v List version/generation number"
45//usage: )
46//usage: IF_PLATFORM_MINGW32(
47//usage: "\n\nAttributes:\n"
48//usage: "\n j Junction"
49//usage: "\n l Symbolic link"
50//usage: "\n A App exec link"
51//usage: "\n R Reparse point"
52//usage: "\n o Offline"
53//usage: "\n e Encrypted"
54//usage: "\n c Compressed"
55//usage: "\n S Sparse"
56//usage: "\n r Read only"
57//usage: "\n h Hidden"
58//usage: "\n s System"
59//usage: "\n a Archive"
60//usage: "\n t Temporary"
61//usage: "\n n Not indexed"
62//usage: )
34 63
35#include "libbb.h" 64#include "libbb.h"
36#include "e2fs_lib.h" 65#include "e2fs_lib.h"
@@ -46,6 +75,7 @@ enum {
46 75
47static void list_attributes(const char *name) 76static void list_attributes(const char *name)
48{ 77{
78#if !ENABLE_PLATFORM_MINGW32
49 unsigned fsflags; 79 unsigned fsflags;
50 int fd, r; 80 int fd, r;
51 81
@@ -80,6 +110,15 @@ static void list_attributes(const char *name)
80 goto read_err; 110 goto read_err;
81 111
82 close(fd); 112 close(fd);
113#else /* ENABLE_PLATFORM_MINGW32 */
114 struct stat st;
115
116 if (lstat(name, &st) == 0 && !(S_ISREG(st.st_mode) ||
117 S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode)))
118 goto read_err;
119
120#define fsflags &st
121#endif
83 122
84 if (option_mask32 & OPT_PF_LONG) { 123 if (option_mask32 & OPT_PF_LONG) {
85 printf("%-28s ", name); 124 printf("%-28s ", name);
@@ -93,7 +132,9 @@ static void list_attributes(const char *name)
93 return; 132 return;
94 read_err: 133 read_err:
95 bb_perror_msg("reading %s", name); 134 bb_perror_msg("reading %s", name);
135#if !ENABLE_PLATFORM_MINGW32
96 close(fd); 136 close(fd);
137#endif
97} 138}
98 139
99static int FAST_FUNC lsattr_dir_proc(const char *dir_name, 140static int FAST_FUNC lsattr_dir_proc(const char *dir_name,
@@ -142,7 +183,11 @@ static void lsattr_args(const char *name)
142int lsattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 183int lsattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
143int lsattr_main(int argc UNUSED_PARAM, char **argv) 184int lsattr_main(int argc UNUSED_PARAM, char **argv)
144{ 185{
186#if ENABLE_PLATFORM_MINGW32
187 getopt32(argv, "Radl");
188#else
145 getopt32(argv, "Radlvp"); 189 getopt32(argv, "Radlvp");
190#endif
146 argv += optind; 191 argv += optind;
147 192
148 if (!*argv) 193 if (!*argv)
diff --git a/editors/awk.c b/editors/awk.c
index 64e752f4b..1feb49da1 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -970,7 +970,7 @@ static double my_strtod_or_hexoct(char **pp)
970static const char *fmt_num(const char *format, double n) 970static const char *fmt_num(const char *format, double n)
971{ 971{
972 if (n == (long long)n) { 972 if (n == (long long)n) {
973 snprintf(g_buf, MAXVARFMT, "%lld", (long long)n); 973 snprintf(g_buf, MAXVARFMT, "%"LL_FMT"d", (long long)n);
974 } else { 974 } else {
975 const char *s = format; 975 const char *s = format;
976 char c; 976 char c;
@@ -2929,6 +2929,15 @@ static int try_to_assign(const char *expr)
2929 return TRUE; 2929 return TRUE;
2930} 2930}
2931 2931
2932
2933#if ENABLE_PLATFORM_MINGW32
2934static void set_text_mode(FILE *f)
2935{
2936 if (f)
2937 _setmode(fileno(f), _O_TEXT);
2938}
2939#endif
2940
2932/* switch to next input file */ 2941/* switch to next input file */
2933static int next_input_file(void) 2942static int next_input_file(void)
2934{ 2943{
@@ -2972,6 +2981,9 @@ static int next_input_file(void)
2972 break; 2981 break;
2973 } 2982 }
2974 } 2983 }
2984#if ENABLE_PLATFORM_MINGW32
2985 set_text_mode(iF.F);
2986#endif
2975 2987
2976 setvar_s(intvar[FILENAME], fname); 2988 setvar_s(intvar[FILENAME], fname);
2977 input_file_seen = TRUE; 2989 input_file_seen = TRUE;
@@ -2980,6 +2992,17 @@ static int next_input_file(void)
2980#undef input_file_seen 2992#undef input_file_seen
2981} 2993}
2982 2994
2995#if ENABLE_PLATFORM_MINGW32
2996static unsigned triple32(unsigned x)
2997{
2998 x ^= x >> 17; x *= 0xed5ad4bb;
2999 x ^= x >> 11; x *= 0xac4c1b51;
3000 x ^= x >> 15; x *= 0x31848bab;
3001 x ^= x >> 14;
3002 return x;
3003}
3004#endif
3005
2983/* 3006/*
2984 * Evaluate node - the heart of the program. Supplied with subtree 3007 * Evaluate node - the heart of the program. Supplied with subtree
2985 * and "res" variable to assign the result to if we evaluate an expression. 3008 * and "res" variable to assign the result to if we evaluate an expression.
@@ -3361,6 +3384,9 @@ static var *evaluate(node *op, var *res)
3361 } else { 3384 } else {
3362 rsm->F = fopen_for_read(L.s); /* not xfopen! */ 3385 rsm->F = fopen_for_read(L.s); /* not xfopen! */
3363 } 3386 }
3387#if ENABLE_PLATFORM_MINGW32
3388 set_text_mode(rsm->F);
3389#endif
3364 } 3390 }
3365 } else { 3391 } else {
3366 if (!iF.F) 3392 if (!iF.F)
@@ -3412,6 +3438,12 @@ static var *evaluate(node *op, var *res)
3412 v &= 0x7fffffffffffffffULL; 3438 v &= 0x7fffffffffffffffULL;
3413# endif 3439# endif
3414 R_d = (double)v / 0x8000000000000000ULL; 3440 R_d = (double)v / 0x8000000000000000ULL;
3441#elif ENABLE_PLATFORM_MINGW32 && RAND_MAX == 0x7fff
3442 /* 45 bits of randomness ought to be enough for anyone */
3443 uint64_t v = ((uint64_t)rand() << 18) |
3444 ((uint64_t)rand() << 33) |
3445 ((uint64_t)rand() << 48);
3446 R_d = (double)v / 0x8000000000000000ULL;
3415#else 3447#else
3416# error Not implemented for this value of RAND_MAX 3448# error Not implemented for this value of RAND_MAX
3417#endif 3449#endif
@@ -3453,7 +3485,11 @@ static var *evaluate(node *op, var *res)
3453 case F_sr: 3485 case F_sr:
3454 R_d = (double)seed; 3486 R_d = (double)seed;
3455 seed = op1 ? (unsigned)L_d : (unsigned)time(NULL); 3487 seed = op1 ? (unsigned)L_d : (unsigned)time(NULL);
3488#if ENABLE_PLATFORM_MINGW32
3489 srand(seed == 1 ? 1 : triple32(seed));
3490#else
3456 srand(seed); 3491 srand(seed);
3492#endif
3457 break; 3493 break;
3458 3494
3459 case F_ti: /*systime*/ 3495 case F_ti: /*systime*/
@@ -3797,6 +3833,9 @@ int awk_main(int argc UNUSED_PARAM, char **argv)
3797 char *s; 3833 char *s;
3798 g_progname = optarg; 3834 g_progname = optarg;
3799 fd = xopen_stdin(g_progname); 3835 fd = xopen_stdin(g_progname);
3836#if ENABLE_PLATFORM_MINGW32
3837 _setmode(fd, _O_TEXT);
3838#endif
3800 s = xmalloc_read(fd, NULL); /* it's NUL-terminated */ 3839 s = xmalloc_read(fd, NULL); /* it's NUL-terminated */
3801 if (!s) 3840 if (!s)
3802 bb_perror_msg_and_die("read error from '%s'", g_progname); 3841 bb_perror_msg_and_die("read error from '%s'", g_progname);
diff --git a/editors/diff.c b/editors/diff.c
index 1adc4cbc7..b324feaa5 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -119,6 +119,9 @@
119//usage: "\n -t Expand tabs to spaces in output" 119//usage: "\n -t Expand tabs to spaces in output"
120//usage: "\n -U Output LINES lines of context" 120//usage: "\n -U Output LINES lines of context"
121//usage: "\n -w Ignore all whitespace" 121//usage: "\n -w Ignore all whitespace"
122//usage: IF_PLATFORM_MINGW32(IF_FEATURE_DIFF_LONG_OPTIONS(
123//usage: "\n --binary Treat input as binary, not text"
124//usage: ))
122 125
123#include "libbb.h" 126#include "libbb.h"
124#include "common_bufsiz.h" 127#include "common_bufsiz.h"
@@ -154,6 +157,9 @@ enum { /* Commandline flags */
154 FLAG_p, /* not implemented */ 157 FLAG_p, /* not implemented */
155 FLAG_B, 158 FLAG_B,
156 FLAG_E, /* not implemented */ 159 FLAG_E, /* not implemented */
160#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_DIFF_LONG_OPTIONS
161 FLAG_binary,
162#endif
157}; 163};
158#define FLAG(x) (1 << FLAG_##x) 164#define FLAG(x) (1 << FLAG_##x)
159 165
@@ -217,6 +223,9 @@ static int read_token(FILE_and_pos_t *ft, token_t tok)
217 int t; 223 int t;
218 224
219 t = fgetc(ft->ft_fp); 225 t = fgetc(ft->ft_fp);
226#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_DIFF_LONG_OPTIONS
227 newline:
228#endif
220 if (t != EOF) 229 if (t != EOF)
221 ft->ft_pos++; 230 ft->ft_pos++;
222 is_space = (t == EOF || isspace(t)); 231 is_space = (t == EOF || isspace(t));
@@ -232,6 +241,16 @@ static int read_token(FILE_and_pos_t *ft, token_t tok)
232 241
233 if ((option_mask32 & FLAG(w)) && is_space) 242 if ((option_mask32 & FLAG(w)) && is_space)
234 continue; 243 continue;
244#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_DIFF_LONG_OPTIONS
245 if (!(option_mask32 & FLAG(binary)) && t == '\r') {
246 int t2 = fgetc(ft->ft_fp);
247 if (t2 == '\n') {
248 t = t2;
249 goto newline;
250 }
251 ungetc(t2, ft->ft_fp);
252 }
253#endif
235 254
236 /* Trim char value to low 9 bits */ 255 /* Trim char value to low 9 bits */
237 t &= CHAR_MASK; 256 t &= CHAR_MASK;
@@ -709,6 +728,10 @@ static int diffreg(char *file[2])
709 FILE *fp[2]; 728 FILE *fp[2];
710 bool binary = false, differ = false; 729 bool binary = false, differ = false;
711 int status = STATUS_SAME, i; 730 int status = STATUS_SAME, i;
731#if ENABLE_PLATFORM_MINGW32
732 char *tmpfile[2] = { NULL, NULL };
733 char *tmpdir;
734#endif
712 735
713 fp[0] = stdin; 736 fp[0] = stdin;
714 fp[1] = stdin; 737 fp[1] = stdin;
@@ -730,10 +753,19 @@ static int diffreg(char *file[2])
730 * When we meet non-seekable file, we must make a temp copy. 753 * When we meet non-seekable file, we must make a temp copy.
731 */ 754 */
732 if (lseek(fd, 0, SEEK_SET) == -1 && errno == ESPIPE) { 755 if (lseek(fd, 0, SEEK_SET) == -1 && errno == ESPIPE) {
756#if !ENABLE_PLATFORM_MINGW32
733 char name[] = "/tmp/difXXXXXX"; 757 char name[] = "/tmp/difXXXXXX";
734 int fd_tmp = xmkstemp(name); 758 int fd_tmp = xmkstemp(name);
735 759
736 unlink(name); 760 unlink(name);
761#else
762 int fd_tmp;
763
764 if (!(tmpdir=getenv("TMPDIR")))
765 goto out;
766 tmpfile[i] = xasprintf("%s/difXXXXXX", tmpdir);
767 fd_tmp = xmkstemp(tmpfile[i]);
768#endif
737 if (bb_copyfd_eof(fd, fd_tmp) < 0) 769 if (bb_copyfd_eof(fd, fd_tmp) < 0)
738 xfunc_die(); 770 xfunc_die();
739 if (fd != STDIN_FILENO) 771 if (fd != STDIN_FILENO)
@@ -776,6 +808,14 @@ static int diffreg(char *file[2])
776out: 808out:
777 fclose_if_not_stdin(fp[0]); 809 fclose_if_not_stdin(fp[0]);
778 fclose_if_not_stdin(fp[1]); 810 fclose_if_not_stdin(fp[1]);
811#if ENABLE_PLATFORM_MINGW32
812 for (i = 0; i < 2; i++) {
813 if (tmpfile[i]) {
814 unlink(tmpfile[i]);
815 free(tmpfile[i]);
816 }
817 }
818#endif
779 819
780 return status; 820 return status;
781} 821}
@@ -964,6 +1004,9 @@ static const char diff_longopts[] ALIGN1 =
964 "report-identical-files\0" No_argument "s" 1004 "report-identical-files\0" No_argument "s"
965 "starting-file\0" Required_argument "S" 1005 "starting-file\0" Required_argument "S"
966 "minimal\0" No_argument "d" 1006 "minimal\0" No_argument "d"
1007#if ENABLE_PLATFORM_MINGW32
1008 "binary\0" No_argument "\xff"
1009#endif
967 ; 1010 ;
968# define GETOPT32 getopt32long 1011# define GETOPT32 getopt32long
969# define LONGOPTS ,diff_longopts 1012# define LONGOPTS ,diff_longopts
@@ -1019,6 +1062,11 @@ int diff_main(int argc UNUSED_PARAM, char **argv)
1019 * 255, or if a local inode number (st_ino) exceeds 16777215. 1062 * 255, or if a local inode number (st_ino) exceeds 16777215.
1020 */ 1063 */
1021 if (ENABLE_DESKTOP 1064 if (ENABLE_DESKTOP
1065 && (ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA)
1066#if ENABLE_FEATURE_EXTRA_FILE_DATA
1067 /* ignore invalid inode numbers */
1068 && stb[0].st_ino != 0
1069#endif
1022 && stb[0].st_ino == stb[1].st_ino 1070 && stb[0].st_ino == stb[1].st_ino
1023 && stb[0].st_dev == stb[1].st_dev 1071 && stb[0].st_dev == stb[1].st_dev
1024 && stb[0].st_size == stb[1].st_size 1072 && stb[0].st_size == stb[1].st_size
diff --git a/editors/sed.c b/editors/sed.c
index 6179c5e80..107e664a0 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -74,6 +74,9 @@
74//usage: "\n Optionally back files up, appending SFX" 74//usage: "\n Optionally back files up, appending SFX"
75//usage: "\n -n Suppress automatic printing of pattern space" 75//usage: "\n -n Suppress automatic printing of pattern space"
76//usage: "\n -r,-E Use extended regex syntax" 76//usage: "\n -r,-E Use extended regex syntax"
77//usage: IF_PLATFORM_MINGW32(
78//usage: "\n -b Keep CR/LF (Windows-only)"
79//usage: )
77//usage: "\n" 80//usage: "\n"
78//usage: "\nIf no -e or -f, the first non-option argument is the sed command string." 81//usage: "\nIf no -e or -f, the first non-option argument is the sed command string."
79//usage: "\nRemaining arguments are input files (stdin if none)." 82//usage: "\nRemaining arguments are input files (stdin if none)."
@@ -138,6 +141,9 @@ static const char semicolon_whitespace[] ALIGN1 = "; \n\r\t\v";
138struct globals { 141struct globals {
139 /* options */ 142 /* options */
140 int be_quiet, regex_type; 143 int be_quiet, regex_type;
144#if ENABLE_PLATFORM_MINGW32
145 int keep_cr;
146#endif
141 147
142 FILE *nonstdout; 148 FILE *nonstdout;
143 char *outname, *hold_space; 149 char *outname, *hold_space;
@@ -1065,6 +1071,11 @@ static char *get_next_line(char *gets_char, char *last_puts_char)
1065 char c = temp[len-1]; 1071 char c = temp[len-1];
1066 if (c == '\n' || c == '\0') { 1072 if (c == '\n' || c == '\0') {
1067 temp[len-1] = '\0'; 1073 temp[len-1] = '\0';
1074#if ENABLE_PLATFORM_MINGW32
1075 if (!G.keep_cr && c == '\n' && len > 1 && temp[len-2] == '\r') {
1076 temp[len-2] = '\0';
1077 }
1078#endif
1068 gc = c; 1079 gc = c;
1069 if (c == '\0') { 1080 if (c == '\0') {
1070 int ch = fgetc(fp); 1081 int ch = fgetc(fp);
@@ -1541,7 +1552,12 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1541 "quiet\0" No_argument "n" 1552 "quiet\0" No_argument "n"
1542 "silent\0" No_argument "n" 1553 "silent\0" No_argument "n"
1543 "expression\0" Required_argument "e" 1554 "expression\0" Required_argument "e"
1555# if !ENABLE_PLATFORM_MINGW32
1544 "file\0" Required_argument "f"; 1556 "file\0" Required_argument "f";
1557# else
1558 "file\0" Required_argument "f"
1559 "binary\0" No_argument "b";
1560# endif
1545#endif 1561#endif
1546 1562
1547 INIT_G(); 1563 INIT_G();
@@ -1565,6 +1581,7 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1565 */ 1581 */
1566 opt = getopt32long(argv, "^" 1582 opt = getopt32long(argv, "^"
1567 "i::rEne:*f:*" 1583 "i::rEne:*f:*"
1584 IF_PLATFORM_MINGW32("b")
1568 "\0" "nn"/*count -n*/, 1585 "\0" "nn"/*count -n*/,
1569 sed_longopts, 1586 sed_longopts,
1570 &opt_i, &opt_e, &opt_f, 1587 &opt_i, &opt_e, &opt_f,
@@ -1578,6 +1595,10 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1578 G.regex_type |= REG_EXTENDED; // -r or -E 1595 G.regex_type |= REG_EXTENDED; // -r or -E
1579 //if (opt & 8) 1596 //if (opt & 8)
1580 // G.be_quiet++; // -n (implemented with a counter instead) 1597 // G.be_quiet++; // -n (implemented with a counter instead)
1598#if ENABLE_PLATFORM_MINGW32
1599 if (opt & 0x40)
1600 G.keep_cr = 1;
1601#endif
1581 while (opt_e) { // -e 1602 while (opt_e) { // -e
1582 add_cmd_block(llist_pop(&opt_e)); 1603 add_cmd_block(llist_pop(&opt_e));
1583 } 1604 }
diff --git a/editors/vi.c b/editors/vi.c
index 34932f60c..e59083ddb 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -112,6 +112,19 @@
112//config: help 112//config: help
113//config: Enable the editor to set some (ai, ic, showmatch) options. 113//config: Enable the editor to set some (ai, ic, showmatch) options.
114//config: 114//config:
115//config:config FEATURE_VI_FILE_FORMAT
116//config: bool "Enable detection of file format"
117//config: default y
118//config: depends on VI && FEATURE_VI_SETOPTS && PLATFORM_MINGW32
119//config: help
120//config: Enable the editor to detect the format of files it reads
121//config: so they can be written out with the appropriate line
122//config: endings. Also allow files to be edited in binary mode.
123//config:
124//config: This enables the 'fileformat', 'fileformats' and 'binary'
125//config: options and the '-b' command line flag.
126//config:
127//config:
115//config:config FEATURE_VI_SET 128//config:config FEATURE_VI_SET
116//config: bool "Support :set" 129//config: bool "Support :set"
117//config: default y 130//config: default y
@@ -181,9 +194,12 @@
181//kbuild:lib-$(CONFIG_VI) += vi.o 194//kbuild:lib-$(CONFIG_VI) += vi.o
182 195
183//usage:#define vi_trivial_usage 196//usage:#define vi_trivial_usage
184//usage: IF_FEATURE_VI_COLON("[-c CMD] ")IF_FEATURE_VI_READONLY("[-R] ")"[-H] [FILE]..." 197//usage: IF_FEATURE_VI_FILE_FORMAT("[-b] ")IF_FEATURE_VI_COLON("[-c CMD] ")IF_FEATURE_VI_READONLY("[-R] ")"[-H] [FILE]..."
185//usage:#define vi_full_usage "\n\n" 198//usage:#define vi_full_usage "\n\n"
186//usage: "Edit FILE\n" 199//usage: "Edit FILE\n"
200//usage: IF_FEATURE_VI_FILE_FORMAT(
201//usage: "\n -b Edit file in binary mode"
202//usage: )
187//usage: IF_FEATURE_VI_COLON( 203//usage: IF_FEATURE_VI_COLON(
188//usage: "\n -c CMD Initial command to run ($EXINIT and ~/.exrc also available)" 204//usage: "\n -c CMD Initial command to run ($EXINIT and ~/.exrc also available)"
189//usage: ) 205//usage: )
@@ -198,6 +214,9 @@
198#if ENABLE_FEATURE_VI_REGEX_SEARCH 214#if ENABLE_FEATURE_VI_REGEX_SEARCH
199# include <regex.h> 215# include <regex.h>
200#endif 216#endif
217#if ENABLE_PLATFORM_MINGW32
218# include "BB_VER.h"
219#endif
201 220
202// the CRASHME code is unmaintained, and doesn't currently build 221// the CRASHME code is unmaintained, and doesn't currently build
203#define ENABLE_FEATURE_VI_CRASHME 0 222#define ENABLE_FEATURE_VI_CRASHME 0
@@ -224,7 +243,11 @@
224 243
225#endif 244#endif
226 245
246#if !ENABLE_PLATFORM_MINGW32
227#define isbackspace(c) ((c) == term_orig.c_cc[VERASE] || (c) == 8 || (c) == 127) 247#define isbackspace(c) ((c) == term_orig.c_cc[VERASE] || (c) == 8 || (c) == 127)
248#else
249#define isbackspace(c) ((c) == 8 || (c) == 127)
250#endif
228 251
229enum { 252enum {
230 MAX_TABSTOP = 32, // sanity limit 253 MAX_TABSTOP = 32, // sanity limit
@@ -298,6 +321,7 @@ struct globals {
298 321
299 // the rest 322 // the rest
300#if ENABLE_FEATURE_VI_SETOPTS 323#if ENABLE_FEATURE_VI_SETOPTS
324#if !ENABLE_FEATURE_VI_FILE_FORMAT
301 smallint vi_setops; // set by setops() 325 smallint vi_setops; // set by setops()
302#define VI_AUTOINDENT (1 << 0) 326#define VI_AUTOINDENT (1 << 0)
303#define VI_EXPANDTAB (1 << 1) 327#define VI_EXPANDTAB (1 << 1)
@@ -305,6 +329,19 @@ struct globals {
305#define VI_IGNORECASE (1 << 3) 329#define VI_IGNORECASE (1 << 3)
306#define VI_SHOWMATCH (1 << 4) 330#define VI_SHOWMATCH (1 << 4)
307#define VI_TABSTOP (1 << 5) 331#define VI_TABSTOP (1 << 5)
332#else
333 int vi_setops; // set by setops()
334#define VI_AUTOINDENT (1 << 0)
335#define VI_BINARY (1 << 1)
336#define VI_EXPANDTAB (1 << 2)
337#define VI_FILEFORMAT (1 << 3)
338#define VI_FILEFORMATS (1 << 4)
339#define VI_ERR_METHOD (1 << 5)
340#define VI_IGNORECASE (1 << 6)
341#define VI_SHOWMATCH (1 << 7)
342#define VI_TABSTOP (1 << 8)
343#define binary (vi_setops & VI_BINARY )
344#endif
308#define autoindent (vi_setops & VI_AUTOINDENT) 345#define autoindent (vi_setops & VI_AUTOINDENT)
309#define expandtab (vi_setops & VI_EXPANDTAB ) 346#define expandtab (vi_setops & VI_EXPANDTAB )
310#define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash 347#define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash
@@ -313,11 +350,25 @@ struct globals {
313// order of constants and strings must match 350// order of constants and strings must match
314#define OPTS_STR \ 351#define OPTS_STR \
315 "ai\0""autoindent\0" \ 352 "ai\0""autoindent\0" \
353 IF_FEATURE_VI_FILE_FORMAT("bin\0""binary\0") \
316 "et\0""expandtab\0" \ 354 "et\0""expandtab\0" \
355 IF_FEATURE_VI_FILE_FORMAT("ff\0""fileformat\0") \
356 IF_FEATURE_VI_FILE_FORMAT("ffs\0""fileformats\0") \
317 "fl\0""flash\0" \ 357 "fl\0""flash\0" \
318 "ic\0""ignorecase\0" \ 358 "ic\0""ignorecase\0" \
319 "sm\0""showmatch\0" \ 359 "sm\0""showmatch\0" \
320 "ts\0""tabstop\0" 360 "ts\0""tabstop\0"
361
362#define FF_DOS 0
363#define FF_UNIX 1
364
365#define FF_STR \
366 "dos\0" \
367 "unix\0"
368
369#define FFS_STR \
370 "dos,unix\0" \
371 "unix,dos\0"
321#else 372#else
322#define autoindent (0) 373#define autoindent (0)
323#define expandtab (0) 374#define expandtab (0)
@@ -384,6 +435,10 @@ struct globals {
384 int newindent; // autoindent value for 'O'/'cc' commands 435 int newindent; // autoindent value for 'O'/'cc' commands
385 // or -1 to use indent from previous line 436 // or -1 to use indent from previous line
386#endif 437#endif
438#if ENABLE_FEATURE_VI_FILE_FORMAT
439 smallint fileformat;
440 smallint fileformats;
441#endif
387 smallint cmd_error; 442 smallint cmd_error;
388 443
389 // former statics 444 // former statics
@@ -511,6 +566,8 @@ struct globals {
511#define last_search_pattern (G.last_search_pattern) 566#define last_search_pattern (G.last_search_pattern)
512#define char_insert__indentcol (G.char_insert__indentcol) 567#define char_insert__indentcol (G.char_insert__indentcol)
513#define newindent (G.newindent ) 568#define newindent (G.newindent )
569#define fileformat (G.fileformat )
570#define fileformats (G.fileformats )
514#define cmd_error (G.cmd_error ) 571#define cmd_error (G.cmd_error )
515 572
516#define edit_file__cur_line (G.edit_file__cur_line) 573#define edit_file__cur_line (G.edit_file__cur_line)
@@ -615,6 +672,23 @@ static ALWAYS_INLINE int query_screen_dimensions(void)
615// sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready) 672// sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready)
616static int mysleep(int hund) 673static int mysleep(int hund)
617{ 674{
675#if ENABLE_PLATFORM_MINGW32
676 HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
677 DWORD ret;
678
679 if (hund == 0) {
680 // Allow two events in the queue. Otherwise pasted test isn't
681 // displayed because there's still a key release event waiting
682 // after the last character is processed.
683 DWORD nevent_out;
684
685 ret = GetNumberOfConsoleInputEvents(h, &nevent_out);
686 return ret != 0 ? (nevent_out > 2) : 0;
687 }
688 fflush_all();
689 ret = WaitForSingleObject(h, hund*10);
690 return ret != WAIT_TIMEOUT;
691#else
618 struct pollfd pfd[1]; 692 struct pollfd pfd[1];
619 693
620 if (hund != 0) 694 if (hund != 0)
@@ -623,6 +697,7 @@ static int mysleep(int hund)
623 pfd[0].fd = STDIN_FILENO; 697 pfd[0].fd = STDIN_FILENO;
624 pfd[0].events = POLLIN; 698 pfd[0].events = POLLIN;
625 return safe_poll(pfd, 1, hund*10) > 0; 699 return safe_poll(pfd, 1, hund*10) > 0;
700#endif
626} 701}
627 702
628//----- Set terminal attributes -------------------------------- 703//----- Set terminal attributes --------------------------------
@@ -1978,6 +2053,18 @@ static char *yank_delete(char *start, char *stop, int buftype, int yf, int undo)
1978 return p; 2053 return p;
1979} 2054}
1980 2055
2056#if ENABLE_PLATFORM_MINGW32
2057static int count_cr(char *p, int len)
2058{
2059 int i, cnt;
2060
2061 for (i = cnt = 0; i < len; ++i)
2062 if (p[i] == '\n')
2063 ++cnt;
2064 return cnt;
2065}
2066#endif
2067
1981// might reallocate text[]! 2068// might reallocate text[]!
1982static int file_insert(const char *fn, char *p, int initial) 2069static int file_insert(const char *fn, char *p, int initial)
1983{ 2070{
@@ -1990,7 +2077,13 @@ static int file_insert(const char *fn, char *p, int initial)
1990 if (p > end) 2077 if (p > end)
1991 p = end; 2078 p = end;
1992 2079
2080#if !ENABLE_PLATFORM_MINGW32
1993 fd = open(fn, O_RDONLY); 2081 fd = open(fn, O_RDONLY);
2082#elif ENABLE_FEATURE_VI_FILE_FORMAT
2083 fd = open(fn, O_RDONLY | (!binary ? _O_TEXT : 0));
2084#else
2085 fd = open(fn, O_RDONLY | _O_TEXT);
2086#endif
1994 if (fd < 0) { 2087 if (fd < 0) {
1995 if (!initial) 2088 if (!initial)
1996 status_line_bold_errno(fn); 2089 status_line_bold_errno(fn);
@@ -2013,8 +2106,15 @@ static int file_insert(const char *fn, char *p, int initial)
2013 status_line_bold_errno(fn); 2106 status_line_bold_errno(fn);
2014 p = text_hole_delete(p, p + size - 1, NO_UNDO); // un-do buffer insert 2107 p = text_hole_delete(p, p + size - 1, NO_UNDO); // un-do buffer insert
2015 } else if (cnt < size) { 2108 } else if (cnt < size) {
2109#if ENABLE_PLATFORM_MINGW32
2110 // On WIN32 a partial read might just mean CRs have been removed
2111 int cnt_cr = cnt + count_cr(p, cnt);
2112#endif
2016 // There was a partial read, shrink unused space 2113 // There was a partial read, shrink unused space
2017 p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO); 2114 p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO);
2115#if ENABLE_PLATFORM_MINGW32
2116 if (cnt_cr < size)
2117#endif
2018 status_line_bold("can't read '%s'", fn); 2118 status_line_bold("can't read '%s'", fn);
2019 } 2119 }
2020# if ENABLE_FEATURE_VI_UNDO 2120# if ENABLE_FEATURE_VI_UNDO
@@ -2022,6 +2122,10 @@ static int file_insert(const char *fn, char *p, int initial)
2022 undo_push_insert(p, size, ALLOW_UNDO); 2122 undo_push_insert(p, size, ALLOW_UNDO);
2023 } 2123 }
2024# endif 2124# endif
2125#if ENABLE_FEATURE_VI_FILE_FORMAT
2126 if (initial && cnt > 0)
2127 fileformat = cnt == size ? FF_UNIX : FF_DOS;
2128#endif
2025 fi: 2129 fi:
2026 close(fd); 2130 close(fd);
2027 2131
@@ -2312,6 +2416,9 @@ static int init_text_buffer(char *fn)
2312 free(text); 2416 free(text);
2313 text_size = 10240; 2417 text_size = 10240;
2314 screenbegin = dot = end = text = xzalloc(text_size); 2418 screenbegin = dot = end = text = xzalloc(text_size);
2419#if ENABLE_FEATURE_VI_FILE_FORMAT
2420 fileformat = fileformats;
2421#endif
2315 2422
2316 update_filename(fn); 2423 update_filename(fn);
2317 rc = file_insert(fn, text, 1); 2424 rc = file_insert(fn, text, 1);
@@ -2358,6 +2465,13 @@ static uintptr_t string_insert(char *p, const char *s, int undo) // insert the s
2358static int file_write(char *fn, char *first, char *last) 2465static int file_write(char *fn, char *first, char *last)
2359{ 2466{
2360 int fd, cnt, charcnt; 2467 int fd, cnt, charcnt;
2468#if ENABLE_PLATFORM_MINGW32
2469# if ENABLE_FEATURE_VI_FILE_FORMAT
2470# define dos (!binary && fileformat == FF_DOS)
2471# else
2472# define dos (1)
2473# endif
2474#endif
2361 2475
2362 if (fn == 0) { 2476 if (fn == 0) {
2363 status_line_bold("No current filename"); 2477 status_line_bold("No current filename");
@@ -2366,12 +2480,22 @@ static int file_write(char *fn, char *first, char *last)
2366 // By popular request we do not open file with O_TRUNC, 2480 // By popular request we do not open file with O_TRUNC,
2367 // but instead ftruncate() it _after_ successful write. 2481 // but instead ftruncate() it _after_ successful write.
2368 // Might reduce amount of data lost on power fail etc. 2482 // Might reduce amount of data lost on power fail etc.
2483#if !ENABLE_PLATFORM_MINGW32
2369 fd = open(fn, (O_WRONLY | O_CREAT), 0666); 2484 fd = open(fn, (O_WRONLY | O_CREAT), 0666);
2485#else
2486 fd = open(fn, (O_WRONLY | O_CREAT | (dos ? _O_TEXT : 0)), 0666);
2487#endif
2370 if (fd < 0) 2488 if (fd < 0)
2371 return -1; 2489 return -1;
2372 cnt = last - first + 1; 2490 cnt = last - first + 1;
2373 charcnt = full_write(fd, first, cnt); 2491 charcnt = full_write(fd, first, cnt);
2492#if !ENABLE_PLATFORM_MINGW32
2374 ftruncate(fd, charcnt); 2493 ftruncate(fd, charcnt);
2494#else
2495 // If file was written in text mode it will be bigger so adjust
2496 // the truncation to match.
2497 ftruncate(fd, charcnt + (dos ? count_cr(first, cnt) : 0));
2498#endif
2375 if (charcnt == cnt) { 2499 if (charcnt == cnt) {
2376 // good write 2500 // good write
2377 //modified_count = FALSE; 2501 //modified_count = FALSE;
@@ -2660,6 +2784,7 @@ static void setops(char *args, int flg_no)
2660 2784
2661 index = 1 << (index >> 1); // convert to VI_bit 2785 index = 1 << (index >> 1); // convert to VI_bit
2662 2786
2787#if !ENABLE_FEATURE_VI_FILE_FORMAT
2663 if (index & VI_TABSTOP) { 2788 if (index & VI_TABSTOP) {
2664 int t; 2789 int t;
2665 if (!eq || flg_no) // no "=NNN" or it is "notabstop"? 2790 if (!eq || flg_no) // no "=NNN" or it is "notabstop"?
@@ -2670,11 +2795,43 @@ static void setops(char *args, int flg_no)
2670 tabstop = t; 2795 tabstop = t;
2671 return; 2796 return;
2672 } 2797 }
2798#else
2799 if (index & (VI_TABSTOP | VI_FILEFORMAT | VI_FILEFORMATS)) {
2800 if (!eq || flg_no) // no "=NNN" or it is "notabstop"?
2801 goto bad;
2802 if (index & VI_TABSTOP) {
2803 int t = bb_strtou(eq + 1, NULL, 10);
2804 if (t <= 0 || t > MAX_TABSTOP)
2805 goto bad;
2806 tabstop = t;
2807 return;
2808 } else if (index & VI_FILEFORMAT) {
2809 int t = index_in_strings(FF_STR, eq + 1);
2810 if (t < 0)
2811 goto bad;
2812 if (fileformat != t)
2813 modified_count++;
2814 fileformat = t;
2815 return;
2816 } else { // VI_FILEFORMATS
2817 int t = index_in_strings(FFS_STR, eq + 1);
2818 if (t < 0)
2819 goto bad;
2820 fileformats = t;
2821 return;
2822 }
2823 }
2824#endif
2673 if (eq) goto bad; // boolean option has "="? 2825 if (eq) goto bad; // boolean option has "="?
2674 if (flg_no) { 2826 if (flg_no) {
2675 vi_setops &= ~index; 2827 vi_setops &= ~index;
2676 } else { 2828 } else {
2677 vi_setops |= index; 2829 vi_setops |= index;
2830#if ENABLE_FEATURE_VI_FILE_FORMAT
2831 if (index == VI_BINARY) {
2832 vi_setops &= ~VI_EXPANDTAB;
2833 }
2834#endif
2678 } 2835 }
2679} 2836}
2680# endif 2837# endif
@@ -3166,6 +3323,7 @@ static void colon(char *buf)
3166 if (!args[0] || strcmp(args, "all") == 0) { 3323 if (!args[0] || strcmp(args, "all") == 0) {
3167 // print out values of all options 3324 // print out values of all options
3168# if ENABLE_FEATURE_VI_SETOPTS 3325# if ENABLE_FEATURE_VI_SETOPTS
3326# if !ENABLE_FEATURE_VI_FILE_FORMAT
3169 status_line_bold( 3327 status_line_bold(
3170 "%sautoindent " 3328 "%sautoindent "
3171 "%sexpandtab " 3329 "%sexpandtab "
@@ -3180,6 +3338,28 @@ static void colon(char *buf)
3180 showmatch ? "" : "no", 3338 showmatch ? "" : "no",
3181 tabstop 3339 tabstop
3182 ); 3340 );
3341# else // ENABLE_FEATURE_VI_FILE_FORMAT
3342 unsigned int mask = 1, j = 0;
3343 go_bottom_and_clear_to_eol();
3344 for (;;) {
3345 const char *name = nth_string(OPTS_STR, 2 * j + 1);
3346 if (!name[0])
3347 break;
3348 if (mask == VI_FILEFORMAT)
3349 printf("%s=%s ", name, nth_string(FF_STR, fileformat));
3350 else if (mask == VI_FILEFORMATS)
3351 printf("%s=%s ", name, nth_string(FFS_STR, fileformats));
3352 else if (mask == VI_TABSTOP)
3353 printf("%s=%u ", name, tabstop);
3354 else
3355 printf("%s%s ", vi_setops & mask ? "" : "no", name);
3356 if (j++ == 4)
3357 bb_putchar('\n');
3358 mask <<= 1;
3359 }
3360 bb_putchar('\n');
3361 Hit_Return();
3362# endif
3183# endif 3363# endif
3184 goto ret; 3364 goto ret;
3185 } 3365 }
@@ -4934,17 +5114,20 @@ static void edit_file(char *fn)
4934} 5114}
4935 5115
4936#define VI_OPTSTR \ 5116#define VI_OPTSTR \
5117 IF_FEATURE_VI_FILE_FORMAT("b") \
4937 IF_FEATURE_VI_CRASHME("C") \ 5118 IF_FEATURE_VI_CRASHME("C") \
4938 IF_FEATURE_VI_COLON("c:*") \ 5119 IF_FEATURE_VI_COLON("c:*") \
4939 "Hh" \ 5120 "Hh" \
4940 IF_FEATURE_VI_READONLY("R") 5121 IF_FEATURE_VI_READONLY("R")
4941 5122
4942enum { 5123enum {
5124 IF_FEATURE_VI_FILE_FORMAT(OPTBIT_b,)
4943 IF_FEATURE_VI_CRASHME(OPTBIT_C,) 5125 IF_FEATURE_VI_CRASHME(OPTBIT_C,)
4944 IF_FEATURE_VI_COLON(OPTBIT_c,) 5126 IF_FEATURE_VI_COLON(OPTBIT_c,)
4945 OPTBIT_H, 5127 OPTBIT_H,
4946 OPTBIT_h, 5128 OPTBIT_h,
4947 IF_FEATURE_VI_READONLY(OPTBIT_R,) 5129 IF_FEATURE_VI_READONLY(OPTBIT_R,)
5130 OPT_b = IF_FEATURE_VI_FILE_FORMAT( (1 << OPTBIT_b)) + 0,
4948 OPT_C = IF_FEATURE_VI_CRASHME( (1 << OPTBIT_C)) + 0, 5131 OPT_C = IF_FEATURE_VI_CRASHME( (1 << OPTBIT_C)) + 0,
4949 OPT_c = IF_FEATURE_VI_COLON( (1 << OPTBIT_c)) + 0, 5132 OPT_c = IF_FEATURE_VI_COLON( (1 << OPTBIT_c)) + 0,
4950 OPT_H = 1 << OPTBIT_H, 5133 OPT_H = 1 << OPTBIT_H,
@@ -4981,6 +5164,10 @@ int vi_main(int argc, char **argv)
4981 //vi_setops = 0; 5164 //vi_setops = 0;
4982 opts = getopt32(argv, VI_OPTSTR IF_FEATURE_VI_COLON(, &initial_cmds)); 5165 opts = getopt32(argv, VI_OPTSTR IF_FEATURE_VI_COLON(, &initial_cmds));
4983 5166
5167#if ENABLE_FEATURE_VI_FILE_FORMAT
5168 if (opts & OPT_b)
5169 vi_setops |= VI_BINARY;
5170#endif
4984#if ENABLE_FEATURE_VI_CRASHME 5171#if ENABLE_FEATURE_VI_CRASHME
4985 if (opts & OPT_C) 5172 if (opts & OPT_C)
4986 crashme = 1; 5173 crashme = 1;
@@ -5016,7 +5203,11 @@ int vi_main(int argc, char **argv)
5016 5203
5017 // .exrc must belong to and only be writable by user 5204 // .exrc must belong to and only be writable by user
5018 if (stat(exrc, &st) == 0) { 5205 if (stat(exrc, &st) == 0) {
5206# if !ENABLE_PLATFORM_MINGW32
5019 if ((st.st_mode & (S_IWGRP|S_IWOTH)) == 0 5207 if ((st.st_mode & (S_IWGRP|S_IWOTH)) == 0
5208# else
5209 if (1
5210# endif
5020 && st.st_uid == getuid() 5211 && st.st_uid == getuid()
5021 ) { 5212 ) {
5022 cmds = xmalloc_open_read_close(exrc, NULL); 5213 cmds = xmalloc_open_read_close(exrc, NULL);
diff --git a/examples/mswin-build/README b/examples/mswin-build/README
new file mode 100644
index 000000000..e1d550d74
--- /dev/null
+++ b/examples/mswin-build/README
@@ -0,0 +1,26 @@
1These scripts can be used to cross-compile busybox-w32 on a
2Fedora Linux system with mingw-w64 and llvm-mingw toolchains.
3The former are available from the Fedora repositories; the
4latter needs to be downloaded and installed from:
5
6 https://github.com/mstorsjo/llvm-mingw
7
8The script should be run from the directory above a git repository
9named busybox-w32. The builds are performed in the directories
10named in the TARGETS variable in the scripts. Previous copies of
11these directories are deleted.
12
13The scripts check out the master branch of the git repository. You
14should edit the script if you wish to build from a different commit.
15
16The build time recorded in the executables is the time of the checked
17out commit. This may not result in a perfectly reproducible build
18but it's a step in that direction.
19
20The release build performs some additional optimisation and takes
21slightly longer as a result.
22
23The busybox-w32 help message includes information about the build
24platform. Obtaining this information is very specific to the
25platform used: you may need to adjust this if building on something
26other than Fedora.
diff --git a/examples/mswin-build/mkprerelease b/examples/mswin-build/mkprerelease
new file mode 100755
index 000000000..7562c8557
--- /dev/null
+++ b/examples/mswin-build/mkprerelease
@@ -0,0 +1,84 @@
1#!/bin/sh
2#
3# Build busybox prerelease binaries
4#
5TARGETS="build_pre_32 build_pre_64 build_pre_64a build_pre_64u"
6
7# If an argument is supplied it overrides the default source directory.
8SRC=busybox-w32
9if [ $# -eq 1 ]
10then
11 SRC=$1
12fi
13
14if [ ! -d $SRC ]
15then
16 echo "$SRC doesn't exist"
17 exit 0
18fi
19
20# remove old and make new build directories
21for i in $TARGETS
22do
23 rm -rf $i
24 cp -rp $SRC $i
25done
26
27# apply default configuration
28for i in $TARGETS
29do
30 (
31 if [ $i = "build_pre_64" ]
32 then
33 CONFIG=mingw64_defconfig
34 elif [ $i = "build_pre_64u" ]
35 then
36 CONFIG=mingw64u_defconfig
37 elif [ $i = "build_pre_64a" ]
38 then
39 CONFIG=mingw64a_defconfig
40 PATH="/data2/llvm/current/bin:$PATH"
41 elif [ $i = "build_pre_32" ]
42 then
43 CONFIG=mingw32_defconfig
44 fi
45
46 cd $i
47 git checkout master
48 SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) TZ=UTC0 \
49 make ${CONFIG}
50 )
51done
52
53# perform build
54for i in $TARGETS
55do
56 BITS=64
57 if [ $i = "build_pre_32" ]
58 then
59 BITS=32;
60 fi
61
62 (
63 cd $i
64 if [ $i = "build_pre_64a" ]
65 then
66 # /data2/llvm/current should be a symlink
67 PATH="/data2/llvm/current/bin:$PATH"
68 VERSION=$(readlink /data2/llvm/current)
69 else
70 GCCV=$(rpm -q --qf '%{name} %{version}-%{release}\n' mingw${BITS}-gcc)
71 CRTV=$(rpm -q --qf '%{name} %{version}-%{release}\n' mingw${BITS}-crt)
72 VERSION="$GCCV; $CRTV"
73 fi
74 SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) TZ=UTC0 \
75 make -j $(nproc) EXTRAVERSION="-$(git describe --match=FRP | sed 's/FRP/PRE/')" MINGW_VER="$VERSION"
76 )
77done
78
79# Check the expected binaries exist
80echo
81for i in $TARGETS
82do
83 ls -l $i/busybox.exe
84done
diff --git a/examples/mswin-build/mkrelease b/examples/mswin-build/mkrelease
new file mode 100755
index 000000000..2f59dce13
--- /dev/null
+++ b/examples/mswin-build/mkrelease
@@ -0,0 +1,104 @@
1#!/bin/sh
2#
3# Build 32- and 64-bit busybox binaries for release
4#
5TARGETS="build_32 build_64 build_64a build_64u"
6
7if [ ! -d busybox-w32 ]
8then
9 echo "busybox-w32 doesn't exist"
10 exit 0
11fi
12
13# remove old and make new build directories
14for i in $TARGETS
15do
16 rm -rf $i
17 cp -rp busybox-w32 $i
18done
19
20# apply default configuration
21for i in $TARGETS
22do
23 (
24 if [ $i = "build_64" ]
25 then
26 CONFIG=mingw64_defconfig
27 BITS=64
28 elif [ $i = "build_64a" ]
29 then
30 PATH="/data2/llvm/current/bin:$PATH"
31 CONFIG=mingw64a_defconfig
32 BITS=64
33 elif [ $i = "build_64u" ]
34 then
35 CONFIG=mingw64u_defconfig
36 BITS=64
37 elif [ $i = "build_32" ]
38 then
39 CONFIG=mingw32_defconfig
40 BITS=32
41 fi
42
43 cd $i
44 git checkout master
45 SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) TZ=UTC0 \
46 make ${CONFIG}
47
48 # The clang/aarch64 build is not subject to optimisation. The
49 # '-flto' option increased the size of the binary slightly (0.23%)
50 # and decreased the time to run the testsuite slightly (0.33%).
51 # It hardly seems worth bothering about.
52 #
53 if [ $i != "build_64a" ]
54 then
55 # link time optimisation, stack protection
56 sed -e 's/^CONFIG_EXTRA_CFLAGS="\(.*\)"$/CONFIG_EXTRA_CFLAGS="\1 -flto -fstack-protector --param=ssp-buffer-size=4"/' \
57 -e 's/^CONFIG_EXTRA_CFLAGS=" /CONFIG_EXTRA_CFLAGS="/' \
58 -e 's/^CONFIG_EXTRA_LDLIBS="\(.*\)"$/CONFIG_EXTRA_LDLIBS="\1 -l:libssp.a"/' \
59 -e 's/^CONFIG_EXTRA_LDLIBS=" /CONFIG_EXTRA_LDLIBS="/' \
60 -i .config
61 # does ld support --disable-reloc-section?
62 eval $(grep CONFIG_CROSS_COMPILER_PREFIX .config)
63 [ $BITS -eq 32 ] && [ -n "$CONFIG_CROSS_COMPILER_PREFIX" ] && \
64 ${CONFIG_CROSS_COMPILER_PREFIX}ld --help | \
65 grep -q disable-reloc-section &&
66 sed -e 's/^CONFIG_EXTRA_LDFLAGS="\(.*\)"$/CONFIG_EXTRA_LDFLAGS="\1 -Wl,--disable-reloc-section"/' \
67 -e 's/^CONFIG_EXTRA_LDFLAGS=" /CONFIG_EXTRA_LDFLAGS="/' \
68 -i .config
69 fi
70 )
71done
72
73# perform build
74for i in $TARGETS
75do
76 BITS=64
77 if [ $i = "build_32" ]
78 then
79 BITS=32
80 fi
81
82 (
83 cd $i
84 if [ $i = "build_64a" ]
85 then
86 # /data2/llvm/current should be a symlink
87 PATH="/data2/llvm/current/bin:$PATH"
88 VERSION=$(readlink /data2/llvm/current)
89 else
90 GCCV=$(rpm -q --qf '%{name} %{version}-%{release}\n' mingw${BITS}-gcc)
91 CRTV=$(rpm -q --qf '%{name} %{version}-%{release}\n' mingw${BITS}-crt)
92 VERSION="$GCCV; $CRTV"
93 fi
94 SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) TZ=UTC0 \
95 make -j $(nproc) EXTRAVERSION="-`git describe --match=FRP`" MINGW_VER="$VERSION"
96 )
97done
98
99# Check the expected binaries exist
100echo
101for i in $TARGETS
102do
103 ls -l $i/busybox.exe
104done
diff --git a/findutils/find.c b/findutils/find.c
index 31c996988..c1d03c9f6 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -135,7 +135,7 @@
135//config:config FEATURE_FIND_XDEV 135//config:config FEATURE_FIND_XDEV
136//config: bool "Enable -xdev: 'stay in filesystem'" 136//config: bool "Enable -xdev: 'stay in filesystem'"
137//config: default y 137//config: default y
138//config: depends on FIND 138//config: depends on FIND && (PLATFORM_POSIX || FEATURE_EXTRA_FILE_DATA)
139//config: 139//config:
140//config:config FEATURE_FIND_MAXDEPTH 140//config:config FEATURE_FIND_MAXDEPTH
141//config: bool "Enable -mindepth N and -maxdepth N" 141//config: bool "Enable -mindepth N and -maxdepth N"
@@ -153,12 +153,12 @@
153//config:config FEATURE_FIND_INUM 153//config:config FEATURE_FIND_INUM
154//config: bool "Enable -inum: inode number matching" 154//config: bool "Enable -inum: inode number matching"
155//config: default y 155//config: default y
156//config: depends on FIND 156//config: depends on FIND && (PLATFORM_POSIX || FEATURE_EXTRA_FILE_DATA)
157//config: 157//config:
158//config:config FEATURE_FIND_SAMEFILE 158//config:config FEATURE_FIND_SAMEFILE
159//config: bool "Enable -samefile: reference file matching" 159//config: bool "Enable -samefile: reference file matching"
160//config: default y 160//config: default y
161//config: depends on FIND 161//config: depends on FIND && (PLATFORM_POSIX || FEATURE_EXTRA_FILE_DATA)
162//config: help 162//config: help
163//config: Support the 'find -samefile' option for searching by a reference file. 163//config: Support the 'find -samefile' option for searching by a reference file.
164//config: 164//config:
@@ -281,7 +281,7 @@
281//config:config FEATURE_FIND_LINKS 281//config:config FEATURE_FIND_LINKS
282//config: bool "Enable -links: link count matching" 282//config: bool "Enable -links: link count matching"
283//config: default y 283//config: default y
284//config: depends on FIND 284//config: depends on FIND && (PLATFORM_POSIX || FEATURE_EXTRA_FILE_DATA)
285//config: help 285//config: help
286//config: Support the 'find -links' option for matching number of links. 286//config: Support the 'find -links' option for matching number of links.
287 287
@@ -1561,7 +1561,11 @@ static action*** parse_params(char **argv)
1561 action_inum *ap; 1561 action_inum *ap;
1562 dbg("%d", __LINE__); 1562 dbg("%d", __LINE__);
1563 ap = ALLOC_ACTION(inum); 1563 ap = ALLOC_ACTION(inum);
1564# if !ENABLE_FEATURE_EXTRA_FILE_DATA
1564 ap->inode_num = xatoul(arg1); 1565 ap->inode_num = xatoul(arg1);
1566# else
1567 ap->inode_num = xatoull(arg1);
1568# endif
1565 } 1569 }
1566#endif 1570#endif
1567#if ENABLE_FEATURE_FIND_SAMEFILE 1571#if ENABLE_FEATURE_FIND_SAMEFILE
diff --git a/findutils/xargs.c b/findutils/xargs.c
index 890c37534..f0abf1a23 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -74,6 +74,11 @@
74 74
75//kbuild:lib-$(CONFIG_XARGS) += xargs.o 75//kbuild:lib-$(CONFIG_XARGS) += xargs.o
76 76
77#if ENABLE_PLATFORM_MINGW32
78#include <conio.h>
79#include "busybox.h"
80#include "NUM_APPLETS.h"
81#endif
77#include "libbb.h" 82#include "libbb.h"
78#include "common_bufsiz.h" 83#include "common_bufsiz.h"
79 84
@@ -111,11 +116,19 @@ struct globals {
111#endif 116#endif
112 const char *eof_str; 117 const char *eof_str;
113 int idx; 118 int idx;
119#if !ENABLE_PLATFORM_MINGW32
114 int fd_tty; 120 int fd_tty;
115 int fd_stdin; 121 int fd_stdin;
122#endif
116#if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL 123#if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL
117 int running_procs; 124 int running_procs;
118 int max_procs; 125 int max_procs;
126# if ENABLE_PLATFORM_MINGW32
127 HANDLE *procs;
128# endif
129#endif
130#if ENABLE_PLATFORM_MINGW32
131 pid_t pid;
119#endif 132#endif
120 smalluint xargs_exitcode; 133 smalluint xargs_exitcode;
121#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES 134#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
@@ -137,6 +150,7 @@ struct globals {
137 G.idx = 0; \ 150 G.idx = 0; \
138 IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.running_procs = 0;) \ 151 IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.running_procs = 0;) \
139 IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.max_procs = 1;) \ 152 IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.max_procs = 1;) \
153 IF_FEATURE_XARGS_SUPPORT_PARALLEL(IF_PLATFORM_MINGW32(G.procs = NULL;)) \
140 G.xargs_exitcode = 0; \ 154 G.xargs_exitcode = 0; \
141 IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__state = NORM;) \ 155 IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__state = NORM;) \
142 IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__q = '\0';) \ 156 IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__q = '\0';) \
@@ -150,7 +164,7 @@ enum {
150 OPTBIT_UPTO_SIZE, 164 OPTBIT_UPTO_SIZE,
151 OPTBIT_EOF_STRING, 165 OPTBIT_EOF_STRING,
152 OPTBIT_EOF_STRING1, 166 OPTBIT_EOF_STRING1,
153 OPTBIT_STDIN_TTY, 167 IF_NOT_PLATFORM_MINGW32( OPTBIT_STDIN_TTY ,)
154 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,) 168 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,)
155 IF_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,) 169 IF_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,)
156 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,) 170 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,)
@@ -163,14 +177,15 @@ enum {
163 OPT_UPTO_SIZE = 1 << OPTBIT_UPTO_SIZE , 177 OPT_UPTO_SIZE = 1 << OPTBIT_UPTO_SIZE ,
164 OPT_EOF_STRING = 1 << OPTBIT_EOF_STRING , /* GNU: -e[<param>] */ 178 OPT_EOF_STRING = 1 << OPTBIT_EOF_STRING , /* GNU: -e[<param>] */
165 OPT_EOF_STRING1 = 1 << OPTBIT_EOF_STRING1, /* SUS: -E<param> */ 179 OPT_EOF_STRING1 = 1 << OPTBIT_EOF_STRING1, /* SUS: -E<param> */
166 OPT_STDIN_TTY = 1 << OPTBIT_STDIN_TTY, 180 OPT_STDIN_TTY = IF_NOT_PLATFORM_MINGW32( (1 << OPTBIT_STDIN_TTY )) + 0,
167 OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0, 181 OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0,
168 OPT_TERMINATE = IF_FEATURE_XARGS_SUPPORT_TERMOPT( (1 << OPTBIT_TERMINATE )) + 0, 182 OPT_TERMINATE = IF_FEATURE_XARGS_SUPPORT_TERMOPT( (1 << OPTBIT_TERMINATE )) + 0,
169 OPT_ZEROTERM = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1 << OPTBIT_ZEROTERM )) + 0, 183 OPT_ZEROTERM = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1 << OPTBIT_ZEROTERM )) + 0,
170 OPT_REPLSTR = IF_FEATURE_XARGS_SUPPORT_REPL_STR( (1 << OPTBIT_REPLSTR )) + 0, 184 OPT_REPLSTR = IF_FEATURE_XARGS_SUPPORT_REPL_STR( (1 << OPTBIT_REPLSTR )) + 0,
171 OPT_REPLSTR1 = IF_FEATURE_XARGS_SUPPORT_REPL_STR( (1 << OPTBIT_REPLSTR1 )) + 0, 185 OPT_REPLSTR1 = IF_FEATURE_XARGS_SUPPORT_REPL_STR( (1 << OPTBIT_REPLSTR1 )) + 0,
172}; 186};
173#define OPTION_STR "+trn:s:e::E:o" \ 187#define OPTION_STR "+trn:s:e::E:" \
188 IF_NOT_PLATFORM_MINGW32( "o") \
174 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \ 189 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \
175 IF_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \ 190 IF_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \
176 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0") \ 191 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0") \
@@ -179,6 +194,83 @@ enum {
179 IF_FEATURE_XARGS_SUPPORT_ARGS_FILE( "a:") 194 IF_FEATURE_XARGS_SUPPORT_ARGS_FILE( "a:")
180 195
181 196
197#if ENABLE_PLATFORM_MINGW32
198static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
199{
200 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
201# if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL
202 if (G.max_procs == 1)
203# endif
204 {
205 if (G.pid > 0)
206 kill(-G.pid, SIGTERM);
207 }
208# if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL
209 else {
210 int i;
211
212 for (i = 0; i < G.running_procs; ++i) {
213 pid_t pid = GetProcessId(G.procs[i]);
214 if (pid > 0)
215 kill(-pid, SIGTERM);
216 }
217 }
218# endif
219 exit(SIGINT << 24);
220 return TRUE;
221 }
222 return FALSE;
223}
224#endif
225
226#if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL && ENABLE_PLATFORM_MINGW32
227static int wait_for_slot(int *idx)
228{
229 int i;
230
231 /* if less than max_procs running, set status to 0, return next free slot */
232 if (G.running_procs < G.max_procs) {
233 *idx = G.running_procs++;
234 return 0;
235 }
236
237check_exit_codes:
238 for (i = G.running_procs - 1; i >= 0; i--) {
239 DWORD status = 0;
240 if (!GetExitCodeProcess(G.procs[i], &status) ||
241 status != STILL_ACTIVE) {
242 CloseHandle(G.procs[i]);
243 if (i + 1 < G.running_procs)
244 G.procs[i] = G.procs[G.running_procs - 1];
245 *idx = G.running_procs - 1;
246 if (!G.max_procs)
247 G.running_procs--;
248 return status;
249 }
250 }
251
252 if (G.running_procs < MAXIMUM_WAIT_OBJECTS)
253 WaitForMultipleObjects((DWORD)G.running_procs, G.procs, FALSE,
254 INFINITE);
255 else {
256 /* Fall back to polling */
257 for (;;) {
258 DWORD nr = i + MAXIMUM_WAIT_OBJECTS > G.running_procs ?
259 MAXIMUM_WAIT_OBJECTS : (DWORD)(G.running_procs - i);
260 DWORD ret = WaitForMultipleObjects(nr, G.procs + i, FALSE, 100);
261
262 if (ret != WAIT_TIMEOUT)
263 break;
264 i += MAXIMUM_WAIT_OBJECTS;
265 if (i > G.running_procs)
266 i = 0;
267 }
268 }
269
270 goto check_exit_codes;
271}
272#endif /* SUPPORT_PARALLEL && PLATFORM_MINGW32 */
273
182/* 274/*
183 * Returns 0 if xargs should continue (but may set G.xargs_exitcode to 123). 275 * Returns 0 if xargs should continue (but may set G.xargs_exitcode to 123).
184 * Else sets G.xargs_exitcode to error code and returns nonzero. 276 * Else sets G.xargs_exitcode to error code and returns nonzero.
@@ -189,6 +281,7 @@ static int xargs_exec(void)
189{ 281{
190 int status; 282 int status;
191 283
284#if !ENABLE_PLATFORM_MINGW32
192 if (option_mask32 & OPT_STDIN_TTY) 285 if (option_mask32 & OPT_STDIN_TTY)
193 xdup2(G.fd_tty, STDIN_FILENO); 286 xdup2(G.fd_tty, STDIN_FILENO);
194 287
@@ -240,6 +333,45 @@ static int xargs_exec(void)
240 } 333 }
241 } 334 }
242#endif 335#endif
336#endif
337
338#if ENABLE_PLATFORM_MINGW32
339 /* Any change to the logic for NOFORK applets must be duplicated
340 * in xargs_main() below. */
341# if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL
342 if (G.max_procs == 1) {
343# endif
344# if ENABLE_FEATURE_PREFER_APPLETS && (NUM_APPLETS > 1)
345 int applet = find_applet_by_name(G.args[0]);
346 if (applet >= 0 && APPLET_IS_NOFORK(applet)) {
347 status = run_nofork_applet(applet, G.args);
348 } else
349# endif
350 {
351 G.pid = spawn(G.args);
352 status = G.pid < 0 ? -1 : wait4pid(G.pid);
353 }
354# if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL
355 }
356 else {
357 int idx;
358 status = !G.running_procs && !G.max_procs ? 0 : wait_for_slot(&idx);
359 if (G.max_procs) {
360 HANDLE p = (HANDLE)mingw_spawn_proc((const char **)G.args);
361 if (p < 0)
362 status = -1;
363 else
364 G.procs[idx] = p;
365 } else {
366 while (G.running_procs) {
367 int status2 = wait_for_slot(&idx);
368 if (status2 && !status)
369 status = status2;
370 }
371 }
372 }
373# endif
374#endif
243 /* Manpage: 375 /* Manpage:
244 * """xargs exits with the following status: 376 * """xargs exits with the following status:
245 * 0 if it succeeds 377 * 0 if it succeeds
@@ -278,8 +410,10 @@ static int xargs_exec(void)
278 ret: 410 ret:
279 if (status != 0) 411 if (status != 0)
280 G.xargs_exitcode = status; 412 G.xargs_exitcode = status;
413#if !ENABLE_PLATFORM_MINGW32
281 if (option_mask32 & OPT_STDIN_TTY) 414 if (option_mask32 & OPT_STDIN_TTY)
282 xdup2(G.fd_stdin, STDIN_FILENO); 415 xdup2(G.fd_stdin, STDIN_FILENO);
416#endif
283 return status; 417 return status;
284} 418}
285 419
@@ -559,6 +693,7 @@ static char* FAST_FUNC process_stdin_with_replace(int n_max_chars, int n_max_arg
559 */ 693 */
560static int xargs_ask_confirmation(void) 694static int xargs_ask_confirmation(void)
561{ 695{
696#if !ENABLE_PLATFORM_MINGW32
562 FILE *tty_stream; 697 FILE *tty_stream;
563 int r; 698 int r;
564 699
@@ -568,6 +703,18 @@ static int xargs_ask_confirmation(void)
568 r = bb_ask_y_confirmation_FILE(tty_stream); 703 r = bb_ask_y_confirmation_FILE(tty_stream);
569 704
570 fclose(tty_stream); 705 fclose(tty_stream);
706#else
707 int r, c, savec;
708
709 fputs(" ?...", stderr);
710 fflush_all();
711 c = savec = getche();
712 while (c != EOF && c != '\r')
713 c = getche();
714 fputs("\n", stderr);
715 fflush_all();
716 r = (savec == 'y' || savec == 'Y');
717#endif
571 718
572 return r; 719 return r;
573} 720}
@@ -575,6 +722,20 @@ static int xargs_ask_confirmation(void)
575# define xargs_ask_confirmation() 1 722# define xargs_ask_confirmation() 1
576#endif 723#endif
577 724
725#if ENABLE_PLATFORM_MINGW32
726// Maximum command length (less a few bytes)
727# define WIN32_MAX_CHARS (32750)
728
729static size_t quote_len(const char *arg)
730{
731 char *s = quote_arg(arg);
732 size_t len = strlen(s);
733
734 free(s);
735 return len;
736}
737#endif
738
578//usage:#define xargs_trivial_usage 739//usage:#define xargs_trivial_usage
579//usage: "[OPTIONS] [PROG ARGS]" 740//usage: "[OPTIONS] [PROG ARGS]"
580//usage:#define xargs_full_usage "\n\n" 741//usage:#define xargs_full_usage "\n\n"
@@ -585,7 +746,9 @@ static int xargs_ask_confirmation(void)
585//usage: IF_FEATURE_XARGS_SUPPORT_ARGS_FILE( 746//usage: IF_FEATURE_XARGS_SUPPORT_ARGS_FILE(
586//usage: "\n -a FILE Read from FILE instead of stdin" 747//usage: "\n -a FILE Read from FILE instead of stdin"
587//usage: ) 748//usage: )
749//usage: IF_NOT_PLATFORM_MINGW32(
588//usage: "\n -o Reopen stdin as /dev/tty" 750//usage: "\n -o Reopen stdin as /dev/tty"
751//usage: )
589//usage: "\n -r Don't run command if input is empty" 752//usage: "\n -r Don't run command if input is empty"
590//usage: "\n -t Print the command on stderr before execution" 753//usage: "\n -t Print the command on stderr before execution"
591//usage: IF_FEATURE_XARGS_SUPPORT_CONFIRMATION( 754//usage: IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(
@@ -618,6 +781,11 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
618 unsigned opt; 781 unsigned opt;
619 int n_max_chars; 782 int n_max_chars;
620 int n_max_arg; 783 int n_max_arg;
784#if ENABLE_PLATFORM_MINGW32
785 int delta = 0;
786 int quote = TRUE;
787 char *old_buf = NULL;
788#endif
621#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM \ 789#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM \
622 || ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR 790 || ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR
623 char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin; 791 char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin;
@@ -628,6 +796,9 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
628 796
629 INIT_G(); 797 INIT_G();
630 798
799#if ENABLE_PLATFORM_MINGW32
800 SetConsoleCtrlHandler(ctrl_handler, TRUE);
801#endif
631 opt = getopt32long(argv, OPTION_STR, 802 opt = getopt32long(argv, OPTION_STR,
632 "no-run-if-empty\0" No_argument "r", 803 "no-run-if-empty\0" No_argument "r",
633 &max_args, &max_chars, &G.eof_str, &G.eof_str 804 &max_args, &max_chars, &G.eof_str, &G.eof_str
@@ -638,7 +809,12 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
638 809
639#if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL 810#if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL
640 if (G.max_procs <= 0) /* -P0 means "run lots of them" */ 811 if (G.max_procs <= 0) /* -P0 means "run lots of them" */
812#if !ENABLE_PLATFORM_MINGW32
641 G.max_procs = 100; /* let's not go crazy high */ 813 G.max_procs = 100; /* let's not go crazy high */
814#else
815 G.max_procs = MAXIMUM_WAIT_OBJECTS;
816 G.procs = xmalloc(sizeof(G.procs[0]) * G.max_procs);
817#endif
642#endif 818#endif
643 819
644#if ENABLE_FEATURE_XARGS_SUPPORT_ARGS_FILE 820#if ENABLE_FEATURE_XARGS_SUPPORT_ARGS_FILE
@@ -665,6 +841,24 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
665 //argc++; 841 //argc++;
666 } 842 }
667 843
844#if ENABLE_PLATFORM_MINGW32
845 /* On Windows the command line may be expanded by the need to quote
846 * arguments, but not if the command is a NOFORK applet. If the rules
847 * to detect this situation change xargs_exec() above will also need
848 * to be updated. */
849# if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL
850 if (G.max_procs == 1)
851# endif
852 {
853# if ENABLE_FEATURE_PREFER_APPLETS && (NUM_APPLETS > 1)
854 int applet = find_applet_by_name(argv[0]);
855 if (applet >= 0 && APPLET_IS_NOFORK(applet)) {
856 quote = FALSE;
857 }
858 }
859# endif
860#endif
861
668 /* 862 /*
669 * The Open Group Base Specifications Issue 6: 863 * The Open Group Base Specifications Issue 6:
670 * "The xargs utility shall limit the command line length such that 864 * "The xargs utility shall limit the command line length such that
@@ -689,7 +883,12 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
689 { 883 {
690 size_t n_chars = 0; 884 size_t n_chars = 0;
691 for (i = 0; argv[i]; i++) { 885 for (i = 0; argv[i]; i++) {
692 n_chars += strlen(argv[i]) + 1; 886#if ENABLE_PLATFORM_MINGW32
887 if (quote)
888 n_chars += quote_len(argv[i]) + 1;
889 else
890#endif
891 n_chars += strlen(argv[i]) + 1;
693 } 892 }
694 n_max_chars -= n_chars; 893 n_max_chars -= n_chars;
695 } 894 }
@@ -736,21 +935,48 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
736 store_param(argv[i]); 935 store_param(argv[i]);
737 } 936 }
738 937
938#if !ENABLE_PLATFORM_MINGW32
739 if (opt & OPT_STDIN_TTY) { 939 if (opt & OPT_STDIN_TTY) {
740 G.fd_tty = xopen(CURRENT_TTY, O_RDONLY); 940 G.fd_tty = xopen(CURRENT_TTY, O_RDONLY);
741 close_on_exec_on(G.fd_tty); 941 close_on_exec_on(G.fd_tty);
742 G.fd_stdin = dup(STDIN_FILENO); 942 G.fd_stdin = dup(STDIN_FILENO);
743 close_on_exec_on(G.fd_stdin); 943 close_on_exec_on(G.fd_stdin);
744 } 944 }
945#endif
745 946
746 initial_idx = G.idx; 947 initial_idx = G.idx;
747 while (1) { 948 while (1) {
748 char *rem; 949 char *rem;
950#if ENABLE_PLATFORM_MINGW32
951 char **args;
952 char **tail = NULL;
953 char *saved_arg = NULL;
954 size_t n_chars;
955#endif
749 956
750 G.idx = initial_idx; 957 G.idx = initial_idx IF_PLATFORM_MINGW32(+ delta);
751 rem = read_args(n_max_chars, n_max_arg, buf); 958 rem = read_args(n_max_chars, n_max_arg, buf);
752 store_param(NULL); 959 store_param(NULL);
753 960
961#if ENABLE_PLATFORM_MINGW32
962 /* Check if quoting expands the command line. If it does we
963 * truncate args[] and preserve the tail for processing later. */
964 args = G.args;
965 if (quote) {
966 skip_read:
967 n_chars = 0;
968 for (i = initial_idx; args[i]; i++) {
969 n_chars += quote_len(args[i]) + 1;
970 if (n_chars > WIN32_MAX_CHARS) {
971 tail = args + i;
972 saved_arg = *tail;
973 *tail = NULL;
974 break;
975 }
976 }
977 }
978#endif
979
754 if (!G.args[initial_idx]) { /* not even one ARG was added? */ 980 if (!G.args[initial_idx]) { /* not even one ARG was added? */
755 if (*rem != '\0') 981 if (*rem != '\0')
756 bb_simple_error_msg_and_die("argument line too long"); 982 bb_simple_error_msg_and_die("argument line too long");
@@ -761,7 +987,9 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
761 987
762 if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) { 988 if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) {
763 const char *fmt = " %s" + 1; 989 const char *fmt = " %s" + 1;
990#if !ENABLE_PLATFORM_MINGW32
764 char **args = G.args; 991 char **args = G.args;
992#endif
765 for (i = 0; args[i]; i++) { 993 for (i = 0; args[i]; i++) {
766 fprintf(stderr, fmt, args[i]); 994 fprintf(stderr, fmt, args[i]);
767 fmt = " %s"; 995 fmt = " %s";
@@ -775,6 +1003,33 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
775 break; /* G.xargs_exitcode is set by xargs_exec() */ 1003 break; /* G.xargs_exitcode is set by xargs_exec() */
776 } 1004 }
777 1005
1006#if ENABLE_PLATFORM_MINGW32
1007 delta = 0;
1008 if (quote && tail) {
1009 /* The command line was truncated. Preload args[] with
1010 * the tail we saved earlier. */
1011 *tail = saved_arg;
1012 n_chars = 0;
1013 for (i = 0; tail[i]; i++) {
1014 args[initial_idx + i] = tail[i];
1015 n_chars += quote_len(tail[i]) + 1;
1016 }
1017 args[initial_idx + i] = NULL;
1018 delta = i;
1019
1020 /* The command line still overflows after quoting.
1021 * Truncate the new args[] and exec it. */
1022 if (n_chars > WIN32_MAX_CHARS)
1023 goto skip_read;
1024
1025 /* The first elements of args[] point to strings in the
1026 * current buf, so we need to preserve it. Allocate a
1027 * new buf for future use. */
1028 free(old_buf);
1029 old_buf = buf;
1030 buf = xzalloc(n_max_chars + 1);
1031 }
1032#endif
778 overlapping_strcpy(buf, rem); 1033 overlapping_strcpy(buf, rem);
779 } /* while */ 1034 } /* while */
780 1035
@@ -782,6 +1037,9 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
782 free(G.args); 1037 free(G.args);
783 free(buf); 1038 free(buf);
784 } 1039 }
1040#if ENABLE_FEATURE_CLEAN_UP && ENABLE_PLATFORM_MINGW32
1041 free(old_buf);
1042#endif
785 1043
786#if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL 1044#if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL
787 G.max_procs = 0; 1045 G.max_procs = 0;
diff --git a/include/.gitignore b/include/.gitignore
index 13a96e018..91575ed3f 100644
--- a/include/.gitignore
+++ b/include/.gitignore
@@ -3,6 +3,7 @@
3/applets.h 3/applets.h
4/applet_tables.h 4/applet_tables.h
5/autoconf.h 5/autoconf.h
6/BB_VER.h
6/bbconfigopts_bz2.h 7/bbconfigopts_bz2.h
7/bbconfigopts.h 8/bbconfigopts.h
8/embedded_scripts.h 9/embedded_scripts.h
diff --git a/include/bb_archive.h b/include/bb_archive.h
index e0ef8fc4e..3422c9656 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -2,6 +2,16 @@
2#ifndef UNARCHIVE_H 2#ifndef UNARCHIVE_H
3#define UNARCHIVE_H 1 3#define UNARCHIVE_H 1
4 4
5#if !defined(BB_ARCHIVE_PUBLIC) && ENABLE_PLATFORM_MINGW32
6/* treat mingw as a non-MMU platform */
7#undef BB_MMU
8#undef USE_FOR_NOMMU
9#undef USE_FOR_MMU
10#define BB_MMU 0
11#define USE_FOR_NOMMU(...) __VA_ARGS__
12#define USE_FOR_MMU(...)
13#endif
14
5PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 15PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
6 16
7enum { 17enum {
@@ -277,7 +287,11 @@ enum {
277 BBUNPK_SEAMLESS_MAGIC = (1 << 31) * ENABLE_ZCAT * SEAMLESS_COMPRESSION, 287 BBUNPK_SEAMLESS_MAGIC = (1 << 31) * ENABLE_ZCAT * SEAMLESS_COMPRESSION,
278}; 288};
279 289
290#if !ENABLE_PLATFORM_MINGW32
280void check_errors_in_children(int signo); 291void check_errors_in_children(int signo);
292#else
293#define check_errors_in_children(s) ((void)0)
294#endif
281#if BB_MMU 295#if BB_MMU
282void fork_transformer(int fd, 296void fork_transformer(int fd,
283 int signature_skipped, 297 int signature_skipped,
diff --git a/include/libbb.h b/include/libbb.h
index 4d6193795..bc1453e12 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -10,6 +10,12 @@
10#ifndef LIBBB_H 10#ifndef LIBBB_H
11#define LIBBB_H 1 11#define LIBBB_H 1
12 12
13#if ENABLE_PLATFORM_MINGW32
14/* We have our own nanosleep(), clock_gettime() and clock_settime(). */
15/* Skip the Windows include file that declares them. */
16# define WIN_PTHREADS_TIME_H
17#endif
18
13#include "platform.h" 19#include "platform.h"
14 20
15#include <ctype.h> 21#include <ctype.h>
@@ -143,6 +149,9 @@
143# include <arpa/inet.h> 149# include <arpa/inet.h>
144#elif defined __APPLE__ 150#elif defined __APPLE__
145# include <netinet/in.h> 151# include <netinet/in.h>
152#elif ENABLE_PLATFORM_MINGW32
153# include <winsock2.h>
154# include <ws2tcpip.h>
146#else 155#else
147# include <arpa/inet.h> 156# include <arpa/inet.h>
148//This breaks on bionic: 157//This breaks on bionic:
@@ -182,7 +191,9 @@
182 191
183/* Some libc's forget to declare these, do it ourself */ 192/* Some libc's forget to declare these, do it ourself */
184 193
194#if !ENABLE_PLATFORM_MINGW32
185extern char **environ; 195extern char **environ;
196#endif
186/* klogctl is in libc's klog.h, but we cheat and not #include that */ 197/* klogctl is in libc's klog.h, but we cheat and not #include that */
187int klogctl(int type, char *b, int len); 198int klogctl(int type, char *b, int len);
188#ifndef PATH_MAX 199#ifndef PATH_MAX
@@ -192,6 +203,13 @@ int klogctl(int type, char *b, int len);
192# define BUFSIZ 4096 203# define BUFSIZ 4096
193#endif 204#endif
194 205
206#if ENABLE_PLATFORM_MINGW32
207# include "mingw.h"
208# define MINGW_SPECIAL(a) mingw_ ## a
209#else
210# define MINGW_SPECIAL(a) a
211#endif
212
195#if __GNUC_PREREQ(5,0) 213#if __GNUC_PREREQ(5,0)
196/* Since musl is apparently unable to get it right and would use 214/* Since musl is apparently unable to get it right and would use
197 * a function call to a single-instruction function of "bswap %eax", 215 * a function call to a single-instruction function of "bswap %eax",
@@ -276,6 +294,20 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
276 : ((T)1 << (sizeof(T)*8-1)) \ 294 : ((T)1 << (sizeof(T)*8-1)) \
277 ) 295 )
278 296
297// UCRT supports both "ll" and "I64", but gcc warns on "I64" with UCRT mingw
298#if ENABLE_PLATFORM_MINGW32 && !defined(_UCRT) && \
299 (!defined(__USE_MINGW_ANSI_STDIO) || !__USE_MINGW_ANSI_STDIO)
300#define LL_FMT "I64"
301#else
302#define LL_FMT "ll"
303#endif
304
305#if ENABLE_PLATFORM_MINGW32 && defined(_WIN64)
306#define PID_FMT LL_FMT
307#else
308#define PID_FMT
309#endif
310
279/* Large file support */ 311/* Large file support */
280/* Note that CONFIG_LFS=y forces bbox to be built with all common ops 312/* Note that CONFIG_LFS=y forces bbox to be built with all common ops
281 * (stat, lseek etc) mapped to "largefile" variants by libc. 313 * (stat, lseek etc) mapped to "largefile" variants by libc.
@@ -301,7 +333,7 @@ typedef unsigned long long uoff_t;
301# define XATOOFF(a) xatoull_range((a), 0, LLONG_MAX) 333# define XATOOFF(a) xatoull_range((a), 0, LLONG_MAX)
302# define BB_STRTOOFF bb_strtoull 334# define BB_STRTOOFF bb_strtoull
303# define STRTOOFF strtoull 335# define STRTOOFF strtoull
304# define OFF_FMT "ll" 336# define OFF_FMT LL_FMT
305# endif 337# endif
306#else 338#else
307/* CONFIG_LFS is off */ 339/* CONFIG_LFS is off */
@@ -570,13 +602,20 @@ char *bb_get_last_path_component_nostrip(const char *path) FAST_FUNC;
570const char *bb_basename(const char *name) FAST_FUNC; 602const char *bb_basename(const char *name) FAST_FUNC;
571/* NB: can violate const-ness (similarly to strchr) */ 603/* NB: can violate const-ness (similarly to strchr) */
572char *last_char_is(const char *s, int c) FAST_FUNC; 604char *last_char_is(const char *s, int c) FAST_FUNC;
605char *last_char_is_dir_sep(const char *s) FAST_FUNC;
573const char* endofname(const char *name) FAST_FUNC; 606const char* endofname(const char *name) FAST_FUNC;
574char *is_prefixed_with(const char *string, const char *key) FAST_FUNC; 607char *is_prefixed_with(const char *string, const char *key) FAST_FUNC;
575char *is_suffixed_with(const char *string, const char *key) FAST_FUNC; 608char *is_suffixed_with(const char *string, const char *key) FAST_FUNC;
576 609
610#if !ENABLE_PLATFORM_MINGW32
577int ndelay_on(int fd) FAST_FUNC; 611int ndelay_on(int fd) FAST_FUNC;
578int ndelay_off(int fd) FAST_FUNC; 612int ndelay_off(int fd) FAST_FUNC;
579void close_on_exec_on(int fd) FAST_FUNC; 613void close_on_exec_on(int fd) FAST_FUNC;
614#else
615static inline int ndelay_on(int fd UNUSED_PARAM) { return 0; }
616static inline int ndelay_off(int fd UNUSED_PARAM) { return 0; }
617static inline void close_on_exec_on(int fd UNUSED_PARAM) { return; }
618#endif
580void xdup2(int, int) FAST_FUNC; 619void xdup2(int, int) FAST_FUNC;
581void xmove_fd(int, int) FAST_FUNC; 620void xmove_fd(int, int) FAST_FUNC;
582 621
@@ -610,20 +649,37 @@ enum {
610 * Dance around with long long to guard against that... 649 * Dance around with long long to guard against that...
611 */ 650 */
612 BB_FATAL_SIGS = (int)(0 651 BB_FATAL_SIGS = (int)(0
652#ifdef SIGHUP
613 + (1LL << SIGHUP) 653 + (1LL << SIGHUP)
654#endif
614 + (1LL << SIGINT) 655 + (1LL << SIGINT)
615 + (1LL << SIGTERM) 656 + (1LL << SIGTERM)
616 + (1LL << SIGPIPE) // Write to pipe with no readers 657 + (1LL << SIGPIPE) // Write to pipe with no readers
658#ifdef SIGQUIT
617 + (1LL << SIGQUIT) // Quit from keyboard 659 + (1LL << SIGQUIT) // Quit from keyboard
660#endif
618 + (1LL << SIGABRT) // Abort signal from abort(3) 661 + (1LL << SIGABRT) // Abort signal from abort(3)
662#ifdef SIGALRM
619 + (1LL << SIGALRM) // Timer signal from alarm(2) 663 + (1LL << SIGALRM) // Timer signal from alarm(2)
664#endif
665#ifdef SIGVTALRM
620 + (1LL << SIGVTALRM) // Virtual alarm clock 666 + (1LL << SIGVTALRM) // Virtual alarm clock
667#endif
668#ifdef SIGXCPU
621 + (1LL << SIGXCPU) // CPU time limit exceeded 669 + (1LL << SIGXCPU) // CPU time limit exceeded
670#endif
671#ifdef SIGXFSZ
622 + (1LL << SIGXFSZ) // File size limit exceeded 672 + (1LL << SIGXFSZ) // File size limit exceeded
673#endif
674#ifdef SIGUSR1
623 + (1LL << SIGUSR1) // Yes kids, these are also fatal! 675 + (1LL << SIGUSR1) // Yes kids, these are also fatal!
676#endif
677#ifdef SIGUSR1
624 + (1LL << SIGUSR2) 678 + (1LL << SIGUSR2)
679#endif
625 + 0), 680 + 0),
626}; 681};
682#if !ENABLE_PLATFORM_MINGW32
627void bb_signals(int sigs, void (*f)(int)) FAST_FUNC; 683void bb_signals(int sigs, void (*f)(int)) FAST_FUNC;
628/* Unlike signal() and bb_signals, sets handler with sigaction() 684/* Unlike signal() and bb_signals, sets handler with sigaction()
629 * and in a way that while signal handler is run, no other signals 685 * and in a way that while signal handler is run, no other signals
@@ -643,6 +699,10 @@ int sigaction_set(int sig, const struct sigaction *act) FAST_FUNC;
643int sigprocmask_allsigs(int how) FAST_FUNC; 699int sigprocmask_allsigs(int how) FAST_FUNC;
644/* Return old set in the same set: */ 700/* Return old set in the same set: */
645int sigprocmask2(int how, sigset_t *set) FAST_FUNC; 701int sigprocmask2(int how, sigset_t *set) FAST_FUNC;
702#else
703#define bb_signals(s, f)
704#define kill_myself_with_sig(s)
705#endif
646/* Standard handler which just records signo */ 706/* Standard handler which just records signo */
647extern smallint bb_got_signal; 707extern smallint bb_got_signal;
648void record_signo(int signo); /* not FAST_FUNC! */ 708void record_signo(int signo); /* not FAST_FUNC! */
@@ -726,7 +786,7 @@ void xsettimeofday(const struct timeval *tv) FAST_FUNC;
726int xsocket(int domain, int type, int protocol) FAST_FUNC; 786int xsocket(int domain, int type, int protocol) FAST_FUNC;
727void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC; 787void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC;
728void xlisten(int s, int backlog) FAST_FUNC; 788void xlisten(int s, int backlog) FAST_FUNC;
729void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) FAST_FUNC; 789void xconnect(int s, const struct sockaddr *saddr, socklen_t addrlen) FAST_FUNC;
730ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, 790ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
731 socklen_t tolen) FAST_FUNC; 791 socklen_t tolen) FAST_FUNC;
732 792
@@ -933,7 +993,7 @@ int bb_putchar(int ch) FAST_FUNC;
933/* Note: does not use stdio, writes to fd 2 directly */ 993/* Note: does not use stdio, writes to fd 2 directly */
934int bb_putchar_stderr(char ch) FAST_FUNC; 994int bb_putchar_stderr(char ch) FAST_FUNC;
935int fputs_stdout(const char *s) FAST_FUNC; 995int fputs_stdout(const char *s) FAST_FUNC;
936char *xasprintf(const char *format, ...) __attribute__ ((format(printf, 1, 2))) FAST_FUNC RETURNS_MALLOC; 996char *xasprintf(const char *format, ...) __attribute__ ((format(printf, 1, 2))) RETURNS_MALLOC;
937char *auto_string(char *str) FAST_FUNC; 997char *auto_string(char *str) FAST_FUNC;
938// gcc-4.1.1 still isn't good enough at optimizing it 998// gcc-4.1.1 still isn't good enough at optimizing it
939// (+200 bytes compared to macro) 999// (+200 bytes compared to macro)
@@ -1208,12 +1268,20 @@ gid_t *bb_getgroups(int *ngroups, gid_t *group_array) FAST_FUNC;
1208struct cached_groupinfo { 1268struct cached_groupinfo {
1209 uid_t euid; 1269 uid_t euid;
1210 gid_t egid; 1270 gid_t egid;
1271#if !ENABLE_PLATFORM_MINGW32
1272 // If these are ever restored on Windows it will be necessary to alter
1273 // globals_misc_size()/globals_misc_copy() in ash.
1211 int ngroups; 1274 int ngroups;
1212 gid_t *supplementary_array; 1275 gid_t *supplementary_array;
1276#endif
1213}; 1277};
1214uid_t FAST_FUNC get_cached_euid(uid_t *euid); 1278uid_t FAST_FUNC get_cached_euid(uid_t *euid);
1215gid_t FAST_FUNC get_cached_egid(gid_t *egid); 1279gid_t FAST_FUNC get_cached_egid(gid_t *egid);
1280#if !ENABLE_PLATFORM_MINGW32
1216int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid); 1281int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid);
1282#else
1283# define is_in_supplementary_groups(g, i) (FALSE)
1284#endif
1217 1285
1218#if ENABLE_FEATURE_UTMP 1286#if ENABLE_FEATURE_UTMP
1219void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); 1287void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname);
@@ -1249,6 +1317,7 @@ void BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC;
1249 1317
1250/* xvfork() can't be a _function_, return after vfork in child mangles stack 1318/* xvfork() can't be a _function_, return after vfork in child mangles stack
1251 * in the parent. It must be a macro. */ 1319 * in the parent. It must be a macro. */
1320#if !ENABLE_PLATFORM_MINGW32
1252#define xvfork() \ 1321#define xvfork() \
1253({ \ 1322({ \
1254 pid_t bb__xvfork_pid = vfork(); \ 1323 pid_t bb__xvfork_pid = vfork(); \
@@ -1256,6 +1325,9 @@ void BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC;
1256 bb_simple_perror_msg_and_die("vfork"); \ 1325 bb_simple_perror_msg_and_die("vfork"); \
1257 bb__xvfork_pid; \ 1326 bb__xvfork_pid; \
1258}) 1327})
1328#else
1329#define xvfork() vfork()
1330#endif
1259#if BB_MMU 1331#if BB_MMU
1260pid_t xfork(void) FAST_FUNC; 1332pid_t xfork(void) FAST_FUNC;
1261#endif 1333#endif
@@ -1290,6 +1362,15 @@ void run_noexec_applet_and_exit(int a, const char *name, char **argv) NORETURN F
1290#ifndef BUILD_INDIVIDUAL 1362#ifndef BUILD_INDIVIDUAL
1291int find_applet_by_name(const char *name) FAST_FUNC; 1363int find_applet_by_name(const char *name) FAST_FUNC;
1292void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; 1364void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC;
1365# if ENABLE_PLATFORM_MINGW32
1366# if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE
1367int prefer_applet(const char *name, const char *path) FAST_FUNC;
1368int find_applet_by_name_for_sh(const char *name, const char *path) FAST_FUNC;
1369# endif
1370# else
1371# define prefer_applet(n, p) (1)
1372# define find_applet_by_name_for_sh(n, p) find_applet_by_name(n)
1373# endif
1293#endif 1374#endif
1294void show_usage_if_dash_dash_help(int applet_no, char **argv) FAST_FUNC; 1375void show_usage_if_dash_dash_help(int applet_no, char **argv) FAST_FUNC;
1295#if defined(__linux__) 1376#if defined(__linux__)
@@ -1370,12 +1451,12 @@ char* single_argv(char **argv) FAST_FUNC;
1370char **skip_dash_dash(char **argv) FAST_FUNC; 1451char **skip_dash_dash(char **argv) FAST_FUNC;
1371extern const char *const bb_argv_dash[]; /* { "-", NULL } */ 1452extern const char *const bb_argv_dash[]; /* { "-", NULL } */
1372extern uint32_t option_mask32; 1453extern uint32_t option_mask32;
1373uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; 1454uint32_t getopt32(char **argv, const char *applet_opts, ...);
1374# define No_argument "\0" 1455# define No_argument "\0"
1375# define Required_argument "\001" 1456# define Required_argument "\001"
1376# define Optional_argument "\002" 1457# define Optional_argument "\002"
1377#if ENABLE_LONG_OPTS 1458#if ENABLE_LONG_OPTS
1378uint32_t getopt32long(char **argv, const char *optstring, const char *longopts, ...) FAST_FUNC; 1459uint32_t getopt32long(char **argv, const char *optstring, const char *longopts, ...);
1379#else 1460#else
1380#define getopt32long(argv,optstring,longopts,...) \ 1461#define getopt32long(argv,optstring,longopts,...) \
1381 getopt32(argv,optstring,##__VA_ARGS__) 1462 getopt32(argv,optstring,##__VA_ARGS__)
@@ -1450,17 +1531,17 @@ extern uint8_t xfunc_error_retval;
1450extern void (*die_func)(void); 1531extern void (*die_func)(void);
1451void xfunc_die(void) NORETURN FAST_FUNC; 1532void xfunc_die(void) NORETURN FAST_FUNC;
1452void bb_show_usage(void) NORETURN FAST_FUNC; 1533void bb_show_usage(void) NORETURN FAST_FUNC;
1453void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; 1534void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
1454void bb_simple_error_msg(const char *s) FAST_FUNC; 1535void bb_simple_error_msg(const char *s) FAST_FUNC;
1455void bb_error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; 1536void bb_error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
1456void bb_simple_error_msg_and_die(const char *s) NORETURN FAST_FUNC; 1537void bb_simple_error_msg_and_die(const char *s) NORETURN FAST_FUNC;
1457void bb_perror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; 1538void bb_perror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
1458void bb_simple_perror_msg(const char *s) FAST_FUNC; 1539void bb_simple_perror_msg(const char *s) FAST_FUNC;
1459void bb_perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; 1540void bb_perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
1460void bb_simple_perror_msg_and_die(const char *s) NORETURN FAST_FUNC; 1541void bb_simple_perror_msg_and_die(const char *s) NORETURN FAST_FUNC;
1461void bb_herror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; 1542void bb_herror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
1462void bb_simple_herror_msg(const char *s) FAST_FUNC; 1543void bb_simple_herror_msg(const char *s) FAST_FUNC;
1463void bb_herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; 1544void bb_herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
1464void bb_simple_herror_msg_and_die(const char *s) NORETURN FAST_FUNC; 1545void bb_simple_herror_msg_and_die(const char *s) NORETURN FAST_FUNC;
1465void bb_perror_nomsg_and_die(void) NORETURN FAST_FUNC; 1546void bb_perror_nomsg_and_die(void) NORETURN FAST_FUNC;
1466void bb_perror_nomsg(void) FAST_FUNC; 1547void bb_perror_nomsg(void) FAST_FUNC;
@@ -1476,7 +1557,7 @@ void bb_logenv_override(void) FAST_FUNC;
1476typedef smalluint exitcode_t; 1557typedef smalluint exitcode_t;
1477 1558
1478#if ENABLE_FEATURE_SYSLOG_INFO 1559#if ENABLE_FEATURE_SYSLOG_INFO
1479void bb_info_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; 1560void bb_info_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
1480void bb_simple_info_msg(const char *s) FAST_FUNC; 1561void bb_simple_info_msg(const char *s) FAST_FUNC;
1481void bb_vinfo_msg(const char *s, va_list p) FAST_FUNC; 1562void bb_vinfo_msg(const char *s, va_list p) FAST_FUNC;
1482#else 1563#else
@@ -1853,8 +1934,8 @@ int get_termios_and_make_raw(int fd, struct termios *newterm, struct termios *ol
1853int set_termios_to_raw(int fd, struct termios *oldterm, int flags) FAST_FUNC; 1934int set_termios_to_raw(int fd, struct termios *oldterm, int flags) FAST_FUNC;
1854 1935
1855/* NB: "unsigned request" is crucial! "int request" will break some arches! */ 1936/* NB: "unsigned request" is crucial! "int request" will break some arches! */
1856int ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) __attribute__ ((format (printf, 4, 5))) FAST_FUNC; 1937int ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) __attribute__ ((format (printf, 4, 5)));
1857int ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...) __attribute__ ((format (printf, 4, 5))) FAST_FUNC; 1938int ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...) __attribute__ ((format (printf, 4, 5)));
1858#if ENABLE_IOCTL_HEX2STR_ERROR 1939#if ENABLE_IOCTL_HEX2STR_ERROR
1859int bb_ioctl_or_warn(int fd, unsigned request, void *argp, const char *ioctl_name) FAST_FUNC; 1940int bb_ioctl_or_warn(int fd, unsigned request, void *argp, const char *ioctl_name) FAST_FUNC;
1860int bb_xioctl(int fd, unsigned request, void *argp, const char *ioctl_name) FAST_FUNC; 1941int bb_xioctl(int fd, unsigned request, void *argp, const char *ioctl_name) FAST_FUNC;
@@ -1867,9 +1948,15 @@ int bb_xioctl(int fd, unsigned request, void *argp) FAST_FUNC;
1867#define xioctl(fd,request,argp) bb_xioctl(fd,request,argp) 1948#define xioctl(fd,request,argp) bb_xioctl(fd,request,argp)
1868#endif 1949#endif
1869 1950
1951#if !ENABLE_PLATFORM_MINGW32 || ENABLE_FEATURE_EXTRA_FILE_DATA
1870char *is_in_ino_dev_hashtable(const struct stat *statbuf) FAST_FUNC; 1952char *is_in_ino_dev_hashtable(const struct stat *statbuf) FAST_FUNC;
1871void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) FAST_FUNC; 1953void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) FAST_FUNC;
1872void reset_ino_dev_hashtable(void) FAST_FUNC; 1954void reset_ino_dev_hashtable(void) FAST_FUNC;
1955#else
1956#define add_to_ino_dev_hashtable(s, n) (void)0
1957#define is_in_ino_dev_hashtable(s) NULL
1958#define reset_ino_dev_hashtable()
1959#endif
1873#ifdef __GLIBC__ 1960#ifdef __GLIBC__
1874/* At least glibc has horrendously large inline for this, so wrap it */ 1961/* At least glibc has horrendously large inline for this, so wrap it */
1875unsigned long long bb_makedev(unsigned major, unsigned minor) FAST_FUNC; 1962unsigned long long bb_makedev(unsigned major, unsigned minor) FAST_FUNC;
@@ -1947,6 +2034,9 @@ enum {
1947 * >=0: poll() for TIMEOUT milliseconds, return -1/EAGAIN on timeout 2034 * >=0: poll() for TIMEOUT milliseconds, return -1/EAGAIN on timeout
1948 */ 2035 */
1949int64_t read_key(int fd, char *buffer, int timeout) FAST_FUNC; 2036int64_t read_key(int fd, char *buffer, int timeout) FAST_FUNC;
2037#if ENABLE_PLATFORM_MINGW32
2038int64_t windows_read_key(int fd, char *buffer, int timeout) FAST_FUNC;
2039#endif
1950/* This version loops on EINTR: */ 2040/* This version loops on EINTR: */
1951int64_t safe_read_key(int fd, char *buffer, int timeout) FAST_FUNC; 2041int64_t safe_read_key(int fd, char *buffer, int timeout) FAST_FUNC;
1952void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; 2042void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC;
@@ -1960,8 +2050,14 @@ unsigned size_from_HISTFILESIZE(const char *hp) FAST_FUNC;
1960# else 2050# else
1961# define MAX_HISTORY 0 2051# define MAX_HISTORY 0
1962# endif 2052# endif
2053# if defined CONFIG_FEATURE_EDITING_HISTORY_DEFAULT && CONFIG_FEATURE_EDITING_HISTORY_DEFAULT > 0
2054# define DEFAULT_HISTORY (CONFIG_FEATURE_EDITING_HISTORY_DEFAULT + 0)
2055# else
2056# define DEFAULT_HISTORY 0
2057# endif
1963typedef const char *get_exe_name_t(int i) FAST_FUNC; 2058typedef const char *get_exe_name_t(int i) FAST_FUNC;
1964typedef const char *sh_get_var_t(const char *name) FAST_FUNC; 2059typedef const char *sh_get_var_t(const char *name) FAST_FUNC;
2060typedef int sh_accept_glob_t(const char *name) FAST_FUNC;
1965typedef struct line_input_t { 2061typedef struct line_input_t {
1966 int flags; 2062 int flags;
1967 int timeout; 2063 int timeout;
@@ -1975,6 +2071,9 @@ typedef struct line_input_t {
1975# if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH 2071# if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH
1976 /* function to fetch additional application-specific names to match */ 2072 /* function to fetch additional application-specific names to match */
1977 get_exe_name_t *get_exe_name; 2073 get_exe_name_t *get_exe_name;
2074# if ENABLE_ASH_GLOB_OPTIONS
2075 sh_accept_glob_t *sh_accept_glob;
2076# endif
1978# endif 2077# endif
1979# endif 2078# endif
1980# if (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT) \ 2079# if (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT) \
@@ -2009,6 +2108,9 @@ enum {
2009 VI_MODE = 8 * ENABLE_FEATURE_EDITING_VI, 2108 VI_MODE = 8 * ENABLE_FEATURE_EDITING_VI,
2010 WITH_PATH_LOOKUP = 0x10, 2109 WITH_PATH_LOOKUP = 0x10,
2011 LI_INTERRUPTIBLE = 0x20, 2110 LI_INTERRUPTIBLE = 0x20,
2111#if ENABLE_PLATFORM_MINGW32
2112 IGNORE_CTRL_C = 0x40,
2113#endif
2012 FOR_SHELL = DO_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION | LI_INTERRUPTIBLE, 2114 FOR_SHELL = DO_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION | LI_INTERRUPTIBLE,
2013}; 2115};
2014line_input_t *new_line_input_t(int flags) FAST_FUNC; 2116line_input_t *new_line_input_t(int flags) FAST_FUNC;
@@ -2038,6 +2140,10 @@ int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC;
2038 2140
2039unsigned long* FAST_FUNC get_malloc_cpu_affinity(int pid, unsigned *sz); 2141unsigned long* FAST_FUNC get_malloc_cpu_affinity(int pid, unsigned *sz);
2040 2142
2143#if ENABLE_PLATFORM_MINGW32
2144# undef COMM_LEN
2145# define COMM_LEN 32
2146#endif
2041#ifndef COMM_LEN 2147#ifndef COMM_LEN
2042# ifdef TASK_COMM_LEN 2148# ifdef TASK_COMM_LEN
2043enum { COMM_LEN = TASK_COMM_LEN }; 2149enum { COMM_LEN = TASK_COMM_LEN };
@@ -2075,7 +2181,13 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
2075 void (*cb)(struct smaprec *, void *), void *data); 2181 void (*cb)(struct smaprec *, void *), void *data);
2076 2182
2077typedef struct procps_status_t { 2183typedef struct procps_status_t {
2184#if !ENABLE_PLATFORM_MINGW32
2078 DIR *dir; 2185 DIR *dir;
2186#else
2187 HANDLE snapshot;
2188 DWORD *pids;
2189 int npids;
2190#endif
2079 IF_FEATURE_SHOW_THREADS(DIR *task_dir;) 2191 IF_FEATURE_SHOW_THREADS(DIR *task_dir;)
2080 uint8_t shift_pages_to_bytes; 2192 uint8_t shift_pages_to_bytes;
2081 uint8_t shift_pages_to_kb; 2193 uint8_t shift_pages_to_kb;
@@ -2309,11 +2421,18 @@ extern const char bb_path_wtmp_file[] ALIGN1;
2309#define bb_path_motd_file "/etc/motd" 2421#define bb_path_motd_file "/etc/motd"
2310 2422
2311#define bb_dev_null "/dev/null" 2423#define bb_dev_null "/dev/null"
2424#if ENABLE_PLATFORM_MINGW32
2425#define bb_busybox_exec_path get_busybox_exec_path()
2426extern char bb_comm[];
2427extern char bb_command_line[];
2428#else
2312extern const char bb_busybox_exec_path[] ALIGN1; 2429extern const char bb_busybox_exec_path[] ALIGN1;
2430#endif
2313/* allow default system PATH to be extended via CFLAGS */ 2431/* allow default system PATH to be extended via CFLAGS */
2314#ifndef BB_ADDITIONAL_PATH 2432#ifndef BB_ADDITIONAL_PATH
2315#define BB_ADDITIONAL_PATH "" 2433#define BB_ADDITIONAL_PATH ""
2316#endif 2434#endif
2435#if !ENABLE_PLATFORM_MINGW32
2317#define BB_PATH_ROOT_PATH "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH 2436#define BB_PATH_ROOT_PATH "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH
2318extern const char bb_PATH_root_path[] ALIGN1; /* BB_PATH_ROOT_PATH */ 2437extern const char bb_PATH_root_path[] ALIGN1; /* BB_PATH_ROOT_PATH */
2319#define bb_default_root_path (bb_PATH_root_path + sizeof("PATH")) 2438#define bb_default_root_path (bb_PATH_root_path + sizeof("PATH"))
@@ -2321,6 +2440,23 @@ extern const char bb_PATH_root_path[] ALIGN1; /* BB_PATH_ROOT_PATH */
2321 * but I want to save a few bytes here: 2440 * but I want to save a few bytes here:
2322 */ 2441 */
2323#define bb_default_path (bb_PATH_root_path + sizeof("PATH=/sbin:/usr/sbin")) 2442#define bb_default_path (bb_PATH_root_path + sizeof("PATH=/sbin:/usr/sbin"))
2443#define PATH_SEP ':'
2444#define PATH_SEP_STR ":"
2445#else
2446#define BB_PATH_ROOT_PATH "PATH=C:/Windows/System32;C:/Windows" BB_ADDITIONAL_PATH
2447extern const char bb_PATH_root_path[] ALIGN1; /* BB_PATH_ROOT_PATH */
2448#define bb_default_root_path (bb_PATH_root_path + sizeof("PATH"))
2449#define bb_default_path (bb_PATH_root_path + sizeof("PATH"))
2450#define PATH_SEP ';'
2451#define PATH_SEP_STR ";"
2452extern const char bbvar[] ALIGN1;
2453#define bbafter(p) (p + sizeof(#p))
2454#define BB_OVERRIDE_APPLETS bbvar
2455#define BB_SKIP_ANSI_EMULATION bbafter(BB_OVERRIDE_APPLETS)
2456#define BB_TERMINAL_MODE bbafter(BB_SKIP_ANSI_EMULATION)
2457#define BB_SYSTEMROOT bbafter(BB_TERMINAL_MODE)
2458#define BB_CRITICAL_ERROR_DIALOGS bbafter(BB_SYSTEMROOT)
2459#endif
2324 2460
2325extern const int const_int_0; 2461extern const int const_int_0;
2326//extern const int const_int_1; 2462//extern const int const_int_1;
@@ -2350,10 +2486,15 @@ static ALWAYS_INLINE void* not_const_pp(const void *p)
2350 ); 2486 );
2351 return pp; 2487 return pp;
2352} 2488}
2489# if !ENABLE_PLATFORM_MINGW32
2353# define ASSIGN_CONST_PTR(pptr, v) do { \ 2490# define ASSIGN_CONST_PTR(pptr, v) do { \
2354 *(void**)not_const_pp(pptr) = (void*)(v); \ 2491 *(void**)not_const_pp(pptr) = (void*)(v); \
2355 barrier(); \ 2492 barrier(); \
2356} while (0) 2493} while (0)
2494#else
2495/* On Windows it seems necessary for this to be a function too. */
2496void ASSIGN_CONST_PTR(const void *pptr, const void *ptr) FAST_FUNC;
2497#endif
2357/* XZALLOC_CONST_PTR() is an out-of-line function to prevent 2498/* XZALLOC_CONST_PTR() is an out-of-line function to prevent
2358 * clang from reading pointer before it is assigned. 2499 * clang from reading pointer before it is assigned.
2359 */ 2500 */
diff --git a/include/mingw.h b/include/mingw.h
new file mode 100644
index 000000000..c41c0f91e
--- /dev/null
+++ b/include/mingw.h
@@ -0,0 +1,671 @@
1
2#define NOIMPL(name,...) static inline int name(__VA_ARGS__) { errno = ENOSYS; return -1; }
3#define IMPL(name,ret,retval,...) static inline ret name(__VA_ARGS__) { return retval; }
4
5/* Use 64-bit time on 32-bit platforms. */
6#if !defined(_WIN64)
7# define time_t __time64_t
8# define ctime(t) _ctime64(t)
9# define localtime(t) _localtime64(t)
10# define time(t) _time64(t)
11# define gmtime(t) _gmtime64(t)
12# define mktime(t) _mktime64(t)
13# define timespec _timespec64
14#endif
15
16/*
17 * sys/types.h
18 */
19typedef int gid_t;
20typedef int uid_t;
21
22#define DEFAULT_UID 4095
23#define DEFAULT_GID DEFAULT_UID
24
25/*
26 * arpa/inet.h
27 */
28static inline unsigned int git_ntohl(unsigned int x) { return (unsigned int)ntohl(x); }
29#define ntohl git_ntohl
30int inet_aton(const char *cp, struct in_addr *inp);
31int inet_pton(int af, const char *src, void *dst);
32
33/*
34 * fcntl.h
35 */
36#define F_DUPFD 0
37#define F_GETFD 1
38#define F_SETFD 2
39#define F_GETFL 3
40#define F_SETFL 3
41#define FD_CLOEXEC 0x1
42#define O_NONBLOCK 0
43#define O_NOFOLLOW 0
44#define O_NOCTTY 0
45#define O_DIRECT 0
46#define O_SPECIAL 0x800000
47
48#define AT_FDCWD -100
49#define AT_SYMLINK_NOFOLLOW 0x100
50
51/*
52 * grp.h
53 */
54
55struct group {
56 char *gr_name;
57 char *gr_passwd;
58 gid_t gr_gid;
59 char **gr_mem;
60};
61IMPL(getgrnam,struct group *,NULL,const char *name UNUSED_PARAM);
62struct group *getgrgid(gid_t gid);
63NOIMPL(initgroups,const char *group UNUSED_PARAM,gid_t gid UNUSED_PARAM);
64static inline void endgrent(void) {}
65int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups);
66
67/*
68 * limits.h
69 */
70#define NAME_MAX 255
71#define MAXSYMLINKS 20
72
73#ifdef LONG_MAX
74# if LONG_MAX == 2147483647
75# define LONG_BIT 32
76# else
77/* Safe assumption. */
78# define LONG_BIT 64
79# endif
80#elif defined __LONG_MAX__
81# if __LONG_MAX__ == 2147483647
82# define LONG_BIT 32
83# else
84/* Safe assumption. */
85# define LONG_BIT 64
86# endif
87#endif
88
89/*
90 * netdb.h
91 */
92
93typedef int sa_family_t;
94
95/*
96 * linux/un.h
97 */
98struct sockaddr_un {
99 sa_family_t sun_family;
100 char sun_path[1]; /* to make compiler happy, don't bother */
101};
102
103/*
104 * pwd.h
105 */
106struct passwd {
107 char *pw_name;
108 char *pw_passwd;
109 char *pw_gecos;
110 char *pw_dir;
111 char *pw_shell;
112 uid_t pw_uid;
113 gid_t pw_gid;
114};
115
116struct passwd *getpwnam(const char *name);
117struct passwd *getpwuid(uid_t uid);
118static inline void setpwent(void) {}
119static inline void endpwent(void) {}
120IMPL(getpwent_r,int,ENOENT,struct passwd *pwbuf UNUSED_PARAM,char *buf UNUSED_PARAM,size_t buflen UNUSED_PARAM,struct passwd **pwbufp UNUSED_PARAM);
121IMPL(getpwent,struct passwd *,NULL,void)
122
123/*
124 * signal.h
125 */
126#define SIGHUP 1
127#define SIGQUIT 3
128#define SIGKILL 9
129#define SIGPIPE 13
130
131#define SIG_UNBLOCK 1
132
133typedef void (*sighandler_t)(int);
134sighandler_t winansi_signal(int signum, sighandler_t handler);
135#define signal(s, h) winansi_signal(s, h)
136
137/*
138 * stdio.h
139 */
140#undef fseeko
141#define fseeko(f,o,w) fseek(f,o,w)
142
143int fdprintf(int fd, const char *format, ...);
144FILE* mingw_fopen(const char *filename, const char *mode);
145int mingw_rename(const char*, const char*);
146#define fopen mingw_fopen
147#define rename mingw_rename
148
149FILE *mingw_popen(const char *cmd, const char *mode);
150int mingw_popen_fd(const char *exe, const char *cmd, const char *mode,
151 int fd0, pid_t *pid);
152int mingw_pclose(FILE *fd);
153pid_t mingw_fork_compressor(int fd, const char *compressor, const char *mode);
154#undef popen
155#undef pclose
156#define popen mingw_popen
157#define pclose mingw_pclose
158
159IMPL(setlinebuf, void, ,FILE *fd UNUSED_PARAM)
160
161/*
162 * ANSI emulation wrappers
163 */
164
165BOOL conToCharBuffA(LPSTR d, DWORD len);
166BOOL conToCharA(LPSTR d);
167
168// same as ReadConsoleInputA, but delivers UTF8 regardless of console CP
169BOOL readConsoleInput_utf8(HANDLE h, INPUT_RECORD *r, DWORD len, DWORD *got);
170
171void set_title(const char *str);
172int get_title(char *buf, int len);
173void move_cursor_row(int n);
174void reset_screen(void);
175int winansi_putchar(int c);
176int winansi_puts(const char *s);
177size_t winansi_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
178int winansi_fputs(const char *str, FILE *stream);
179int winansi_fputc(int c, FILE *stream);
180int winansi_vsnprintf(char *buf, size_t size, const char *format, va_list list);
181int winansi_vfprintf(FILE *stream, const char *format, va_list list);
182int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
183int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
184int winansi_write(int fd, const void *buf, size_t count);
185int winansi_read(int fd, void *buf, size_t count);
186size_t winansi_fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
187int winansi_getc(FILE *stream);
188int winansi_getchar(void);
189char *winansi_fgets(char *s, int size, FILE *stream);
190void console_write(const char *str, int len);
191
192#define putchar winansi_putchar
193#define puts winansi_puts
194#define fwrite winansi_fwrite
195#define fputs winansi_fputs
196#define fputc winansi_fputc
197#if !defined(__USE_MINGW_ANSI_STDIO) || !__USE_MINGW_ANSI_STDIO
198#define vsnprintf(buf, size, ...) winansi_vsnprintf(buf, size, __VA_ARGS__)
199#endif
200#define vfprintf(stream, ...) winansi_vfprintf(stream, __VA_ARGS__)
201#define vprintf(...) winansi_vfprintf(stdout, __VA_ARGS__)
202#define printf(...) winansi_printf(__VA_ARGS__)
203#define fprintf(...) winansi_fprintf(__VA_ARGS__)
204#define write winansi_write
205#define read winansi_read
206#define fread winansi_fread
207#define getc winansi_getc
208#define fgetc winansi_getc
209#define getchar winansi_getchar
210#define fgets winansi_fgets
211
212/*
213 * stdlib.h
214 */
215#define WTERMSIG(x) ((x) & 0x7f)
216#define WIFEXITED(x) (WTERMSIG(x) == 0)
217#define WEXITSTATUS(x) (((x) & 0xff00) >> 8)
218#define WIFSIGNALED(x) (((signed char) (((x) & 0x7f) + 1) >> 1) > 0)
219#define WCOREDUMP(x) 0
220#define WIFSTOPPED(x) 0
221
222int mingw_system(const char *cmd);
223#define system mingw_system
224
225int clearenv(void);
226char *mingw_getenv(const char *name);
227int mingw_putenv(const char *env);
228char *mingw_mktemp(char *template);
229int mkstemp(char *template);
230char *realpath(const char *path, char *resolved_path);
231int setenv(const char *name, const char *value, int replace);
232int unsetenv(const char *env);
233
234#define getenv mingw_getenv
235#define putenv mingw_putenv
236#define mktemp mingw_mktemp
237
238/*
239 * string.h
240 */
241char *strndup(char const *s, size_t n);
242char *mingw_strerror(int errnum);
243char *strsignal(int sig);
244int strverscmp(const char *s1, const char *s2);
245
246#define strerror mingw_strerror
247
248/*
249 * strings.h
250 */
251#if !defined(__GNUC__)
252int ffs(int i);
253#else
254# define ffs(i) __builtin_ffs(i)
255#endif
256
257/*
258 * sys/ioctl.h
259 */
260
261#define TIOCGWINSZ 0x5413
262
263int ioctl(int fd, int code, ...);
264
265/*
266 * sys/socket.h
267 */
268#define hstrerror strerror
269
270#define SHUT_WR SD_SEND
271
272int mingw_socket(int domain, int type, int protocol);
273int mingw_connect(int sockfd, const struct sockaddr *sa, size_t sz);
274int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
275int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen);
276int mingw_shutdown(int sockfd, int how);
277int mingw_listen(int sockfd, int backlog);
278int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz);
279int mingw_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
280 struct timeval *timeout);
281int mingw_getpeername(int fd, struct sockaddr *sa, socklen_t *sz);
282int mingw_gethostname(char *host, int namelen);
283int mingw_getaddrinfo(const char *node, const char *service,
284 const struct addrinfo *hints, struct addrinfo **res);
285struct hostent *mingw_gethostbyaddr(const void *addr, socklen_t len, int type);
286
287#define socket mingw_socket
288#define connect mingw_connect
289#define listen mingw_listen
290#define bind mingw_bind
291#define setsockopt mingw_setsockopt
292#define shutdown mingw_shutdown
293#define accept mingw_accept
294#define select mingw_select
295#define getpeername mingw_getpeername
296#define gethostname mingw_gethostname
297#define getaddrinfo mingw_getaddrinfo
298#define gethostbyaddr mingw_gethostbyaddr
299
300/*
301 * sys/time.h
302 */
303#ifndef _TIMESPEC_DEFINED
304#define _TIMESPEC_DEFINED
305struct timespec {
306 time_t tv_sec;
307 long int tv_nsec;
308};
309#endif
310
311typedef int clockid_t;
312#define CLOCK_REALTIME 0
313
314time_t timegm(struct tm *tm);
315
316int nanosleep(const struct timespec *req, struct timespec *rem);
317int clock_gettime(clockid_t clockid, struct timespec *tp);
318int clock_settime(clockid_t clockid, const struct timespec *tp);
319
320/*
321 * sys/stat.h
322 */
323#define S_ISUID 04000
324#define S_ISGID 02000
325#define S_ISVTX 01000
326#ifndef S_IRWXU
327#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
328#endif
329#define S_IRWXG (S_IRWXU >> 3)
330#define S_IRWXO (S_IRWXG >> 3)
331
332#define S_IFSOCK 0140000
333#define S_IFLNK 0120000 /* Symbolic link */
334#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
335#define S_ISSOCK(x) 0
336
337#define S_IRGRP (S_IRUSR >> 3)
338#define S_IWGRP (S_IWUSR >> 3)
339#define S_IXGRP (S_IXUSR >> 3)
340#define S_IROTH (S_IRGRP >> 3)
341#define S_IWOTH (S_IWGRP >> 3)
342#define S_IXOTH (S_IXGRP >> 3)
343
344mode_t mingw_umask(mode_t mode);
345#define umask mingw_umask
346
347#define DEFAULT_UMASK 0002
348
349IMPL(fchmod,int,0,int fildes UNUSED_PARAM, mode_t mode UNUSED_PARAM);
350NOIMPL(fchown,int fd UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM);
351int mingw_mkdir(const char *path, int mode);
352int mingw_chdir(const char *path);
353int mingw_chmod(const char *path, int mode);
354
355#define mkdir mingw_mkdir
356#define chdir mingw_chdir
357#define chmod mingw_chmod
358
359#if ENABLE_LFS && !defined(__MINGW64_VERSION_MAJOR)
360# define off_t off64_t
361#endif
362
363typedef int nlink_t;
364typedef int blksize_t;
365typedef off_t blkcnt_t;
366#if ENABLE_FEATURE_EXTRA_FILE_DATA
367#define ino_t uint64_t
368#endif
369
370struct mingw_stat {
371 dev_t st_dev;
372 ino_t st_ino;
373 mode_t st_mode;
374 nlink_t st_nlink;
375 uid_t st_uid;
376 gid_t st_gid;
377 dev_t st_rdev;
378 off_t st_size;
379 struct timespec st_atim;
380 struct timespec st_mtim;
381 struct timespec st_ctim;
382 blksize_t st_blksize;
383 blkcnt_t st_blocks;
384 DWORD st_attr;
385 DWORD st_tag;
386};
387#define st_atime st_atim.tv_sec
388#define st_mtime st_mtim.tv_sec
389#define st_ctime st_ctim.tv_sec
390
391int count_subdirs(const char *pathname);
392int mingw_lstat(const char *file_name, struct mingw_stat *buf);
393int mingw_stat(const char *file_name, struct mingw_stat *buf);
394int mingw_fstat(int fd, struct mingw_stat *buf);
395#undef lstat
396#undef stat
397#undef fstat
398#define lstat mingw_lstat
399#define stat mingw_stat
400#define fstat mingw_fstat
401
402#define UTIME_NOW ((1l << 30) - 1l)
403#define UTIME_OMIT ((1l << 30) - 2l)
404
405int utimensat(int fd, const char *path, const struct timespec times[2],
406 int flags);
407int futimens(int fd, const struct timespec times[2]);
408
409/*
410 * sys/sysinfo.h
411 */
412struct sysinfo {
413 long uptime; /* Seconds since boot */
414 unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
415 unsigned long totalram; /* Total usable main memory size */
416 unsigned long freeram; /* Available memory size */
417 unsigned long sharedram; /* Amount of shared memory */
418 unsigned long bufferram; /* Memory used by buffers */
419 unsigned long totalswap; /* Total swap space size */
420 unsigned long freeswap; /* Swap space still available */
421 unsigned short procs; /* Number of current processes */
422 unsigned long totalhigh; /* Total high memory size */
423 unsigned long freehigh; /* Available high memory size */
424 unsigned int mem_unit; /* Memory unit size in bytes */
425};
426
427int sysinfo(struct sysinfo *info);
428
429/*
430 * sys/sysmacros.h
431 */
432#define makedev(a,b) 0*(a)*(b) /* avoid unused warning */
433#define minor(x) 0
434#define major(x) 0
435
436/*
437 * sys/wait.h
438 */
439#define WNOHANG 1
440#define WUNTRACED 2
441pid_t waitpid(pid_t pid, int *status, int options);
442pid_t mingw_wait3(pid_t pid, int *status, int options, struct rusage *rusage);
443
444/*
445 * time.h
446 */
447struct tm *gmtime_r(const time_t *timep, struct tm *result);
448struct tm *localtime_r(const time_t *timep, struct tm *result);
449char *strptime(const char *s, const char *format, struct tm *tm);
450char *mingw_strptime(const char *s, const char *format, struct tm *tm, long *gmt);
451size_t mingw_strftime(char *buf, size_t max, const char *format, const struct tm *tm);
452
453#define strftime mingw_strftime
454
455/*
456 * times.h
457 */
458#define clock_t long
459
460struct tms {
461 clock_t tms_utime; /* user CPU time */
462 clock_t tms_stime; /* system CPU time */
463 clock_t tms_cutime; /* user CPU time of children */
464 clock_t tms_cstime; /* system CPU time of children */
465};
466
467clock_t times(struct tms *buf);
468
469/*
470 * unistd.h
471 */
472#define PIPE_BUF 8192
473
474#define _SC_CLK_TCK 2
475
476#define TICKS_PER_SECOND 100
477#define MS_PER_TICK 10
478#define HNSEC_PER_TICK 100000
479
480IMPL(alarm,unsigned int,0,unsigned int seconds UNUSED_PARAM);
481IMPL(chown,int,0,const char *path UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM);
482NOIMPL(chroot,const char *root UNUSED_PARAM);
483NOIMPL(fchdir,int fd UNUSED_PARAM);
484int mingw_dup2 (int fd, int fdto);
485char *mingw_getcwd(char *pointer, int len);
486off_t mingw_lseek(int fd, off_t offset, int whence);
487
488
489int getuid(void);
490#define getgid getuid
491#define geteuid getuid
492#define getegid getuid
493int getgroups(int n, gid_t *groups);
494pid_t getppid(void);
495NOIMPL(getsid,pid_t pid UNUSED_PARAM);
496int getlogin_r(char *buf, size_t len);
497int fcntl(int fd, int cmd, ...);
498int fsync(int fd);
499int kill(pid_t pid, int sig);
500int link(const char *oldpath, const char *newpath);
501NOIMPL(mknod,const char *name UNUSED_PARAM, mode_t mode UNUSED_PARAM, dev_t device UNUSED_PARAM);
502/* order of devices must match that in get_dev_type */
503enum {DEV_NULL, DEV_ZERO, DEV_URANDOM, NOT_DEVICE = -1};
504int get_dev_type(const char *filename);
505void update_special_fd(int dev, int fd);
506int mingw_open (const char *filename, int oflags, ...);
507
508/* functions which add O_SPECIAL to open(2) to allow access to devices */
509int mingw_xopen(const char *filename, int oflags);
510ssize_t mingw_open_read_close(const char *fn, void *buf, size_t size) FAST_FUNC;
511
512#ifndef IO_REPARSE_TAG_APPEXECLINK
513# define IO_REPARSE_TAG_APPEXECLINK 0x8000001b
514#endif
515
516ssize_t mingw_read(int fd, void *buf, size_t count);
517int mingw_close(int fd);
518int pipe(int filedes[2]);
519NOIMPL(setgid,gid_t gid UNUSED_PARAM);
520NOIMPL(setegid,gid_t gid UNUSED_PARAM);
521NOIMPL(setsid,void);
522NOIMPL(setuid,uid_t gid UNUSED_PARAM);
523NOIMPL(seteuid,uid_t gid UNUSED_PARAM);
524unsigned int sleep(unsigned int seconds);
525int symlink(const char *target, const char *linkpath);
526int create_junction(const char *oldpath, const char *newpath);
527long sysconf(int name);
528IMPL(getpagesize,int,4096,void);
529NOIMPL(ttyname_r,int fd UNUSED_PARAM, char *buf UNUSED_PARAM, int sz UNUSED_PARAM);
530int mingw_unlink(const char *pathname);
531int mingw_access(const char *name, int mode);
532int mingw_rmdir(const char *name);
533void mingw_sync(void);
534int mingw_isatty(int fd);
535
536#define dup2 mingw_dup2
537#define getcwd mingw_getcwd
538#define lchown chown
539#define open mingw_open
540#define close mingw_close
541#define unlink mingw_unlink
542#define rmdir mingw_rmdir
543#define sync mingw_sync
544#undef lseek
545#define lseek mingw_lseek
546
547#undef access
548#define access mingw_access
549#define isatty mingw_isatty
550
551/*
552 * utime.h
553 */
554int utimes(const char *file_name, const struct timeval times[2]);
555
556/*
557 * Functions with different prototypes in BusyBox and WIN32
558 */
559#define itoa bb_itoa
560#define strrev bb_strrev
561
562/*
563 * MinGW specific
564 */
565#define is_dir_sep(c) ((c) == '/' || (c) == '\\')
566#define is_unc_path(x) (strlen(x) > 4 && is_dir_sep(x[0]) && \
567 is_dir_sep(x[1]) && !is_dir_sep(x[2]))
568
569typedef struct {
570 char *path;
571 char *name;
572 char *opts;
573 char buf[100];
574} interp_t;
575
576int FAST_FUNC parse_interpreter(const char *cmd, interp_t *interp);
577char ** FAST_FUNC grow_argv(char **argv, int n);
578pid_t FAST_FUNC mingw_spawn(char **argv);
579intptr_t FAST_FUNC mingw_spawn_detach(char **argv);
580intptr_t FAST_FUNC mingw_spawn_proc(const char **argv);
581int mingw_execv(const char *cmd, char *const *argv);
582int httpd_execv_detach(const char *cmd, char *const *argv);
583int mingw_execvp(const char *cmd, char *const *argv);
584int mingw_execve(const char *cmd, char *const *argv, char *const *envp);
585#define spawn mingw_spawn
586#define execvp mingw_execvp
587#define execve mingw_execve
588#define execv mingw_execv
589#define HTTPD_DETACH (8)
590
591#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':')
592
593BOOL WINAPI kill_child_ctrl_handler(DWORD dwCtrlType);
594int FAST_FUNC is_valid_signal(int number);
595int exit_code_to_wait_status(DWORD win_exit_code);
596int exit_code_to_posix(DWORD win_exit_code);
597
598#define find_mount_point(n, s) find_mount_point(n)
599
600char *is_prefixed_with_case(const char *string, const char *key) FAST_FUNC;
601char *is_suffixed_with_case(const char *string, const char *key) FAST_FUNC;
602
603#define VT_OUTPUT 1
604#define VT_INPUT 2
605
606/*
607 * helpers
608 */
609
610const char *get_busybox_exec_path(void);
611void init_winsock(void);
612
613int has_bat_suffix(const char *p);
614int has_exe_suffix(const char *p);
615int has_exe_suffix_or_dot(const char *name);
616char *alloc_ext_space(const char *path);
617int add_win32_extension(char *p);
618char *file_is_win32_exe(const char *name);
619
620#if ENABLE_UNICODE_SUPPORT
621/*
622 * windows wchar_t is 16 bit, while linux (and busybox expectation) is 32.
623 * so when (busybox) unicode.h is included, wchar_t is 32 bit.
624 * Without unicode.h, MINGW_BB_WCHAR_T is busybox wide char (32),
625 * and wchar_t is Windows wide char (16).
626 */
627#define MINGW_BB_WCHAR_T uint32_t /* keep in sync with unicode.h */
628
629MINGW_BB_WCHAR_T *bs_to_slash_u(MINGW_BB_WCHAR_T *p) FAST_FUNC;
630#endif
631
632char *bs_to_slash(char *p) FAST_FUNC;
633void slash_to_bs(char *p) FAST_FUNC;
634void strip_dot_space(char *p) FAST_FUNC;
635size_t remove_cr(char *p, size_t len) FAST_FUNC;
636
637int err_win_to_posix(void);
638
639ULONGLONG CompatGetTickCount64(void);
640#define GetTickCount64 CompatGetTickCount64
641
642ssize_t get_random_bytes(void *buf, ssize_t count);
643int enumerate_links(const char *file, char *name);
644
645int unc_root_len(const char *dir) FAST_FUNC;
646int root_len(const char *path) FAST_FUNC;
647const char *get_system_drive(void) FAST_FUNC;
648int chdir_system_drive(void);
649char *xabsolute_path(char *path) FAST_FUNC;
650char *get_drive_cwd(const char *path, char *buffer, int size) FAST_FUNC;
651void fix_path_case(char *path) FAST_FUNC;
652void make_sparse(int fd, off_t start, off_t end) FAST_FUNC;
653int terminal_mode(int reset) FAST_FUNC;
654int unix_path(const char *path) FAST_FUNC;
655int has_path(const char *file) FAST_FUNC;
656int is_relative_path(const char *path) FAST_FUNC;
657char *get_last_slash(const char *path) FAST_FUNC;
658const char *applet_to_exe(const char *name) FAST_FUNC;
659char *get_user_name(void);
660char *quote_arg(const char *arg) FAST_FUNC;
661char *find_first_executable(const char *name) FAST_FUNC;
662char *xappendword(const char *str, const char *word) FAST_FUNC;
663int windows_env(void);
664void change_critical_error_dialogs(const char *newval) FAST_FUNC;
665char *exe_relative_path(const char *tail) FAST_FUNC;
666enum {
667 ELEVATED_PRIVILEGE = 1,
668 ADMIN_ENABLED = 2
669};
670int elevation_state(void);
671void set_interp(int i) FAST_FUNC;
diff --git a/include/platform.h b/include/platform.h
index ea0512f36..5795a0cf3 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -7,6 +7,20 @@
7#ifndef BB_PLATFORM_H 7#ifndef BB_PLATFORM_H
8#define BB_PLATFORM_H 1 8#define BB_PLATFORM_H 1
9 9
10#if ENABLE_PLATFORM_MINGW32
11# if !defined(__MINGW32__) /* HOSTCC is called */
12# undef ENABLE_PLATFORM_MINGW32
13# else
14# undef __USE_MINGW_ANSI_STDIO
15# define __USE_MINGW_ANSI_STDIO 0
16# undef _WIN32_WINNT
17# define _WIN32_WINNT 0x502
18# endif
19#else
20# if defined(__MINGW32__)
21# error "You must select target platform MS Windows, or it won't build"
22# endif
23#endif
10 24
11/* Convenience macros to test the version of gcc. */ 25/* Convenience macros to test the version of gcc. */
12#undef __GNUC_PREREQ 26#undef __GNUC_PREREQ
@@ -135,7 +149,7 @@
135 149
136/* Make all declarations hidden (-fvisibility flag only affects definitions) */ 150/* Make all declarations hidden (-fvisibility flag only affects definitions) */
137/* (don't include system headers after this until corresponding pop!) */ 151/* (don't include system headers after this until corresponding pop!) */
138#if __GNUC_PREREQ(4,1) && !defined(__CYGWIN__) 152#if __GNUC_PREREQ(4,1) && !defined(__CYGWIN__) && !ENABLE_PLATFORM_MINGW32
139# define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN _Pragma("GCC visibility push(hidden)") 153# define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN _Pragma("GCC visibility push(hidden)")
140# define POP_SAVED_FUNCTION_VISIBILITY _Pragma("GCC visibility pop") 154# define POP_SAVED_FUNCTION_VISIBILITY _Pragma("GCC visibility pop")
141#else 155#else
@@ -164,6 +178,13 @@
164# define bswap_64 __bswap64 178# define bswap_64 __bswap64
165# define bswap_32 __bswap32 179# define bswap_32 __bswap32
166# define bswap_16 __bswap16 180# define bswap_16 __bswap16
181#elif ENABLE_PLATFORM_MINGW32
182# define __BIG_ENDIAN 0
183# define __LITTLE_ENDIAN 1
184# define __BYTE_ORDER __LITTLE_ENDIAN
185# define bswap_16(x) ((((x) & 0xFF00) >> 8) | (((x) & 0xFF) << 8))
186# define bswap_32(x) ((bswap_16(((x) & 0xFFFF0000L) >> 16)) | (bswap_16((x) & 0xFFFFL) << 16))
187# define bswap_64(x) ((bswap_32(((x) & 0xFFFFFFFF00000000LL) >> 32)) | (bswap_32((x) & 0xFFFFFFFFLL) << 32))
167#else 188#else
168# include <byteswap.h> 189# include <byteswap.h>
169# include <endian.h> 190# include <endian.h>
@@ -443,6 +464,26 @@ typedef unsigned smalluint;
443# endif 464# endif
444#endif 465#endif
445 466
467#if ENABLE_PLATFORM_MINGW32
468# undef HAVE_FDATASYNC
469# undef HAVE_DPRINTF
470# undef HAVE_GETLINE
471# undef HAVE_MEMRCHR
472# undef HAVE_MKDTEMP
473# undef HAVE_SETBIT
474# undef HAVE_STPCPY
475# undef HAVE_STPNCPY
476# undef HAVE_STRCASESTR
477# undef HAVE_STRCHRNUL
478# undef HAVE_STRSEP
479#if !defined(__MINGW64_VERSION_MAJOR)
480# undef HAVE_VASPRINTF
481#endif
482# undef HAVE_UNLOCKED_STDIO
483# undef HAVE_UNLOCKED_LINE_OPS
484# undef HAVE_PRINTF_PERCENTM
485#endif
486
446#if defined(__WATCOMC__) 487#if defined(__WATCOMC__)
447# undef HAVE_DPRINTF 488# undef HAVE_DPRINTF
448# undef HAVE_GETLINE 489# undef HAVE_GETLINE
@@ -563,6 +604,7 @@ extern int dprintf(int fd, const char *format, ...);
563#endif 604#endif
564 605
565#ifndef HAVE_MEMRCHR 606#ifndef HAVE_MEMRCHR
607#include <stddef.h>
566extern void *memrchr(const void *s, int c, size_t n) FAST_FUNC; 608extern void *memrchr(const void *s, int c, size_t n) FAST_FUNC;
567#endif 609#endif
568 610
@@ -626,6 +668,7 @@ extern int usleep(unsigned) FAST_FUNC;
626#endif 668#endif
627 669
628#ifndef HAVE_VASPRINTF 670#ifndef HAVE_VASPRINTF
671# include <stdarg.h>
629extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC; 672extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC;
630#endif 673#endif
631 674
diff --git a/include/unicode.h b/include/unicode.h
index 0317a2151..cdf35acb7 100644
--- a/include/unicode.h
+++ b/include/unicode.h
@@ -33,7 +33,11 @@ enum {
33 33
34# if CONFIG_LAST_SUPPORTED_WCHAR < 126 || CONFIG_LAST_SUPPORTED_WCHAR >= 0x30000 34# if CONFIG_LAST_SUPPORTED_WCHAR < 126 || CONFIG_LAST_SUPPORTED_WCHAR >= 0x30000
35# undef CONFIG_LAST_SUPPORTED_WCHAR 35# undef CONFIG_LAST_SUPPORTED_WCHAR
36# if ENABLE_PLATFORM_MINGW32
37# define CONFIG_LAST_SUPPORTED_WCHAR 0x10ffff /* full unicode range */
38# else
36# define CONFIG_LAST_SUPPORTED_WCHAR 0x2ffff 39# define CONFIG_LAST_SUPPORTED_WCHAR 0x2ffff
40# endif
37# endif 41# endif
38 42
39# if CONFIG_LAST_SUPPORTED_WCHAR < 0x300 43# if CONFIG_LAST_SUPPORTED_WCHAR < 0x300
@@ -87,6 +91,21 @@ void reinit_unicode(const char *LANG) FAST_FUNC;
87# undef MB_CUR_MAX 91# undef MB_CUR_MAX
88# define MB_CUR_MAX 6 92# define MB_CUR_MAX 6
89 93
94#if ENABLE_PLATFORM_MINGW32
95 #undef wint_t
96 #undef mbstate_t
97 #undef mbstowcs
98 #undef wcstombs
99 #undef wcrtomb
100 #undef iswspace
101 #undef iswalnum
102 #undef iswpunct
103 #undef wcwidth
104
105 #undef wchar_t
106 #define wchar_t uint32_t /* keep in sync with MINGW_BB_WCHAR_T */
107#endif
108
90/* Prevent name collisions */ 109/* Prevent name collisions */
91# define wint_t bb_wint_t 110# define wint_t bb_wint_t
92# define mbstate_t bb_mbstate_t 111# define mbstate_t bb_mbstate_t
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
diff --git a/loginutils/su.c b/loginutils/su.c
index 6efe1981a..b61e3753a 100644
--- a/loginutils/su.c
+++ b/loginutils/su.c
@@ -8,6 +8,7 @@
8//config: bool "su (19 kb)" 8//config: bool "su (19 kb)"
9//config: default y 9//config: default y
10//config: select FEATURE_SYSLOG 10//config: select FEATURE_SYSLOG
11//config: depends on PLATFORM_POSIX
11//config: help 12//config: help
12//config: su is used to become another user during a login session. 13//config: su is used to become another user during a login session.
13//config: Invoked without a username, su defaults to becoming the super user. 14//config: Invoked without a username, su defaults to becoming the super user.
diff --git a/loginutils/suw32.c b/loginutils/suw32.c
new file mode 100644
index 000000000..b3976dcfd
--- /dev/null
+++ b/loginutils/suw32.c
@@ -0,0 +1,169 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini su implementation for busybox-w32
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 */
7//config:config SUW32
8//config: bool "su for Microsoft Windows"
9//config: default y
10//config: depends on PLATFORM_MINGW32 && ASH
11//config: help
12//config: su runs a shell with elevated privileges.
13
14//applet:IF_SUW32(APPLET_ODDNAME(su, suw32, BB_DIR_BIN, BB_SUID_DROP, suw32))
15
16//kbuild:lib-$(CONFIG_SUW32) += suw32.o
17
18//usage:#define suw32_trivial_usage
19//usage: "[-tW] [-N|-s SHELL] [root]\n"
20//usage: "or: su [-tW] [-N|-s SHELL] -c CMD_STRING [[--] root [ARG0 [ARG...]]]\n"
21//usage: "or: su [-tW] [-N|-s SHELL] [--] root [arbitrary sh arguments]"
22//usage:#define suw32_full_usage "\n\n"
23//usage: "Run shell with elevated privileges\n"
24//usage: "\n -c CMD Command to pass to 'sh -c'"
25//usage: "\n -s SHELL Use specified shell"
26//usage: "\n -N Don't close console when shell exits"
27//usage: "\n -t Test mode, no elevation, implies -W"
28//usage: "\n -W Wait for shell exit code"
29
30#include "libbb.h"
31#include "lazyload.h"
32
33enum {
34 OPT_c = (1 << 0),
35 OPT_s = (1 << 1),
36 OPT_t = (1 << 2),
37 OPT_N = (1 << 3),
38 OPT_W = (1 << 4)
39};
40
41#define test_mode (opt & OPT_t)
42
43int suw32_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
44int suw32_main(int argc UNUSED_PARAM, char **argv)
45{
46 int ret = 0;
47 unsigned opt;
48 char *opt_command = NULL;
49 char *opt_shell = NULL;
50 SHELLEXECUTEINFO info;
51 char *bb_path, *cwd, *realcwd, *q, *args;
52 DECLARE_PROC_ADDR(BOOL, ShellExecuteExA, SHELLEXECUTEINFOA *);
53
54 opt = getopt32(argv, "^c:s:tNW" "\0" "s--N:N--s", &opt_command, &opt_shell);
55 argv += optind;
56 if (argv[0]) {
57 if (!test_mode && strcmp(argv[0], "root") != 0) {
58 bb_error_msg_and_die("unknown user '%s'", argv[0]);
59 }
60 ++argv;
61 }
62
63#if ENABLE_DROP || ENABLE_CDROP || ENABLE_PDROP
64 // If privilege has been dropped (ELEVATED_PRIVILEGE but not
65 // ADMIN_ENABLED) ShellExecuteEx() thinks we already have elevated
66 // privilege and doesn't raise privilege. In that case, give up.
67 if (!test_mode && elevation_state() == ELEVATED_PRIVILEGE) {
68 xfunc_error_retval = 2;
69 bb_error_msg_and_die("unable to restore privilege");
70 }
71#endif
72
73 /* ShellExecuteEx() needs backslash as separator in UNC paths. */
74 if (opt_shell) {
75 bb_path = file_is_win32_exe(opt_shell);
76 if (!bb_path)
77 bb_error_msg_and_die("%s: Not found", opt_shell);
78 args = NULL;
79 } else {
80 bb_path = xstrdup(bb_busybox_exec_path);
81 args = xstrdup("--busybox ash");
82 if (!test_mode)
83 args = xappendword(args, "-t \"BusyBox ash (Admin)\"");
84 }
85 slash_to_bs(bb_path);
86
87 memset(&info, 0, sizeof(SHELLEXECUTEINFO));
88 info.cbSize = sizeof(SHELLEXECUTEINFO);
89 /* info.fMask = SEE_MASK_DEFAULT; */
90 if (opt & (OPT_t|OPT_W))
91 info.fMask |= SEE_MASK_NOCLOSEPROCESS;
92 if (test_mode)
93 info.fMask |= SEE_MASK_NO_CONSOLE;
94 /* info.hwnd = NULL; */
95 info.lpVerb = !test_mode ? "runas" : "open";
96 info.lpFile = bb_path;
97 /*
98 * It seems that when ShellExecuteEx() runs binaries residing in
99 * certain 'system' directories it sets the current directory of
100 * the process to %SYSTEMROOT%\System32. Override this by passing
101 * the directory we want to the shell.
102 *
103 * Canonicalise the directory now: if it's in a drive mapped to
104 * a network share it may not be available once we have elevated
105 * privileges.
106 */
107 if (opt_shell == NULL) {
108 cwd = getcwd(NULL, 0);
109 realcwd = cwd ? xmalloc_realpath(cwd) : NULL;
110 if (realcwd || cwd) {
111 args = xappendword(args, "-d");
112 q = quote_arg(realcwd ?: cwd);
113 args = xappendword(args, q);
114 free(q);
115 }
116 }
117
118 if (opt & OPT_N)
119 args = xappendword(args, "-N");
120
121 if (opt_command) {
122 args = xappendword(args,
123 (opt_shell && strcasecmp(bb_basename(bb_path), "cmd.exe") == 0) ?
124 "/c" : "-c");
125 q = quote_arg(opt_command);
126 args = xappendword(args, q);
127 free(q);
128 }
129
130 while (*argv) {
131 q = quote_arg(*argv++);
132 args = xappendword(args, q);
133 free(q);
134 }
135
136 info.lpParameters = args;
137 /* info.lpDirectory = NULL; */
138 info.nShow = SW_SHOWNORMAL;
139
140 if (!INIT_PROC_ADDR(shell32.dll, ShellExecuteExA)) {
141 ret = -1;
142 goto end;
143 }
144
145 if (!ShellExecuteExA(&info)) {
146 ret = 1;
147 goto end;
148 }
149
150 if (opt & (OPT_t|OPT_W)) {
151 DWORD r;
152
153 WaitForSingleObject(info.hProcess, INFINITE);
154 if (!GetExitCodeProcess(info.hProcess, &r))
155 ret = 1;
156 else
157 ret = exit_code_to_posix(r);
158 CloseHandle(info.hProcess);
159 }
160 end:
161 if (ENABLE_FEATURE_CLEAN_UP) {
162 free(bb_path);
163 free(cwd);
164 free(realcwd);
165 free(args);
166 }
167
168 return ret;
169}
diff --git a/miscutils/bbconfig.c b/miscutils/bbconfig.c
index fe02516a8..077e03c5d 100644
--- a/miscutils/bbconfig.c
+++ b/miscutils/bbconfig.c
@@ -35,6 +35,7 @@
35#include "libbb.h" 35#include "libbb.h"
36#include "bbconfigopts.h" 36#include "bbconfigopts.h"
37#if ENABLE_FEATURE_COMPRESS_BBCONFIG 37#if ENABLE_FEATURE_COMPRESS_BBCONFIG
38#define BB_ARCHIVE_PUBLIC
38# include "bb_archive.h" 39# include "bb_archive.h"
39# include "bbconfigopts_bz2.h" 40# include "bbconfigopts_bz2.h"
40#endif 41#endif
diff --git a/miscutils/bc.c b/miscutils/bc.c
index 28bc40c8b..31485ae9c 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -203,6 +203,9 @@
203 203
204#include "libbb.h" 204#include "libbb.h"
205#include "common_bufsiz.h" 205#include "common_bufsiz.h"
206#if ENABLE_PLATFORM_MINGW32
207# include "BB_VER.h"
208#endif
206 209
207#if !ENABLE_BC && !ENABLE_FEATURE_DC_BIG 210#if !ENABLE_BC && !ENABLE_FEATURE_DC_BIG
208# include "dc.c" 211# include "dc.c"
@@ -7466,6 +7469,17 @@ static unsigned xc_vm_envLen(const char *var)
7466 return len; 7469 return len;
7467} 7470}
7468 7471
7472#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_BC_INTERACTIVE
7473static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
7474{
7475 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
7476 bb_got_signal = SIGINT;
7477 return TRUE;
7478 }
7479 return FALSE;
7480}
7481#endif
7482
7469static int xc_vm_init(const char *env_len) 7483static int xc_vm_init(const char *env_len)
7470{ 7484{
7471 G.prog.len = xc_vm_envLen(env_len); 7485 G.prog.len = xc_vm_envLen(env_len);
@@ -7491,7 +7505,11 @@ static int xc_vm_init(const char *env_len)
7491 // from stdin is not interrupted by ^C either, 7505 // from stdin is not interrupted by ^C either,
7492 // it restarts, thus fgetc() does not return on ^C. 7506 // it restarts, thus fgetc() does not return on ^C.
7493 // (This problem manifests only if line editing is disabled) 7507 // (This problem manifests only if line editing is disabled)
7508# if !ENABLE_PLATFORM_MINGW32
7494 signal_SA_RESTART_empty_mask(SIGINT, record_signo); 7509 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7510# else
7511 SetConsoleCtrlHandler(ctrl_handler, TRUE);
7512# endif
7495 7513
7496 // Without SA_RESTART, this exhibits a bug: 7514 // Without SA_RESTART, this exhibits a bug:
7497 // "while (1) print 1" and try ^C-ing it. 7515 // "while (1) print 1" and try ^C-ing it.
diff --git a/miscutils/dc.c b/miscutils/dc.c
index 42baa67ad..d6369fd15 100644
--- a/miscutils/dc.c
+++ b/miscutils/dc.c
@@ -17,7 +17,7 @@ typedef unsigned long data_t;
17#define DATA_FMT "l" 17#define DATA_FMT "l"
18#else 18#else
19typedef unsigned long long data_t; 19typedef unsigned long long data_t;
20#define DATA_FMT "ll" 20#define DATA_FMT LL_FMT
21#endif 21#endif
22 22
23struct globals { 23struct globals {
diff --git a/miscutils/drop.c b/miscutils/drop.c
new file mode 100644
index 000000000..bef1fa52b
--- /dev/null
+++ b/miscutils/drop.c
@@ -0,0 +1,220 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * drop - run a command without elevated privileges.
4 *
5 * Copyright (c) 2023 Ronald M Yorston
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9//config:config DROP
10//config: bool "drop"
11//config: default y
12//config: depends on PLATFORM_MINGW32 && SH_IS_ASH
13//config: help
14//config: Run a command without elevated privileges
15
16//config:config CDROP
17//config: bool "cdrop"
18//config: default y
19//config: depends on PLATFORM_MINGW32
20//config: help
21//config: Run a command without elevated privileges using cmd.exe
22
23//config:config PDROP
24//config: bool "pdrop"
25//config: default y
26//config: depends on PLATFORM_MINGW32
27//config: help
28//config: Run a command without elevated privileges using PowerShell
29
30//applet:IF_DROP(APPLET(drop, BB_DIR_USR_BIN, BB_SUID_DROP))
31//applet:IF_CDROP(APPLET_ODDNAME(cdrop, drop, BB_DIR_USR_BIN, BB_SUID_DROP, cdrop))
32//applet:IF_PDROP(APPLET_ODDNAME(pdrop, drop, BB_DIR_USR_BIN, BB_SUID_DROP, pdrop))
33
34//kbuild:lib-$(CONFIG_DROP) += drop.o
35//kbuild:lib-$(CONFIG_CDROP) += drop.o
36//kbuild:lib-$(CONFIG_PDROP) += drop.o
37
38//usage:#define drop_trivial_usage
39//usage: "[COMMAND [ARG...] | [-s SHELL] -c CMD_STRING [ARG...]]"
40//usage:#define drop_full_usage "\n\n"
41//usage: "Drop elevated privileges and run a command. If no command\n"
42//usage: "is provided run a shell (by default, the BusyBox shell).\n"
43
44//usage:#define cdrop_trivial_usage
45//usage: "[COMMAND [ARG...] | -c CMD_STRING [ARG...]]"
46//usage:#define cdrop_full_usage "\n\n"
47//usage: "Drop elevated privileges and run a command. If no command\n"
48//usage: "is provided run cmd.exe.\n"
49
50//usage:#define pdrop_trivial_usage
51//usage: "[COMMAND [ARG...] | -c CMD_STRING [ARG...]]"
52//usage:#define pdrop_full_usage "\n\n"
53//usage: "Drop elevated privileges and run a command. If no command\n"
54//usage: "is provided run PowerShell.\n"
55
56#include "libbb.h"
57#include <winsafer.h>
58#include <lazyload.h>
59#include "NUM_APPLETS.h"
60
61// Set an environment variable to the name of the unprivileged user,
62// but only if it was previously unset or contained "root".
63static void setenv_name(const char *key)
64{
65 const char *name = get_user_name();
66 const char *oldname = getenv(key);
67
68 if (name && (!oldname || strcmp(oldname, "root") == 0)) {
69 setenv(key, name, 1);
70 }
71}
72
73int drop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
74int drop_main(int argc UNUSED_PARAM, char **argv)
75{
76 SAFER_LEVEL_HANDLE safer;
77 HANDLE token;
78 STARTUPINFO si;
79 PROCESS_INFORMATION pi;
80 TOKEN_MANDATORY_LABEL TIL;
81 // Medium integrity level S-1-16-8192
82 unsigned char medium[12] = {
83 0x01, 0x01, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x10,
85 0x00, 0x20, 0x00, 0x00
86 };
87 DWORD code;
88 // This shouldn't be necessary but without it the binary complains
89 // it can't find CreateProcessAsUserA on older versions of Windows.
90 DECLARE_PROC_ADDR(BOOL, CreateProcessAsUserA, HANDLE, LPCSTR, LPSTR,
91 LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD,
92 LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION);
93
94 if (!INIT_PROC_ADDR(advapi32.dll, CreateProcessAsUserA))
95 bb_simple_error_msg_and_die("not supported");
96
97 /*
98 * Run a shell using a token with reduced privilege. Hints from:
99 *
100 * https://stackoverflow.com/questions/17765568/
101 */
102 if (SaferCreateLevel(SAFER_SCOPEID_USER, SAFER_LEVELID_NORMALUSER,
103 SAFER_LEVEL_OPEN, &safer, NULL) &&
104 SaferComputeTokenFromLevel(safer, NULL, &token, 0, NULL)) {
105
106 // Set medium integrity
107 TIL.Label.Sid = (PSID)medium;
108 TIL.Label.Attributes = SE_GROUP_INTEGRITY;
109 if (SetTokenInformation(token, TokenIntegrityLevel, &TIL,
110 sizeof(TOKEN_MANDATORY_LABEL))) {
111 char *opt_command = NULL;
112 char *opt_shell = NULL;
113 char **a;
114 const char *opt, *arg;
115 char *exe, *cmd, *q;
116
117 if (*applet_name == 'd')
118 getopt32(argv, "c:s:", &opt_command, &opt_shell);
119 else
120 getopt32(argv, "c:", &opt_command);
121 a = argv + optind;
122 opt = "-c";
123
124 if (*a == NULL || opt_command) {
125 switch (*applet_name) {
126#if ENABLE_PDROP
127 case 'p':
128 arg = "powershell.exe";
129 exe = find_first_executable(arg);
130 break;
131#endif
132#if ENABLE_CDROP
133 case 'c':
134 opt = "/c";
135 arg = "cmd.exe";
136 exe = find_first_executable(arg);
137 break;
138#endif
139#if ENABLE_DROP
140 case 'd':
141 if (opt_shell) {
142 arg = bb_basename(opt_shell);
143 if (strcasecmp(arg, "cmd.exe") == 0)
144 opt = "/c";
145 exe = file_is_win32_exe(opt_shell);
146 } else {
147 arg = "sh";
148 exe = xstrdup(bb_busybox_exec_path);
149 }
150 break;
151#endif
152 default:
153 // Never executed, just to silence warnings.
154 arg = argv[0];
155 exe = NULL;
156 break;
157 }
158 } else {
159 arg = *a++;
160
161#if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1
162 if (!has_path(arg) && find_applet_by_name(arg) >= 0) {
163 exe = xstrdup(bb_busybox_exec_path);
164 } else
165#endif
166 if (has_path(arg)) {
167 exe = file_is_win32_exe(arg);
168 } else {
169 exe = find_first_executable(arg);
170 }
171 }
172
173 if (exe == NULL) {
174 xfunc_error_retval = 127;
175 bb_error_msg_and_die("can't find '%s'", arg);
176 }
177
178 slash_to_bs(exe);
179 cmd = quote_arg(arg);
180 if (opt_command) {
181 cmd = xappendword(cmd, opt);
182 q = quote_arg(opt_command);
183 cmd = xappendword(cmd, q);
184 free(q);
185 }
186
187 // Build the command line
188 while (*a) {
189 q = quote_arg(*a++);
190 cmd = xappendword(cmd, q);
191 free(q);
192 }
193
194 ZeroMemory(&si, sizeof(STARTUPINFO));
195 si.cb = sizeof(STARTUPINFO);
196 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
197 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
198 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
199 si.dwFlags = STARTF_USESTDHANDLES;
200
201 setenv_name("USER");
202 setenv_name("LOGNAME");
203
204 if (!CreateProcessAsUserA(token, exe, cmd, NULL, NULL, TRUE,
205 0, NULL, NULL, &si, &pi)) {
206 xfunc_error_retval = 126;
207 bb_error_msg_and_die("can't execute '%s'", exe);
208 }
209
210 kill_child_ctrl_handler(pi.dwProcessId);
211 SetConsoleCtrlHandler(kill_child_ctrl_handler, TRUE);
212 WaitForSingleObject(pi.hProcess, INFINITE);
213 if (GetExitCodeProcess(pi.hProcess, &code)) {
214 return exit_code_to_posix(code);
215 }
216 }
217 }
218
219 return EXIT_FAILURE;
220}
diff --git a/miscutils/iconv.c b/miscutils/iconv.c
new file mode 100644
index 000000000..bedbb718d
--- /dev/null
+++ b/miscutils/iconv.c
@@ -0,0 +1,1771 @@
1/*
2 * iconv implementation using Win32 API to convert.
3 *
4 * This file is placed in the public domain.
5 */
6
7/*
8 * This code was obtained from:
9 *
10 * https://github.com/win-iconv/win-iconv
11 *
12 * Modified for busybox-w32 by Ronald M Yorston. These modifications
13 * are also dedicated to the public domain.
14 */
15
16//config:config ICONV
17//config: bool "iconv (11.4 kb)"
18//config: default y
19//config: depends on PLATFORM_MINGW32
20//config: help
21//config: 'iconv' converts text between character encodings.
22
23//applet:IF_ICONV(APPLET(iconv, BB_DIR_USR_BIN, BB_SUID_DROP))
24
25//kbuild:lib-$(CONFIG_ICONV) += iconv.o
26
27//usage:#define iconv_trivial_usage
28//usage: "[-lc] [-o outfile] [-f from-enc] [-t to-enc] [FILE]..."
29//usage:#define iconv_full_usage "\n\n"
30//usage: "Convert text between character encodings\n"
31//usage: "\n -l List all known character encodings"
32//usage: "\n -c Silently discard characters that cannot be converted"
33//usage: "\n -o Use outfile for output"
34//usage: "\n -f Use from-enc for input characters"
35//usage: "\n -t Use to-enc for output characters"
36
37#include "libbb.h"
38
39/* WORKAROUND: */
40#define GetProcAddressA GetProcAddress
41
42#define MB_CHAR_MAX 16
43
44#define UNICODE_MODE_BOM_DONE 1
45#define UNICODE_MODE_SWAPPED 2
46
47#define FLAG_USE_BOM 1
48#define FLAG_TRANSLIT 2 /* //TRANSLIT */
49#define FLAG_IGNORE 4 /* //IGNORE */
50
51typedef unsigned char uchar;
52typedef unsigned short ushort;
53typedef unsigned int uint;
54
55typedef void* iconv_t;
56
57static iconv_t iconv_open(const char *tocode, const char *fromcode);
58static int iconv_close(iconv_t cd);
59static size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
60
61typedef struct compat_t compat_t;
62typedef struct csconv_t csconv_t;
63typedef struct rec_iconv_t rec_iconv_t;
64
65typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
66typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
67typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize);
68typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize);
69
70#define COMPAT_IN 1
71#define COMPAT_OUT 2
72
73/* unicode mapping for compatibility with other conversion table. */
74struct compat_t {
75 uint in;
76 uint out;
77 uint flag;
78};
79
80struct csconv_t {
81 int codepage;
82 int flags;
83 f_mbtowc mbtowc;
84 f_wctomb wctomb;
85 f_mblen mblen;
86 f_flush flush;
87 DWORD mode;
88 compat_t *compat;
89};
90
91struct rec_iconv_t {
92 iconv_t cd;
93 csconv_t from;
94 csconv_t to;
95};
96
97static int load_mlang(void);
98static int make_csconv(const char *name, csconv_t *cv);
99static int name_to_codepage(const char *name);
100static uint utf16_to_ucs4(const ushort *wbuf);
101static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize);
102static int mbtowc_flags(int codepage);
103static int must_use_null_useddefaultchar(int codepage);
104static int seterror(int err);
105
106static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
107static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
108static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
109static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize);
110static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize);
111
112static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
113static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
114static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
115static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
116static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
117static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
118static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
119static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
120static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
121static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
122static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize);
123
124#define CP_ALIAS_LIST \
125 CP_ALIAS(65001, "CP65001") \
126 CP_ALIAS(65001, "UTF8") \
127 CP_ALIAS(65001, "UTF-8") \
128\
129 CP_ALIAS(1200, "CP1200") \
130 CP_ALIAS(1200, "UTF16LE") \
131 CP_ALIAS(1200, "UTF-16LE") \
132 CP_ALIAS(1200, "UCS2LE") \
133 CP_ALIAS(1200, "UCS-2LE") \
134 CP_ALIAS(1200, "UCS-2-INTERNAL") \
135\
136 CP_ALIAS(1201, "CP1201") \
137 CP_ALIAS(1201, "UTF16BE") \
138 CP_ALIAS(1201, "UTF-16BE") \
139 CP_ALIAS(1201, "UCS2BE") \
140 CP_ALIAS(1201, "UCS-2BE") \
141 CP_ALIAS(1201, "unicodeFFFE") \
142\
143 CP_ALIAS(12000, "CP12000") \
144 CP_ALIAS(12000, "UTF32LE") \
145 CP_ALIAS(12000, "UTF-32LE") \
146 CP_ALIAS(12000, "UCS4LE") \
147 CP_ALIAS(12000, "UCS-4LE") \
148\
149 CP_ALIAS(12001, "CP12001") \
150 CP_ALIAS(12001, "UTF32BE") \
151 CP_ALIAS(12001, "UTF-32BE") \
152 CP_ALIAS(12001, "UCS4BE") \
153 CP_ALIAS(12001, "UCS-4BE") \
154\
155 /* Default is little endian, because the platform is */ \
156 CP_ALIAS(1200, "UTF16") \
157 CP_ALIAS(1200, "UTF-16") \
158 CP_ALIAS(1200, "UCS2") \
159 CP_ALIAS(1200, "UCS-2") \
160 CP_ALIAS(12000, "UTF32") \
161 CP_ALIAS(12000, "UTF-32") \
162 CP_ALIAS(12000, "UCS4") \
163 CP_ALIAS(12000, "UCS-4") \
164\
165 /* copy from libiconv `iconv -l` */ \
166 /* !IsValidCodePage(367) */ \
167 CP_ALIAS(20127, "ANSI_X3.4-1968") \
168 CP_ALIAS(20127, "ANSI_X3.4-1986") \
169 CP_ALIAS(20127, "ASCII") \
170 CP_ALIAS(20127, "CP367") \
171 CP_ALIAS(20127, "IBM367") \
172 CP_ALIAS(20127, "ISO-IR-6") \
173 CP_ALIAS(20127, "ISO646-US") \
174 CP_ALIAS(20127, "ISO_646.IRV:1991") \
175 CP_ALIAS(20127, "US") \
176 CP_ALIAS(20127, "US-ASCII") \
177 CP_ALIAS(20127, "CSASCII") \
178\
179 /* !IsValidCodePage(819) */ \
180 CP_ALIAS(1252, "CP819") \
181 CP_ALIAS(1252, "IBM819") \
182 CP_ALIAS(28591, "ISO-8859-1") \
183 CP_ALIAS(28591, "ISO-IR-100") \
184 CP_ALIAS(28591, "ISO8859-1") \
185 CP_ALIAS(28591, "ISO_8859-1") \
186 CP_ALIAS(28591, "ISO_8859-1:1987") \
187 CP_ALIAS(28591, "L1") \
188 CP_ALIAS(28591, "LATIN1") \
189 CP_ALIAS(28591, "CSISOLATIN1") \
190\
191 CP_ALIAS(1250, "CP1250") \
192 CP_ALIAS(1250, "MS-EE") \
193 CP_ALIAS(1250, "WINDOWS-1250") \
194\
195 CP_ALIAS(1251, "CP1251") \
196 CP_ALIAS(1251, "MS-CYRL") \
197 CP_ALIAS(1251, "WINDOWS-1251") \
198\
199 CP_ALIAS(1252, "CP1252") \
200 CP_ALIAS(1252, "MS-ANSI") \
201 CP_ALIAS(1252, "WINDOWS-1252") \
202\
203 CP_ALIAS(1253, "CP1253") \
204 CP_ALIAS(1253, "MS-GREEK") \
205 CP_ALIAS(1253, "WINDOWS-1253") \
206\
207 CP_ALIAS(1254, "CP1254") \
208 CP_ALIAS(1254, "MS-TURK") \
209 CP_ALIAS(1254, "WINDOWS-1254") \
210\
211 CP_ALIAS(1255, "CP1255") \
212 CP_ALIAS(1255, "MS-HEBR") \
213 CP_ALIAS(1255, "WINDOWS-1255") \
214\
215 CP_ALIAS(1256, "CP1256") \
216 CP_ALIAS(1256, "MS-ARAB") \
217 CP_ALIAS(1256, "WINDOWS-1256") \
218\
219 CP_ALIAS(1257, "CP1257") \
220 CP_ALIAS(1257, "WINBALTRIM") \
221 CP_ALIAS(1257, "WINDOWS-1257") \
222\
223 CP_ALIAS(1258, "CP1258") \
224 CP_ALIAS(1258, "WINDOWS-1258") \
225\
226 CP_ALIAS(850, "850") \
227 CP_ALIAS(850, "CP850") \
228 CP_ALIAS(850, "IBM850") \
229 CP_ALIAS(850, "CSPC850MULTILINGUAL") \
230\
231 /* !IsValidCodePage(862) */ \
232 CP_ALIAS(862, "862") \
233 CP_ALIAS(862, "CP862") \
234 CP_ALIAS(862, "IBM862") \
235 CP_ALIAS(862, "CSPC862LATINHEBREW") \
236\
237 CP_ALIAS(866, "866") \
238 CP_ALIAS(866, "CP866") \
239 CP_ALIAS(866, "IBM866") \
240 CP_ALIAS(866, "CSIBM866") \
241\
242 /* !IsValidCodePage(154) */ \
243 CP_ALIAS(154, "CP154") \
244 CP_ALIAS(154, "CYRILLIC-ASIAN") \
245 CP_ALIAS(154, "PT154") \
246 CP_ALIAS(154, "PTCP154") \
247 CP_ALIAS(154, "CSPTCP154") \
248\
249 /* !IsValidCodePage(1133) */ \
250 CP_ALIAS(1133, "CP1133") \
251 CP_ALIAS(1133, "IBM-CP1133") \
252\
253 CP_ALIAS(874, "CP874") \
254 CP_ALIAS(874, "WINDOWS-874") \
255\
256 /* !IsValidCodePage(51932) */ \
257 CP_ALIAS(51932, "CP51932") \
258 CP_ALIAS(51932, "MS51932") \
259 CP_ALIAS(51932, "WINDOWS-51932") \
260 CP_ALIAS(51932, "EUC-JP") \
261\
262 CP_ALIAS(932, "CP932") \
263 CP_ALIAS(932, "MS932") \
264 CP_ALIAS(932, "SHIFFT_JIS") \
265 CP_ALIAS(932, "SHIFFT_JIS-MS") \
266 CP_ALIAS(932, "SJIS") \
267 CP_ALIAS(932, "SJIS-MS") \
268 CP_ALIAS(932, "SJIS-OPEN") \
269 CP_ALIAS(932, "SJIS-WIN") \
270 CP_ALIAS(932, "WINDOWS-31J") \
271 CP_ALIAS(932, "WINDOWS-932") \
272 CP_ALIAS(932, "CSWINDOWS31J") \
273\
274 CP_ALIAS(50221, "CP50221") \
275 CP_ALIAS(50221, "ISO-2022-JP") \
276 CP_ALIAS(50221, "ISO-2022-JP-MS") \
277 CP_ALIAS(50221, "ISO2022-JP") \
278 CP_ALIAS(50221, "ISO2022-JP-MS") \
279 CP_ALIAS(50221, "MS50221") \
280 CP_ALIAS(50221, "WINDOWS-50221") \
281\
282 CP_ALIAS(936, "CP936") \
283 CP_ALIAS(936, "GBK") \
284 CP_ALIAS(936, "MS936") \
285 CP_ALIAS(936, "WINDOWS-936") \
286\
287 CP_ALIAS(950, "CP950") \
288 CP_ALIAS(950, "BIG5") \
289 CP_ALIAS(950, "BIG5HKSCS") \
290 CP_ALIAS(950, "BIG5-HKSCS") \
291\
292 CP_ALIAS(949, "CP949") \
293 CP_ALIAS(949, "UHC") \
294 CP_ALIAS(949, "EUC-KR") \
295\
296 CP_ALIAS(1361, "CP1361") \
297 CP_ALIAS(1361, "JOHAB") \
298\
299 CP_ALIAS(437, "437") \
300 CP_ALIAS(437, "CP437") \
301 CP_ALIAS(437, "IBM437") \
302 CP_ALIAS(437, "CSPC8CODEPAGE437") \
303\
304 CP_ALIAS(737, "CP737") \
305\
306 CP_ALIAS(775, "CP775") \
307 CP_ALIAS(775, "IBM775") \
308 CP_ALIAS(775, "CSPC775BALTIC") \
309\
310 CP_ALIAS(852, "852") \
311 CP_ALIAS(852, "CP852") \
312 CP_ALIAS(852, "IBM852") \
313 CP_ALIAS(852, "CSPCP852") \
314\
315 /* !IsValidCodePage(853) */ \
316 CP_ALIAS(853, "CP853") \
317\
318 CP_ALIAS(855, "855") \
319 CP_ALIAS(855, "CP855") \
320 CP_ALIAS(855, "IBM855") \
321 CP_ALIAS(855, "CSIBM855") \
322\
323 CP_ALIAS(857, "857") \
324 CP_ALIAS(857, "CP857") \
325 CP_ALIAS(857, "IBM857") \
326 CP_ALIAS(857, "CSIBM857") \
327\
328 /* !IsValidCodePage(858) */ \
329 CP_ALIAS(858, "CP858") \
330\
331 CP_ALIAS(860, "860") \
332 CP_ALIAS(860, "CP860") \
333 CP_ALIAS(860, "IBM860") \
334 CP_ALIAS(860, "CSIBM860") \
335\
336 CP_ALIAS(861, "861") \
337 CP_ALIAS(861, "CP-IS") \
338 CP_ALIAS(861, "CP861") \
339 CP_ALIAS(861, "IBM861") \
340 CP_ALIAS(861, "CSIBM861") \
341\
342 CP_ALIAS(863, "863") \
343 CP_ALIAS(863, "CP863") \
344 CP_ALIAS(863, "IBM863") \
345 CP_ALIAS(863, "CSIBM863") \
346\
347 CP_ALIAS(864, "CP864") \
348 CP_ALIAS(864, "IBM864") \
349 CP_ALIAS(864, "CSIBM864") \
350\
351 CP_ALIAS(865, "865") \
352 CP_ALIAS(865, "CP865") \
353 CP_ALIAS(865, "IBM865") \
354 CP_ALIAS(865, "CSIBM865") \
355\
356 CP_ALIAS(869, "869") \
357 CP_ALIAS(869, "CP-GR") \
358 CP_ALIAS(869, "CP869") \
359 CP_ALIAS(869, "IBM869") \
360 CP_ALIAS(869, "CSIBM869") \
361\
362 /* !IsValidCodePage(1152) */ \
363 CP_ALIAS(1125, "CP1125") \
364\
365 /* \
366 * Code Page Identifiers \
367 * http://msdn2.microsoft.com/en-us/library/ms776446.aspx \
368 */ \
369 CP_ALIAS(37, "IBM037") /* IBM EBCDIC US-Canada */ \
370 CP_ALIAS(437, "IBM437") /* OEM United States */ \
371 CP_ALIAS(500, "IBM500") /* IBM EBCDIC International */ \
372 CP_ALIAS(708, "ASMO-708") /* Arabic (ASMO 708) */ \
373 /* 709 Arabic (ASMO-449+, BCON V4) */ \
374 /* 710 Arabic - Transparent Arabic */ \
375 CP_ALIAS(720, "DOS-720") /* Arabic (Transparent ASMO); Arabic (DOS) */ \
376 CP_ALIAS(737, "ibm737") /* OEM Greek (formerly 437G); Greek (DOS) */ \
377 CP_ALIAS(775, "ibm775") /* OEM Baltic; Baltic (DOS) */ \
378 CP_ALIAS(850, "ibm850") /* OEM Multilingual Latin 1; Western European (DOS) */ \
379 CP_ALIAS(852, "ibm852") /* OEM Latin 2; Central European (DOS) */ \
380 CP_ALIAS(855, "IBM855") /* OEM Cyrillic (primarily Russian) */ \
381 CP_ALIAS(857, "ibm857") /* OEM Turkish; Turkish (DOS) */ \
382 CP_ALIAS(858, "IBM00858") /* OEM Multilingual Latin 1 + Euro symbol */ \
383 CP_ALIAS(860, "IBM860") /* OEM Portuguese; Portuguese (DOS) */ \
384 CP_ALIAS(861, "ibm861") /* OEM Icelandic; Icelandic (DOS) */ \
385 CP_ALIAS(862, "DOS-862") /* OEM Hebrew; Hebrew (DOS) */ \
386 CP_ALIAS(863, "IBM863") /* OEM French Canadian; French Canadian (DOS) */ \
387 CP_ALIAS(864, "IBM864") /* OEM Arabic; Arabic (864) */ \
388 CP_ALIAS(865, "IBM865") /* OEM Nordic; Nordic (DOS) */ \
389 CP_ALIAS(866, "cp866") /* OEM Russian; Cyrillic (DOS) */ \
390 CP_ALIAS(869, "ibm869") /* OEM Modern Greek; Greek, Modern (DOS) */ \
391 CP_ALIAS(870, "IBM870") /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */ \
392 CP_ALIAS(874, "windows-874") /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */ \
393 CP_ALIAS(875, "cp875") /* IBM EBCDIC Greek Modern */ \
394 CP_ALIAS(932, "shift_jis") /* ANSI/OEM Japanese; Japanese (Shift-JIS) */ \
395 CP_ALIAS(932, "shift-jis") /* alternative name for it */ \
396 CP_ALIAS(936, "gb2312") /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */ \
397 CP_ALIAS(949, "ks_c_5601-1987") /* ANSI/OEM Korean (Unified Hangul Code) */ \
398 CP_ALIAS(950, "big5") /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */ \
399 CP_ALIAS(950, "big5hkscs") /* ANSI/OEM Traditional Chinese (Hong Kong SAR); Chinese Traditional (Big5-HKSCS) */ \
400 CP_ALIAS(950, "big5-hkscs") /* alternative name for it */ \
401 CP_ALIAS(1026, "IBM1026") /* IBM EBCDIC Turkish (Latin 5) */ \
402 CP_ALIAS(1047, "IBM01047") /* IBM EBCDIC Latin 1/Open System */ \
403 CP_ALIAS(1140, "IBM01140") /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */ \
404 CP_ALIAS(1141, "IBM01141") /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */ \
405 CP_ALIAS(1142, "IBM01142") /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */ \
406 CP_ALIAS(1143, "IBM01143") /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */ \
407 CP_ALIAS(1144, "IBM01144") /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */ \
408 CP_ALIAS(1145, "IBM01145") /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */ \
409 CP_ALIAS(1146, "IBM01146") /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */ \
410 CP_ALIAS(1147, "IBM01147") /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */ \
411 CP_ALIAS(1148, "IBM01148") /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */ \
412 CP_ALIAS(1149, "IBM01149") /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */ \
413 CP_ALIAS(1250, "windows-1250") /* ANSI Central European; Central European (Windows) */ \
414 CP_ALIAS(1251, "windows-1251") /* ANSI Cyrillic; Cyrillic (Windows) */ \
415 CP_ALIAS(1252, "windows-1252") /* ANSI Latin 1; Western European (Windows) */ \
416 CP_ALIAS(1253, "windows-1253") /* ANSI Greek; Greek (Windows) */ \
417 CP_ALIAS(1254, "windows-1254") /* ANSI Turkish; Turkish (Windows) */ \
418 CP_ALIAS(1255, "windows-1255") /* ANSI Hebrew; Hebrew (Windows) */ \
419 CP_ALIAS(1256, "windows-1256") /* ANSI Arabic; Arabic (Windows) */ \
420 CP_ALIAS(1257, "windows-1257") /* ANSI Baltic; Baltic (Windows) */ \
421 CP_ALIAS(1258, "windows-1258") /* ANSI/OEM Vietnamese; Vietnamese (Windows) */ \
422 CP_ALIAS(1361, "Johab") /* Korean (Johab) */ \
423 CP_ALIAS(10000, "macintosh") /* MAC Roman; Western European (Mac) */ \
424 CP_ALIAS(10001, "x-mac-japanese") /* Japanese (Mac) */ \
425 CP_ALIAS(10002, "x-mac-chinesetrad") /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */ \
426 CP_ALIAS(10003, "x-mac-korean") /* Korean (Mac) */ \
427 CP_ALIAS(10004, "x-mac-arabic") /* Arabic (Mac) */ \
428 CP_ALIAS(10005, "x-mac-hebrew") /* Hebrew (Mac) */ \
429 CP_ALIAS(10006, "x-mac-greek") /* Greek (Mac) */ \
430 CP_ALIAS(10007, "x-mac-cyrillic") /* Cyrillic (Mac) */ \
431 CP_ALIAS(10008, "x-mac-chinesesimp") /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */ \
432 CP_ALIAS(10010, "x-mac-romanian") /* Romanian (Mac) */ \
433 CP_ALIAS(10017, "x-mac-ukrainian") /* Ukrainian (Mac) */ \
434 CP_ALIAS(10021, "x-mac-thai") /* Thai (Mac) */ \
435 CP_ALIAS(10029, "x-mac-ce") /* MAC Latin 2; Central European (Mac) */ \
436 CP_ALIAS(10079, "x-mac-icelandic") /* Icelandic (Mac) */ \
437 CP_ALIAS(10081, "x-mac-turkish") /* Turkish (Mac) */ \
438 CP_ALIAS(10082, "x-mac-croatian") /* Croatian (Mac) */ \
439 CP_ALIAS(20000, "x-Chinese_CNS") /* CNS Taiwan; Chinese Traditional (CNS) */ \
440 CP_ALIAS(20001, "x-cp20001") /* TCA Taiwan */ \
441 CP_ALIAS(20002, "x_Chinese-Eten") /* Eten Taiwan; Chinese Traditional (Eten) */ \
442 CP_ALIAS(20003, "x-cp20003") /* IBM5550 Taiwan */ \
443 CP_ALIAS(20004, "x-cp20004") /* TeleText Taiwan */ \
444 CP_ALIAS(20005, "x-cp20005") /* Wang Taiwan */ \
445 CP_ALIAS(20105, "x-IA5") /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */ \
446 CP_ALIAS(20106, "x-IA5-German") /* IA5 German (7-bit) */ \
447 CP_ALIAS(20107, "x-IA5-Swedish") /* IA5 Swedish (7-bit) */ \
448 CP_ALIAS(20108, "x-IA5-Norwegian") /* IA5 Norwegian (7-bit) */ \
449 CP_ALIAS(20127, "us-ascii") /* US-ASCII (7-bit) */ \
450 CP_ALIAS(20261, "x-cp20261") /* T.61 */ \
451 CP_ALIAS(20269, "x-cp20269") /* ISO 6937 Non-Spacing Accent */ \
452 CP_ALIAS(20273, "IBM273") /* IBM EBCDIC Germany */ \
453 CP_ALIAS(20277, "IBM277") /* IBM EBCDIC Denmark-Norway */ \
454 CP_ALIAS(20278, "IBM278") /* IBM EBCDIC Finland-Sweden */ \
455 CP_ALIAS(20280, "IBM280") /* IBM EBCDIC Italy */ \
456 CP_ALIAS(20284, "IBM284") /* IBM EBCDIC Latin America-Spain */ \
457 CP_ALIAS(20285, "IBM285") /* IBM EBCDIC United Kingdom */ \
458 CP_ALIAS(20290, "IBM290") /* IBM EBCDIC Japanese Katakana Extended */ \
459 CP_ALIAS(20297, "IBM297") /* IBM EBCDIC France */ \
460 CP_ALIAS(20420, "IBM420") /* IBM EBCDIC Arabic */ \
461 CP_ALIAS(20423, "IBM423") /* IBM EBCDIC Greek */ \
462 CP_ALIAS(20424, "IBM424") /* IBM EBCDIC Hebrew */ \
463 CP_ALIAS(20833, "x-EBCDIC-KoreanExtended") /* IBM EBCDIC Korean Extended */ \
464 CP_ALIAS(20838, "IBM-Thai") /* IBM EBCDIC Thai */ \
465 CP_ALIAS(20866, "koi8-r") /* Russian (KOI8-R); Cyrillic (KOI8-R) */ \
466 CP_ALIAS(20871, "IBM871") /* IBM EBCDIC Icelandic */ \
467 CP_ALIAS(20880, "IBM880") /* IBM EBCDIC Cyrillic Russian */ \
468 CP_ALIAS(20905, "IBM905") /* IBM EBCDIC Turkish */ \
469 CP_ALIAS(20924, "IBM00924") /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */ \
470 CP_ALIAS(20932, "EUC-JP") /* Japanese (JIS 0208-1990 and 0121-1990) */ \
471 CP_ALIAS(20936, "x-cp20936") /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */ \
472 CP_ALIAS(20949, "x-cp20949") /* Korean Wansung */ \
473 CP_ALIAS(21025, "cp1025") /* IBM EBCDIC Cyrillic Serbian-Bulgarian */ \
474 /* 21027 (deprecated) */ \
475 CP_ALIAS(21866, "koi8-u") /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */ \
476 CP_ALIAS(28591, "iso-8859-1") /* ISO 8859-1 Latin 1; Western European (ISO) */ \
477 CP_ALIAS(28591, "iso8859-1") /* ISO 8859-1 Latin 1; Western European (ISO) */ \
478 CP_ALIAS(28591, "iso_8859-1") \
479 CP_ALIAS(28591, "iso_8859_1") \
480 CP_ALIAS(28592, "iso-8859-2") /* ISO 8859-2 Central European; Central European (ISO) */ \
481 CP_ALIAS(28592, "iso8859-2") /* ISO 8859-2 Central European; Central European (ISO) */ \
482 CP_ALIAS(28592, "iso_8859-2") \
483 CP_ALIAS(28592, "iso_8859_2") \
484 CP_ALIAS(28593, "iso-8859-3") /* ISO 8859-3 Latin 3 */ \
485 CP_ALIAS(28593, "iso8859-3") /* ISO 8859-3 Latin 3 */ \
486 CP_ALIAS(28593, "iso_8859-3") \
487 CP_ALIAS(28593, "iso_8859_3") \
488 CP_ALIAS(28594, "iso-8859-4") /* ISO 8859-4 Baltic */ \
489 CP_ALIAS(28594, "iso8859-4") /* ISO 8859-4 Baltic */ \
490 CP_ALIAS(28594, "iso_8859-4") \
491 CP_ALIAS(28594, "iso_8859_4") \
492 CP_ALIAS(28595, "iso-8859-5") /* ISO 8859-5 Cyrillic */ \
493 CP_ALIAS(28595, "iso8859-5") /* ISO 8859-5 Cyrillic */ \
494 CP_ALIAS(28595, "iso_8859-5") \
495 CP_ALIAS(28595, "iso_8859_5") \
496 CP_ALIAS(28596, "iso-8859-6") /* ISO 8859-6 Arabic */ \
497 CP_ALIAS(28596, "iso8859-6") /* ISO 8859-6 Arabic */ \
498 CP_ALIAS(28596, "iso_8859-6") \
499 CP_ALIAS(28596, "iso_8859_6") \
500 CP_ALIAS(28597, "iso-8859-7") /* ISO 8859-7 Greek */ \
501 CP_ALIAS(28597, "iso8859-7") /* ISO 8859-7 Greek */ \
502 CP_ALIAS(28597, "iso_8859-7") \
503 CP_ALIAS(28597, "iso_8859_7") \
504 CP_ALIAS(28598, "iso-8859-8") /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */ \
505 CP_ALIAS(28598, "iso8859-8") /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */ \
506 CP_ALIAS(28598, "iso_8859-8") \
507 CP_ALIAS(28598, "iso_8859_8") \
508 CP_ALIAS(28599, "iso-8859-9") /* ISO 8859-9 Turkish */ \
509 CP_ALIAS(28599, "iso8859-9") /* ISO 8859-9 Turkish */ \
510 CP_ALIAS(28599, "iso_8859-9") \
511 CP_ALIAS(28599, "iso_8859_9") \
512 CP_ALIAS(28603, "iso-8859-13") /* ISO 8859-13 Estonian */ \
513 CP_ALIAS(28603, "iso8859-13") /* ISO 8859-13 Estonian */ \
514 CP_ALIAS(28603, "iso_8859-13") \
515 CP_ALIAS(28603, "iso_8859_13") \
516 CP_ALIAS(28605, "iso-8859-15") /* ISO 8859-15 Latin 9 */ \
517 CP_ALIAS(28605, "iso8859-15") /* ISO 8859-15 Latin 9 */ \
518 CP_ALIAS(28605, "iso_8859-15") \
519 CP_ALIAS(28605, "iso_8859_15") \
520 CP_ALIAS(29001, "x-Europa") /* Europa 3 */ \
521 CP_ALIAS(38598, "iso-8859-8-i") /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */ \
522 CP_ALIAS(38598, "iso8859-8-i") /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */ \
523 CP_ALIAS(38598, "iso_8859-8-i") \
524 CP_ALIAS(38598, "iso_8859_8-i") \
525 CP_ALIAS(50220, "iso-2022-jp") /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */ \
526 CP_ALIAS(50221, "csISO2022JP") /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */ \
527 CP_ALIAS(50222, "iso-2022-jp") /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */ \
528 CP_ALIAS(50225, "iso-2022-kr") /* ISO 2022 Korean */ \
529 CP_ALIAS(50225, "iso2022-kr") /* ISO 2022 Korean */ \
530 CP_ALIAS(50227, "x-cp50227") /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */ \
531 /* 50229 ISO 2022 Traditional Chinese */ \
532 /* 50930 EBCDIC Japanese (Katakana) Extended */ \
533 /* 50931 EBCDIC US-Canada and Japanese */ \
534 /* 50933 EBCDIC Korean Extended and Korean */ \
535 /* 50935 EBCDIC Simplified Chinese Extended and Simplified Chinese */ \
536 /* 50936 EBCDIC Simplified Chinese */ \
537 /* 50937 EBCDIC US-Canada and Traditional Chinese */ \
538 /* 50939 EBCDIC Japanese (Latin) Extended and Japanese */ \
539 CP_ALIAS(51932, "euc-jp") /* EUC Japanese */ \
540 CP_ALIAS(51936, "EUC-CN") /* EUC Simplified Chinese; Chinese Simplified (EUC) */ \
541 CP_ALIAS(51949, "euc-kr") /* EUC Korean */ \
542 /* 51950 EUC Traditional Chinese */ \
543 CP_ALIAS(52936, "hz-gb-2312") /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */ \
544 CP_ALIAS(54936, "GB18030") /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */ \
545 CP_ALIAS(57002, "x-iscii-de") /* ISCII Devanagari */ \
546 CP_ALIAS(57003, "x-iscii-be") /* ISCII Bengali */ \
547 CP_ALIAS(57004, "x-iscii-ta") /* ISCII Tamil */ \
548 CP_ALIAS(57005, "x-iscii-te") /* ISCII Telugu */ \
549 CP_ALIAS(57006, "x-iscii-as") /* ISCII Assamese */ \
550 CP_ALIAS(57007, "x-iscii-or") /* ISCII Oriya */ \
551 CP_ALIAS(57008, "x-iscii-ka") /* ISCII Kannada */ \
552 CP_ALIAS(57009, "x-iscii-ma") /* ISCII Malayalam */ \
553 CP_ALIAS(57010, "x-iscii-gu") /* ISCII Gujarati */ \
554 CP_ALIAS(57011, "x-iscii-pa") /* ISCII Punjabi */
555
556#define CP_ALIAS(codepage, alias) codepage,
557static const int cp_codepage[] = {
558 CP_ALIAS_LIST
559};
560#undef CP_ALIAS
561
562#define CP_ALIAS(codepage, alias) alias"\0"
563static const char cp_alias[] ALIGN1 =
564 CP_ALIAS_LIST;
565#undef CP_ALIAS
566
567/*
568 * SJIS SHIFTJIS table CP932 table
569 * ---- --------------------------- --------------------------------
570 * 5C U+00A5 YEN SIGN U+005C REVERSE SOLIDUS
571 * 7E U+203E OVERLINE U+007E TILDE
572 * 815C U+2014 EM DASH U+2015 HORIZONTAL BAR
573 * 815F U+005C REVERSE SOLIDUS U+FF3C FULLWIDTH REVERSE SOLIDUS
574 * 8160 U+301C WAVE DASH U+FF5E FULLWIDTH TILDE
575 * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO
576 * 817C U+2212 MINUS SIGN U+FF0D FULLWIDTH HYPHEN-MINUS
577 * 8191 U+00A2 CENT SIGN U+FFE0 FULLWIDTH CENT SIGN
578 * 8192 U+00A3 POUND SIGN U+FFE1 FULLWIDTH POUND SIGN
579 * 81CA U+00AC NOT SIGN U+FFE2 FULLWIDTH NOT SIGN
580 *
581 * EUC-JP and ISO-2022-JP should be compatible with CP932.
582 *
583 * Kernel and MLang have different Unicode mapping table. Make sure
584 * which API is used.
585 */
586static compat_t cp932_compat[] = {
587 {0x00A5, 0x005C, COMPAT_OUT},
588 {0x203E, 0x007E, COMPAT_OUT},
589 {0x2014, 0x2015, COMPAT_OUT},
590 {0x301C, 0xFF5E, COMPAT_OUT},
591 {0x2016, 0x2225, COMPAT_OUT},
592 {0x2212, 0xFF0D, COMPAT_OUT},
593 {0x00A2, 0xFFE0, COMPAT_OUT},
594 {0x00A3, 0xFFE1, COMPAT_OUT},
595 {0x00AC, 0xFFE2, COMPAT_OUT},
596 {0, 0, 0}
597};
598
599static compat_t cp20932_compat[] = {
600 {0x00A5, 0x005C, COMPAT_OUT},
601 {0x203E, 0x007E, COMPAT_OUT},
602 {0x2014, 0x2015, COMPAT_OUT},
603 {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN},
604 {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN},
605 {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN},
606 {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN},
607 {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN},
608 {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN},
609 {0, 0, 0}
610};
611
612static compat_t *cp51932_compat = cp932_compat;
613
614/* cp20932_compat for kernel. cp932_compat for mlang. */
615static compat_t *cp5022x_compat = cp932_compat;
616
617typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)(
618 LPDWORD lpdwMode,
619 DWORD dwSrcEncoding,
620 LPCSTR lpSrcStr,
621 LPINT lpnMultiCharCount,
622 LPWSTR lpDstStr,
623 LPINT lpnWideCharCount
624);
625
626typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)(
627 LPDWORD lpdwMode,
628 DWORD dwEncoding,
629 LPCWSTR lpSrcStr,
630 LPINT lpnWideCharCount,
631 LPSTR lpDstStr,
632 LPINT lpnMultiCharCount
633);
634
635static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode;
636static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte;
637
638static int
639load_mlang(void)
640{
641 HMODULE h;
642 if (ConvertINetMultiByteToUnicode != NULL)
643 return TRUE;
644 h = LoadLibrary(TEXT("mlang.dll"));
645 if (!h)
646 return FALSE;
647 ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddressA(h, "ConvertINetMultiByteToUnicode");
648 ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddressA(h, "ConvertINetUnicodeToMultiByte");
649 return TRUE;
650}
651
652static iconv_t
653iconv_open(const char *tocode, const char *fromcode)
654{
655 rec_iconv_t *cd;
656
657 cd = (rec_iconv_t *)xzalloc(sizeof(rec_iconv_t));
658
659 /* reset the errno to prevent reporting wrong error code.
660 * 0 for unsorted error. */
661 errno = 0;
662 if (make_csconv(fromcode, &cd->from) && make_csconv(tocode, &cd->to)) {
663 cd->cd = (iconv_t)cd;
664 return (iconv_t)cd;
665 }
666
667 free(cd);
668 return (iconv_t)(-1);
669}
670
671static int
672iconv_close(iconv_t _cd)
673{
674 free(_cd);
675 return 0;
676}
677
678static size_t
679iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
680{
681 rec_iconv_t *cd = (rec_iconv_t *)_cd;
682 ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */
683 int insize;
684 int outsize;
685 int wsize;
686 DWORD frommode;
687 DWORD tomode;
688 uint wc;
689 compat_t *cp;
690 int i;
691
692 if (inbuf == NULL || *inbuf == NULL)
693 {
694 if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL)
695 {
696 tomode = cd->to.mode;
697 outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft);
698 if (outsize == -1)
699 {
700 if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG)
701 {
702 outsize = 0;
703 }
704 else
705 {
706 cd->to.mode = tomode;
707 return (size_t)(-1);
708 }
709 }
710 *outbuf += outsize;
711 *outbytesleft -= outsize;
712 }
713 cd->from.mode = 0;
714 cd->to.mode = 0;
715 return 0;
716 }
717
718 while (*inbytesleft != 0)
719 {
720 frommode = cd->from.mode;
721 tomode = cd->to.mode;
722 wsize = MB_CHAR_MAX;
723
724 insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize);
725 if (insize == -1)
726 {
727 if (cd->to.flags & FLAG_IGNORE)
728 {
729 cd->from.mode = frommode;
730 insize = 1;
731 wsize = 0;
732 }
733 else
734 {
735 cd->from.mode = frommode;
736 return (size_t)(-1);
737 }
738 }
739
740 if (wsize == 0)
741 {
742 *inbuf += insize;
743 *inbytesleft -= insize;
744 continue;
745 }
746
747 if (cd->from.compat != NULL)
748 {
749 wc = utf16_to_ucs4(wbuf);
750 cp = cd->from.compat;
751 for (i = 0; cp[i].in != 0; ++i)
752 {
753 if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc)
754 {
755 ucs4_to_utf16(cp[i].in, wbuf, &wsize);
756 break;
757 }
758 }
759 }
760
761 if (cd->to.compat != NULL)
762 {
763 wc = utf16_to_ucs4(wbuf);
764 cp = cd->to.compat;
765 for (i = 0; cp[i].in != 0; ++i)
766 {
767 if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc)
768 {
769 ucs4_to_utf16(cp[i].out, wbuf, &wsize);
770 break;
771 }
772 }
773 }
774
775 outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft);
776 if (outsize == -1)
777 {
778 if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG)
779 {
780 cd->to.mode = tomode;
781 outsize = 0;
782 }
783 else
784 {
785 cd->from.mode = frommode;
786 cd->to.mode = tomode;
787 return (size_t)(-1);
788 }
789 }
790
791 *inbuf += insize;
792 *outbuf += outsize;
793 *inbytesleft -= insize;
794 *outbytesleft -= outsize;
795 }
796
797 return 0;
798}
799
800static int
801make_csconv(const char *_name, csconv_t *cv)
802{
803 CPINFO cpinfo;
804 int use_compat = TRUE;
805 int flag = 0;
806 char *name;
807 char *p, *s;
808
809 name = xstrdup(_name);
810
811 /* check for option "enc_name//opt1//opt2" */
812 while ((p = strrstr(name, "//")) != NULL)
813 {
814 for (s = p + 2; *s; ++s)
815 *s = tolower(*s);
816 switch (index_in_strings("nocompat\0translit\0ignore\0", p + 2)) {
817 case 0:
818 use_compat = FALSE;
819 break;
820 case 1:
821 flag |= FLAG_TRANSLIT;
822 break;
823 case 2:
824 flag |= FLAG_IGNORE;
825 break;
826 }
827 *p = 0;
828 }
829
830 cv->mode = 0;
831 cv->flags = flag;
832 cv->mblen = NULL;
833 cv->flush = NULL;
834 cv->compat = NULL;
835 cv->codepage = name_to_codepage(name);
836 if (cv->codepage == 1200 || cv->codepage == 1201)
837 {
838 cv->mbtowc = utf16_mbtowc;
839 cv->wctomb = utf16_wctomb;
840 if (_stricmp(name, "UTF-16") == 0 || _stricmp(name, "UTF16") == 0 ||
841 _stricmp(name, "UCS-2") == 0 || _stricmp(name, "UCS2") == 0 ||
842 _stricmp(name,"UCS-2-INTERNAL") == 0)
843 cv->flags |= FLAG_USE_BOM;
844 }
845 else if (cv->codepage == 12000 || cv->codepage == 12001)
846 {
847 cv->mbtowc = utf32_mbtowc;
848 cv->wctomb = utf32_wctomb;
849 if (_stricmp(name, "UTF-32") == 0 || _stricmp(name, "UTF32") == 0 ||
850 _stricmp(name, "UCS-4") == 0 || _stricmp(name, "UCS4") == 0)
851 cv->flags |= FLAG_USE_BOM;
852 }
853 else if (cv->codepage == 65001)
854 {
855 cv->mbtowc = kernel_mbtowc;
856 cv->wctomb = kernel_wctomb;
857 cv->mblen = utf8_mblen;
858 }
859 else if ((cv->codepage == 50220 || cv->codepage == 50221 || cv->codepage == 50222) && load_mlang())
860 {
861 cv->mbtowc = iso2022jp_mbtowc;
862 cv->wctomb = iso2022jp_wctomb;
863 cv->flush = iso2022jp_flush;
864 }
865 else if (cv->codepage == 51932 && load_mlang())
866 {
867 cv->mbtowc = mlang_mbtowc;
868 cv->wctomb = mlang_wctomb;
869 cv->mblen = eucjp_mblen;
870 }
871 else if (IsValidCodePage(cv->codepage)
872 && GetCPInfo(cv->codepage, &cpinfo) != 0)
873 {
874 cv->mbtowc = kernel_mbtowc;
875 cv->wctomb = kernel_wctomb;
876 if (cpinfo.MaxCharSize == 1)
877 cv->mblen = sbcs_mblen;
878 else if (cpinfo.MaxCharSize == 2)
879 cv->mblen = dbcs_mblen;
880 else
881 cv->mblen = mbcs_mblen;
882 }
883 else
884 {
885 /* not supported */
886 free(name);
887 errno = EINVAL;
888 return FALSE;
889 }
890
891 if (use_compat)
892 {
893 switch (cv->codepage)
894 {
895 case 932: cv->compat = cp932_compat; break;
896 case 20932: cv->compat = cp20932_compat; break;
897 case 51932: cv->compat = cp51932_compat; break;
898 case 50220: case 50221: case 50222: cv->compat = cp5022x_compat; break;
899 }
900 }
901
902 free(name);
903
904 return TRUE;
905}
906
907static int
908name_to_codepage(const char *name)
909{
910 int i;
911 const char *alias;
912
913 if (*name == '\0' || strcmp(name, "char") == 0)
914 return GetACP();
915 else if (strcmp(name, "wchar_t") == 0)
916 return 1200;
917 else if (_strnicmp(name, "cp", 2) == 0)
918 return atoi(name + 2); /* CP123 */
919 else if ('0' <= name[0] && name[0] <= '9')
920 return atoi(name); /* 123 */
921 else if (_strnicmp(name, "xx", 2) == 0)
922 return atoi(name + 2); /* XX123 for debug */
923
924 i = 0;
925 alias = cp_alias;
926 while (*alias) {
927 if (_stricmp(alias, name) == 0) {
928 return cp_codepage[i];
929 }
930 alias += strlen(alias) + 1;
931 ++i;
932 }
933 return -1;
934}
935
936/*
937 * http://www.faqs.org/rfcs/rfc2781.html
938 */
939static uint
940utf16_to_ucs4(const ushort *wbuf)
941{
942 uint wc = wbuf[0];
943 if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
944 wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000;
945 return wc;
946}
947
948static void
949ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize)
950{
951 if (wc < 0x10000)
952 {
953 wbuf[0] = wc;
954 *wbufsize = 1;
955 }
956 else
957 {
958 wc -= 0x10000;
959 wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF);
960 wbuf[1] = 0xDC00 | (wc & 0x3FF);
961 *wbufsize = 2;
962 }
963}
964
965/*
966 * Check if codepage is one of those for which the dwFlags parameter
967 * to MultiByteToWideChar() must be zero. Return zero or
968 * MB_ERR_INVALID_CHARS. The docs in Platform SDK for Windows
969 * Server 2003 R2 claims that also codepage 65001 is one of these, but
970 * that doesn't seem to be the case. The MSDN docs for MSVS2008 leave
971 * out 65001 (UTF-8), and that indeed seems to be the case on XP, it
972 * works fine to pass MB_ERR_INVALID_CHARS in dwFlags when converting
973 * from UTF-8.
974 */
975static int
976mbtowc_flags(int codepage)
977{
978 return (codepage == 50220 || codepage == 50221 ||
979 codepage == 50222 || codepage == 50225 ||
980 codepage == 50227 || codepage == 50229 ||
981 codepage == 52936 || codepage == 54936 ||
982 (codepage >= 57002 && codepage <= 57011) ||
983 codepage == 65000 || codepage == 42) ? 0 : MB_ERR_INVALID_CHARS;
984}
985
986/*
987 * Check if codepage is one those for which the lpUsedDefaultChar
988 * parameter to WideCharToMultiByte() must be NULL. The docs in
989 * Platform SDK for Windows Server 2003 R2 claims that this is the
990 * list below, while the MSDN docs for MSVS2008 claim that it is only
991 * for 65000 (UTF-7) and 65001 (UTF-8). This time the earlier Platform
992 * SDK seems to be correct, at least for XP.
993 */
994static int
995must_use_null_useddefaultchar(int codepage)
996{
997 return (codepage == 65000 || codepage == 65001 ||
998 codepage == 50220 || codepage == 50221 ||
999 codepage == 50222 || codepage == 50225 ||
1000 codepage == 50227 || codepage == 50229 ||
1001 codepage == 52936 || codepage == 54936 ||
1002 (codepage >= 57002 && codepage <= 57011) ||
1003 codepage == 42);
1004}
1005
1006static int
1007seterror(int err)
1008{
1009 errno = err;
1010 return -1;
1011}
1012
1013static int
1014sbcs_mblen(csconv_t *cv UNUSED_PARAM, const uchar *buf UNUSED_PARAM,
1015 int bufsize UNUSED_PARAM)
1016{
1017 return 1;
1018}
1019
1020static int
1021dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
1022{
1023 int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1;
1024 if (bufsize < len)
1025 return seterror(EINVAL);
1026 return len;
1027}
1028
1029static int
1030mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
1031{
1032 int len = 0;
1033
1034 if (cv->codepage == 54936) {
1035 if (buf[0] <= 0x7F)
1036 len = 1;
1037 else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
1038 bufsize >= 2 &&
1039 ((buf[1] >= 0x40 && buf[1] <= 0x7E) ||
1040 (buf[1] >= 0x80 && buf[1] <= 0xFE)))
1041 len = 2;
1042 else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
1043 bufsize >= 4 &&
1044 buf[1] >= 0x30 && buf[1] <= 0x39)
1045 len = 4;
1046 else
1047 return seterror(EINVAL);
1048 return len;
1049 }
1050 else
1051 return seterror(EINVAL);
1052}
1053
1054static int
1055utf8_mblen(csconv_t *cv UNUSED_PARAM, const uchar *buf, int bufsize)
1056{
1057 int len = 0;
1058
1059 if (buf[0] < 0x80) len = 1;
1060 else if ((buf[0] & 0xE0) == 0xC0) len = 2;
1061 else if ((buf[0] & 0xF0) == 0xE0) len = 3;
1062 else if ((buf[0] & 0xF8) == 0xF0) len = 4;
1063 else if ((buf[0] & 0xFC) == 0xF8) len = 5;
1064 else if ((buf[0] & 0xFE) == 0xFC) len = 6;
1065
1066 if (len == 0)
1067 return seterror(EILSEQ);
1068 else if (bufsize < len)
1069 return seterror(EINVAL);
1070 return len;
1071}
1072
1073static int
1074eucjp_mblen(csconv_t *cv UNUSED_PARAM, const uchar *buf, int bufsize)
1075{
1076 if (buf[0] < 0x80) /* ASCII */
1077 return 1;
1078 else if (buf[0] == 0x8E) /* JIS X 0201 */
1079 {
1080 if (bufsize < 2)
1081 return seterror(EINVAL);
1082 else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF))
1083 return seterror(EILSEQ);
1084 return 2;
1085 }
1086 else if (buf[0] == 0x8F) /* JIS X 0212 */
1087 {
1088 if (bufsize < 3)
1089 return seterror(EINVAL);
1090 else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE)
1091 || !(0xA1 <= buf[2] && buf[2] <= 0xFE))
1092 return seterror(EILSEQ);
1093 return 3;
1094 }
1095 else /* JIS X 0208 */
1096 {
1097 if (bufsize < 2)
1098 return seterror(EINVAL);
1099 else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE)
1100 || !(0xA1 <= buf[1] && buf[1] <= 0xFE))
1101 return seterror(EILSEQ);
1102 return 2;
1103 }
1104}
1105
1106static int
1107kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
1108{
1109 int len;
1110
1111 len = cv->mblen(cv, buf, bufsize);
1112 if (len == -1)
1113 return -1;
1114 /* If converting from ASCII, reject 8bit
1115 * chars. MultiByteToWideChar() doesn't. Note that for ASCII we
1116 * know that the mblen function is sbcs_mblen() so len is 1.
1117 */
1118 if (cv->codepage == 20127 && buf[0] >= 0x80)
1119 return seterror(EILSEQ);
1120 *wbufsize = MultiByteToWideChar(cv->codepage, mbtowc_flags (cv->codepage),
1121 (const char *)buf, len, (wchar_t *)wbuf, *wbufsize);
1122 if (*wbufsize == 0)
1123 return seterror(EILSEQ);
1124 return len;
1125}
1126
1127static int
1128kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
1129{
1130 BOOL usedDefaultChar = 0;
1131 BOOL *p = NULL;
1132 int flags = 0;
1133 int len;
1134
1135 if (bufsize == 0)
1136 return seterror(E2BIG);
1137 if (!must_use_null_useddefaultchar(cv->codepage))
1138 {
1139 p = &usedDefaultChar;
1140#ifdef WC_NO_BEST_FIT_CHARS
1141 if (!(cv->flags & FLAG_TRANSLIT))
1142 flags |= WC_NO_BEST_FIT_CHARS;
1143#endif
1144 }
1145 len = WideCharToMultiByte(cv->codepage, flags,
1146 (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL, p);
1147 if (len == 0)
1148 {
1149 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1150 return seterror(E2BIG);
1151 return seterror(EILSEQ);
1152 }
1153 else if (usedDefaultChar && !(cv->flags & FLAG_TRANSLIT))
1154 return seterror(EILSEQ);
1155 else if (cv->mblen(cv, buf, len) != len) /* validate result */
1156 return seterror(EILSEQ);
1157 return len;
1158}
1159
1160/*
1161 * It seems that the mode (cv->mode) is fixnum.
1162 * For example, when converting iso-2022-jp(cp50221) to unicode:
1163 * in ascii sequence: mode=0xC42C0000
1164 * in jisx0208 sequence: mode=0xC42C0001
1165 * "C42C" is same for each convert session.
1166 * It should be: ((codepage-1)<<16)|state
1167 */
1168static int
1169mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
1170{
1171 int len;
1172 int insize;
1173 HRESULT hr;
1174
1175 len = cv->mblen(cv, buf, bufsize);
1176 if (len == -1)
1177 return -1;
1178 insize = len;
1179 hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage,
1180 (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize);
1181 if (hr != S_OK || insize != len)
1182 return seterror(EILSEQ);
1183 return len;
1184}
1185
1186static int
1187mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
1188{
1189 char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */
1190 int tmpsize = MB_CHAR_MAX;
1191 int insize = wbufsize;
1192 HRESULT hr;
1193
1194 hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage,
1195 (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize);
1196 if (hr != S_OK || insize != wbufsize)
1197 return seterror(EILSEQ);
1198 else if (bufsize < tmpsize)
1199 return seterror(E2BIG);
1200 else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize)
1201 return seterror(EILSEQ);
1202 memcpy(buf, tmpbuf, tmpsize);
1203 return tmpsize;
1204}
1205
1206static int
1207utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
1208{
1209 int codepage = cv->codepage;
1210
1211 /* swap endian: 1200 <-> 1201 */
1212 if (cv->mode & UNICODE_MODE_SWAPPED)
1213 codepage ^= 1;
1214
1215 if (bufsize < 2)
1216 return seterror(EINVAL);
1217 if (codepage == 1200) /* little endian */
1218 wbuf[0] = (buf[1] << 8) | buf[0];
1219 else if (codepage == 1201) /* big endian */
1220 wbuf[0] = (buf[0] << 8) | buf[1];
1221
1222 if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
1223 {
1224 cv->mode |= UNICODE_MODE_BOM_DONE;
1225 if (wbuf[0] == 0xFFFE)
1226 {
1227 cv->mode |= UNICODE_MODE_SWAPPED;
1228 *wbufsize = 0;
1229 return 2;
1230 }
1231 else if (wbuf[0] == 0xFEFF)
1232 {
1233 *wbufsize = 0;
1234 return 2;
1235 }
1236 }
1237
1238 if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF)
1239 return seterror(EILSEQ);
1240 if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
1241 {
1242 if (bufsize < 4)
1243 return seterror(EINVAL);
1244 if (codepage == 1200) /* little endian */
1245 wbuf[1] = (buf[3] << 8) | buf[2];
1246 else if (codepage == 1201) /* big endian */
1247 wbuf[1] = (buf[2] << 8) | buf[3];
1248 if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF))
1249 return seterror(EILSEQ);
1250 *wbufsize = 2;
1251 return 4;
1252 }
1253 *wbufsize = 1;
1254 return 2;
1255}
1256
1257static int
1258utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
1259{
1260 if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
1261 {
1262 int r;
1263
1264 cv->mode |= UNICODE_MODE_BOM_DONE;
1265 if (bufsize < 2)
1266 return seterror(E2BIG);
1267 if (cv->codepage == 1200) /* little endian */
1268 memcpy(buf, "\xFF\xFE", 2);
1269 else if (cv->codepage == 1201) /* big endian */
1270 memcpy(buf, "\xFE\xFF", 2);
1271
1272 r = utf16_wctomb(cv, wbuf, wbufsize, buf + 2, bufsize - 2);
1273 if (r == -1)
1274 return -1;
1275 return r + 2;
1276 }
1277
1278 if (bufsize < 2)
1279 return seterror(E2BIG);
1280 if (cv->codepage == 1200) /* little endian */
1281 {
1282 buf[0] = (wbuf[0] & 0x00FF);
1283 buf[1] = (wbuf[0] & 0xFF00) >> 8;
1284 }
1285 else if (cv->codepage == 1201) /* big endian */
1286 {
1287 buf[0] = (wbuf[0] & 0xFF00) >> 8;
1288 buf[1] = (wbuf[0] & 0x00FF);
1289 }
1290 if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
1291 {
1292 if (bufsize < 4)
1293 return seterror(E2BIG);
1294 if (cv->codepage == 1200) /* little endian */
1295 {
1296 buf[2] = (wbuf[1] & 0x00FF);
1297 buf[3] = (wbuf[1] & 0xFF00) >> 8;
1298 }
1299 else if (cv->codepage == 1201) /* big endian */
1300 {
1301 buf[2] = (wbuf[1] & 0xFF00) >> 8;
1302 buf[3] = (wbuf[1] & 0x00FF);
1303 }
1304 return 4;
1305 }
1306 return 2;
1307}
1308
1309static int
1310utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
1311{
1312 int codepage = cv->codepage;
1313 uint wc = 0xD800;
1314
1315 /* swap endian: 12000 <-> 12001 */
1316 if (cv->mode & UNICODE_MODE_SWAPPED)
1317 codepage ^= 1;
1318
1319 if (bufsize < 4)
1320 return seterror(EINVAL);
1321 if (codepage == 12000) /* little endian */
1322 wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
1323 else if (codepage == 12001) /* big endian */
1324 wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
1325
1326 if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
1327 {
1328 cv->mode |= UNICODE_MODE_BOM_DONE;
1329 if (wc == 0xFFFE0000)
1330 {
1331 cv->mode |= UNICODE_MODE_SWAPPED;
1332 *wbufsize = 0;
1333 return 4;
1334 }
1335 else if (wc == 0x0000FEFF)
1336 {
1337 *wbufsize = 0;
1338 return 4;
1339 }
1340 }
1341
1342 if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc)
1343 return seterror(EILSEQ);
1344 ucs4_to_utf16(wc, wbuf, wbufsize);
1345 return 4;
1346}
1347
1348static int
1349utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
1350{
1351 uint wc;
1352
1353 if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
1354 {
1355 int r;
1356
1357 cv->mode |= UNICODE_MODE_BOM_DONE;
1358 if (bufsize < 4)
1359 return seterror(E2BIG);
1360 if (cv->codepage == 12000) /* little endian */
1361 memcpy(buf, "\xFF\xFE\x00\x00", 4);
1362 else if (cv->codepage == 12001) /* big endian */
1363 memcpy(buf, "\x00\x00\xFE\xFF", 4);
1364
1365 r = utf32_wctomb(cv, wbuf, wbufsize, buf + 4, bufsize - 4);
1366 if (r == -1)
1367 return -1;
1368 return r + 4;
1369 }
1370
1371 if (bufsize < 4)
1372 return seterror(E2BIG);
1373 wc = utf16_to_ucs4(wbuf);
1374 if (cv->codepage == 12000) /* little endian */
1375 {
1376 buf[0] = wc & 0x000000FF;
1377 buf[1] = (wc & 0x0000FF00) >> 8;
1378 buf[2] = (wc & 0x00FF0000) >> 16;
1379 buf[3] = (wc & 0xFF000000) >> 24;
1380 }
1381 else if (cv->codepage == 12001) /* big endian */
1382 {
1383 buf[0] = (wc & 0xFF000000) >> 24;
1384 buf[1] = (wc & 0x00FF0000) >> 16;
1385 buf[2] = (wc & 0x0000FF00) >> 8;
1386 buf[3] = wc & 0x000000FF;
1387 }
1388 return 4;
1389}
1390
1391/*
1392 * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
1393 * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow
1394 * 1 byte Kana)
1395 * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte
1396 * Kana - SO/SI)
1397 *
1398 * MultiByteToWideChar() and WideCharToMultiByte() behave differently
1399 * depending on Windows version. On XP, WideCharToMultiByte() doesn't
1400 * terminate result sequence with ascii escape. But Vista does.
1401 * Use MLang instead.
1402 */
1403
1404#define ISO2022_MODE(cs, shift) (((cs) << 8) | (shift))
1405#define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF)
1406#define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF)
1407
1408#define ISO2022_SI 0
1409#define ISO2022_SO 1
1410
1411/* shift in */
1412static const char iso2022_SI_seq[] = "\x0F";
1413/* shift out */
1414static const char iso2022_SO_seq[] = "\x0E";
1415
1416typedef struct iso2022_esc_t iso2022_esc_t;
1417struct iso2022_esc_t {
1418 const char *esc;
1419 int esc_len;
1420 int len;
1421 int cs;
1422};
1423
1424#define ISO2022JP_CS_ASCII 0
1425#define ISO2022JP_CS_JISX0201_ROMAN 1
1426#define ISO2022JP_CS_JISX0201_KANA 2
1427#define ISO2022JP_CS_JISX0208_1978 3
1428#define ISO2022JP_CS_JISX0208_1983 4
1429#define ISO2022JP_CS_JISX0212 5
1430
1431static iso2022_esc_t iso2022jp_esc[] = {
1432 {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII},
1433 {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN},
1434 {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA},
1435 {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */
1436 {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983},
1437 {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212},
1438 {NULL, 0, 0, 0}
1439};
1440
1441static int
1442iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
1443{
1444 iso2022_esc_t *iesc = iso2022jp_esc;
1445 char tmp[MB_CHAR_MAX];
1446 int insize;
1447 HRESULT hr;
1448 DWORD dummy = 0;
1449 int len;
1450 int esc_len;
1451 int cs;
1452 int shift;
1453 int i;
1454
1455 if (buf[0] == 0x1B)
1456 {
1457 for (i = 0; iesc[i].esc != NULL; ++i)
1458 {
1459 esc_len = iesc[i].esc_len;
1460 if (bufsize < esc_len)
1461 {
1462 if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0)
1463 return seterror(EINVAL);
1464 }
1465 else
1466 {
1467 if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0)
1468 {
1469 cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI);
1470 *wbufsize = 0;
1471 return esc_len;
1472 }
1473 }
1474 }
1475 /* not supported escape sequence */
1476 return seterror(EILSEQ);
1477 }
1478 else if (buf[0] == iso2022_SO_seq[0])
1479 {
1480 cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO);
1481 *wbufsize = 0;
1482 return 1;
1483 }
1484 else if (buf[0] == iso2022_SI_seq[0])
1485 {
1486 cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI);
1487 *wbufsize = 0;
1488 return 1;
1489 }
1490
1491 cs = ISO2022_MODE_CS(cv->mode);
1492 shift = ISO2022_MODE_SHIFT(cv->mode);
1493
1494 /* reset the mode for informal sequence */
1495 if (buf[0] < 0x20)
1496 {
1497 cs = ISO2022JP_CS_ASCII;
1498 shift = ISO2022_SI;
1499 }
1500
1501 len = iesc[cs].len;
1502 if (bufsize < len)
1503 return seterror(EINVAL);
1504 for (i = 0; i < len; ++i)
1505 if (!(buf[i] < 0x80))
1506 return seterror(EILSEQ);
1507 esc_len = iesc[cs].esc_len;
1508 memcpy(tmp, iesc[cs].esc, esc_len);
1509 if (shift == ISO2022_SO)
1510 {
1511 memcpy(tmp + esc_len, iso2022_SO_seq, 1);
1512 esc_len += 1;
1513 }
1514 memcpy(tmp + esc_len, buf, len);
1515
1516 if ((cv->codepage == 50220 || cv->codepage == 50221
1517 || cv->codepage == 50222) && shift == ISO2022_SO)
1518 {
1519 /* XXX: shift-out cannot be used for mbtowc (both kernel and
1520 * mlang) */
1521 esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len;
1522 memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len);
1523 memcpy(tmp + esc_len, buf, len);
1524 }
1525
1526 insize = len + esc_len;
1527 hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage,
1528 (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize);
1529 if (hr != S_OK || insize != len + esc_len)
1530 return seterror(EILSEQ);
1531
1532 /* Check for conversion error. Assuming defaultChar is 0x3F. */
1533 /* ascii should be converted from ascii */
1534 if (wbuf[0] == buf[0]
1535 && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
1536 return seterror(EILSEQ);
1537
1538 /* reset the mode for informal sequence */
1539 if (cv->mode != ISO2022_MODE(cs, shift))
1540 cv->mode = ISO2022_MODE(cs, shift);
1541
1542 return len;
1543}
1544
1545static int
1546iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
1547{
1548 iso2022_esc_t *iesc = iso2022jp_esc;
1549 char tmp[MB_CHAR_MAX];
1550 int tmpsize = MB_CHAR_MAX;
1551 int insize = wbufsize;
1552 HRESULT hr;
1553 DWORD dummy = 0;
1554 int len;
1555 int esc_len;
1556 int cs;
1557 int shift;
1558 int i;
1559
1560 /*
1561 * MultiByte = [escape sequence] + character + [escape sequence]
1562 *
1563 * Whether trailing escape sequence is added depends on which API is
1564 * used (kernel or MLang, and its version).
1565 */
1566 hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage,
1567 (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize);
1568 if (hr != S_OK || insize != wbufsize)
1569 return seterror(EILSEQ);
1570 else if (bufsize < tmpsize)
1571 return seterror(E2BIG);
1572
1573 if (tmpsize == 1)
1574 {
1575 cs = ISO2022JP_CS_ASCII;
1576 esc_len = 0;
1577 }
1578 else
1579 {
1580 for (i = 1; iesc[i].esc != NULL; ++i)
1581 {
1582 esc_len = iesc[i].esc_len;
1583 if (strncmp(tmp, iesc[i].esc, esc_len) == 0)
1584 {
1585 cs = iesc[i].cs;
1586 break;
1587 }
1588 }
1589 if (iesc[i].esc == NULL)
1590 /* not supported escape sequence */
1591 return seterror(EILSEQ);
1592 }
1593
1594 shift = ISO2022_SI;
1595 if (tmp[esc_len] == iso2022_SO_seq[0])
1596 {
1597 shift = ISO2022_SO;
1598 esc_len += 1;
1599 }
1600
1601 len = iesc[cs].len;
1602
1603 /* Check for converting error. Assuming defaultChar is 0x3F. */
1604 /* ascii should be converted from ascii */
1605 if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80))
1606 return seterror(EILSEQ);
1607 else if (tmpsize < esc_len + len)
1608 return seterror(EILSEQ);
1609
1610 if (cv->mode == ISO2022_MODE(cs, shift))
1611 {
1612 /* remove escape sequence */
1613 if (esc_len != 0)
1614 memmove(tmp, tmp + esc_len, len);
1615 esc_len = 0;
1616 }
1617 else
1618 {
1619 if (cs == ISO2022JP_CS_ASCII)
1620 {
1621 esc_len = iesc[ISO2022JP_CS_ASCII].esc_len;
1622 memmove(tmp + esc_len, tmp, len);
1623 memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len);
1624 }
1625 if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO)
1626 {
1627 /* shift-in before changing to other mode */
1628 memmove(tmp + 1, tmp, len + esc_len);
1629 memcpy(tmp, iso2022_SI_seq, 1);
1630 esc_len += 1;
1631 }
1632 }
1633
1634 if (bufsize < len + esc_len)
1635 return seterror(E2BIG);
1636 memcpy(buf, tmp, len + esc_len);
1637 cv->mode = ISO2022_MODE(cs, shift);
1638 return len + esc_len;
1639}
1640
1641static int
1642iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize)
1643{
1644 iso2022_esc_t *iesc = iso2022jp_esc;
1645 int esc_len;
1646
1647 if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
1648 {
1649 esc_len = 0;
1650 if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
1651 esc_len += 1;
1652 if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
1653 esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
1654 if (bufsize < esc_len)
1655 return seterror(E2BIG);
1656
1657 esc_len = 0;
1658 if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
1659 {
1660 memcpy(buf, iso2022_SI_seq, 1);
1661 esc_len += 1;
1662 }
1663 if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
1664 {
1665 memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc,
1666 iesc[ISO2022JP_CS_ASCII].esc_len);
1667 esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
1668 }
1669 return esc_len;
1670 }
1671 return 0;
1672}
1673
1674static void process_file(iconv_t cd, FILE *in, FILE *out)
1675{
1676 char inbuf[BUFSIZ];
1677 char outbuf[BUFSIZ];
1678 const char *pin;
1679 char *pout;
1680 size_t inbytesleft;
1681 size_t outbytesleft;
1682 size_t rest = 0;
1683 size_t r;
1684
1685 while ((inbytesleft=fread(inbuf+rest, 1, sizeof(inbuf)-rest, in)) != 0
1686 || rest != 0) {
1687 inbytesleft += rest;
1688 pin = inbuf;
1689 pout = outbuf;
1690 outbytesleft = sizeof(outbuf);
1691 r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft);
1692 fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, out);
1693 if (r == (size_t)(-1) && errno != E2BIG &&
1694 (errno != EINVAL || feof(in)))
1695 bb_perror_msg_and_die("conversion error");
1696 memmove(inbuf, pin, inbytesleft);
1697 rest = inbytesleft;
1698 if (rest == 0 && feof(in))
1699 break;
1700 }
1701 pout = outbuf;
1702 outbytesleft = sizeof(outbuf);
1703 r = iconv(cd, NULL, NULL, &pout, &outbytesleft);
1704 fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, out);
1705 if (r == (size_t)(-1))
1706 bb_perror_msg_and_die("conversion error");
1707}
1708
1709enum {
1710 OPT_f = (1 << 0),
1711 OPT_t = (1 << 1),
1712 OPT_l = (1 << 2),
1713 OPT_c = (1 << 3),
1714 OPT_o = (1 << 4),
1715};
1716
1717int iconv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1718int iconv_main(int argc, char **argv)
1719{
1720 const char *fromcode = "", *tocode = "", *outfile;
1721 char *tmpname = NULL;
1722 int i, opt;
1723 iconv_t cd;
1724 FILE *in;
1725 FILE *out = stdout;
1726
1727 opt = getopt32(argv, "f:t:lco:", &fromcode, &tocode, &outfile);
1728
1729 if (opt & OPT_l) {
1730 const char *alias = cp_alias;
1731 while (*alias) {
1732 printf("%s\n", alias);
1733 alias += strlen(alias) + 1;
1734 }
1735 return 0;
1736 }
1737
1738 if (opt & OPT_o) {
1739 tmpname = xasprintf("%sXXXXXX", outfile);
1740 mktemp(tmpname);
1741 out = xfopen(tmpname, "wb");
1742 }
1743
1744 if (opt & OPT_c)
1745 tocode = xasprintf("%s//IGNORE", tocode);
1746
1747 cd = iconv_open(tocode, fromcode);
1748 if (cd == (iconv_t)(-1))
1749 bb_perror_msg_and_die("iconv_open error");
1750
1751 if (optind == argc)
1752 argv[argc++] = (char *)"-";
1753
1754 for (i=optind; i<argc; ++i) {
1755 if (argv[i][0] == '-' && argv[i][1] == '\0')
1756 in = stdin;
1757 else
1758 in = xfopen(argv[optind], "rb");
1759 process_file(cd, in, out);
1760 fclose(in);
1761 }
1762
1763 if (tmpname) {
1764 fclose(out);
1765 xrename(tmpname, outfile);
1766 }
1767
1768 if (ENABLE_FEATURE_CLEAN_UP)
1769 iconv_close(cd);
1770 return 0;
1771}
diff --git a/miscutils/inotifyd.c b/miscutils/inotifyd.c
index 8bff86ae5..fdd04c292 100644
--- a/miscutils/inotifyd.c
+++ b/miscutils/inotifyd.c
@@ -45,8 +45,11 @@
45//usage: "\nPROG ACTUAL_EVENTS FILEn [SUBFILE] is run." 45//usage: "\nPROG ACTUAL_EVENTS FILEn [SUBFILE] is run."
46//usage: "\nIf PROG is -, events are sent to stdout." 46//usage: "\nIf PROG is -, events are sent to stdout."
47//usage: "\nEvents:" 47//usage: "\nEvents:"
48//usage: IF_NOT_PLATFORM_MINGW32(
48//usage: "\n a File is accessed" 49//usage: "\n a File is accessed"
50//usage: )
49//usage: "\n c File is modified" 51//usage: "\n c File is modified"
52//usage: IF_NOT_PLATFORM_MINGW32(
50//usage: "\n e Metadata changed" 53//usage: "\n e Metadata changed"
51//usage: "\n w Writable file is closed" 54//usage: "\n w Writable file is closed"
52//usage: "\n 0 Unwritable file is closed" 55//usage: "\n 0 Unwritable file is closed"
@@ -55,8 +58,11 @@
55//usage: "\n M File is moved" 58//usage: "\n M File is moved"
56//usage: "\n u Backing fs is unmounted" 59//usage: "\n u Backing fs is unmounted"
57//usage: "\n o Event queue overflowed" 60//usage: "\n o Event queue overflowed"
61//usage: )
58//usage: "\n x File can't be watched anymore" 62//usage: "\n x File can't be watched anymore"
63//usage: IF_NOT_PLATFORM_MINGW32(
59//usage: "\nIf watching a directory:" 64//usage: "\nIf watching a directory:"
65//usage: )
60//usage: "\n y Subfile is moved into dir" 66//usage: "\n y Subfile is moved into dir"
61//usage: "\n m Subfile is moved out of dir" 67//usage: "\n m Subfile is moved out of dir"
62//usage: "\n n Subfile is created" 68//usage: "\n n Subfile is created"
@@ -69,6 +75,7 @@
69#include "common_bufsiz.h" 75#include "common_bufsiz.h"
70#include <sys/inotify.h> 76#include <sys/inotify.h>
71 77
78#if !ENABLE_PLATFORM_MINGW32
72static const char mask_names[] ALIGN1 = 79static const char mask_names[] ALIGN1 =
73 "a" // 0x00000001 File was accessed 80 "a" // 0x00000001 File was accessed
74 "c" // 0x00000002 File was modified 81 "c" // 0x00000002 File was modified
@@ -222,3 +229,207 @@ int inotifyd_main(int argc, char **argv)
222 done: 229 done:
223 return bb_got_signal; 230 return bb_got_signal;
224} 231}
232#else /* ENABLE_PLATFORM_MINGW32 */
233/*
234 * Order is important: the indices match the values taken by the
235 * Action member of the FILE_NOTIFY_INFORMATION structure, including
236 * the undocumented zero value when the directory itself is deleted.
237 */
238static const char mask_names[] ALIGN1 =
239 "x" // File is no longer watched (usually deleted)
240 "n" // Subfile was created
241 "d" // Subfile was deleted
242 "c" // File was modified
243 "m" // File was moved from X
244 "y" // File was moved to Y
245;
246
247enum {
248 MASK_BITS = sizeof(mask_names) - 1
249};
250
251static const unsigned mask_values[] = {
252 0x000, // File is no longer watched (usually deleted)
253 0x003, // Subfile was created
254 0x003, // Subfile was deleted
255 0x1fc, // File was modified (everything except create/delete/move)
256 0x003, // File was moved from X
257 0x003, // File was moved to Y
258};
259
260struct watch {
261 HANDLE hdir;
262 HANDLE hevent;
263 DWORD mask; // notification filter
264 DWORD bits; // events to report
265 OVERLAPPED overlap;
266 const char *dirname;
267 char buf[2048];
268};
269
270static void run_agent(const char *agent, FILE_NOTIFY_INFORMATION *info,
271 struct watch *w)
272{
273 int len;
274 char filename[MAX_PATH];
275 char event[2];
276 const char *args[5];
277
278 memset(filename, 0, sizeof(filename));
279 len = WideCharToMultiByte(CP_ACP, 0, info->FileName,
280 info->FileNameLength/2, filename, sizeof(filename),
281 NULL, NULL);
282
283 if (info->Action >= 0 && info->Action < 6 &&
284 ((1 << info->Action) & w->bits)) {
285 event[0] = mask_names[info->Action];
286 event[1] = '\0';
287
288 if (LONE_CHAR(agent, '-')) {
289 /* "inotifyd - FILE": built-in echo */
290 printf(len ? "%s\t%s\t%s\n" : "%s\t%s\n",
291 event, w->dirname, filename);
292 fflush(stdout);
293 }
294 else {
295 args[0] = agent;
296 args[1] = event;
297 args[2] = w->dirname;
298 args[3] = len ? filename : NULL;
299 args[4] = NULL;
300 spawn_and_wait((char **)args);
301 }
302 }
303}
304
305static BOOL start_watch(struct watch *w)
306{
307 DWORD nret;
308
309 memset(w->buf, 0, sizeof(w->buf));
310 memset(&w->overlap, 0, sizeof(OVERLAPPED));
311 w->overlap.hEvent = w->hevent;
312 ResetEvent(w->hevent);
313
314 return ReadDirectoryChangesW(w->hdir, w->buf, sizeof(w->buf),
315 FALSE, w->mask, &nret, &w->overlap, NULL);
316}
317
318int inotifyd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
319int inotifyd_main(int argc, char **argv)
320{
321 int n;
322 unsigned mask, bits;
323 const char *agent;
324 HANDLE *hevent;
325 struct watch *watch;
326
327 // sanity check: agent and at least one watch must be given
328 if (!argv[1] || !argv[2])
329 bb_show_usage();
330
331 argv++;
332 agent = *argv;
333 argc -= 2; // number of files we watch
334
335 watch = (struct watch *)xzalloc(argc * sizeof(struct watch));
336 hevent = (HANDLE *)xzalloc(argc * sizeof(HANDLE));
337
338 // setup watches
339 for (n = 0; *++argv; ++n) {
340 char *masks;
341
342 masks = strrchr(*argv, ':');
343 // don't confuse a drive prefix with a mask
344 if (masks && masks != (*argv)+1)
345 *masks = '\0';
346
347 mask = 0x01ff; // assuming we want all notifications
348 bits = 0x3f; // assuming we want to report everything
349 // if mask is specified ->
350 if (masks && *masks == '\0') {
351 // convert names to notification filter and report bitmask
352 mask = bits = 0;
353 while (*++masks) {
354 const char *found;
355 found = memchr(mask_names, *masks, MASK_BITS);
356 if (found) {
357 mask |= mask_values[(found - mask_names)];
358 bits |= (1 << (found - mask_names));
359 }
360 }
361 }
362
363 if (mask == 0)
364 bb_error_msg_and_die("%s: invalid mask\n", *argv);
365
366 if (!is_directory(*argv, FALSE))
367 bb_error_msg_and_die("%s: not a directory", *argv);
368
369 watch[n].hdir = CreateFile(*argv, GENERIC_READ|FILE_LIST_DIRECTORY,
370 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
371 NULL, OPEN_EXISTING,
372 FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL);
373 if (watch[n].hdir == INVALID_HANDLE_VALUE)
374 break;
375
376 watch[n].dirname = *argv;
377 watch[n].mask = mask;
378 watch[n].bits = bits;
379 watch[n].hevent = hevent[n] = CreateEvent(NULL, TRUE, FALSE, NULL);
380
381 if (!start_watch(watch+n))
382 break;
383 }
384
385 if (*argv != NULL) {
386 errno = err_win_to_posix();
387 bb_perror_msg_and_die("add watch (%s) failed", *argv);
388 }
389
390 while (1) {
391 DWORD status;
392
393 status = WaitForMultipleObjects(n, hevent, FALSE, INFINITE);
394 if (WAIT_OBJECT_0 <= status && status < WAIT_OBJECT_0 + n) {
395 FILE_NOTIFY_INFORMATION *info;
396 int index = status - WAIT_OBJECT_0;
397 int offset = 0;
398 struct watch *w = watch + index;
399 int got_zero = 0;
400
401 do {
402 info = (FILE_NOTIFY_INFORMATION *)(w->buf + offset);
403 got_zero += (info->Action == 0);
404 run_agent(agent, info, w);
405 offset += info->NextEntryOffset;
406 } while (info->NextEntryOffset);
407
408 if (!start_watch(w)) {
409 // directory was deleted?
410 int i, count;
411
412 if (!got_zero) {
413 // we haven't seen an 'x' event, fake one
414 memset(info, 0, sizeof(FILE_NOTIFY_INFORMATION));
415 run_agent(agent, info, w);
416 }
417
418 // mark watch as dead, terminate if all are dead
419 w->mask = 0;
420 for (count = i = 0; i<n; ++i)
421 if (watch[i].mask)
422 ++count;
423 if (count == 0)
424 break;
425 }
426 }
427 else {
428 errno = err_win_to_posix();
429 bb_perror_msg_and_die("watch failed");
430 }
431 }
432
433 return EXIT_SUCCESS;
434}
435#endif
diff --git a/miscutils/jn.c b/miscutils/jn.c
new file mode 100644
index 000000000..db6a3e6d9
--- /dev/null
+++ b/miscutils/jn.c
@@ -0,0 +1,37 @@
1/*
2 * directory junction creation for busybox
3 *
4 * Copyright (C) 2017 Denys Vlasenko <vda.linux@googlemail.com>
5 * Copyright (C) 2022 Ron Yorston <rmy@pobox.com>
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9//config:config JN
10//config: bool "jn (3.2 kb)"
11//config: default y
12//config: depends on PLATFORM_MINGW32
13//config: help
14//config: Creates a directory junction.
15
16//applet:IF_JN(APPLET_NOEXEC(jn, jn, BB_DIR_USR_BIN, BB_SUID_DROP, jn))
17
18//kbuild:lib-$(CONFIG_JN) += jn.o
19
20//usage:#define jn_trivial_usage
21//usage: "DIR JUNC"
22//usage:#define jn_full_usage "\n\n"
23//usage: "Create directory junction JUNC to DIR"
24
25#include "libbb.h"
26
27int jn_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
28int jn_main(int argc UNUSED_PARAM, char **argv)
29{
30 getopt32(argv, "^" "" "\0" "=2");
31 argv += optind;
32 if (create_junction(argv[0], argv[1]) != 0) {
33 bb_perror_msg_and_die("can't create junction '%s' to '%s'",
34 argv[1], argv[0]);
35 }
36 return EXIT_SUCCESS;
37}
diff --git a/miscutils/less.c b/miscutils/less.c
index 8a0525cb7..467c76e2a 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -145,6 +145,10 @@
145 145
146#include <sched.h> /* sched_yield() */ 146#include <sched.h> /* sched_yield() */
147 147
148#if ENABLE_PLATFORM_MINGW32
149#include <conio.h>
150#endif
151
148#include "libbb.h" 152#include "libbb.h"
149#include "common_bufsiz.h" 153#include "common_bufsiz.h"
150#if ENABLE_FEATURE_LESS_REGEXP 154#if ENABLE_FEATURE_LESS_REGEXP
@@ -330,7 +334,11 @@ static void restore_tty(void)
330 set_tty_cooked(); 334 set_tty_cooked();
331 if (!(G.kbd_fd_orig_flags & O_NONBLOCK)) 335 if (!(G.kbd_fd_orig_flags & O_NONBLOCK))
332 ndelay_off(kbd_fd); 336 ndelay_off(kbd_fd);
337#if !ENABLE_PLATFORM_MINGW32
333 clear_line(); 338 clear_line();
339#else
340 printf(ESC"[?1049l");
341#endif
334} 342}
335 343
336static NOINLINE void less_exit(void) 344static NOINLINE void less_exit(void)
@@ -578,6 +586,11 @@ static void read_lines(void)
578 last_line_pos = 0; 586 last_line_pos = 0;
579 break; 587 break;
580 } 588 }
589#if ENABLE_PLATFORM_MINGW32
590 if (c == '\r') {
591 continue;
592 }
593#endif
581 /* NUL is substituted by '\n'! */ 594 /* NUL is substituted by '\n'! */
582 if (c == '\0') c = '\n'; 595 if (c == '\0') c = '\n';
583 *p++ = c; 596 *p++ = c;
@@ -674,7 +687,12 @@ static void update_num_lines(void)
674 /* only do this for regular files */ 687 /* only do this for regular files */
675 if (num_lines == REOPEN_AND_COUNT || num_lines == REOPEN_STDIN) { 688 if (num_lines == REOPEN_AND_COUNT || num_lines == REOPEN_STDIN) {
676 count = 0; 689 count = 0;
690#if !ENABLE_PLATFORM_MINGW32
677 fd = open("/proc/self/fd/0", O_RDONLY); 691 fd = open("/proc/self/fd/0", O_RDONLY);
692#else
693 /* don't even try to access /proc on WIN32 */
694 fd = -1;
695#endif
678 if (fd < 0 && num_lines == REOPEN_AND_COUNT) { 696 if (fd < 0 && num_lines == REOPEN_AND_COUNT) {
679 /* "filename" is valid only if REOPEN_AND_COUNT */ 697 /* "filename" is valid only if REOPEN_AND_COUNT */
680 fd = open(filename, O_RDONLY); 698 fd = open(filename, O_RDONLY);
@@ -857,7 +875,12 @@ static void print_found(const char *line)
857 match_status = 1; 875 match_status = 1;
858 } 876 }
859 877
878#if !ENABLE_PLATFORM_MINGW32
860 printf("%s%s\n", growline ? growline : "", str); 879 printf("%s%s\n", growline ? growline : "", str);
880#else
881 /* skip newline, we use explicit positioning on WIN32 */
882 printf("%s%s", growline ? growline : "", str);
883#endif
861 free(growline); 884 free(growline);
862} 885}
863#else 886#else
@@ -893,7 +916,12 @@ static void print_ascii(const char *str)
893 *p = '\0'; 916 *p = '\0';
894 print_hilite(buf); 917 print_hilite(buf);
895 } 918 }
919#if !ENABLE_PLATFORM_MINGW32
896 puts(str); 920 puts(str);
921#else
922 /* skip newline, we use explicit positioning on WIN32 */
923 printf("%s", str);
924#endif
897} 925}
898 926
899/* Print the buffer */ 927/* Print the buffer */
@@ -903,6 +931,10 @@ static void buffer_print(void)
903 931
904 move_cursor(0, 0); 932 move_cursor(0, 0);
905 for (i = 0; i <= max_displayed_line; i++) { 933 for (i = 0; i <= max_displayed_line; i++) {
934#if ENABLE_PLATFORM_MINGW32
935 /* make sure we're on the right line */
936 move_cursor(i+1, 0);
937#endif
906 printf(CLEAR_2_EOL); 938 printf(CLEAR_2_EOL);
907 if (option_mask32 & FLAG_N) 939 if (option_mask32 & FLAG_N)
908 print_lineno(buffer[i]); 940 print_lineno(buffer[i]);
@@ -1090,10 +1122,17 @@ static void reinitialize(void)
1090 if (G.winsize_err) 1122 if (G.winsize_err)
1091 printf(ESC"[999;999H" ESC"[6n"); 1123 printf(ESC"[999;999H" ESC"[6n");
1092#endif 1124#endif
1125#if ENABLE_PLATFORM_MINGW32
1126 printf(ESC"[?1049h");
1127#endif
1093 buffer_fill_and_print(); 1128 buffer_fill_and_print();
1094} 1129}
1095 1130
1131#if ENABLE_PLATFORM_MINGW32
1132static int64_t unix_getch_nowait(void)
1133#else
1096static int64_t getch_nowait(void) 1134static int64_t getch_nowait(void)
1135#endif
1097{ 1136{
1098 int rd; 1137 int rd;
1099 int64_t key64; 1138 int64_t key64;
@@ -1155,6 +1194,50 @@ static int64_t getch_nowait(void)
1155 return key64; 1194 return key64;
1156} 1195}
1157 1196
1197#if ENABLE_PLATFORM_MINGW32
1198static int64_t getch_nowait(void)
1199{
1200 int64_t c;
1201
1202 if (terminal_mode(FALSE) & VT_INPUT)
1203 return unix_getch_nowait();
1204
1205retry:
1206 c = _getch();
1207 if (c == 0 || c == 0xe0) {
1208 switch (_getch()) {
1209 case 0x48:
1210 c = KEYCODE_UP;
1211 break;
1212 case 0x50:
1213 c = KEYCODE_DOWN;
1214 break;
1215 case 0x49:
1216 c = KEYCODE_PAGEUP;
1217 break;
1218 case 0x51:
1219 c = KEYCODE_PAGEDOWN;
1220 break;
1221 case 0x47:
1222 c = KEYCODE_HOME;
1223 break;
1224 case 0x4f:
1225 c = KEYCODE_END;
1226 break;
1227 default:
1228 goto retry;
1229 }
1230 }
1231
1232 /* Position cursor if line input is done */
1233 if (less_gets_pos >= 0)
1234 move_cursor(max_displayed_line + 2, less_gets_pos + 1);
1235 fflush_all();
1236
1237 return c;
1238}
1239#endif
1240
1158/* Grab a character from input without requiring the return key. 1241/* Grab a character from input without requiring the return key.
1159 * May return KEYCODE_xxx values. 1242 * May return KEYCODE_xxx values.
1160 * Note that this function works best with raw input. */ 1243 * Note that this function works best with raw input. */
@@ -1794,11 +1877,13 @@ static void keypress_process(int keypress)
1794 number_process(keypress); 1877 number_process(keypress);
1795} 1878}
1796 1879
1880#if !ENABLE_PLATFORM_MINGW32
1797static void sig_catcher(int sig) 1881static void sig_catcher(int sig)
1798{ 1882{
1799 restore_tty(); 1883 restore_tty();
1800 kill_myself_with_sig(sig); /* does not return */ 1884 kill_myself_with_sig(sig); /* does not return */
1801} 1885}
1886#endif
1802 1887
1803#if ENABLE_FEATURE_LESS_WINCH 1888#if ENABLE_FEATURE_LESS_WINCH
1804static void sigwinch_handler(int sig UNUSED_PARAM) 1889static void sigwinch_handler(int sig UNUSED_PARAM)
@@ -1810,7 +1895,11 @@ static void sigwinch_handler(int sig UNUSED_PARAM)
1810int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1895int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1811int less_main(int argc, char **argv) 1896int less_main(int argc, char **argv)
1812{ 1897{
1898#if !ENABLE_PLATFORM_MINGW32
1813 char *tty_name; 1899 char *tty_name;
1900#else
1901 HANDLE h;
1902#endif
1814 int tty_fd; 1903 int tty_fd;
1815 1904
1816 INIT_G(); 1905 INIT_G();
@@ -1869,6 +1958,7 @@ int less_main(int argc, char **argv)
1869 if (option_mask32 & FLAG_TILDE) 1958 if (option_mask32 & FLAG_TILDE)
1870 empty_line_marker = ""; 1959 empty_line_marker = "";
1871 1960
1961#if !ENABLE_PLATFORM_MINGW32
1872 /* Some versions of less can survive w/o controlling tty, 1962 /* Some versions of less can survive w/o controlling tty,
1873 * try to do the same. This also allows to specify an alternative 1963 * try to do the same. This also allows to specify an alternative
1874 * tty via "less 1<>TTY". 1964 * tty via "less 1<>TTY".
@@ -1894,6 +1984,15 @@ int less_main(int argc, char **argv)
1894 } 1984 }
1895 G.kbd_fd_orig_flags = ndelay_on(tty_fd); 1985 G.kbd_fd_orig_flags = ndelay_on(tty_fd);
1896 kbd_fd = tty_fd; /* save in a global */ 1986 kbd_fd = tty_fd; /* save in a global */
1987#else
1988 h = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE,
1989 FILE_SHARE_READ, NULL, OPEN_EXISTING,
1990 FILE_ATTRIBUTE_NORMAL, NULL);
1991 if (h == INVALID_HANDLE_VALUE)
1992 bb_simple_error_msg_and_die("unable to open console");
1993
1994 kbd_fd = tty_fd = _open_osfhandle((intptr_t)h, O_BINARY);
1995#endif
1897 1996
1898 get_termios_and_make_raw(tty_fd, &term_less, &term_orig, TERMIOS_RAW_CRNL_INPUT); 1997 get_termios_and_make_raw(tty_fd, &term_less, &term_orig, TERMIOS_RAW_CRNL_INPUT);
1899 1998
diff --git a/miscutils/make.c b/miscutils/make.c
new file mode 100644
index 000000000..7316408bf
--- /dev/null
+++ b/miscutils/make.c
@@ -0,0 +1,3382 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * make implementation for BusyBox
4 *
5 * Based on public domain POSIX make: https://frippery.org/make
6 */
7//config:config MAKE
8//config: bool "make (18 kb)"
9//config: default n
10//config: help
11//config: The make command can be used to maintain files that depend on
12//config: other files. Normally it's used to build programs from source
13//config: code but it can be used in other situations too.
14//config:
15//config:config PDPMAKE
16//config: bool "pdpmake (18 kb)"
17//config: default n
18//config: help
19//config: Alias for "make"
20//config:
21//config:config FEATURE_MAKE_POSIX
22//config: bool "Runtime enforcement of POSIX"
23//config: default n
24//config: depends on MAKE || PDPMAKE
25//config: help
26//config: Allow strict enforcement of POSIX compliance at runtime by:
27//config: - .POSIX special target in makefile
28//config: - '--posix' command line option
29//config: - PDPMAKE_POSIXLY_CORRECT environment variable
30//config: Enable this if you want to check whether your makefiles are
31//config: POSIX compliant. This adds about 1.7 kb.
32//config:
33//config:choice
34//config: prompt "Default POSIX level to enforce"
35//config: depends on FEATURE_MAKE_POSIX
36//config: default FEATURE_MAKE_POSIX_2017
37//config:
38//config:config FEATURE_MAKE_POSIX_2017
39//config: bool "2017"
40//config:
41//config:config FEATURE_MAKE_POSIX_2024
42//config: bool "2024"
43//config:
44//config:endchoice
45
46//applet:IF_MAKE(APPLET(make, BB_DIR_USR_BIN, BB_SUID_DROP))
47//applet:IF_PDPMAKE(APPLET_ODDNAME(pdpmake, make, BB_DIR_USR_BIN, BB_SUID_DROP, make))
48
49//kbuild:lib-$(CONFIG_MAKE) += make.o
50//kbuild:lib-$(CONFIG_PDPMAKE) += make.o
51
52//usage:#define make_trivial_usage
53//usage: IF_FEATURE_MAKE_POSIX(
54//usage: "[--posix] [-C DIR] [-f FILE] [-j NUM] [-x PRAG] [-eiknpqrsSt] [MACRO[:[:[:]]]=VAL]... [TARGET]..."
55//usage: )
56//usage: IF_NOT_FEATURE_MAKE_POSIX(
57//usage: "[-C DIR] [-f FILE] [-j NUM] [-eiknpqrsSt] [MACRO[:[:[:]]]=VAL]... [TARGET]..."
58//usage: )
59//usage:#define make_full_usage "\n\n"
60//usage: "Maintain files based on their dependencies\n"
61//usage: IF_FEATURE_MAKE_POSIX(
62//usage: "\n --posix Enforce POSIX mode"
63//usage: )
64//usage: "\n -C DIR Change to DIR"
65//usage: "\n -f FILE Makefile"
66//usage: "\n -j NUM Jobs to run in parallel (not implemented)"
67//usage: IF_FEATURE_MAKE_POSIX(
68//usage: "\n -x PRAG Make POSIX mode less strict"
69//usage: )
70//usage: "\n -e Environment variables override macros in makefiles"
71//usage: "\n -i Ignore exit status"
72//usage: "\n -k Continue on error"
73//usage: "\n -n Dry run"
74//usage: "\n -p Print macros and targets"
75//usage: "\n -q Query target; exit status 1 if not up to date"
76//usage: "\n -r Don't use built-in rules"
77//usage: "\n -s Make silently"
78//usage: "\n -S Stop on error"
79//usage: "\n -t Touch files instead of making them"
80//usage: IF_FEATURE_MAKE_POSIX(
81//usage: "\n\nThis build supports: non-POSIX extensions, POSIX 2024, POSIX 2017"
82//usage: )
83//usage: IF_FEATURE_MAKE_POSIX_2017(
84//usage: "\nIn strict POSIX mode the 2017 standard is enforced by default"
85//usage: )
86//usage: IF_FEATURE_MAKE_POSIX_2024(
87//usage: "\nIn strict POSIX mode the 2024 standard is enforced by default"
88//usage: )
89
90#include "libbb.h"
91#include "bb_archive.h"
92#include "common_bufsiz.h"
93#include <glob.h>
94
95// Supported POSIX levels
96#define STD_POSIX_2017 0
97#define STD_POSIX_2024 1
98
99#define POSIX_2017 (posix && posix_level == STD_POSIX_2017)
100
101#if ENABLE_FEATURE_MAKE_POSIX_2017
102# define DEFAULT_POSIX_LEVEL STD_POSIX_2017
103#else
104# define DEFAULT_POSIX_LEVEL STD_POSIX_2024
105#endif
106
107#define OPTSTR1 "eij:+knqrsSt"
108#if ENABLE_FEATURE_MAKE_POSIX
109#define OPTSTR2 "pf:*C:*x:*"
110#else
111#define OPTSTR2 "pf:*C:*"
112#endif
113
114enum {
115 OPTBIT_e = 0,
116 OPTBIT_i,
117 OPTBIT_j,
118 OPTBIT_k,
119 OPTBIT_n,
120 OPTBIT_q,
121 OPTBIT_r,
122 OPTBIT_s,
123 OPTBIT_S,
124 OPTBIT_t,
125 OPTBIT_p,
126 OPTBIT_f,
127 OPTBIT_C,
128 IF_FEATURE_MAKE_POSIX(OPTBIT_x,)
129 OPTBIT_precious,
130 OPTBIT_phony,
131 OPTBIT_include,
132 OPTBIT_make,
133
134 OPT_e = (1 << OPTBIT_e),
135 OPT_i = (1 << OPTBIT_i),
136 OPT_j = (1 << OPTBIT_j),
137 OPT_k = (1 << OPTBIT_k),
138 OPT_n = (1 << OPTBIT_n),
139 OPT_q = (1 << OPTBIT_q),
140 OPT_r = (1 << OPTBIT_r),
141 OPT_s = (1 << OPTBIT_s),
142 OPT_S = (1 << OPTBIT_S),
143 OPT_t = (1 << OPTBIT_t),
144 // These options aren't allowed in MAKEFLAGS
145 OPT_p = (1 << OPTBIT_p),
146 OPT_f = (1 << OPTBIT_f),
147 OPT_C = (1 << OPTBIT_C),
148 OPT_x = IF_FEATURE_MAKE_POSIX((1 << OPTBIT_x)) + 0,
149 // The following aren't command line options and must be last
150 OPT_precious = (1 << OPTBIT_precious),
151 OPT_phony = (1 << OPTBIT_phony),
152 OPT_include = (1 << OPTBIT_include),
153 OPT_make = (1 << OPTBIT_make),
154};
155
156// Options in OPTSTR1 that aren't included in MAKEFLAGS
157#define OPT_MASK (~OPT_S)
158
159#define useenv (opts & OPT_e)
160#define ignore (opts & OPT_i)
161#define errcont (opts & OPT_k)
162#define dryrun (opts & OPT_n)
163#define print (opts & OPT_p)
164#define quest (opts & OPT_q)
165#define norules (opts & OPT_r)
166#define silent (opts & OPT_s)
167#define dotouch (opts & OPT_t)
168#define precious (opts & OPT_precious)
169#define doinclude (opts & OPT_include)
170#define domake (opts & OPT_make)
171
172// A name. This represents a file, either to be made, or pre-existing.
173struct name {
174 struct name *n_next; // Next in the list of names
175 char *n_name; // Called
176 struct rule *n_rule; // Rules to build this (prerequisites/commands)
177 struct timespec n_tim; // Modification time of this name
178 uint16_t n_flag; // Info about the name
179};
180
181#define N_DOING 0x01 // Name in process of being built
182#define N_DONE 0x02 // Name looked at
183#define N_TARGET 0x04 // Name is a target
184#define N_PRECIOUS 0x08 // Target is precious
185#define N_DOUBLE 0x10 // Double-colon target
186#define N_SILENT 0x20 // Build target silently
187#define N_IGNORE 0x40 // Ignore build errors
188#define N_SPECIAL 0x80 // Special target
189#define N_MARK 0x100 // Mark for deduplication
190#define N_PHONY 0x200 // Name is a phony target
191#define N_INFERENCE 0x400 // Inference rule
192
193// List of rules to build a target
194struct rule {
195 struct rule *r_next; // Next rule
196 struct depend *r_dep; // Prerequisites for this rule
197 struct cmd *r_cmd; // Commands for this rule
198};
199
200// NOTE: the layout of the following two structures must be compatible.
201// Also, their first two members must be compatible with llist_t.
202
203// List of prerequisites for a rule
204struct depend {
205 struct depend *d_next; // Next prerequisite
206 struct name *d_name; // Name of prerequisite
207 int d_refcnt; // Reference count
208};
209
210// List of commands for a rule
211struct cmd {
212 struct cmd *c_next; // Next command line
213 char *c_cmd; // Text of command line
214 int c_refcnt; // Reference count
215 const char *c_makefile; // Makefile in which command was defined
216 int c_dispno; // Line number within makefile
217};
218
219// Macro storage
220struct macro {
221 struct macro *m_next; // Next variable
222 char *m_name; // Its name
223 char *m_val; // Its value
224 bool m_immediate; // Immediate-expansion macro set using ::=
225 bool m_flag; // Infinite loop check
226 uint8_t m_level; // Level at which macro was created
227};
228
229// Flags passed to setmacro()
230#define M_IMMEDIATE 0x08 // immediate-expansion macro is being defined
231#define M_VALID 0x10 // assert macro name is valid
232#define M_ENVIRON 0x20 // macro imported from environment
233
234// Constants for PRAGMA. Order must match strings in set_pragma().
235enum {
236 BIT_MACRO_NAME = 0,
237 BIT_TARGET_NAME,
238 BIT_COMMAND_COMMENT,
239 BIT_EMPTY_SUFFIX,
240#if ENABLE_PLATFORM_MINGW32
241 BIT_WINDOWS,
242#endif
243 BIT_POSIX_2017,
244 BIT_POSIX_2024,
245 BIT_POSIX_202X,
246
247 P_MACRO_NAME = (1 << BIT_MACRO_NAME),
248 P_TARGET_NAME = (1 << BIT_TARGET_NAME),
249 P_COMMAND_COMMENT = (1 << BIT_COMMAND_COMMENT),
250 P_EMPTY_SUFFIX = (1 << BIT_EMPTY_SUFFIX),
251#if ENABLE_PLATFORM_MINGW32
252 P_WINDOWS = (1 << BIT_WINDOWS),
253#endif
254};
255
256// Status of make()
257#define MAKE_FAILURE 0x01
258#define MAKE_DIDSOMETHING 0x02
259
260#define HTABSIZE 39
261
262struct globals {
263 uint32_t opts;
264 const char *makefile;
265 llist_t *makefiles;
266 llist_t *dirs;
267 struct name *namehead[HTABSIZE];
268 struct macro *macrohead[HTABSIZE];
269 struct name *firstname;
270 struct name *target;
271 time_t ar_mtime;
272 int lineno; // Physical line number in file
273 int dispno; // Line number for display purposes
274 const char *rulepos;
275 int rule_idx;
276#define IF_MAX 10
277 uint8_t clevel;
278 uint8_t cstate[IF_MAX + 1];
279 int numjobs;
280#if ENABLE_FEATURE_MAKE_POSIX
281 bool posix;
282 bool seen_first;
283 llist_t *pragmas;
284 unsigned char pragma;
285 unsigned char posix_level;
286#endif
287} FIX_ALIASING;
288
289#define G (*(struct globals*)bb_common_bufsiz1)
290#define INIT_G() do { \
291 setup_common_bufsiz(); \
292} while (0)
293
294#define opts (G.opts)
295#define makefile (G.makefile)
296#define makefiles (G.makefiles)
297#define dirs (G.dirs)
298#define namehead (G.namehead)
299#define macrohead (G.macrohead)
300#define firstname (G.firstname)
301#define target (G.target)
302#define ar_mtime (G.ar_mtime)
303#define lineno (G.lineno)
304#define dispno (G.dispno)
305#define rulepos (G.rulepos)
306#define rule_idx (G.rule_idx)
307#define clevel (G.clevel)
308#define cstate (G.cstate)
309#define numjobs (G.numjobs)
310#if ENABLE_FEATURE_MAKE_POSIX
311#define posix (G.posix)
312#define seen_first (G.seen_first)
313#define pragmas (G.pragmas)
314#define pragma (G.pragma)
315#define posix_level (G.posix_level)
316#else
317#define posix 0
318#define pragma 0
319#define posix_level DEFAULT_POSIX_LEVEL
320#endif
321
322static int make(struct name *np, int level);
323
324// Return TRUE if c is allowed in a POSIX 2017 macro or target name
325#define ispname(c) (isalpha(c) || isdigit(c) || c == '.' || c == '_')
326// Return TRUE if c is in the POSIX 'portable filename character set'
327#define isfname(c) (ispname(c) || c == '-')
328
329/*
330 * Utility functions.
331 */
332
333/*
334 * Print message, with makefile and line number if possible.
335 */
336static void
337vwarning(FILE *stream, const char *msg, va_list list)
338{
339 fprintf(stream, "%s: ", applet_name);
340 if (makefile)
341 fprintf(stream, "(%s:%d): ", makefile, dispno);
342 vfprintf(stream, msg, list);
343 fputc('\n', stream);
344}
345
346/*
347 * Diagnostic handler. Print message to standard error.
348 */
349static void
350diagnostic(const char *msg, ...)
351{
352 va_list list;
353
354 va_start(list, msg);
355 vwarning(stderr, msg, list);
356 va_end(list);
357}
358
359/*
360 * Error handler. Print message and exit.
361 */
362static void error(const char *msg, ...) NORETURN;
363static void
364error(const char *msg, ...)
365{
366 va_list list;
367
368 va_start(list, msg);
369 vwarning(stderr, msg, list);
370 va_end(list);
371 exit(2);
372}
373
374static void error_unexpected(const char *s) NORETURN;
375static void
376error_unexpected(const char *s)
377{
378 error("unexpected %s", s);
379}
380
381static void error_in_inference_rule(const char *s) NORETURN;
382static void
383error_in_inference_rule(const char *s)
384{
385 error("%s in inference rule", s);
386}
387
388static void
389error_not_allowed(const char *s, const char *t)
390{
391 error("%s not allowed for %s", s, t);
392}
393
394static void
395warning(const char *msg, ...)
396{
397 va_list list;
398
399 va_start(list, msg);
400 vwarning(stdout, msg, list);
401 va_end(list);
402}
403
404static char *
405auto_concat(const char *s1, const char *s2)
406{
407 return auto_string(xasprintf("%s%s", s1, s2));
408}
409
410#if !ENABLE_PLATFORM_MINGW32
411/*
412 * Append a word to a space-separated string of words. The first
413 * call should use a NULL pointer for str, subsequent calls should
414 * pass an allocated string which will be freed.
415 */
416static char *
417xappendword(const char *str, const char *word)
418{
419 char *newstr = str ? xasprintf("%s %s", str, word) : xstrdup(word);
420 free((void *)str);
421 return newstr;
422}
423#endif
424
425static unsigned int
426getbucket(const char *name)
427{
428 unsigned int hashval = 0;
429 const unsigned char *p = (unsigned char *)name;
430
431 while (*p)
432 hashval ^= (hashval << 5) + (hashval >> 2) + *p++;
433 return hashval % HTABSIZE;
434}
435
436/*
437 * Add a prerequisite to the end of the supplied list.
438 */
439static void
440newdep(struct depend **dphead, struct name *np)
441{
442 while (*dphead)
443 dphead = &(*dphead)->d_next;
444 *dphead = xzalloc(sizeof(struct depend));
445 /*(*dphead)->d_next = NULL; - xzalloc did it */
446 (*dphead)->d_name = np;
447 /*(*dphead)->d_refcnt = 0; */
448}
449
450static void
451freedeps(struct depend *dp)
452{
453 if (dp && --dp->d_refcnt <= 0)
454 llist_free((llist_t *)dp, NULL);
455}
456
457/*
458 * Add a command to the end of the supplied list of commands.
459 */
460static void
461newcmd(struct cmd **cphead, char *str)
462{
463 while (isspace(*str))
464 str++;
465
466 while (*cphead)
467 cphead = &(*cphead)->c_next;
468 *cphead = xzalloc(sizeof(struct cmd));
469 /*(*cphead)->c_next = NULL; - xzalloc did it */
470 (*cphead)->c_cmd = xstrdup(str);
471 /*(*cphead)->c_refcnt = 0; */
472 if (makefile)
473 (*cphead)->c_makefile = xstrdup(makefile);
474 (*cphead)->c_dispno = dispno;
475}
476
477static void
478freecmds(struct cmd *cp)
479{
480 struct cmd *nextcp;
481
482 if (cp && --cp->c_refcnt <= 0) {
483 for (; cp; cp = nextcp) {
484 nextcp = cp->c_next;
485 free(cp->c_cmd);
486 free((void *)cp->c_makefile);
487 free(cp);
488 }
489 }
490}
491
492static struct name *
493findname(const char *name)
494{
495 struct name *np = namehead[getbucket(name)];
496 return (struct name *)llist_find_str((llist_t *)np, name);
497}
498
499static int
500check_name(const char *name)
501{
502 const char *s;
503
504#if ENABLE_PLATFORM_MINGW32
505 if (!posix || (pragma & P_WINDOWS)) {
506 if (isalpha(name[0]) && name[1] == ':' && name[2] == '/') {
507 name += 3;
508 }
509 }
510#endif
511 if (!posix) {
512 for (s = name; *s; ++s) {
513 if (*s == '=')
514 return FALSE;
515 }
516 return TRUE;
517 }
518
519 for (s = name; *s; ++s) {
520 if ((pragma & P_TARGET_NAME) || !POSIX_2017 ?
521 !(isfname(*s) || *s == '/') : !ispname(*s))
522 return FALSE;
523 }
524 return TRUE;
525}
526
527static char *splitlib(const char *name, char **member);
528
529static int
530is_valid_target(const char *name)
531{
532 char *archive, *member = NULL;
533 int ret;
534
535 /* Names of the form 'lib(member)' are referred to as 'expressions'
536 * in POSIX and are subjected to special treatment. The 'lib'
537 * and 'member' elements must each be a valid target name. */
538 archive = splitlib(name, &member);
539 ret = check_name(archive) && (member == NULL || check_name(member));
540 free(archive);
541
542 return ret;
543}
544
545#if ENABLE_FEATURE_MAKE_POSIX
546static int
547potentially_valid_target(const char *name)
548{
549 int ret = FALSE;
550
551 if (!(pragma & P_TARGET_NAME)) {
552 pragma |= P_TARGET_NAME;
553 ret = is_valid_target(name);
554 pragma &= ~P_TARGET_NAME;
555 }
556 return ret;
557}
558#endif
559
560/*
561 * Intern a name. Return a pointer to the name struct
562 */
563static struct name *
564newname(const char *name)
565{
566 struct name *np = findname(name);
567
568 if (np == NULL) {
569 unsigned int bucket;
570
571 if (!is_valid_target(name))
572#if ENABLE_FEATURE_MAKE_POSIX
573 error("invalid target name '%s'%s", name,
574 potentially_valid_target(name) ?
575 ": allow with pragma target_name" : "");
576#else
577 error("invalid target name '%s'", name);
578#endif
579
580 bucket = getbucket(name);
581 np = xzalloc(sizeof(struct name));
582 np->n_next = namehead[bucket];
583 namehead[bucket] = np;
584 np->n_name = xstrdup(name);
585 /*np->n_rule = NULL; - xzalloc did it */
586 /*np->n_tim = (struct timespec){0, 0}; */
587 /*np->n_flag = 0; */
588 }
589 return np;
590}
591
592/*
593 * Return the commands on the first rule that has them or NULL.
594 */
595static struct cmd *
596getcmd(struct name *np)
597{
598 struct rule *rp;
599
600 if (np == NULL)
601 return NULL;
602
603 for (rp = np->n_rule; rp; rp = rp->r_next)
604 if (rp->r_cmd)
605 return rp->r_cmd;
606 return NULL;
607}
608
609#if ENABLE_FEATURE_CLEAN_UP
610static void
611freenames(void)
612{
613 int i;
614 struct name *np, *nextnp;
615
616 for (i = 0; i < HTABSIZE; i++) {
617 for (np = namehead[i]; np; np = nextnp) {
618 nextnp = np->n_next;
619 free(np->n_name);
620 freerules(np->n_rule);
621 free(np);
622 }
623 }
624}
625#endif
626
627static void
628freerules(struct rule *rp)
629{
630 struct rule *nextrp;
631
632 for (; rp; rp = nextrp) {
633 nextrp = rp->r_next;
634 freedeps(rp->r_dep);
635 freecmds(rp->r_cmd);
636 free(rp);
637 }
638}
639
640static void *
641inc_ref(void *vp)
642{
643 if (vp) {
644 struct depend *dp = vp;
645 if (dp->d_refcnt == INT_MAX)
646 bb_die_memory_exhausted();
647 dp->d_refcnt++;
648 }
649 return vp;
650}
651
652#if ENABLE_FEATURE_MAKE_POSIX
653// Order must match constants above.
654// POSIX levels must be last and in increasing order
655static const char *p_name =
656 "macro_name\0"
657 "target_name\0"
658 "command_comment\0"
659 "empty_suffix\0"
660#if ENABLE_PLATFORM_MINGW32
661 "windows\0"
662#endif
663 "posix_2017\0"
664 "posix_2024\0"
665 "posix_202x\0";
666
667static void
668set_pragma(const char *name)
669{
670 int idx = index_in_strings(p_name, name);
671
672 if (idx != -1) {
673 if (idx >= BIT_POSIX_2017) {
674 // POSIX level is stored in a separate variable.
675 // No bits in 'pragma' are used.
676 if (posix_level == DEFAULT_POSIX_LEVEL) {
677 posix_level = idx - BIT_POSIX_2017;
678 if (posix_level > STD_POSIX_2024)
679 posix_level = STD_POSIX_2024;
680 } else if (posix_level != idx - BIT_POSIX_2017)
681 warning("unable to change POSIX level");
682 } else {
683 pragma |= 1 << idx;
684 }
685 return;
686 }
687 warning("invalid pragma '%s'", name);
688}
689
690static void
691pragmas_to_env(void)
692{
693 int i;
694 char *val = NULL;
695
696 for (i = 0; i < BIT_POSIX_2017; ++i) {
697 if ((pragma & (1 << i)))
698 val = xappendword(val, nth_string(p_name, i));
699 }
700
701 if (posix_level != DEFAULT_POSIX_LEVEL)
702 val = xappendword(val,
703 nth_string(p_name, BIT_POSIX_2017 + posix_level));
704
705 if (val) {
706 setenv("PDPMAKE_PRAGMAS", val, 1);
707 free(val);
708 }
709}
710#endif
711
712/*
713 * Add a new rule to a target. This checks to see if commands already
714 * exist for the target. If flag is TRUE the target can have multiple
715 * rules with commands (double-colon rules).
716 *
717 * i) If the name is a special target and there are no prerequisites
718 * or commands to be added remove all prerequisites and commands.
719 * This is necessary when clearing a built-in inference rule.
720 * ii) If name is a special target and has commands, replace them.
721 * This is for redefining commands for an inference rule.
722 */
723static void
724addrule(struct name *np, struct depend *dp, struct cmd *cp, int flag)
725{
726 struct rule *rp;
727 struct rule **rpp;
728
729 // Can't mix single-colon and double-colon rules
730 if (!posix && (np->n_flag & N_TARGET)) {
731 if (!(np->n_flag & N_DOUBLE) != !flag) // like xor
732 error("inconsistent rules for target %s", np->n_name);
733 }
734
735 // Clear out prerequisites and commands
736 if ((np->n_flag & N_SPECIAL) && !dp && !cp) {
737 if (strcmp(np->n_name, ".PHONY") == 0)
738 return;
739 freerules(np->n_rule);
740 np->n_rule = NULL;
741 return;
742 }
743
744 if (cp && !(np->n_flag & N_DOUBLE) && getcmd(np)) {
745 // Handle the inference rule redefinition case
746 // .DEFAULT rule can also be redefined (as an extension).
747 if ((np->n_flag & N_INFERENCE)
748 && !(posix && (np->n_flag & N_SPECIAL))
749 ) {
750 freerules(np->n_rule);
751 np->n_rule = NULL;
752 } else {
753 error("commands defined twice for target %s", np->n_name);
754 }
755 }
756
757 rpp = &np->n_rule;
758 while (*rpp)
759 rpp = &(*rpp)->r_next;
760
761 *rpp = rp = xzalloc(sizeof(struct rule));
762 /*rp->r_next = NULL; - xzalloc did it */
763 rp->r_dep = inc_ref(dp);
764 rp->r_cmd = inc_ref(cp);
765
766 np->n_flag |= N_TARGET;
767 if (flag)
768 np->n_flag |= N_DOUBLE;
769#if ENABLE_FEATURE_MAKE_POSIX
770 if (strcmp(np->n_name, ".PRAGMA") == 0) {
771 for (; dp; dp = dp->d_next) {
772 set_pragma(dp->d_name->n_name);
773 }
774 pragmas_to_env();
775 }
776#endif
777}
778
779/*
780 * Macro control for make
781 */
782static struct macro *
783getmp(const char *name)
784{
785 struct macro *mp = macrohead[getbucket(name)];
786 return (struct macro *)llist_find_str((llist_t *)mp, name);
787}
788
789static int
790is_valid_macro(const char *name)
791{
792 const char *s;
793 for (s = name; *s; ++s) {
794 // In POSIX mode only a limited set of characters are guaranteed
795 // to be allowed in macro names.
796 if (posix) {
797 // Find the appropriate character set
798 if ((pragma & P_MACRO_NAME) || !POSIX_2017 ?
799 !isfname(*s) : !ispname(*s))
800 return FALSE;
801 }
802 // As an extension allow anything that can get through the
803 // input parser, apart from the following.
804 if (*s == '=' || isblank(*s) || iscntrl(*s))
805 return FALSE;
806 }
807 return TRUE;
808}
809
810#if ENABLE_FEATURE_MAKE_POSIX
811static int
812potentially_valid_macro(const char *name)
813{
814 int ret = FALSE;
815
816 if (!(pragma & P_MACRO_NAME)) {
817 pragma |= P_MACRO_NAME;
818 ret = is_valid_macro(name);
819 pragma &= ~P_MACRO_NAME;
820 }
821 return ret;
822}
823#endif
824
825static void
826setmacro(const char *name, const char *val, int level)
827{
828 struct macro *mp;
829 bool valid = level & M_VALID;
830 bool from_env = level & M_ENVIRON;
831 bool immediate = level & M_IMMEDIATE;
832
833 level &= ~(M_IMMEDIATE | M_VALID | M_ENVIRON);
834 mp = getmp(name);
835 if (mp) {
836 // Don't replace existing macro from a lower level
837 if (level > mp->m_level)
838 return;
839
840 // Replace existing macro
841 free(mp->m_val);
842 } else {
843 // If not defined, allocate space for new
844 unsigned int bucket;
845
846 if (!valid && !is_valid_macro(name)) {
847 // Silently drop invalid names from the environment
848 if (from_env)
849 return;
850#if ENABLE_FEATURE_MAKE_POSIX
851 error("invalid macro name '%s'%s", name,
852 potentially_valid_macro(name) ?
853 ": allow with pragma macro_name" : "");
854#else
855 error("invalid macro name '%s'", name);
856#endif
857 }
858
859 bucket = getbucket(name);
860 mp = xzalloc(sizeof(struct macro));
861 mp->m_next = macrohead[bucket];
862 macrohead[bucket] = mp;
863 /* mp->m_flag = FALSE; - xzalloc did it */
864 mp->m_name = xstrdup(name);
865 }
866 mp->m_immediate = immediate;
867 mp->m_level = level;
868 mp->m_val = xstrdup(val ? val : "");
869}
870
871#if ENABLE_FEATURE_CLEAN_UP
872static void
873freemacros(void)
874{
875 int i;
876 struct macro *mp, *nextmp;
877
878 for (i = 0; i < HTABSIZE; i++) {
879 for (mp = macrohead[i]; mp; mp = nextmp) {
880 nextmp = mp->m_next;
881 free(mp->m_name);
882 free(mp->m_val);
883 free(mp);
884 }
885 }
886}
887#endif
888
889/*
890 * Get modification time of file or archive member
891 */
892static void FAST_FUNC
893record_mtime(const file_header_t *file_header)
894{
895 ar_mtime = file_header->mtime;
896}
897
898static time_t
899artime(const char *archive, const char *member)
900{
901 archive_handle_t *archive_handle;
902
903 ar_mtime = 0;
904 archive_handle = init_handle();
905 archive_handle->src_fd = open(archive, O_RDONLY);
906 if (archive_handle->src_fd != -1) {
907 archive_handle->action_header = record_mtime;
908 archive_handle->filter = filter_accept_list;
909 llist_add_to_end(&archive_handle->accept, (void *)member);
910 unpack_ar_archive(archive_handle);
911 close(archive_handle->src_fd);
912 }
913
914#if ENABLE_FEATURE_AR_LONG_FILENAMES
915 free(archive_handle->ar__long_names);
916#endif
917 llist_free(archive_handle->accept, NULL);
918 free(archive_handle->file_header);
919 free(archive_handle);
920
921 return ar_mtime;
922}
923
924/*
925 * If the name is of the form 'libname(member.o)' split it into its
926 * name and member parts and set the member pointer to point to the
927 * latter. Otherwise just take a copy of the name and don't alter
928 * the member pointer.
929 *
930 * In either case the return value is an allocated string which must
931 * be freed by the caller.
932 */
933static char *
934splitlib(const char *name, char **member)
935{
936 char *s, *t;
937 size_t len;
938
939 t = xstrdup(name);
940 s = strchr(t, '(');
941 if (s) {
942 // We have 'libname(member.o)'
943 *s++ = '\0';
944 len = strlen(s);
945 if (len <= 1 || s[len - 1] != ')' || *t == '\0')
946 error("invalid name '%s'", name);
947 s[len - 1] = '\0';
948 *member = s;
949 }
950 return t;
951}
952
953/*
954 * Get the modification time of a file. Set it to 0 if the file
955 * doesn't exist.
956 */
957static void
958modtime(struct name *np)
959{
960 char *name, *member = NULL;
961 struct stat info;
962
963 name = splitlib(np->n_name, &member);
964 if (member) {
965 // Looks like library(member)
966 np->n_tim.tv_sec = artime(name, member);
967 np->n_tim.tv_nsec = 0;
968 } else if (stat(name, &info) < 0) {
969 if (errno != ENOENT)
970 bb_perror_msg("can't open %s", name);
971 np->n_tim.tv_sec = 0;
972 np->n_tim.tv_nsec = 0;
973 } else {
974 np->n_tim.tv_sec = info.st_mtim.tv_sec;
975 np->n_tim.tv_nsec = info.st_mtim.tv_nsec;
976 }
977 free(name);
978}
979
980/*
981 * Control of the implicit suffix rules
982 */
983
984/*
985 * Return a pointer to the suffix of a name (which may be the
986 * terminating NUL if there's no suffix).
987 */
988static char *
989suffix(const char *name)
990{
991 char *p = strrchr(name, '.');
992 return p ? p : (char *)name + strlen(name);
993}
994
995/*
996 * Dynamic dependency. This routine applies the suffix rules
997 * to try and find a source and a set of rules for a missing
998 * target. NULL is returned on failure. On success the name of
999 * the implicit prerequisite is returned and the details are
1000 * placed in the imprule structure provided by the caller.
1001 */
1002static struct name *
1003dyndep(struct name *np, struct rule *imprule)
1004{
1005 char *suff, *newsuff;
1006 char *base, *name, *member;
1007 struct name *xp; // Suffixes
1008 struct name *sp; // Suffix rule
1009 struct name *pp = NULL; // Implicit prerequisite
1010 struct rule *rp;
1011 struct depend *dp;
1012 bool chain = FALSE;
1013
1014 member = NULL;
1015 name = splitlib(np->n_name, &member);
1016
1017 suff = xstrdup(suffix(name));
1018 base = member ? member : name;
1019 *suffix(base) = '\0';
1020
1021 xp = newname(".SUFFIXES");
1022 retry:
1023 for (rp = xp->n_rule; rp; rp = rp->r_next) {
1024 for (dp = rp->r_dep; dp; dp = dp->d_next) {
1025 // Generate new suffix rule to try
1026 newsuff = dp->d_name->n_name;
1027 sp = findname(auto_concat(newsuff, suff));
1028 if (sp && sp->n_rule) {
1029 struct name *ip;
1030 int got_ip;
1031
1032 // Has rule already been used in this chain?
1033 if ((sp->n_flag & N_MARK))
1034 continue;
1035
1036 // Generate a name for an implicit prerequisite
1037 ip = newname(auto_concat(base, newsuff));
1038 if ((ip->n_flag & N_DOING))
1039 continue;
1040
1041 if (!ip->n_tim.tv_sec)
1042 modtime(ip);
1043
1044 if (!chain) {
1045 got_ip = ip->n_tim.tv_sec || (ip->n_flag & N_TARGET);
1046 } else {
1047 sp->n_flag |= N_MARK;
1048 got_ip = dyndep(ip, NULL) != NULL;
1049 sp->n_flag &= ~N_MARK;
1050 }
1051
1052 if (got_ip) {
1053 // Prerequisite exists or we know how to make it
1054 if (imprule) {
1055 dp = NULL;
1056 newdep(&dp, ip);
1057 imprule->r_dep = dp;
1058 imprule->r_cmd = sp->n_rule->r_cmd;
1059 }
1060 pp = ip;
1061 goto finish;
1062 }
1063 }
1064 }
1065 }
1066 // If we didn't find an existing file or an explicit rule try
1067 // again, this time looking for a chained inference rule.
1068 if (!posix && !chain) {
1069 chain = TRUE;
1070 goto retry;
1071 }
1072 finish:
1073 free(suff);
1074 free(name);
1075 return pp;
1076}
1077
1078#define RULES \
1079 ".c.o:\n" \
1080 " $(CC) $(CFLAGS) -c $<\n" \
1081 ".y.o:\n" \
1082 " $(YACC) $(YFLAGS) $<\n" \
1083 " $(CC) $(CFLAGS) -c y.tab.c\n" \
1084 " rm -f y.tab.c\n" \
1085 " mv y.tab.o $@\n" \
1086 ".y.c:\n" \
1087 " $(YACC) $(YFLAGS) $<\n" \
1088 " mv y.tab.c $@\n" \
1089 ".l.o:\n" \
1090 " $(LEX) $(LFLAGS) $<\n" \
1091 " $(CC) $(CFLAGS) -c lex.yy.c\n" \
1092 " rm -f lex.yy.c\n" \
1093 " mv lex.yy.o $@\n" \
1094 ".l.c:\n" \
1095 " $(LEX) $(LFLAGS) $<\n" \
1096 " mv lex.yy.c $@\n" \
1097 ".c.a:\n" \
1098 " $(CC) -c $(CFLAGS) $<\n" \
1099 " $(AR) $(ARFLAGS) $@ $*.o\n" \
1100 " rm -f $*.o\n" \
1101 ".c:\n" \
1102 " $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<\n" \
1103 ".sh:\n" \
1104 " cp $< $@\n" \
1105 " chmod a+x $@\n"
1106
1107#define RULES_2017 \
1108 ".SUFFIXES:.o .c .y .l .a .sh .f\n" \
1109 ".f.o:\n" \
1110 " $(FC) $(FFLAGS) -c $<\n" \
1111 ".f.a:\n" \
1112 " $(FC) -c $(FFLAGS) $<\n" \
1113 " $(AR) $(ARFLAGS) $@ $*.o\n" \
1114 " rm -f $*.o\n" \
1115 ".f:\n" \
1116 " $(FC) $(FFLAGS) $(LDFLAGS) -o $@ $<\n"
1117
1118#define RULES_2024 \
1119 ".SUFFIXES:.o .c .y .l .a .sh\n"
1120
1121#define MACROS \
1122 "CFLAGS=-O1\n" \
1123 "YACC=yacc\n" \
1124 "YFLAGS=\n" \
1125 "LEX=lex\n" \
1126 "LFLAGS=\n" \
1127 "AR=ar\n" \
1128 "ARFLAGS=-rv\n" \
1129 "LDFLAGS=\n"
1130
1131#define MACROS_2017 \
1132 "CC=c99\n" \
1133 "FC=fort77\n" \
1134 "FFLAGS=-O1\n" \
1135
1136#define MACROS_2024 \
1137 "CC=c17\n"
1138
1139#define MACROS_EXT \
1140 "CC=cc\n"
1141
1142/*
1143 * Read the built-in rules using a fake fgets-like interface.
1144 */
1145static char *
1146getrules(char *s, int size)
1147{
1148 char *r = s;
1149
1150 if (rulepos == NULL || *rulepos == '\0') {
1151 if (rule_idx == 0) {
1152 rulepos = MACROS;
1153 rule_idx++;
1154 } else if (rule_idx == 1) {
1155 if (POSIX_2017)
1156 rulepos = MACROS_2017;
1157 else if (posix)
1158 rulepos = MACROS_2024;
1159 else
1160 rulepos = MACROS_EXT;
1161 rule_idx++;
1162 } else if (!norules) {
1163 if (rule_idx == 2) {
1164 rulepos = POSIX_2017 ? RULES_2017 : RULES_2024;
1165 rule_idx++;
1166 } else if (rule_idx == 3) {
1167 rulepos = RULES;
1168 rule_idx++;
1169 }
1170 }
1171 }
1172
1173 if (*rulepos == '\0')
1174 return NULL;
1175
1176 while (--size) {
1177 if ((*r++ = *rulepos++) == '\n')
1178 break;
1179 }
1180 *r = '\0';
1181 return s;
1182}
1183
1184/*
1185 * Parse a makefile
1186 */
1187
1188/*
1189 * Return a pointer to the next blank-delimited word or NULL if
1190 * there are none left.
1191 */
1192static char *
1193gettok(char **ptr)
1194{
1195 char *p;
1196
1197 while (isblank(**ptr)) // Skip blanks
1198 (*ptr)++;
1199
1200 if (**ptr == '\0') // Nothing after blanks
1201 return NULL;
1202
1203 p = *ptr; // Word starts here
1204
1205 while (**ptr != '\0' && !isblank(**ptr))
1206 (*ptr)++; // Find end of word
1207
1208 // Terminate token and move on unless already at end of string
1209 if (**ptr != '\0')
1210 *(*ptr)++ = '\0';
1211
1212 return(p);
1213}
1214
1215/*
1216 * Skip over (possibly adjacent or nested) macro expansions.
1217 */
1218static char *
1219skip_macro(const char *s)
1220{
1221 while (*s && s[0] == '$') {
1222 if (s[1] == '(' || s[1] == '{') {
1223 char end = *++s == '(' ? ')' : '}';
1224 while (*s && *s != end)
1225 s = skip_macro(s + 1);
1226 if (*s == end)
1227 ++s;
1228 } else if (s[1] != '\0') {
1229 s += 2;
1230 } else {
1231 break;
1232 }
1233 }
1234 return (char *)s;
1235}
1236
1237/*
1238 * Process each whitespace-separated word in the input string:
1239 *
1240 * - replace paths with their directory or filename part
1241 * - replace prefixes and suffixes
1242 *
1243 * Returns an allocated string or NULL if the input is unmodified.
1244 */
1245static char *
1246modify_words(const char *val, int modifier, size_t lenf, size_t lenr,
1247 const char *find_pref, const char *repl_pref,
1248 const char *find_suff, const char *repl_suff)
1249{
1250 char *s, *copy, *word, *sep, *buf = NULL;
1251 size_t find_pref_len = 0, find_suff_len = 0;
1252
1253 if (!modifier && lenf == 0 && lenr == 0)
1254 return buf;
1255
1256 if (find_pref) {
1257 // get length of find prefix, e.g: src/
1258 find_pref_len = strlen(find_pref);
1259 // get length of find suffix, e.g: .c
1260 find_suff_len = lenf - find_pref_len - 1;
1261 }
1262
1263 s = copy = xstrdup(val);
1264 while ((word = gettok(&s)) != NULL) {
1265 if (modifier) {
1266 sep = strrchr(word, '/');
1267 if (modifier == 'D') {
1268 if (!sep) {
1269 word[0] = '.'; // no '/', return "."
1270 sep = word + 1;
1271 } else if (sep == word) {
1272 // '/' at start of word, return "/"
1273 sep = word + 1;
1274 }
1275 // else terminate at separator
1276 *sep = '\0';
1277 } else if (/* modifier == 'F' && */ sep) {
1278 word = sep + 1;
1279 }
1280 }
1281 if (find_pref != NULL || lenf != 0 || lenr != 0) {
1282 size_t lenw = strlen(word);
1283 // This code implements pattern macro expansions:
1284 // https://austingroupbugs.net/view.php?id=519
1285 //
1286 // find: <prefix>%<suffix>
1287 // example: src/%.c
1288 //
1289 // For a pattern of the form:
1290 // $(string1:[op]%[os]=[np][%][ns])
1291 // lenf is the length of [op]%[os]. So lenf >= 1.
1292 if (find_pref != NULL && lenw + 1 >= lenf) {
1293 // If prefix and suffix of word match find_pref and
1294 // find_suff, then do substitution.
1295 if (strncmp(word, find_pref, find_pref_len) == 0 &&
1296 strcmp(word + lenw - find_suff_len, find_suff) == 0) {
1297 // replace: <prefix>[%<suffix>]
1298 // example: build/%.o or build/all.o (notice no %)
1299 // If repl_suff is NULL, replace whole word with repl_pref.
1300 if (!repl_suff) {
1301 word = xstrdup(repl_pref);
1302 } else {
1303 word[lenw - find_suff_len] = '\0';
1304 word = xasprintf("%s%s%s", repl_pref,
1305 word + find_pref_len, repl_suff);
1306 }
1307 word = auto_string(word);
1308 }
1309 } else if (lenw >= lenf &&
1310 strcmp(word + lenw - lenf, find_suff) == 0) {
1311 word[lenw - lenf] = '\0';
1312 word = auto_concat(word, repl_suff);
1313 }
1314 }
1315 buf = xappendword(buf, word);
1316 }
1317 free(copy);
1318 return buf;
1319}
1320
1321/*
1322 * Return a pointer to the next instance of a given character. Macro
1323 * expansions are skipped so the ':' and '=' in $(VAR:.s1=.s2) aren't
1324 * detected as separators in macro definitions. Some other situations
1325 * also require skipping the internals of a macro expansion.
1326 */
1327static char *
1328find_char(const char *str, int c)
1329{
1330 const char *s;
1331
1332 for (s = skip_macro(str); *s; s = skip_macro(s + 1)) {
1333 if (*s == c)
1334 return (char *)s;
1335 }
1336 return NULL;
1337}
1338
1339#if ENABLE_PLATFORM_MINGW32
1340/*
1341 * Check for a target rule by searching for a colon that isn't
1342 * part of a Windows path. Return a pointer to the colon or NULL.
1343 */
1344static char *
1345find_colon(char *p)
1346{
1347 char *q;
1348
1349 for (q = p; (q = strchr(q, ':')); ++q) {
1350 if (posix && !(pragma & P_WINDOWS))
1351 break;
1352 if (q == p || !isalpha(q[-1]) || q[1] != '/')
1353 break;
1354 }
1355 return q;
1356}
1357#else
1358# define find_colon(s) strchr(s, ':')
1359#endif
1360
1361/*
1362 * Recursively expand any macros in str to an allocated string.
1363 */
1364static char *
1365expand_macros(const char *str, int except_dollar)
1366{
1367 char *exp, *newexp, *s, *t, *p, *q, *name;
1368 char *find, *replace, *modified;
1369 char *expval, *expfind, *find_suff, *repl_suff;
1370 char *find_pref = NULL, *repl_pref = NULL;
1371 size_t lenf, lenr;
1372 char modifier;
1373 struct macro *mp;
1374
1375 exp = xstrdup(str);
1376 for (t = exp; *t; t++) {
1377 if (*t == '$') {
1378 if (t[1] == '\0') {
1379 break;
1380 }
1381 if (t[1] == '$' && except_dollar) {
1382 t++;
1383 continue;
1384 }
1385 // Need to expand a macro. Find its extent (s to t inclusive)
1386 // and take a copy of its content.
1387 s = t;
1388 t++;
1389 if (*t == '{' || *t == '(') {
1390 t = find_char(t, *t == '{' ? '}' : ')');
1391 if (t == NULL)
1392 error("unterminated variable '%s'", s);
1393 name = xstrndup(s + 2, t - s - 2);
1394 } else {
1395 name = xzalloc(2);
1396 name[0] = *t;
1397 /*name[1] = '\0'; - xzalloc did it */
1398 }
1399
1400 // Only do suffix replacement or pattern macro expansion
1401 // if both ':' and '=' are found, plus a '%' for the latter.
1402 // Suffix replacement is indicated by
1403 // find_pref == NULL && (lenf != 0 || lenr != 0);
1404 // pattern macro expansion by find_pref != NULL.
1405 expfind = NULL;
1406 find_suff = repl_suff = NULL;
1407 lenf = lenr = 0;
1408 if ((find = find_char(name, ':'))) {
1409 *find++ = '\0';
1410 expfind = expand_macros(find, FALSE);
1411 if ((replace = find_char(expfind, '='))) {
1412 *replace++ = '\0';
1413 lenf = strlen(expfind);
1414 if (!POSIX_2017 && (find_suff = strchr(expfind, '%'))) {
1415 find_pref = expfind;
1416 repl_pref = replace;
1417 *find_suff++ = '\0';
1418 if ((repl_suff = strchr(replace, '%')))
1419 *repl_suff++ = '\0';
1420 } else {
1421 if (posix && !(pragma & P_EMPTY_SUFFIX) && lenf == 0)
1422 error("empty suffix%s",
1423 !ENABLE_FEATURE_MAKE_POSIX ? "" :
1424 ": allow with pragma empty_suffix");
1425 find_suff = expfind;
1426 repl_suff = replace;
1427 lenr = strlen(repl_suff);
1428 }
1429 }
1430 }
1431
1432 p = q = name;
1433 // If not in POSIX mode expand macros in the name.
1434 if (!POSIX_2017) {
1435 char *expname = expand_macros(name, FALSE);
1436 free(name);
1437 name = expname;
1438 } else {
1439 // Skip over nested expansions in name
1440 do {
1441 *q++ = *p;
1442 } while ((p = skip_macro(p + 1)) && *p);
1443 }
1444
1445 // The internal macros support 'D' and 'F' modifiers
1446 modifier = '\0';
1447 switch (name[0]) {
1448 case '^':
1449 case '+':
1450 if (POSIX_2017)
1451 break;
1452 // fall through
1453 case '@': case '%': case '?': case '<': case '*':
1454 if ((name[1] == 'D' || name[1] == 'F') && name[2] == '\0') {
1455 modifier = name[1];
1456 name[1] = '\0';
1457 }
1458 break;
1459 }
1460
1461 modified = NULL;
1462 if ((mp = getmp(name))) {
1463 // Recursive expansion
1464 if (mp->m_flag)
1465 error("recursive macro %s", name);
1466 // Note if we've expanded $(MAKE)
1467 if (strcmp(name, "MAKE") == 0)
1468 opts |= OPT_make;
1469 mp->m_flag = TRUE;
1470 expval = expand_macros(mp->m_val, FALSE);
1471 mp->m_flag = FALSE;
1472 modified = modify_words(expval, modifier, lenf, lenr,
1473 find_pref, repl_pref, find_suff, repl_suff);
1474 if (modified)
1475 free(expval);
1476 else
1477 modified = expval;
1478 }
1479 free(name);
1480 free(expfind);
1481
1482 if (modified && *modified) {
1483 // The text to be replaced by the macro expansion is
1484 // from s to t inclusive.
1485 *s = '\0';
1486 newexp = xasprintf("%s%s%s", exp, modified, t + 1);
1487 t = newexp + (s - exp) + strlen(modified) - 1;
1488 free(exp);
1489 exp = newexp;
1490 } else {
1491 // Macro wasn't expanded or expanded to nothing.
1492 // Close the space occupied by the macro reference.
1493 q = t + 1;
1494 t = s - 1;
1495 while ((*s++ = *q++))
1496 continue;
1497 }
1498 free(modified);
1499 }
1500 }
1501 return exp;
1502}
1503
1504/*
1505 * Process a non-command line
1506 */
1507static void
1508process_line(char *s)
1509{
1510 char *t;
1511
1512 // Strip comment
1513 // don't treat '#' in macro expansion as a comment
1514 // nor '#' outside macro expansion preceded by backslash
1515 if (!posix) {
1516 char *u = s;
1517 while ((t = find_char(u, '#')) && t > u && t[-1] == '\\') {
1518 for (u = t; *u; ++u) {
1519 u[-1] = u[0];
1520 }
1521 *u = '\0';
1522 u = t;
1523 }
1524 } else
1525 t = strchr(s, '#');
1526 if (t)
1527 *t = '\0';
1528
1529 // Replace escaped newline and any leading white space on the
1530 // following line with a single space. Stop processing at a
1531 // non-escaped newline.
1532 for (t = s; *s && *s != '\n'; ) {
1533 if (s[0] == '\\' && s[1] == '\n') {
1534 s += 2;
1535 while (isspace(*s))
1536 ++s;
1537 *t++ = ' ';
1538 } else {
1539 *t++ = *s++;
1540 }
1541 }
1542 *t = '\0';
1543}
1544
1545enum {
1546 INITIAL = 0,
1547 SKIP_LINE = 1 << 0,
1548 EXPECT_ELSE = 1 << 1,
1549 GOT_MATCH = 1 << 2
1550};
1551
1552#define IFDEF 0
1553#define IFNDEF 1
1554#define IFEQ 2
1555#define IFNEQ 3
1556#define ELSE 0
1557#define ENDIF 1
1558
1559/*
1560 * Extract strings following ifeq/ifneq and compare them.
1561 * Return -1 on error.
1562 */
1563static int
1564compare_strings(char *arg1)
1565{
1566 char *arg2, *end, term, *t1, *t2;
1567 int ret;
1568
1569 // Get first string terminator.
1570 if (arg1[0] == '(')
1571 term = ',';
1572 else if (arg1[0] == '"' || arg1[0] == '\'')
1573 term = arg1[0];
1574 else
1575 return -1;
1576
1577 arg2 = find_char(++arg1, term);
1578 if (arg2 == NULL)
1579 return -1;
1580 *arg2++ = '\0';
1581
1582 // Get second string terminator.
1583 if (term == ',') {
1584 term = ')';
1585 } else {
1586 // Skip spaces between quoted strings.
1587 while (isspace(arg2[0]))
1588 arg2++;
1589 if (arg2[0] == '"' || arg2[0] == '\'')
1590 term = arg2[0];
1591 else
1592 return -1;
1593 ++arg2;
1594 }
1595
1596 end = find_char(arg2, term);
1597 if (end == NULL)
1598 return -1;
1599 *end++ = '\0';
1600
1601 if (gettok(&end) != NULL) {
1602 warning("unexpected text");
1603 }
1604
1605 t1 = expand_macros(arg1, FALSE);
1606 t2 = expand_macros(arg2, FALSE);
1607
1608 ret = strcmp(t1, t2) == 0;
1609 free(t1);
1610 free(t2);
1611 return ret;
1612}
1613
1614/*
1615 * Process conditional directives and return TRUE if the current line
1616 * should be skipped.
1617 */
1618static int
1619skip_line(const char *str1)
1620{
1621 char *copy, *q, *token;
1622 bool new_level = TRUE;
1623 // Default is to return skip flag for current level
1624 int ret = cstate[clevel] & SKIP_LINE;
1625 int key;
1626
1627 q = copy = xstrdup(str1);
1628 process_line(copy);
1629 if ((token = gettok(&q)) != NULL) {
1630 switch (index_in_strings("else\0endif\0", token)) {
1631 case ENDIF:
1632 if (gettok(&q) != NULL)
1633 error_unexpected("text");
1634 if (clevel == 0)
1635 error_unexpected(token);
1636 --clevel;
1637 ret = TRUE;
1638 goto end;
1639 case ELSE:
1640 if (!(cstate[clevel] & EXPECT_ELSE))
1641 error_unexpected(token);
1642
1643 // If an earlier condition matched we'll now skip lines.
1644 // If not we don't, though an 'else if' may override this.
1645 if ((cstate[clevel] & GOT_MATCH))
1646 cstate[clevel] |= SKIP_LINE;
1647 else
1648 cstate[clevel] &= ~SKIP_LINE;
1649
1650 token = gettok(&q);
1651 if (token == NULL) {
1652 // Simple else with no conditional directive
1653 cstate[clevel] &= ~EXPECT_ELSE;
1654 ret = TRUE;
1655 goto end;
1656 } else {
1657 // A conditional directive is now required ('else if').
1658 new_level = FALSE;
1659 }
1660 }
1661
1662 key = index_in_strings("ifdef\0ifndef\0ifeq\0ifneq\0", token);
1663 if (key != -1) {
1664 int match;
1665
1666 if (key == IFDEF || key == IFNDEF) {
1667 // ifdef/ifndef: find out if macro is defined.
1668 char *name = gettok(&q);
1669 if (name != NULL && gettok(&q) == NULL) {
1670 char *t = expand_macros(name, FALSE);
1671 struct macro *mp = getmp(t);
1672 match = mp != NULL && mp->m_val[0] != '\0';
1673 free(t);
1674 } else {
1675 match = -1;
1676 }
1677 } else {
1678 // ifeq/ifneq: compare strings.
1679 match = compare_strings(q);
1680 }
1681
1682 if (match >= 0) {
1683 if (new_level) {
1684 // Start a new level.
1685 if (clevel == IF_MAX)
1686 error("nesting too deep");
1687 ++clevel;
1688 cstate[clevel] = EXPECT_ELSE | SKIP_LINE;
1689 // If we were skipping lines at the previous level
1690 // we need to continue doing that unconditionally
1691 // at the new level.
1692 if ((cstate[clevel - 1] & SKIP_LINE))
1693 cstate[clevel] |= GOT_MATCH;
1694 }
1695
1696 if (!(cstate[clevel] & GOT_MATCH)) {
1697 if (key == IFNDEF || key == IFNEQ)
1698 match = !match;
1699 if (match) {
1700 cstate[clevel] &= ~SKIP_LINE;
1701 cstate[clevel] |= GOT_MATCH;
1702 }
1703 }
1704 } else {
1705 error("invalid condition");
1706 }
1707 ret = TRUE;
1708 } else if (!new_level) {
1709 error("missing conditional");
1710 }
1711 }
1712 end:
1713 free(copy);
1714 return ret;
1715}
1716
1717/*
1718 * If fd is NULL read the built-in rules. Otherwise read from the
1719 * specified file descriptor.
1720 */
1721static char *
1722make_fgets(char *s, int size, FILE *fd)
1723{
1724 return fd ? fgets(s, size, fd) : getrules(s, size);
1725}
1726
1727/*
1728 * Read a newline-terminated line into an allocated string.
1729 * Backslash-escaped newlines don't terminate the line.
1730 * Ignore comment lines. Return NULL on EOF.
1731 */
1732static char *
1733readline(FILE *fd, int want_command)
1734{
1735 char *p, *str = NULL;
1736 int pos = 0;
1737 int len = 0;
1738
1739 for (;;) {
1740 // We need room for at least one character and a NUL terminator
1741 if (len - pos > 1 &&
1742 make_fgets(str + pos, len - pos, fd) == NULL) {
1743 if (pos)
1744 return str;
1745 free(str);
1746 return NULL; // EOF
1747 }
1748
1749 if (len - pos < 2 || (p = strchr(str + pos, '\n')) == NULL) {
1750 // Need more room
1751 if (len)
1752 pos = len - 1;
1753 len += 256;
1754 str = xrealloc(str, len);
1755 continue;
1756 }
1757 lineno++;
1758
1759#if ENABLE_PLATFORM_MINGW32
1760 // Remove CR before LF
1761 if (p != str && p[-1] == '\r') {
1762 p[-1] = '\n';
1763 *p-- = '\0';
1764 }
1765#endif
1766 // Keep going if newline has been escaped
1767 if (p != str && p[-1] == '\\') {
1768 pos = p - str + 1;
1769 continue;
1770 }
1771 dispno = lineno;
1772
1773 // Check for lines that are conditionally skipped.
1774 if (posix || !skip_line(str)) {
1775 if (want_command && *str == '\t')
1776 return str;
1777
1778 // Check for comment lines
1779 p = str;
1780 while (isblank(*p))
1781 p++;
1782
1783 if (*p != '\n' && (posix ? *str != '#' : *p != '#'))
1784 return str;
1785 }
1786
1787 pos = 0;
1788 }
1789}
1790
1791/*
1792 * Return TRUE if the argument is a known suffix.
1793 */
1794static int
1795is_suffix(const char *s)
1796{
1797 struct name *np;
1798 struct rule *rp;
1799 struct depend *dp;
1800
1801 np = newname(".SUFFIXES");
1802 for (rp = np->n_rule; rp; rp = rp->r_next) {
1803 for (dp = rp->r_dep; dp; dp = dp->d_next) {
1804 if (strcmp(s, dp->d_name->n_name) == 0) {
1805 return TRUE;
1806 }
1807 }
1808 }
1809 return FALSE;
1810}
1811
1812enum {
1813 T_NORMAL = 0,
1814 T_SPECIAL = (1 << 0),
1815 T_INFERENCE = (1 << 1), // Inference rule
1816 T_NOPREREQ = (1 << 2), // If set must not have prerequisites
1817 T_COMMAND = (1 << 3), // If set must have commands, if unset must not
1818};
1819
1820/*
1821 * Determine if the argument is a special target and return a set
1822 * of flags indicating its properties.
1823 */
1824static int
1825target_type(char *s)
1826{
1827 char *sfx;
1828 int ret;
1829 static const char *s_name =
1830 ".DEFAULT\0"
1831 ".POSIX\0"
1832 ".IGNORE\0"
1833 ".PRECIOUS\0"
1834 ".SILENT\0"
1835 ".SUFFIXES\0"
1836 ".PHONY\0"
1837 ".NOTPARALLEL\0"
1838 ".WAIT\0"
1839#if ENABLE_FEATURE_MAKE_POSIX
1840 ".PRAGMA\0"
1841#endif
1842 ;
1843
1844 static const uint8_t s_type[] = {
1845 T_SPECIAL | T_NOPREREQ | T_COMMAND,
1846 T_SPECIAL | T_NOPREREQ,
1847 T_SPECIAL,
1848 T_SPECIAL,
1849 T_SPECIAL,
1850 T_SPECIAL,
1851 T_SPECIAL,
1852 T_SPECIAL | T_NOPREREQ,
1853 T_SPECIAL | T_NOPREREQ,
1854 T_SPECIAL,
1855 };
1856
1857 if (*s != '.')
1858 return T_NORMAL;
1859
1860 // Check for one of the known special targets
1861 ret = index_in_strings(s_name, s);
1862 if (ret >= 0)
1863 return s_type[ret];
1864
1865 // Check for an inference rule
1866 ret = T_NORMAL;
1867 sfx = suffix(s);
1868 if (is_suffix(sfx)) {
1869 if (s == sfx) { // Single suffix rule
1870 ret = T_INFERENCE | T_NOPREREQ | T_COMMAND;
1871 } else {
1872 // Suffix is valid, check that prefix is too
1873 *sfx = '\0';
1874 if (is_suffix(s))
1875 ret = T_INFERENCE | T_NOPREREQ | T_COMMAND;
1876 *sfx = '.';
1877 }
1878 }
1879 return ret;
1880}
1881
1882static int
1883ends_with_bracket(const char *s)
1884{
1885 return last_char_is(s, ')') != NULL;
1886}
1887
1888/*
1889 * Process a command line
1890 */
1891static char *
1892process_command(char *s)
1893{
1894 char *t, *u;
1895 int len;
1896 char *outside;
1897
1898 if (!(pragma & P_COMMAND_COMMENT) && posix) {
1899 // POSIX strips comments from command lines
1900 t = strchr(s, '#');
1901 if (t) {
1902 *t = '\0';
1903 warning("comment in command removed: keep with pragma command_comment");
1904 }
1905 }
1906
1907 len = strlen(s) + 1;
1908 outside = xzalloc(len);
1909 for (t = skip_macro(s); *t; t = skip_macro(t + 1)) {
1910 outside[t - s] = 1;
1911 }
1912
1913 // Process escaped newlines. Stop at first non-escaped newline.
1914 for (t = u = s; *u && *u != '\n'; ) {
1915 if (u[0] == '\\' && u[1] == '\n') {
1916 if (POSIX_2017 || outside[u - s]) {
1917 // Outside macro: remove tab following escaped newline.
1918 *t++ = *u++;
1919 *t++ = *u++;
1920 u += (*u == '\t');
1921 } else {
1922 // Inside macro: replace escaped newline and any leading
1923 // whitespace on the following line with a single space.
1924 u += 2;
1925 while (isspace(*u))
1926 ++u;
1927 *t++ = ' ';
1928 }
1929 } else {
1930 *t++ = *u++;
1931 }
1932 }
1933 *t = '\0';
1934 free(outside);
1935 return s;
1936}
1937
1938static char *
1939run_command(const char *cmd)
1940{
1941 FILE *fd;
1942 char *s, *val = NULL;
1943 char buf[256];
1944 size_t len = 0, nread;
1945
1946 if ((fd = popen(cmd, "r")) == NULL)
1947 return val;
1948
1949 for (;;) {
1950 nread = fread(buf, 1, sizeof(buf), fd);
1951 if (nread == 0)
1952 break;
1953
1954 val = xrealloc(val, len + nread + 1);
1955 memcpy(val + len, buf, nread);
1956 len += nread;
1957 val[len] = '\0';
1958 }
1959 pclose(fd);
1960
1961 if (val == NULL)
1962 return NULL;
1963
1964 // Strip leading whitespace in POSIX 2024 mode
1965 if (posix) {
1966 s = val;
1967 while (isspace(*s)) {
1968 ++s;
1969 --len;
1970 }
1971
1972 if (len == 0) {
1973 free(val);
1974 return NULL;
1975 }
1976 memmove(val, s, len + 1);
1977 }
1978
1979#if ENABLE_PLATFORM_MINGW32
1980 len = remove_cr(val, len + 1) - 1;
1981 if (len == 0) {
1982 free(val);
1983 return NULL;
1984 }
1985#endif
1986
1987 // Remove one newline from the end (BSD compatibility)
1988 if (val[len - 1] == '\n')
1989 val[len - 1] = '\0';
1990 // Other newlines are changed to spaces
1991 for (s = val; *s; ++s) {
1992 if (*s == '\n')
1993 *s = ' ';
1994 }
1995 return val;
1996}
1997
1998/*
1999 * Check for an unescaped wildcard character
2000 */
2001static int wildchar(const char *p)
2002{
2003 while (*p) {
2004 switch (*p) {
2005 case '?':
2006 case '*':
2007 case '[':
2008 return 1;
2009 case '\\':
2010 if (p[1] != '\0')
2011 ++p;
2012 break;
2013 }
2014 ++p;
2015 }
2016 return 0;
2017}
2018
2019/*
2020 * Expand any wildcards in a pattern. Return TRUE if a match is
2021 * found, in which case the caller should call globfree() on the
2022 * glob_t structure.
2023 */
2024static int
2025wildcard(char *p, glob_t *gd)
2026{
2027 int ret;
2028 char *s;
2029
2030 // Don't call glob() if there are no wildcards.
2031 if (!wildchar(p)) {
2032 nomatch:
2033 // Remove backslashes from the name.
2034 for (s = p; *p; ++p) {
2035 if (*p == '\\' && p[1] != '\0')
2036 continue;
2037 *s++ = *p;
2038 }
2039 *s = '\0';
2040 return 0;
2041 }
2042
2043 memset(gd, 0, sizeof(*gd));
2044 ret = glob(p, GLOB_NOSORT, NULL, gd);
2045 if (ret == GLOB_NOMATCH) {
2046 globfree(gd);
2047 goto nomatch;
2048 } else if (ret != 0) {
2049 error("glob error for '%s'", p);
2050 }
2051 return 1;
2052}
2053
2054#if ENABLE_FEATURE_MAKE_POSIX
2055static void
2056pragmas_from_env(void)
2057{
2058 char *p, *q, *var;
2059 const char *env = getenv("PDPMAKE_PRAGMAS");
2060
2061 if (env == NULL)
2062 return;
2063
2064 q = var = xstrdup(env);
2065 while ((p = gettok(&q)) != NULL)
2066 set_pragma(p);
2067 free(var);
2068}
2069#endif
2070
2071/*
2072 * Parse input from the makefile and construct a tree structure of it.
2073 */
2074static void
2075input(FILE *fd, int ilevel)
2076{
2077 char *p, *q, *s, *a, *str, *expanded, *copy;
2078 char *str1, *str2;
2079 struct name *np;
2080 struct depend *dp;
2081 struct cmd *cp;
2082 int startno, count;
2083 bool semicolon_cmd, seen_inference;
2084 uint8_t old_clevel = clevel;
2085 bool dbl;
2086 char *lib = NULL;
2087 glob_t gd;
2088 int nfile, i;
2089 char **files;
2090 bool minus;
2091
2092 lineno = 0;
2093 str1 = readline(fd, FALSE);
2094 while (str1) {
2095 str2 = NULL;
2096
2097 // Newlines and comments are handled differently in command lines
2098 // and other types of line. Take a copy of the current line before
2099 // processing it as a non-command line in case it contains a
2100 // rule with a command line. That is, a line of the form:
2101 //
2102 // target: prereq; command
2103 //
2104 copy = xstrdup(str1);
2105 process_line(str1);
2106 str = str1;
2107
2108 // Check for an include line
2109 if (!posix)
2110 while (isblank(*str))
2111 ++str;
2112 minus = !POSIX_2017 && *str == '-';
2113 p = str + minus;
2114 if (strncmp(p, "include", 7) == 0 && isblank(p[7])) {
2115 const char *old_makefile = makefile;
2116 int old_lineno = lineno;
2117
2118 if (ilevel > 16)
2119 error("too many includes");
2120
2121 count = 0;
2122 q = expanded = expand_macros(p + 7, FALSE);
2123 while ((p = gettok(&q)) != NULL) {
2124 FILE *ifd;
2125
2126 ++count;
2127 if (!POSIX_2017) {
2128 // Try to create include file or bring it up-to-date
2129 opts |= OPT_include;
2130 make(newname(p), 1);
2131 opts &= ~OPT_include;
2132 }
2133 if ((ifd = fopen(p, "r")) == NULL) {
2134 if (!minus)
2135 error("can't open include file '%s'", p);
2136 } else {
2137 makefile = p;
2138 input(ifd, ilevel + 1);
2139 fclose(ifd);
2140 makefile = old_makefile;
2141 lineno = old_lineno;
2142 }
2143 if (POSIX_2017)
2144 break;
2145 }
2146 if (POSIX_2017) {
2147 // In POSIX 2017 zero or more than one include file is
2148 // unspecified behaviour.
2149 if (p == NULL || gettok(&q)) {
2150 error("one include file per line");
2151 }
2152 } else if (count == 0) {
2153 // In POSIX 2024 no include file is unspecified behaviour.
2154 if (posix)
2155 error("no include file");
2156 }
2157 goto end_loop;
2158 }
2159
2160 // Check for a macro definition
2161 str = str1;
2162 // POSIX 2024 seems to allow a tab as the first character of
2163 // a macro definition, though most implementations don't.
2164 if (POSIX_2017 && *str == '\t')
2165 error("command not allowed here");
2166 if (find_char(str, '=') != NULL) {
2167 int level = (useenv || fd == NULL) ? 4 : 3;
2168 // Use a copy of the line: we might need the original
2169 // if this turns out to be a target rule.
2170 char *copy2 = xstrdup(str);
2171 char *newq = NULL;
2172 char eq = '\0';
2173 q = find_char(copy2, '='); // q can't be NULL
2174
2175 if (q - 1 > copy2) {
2176 switch (q[-1]) {
2177 case ':':
2178 // '::=' and ':::=' are from POSIX 2024.
2179 if (!POSIX_2017 && q - 2 > copy2 && q[-2] == ':') {
2180 if (q - 3 > copy2 && q[-3] == ':') {
2181 eq = 'B'; // BSD-style ':='
2182 q[-3] = '\0';
2183 } else {
2184 eq = ':'; // GNU-style ':='
2185 q[-2] = '\0';
2186 }
2187 break;
2188 }
2189 // ':=' is a non-POSIX extension.
2190 if (posix)
2191 break;
2192 goto set_eq;
2193 case '+':
2194 case '?':
2195 case '!':
2196 // '+=', '?=' and '!=' are from POSIX 2024.
2197 if (POSIX_2017)
2198 break;
2199 set_eq:
2200 eq = q[-1];
2201 q[-1] = '\0';
2202 break;
2203 }
2204 }
2205 *q++ = '\0'; // Separate name and value
2206 while (isblank(*q))
2207 q++;
2208 if ((p = strrchr(q, '\n')) != NULL)
2209 *p = '\0';
2210
2211 // Expand left-hand side of assignment
2212 p = expanded = expand_macros(copy2, FALSE);
2213 if ((a = gettok(&p)) == NULL)
2214 error("invalid macro assignment");
2215
2216 // If the expanded LHS contains ':' and ';' it can't be a
2217 // macro assignment but it might be a target rule.
2218 if ((s = strchr(a, ':')) != NULL && strchr(s, ';') != NULL) {
2219 free(expanded);
2220 free(copy2);
2221 goto try_target;
2222 }
2223
2224 if (gettok(&p))
2225 error("invalid macro assignment");
2226
2227 if (eq == ':') {
2228 // GNU-style ':='. Expand right-hand side of assignment.
2229 // Macro is of type immediate-expansion.
2230 q = newq = expand_macros(q, FALSE);
2231 level |= M_IMMEDIATE;
2232 }
2233 else if (eq == 'B') {
2234 // BSD-style ':='. Expand right-hand side of assignment,
2235 // though not '$$'. Macro is of type delayed-expansion.
2236 q = newq = expand_macros(q, TRUE);
2237 } else if (eq == '?' && getmp(a) != NULL) {
2238 // Skip assignment if macro is already set
2239 goto end_loop;
2240 } else if (eq == '+') {
2241 // Append to current value
2242 struct macro *mp = getmp(a);
2243 char *rhs;
2244 newq = mp && mp->m_val[0] ? xstrdup(mp->m_val) : NULL;
2245 if (mp && mp->m_immediate) {
2246 // Expand right-hand side of assignment (GNU make
2247 // compatibility)
2248 rhs = expand_macros(q, FALSE);
2249 level |= M_IMMEDIATE;
2250 } else {
2251 rhs = q;
2252 }
2253 newq = xappendword(newq, rhs);
2254 if (rhs != q)
2255 free(rhs);
2256 q = newq;
2257 } else if (eq == '!') {
2258 char *cmd = expand_macros(q, FALSE);
2259 q = newq = run_command(cmd);
2260 free(cmd);
2261 }
2262 setmacro(a, q, level);
2263 free(newq);
2264 free(copy2);
2265 goto end_loop;
2266 }
2267
2268 // If we get here it must be a target rule
2269 try_target:
2270 if (*str == '\t') // Command without target
2271 error("command not allowed here");
2272 p = expanded = expand_macros(str, FALSE);
2273
2274 // Look for colon separator
2275 q = find_colon(p);
2276 if (q == NULL)
2277 error("expected separator");
2278
2279 *q++ = '\0'; // Separate targets and prerequisites
2280
2281 // Double colon
2282 dbl = !posix && *q == ':';
2283 if (dbl)
2284 q++;
2285
2286 // Look for semicolon separator
2287 cp = NULL;
2288 s = strchr(q, ';');
2289 if (s) {
2290 // Retrieve command from expanded copy of line
2291 char *copy3 = expand_macros(copy, FALSE);
2292 if ((p = find_colon(copy3)) && (p = strchr(p, ';')))
2293 newcmd(&cp, process_command(p + 1));
2294 free(copy3);
2295 *s = '\0';
2296 }
2297 semicolon_cmd = cp != NULL && cp->c_cmd[0] != '\0';
2298
2299 // Create list of prerequisites
2300 dp = NULL;
2301 while (((p = gettok(&q)) != NULL)) {
2302 char *newp = NULL;
2303
2304 if (!posix) {
2305 // Allow prerequisites of form library(member1 member2).
2306 // Leading and trailing spaces in the brackets are skipped.
2307 if (!lib) {
2308 s = strchr(p, '(');
2309 if (s && !ends_with_bracket(s) && strchr(q, ')')) {
2310 // Looks like an unterminated archive member
2311 // with a terminator later on the line.
2312 lib = p;
2313 if (s[1] != '\0') {
2314 p = newp = auto_concat(lib, ")");
2315 s[1] = '\0';
2316 } else {
2317 continue;
2318 }
2319 }
2320 } else if (ends_with_bracket(p)) {
2321 if (*p != ')')
2322 p = newp = auto_concat(lib, p);
2323 lib = NULL;
2324 if (newp == NULL)
2325 continue;
2326 } else {
2327 p = newp = auto_string(xasprintf("%s%s)", lib, p));
2328 }
2329 }
2330
2331 // If not in POSIX mode expand wildcards in the name.
2332 nfile = 1;
2333 files = &p;
2334 if (!posix && wildcard(p, &gd)) {
2335 nfile = gd.gl_pathc;
2336 files = gd.gl_pathv;
2337 }
2338 for (i = 0; i < nfile; ++i) {
2339 if (!POSIX_2017 && strcmp(files[i], ".WAIT") == 0)
2340 continue;
2341 np = newname(files[i]);
2342 newdep(&dp, np);
2343 }
2344 if (files != &p)
2345 globfree(&gd);
2346 free(newp);
2347 }
2348 lib = NULL;
2349
2350 // Create list of commands
2351 startno = dispno;
2352 while ((str2 = readline(fd, TRUE)) && *str2 == '\t') {
2353 newcmd(&cp, process_command(str2));
2354 free(str2);
2355 }
2356 dispno = startno;
2357
2358 // Create target names and attach rule to them
2359 q = expanded;
2360 count = 0;
2361 seen_inference = FALSE;
2362 while ((p = gettok(&q)) != NULL) {
2363 // If not in POSIX mode expand wildcards in the name.
2364 nfile = 1;
2365 files = &p;
2366 if (!posix && wildcard(p, &gd)) {
2367 nfile = gd.gl_pathc;
2368 files = gd.gl_pathv;
2369 }
2370 for (i = 0; i < nfile; ++i) {
2371 int ttype = target_type(files[i]);
2372
2373 np = newname(files[i]);
2374 if (ttype != T_NORMAL) {
2375 // Enforce prerequisites/commands in POSIX mode
2376 if (posix) {
2377 if ((ttype & T_NOPREREQ) && dp)
2378 error_not_allowed("prerequisites", p);
2379 if ((ttype & T_INFERENCE)) {
2380 if (semicolon_cmd)
2381 error_in_inference_rule("'; command'");
2382 seen_inference = TRUE;
2383 }
2384 if ((ttype & T_COMMAND) && !cp &&
2385 !((ttype & T_INFERENCE) && !semicolon_cmd))
2386 error("commands required for %s", p);
2387 if (!(ttype & T_COMMAND) && cp)
2388 error_not_allowed("commands", p);
2389 }
2390
2391 if ((ttype & T_INFERENCE)) {
2392 np->n_flag |= N_INFERENCE;
2393 } else if (strcmp(p, ".DEFAULT") == 0) {
2394 // .DEFAULT rule is a special case
2395 np->n_flag |= N_SPECIAL | N_INFERENCE;
2396 } else {
2397 np->n_flag |= N_SPECIAL;
2398 }
2399 } else if (!firstname) {
2400 firstname = np;
2401 }
2402 addrule(np, dp, cp, dbl);
2403 count++;
2404 }
2405 if (files != &p)
2406 globfree(&gd);
2407 }
2408 if (posix && seen_inference && count != 1)
2409 error_in_inference_rule("multiple targets");
2410
2411 // Prerequisites and commands will be unused if there were
2412 // no targets. Avoid leaking memory.
2413 if (count == 0) {
2414 freedeps(dp);
2415 freecmds(cp);
2416 }
2417
2418 end_loop:
2419 free(str1);
2420 dispno = lineno;
2421 str1 = str2 ? str2 : readline(fd, FALSE);
2422 free(copy);
2423 free(expanded);
2424#if ENABLE_FEATURE_MAKE_POSIX
2425 if (!seen_first && fd) {
2426 if (findname(".POSIX")) {
2427 // The first non-comment line from a real makefile
2428 // defined the .POSIX special target.
2429 setenv("PDPMAKE_POSIXLY_CORRECT", "", 1);
2430 posix = TRUE;
2431 }
2432 seen_first = TRUE;
2433 }
2434#endif
2435 }
2436 // Conditionals aren't allowed to span files
2437 if (clevel != old_clevel)
2438 error("invalid conditional");
2439}
2440
2441static void
2442remove_target(void)
2443{
2444 if (!dryrun && !print && !precious &&
2445 target && !(target->n_flag & (N_PRECIOUS | N_PHONY)) &&
2446 unlink(target->n_name) == 0) {
2447 diagnostic("'%s' removed", target->n_name);
2448 }
2449}
2450
2451/*
2452 * Update the modification time of a file to now.
2453 */
2454static void
2455touch(struct name *np)
2456{
2457 if (dryrun || !silent)
2458 printf("touch %s\n", np->n_name);
2459
2460 if (!dryrun) {
2461 const struct timespec timebuf[2] = {{0, UTIME_NOW}, {0, UTIME_NOW}};
2462
2463 if (utimensat(AT_FDCWD, np->n_name, timebuf, 0) < 0) {
2464 if (errno == ENOENT) {
2465 int fd = open(np->n_name, O_RDWR | O_CREAT, 0666);
2466 if (fd >= 0) {
2467 close(fd);
2468 return;
2469 }
2470 }
2471 warning("touch %s failed", np->n_name);
2472 }
2473 }
2474}
2475
2476/*
2477 * Do commands to make a target
2478 */
2479static int
2480docmds(struct name *np, struct cmd *cp)
2481{
2482 int estat = 0;
2483 char *q, *command;
2484
2485 for (; cp; cp = cp->c_next) {
2486 uint32_t ssilent, signore, sdomake;
2487
2488 // Location of command in makefile (for use in error messages)
2489 makefile = cp->c_makefile;
2490 dispno = cp->c_dispno;
2491 opts &= ~OPT_make; // We want to know if $(MAKE) is expanded
2492 q = command = expand_macros(cp->c_cmd, FALSE);
2493 ssilent = silent || (np->n_flag & N_SILENT) || dotouch;
2494 signore = ignore || (np->n_flag & N_IGNORE);
2495 sdomake = (!dryrun || doinclude || domake) && !dotouch;
2496 for (;;) {
2497 if (*q == '@') // Specific silent
2498 ssilent = TRUE + 1;
2499 else if (*q == '-') // Specific ignore
2500 signore = TRUE;
2501 else if (*q == '+') // Specific domake
2502 sdomake = TRUE + 1;
2503 else
2504 break;
2505 do {
2506 q++;
2507 } while (isblank(*q));
2508 }
2509
2510 if (sdomake > TRUE) {
2511 // '+' must not override '@' or .SILENT
2512 if (ssilent != TRUE + 1 && !(np->n_flag & N_SILENT))
2513 ssilent = FALSE;
2514 } else if (!sdomake)
2515 ssilent = dotouch;
2516
2517 if (!ssilent && *q != '\0') { // Ignore empty commands
2518 puts(q);
2519 fflush_all();
2520 }
2521
2522 if (quest && sdomake != TRUE + 1) {
2523 // MAKE_FAILURE means rebuild is needed
2524 estat |= MAKE_FAILURE | MAKE_DIDSOMETHING;
2525 continue;
2526 }
2527
2528 if (sdomake && *q != '\0') { // Ignore empty commands
2529 // Get the shell to execute it
2530 int status;
2531 char *cmd = !signore && posix ? auto_concat("set -e;", q) : q;
2532
2533 target = np;
2534 status = system(cmd);
2535 // If this command was being run to create an include file
2536 // or bring it up-to-date errors should be ignored and a
2537 // failure status returned.
2538 if (status == -1 && !doinclude) {
2539 error("couldn't execute '%s'", q);
2540 } else if (status != 0 && !signore) {
2541 if (!posix && WIFSIGNALED(status))
2542 remove_target();
2543 if (doinclude) {
2544 warning("failed to build '%s'", np->n_name);
2545 } else {
2546 const char *err_type = NULL;
2547 int err_value = 1;
2548
2549 if (WIFEXITED(status)) {
2550 err_type = "exit";
2551 err_value = WEXITSTATUS(status);
2552 } else if (WIFSIGNALED(status)) {
2553 err_type = "signal";
2554 err_value = WTERMSIG(status);
2555 }
2556
2557 if (!quest || err_value == 127) {
2558 if (err_type)
2559 diagnostic("failed to build '%s' %s %d",
2560 np->n_name, err_type, err_value);
2561 else
2562 diagnostic("failed to build '%s'", np->n_name);
2563 }
2564
2565 if (errcont) {
2566 estat |= MAKE_FAILURE;
2567 free(command);
2568 break;
2569 }
2570 exit(2);
2571 }
2572 }
2573 }
2574 if (sdomake || dryrun)
2575 estat = MAKE_DIDSOMETHING;
2576 free(command);
2577 }
2578
2579 if (dotouch && !(np->n_flag & N_PHONY) && !(estat & MAKE_DIDSOMETHING)) {
2580 touch(np);
2581 estat = MAKE_DIDSOMETHING;
2582 }
2583
2584 makefile = NULL;
2585 return estat;
2586}
2587
2588static int
2589make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc,
2590 char *dedup, struct name *implicit)
2591{
2592 char *name, *member = NULL, *base = NULL, *prereq = NULL;
2593
2594 name = splitlib(np->n_name, &member);
2595 setmacro("?", oodate, 0 | M_VALID);
2596 if (!POSIX_2017) {
2597 setmacro("+", allsrc, 0 | M_VALID);
2598 setmacro("^", dedup, 0 | M_VALID);
2599 }
2600 setmacro("%", member, 0 | M_VALID);
2601 setmacro("@", name, 0 | M_VALID);
2602 if (implicit || !posix) {
2603 char *s;
2604
2605 // As an extension, if we're not dealing with an implicit
2606 // rule set $< to the first out-of-date prerequisite.
2607 if (implicit == NULL) {
2608 if (oodate) {
2609 s = strchr(oodate, ' ');
2610 if (s)
2611 *s = '\0';
2612 prereq = oodate;
2613 }
2614 } else
2615 prereq = implicit->n_name;
2616
2617 base = member ? member : name;
2618 s = suffix(base);
2619 // As an extension, if we're not dealing with an implicit
2620 // rule and the target ends with a known suffix, remove it
2621 // and set $* to the stem, else to an empty string.
2622 if (implicit == NULL && !is_suffix(s))
2623 base = NULL;
2624 else
2625 *s = '\0';
2626 }
2627 setmacro("<", prereq, 0 | M_VALID);
2628 setmacro("*", base, 0 | M_VALID);
2629 free(name);
2630
2631 return docmds(np, cp);
2632}
2633
2634/*
2635 * Determine if the modification time of a target, t, is less than
2636 * that of a prerequisite, p. If the tv_nsec member of either is
2637 * exactly 0 we assume (possibly incorrectly) that the time resolution
2638 * is 1 second and only compare tv_sec values.
2639 */
2640static int
2641timespec_le(const struct timespec *t, const struct timespec *p)
2642{
2643 if (t->tv_nsec == 0 || p->tv_nsec == 0)
2644 return t->tv_sec <= p->tv_sec;
2645 else if (t->tv_sec < p->tv_sec)
2646 return TRUE;
2647 else if (t->tv_sec == p->tv_sec)
2648 return t->tv_nsec <= p->tv_nsec;
2649 return FALSE;
2650}
2651
2652/*
2653 * Return the greater of two struct timespecs
2654 */
2655static const struct timespec *
2656timespec_max(const struct timespec *t, const struct timespec *p)
2657{
2658 return timespec_le(t, p) ? p : t;
2659}
2660
2661/*
2662 * Recursive routine to make a target.
2663 */
2664static int
2665make(struct name *np, int level)
2666{
2667 struct depend *dp;
2668 struct rule *rp;
2669 struct name *impdep = NULL; // implicit prerequisite
2670 struct rule imprule;
2671 struct cmd *sc_cmd = NULL; // commands for single-colon rule
2672 char *oodate = NULL;
2673 char *allsrc = NULL;
2674 char *dedup = NULL;
2675 struct timespec dtim = {1, 0};
2676 int estat = 0;
2677
2678 if (np->n_flag & N_DONE)
2679 return 0;
2680 if (np->n_flag & N_DOING)
2681 error("circular dependency for %s", np->n_name);
2682 np->n_flag |= N_DOING;
2683
2684 if (!np->n_tim.tv_sec)
2685 modtime(np); // Get modtime of this file
2686
2687 if (!(np->n_flag & N_DOUBLE)) {
2688 // Find the commands needed for a single-colon rule, using
2689 // an inference rule or .DEFAULT rule if necessary (but,
2690 // as an extension, not for phony targets)
2691 sc_cmd = getcmd(np);
2692 if (!sc_cmd && (posix || !(np->n_flag & N_PHONY))) {
2693 impdep = dyndep(np, &imprule);
2694 if (impdep) {
2695 sc_cmd = imprule.r_cmd;
2696 addrule(np, imprule.r_dep, NULL, FALSE);
2697 }
2698 }
2699
2700 // As a last resort check for a default rule
2701 if (!(np->n_flag & N_TARGET) && np->n_tim.tv_sec == 0) {
2702 if (posix || !(np->n_flag & N_PHONY))
2703 sc_cmd = getcmd(findname(".DEFAULT"));
2704 if (!sc_cmd) {
2705 if (doinclude)
2706 return 1;
2707 error("don't know how to make %s", np->n_name);
2708 }
2709 impdep = np;
2710 }
2711 }
2712 else {
2713 // If any double-colon rule has no commands we need
2714 // an inference rule (but, as an extension, not for phony targets)
2715 for (rp = np->n_rule; rp; rp = rp->r_next) {
2716 if (!rp->r_cmd) {
2717 if (posix || !(np->n_flag & N_PHONY))
2718 impdep = dyndep(np, &imprule);
2719 if (!impdep) {
2720 if (doinclude)
2721 return 1;
2722 error("don't know how to make %s", np->n_name);
2723 }
2724 break;
2725 }
2726 }
2727 }
2728
2729 // Reset flag to detect duplicate prerequisites
2730 if (!(np->n_flag & N_DOUBLE)) {
2731 for (rp = np->n_rule; rp; rp = rp->r_next) {
2732 for (dp = rp->r_dep; dp; dp = dp->d_next) {
2733 dp->d_name->n_flag &= ~N_MARK;
2734 }
2735 }
2736 }
2737
2738 for (rp = np->n_rule; rp; rp = rp->r_next) {
2739 struct name *locdep = NULL;
2740
2741 // Each double-colon rule is handled separately.
2742 if ((np->n_flag & N_DOUBLE)) {
2743 // If the rule has no commands use the inference rule.
2744 if (!rp->r_cmd) {
2745 locdep = impdep;
2746 imprule.r_dep->d_next = rp->r_dep;
2747 rp->r_dep = imprule.r_dep;
2748 rp->r_cmd = imprule.r_cmd;
2749 }
2750 // A rule with no prerequisities is executed unconditionally.
2751 if (!rp->r_dep)
2752 dtim = np->n_tim;
2753 // Reset flag to detect duplicate prerequisites
2754 for (dp = rp->r_dep; dp; dp = dp->d_next) {
2755 dp->d_name->n_flag &= ~N_MARK;
2756 }
2757 }
2758 for (dp = rp->r_dep; dp; dp = dp->d_next) {
2759 // Make prerequisite
2760 estat |= make(dp->d_name, level + 1);
2761
2762 // Make strings of out-of-date prerequisites (for $?),
2763 // all prerequisites (for $+) and deduplicated prerequisites
2764 // (for $^).
2765 if (timespec_le(&np->n_tim, &dp->d_name->n_tim)) {
2766 if (posix || !(dp->d_name->n_flag & N_MARK))
2767 oodate = xappendword(oodate, dp->d_name->n_name);
2768 }
2769 allsrc = xappendword(allsrc, dp->d_name->n_name);
2770 if (!(dp->d_name->n_flag & N_MARK))
2771 dedup = xappendword(dedup, dp->d_name->n_name);
2772 dp->d_name->n_flag |= N_MARK;
2773 dtim = *timespec_max(&dtim, &dp->d_name->n_tim);
2774 }
2775 if ((np->n_flag & N_DOUBLE)) {
2776 if (((np->n_flag & N_PHONY) || timespec_le(&np->n_tim, &dtim))) {
2777 if (!(estat & MAKE_FAILURE)) {
2778 estat |= make1(np, rp->r_cmd, oodate, allsrc,
2779 dedup, locdep);
2780 dtim = (struct timespec){1, 0};
2781 }
2782 free(oodate);
2783 oodate = NULL;
2784 }
2785 free(allsrc);
2786 free(dedup);
2787 allsrc = dedup = NULL;
2788 if (locdep) {
2789 rp->r_dep = rp->r_dep->d_next;
2790 rp->r_cmd = NULL;
2791 }
2792 }
2793 }
2794 if ((np->n_flag & N_DOUBLE) && impdep)
2795 free(imprule.r_dep);
2796
2797 np->n_flag |= N_DONE;
2798 np->n_flag &= ~N_DOING;
2799
2800 if (!(np->n_flag & N_DOUBLE) &&
2801 ((np->n_flag & N_PHONY) || (timespec_le(&np->n_tim, &dtim)))) {
2802 if (!(estat & MAKE_FAILURE)) {
2803 if (sc_cmd)
2804 estat |= make1(np, sc_cmd, oodate, allsrc, dedup, impdep);
2805 else if (!doinclude && level == 0 && !(estat & MAKE_DIDSOMETHING))
2806 warning("nothing to be done for %s", np->n_name);
2807 } else if (!doinclude && !quest) {
2808 diagnostic("'%s' not built due to errors", np->n_name);
2809 }
2810 free(oodate);
2811 }
2812
2813 if (estat & MAKE_DIDSOMETHING) {
2814 modtime(np);
2815 if (!np->n_tim.tv_sec)
2816 clock_gettime(CLOCK_REALTIME, &np->n_tim);
2817 } else if (!quest && level == 0 && !timespec_le(&np->n_tim, &dtim))
2818 printf("%s: '%s' is up to date\n", applet_name, np->n_name);
2819
2820 free(allsrc);
2821 free(dedup);
2822 return estat;
2823}
2824
2825/*
2826 * Check structures for make.
2827 */
2828
2829static void
2830print_name(struct name *np)
2831{
2832 if (np == firstname)
2833 printf("# default target\n");
2834 printf("%s:", np->n_name);
2835 if ((np->n_flag & N_DOUBLE))
2836 putchar(':');
2837}
2838
2839static void
2840print_prerequisites(struct rule *rp)
2841{
2842 struct depend *dp;
2843
2844 for (dp = rp->r_dep; dp; dp = dp->d_next)
2845 printf(" %s", dp->d_name->n_name);
2846}
2847
2848static void
2849print_commands(struct rule *rp)
2850{
2851 struct cmd *cp;
2852
2853 for (cp = rp->r_cmd; cp; cp = cp->c_next)
2854 printf("\t%s\n", cp->c_cmd);
2855}
2856
2857static void
2858print_details(void)
2859{
2860 int i;
2861 struct macro *mp;
2862 struct name *np;
2863 struct rule *rp;
2864
2865 for (i = 0; i < HTABSIZE; i++)
2866 for (mp = macrohead[i]; mp; mp = mp->m_next)
2867 printf("%s = %s\n", mp->m_name, mp->m_val);
2868 putchar('\n');
2869
2870 for (i = 0; i < HTABSIZE; i++) {
2871 for (np = namehead[i]; np; np = np->n_next) {
2872 if (!(np->n_flag & N_DOUBLE)) {
2873 print_name(np);
2874 for (rp = np->n_rule; rp; rp = rp->r_next) {
2875 print_prerequisites(rp);
2876 }
2877 putchar('\n');
2878
2879 for (rp = np->n_rule; rp; rp = rp->r_next) {
2880 print_commands(rp);
2881 }
2882 putchar('\n');
2883 } else {
2884 for (rp = np->n_rule; rp; rp = rp->r_next) {
2885 print_name(np);
2886 print_prerequisites(rp);
2887 putchar('\n');
2888
2889 print_commands(rp);
2890 putchar('\n');
2891 }
2892 }
2893 }
2894 }
2895}
2896
2897/*
2898 * Process options from an argv array. If from_env is non-zero we're
2899 * handling options from MAKEFLAGS so skip '-C', '-f', '-p' and '-x'.
2900 */
2901static uint32_t
2902process_options(char **argv, int from_env)
2903{
2904 uint32_t flags;
2905
2906 flags = getopt32(argv, "^" OPTSTR1 OPTSTR2 "\0k-S:S-k",
2907 &numjobs, &makefiles, &dirs
2908 IF_FEATURE_MAKE_POSIX(, &pragmas));
2909 if (from_env && (flags & (OPT_C | OPT_f | OPT_p | OPT_x)))
2910 error("invalid MAKEFLAGS");
2911 if (posix && (flags & OPT_C))
2912 error("-C not allowed");
2913
2914 return flags;
2915}
2916
2917/*
2918 * Split the contents of MAKEFLAGS into an argv array. If the return
2919 * value (call it fargv) isn't NULL the caller should free fargv[1] and
2920 * fargv.
2921 */
2922static char **
2923expand_makeflags(void)
2924{
2925 const char *m, *makeflags = getenv("MAKEFLAGS");
2926 char *p, *argstr;
2927 int argc;
2928 char **argv;
2929
2930 if (makeflags == NULL)
2931 return NULL;
2932
2933 while (isblank(*makeflags))
2934 makeflags++;
2935
2936 if (*makeflags == '\0')
2937 return NULL;
2938
2939 p = argstr = xzalloc(strlen(makeflags) + 2);
2940
2941 // If MAKEFLAGS doesn't start with a hyphen, doesn't look like
2942 // a macro definition and only contains valid option characters,
2943 // add a hyphen.
2944 argc = 3;
2945 if (makeflags[0] != '-' && strchr(makeflags, '=') == NULL) {
2946 if (strspn(makeflags, OPTSTR1) != strlen(makeflags))
2947 error("invalid MAKEFLAGS");
2948 *p++ = '-';
2949 } else {
2950 // MAKEFLAGS may need to be split, estimate size of argv array.
2951 for (m = makeflags; *m; ++m) {
2952 if (isblank(*m))
2953 argc++;
2954 }
2955 }
2956
2957 argv = xzalloc(argc * sizeof(char *));
2958 argc = 0;
2959 argv[argc++] = (char *)applet_name;
2960 argv[argc++] = argstr;
2961
2962 // Copy MAKEFLAGS into argstr, splitting at non-escaped blanks.
2963 m = makeflags;
2964 do {
2965 if (*m == '\\' && m[1] != '\0')
2966 m++; // Skip backslash, copy next character unconditionally.
2967 else if (isblank(*m)) {
2968 // Terminate current argument and start a new one.
2969 /* *p = '\0'; - xzalloc did it */
2970 argv[argc++] = ++p;
2971 do {
2972 m++;
2973 } while (isblank(*m));
2974 continue;
2975 }
2976 *p++ = *m++;
2977 } while (*m != '\0');
2978 /* *p = '\0'; - xzalloc did it */
2979 /* argv[argc] = NULL; - and this */
2980
2981 return argv;
2982}
2983
2984// These macros require special treatment
2985#define SPECIAL_MACROS "MAKEFLAGS\0SHELL\0CURDIR\0"
2986#define MAKEFLAGS 0
2987#define SHELL 1
2988#define CURDIR 2
2989
2990/*
2991 * Instantiate all macros in an argv-style array of pointers. Stop
2992 * processing at the first string that doesn't contain an equal sign.
2993 * As an extension, target arguments on the command line (level 1)
2994 * are skipped and will be processed later.
2995 */
2996static char **
2997process_macros(char **argv, int level)
2998{
2999 char *equal;
3000
3001 for (; *argv; argv++) {
3002 char *colon = NULL;
3003 int idx, immediate = 0;
3004 int except_dollar = FALSE;
3005
3006 if (!(equal = strchr(*argv, '='))) {
3007 // Skip targets on the command line
3008 if (!posix && level == 1)
3009 continue;
3010 else
3011 // Stop at first target
3012 break;
3013 }
3014
3015 if (equal - 1 > *argv && equal[-1] == ':') {
3016 if (equal - 2 > *argv && equal[-2] == ':') {
3017 if (POSIX_2017)
3018 error("invalid macro assignment");
3019 if (equal - 3 > *argv && equal[-3] == ':') {
3020 // BSD-style ':='. Expand RHS, but not '$$',
3021 // resulting macro is delayed expansion.
3022 colon = equal - 3;
3023 except_dollar = TRUE;
3024 } else {
3025 // GNU-style ':='. Expand RHS, including '$$',
3026 // resulting macro is immediate expansion.
3027 colon = equal - 2;
3028 immediate = M_IMMEDIATE;
3029 }
3030 *colon = '\0';
3031 } else {
3032 if (posix)
3033 error("invalid macro assignment");
3034 colon = equal - 1;
3035 immediate = M_IMMEDIATE;
3036 *colon = '\0';
3037 }
3038 } else
3039 *equal = '\0';
3040
3041 /* We want to process _most_ macro assignments.
3042 * There are exceptions for particular values from the
3043 * environment. */
3044 idx = index_in_strings(SPECIAL_MACROS, *argv);
3045 if (!((level & M_ENVIRON) &&
3046 (idx == MAKEFLAGS || idx == SHELL ||
3047 (idx == CURDIR && !useenv && !POSIX_2017)))) {
3048 if (colon) {
3049 char *exp = expand_macros(equal + 1, except_dollar);
3050 setmacro(*argv, exp, level | immediate);
3051 free(exp);
3052 } else
3053 setmacro(*argv, equal + 1, level);
3054 }
3055
3056 if (colon)
3057 *colon = ':';
3058 else
3059 *equal = '=';
3060 }
3061 return argv;
3062}
3063
3064/*
3065 * Update the MAKEFLAGS macro and environment variable to include any
3066 * command line options that don't have their default value (apart from
3067 * -f, -p and -S). Also add any macros defined on the command line or
3068 * by the MAKEFLAGS environment variable (apart from MAKEFLAGS itself).
3069 * Add macros that were defined on the command line to the environment.
3070 */
3071static void
3072update_makeflags(void)
3073{
3074 int i;
3075 char optbuf[] = "-?";
3076 char *makeflags = NULL;
3077 char *macro, *s;
3078 const char *t;
3079 struct macro *mp;
3080
3081 t = OPTSTR1;
3082 for (i = 0; *t; t++) {
3083 if (*t == ':' || *t == '+')
3084 continue;
3085 if ((opts & OPT_MASK & (1 << i))) {
3086 optbuf[1] = *t;
3087 makeflags = xappendword(makeflags, optbuf);
3088 if (*t == 'j') {
3089 s = auto_string(xasprintf("%d", numjobs));
3090 makeflags = xappendword(makeflags, s);
3091 }
3092 }
3093 i++;
3094 }
3095
3096 for (i = 0; i < HTABSIZE; ++i) {
3097 for (mp = macrohead[i]; mp; mp = mp->m_next) {
3098 if (mp->m_level == 1 || mp->m_level == 2) {
3099 int idx = index_in_strings(SPECIAL_MACROS, mp->m_name);
3100 if (idx == MAKEFLAGS)
3101 continue;
3102 macro = xzalloc(strlen(mp->m_name) + 2 * strlen(mp->m_val) + 1);
3103 s = stpcpy(macro, mp->m_name);
3104 *s++ = '=';
3105 for (t = mp->m_val; *t; t++) {
3106 if (*t == '\\' || isblank(*t))
3107 *s++ = '\\';
3108 *s++ = *t;
3109 }
3110 /* *s = '\0'; - xzalloc did it */
3111
3112 makeflags = xappendword(makeflags, macro);
3113 free(macro);
3114
3115 // Add command line macro definitions to the environment
3116 if (mp->m_level == 1 && idx != SHELL)
3117 setenv(mp->m_name, mp->m_val, 1);
3118 }
3119 }
3120 }
3121
3122 if (makeflags) {
3123 setmacro("MAKEFLAGS", makeflags, 0);
3124 setenv("MAKEFLAGS", makeflags, 1);
3125 free(makeflags);
3126 }
3127}
3128
3129#if !ENABLE_PLATFORM_MINGW32
3130static void
3131make_handler(int sig)
3132{
3133 signal(sig, SIG_DFL);
3134 remove_target();
3135 kill(getpid(), sig);
3136}
3137
3138static void
3139init_signal(int sig)
3140{
3141 struct sigaction sa, new_action;
3142
3143 sigemptyset(&new_action.sa_mask);
3144 new_action.sa_flags = 0;
3145 new_action.sa_handler = make_handler;
3146
3147 sigaction(sig, NULL, &sa);
3148 if (sa.sa_handler != SIG_IGN)
3149 sigaction_set(sig, &new_action);
3150}
3151#endif
3152
3153/*
3154 * If the global option flag associated with a special target hasn't
3155 * been set mark all prerequisites of the target with a flag. If the
3156 * target had no prerequisites set the global option flag.
3157 */
3158static void
3159mark_special(const char *special, uint32_t oflag, uint16_t nflag)
3160{
3161 struct name *np;
3162 struct rule *rp;
3163 struct depend *dp;
3164 int marked = FALSE;
3165
3166 if (!(opts & oflag) && (np = findname(special))) {
3167 for (rp = np->n_rule; rp; rp = rp->r_next) {
3168 for (dp = rp->r_dep; dp; dp = dp->d_next) {
3169 dp->d_name->n_flag |= nflag;
3170 marked = TRUE;
3171 }
3172 }
3173
3174 if (!marked)
3175 opts |= oflag;
3176 }
3177}
3178
3179int make_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
3180int make_main(int argc UNUSED_PARAM, char **argv)
3181{
3182 const char *path, *newpath = NULL;
3183 char **fargv, **fargv0;
3184 const char *dir, *file;
3185#if ENABLE_FEATURE_MAKE_POSIX
3186 const char *prag;
3187#endif
3188 int estat;
3189 bool found_target;
3190 FILE *ifd;
3191
3192 INIT_G();
3193
3194#if ENABLE_FEATURE_MAKE_POSIX
3195 if (argv[1] && strcmp(argv[1], "--posix") == 0) {
3196 argv[1] = argv[0];
3197 ++argv;
3198 --argc;
3199 setenv("PDPMAKE_POSIXLY_CORRECT", "", 1);
3200 posix = TRUE;
3201 } else {
3202 posix = getenv("PDPMAKE_POSIXLY_CORRECT") != NULL;
3203 }
3204 posix_level = DEFAULT_POSIX_LEVEL;
3205 pragmas_from_env();
3206#endif
3207
3208 if (!POSIX_2017) {
3209 path = argv[0];
3210#if ENABLE_PLATFORM_MINGW32
3211 if (has_path(argv[0])) {
3212 // Add extension if necessary, else realpath() will fail
3213 char *p = alloc_ext_space(argv[0]);
3214 add_win32_extension(p);
3215 path = newpath = xmalloc_realpath(p);
3216 free(p);
3217 if (!path) {
3218 if (unix_path(argv[0]))
3219 path = argv[0];
3220 else
3221 bb_perror_msg("can't resolve path for %s", argv[0]);
3222 }
3223 }
3224#else
3225 if (argv[0][0] != '/' && strchr(argv[0], '/')) {
3226 // Make relative path absolute
3227 path = newpath = realpath(argv[0], NULL);
3228 if (!path) {
3229 bb_perror_msg("can't resolve path for %s", argv[0]);
3230 }
3231 }
3232#endif
3233 } else {
3234 path = "make";
3235 }
3236
3237 // Process options from MAKEFLAGS
3238 fargv = fargv0 = expand_makeflags();
3239 if (fargv0) {
3240 opts = process_options(fargv, TRUE);
3241 fargv = fargv0 + optind;
3242 // Reset getopt(3) so we can call it again
3243 GETOPT_RESET();
3244 }
3245
3246 // Process options from the command line
3247 opts |= process_options(argv, FALSE);
3248 argv += optind;
3249
3250 while ((dir = llist_pop(&dirs))) {
3251 if (chdir(dir) == -1) {
3252 bb_perror_msg("can't chdir to %s", dir);
3253 }
3254 }
3255
3256#if ENABLE_FEATURE_MAKE_POSIX
3257 while ((prag = llist_pop(&pragmas)))
3258 set_pragma(prag);
3259 pragmas_to_env();
3260#endif
3261
3262#if !ENABLE_PLATFORM_MINGW32
3263 init_signal(SIGHUP);
3264 init_signal(SIGTERM);
3265#endif
3266
3267 setmacro("$", "$", 0 | M_VALID);
3268
3269 // Process macro definitions from the command line
3270 if (!posix)
3271 process_macros(argv, 1);
3272 else
3273 // In POSIX mode macros must appear before targets.
3274 // argv should now point to targets only.
3275 argv = process_macros(argv, 1);
3276
3277 // Process macro definitions from MAKEFLAGS
3278 if (fargv) {
3279 process_macros(fargv, 2);
3280 free(fargv0[1]);
3281 free(fargv0);
3282 }
3283
3284 // Process macro definitions from the environment
3285 process_macros(environ, 3 | M_ENVIRON);
3286
3287 // Update MAKEFLAGS and environment
3288 update_makeflags();
3289
3290 // Read built-in rules
3291 input(NULL, 0);
3292
3293 setmacro("SHELL", DEFAULT_SHELL, 4);
3294 setmacro("MAKE", path, 4);
3295 if (!POSIX_2017) {
3296 char *cwd = xrealloc_getcwd_or_warn(NULL);
3297
3298 if (cwd) {
3299 if (!useenv) {
3300 // Export cwd to environment, if necessary
3301 char *envcwd = getenv("CURDIR");
3302 if (envcwd && strcmp(cwd, envcwd) != 0)
3303 setenv("CURDIR", cwd, 1);
3304 }
3305 setmacro("CURDIR", cwd, 4);
3306 }
3307 free(cwd);
3308 }
3309 free((void *)newpath);
3310
3311 if (!makefiles) { // Look for a default Makefile
3312 if (!posix && (ifd = fopen("PDPmakefile", "r")) != NULL)
3313 makefile = "PDPmakefile";
3314 else if ((ifd = fopen("PDPmakefile" + 3, "r")) != NULL)
3315 makefile = "PDPmakefile" + 3;
3316#if !ENABLE_PLATFORM_MINGW32
3317 else if ((ifd = fopen("Makefile", "r")) != NULL)
3318 makefile = "Makefile";
3319#endif
3320 else
3321 error("no makefile found");
3322 goto read_makefile;
3323 }
3324
3325 while ((file = llist_pop(&makefiles))) {
3326 if (strcmp(file, "-") == 0) { // Can use stdin as makefile
3327 ifd = stdin;
3328 makefile = "stdin";
3329 } else {
3330 ifd = xfopen_for_read(file);
3331 makefile = file;
3332 }
3333 read_makefile:
3334 input(ifd, 0);
3335 fclose(ifd);
3336 makefile = NULL;
3337 }
3338
3339 if (print)
3340 print_details();
3341
3342 mark_special(".SILENT", OPT_s, N_SILENT);
3343 mark_special(".IGNORE", OPT_i, N_IGNORE);
3344 mark_special(".PRECIOUS", OPT_precious, N_PRECIOUS);
3345 if (!POSIX_2017)
3346 mark_special(".PHONY", OPT_phony, N_PHONY);
3347
3348 if (posix) {
3349 // In POSIX mode only targets should now be in argv.
3350 found_target = FALSE;
3351 for (char **a = argv; *a; a++) {
3352 if (!strchr(*a, '='))
3353 found_target = TRUE;
3354 else if (found_target)
3355 error("macro assignments must precede targets");
3356 }
3357 }
3358
3359 estat = 0;
3360 found_target = FALSE;
3361 for (; *argv; argv++) {
3362 // Skip macro assignments.
3363 if (strchr(*argv, '='))
3364 continue;
3365 found_target = TRUE;
3366 estat |= make(newname(*argv), 0);
3367 }
3368 if (!found_target) {
3369 if (!firstname)
3370 error("no targets defined");
3371 estat = make(firstname, 0);
3372 }
3373
3374#if ENABLE_FEATURE_CLEAN_UP
3375 freenames();
3376 freemacros();
3377 llist_free(makefiles, NULL);
3378 llist_free(dirs, NULL);
3379#endif
3380
3381 return estat & MAKE_FAILURE;
3382}
diff --git a/miscutils/man.c b/miscutils/man.c
index deaf9e5ab..3954455b4 100644
--- a/miscutils/man.c
+++ b/miscutils/man.c
@@ -199,8 +199,7 @@ static char **add_MANPATH(char **man_path_list, int *count_mp, char *path)
199 if (path) while (*path) { 199 if (path) while (*path) {
200 char *next_path; 200 char *next_path;
201 char **path_element; 201 char **path_element;
202 202 next_path = strchr(path, PATH_SEP);
203 next_path = strchr(path, ':');
204 if (next_path) { 203 if (next_path) {
205 if (next_path == path) /* "::"? */ 204 if (next_path == path) /* "::"? */
206 goto next; 205 goto next;
@@ -223,7 +222,7 @@ static char **add_MANPATH(char **man_path_list, int *count_mp, char *path)
223 if (!next_path) 222 if (!next_path)
224 break; 223 break;
225 /* "path" may be a result of getenv(), be nice and don't mangle it */ 224 /* "path" may be a result of getenv(), be nice and don't mangle it */
226 *next_path = ':'; 225 *next_path = PATH_SEP;
227 next: 226 next:
228 path = next_path + 1; 227 path = next_path + 1;
229 } 228 }
@@ -260,11 +259,24 @@ int man_main(int argc UNUSED_PARAM, char **argv)
260 int count_mp; 259 int count_mp;
261 int opt, not_found; 260 int opt, not_found;
262 char *token[2]; 261 char *token[2];
262#if ENABLE_PLATFORM_MINGW32
263 char **ptr;
264 char *relpath;
265 const char *mpl[] = { "/usr/man", "/usr/share/man", NULL, NULL };
266#endif
263 267
264 INIT_G(); 268 INIT_G();
265 269
266 opt = getopt32(argv, "^+" "aw" "\0" "-1"/*at least one arg*/); 270 opt = getopt32(argv, "^+" "aw" "\0" "-1"/*at least one arg*/);
267 argv += optind; 271 argv += optind;
272#if ENABLE_PLATFORM_MINGW32
273 /* add system drive prefix to filenames, if necessary */
274 for (ptr = argv; *ptr; ++ptr) {
275 if (strchr(*ptr, '/') || strchr(*ptr, '\\'))
276 *ptr = xabsolute_path(*ptr);
277 }
278 chdir_system_drive();
279#endif
268 280
269 conf_sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9"); 281 conf_sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9");
270 282
@@ -302,11 +314,24 @@ int man_main(int argc UNUSED_PARAM, char **argv)
302 } 314 }
303 config_close(parser); 315 config_close(parser);
304 316
317#if ENABLE_PLATFORM_MINGW32
318 /* allow man pages to be stored relative to the executable */
319 relpath = exe_relative_path("man");
320
321 if (!man_path_list) {
322 mpl[2] = relpath;
323 man_path_list = (char**)mpl;
324 }
325 else {
326 man_path_list = add_MANPATH(man_path_list, &count_mp, relpath);
327 }
328#else
305 if (!man_path_list) { 329 if (!man_path_list) {
306 static const char *const mpl[] ALIGN_PTR = { "/usr/man", "/usr/share/man", NULL }; 330 static const char *const mpl[] ALIGN_PTR = { "/usr/man", "/usr/share/man", NULL };
307 man_path_list = (char**)mpl; 331 man_path_list = (char**)mpl;
308 /*count_mp = 2; - not used below anyway */ 332 /*count_mp = 2; - not used below anyway */
309 } 333 }
334#endif
310 335
311 { 336 {
312 /* environment overrides setting from man.config */ 337 /* environment overrides setting from man.config */
diff --git a/miscutils/time.c b/miscutils/time.c
index 77d35a832..9a1039be9 100644
--- a/miscutils/time.c
+++ b/miscutils/time.c
@@ -22,10 +22,17 @@
22//kbuild:lib-$(CONFIG_TIME) += time.o 22//kbuild:lib-$(CONFIG_TIME) += time.o
23 23
24//usage:#define time_trivial_usage 24//usage:#define time_trivial_usage
25//usage: IF_NOT_PLATFORM_MINGW32(
25//usage: "[-vpa] [-o FILE] PROG ARGS" 26//usage: "[-vpa] [-o FILE] PROG ARGS"
27//usage: )
28//usage: IF_PLATFORM_MINGW32(
29//usage: "[-pa] [-f FMT] [-o FILE] PROG ARGS"
30//usage: )
26//usage:#define time_full_usage "\n\n" 31//usage:#define time_full_usage "\n\n"
27//usage: "Run PROG, display resource usage when it exits\n" 32//usage: "Run PROG, display resource usage when it exits\n"
33//usage: IF_NOT_PLATFORM_MINGW32(
28//usage: "\n -v Verbose" 34//usage: "\n -v Verbose"
35//usage: )
29//usage: "\n -p POSIX output format" 36//usage: "\n -p POSIX output format"
30//usage: "\n -f FMT Custom format" 37//usage: "\n -f FMT Custom format"
31//usage: "\n -o FILE Write result to FILE" 38//usage: "\n -o FILE Write result to FILE"
@@ -57,6 +64,7 @@ static const char default_format[] ALIGN1 = "real\t%E\nuser\t%u\nsys\t%T";
57/* The output format for the -p option .*/ 64/* The output format for the -p option .*/
58static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S"; 65static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S";
59 66
67#if !ENABLE_PLATFORM_MINGW32
60/* Format string for printing all statistics verbosely. 68/* Format string for printing all statistics verbosely.
61 Keep this output to 24 lines so users on terminals can see it all.*/ 69 Keep this output to 24 lines so users on terminals can see it all.*/
62static const char long_format[] ALIGN1 = 70static const char long_format[] ALIGN1 =
@@ -83,6 +91,7 @@ static const char long_format[] ALIGN1 =
83 "\tSignals delivered: %k\n" 91 "\tSignals delivered: %k\n"
84 "\tPage size (bytes): %Z\n" 92 "\tPage size (bytes): %Z\n"
85 "\tExit status: %x"; 93 "\tExit status: %x";
94#endif
86 95
87/* Wait for and fill in data on child process PID. 96/* Wait for and fill in data on child process PID.
88 Return 0 on error, 1 if ok. */ 97 Return 0 on error, 1 if ok. */
@@ -93,7 +102,11 @@ static void resuse_end(pid_t pid, resource_t *resp)
93 102
94 /* Ignore signals, but don't ignore the children. When wait3 103 /* Ignore signals, but don't ignore the children. When wait3
95 * returns the child process, set the time the command finished. */ 104 * returns the child process, set the time the command finished. */
105#if !ENABLE_PLATFORM_MINGW32
96 while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) { 106 while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) {
107#else
108 while ((caught=mingw_wait3(pid, &resp->waitstatus, 0, &resp->ru)) != pid) {
109#endif
97 if (caught == -1 && errno != EINTR) { 110 if (caught == -1 && errno != EINTR) {
98 bb_simple_perror_msg("wait"); 111 bb_simple_perror_msg("wait");
99 return; 112 return;
@@ -189,9 +202,11 @@ static unsigned long ptok(const unsigned pagesize, const unsigned long pages)
189 202
190static void summarize(const char *fmt, char **command, resource_t *resp) 203static void summarize(const char *fmt, char **command, resource_t *resp)
191{ 204{
205#if !ENABLE_PLATFORM_MINGW32
192 unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */ 206 unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */
193 unsigned cpu_ticks; /* Same, in "CPU ticks" */ 207 unsigned cpu_ticks; /* Same, in "CPU ticks" */
194 unsigned pagesize = bb_getpagesize(); 208 unsigned pagesize = bb_getpagesize();
209#endif
195 210
196 /* Impossible: we do not use WUNTRACED flag in wait()... 211 /* Impossible: we do not use WUNTRACED flag in wait()...
197 if (WIFSTOPPED(resp->waitstatus)) 212 if (WIFSTOPPED(resp->waitstatus))
@@ -205,6 +220,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
205 printf("Command exited with non-zero status %u\n", 220 printf("Command exited with non-zero status %u\n",
206 WEXITSTATUS(resp->waitstatus)); 221 WEXITSTATUS(resp->waitstatus));
207 222
223#if !ENABLE_PLATFORM_MINGW32
208 vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000 224 vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000
209 + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000; 225 + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000;
210 226
@@ -215,6 +231,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
215 cpu_ticks = vv_ms * (unsigned long long)TICKS_PER_SEC / 1000; 231 cpu_ticks = vv_ms * (unsigned long long)TICKS_PER_SEC / 1000;
216#endif 232#endif
217 if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */ 233 if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */
234#endif
218 235
219 while (*fmt) { 236 while (*fmt) {
220 /* Handle leading literal part */ 237 /* Handle leading literal part */
@@ -242,6 +259,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
242 case 'C': /* The command that got timed. */ 259 case 'C': /* The command that got timed. */
243 printargv(command); 260 printargv(command);
244 break; 261 break;
262#if !ENABLE_PLATFORM_MINGW32
245 case 'D': /* Average unshared data size. */ 263 case 'D': /* Average unshared data size. */
246 /* (linux kernel sets ru_idrss/isrss/ixrss to 0, 264 /* (linux kernel sets ru_idrss/isrss/ixrss to 0,
247 * docs say the value is in kbytes, so ptok() is wrong) */ 265 * docs say the value is in kbytes, so ptok() is wrong) */
@@ -251,6 +269,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
251 ) / cpu_ticks 269 ) / cpu_ticks
252 ); 270 );
253 break; 271 break;
272#endif
254 case 'E': { /* Elapsed real (wall clock) time. */ 273 case 'E': { /* Elapsed real (wall clock) time. */
255 unsigned seconds = resp->elapsed_ms / 1000; 274 unsigned seconds = resp->elapsed_ms / 1000;
256 if (seconds >= 3600) /* One hour -> h:m:s. */ 275 if (seconds >= 3600) /* One hour -> h:m:s. */
@@ -265,6 +284,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
265 (unsigned)(resp->elapsed_ms / 10) % 100); 284 (unsigned)(resp->elapsed_ms / 10) % 100);
266 break; 285 break;
267 } 286 }
287#if !ENABLE_PLATFORM_MINGW32
268 case 'F': /* Major page faults. */ 288 case 'F': /* Major page faults. */
269 printf("%lu", resp->ru.ru_majflt); 289 printf("%lu", resp->ru.ru_majflt);
270 break; 290 break;
@@ -297,6 +317,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
297 case 'R': /* Minor page faults (reclaims). */ 317 case 'R': /* Minor page faults (reclaims). */
298 printf("%lu", resp->ru.ru_minflt); 318 printf("%lu", resp->ru.ru_minflt);
299 break; 319 break;
320#endif
300 case 'S': /* System time. */ 321 case 'S': /* System time. */
301 printf("%u.%02u", 322 printf("%u.%02u",
302 (unsigned)resp->ru.ru_stime.tv_sec, 323 (unsigned)resp->ru.ru_stime.tv_sec,
@@ -331,6 +352,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
331 (unsigned)(resp->ru.ru_utime.tv_sec % 60), 352 (unsigned)(resp->ru.ru_utime.tv_sec % 60),
332 (unsigned)(resp->ru.ru_utime.tv_usec / 10000)); 353 (unsigned)(resp->ru.ru_utime.tv_usec / 10000));
333 break; 354 break;
355#if !ENABLE_PLATFORM_MINGW32
334 case 'W': /* Times swapped out. */ 356 case 'W': /* Times swapped out. */
335 printf("%lu", resp->ru.ru_nswap); 357 printf("%lu", resp->ru.ru_nswap);
336 break; 358 break;
@@ -343,11 +365,13 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
343 case 'c': /* Involuntary context switches. */ 365 case 'c': /* Involuntary context switches. */
344 printf("%lu", resp->ru.ru_nivcsw); 366 printf("%lu", resp->ru.ru_nivcsw);
345 break; 367 break;
368#endif
346 case 'e': /* Elapsed real time in seconds. */ 369 case 'e': /* Elapsed real time in seconds. */
347 printf("%u.%02u", 370 printf("%u.%02u",
348 (unsigned)resp->elapsed_ms / 1000, 371 (unsigned)resp->elapsed_ms / 1000,
349 (unsigned)(resp->elapsed_ms / 10) % 100); 372 (unsigned)(resp->elapsed_ms / 10) % 100);
350 break; 373 break;
374#if !ENABLE_PLATFORM_MINGW32
351 case 'k': /* Signals delivered. */ 375 case 'k': /* Signals delivered. */
352 printf("%lu", resp->ru.ru_nsignals); 376 printf("%lu", resp->ru.ru_nsignals);
353 break; 377 break;
@@ -366,6 +390,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
366 case 'w': /* Voluntary context switches. */ 390 case 'w': /* Voluntary context switches. */
367 printf("%lu", resp->ru.ru_nvcsw); 391 printf("%lu", resp->ru.ru_nvcsw);
368 break; 392 break;
393#endif
369 case 'x': /* Exit status. */ 394 case 'x': /* Exit status. */
370 printf("%u", WEXITSTATUS(resp->waitstatus)); 395 printf("%u", WEXITSTATUS(resp->waitstatus));
371 break; 396 break;
@@ -409,6 +434,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
409static void run_command(char *const *cmd, resource_t *resp) 434static void run_command(char *const *cmd, resource_t *resp)
410{ 435{
411 pid_t pid; 436 pid_t pid;
437#if !ENABLE_PLATFORM_MINGW32
412 void (*interrupt_signal)(int); 438 void (*interrupt_signal)(int);
413 void (*quit_signal)(int); 439 void (*quit_signal)(int);
414 440
@@ -429,6 +455,13 @@ static void run_command(char *const *cmd, resource_t *resp)
429 /* Re-enable signals. */ 455 /* Re-enable signals. */
430 signal(SIGINT, interrupt_signal); 456 signal(SIGINT, interrupt_signal);
431 signal(SIGQUIT, quit_signal); 457 signal(SIGQUIT, quit_signal);
458#else
459 resp->elapsed_ms = monotonic_ms();
460 if ((pid=spawn((char **)cmd)) == -1)
461 bb_perror_msg_and_die("can't execute %s", cmd[0]);
462
463 resuse_end(pid, resp);
464#endif
432} 465}
433 466
434int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 467int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -442,20 +475,35 @@ int time_main(int argc UNUSED_PARAM, char **argv)
442 int opt; 475 int opt;
443 int ex; 476 int ex;
444 enum { 477 enum {
478#if !ENABLE_PLATFORM_MINGW32
445 OPT_v = (1 << 0), 479 OPT_v = (1 << 0),
446 OPT_p = (1 << 1), 480 OPT_p = (1 << 1),
447 OPT_a = (1 << 2), 481 OPT_a = (1 << 2),
448 OPT_o = (1 << 3), 482 OPT_o = (1 << 3),
449 OPT_f = (1 << 4), 483 OPT_f = (1 << 4),
484#else
485 OPT_p = (1 << 0),
486 OPT_a = (1 << 1),
487 OPT_o = (1 << 2),
488 OPT_f = (1 << 3),
489#endif
450 }; 490 };
451 491
452 /* "+": stop on first non-option */ 492 /* "+": stop on first non-option */
493#if !ENABLE_PLATFORM_MINGW32
453 opt = getopt32(argv, "^+" "vpao:f:" "\0" "-1"/*at least one arg*/, 494 opt = getopt32(argv, "^+" "vpao:f:" "\0" "-1"/*at least one arg*/,
454 &output_filename, &output_format 495 &output_filename, &output_format
455 ); 496 );
497#else
498 opt = getopt32(argv, "^+" "pao:f:" "\0" "-1"/*at least one arg*/,
499 &output_filename, &output_format
500 );
501#endif
456 argv += optind; 502 argv += optind;
503#if !ENABLE_PLATFORM_MINGW32
457 if (opt & OPT_v) 504 if (opt & OPT_v)
458 output_format = long_format; 505 output_format = long_format;
506#endif
459 if (opt & OPT_p) 507 if (opt & OPT_p)
460 output_format = posix_format; 508 output_format = posix_format;
461 output_fd = STDERR_FILENO; 509 output_fd = STDERR_FILENO;
@@ -476,6 +524,9 @@ int time_main(int argc UNUSED_PARAM, char **argv)
476 524
477 /* Cheat. printf's are shorter :) */ 525 /* Cheat. printf's are shorter :) */
478 xdup2(output_fd, STDOUT_FILENO); 526 xdup2(output_fd, STDOUT_FILENO);
527#if ENABLE_PLATFORM_MINGW32
528 setvbuf(stdout, NULL, _IOFBF, 256);
529#endif
479 summarize(output_format, argv, &res); 530 summarize(output_format, argv, &res);
480 531
481 ex = WEXITSTATUS(res.waitstatus); 532 ex = WEXITSTATUS(res.waitstatus);
diff --git a/miscutils/ts.c b/miscutils/ts.c
index c5c1879df..fb669b858 100644
--- a/miscutils/ts.c
+++ b/miscutils/ts.c
@@ -25,6 +25,9 @@ int ts_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
25int ts_main(int argc UNUSED_PARAM, char **argv) 25int ts_main(int argc UNUSED_PARAM, char **argv)
26{ 26{
27 struct timeval base; 27 struct timeval base;
28#if ENABLE_PLATFORM_MINGW32
29 time_t t;
30#endif
28 unsigned opt; 31 unsigned opt;
29 char *frac; 32 char *frac;
30 char *fmt_dt2str; 33 char *fmt_dt2str;
@@ -73,7 +76,12 @@ int ts_main(int argc UNUSED_PARAM, char **argv)
73 if (opt & 1) /* -i */ 76 if (opt & 1) /* -i */
74 base = ts1; 77 base = ts1;
75 } 78 }
79#if ENABLE_PLATFORM_MINGW32
80 t = ts.tv_sec;
81 localtime_r(&t, &tm_time);
82#else
76 localtime_r(&ts.tv_sec, &tm_time); 83 localtime_r(&ts.tv_sec, &tm_time);
84#endif
77 strftime(date_buf, COMMON_BUFSIZE, fmt_dt2str, &tm_time); 85 strftime(date_buf, COMMON_BUFSIZE, fmt_dt2str, &tm_time);
78 if (!frac) { 86 if (!frac) {
79 printf("%s %s", date_buf, line); 87 printf("%s %s", date_buf, line);
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c
index 1172850ce..86342769b 100644
--- a/networking/ftpgetput.c
+++ b/networking/ftpgetput.c
@@ -106,6 +106,9 @@ static int ftpcmd(const char *s1, const char *s2)
106 fprintf(control_stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3), 106 fprintf(control_stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3),
107 s1, s2); 107 s1, s2);
108 fflush(control_stream); 108 fflush(control_stream);
109#if ENABLE_PLATFORM_MINGW32
110 fseek(control_stream, 0L, SEEK_CUR);
111#endif
109 } 112 }
110 113
111 do { 114 do {
@@ -114,6 +117,9 @@ static int ftpcmd(const char *s1, const char *s2)
114 ftp_die(NULL); 117 ftp_die(NULL);
115 } 118 }
116 } while (!isdigit(buf[0]) || buf[3] != ' '); 119 } while (!isdigit(buf[0]) || buf[3] != ' ');
120#if ENABLE_PLATFORM_MINGW32
121 fseek(control_stream, 0L, SEEK_CUR);
122#endif
117 123
118 buf[3] = '\0'; 124 buf[3] = '\0';
119 n = xatou(buf); 125 n = xatou(buf);
diff --git a/networking/httpd.c b/networking/httpd.c
index ddcb03bca..1dae602ee 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -264,7 +264,12 @@
264//kbuild:lib-$(CONFIG_HTTPD) += httpd.o 264//kbuild:lib-$(CONFIG_HTTPD) += httpd.o
265 265
266//usage:#define httpd_trivial_usage 266//usage:#define httpd_trivial_usage
267//usage: IF_NOT_PLATFORM_MINGW32(
267//usage: "[-ifv[v]]" 268//usage: "[-ifv[v]]"
269//usage: )
270//usage: IF_PLATFORM_MINGW32(
271//usage: "[-fv[v]]"
272//usage: )
268//usage: " [-c CONFFILE]" 273//usage: " [-c CONFFILE]"
269//usage: " [-p [IP:]PORT]" 274//usage: " [-p [IP:]PORT]"
270//usage: IF_FEATURE_HTTPD_SETUID(" [-u USER[:GRP]]") 275//usage: IF_FEATURE_HTTPD_SETUID(" [-u USER[:GRP]]")
@@ -273,7 +278,9 @@
273//usage: "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING" 278//usage: "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING"
274//usage:#define httpd_full_usage "\n\n" 279//usage:#define httpd_full_usage "\n\n"
275//usage: "Listen for incoming HTTP requests\n" 280//usage: "Listen for incoming HTTP requests\n"
281//usage: IF_NOT_PLATFORM_MINGW32(
276//usage: "\n -i Inetd mode" 282//usage: "\n -i Inetd mode"
283//usage: )
277//usage: "\n -f Run in foreground" 284//usage: "\n -f Run in foreground"
278//usage: "\n -v[v] Verbose" 285//usage: "\n -v[v] Verbose"
279//usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:"STR(CONFIG_FEATURE_HTTPD_PORT_DEFAULT)")" 286//usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:"STR(CONFIG_FEATURE_HTTPD_PORT_DEFAULT)")"
@@ -292,6 +299,9 @@
292 299
293#include "libbb.h" 300#include "libbb.h"
294#include "common_bufsiz.h" 301#include "common_bufsiz.h"
302#if ENABLE_PLATFORM_MINGW32
303# include "BB_VER.h"
304#endif
295#if ENABLE_PAM 305#if ENABLE_PAM
296/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */ 306/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */
297# undef setlocale 307# undef setlocale
@@ -322,6 +332,8 @@
322 332
323#define HEADER_READ_TIMEOUT 60 333#define HEADER_READ_TIMEOUT 60
324 334
335static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN;
336
325#define STR1(s) #s 337#define STR1(s) #s
326#define STR(s) STR1(s) 338#define STR(s) STR1(s)
327 339
@@ -452,6 +464,13 @@ static const struct {
452 464
453struct globals { 465struct globals {
454 int verbose; /* must be int (used by getopt32) */ 466 int verbose; /* must be int (used by getopt32) */
467#if ENABLE_PLATFORM_MINGW32
468 smallint foreground;
469# if ENABLE_FEATURE_HTTPD_CGI
470 int server_argc;
471 char **server_argv;
472# endif
473#endif
455 smallint flg_deny_all; 474 smallint flg_deny_all;
456#if ENABLE_FEATURE_HTTPD_GZIP 475#if ENABLE_FEATURE_HTTPD_GZIP
457 /* client can handle gzip / we are going to send gzip */ 476 /* client can handle gzip / we are going to send gzip */
@@ -509,6 +528,11 @@ struct globals {
509}; 528};
510#define G (*ptr_to_globals) 529#define G (*ptr_to_globals)
511#define verbose (G.verbose ) 530#define verbose (G.verbose )
531#if ENABLE_PLATFORM_MINGW32
532#define foreground (G.foreground )
533#define server_argc (G.server_argc )
534#define server_argv (G.server_argv )
535#endif
512#define flg_deny_all (G.flg_deny_all ) 536#define flg_deny_all (G.flg_deny_all )
513#if ENABLE_FEATURE_HTTPD_GZIP 537#if ENABLE_FEATURE_HTTPD_GZIP
514# define content_gzip (G.content_gzip ) 538# define content_gzip (G.content_gzip )
@@ -557,7 +581,12 @@ enum {
557} while (0) 581} while (0)
558 582
559 583
584#if !ENABLE_PLATFORM_MINGW32
560#define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1) 585#define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1)
586#else
587/* Not exactly equivalent to strncasecmp(), but OK for its use here */
588#define STRNCASECMP(a, str) (!is_prefixed_with_case((a), (str)))
589#endif
561 590
562/* Prototypes */ 591/* Prototypes */
563enum { 592enum {
@@ -721,8 +750,16 @@ static int parse_conf(const char *path, int flag)
721 750
722 filename = opt_c_configFile; 751 filename = opt_c_configFile;
723 if (flag == SUBDIR_PARSE || filename == NULL) { 752 if (flag == SUBDIR_PARSE || filename == NULL) {
753#if !ENABLE_PLATFORM_MINGW32
724 filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2); 754 filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2);
725 sprintf((char *)filename, "%s/%s", path, HTTPD_CONF); 755 sprintf((char *)filename, "%s/%s", path, HTTPD_CONF);
756#else
757 const char *sd = "";
758 if (root_len(path) == 0 && (path[0] == '/' || path[0] == '\\'))
759 sd = get_system_drive();
760
761 filename = auto_string(xasprintf("%s%s/%s", sd, path, HTTPD_CONF));
762#endif
726 } 763 }
727 764
728 while ((f = fopen_for_read(filename)) == NULL) { 765 while ((f = fopen_for_read(filename)) == NULL) {
@@ -771,6 +808,7 @@ static int parse_conf(const char *path, int flag)
771 * without needless copying, therefore we don't merge 808 * without needless copying, therefore we don't merge
772 * this operation into next while loop. */ 809 * this operation into next while loop. */
773 while ((ch = *p0) != '\0' && ch != '\n' && ch != '#' 810 while ((ch = *p0) != '\0' && ch != '\n' && ch != '#'
811 IF_PLATFORM_MINGW32(&& ch != '\r')
774 && ch != ' ' && ch != '\t' 812 && ch != ' ' && ch != '\t'
775 ) { 813 ) {
776 p0++; 814 p0++;
@@ -778,7 +816,11 @@ static int parse_conf(const char *path, int flag)
778 p = p0; 816 p = p0;
779 /* if we enter this loop, we have some whitespace. 817 /* if we enter this loop, we have some whitespace.
780 * discard it */ 818 * discard it */
819#if !ENABLE_PLATFORM_MINGW32
781 while (ch != '\0' && ch != '\n' && ch != '#') { 820 while (ch != '\0' && ch != '\n' && ch != '#') {
821#else
822 while (ch != '\0' && ch != '\n' && ch != '\r' && ch != '#') {
823#endif
782 if (ch != ' ' && ch != '\t') { 824 if (ch != ' ' && ch != '\t') {
783 *p++ = ch; 825 *p++ = ch;
784 } 826 }
@@ -1311,7 +1353,21 @@ static unsigned get_line(void)
1311 count = 0; 1353 count = 0;
1312 while (1) { 1354 while (1) {
1313 if (hdr_cnt <= 0) { 1355 if (hdr_cnt <= 0) {
1356#if ENABLE_PLATFORM_MINGW32
1357 int nfds = 1;
1358 struct pollfd fds = {STDIN_FILENO, POLLIN, 0};
1359
1360 switch (poll(&fds, nfds, HEADER_READ_TIMEOUT*1000)) {
1361 case 0:
1362 send_REQUEST_TIMEOUT_and_exit(0);
1363 break;
1364 case -1:
1365 bb_simple_perror_msg_and_die("poll");
1366 break;
1367 }
1368#else
1314 alarm(HEADER_READ_TIMEOUT); 1369 alarm(HEADER_READ_TIMEOUT);
1370#endif
1315 hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf); 1371 hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf);
1316 if (hdr_cnt <= 0) 1372 if (hdr_cnt <= 0)
1317 goto ret; 1373 goto ret;
@@ -1523,6 +1579,47 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
1523#endif 1579#endif
1524 1580
1525#if ENABLE_FEATURE_HTTPD_CGI 1581#if ENABLE_FEATURE_HTTPD_CGI
1582# if ENABLE_PLATFORM_MINGW32
1583static void cgi_handler(char **argv)
1584{
1585 struct fd_pair fromCgi; /* CGI -> httpd pipe */
1586 struct fd_pair toCgi; /* httpd -> CGI pipe */
1587
1588 xfunc_error_retval = 242;
1589
1590 if (sscanf(argv[0], "%d:%d:%d:%d", &toCgi.wr, &toCgi.rd,
1591 &fromCgi.wr, &fromCgi.rd) != 4) {
1592 exit(242);
1593 }
1594
1595 /* NB: close _first_, then move fds! */
1596 close(toCgi.wr);
1597 close(fromCgi.rd);
1598 xmove_fd(toCgi.rd, 0); /* replace stdin with the pipe */
1599 xmove_fd(fromCgi.wr, 1); /* replace stdout with the pipe */
1600
1601 if (argv[1][0] && chdir_or_warn(argv[1]) != 0) {
1602 goto error_execing_cgi;
1603 }
1604
1605 /* set argv[0] to name without path */
1606 argv += 2;
1607
1608 /* _NOT_ execvp. We do not search PATH. argv[0] is a filename
1609 * without any dir components and will only match a file
1610 * in the current directory */
1611 if (foreground)
1612 execv(argv[0], argv);
1613 else
1614 httpd_execv_detach(argv[0], argv);
1615 if (verbose)
1616 bb_perror_msg("can't execute '%s'", argv[0]);
1617 error_execing_cgi:
1618 /* send to stdout */
1619 iobuf = xmalloc(IOBUF_SIZE);
1620 send_headers_and_exit(HTTP_NOT_FOUND);
1621}
1622# endif
1526 1623
1527static void setenv1(const char *name, const char *value) 1624static void setenv1(const char *name, const char *value)
1528{ 1625{
@@ -1556,6 +1653,10 @@ static void send_cgi_and_exit(
1556 struct fd_pair toCgi; /* httpd -> CGI pipe */ 1653 struct fd_pair toCgi; /* httpd -> CGI pipe */
1557 char *script, *last_slash; 1654 char *script, *last_slash;
1558 int pid; 1655 int pid;
1656#if ENABLE_PLATFORM_MINGW32
1657 const char *script_dir;
1658 char **argv;
1659#endif
1559 1660
1560 /* Make a copy. NB: caller guarantees: 1661 /* Make a copy. NB: caller guarantees:
1561 * url[0] == '/', url[1] != '/' */ 1662 * url[0] == '/', url[1] != '/' */
@@ -1592,7 +1693,11 @@ static void send_cgi_and_exit(
1592 *script = '\0'; /* cut off /PATH_INFO */ 1693 *script = '\0'; /* cut off /PATH_INFO */
1593 1694
1594 /* SCRIPT_FILENAME is required by PHP in CGI mode */ 1695 /* SCRIPT_FILENAME is required by PHP in CGI mode */
1696#if ENABLE_PLATFORM_MINGW32
1697 if (!is_relative_path(home_httpd)) {
1698#else
1595 if (home_httpd[0] == '/') { 1699 if (home_httpd[0] == '/') {
1700#endif
1596 char *fullpath = concat_path_file(home_httpd, url); 1701 char *fullpath = concat_path_file(home_httpd, url);
1597 setenv1("SCRIPT_FILENAME", fullpath); 1702 setenv1("SCRIPT_FILENAME", fullpath);
1598 } 1703 }
@@ -1642,6 +1747,50 @@ static void send_cgi_and_exit(
1642 xpiped_pair(fromCgi); 1747 xpiped_pair(fromCgi);
1643 xpiped_pair(toCgi); 1748 xpiped_pair(toCgi);
1644 1749
1750#if ENABLE_PLATFORM_MINGW32
1751 /* Find script's dir */
1752 script_dir = "";
1753 script = last_slash;
1754 if (script != url) { /* paranoia */
1755 *script = '\0';
1756 script_dir = url + 1;
1757 }
1758 script++;
1759
1760 argv = xzalloc((server_argc + 9) * sizeof(char *));
1761 argv[0] = (char *)bb_busybox_exec_path;
1762 argv[1] = (char *)"--busybox";
1763 argv[2] = (char *)"-httpd"; // don't daemonise in main()
1764 argv[3] = (char *)"-I0";
1765 memcpy(argv + 4, server_argv, sizeof(*argv) * server_argc);
1766 argv[server_argc + 4] = xasprintf("%d:%d:%d:%d", toCgi.wr, toCgi.rd,
1767 fromCgi.wr, fromCgi.rd);
1768 argv[server_argc + 5] = (char *)script_dir; // script directory
1769 argv[server_argc + 6] = (char *)script; // script name
1770
1771#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
1772 {
1773 char *suffix = strrchr(script, '.');
1774
1775 if (suffix) {
1776 Htaccess *cur;
1777 for (cur = script_i; cur; cur = cur->next) {
1778 if (strcmp(cur->before_colon + 1, suffix) == 0) {
1779 /* found interpreter name */
1780 argv[server_argc + 6] = (char *)cur->after_colon;
1781 argv[server_argc + 7] = (char *)script;
1782 break;
1783 }
1784 }
1785 }
1786 }
1787#endif
1788 /* argv[server_argc + N] = NULL; - xzalloc did it */
1789
1790 pid = foreground ? mingw_spawn(argv) : mingw_spawn_detach(argv);
1791 if (pid == -1)
1792 log_and_exit();
1793#else
1645 pid = vfork(); 1794 pid = vfork();
1646 if (pid < 0) { 1795 if (pid < 0) {
1647 /* TODO: log perror? */ 1796 /* TODO: log perror? */
@@ -1719,6 +1868,7 @@ static void send_cgi_and_exit(
1719 1868
1720 /* Restore variables possibly changed by child */ 1869 /* Restore variables possibly changed by child */
1721 xfunc_error_retval = 0; 1870 xfunc_error_retval = 0;
1871#endif
1722 1872
1723 /* Pump data */ 1873 /* Pump data */
1724 close(fromCgi.wr); 1874 close(fromCgi.wr);
@@ -1770,7 +1920,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
1770 } 1920 }
1771#if ENABLE_FEATURE_HTTPD_ETAG 1921#if ENABLE_FEATURE_HTTPD_ETAG
1772 /* ETag is "hex(last_mod)-hex(file_size)" e.g. "5e132e20-417" */ 1922 /* ETag is "hex(last_mod)-hex(file_size)" e.g. "5e132e20-417" */
1773 sprintf(G.etag, "\"%llx-%llx\"", (unsigned long long)last_mod, (unsigned long long)file_size); 1923 sprintf(G.etag, "\"%"LL_FMT"x-%"LL_FMT"x\"", (unsigned long long)last_mod, (unsigned long long)file_size);
1774 1924
1775 if (G.if_none_match) { 1925 if (G.if_none_match) {
1776 dbg("If-None-Match:'%s' file's ETag:'%s'\n", G.if_none_match, G.etag); 1926 dbg("If-None-Match:'%s' file's ETag:'%s'\n", G.if_none_match, G.etag);
@@ -2025,7 +2175,11 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2025 2175
2026 /* WHY? */ 2176 /* WHY? */
2027 /* If already saw a match, don't accept other different matches */ 2177 /* If already saw a match, don't accept other different matches */
2178#if !ENABLE_PLATFORM_MINGW32
2028 if (prev && strcmp(prev, dir_prefix) != 0) 2179 if (prev && strcmp(prev, dir_prefix) != 0)
2180#else
2181 if (prev && strcasecmp(prev, dir_prefix) != 0)
2182#endif
2029 continue; 2183 continue;
2030 2184
2031 dbg("checkPerm: '%s' ? '%s'\n", dir_prefix, user_and_passwd); 2185 dbg("checkPerm: '%s' ? '%s'\n", dir_prefix, user_and_passwd);
@@ -2033,7 +2187,11 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2033 /* If it's not a prefix match, continue searching */ 2187 /* If it's not a prefix match, continue searching */
2034 len = strlen(dir_prefix); 2188 len = strlen(dir_prefix);
2035 if (len != 1 /* dir_prefix "/" matches all, don't need to check */ 2189 if (len != 1 /* dir_prefix "/" matches all, don't need to check */
2190#if !ENABLE_PLATFORM_MINGW32
2036 && (strncmp(dir_prefix, path, len) != 0 2191 && (strncmp(dir_prefix, path, len) != 0
2192#else
2193 && (strncasecmp(dir_prefix, path, len) != 0
2194#endif
2037 || (path[len] != '/' && path[len] != '\0') 2195 || (path[len] != '/' && path[len] != '\0')
2038 ) 2196 )
2039 ) { 2197 ) {
@@ -2055,6 +2213,7 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2055 goto bad_input; 2213 goto bad_input;
2056 2214
2057 /* compare "user:" */ 2215 /* compare "user:" */
2216# if !ENABLE_PLATFORM_MINGW32
2058 if (cur->after_colon[0] != '*' 2217 if (cur->after_colon[0] != '*'
2059 && strncmp(cur->after_colon, user_and_passwd, 2218 && strncmp(cur->after_colon, user_and_passwd,
2060 colon_after_user - user_and_passwd + 1) != 0 2219 colon_after_user - user_and_passwd + 1) != 0
@@ -2062,11 +2221,20 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2062 continue; 2221 continue;
2063 } 2222 }
2064 /* this cfg entry is '*' or matches username from peer */ 2223 /* this cfg entry is '*' or matches username from peer */
2224# else
2225 if (strncmp(cur->after_colon, user_and_passwd,
2226 colon_after_user - user_and_passwd + 1) != 0
2227 ) {
2228 continue;
2229 }
2230 /* this cfg entry matches username from peer */
2231# endif
2065 2232
2066 passwd = strchr(cur->after_colon, ':'); 2233 passwd = strchr(cur->after_colon, ':');
2067 if (!passwd) 2234 if (!passwd)
2068 goto bad_input; 2235 goto bad_input;
2069 passwd++; 2236 passwd++;
2237# if !ENABLE_PLATFORM_MINGW32
2070 if (passwd[0] == '*') { 2238 if (passwd[0] == '*') {
2071# if ENABLE_PAM 2239# if ENABLE_PAM
2072 struct pam_userinfo userinfo; 2240 struct pam_userinfo userinfo;
@@ -2114,11 +2282,12 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2114 goto check_encrypted; 2282 goto check_encrypted;
2115# endif /* ENABLE_PAM */ 2283# endif /* ENABLE_PAM */
2116 } 2284 }
2285# endif /* !ENABLE_PLATFORM_MINGW32 */
2117 /* Else: passwd is from httpd.conf, it is either plaintext or encrypted */ 2286 /* Else: passwd is from httpd.conf, it is either plaintext or encrypted */
2118 2287
2119 if (passwd[0] == '$' && isdigit(passwd[1])) { 2288 if (passwd[0] == '$' && isdigit(passwd[1])) {
2120 char *encrypted; 2289 char *encrypted;
2121# if !ENABLE_PAM 2290# if !ENABLE_PAM && !ENABLE_PLATFORM_MINGW32
2122 check_encrypted: 2291 check_encrypted:
2123# endif 2292# endif
2124 /* encrypt pwd from peer and check match with local one */ 2293 /* encrypt pwd from peer and check match with local one */
@@ -2167,7 +2336,6 @@ static Htaccess_Proxy *find_proxy_entry(const char *url)
2167/* 2336/*
2168 * Handle timeouts 2337 * Handle timeouts
2169 */ 2338 */
2170static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN;
2171static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM) 2339static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM)
2172{ 2340{
2173 send_headers_and_exit(HTTP_REQUEST_TIMEOUT); 2341 send_headers_and_exit(HTTP_REQUEST_TIMEOUT);
@@ -2231,17 +2399,29 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2231 remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr); 2399 remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr);
2232 } 2400 }
2233# if ENABLE_FEATURE_IPV6 2401# if ENABLE_FEATURE_IPV6
2402# if !ENABLE_PLATFORM_MINGW32
2234 if (fromAddr->u.sa.sa_family == AF_INET6 2403 if (fromAddr->u.sa.sa_family == AF_INET6
2235 && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0 2404 && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0
2236 && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0 2405 && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0
2237 && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff) 2406 && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff)
2238 remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]); 2407 remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]);
2408# else
2409 if (fromAddr->u.sa.sa_family == AF_INET6
2410 && fromAddr->u.sin6.sin6_addr.s6_words[0] == 0
2411 && fromAddr->u.sin6.sin6_addr.s6_words[1] == 0
2412 && fromAddr->u.sin6.sin6_addr.s6_words[2] == 0
2413 && fromAddr->u.sin6.sin6_addr.s6_words[3] == 0
2414 && ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+4)) == 0xffff)
2415 remote_ip = ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+6));
2416# endif
2239# endif 2417# endif
2240 if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip); 2418 if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip);
2241#endif 2419#endif
2242 2420
2421#ifdef SIGALRM
2243 /* Install timeout handler. get_line() needs it. */ 2422 /* Install timeout handler. get_line() needs it. */
2244 signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit); 2423 signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit);
2424#endif
2245 2425
2246 if (!get_line()) { /* EOF or error or empty line */ 2426 if (!get_line()) { /* EOF or error or empty line */
2247 /* Observed Firefox to "speculatively" open 2427 /* Observed Firefox to "speculatively" open
@@ -2580,7 +2760,11 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2580 /* We are done reading headers, disable peer timeout */ 2760 /* We are done reading headers, disable peer timeout */
2581 alarm(0); 2761 alarm(0);
2582 2762
2763#if !ENABLE_PLATFORM_MINGW32
2583 if (strcmp(bb_basename(urlcopy), HTTPD_CONF) == 0) { 2764 if (strcmp(bb_basename(urlcopy), HTTPD_CONF) == 0) {
2765#else
2766 if (strcasecmp(bb_basename(urlcopy), HTTPD_CONF) == 0) {
2767#endif
2584 /* protect listing [/path]/httpd.conf or IP deny */ 2768 /* protect listing [/path]/httpd.conf or IP deny */
2585 send_headers_and_exit(HTTP_FORBIDDEN); 2769 send_headers_and_exit(HTTP_FORBIDDEN);
2586 } 2770 }
@@ -2626,12 +2810,14 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2626 ); 2810 );
2627} 2811}
2628 2812
2813
2629/* 2814/*
2630 * The main http server function. 2815 * The main http server function.
2631 * Given a socket, listen for new connections and farm out 2816 * Given a socket, listen for new connections and farm out
2632 * the processing as a [v]forked process. 2817 * the processing as a [v]forked process.
2633 * Never returns. 2818 * Never returns.
2634 */ 2819 */
2820# if !ENABLE_PLATFORM_MINGW32
2635#if BB_MMU 2821#if BB_MMU
2636static void mini_httpd(int server_socket) NORETURN; 2822static void mini_httpd(int server_socket) NORETURN;
2637static void mini_httpd(int server_socket) 2823static void mini_httpd(int server_socket)
@@ -2720,6 +2906,40 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv)
2720 /* never reached */ 2906 /* never reached */
2721} 2907}
2722#endif 2908#endif
2909#else /* ENABLE_PLATFORM_MINGW32 */
2910static void mini_httpd_win32(int sock, int argc, char **argv) NORETURN;
2911static void mini_httpd_win32(int sock, int argc, char **argv)
2912{
2913 char *argv_copy[argc + 5];
2914
2915 argv_copy[0] = (char *)bb_busybox_exec_path;
2916 argv_copy[1] = (char *)"--busybox";
2917 argv_copy[2] = (char *)"-httpd"; // don't daemonise in main()
2918 argv_copy[3] = (char *)"-I";
2919 memcpy(&argv_copy[5], &argv[1], argc * sizeof(argv[0]));
2920
2921 while (1) {
2922 int n;
2923
2924 /* Wait for connections... */
2925 n = accept(sock, NULL, NULL);
2926 if (n < 0)
2927 continue;
2928
2929 /* set the KEEPALIVE option to cull dead connections */
2930 setsockopt_keepalive(n);
2931
2932 argv_copy[4] = itoa(n);
2933 if ((foreground ?
2934 spawn(argv_copy) : mingw_spawn_detach(argv_copy)) == -1)
2935 bb_perror_msg_and_die("can't execute 'httpd'");
2936
2937 /* parent, or spawn failed */
2938 close(n);
2939 } /* while (1) */
2940 /* never reached */
2941}
2942#endif
2723 2943
2724/* 2944/*
2725 * Process a HTTP connection on stdin/out. 2945 * Process a HTTP connection on stdin/out.
@@ -2737,12 +2957,36 @@ static void mini_httpd_inetd(void)
2737 handle_incoming_and_exit(&fromAddr); 2957 handle_incoming_and_exit(&fromAddr);
2738} 2958}
2739 2959
2960#if ENABLE_PLATFORM_MINGW32
2961static void mingw_daemonize(char **argv)
2962{
2963 char **new_argv;
2964 int fd;
2965
2966 new_argv = grow_argv(argv + 1, 3);
2967 new_argv[0] = (char *)bb_busybox_exec_path;
2968 new_argv[1] = (char *)"--busybox";
2969 // don't daemonise in main(), we explicitly detach below
2970 new_argv[2] = (char *)"-httpd";
2971
2972 fd = xopen(bb_dev_null, O_RDWR);
2973 xdup2(fd, 0);
2974 xdup2(fd, 1);
2975 xdup2(fd, 2);
2976 close(fd);
2977
2978 exit(mingw_spawn_detach(new_argv) == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
2979}
2980#endif
2981
2982#if !ENABLE_PLATFORM_MINGW32
2740static void sighup_handler(int sig UNUSED_PARAM) 2983static void sighup_handler(int sig UNUSED_PARAM)
2741{ 2984{
2742 int sv = errno; 2985 int sv = errno;
2743 parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE); 2986 parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE);
2744 errno = sv; 2987 errno = sv;
2745} 2988}
2989#endif
2746 2990
2747enum { 2991enum {
2748 c_opt_config_file = 0, 2992 c_opt_config_file = 0,
@@ -2780,6 +3024,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2780 IF_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;) 3024 IF_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;)
2781 IF_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;) 3025 IF_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;)
2782 IF_FEATURE_HTTPD_AUTH_MD5(const char *pass;) 3026 IF_FEATURE_HTTPD_AUTH_MD5(const char *pass;)
3027 IF_PLATFORM_MINGW32(int fd;)
2783 3028
2784 INIT_G(); 3029 INIT_G();
2785 3030
@@ -2798,16 +3043,19 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2798 IF_FEATURE_HTTPD_BASIC_AUTH("r:") 3043 IF_FEATURE_HTTPD_BASIC_AUTH("r:")
2799 IF_FEATURE_HTTPD_AUTH_MD5("m:") 3044 IF_FEATURE_HTTPD_AUTH_MD5("m:")
2800 IF_FEATURE_HTTPD_SETUID("u:") 3045 IF_FEATURE_HTTPD_SETUID("u:")
2801 "p:ifv" 3046 IF_NOT_PLATFORM_MINGW32("p:ifv")
3047 IF_PLATFORM_MINGW32("p:I:+fv")
2802 "\0" 3048 "\0"
2803 /* -v counts, -i implies -f */ 3049 /* -v counts, -i implies -f */
2804 "vv:if", 3050 IF_NOT_PLATFORM_MINGW32("vv:if",)
3051 IF_PLATFORM_MINGW32("vv:",)
2805 &opt_c_configFile, &url_for_decode, &home_httpd 3052 &opt_c_configFile, &url_for_decode, &home_httpd
2806 IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode) 3053 IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode)
2807 IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm) 3054 IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm)
2808 IF_FEATURE_HTTPD_AUTH_MD5(, &pass) 3055 IF_FEATURE_HTTPD_AUTH_MD5(, &pass)
2809 IF_FEATURE_HTTPD_SETUID(, &s_ugid) 3056 IF_FEATURE_HTTPD_SETUID(, &s_ugid)
2810 , &bind_addr_or_port 3057 , &bind_addr_or_port
3058 IF_PLATFORM_MINGW32(, &fd)
2811 , &verbose 3059 , &verbose
2812 ); 3060 );
2813 if (opt & OPT_DECODE_URL) { 3061 if (opt & OPT_DECODE_URL) {
@@ -2837,20 +3085,33 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2837 } 3085 }
2838#endif 3086#endif
2839 3087
3088#if !ENABLE_PLATFORM_MINGW32
2840#if !BB_MMU 3089#if !BB_MMU
2841 if (!(opt & OPT_FOREGROUND)) { 3090 if (!(opt & OPT_FOREGROUND)) {
2842 bb_daemonize_or_rexec(0, argv); /* don't change current directory */ 3091 bb_daemonize_or_rexec(0, argv); /* don't change current directory */
2843 re_execed = 0; /* for the following chdir to work */ 3092 re_execed = 0; /* for the following chdir to work */
2844 } 3093 }
2845#endif 3094#endif
3095#else /* ENABLE_PLATFORM_MINGW32 */
3096 foreground = (opt & OPT_FOREGROUND) == OPT_FOREGROUND;
3097 if (!foreground && argv[0][0] != '-')
3098 mingw_daemonize(argv);
3099#endif
3100
2846 /* Chdir to home (unless we were re_exec()ed for NOMMU case 3101 /* Chdir to home (unless we were re_exec()ed for NOMMU case
2847 * in mini_httpd_nommu(): we are already in the home dir then). 3102 * in mini_httpd_nommu(): we are already in the home dir then).
2848 */ 3103 */
3104#if ENABLE_PLATFORM_MINGW32
3105 if (!(opt & OPT_INETD))
3106#else
2849 if (!re_execed) 3107 if (!re_execed)
3108#endif
2850 xchdir(home_httpd); 3109 xchdir(home_httpd);
2851 3110
2852 if (!(opt & OPT_INETD)) { 3111 if (!(opt & OPT_INETD)) {
3112#ifdef SIGCHLD
2853 signal(SIGCHLD, SIG_IGN); 3113 signal(SIGCHLD, SIG_IGN);
3114#endif
2854 server_socket = openServer(); 3115 server_socket = openServer();
2855#if ENABLE_FEATURE_HTTPD_SETUID 3116#if ENABLE_FEATURE_HTTPD_SETUID
2856 /* drop privileges */ 3117 /* drop privileges */
@@ -2884,12 +3145,35 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2884#endif 3145#endif
2885 3146
2886 parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE); 3147 parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE);
3148#if ENABLE_PLATFORM_MINGW32
3149# if ENABLE_FEATURE_HTTPD_CGI
3150 if ((opt & OPT_INETD) && fd == 0) {
3151 cgi_handler(argv + optind);
3152 return 0;
3153 }
3154# endif
3155#else
2887 if (!(opt & OPT_INETD)) 3156 if (!(opt & OPT_INETD))
2888 signal(SIGHUP, sighup_handler); 3157 signal(SIGHUP, sighup_handler);
3158#endif
2889 3159
2890 xfunc_error_retval = 0; 3160 xfunc_error_retval = 0;
3161#if ENABLE_PLATFORM_MINGW32
3162 if (opt & OPT_INETD) {
3163 xmove_fd(fd, 0);
3164 xdup2(0, 1);
3165 while (--fd > 2)
3166 close(fd);
3167# if ENABLE_FEATURE_HTTPD_CGI
3168 /* Skip 'httpd -I N' and omit any non-option arguments */
3169 server_argc = optind - 3;
3170 server_argv = argv + 3;
3171# endif
3172 }
3173#endif
2891 if (opt & OPT_INETD) 3174 if (opt & OPT_INETD)
2892 mini_httpd_inetd(); /* never returns */ 3175 mini_httpd_inetd(); /* never returns */
3176#if !ENABLE_PLATFORM_MINGW32
2893#if BB_MMU 3177#if BB_MMU
2894 if (!(opt & OPT_FOREGROUND)) 3178 if (!(opt & OPT_FOREGROUND))
2895 bb_daemonize(0); /* don't change current directory */ 3179 bb_daemonize(0); /* don't change current directory */
@@ -2897,5 +3181,8 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2897#else 3181#else
2898 mini_httpd_nommu(server_socket, argc, argv); /* never returns */ 3182 mini_httpd_nommu(server_socket, argc, argv); /* never returns */
2899#endif 3183#endif
3184#else /* ENABLE_PLATFORM_MINGW32 */
3185 mini_httpd_win32(server_socket, argc, argv);
3186#endif
2900 /* return 0; */ 3187 /* return 0; */
2901} 3188}
diff --git a/networking/nc.c b/networking/nc.c
index ab1316339..ee008595d 100644
--- a/networking/nc.c
+++ b/networking/nc.c
@@ -30,7 +30,7 @@
30//config:config NC_EXTRA 30//config:config NC_EXTRA
31//config: bool "Netcat extensions (-eiw and -f FILE)" 31//config: bool "Netcat extensions (-eiw and -f FILE)"
32//config: default y 32//config: default y
33//config: depends on NC || NETCAT 33//config: depends on (NC || NETCAT) && PLATFORM_POSIX
34//config: help 34//config: help
35//config: Add -e (support for executing the rest of the command line after 35//config: Add -e (support for executing the rest of the command line after
36//config: making or receiving a successful connection), -i (delay interval for 36//config: making or receiving a successful connection), -i (delay interval for
@@ -110,10 +110,12 @@
110 * when compared to "standard" nc 110 * when compared to "standard" nc
111 */ 111 */
112 112
113#if !ENABLE_PLATFORM_MINGW32
113static void timeout(int signum UNUSED_PARAM) 114static void timeout(int signum UNUSED_PARAM)
114{ 115{
115 bb_simple_error_msg_and_die("timed out"); 116 bb_simple_error_msg_and_die("timed out");
116} 117}
118#endif
117 119
118int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 120int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
119int nc_main(int argc, char **argv) 121int nc_main(int argc, char **argv)
@@ -123,7 +125,9 @@ int nc_main(int argc, char **argv)
123 int cfd = 0; 125 int cfd = 0;
124 unsigned lport = 0; 126 unsigned lport = 0;
125 IF_NOT_NC_SERVER(const) unsigned do_listen = 0; 127 IF_NOT_NC_SERVER(const) unsigned do_listen = 0;
128#if !ENABLE_PLATFORM_MINGW32
126 IF_NOT_NC_EXTRA (const) unsigned wsecs = 0; 129 IF_NOT_NC_EXTRA (const) unsigned wsecs = 0;
130#endif
127 IF_NOT_NC_EXTRA (const) unsigned delay = 0; 131 IF_NOT_NC_EXTRA (const) unsigned delay = 0;
128 IF_NOT_NC_EXTRA (const int execparam = 0;) 132 IF_NOT_NC_EXTRA (const int execparam = 0;)
129 IF_NC_EXTRA (char **execparam = NULL;) 133 IF_NC_EXTRA (char **execparam = NULL;)
@@ -187,10 +191,12 @@ int nc_main(int argc, char **argv)
187 argv++; 191 argv++;
188 } 192 }
189 193
194#if !ENABLE_PLATFORM_MINGW32
190 if (wsecs) { 195 if (wsecs) {
191 signal(SIGALRM, timeout); 196 signal(SIGALRM, timeout);
192 alarm(wsecs); 197 alarm(wsecs);
193 } 198 }
199#endif
194 200
195 if (!cfd) { 201 if (!cfd) {
196 if (do_listen) { 202 if (do_listen) {
@@ -208,7 +214,7 @@ int nc_main(int argc, char **argv)
208 } 214 }
209#endif 215#endif
210 close_on_exec_on(sfd); 216 close_on_exec_on(sfd);
211 accept_again: 217 IF_NOT_PLATFORM_MINGW32(accept_again:)
212 cfd = accept(sfd, NULL, 0); 218 cfd = accept(sfd, NULL, 0);
213 if (cfd < 0) 219 if (cfd < 0)
214 bb_simple_perror_msg_and_die("accept"); 220 bb_simple_perror_msg_and_die("accept");
@@ -220,6 +226,7 @@ int nc_main(int argc, char **argv)
220 } 226 }
221 } 227 }
222 228
229#if !ENABLE_PLATFORM_MINGW32
223 if (wsecs) { 230 if (wsecs) {
224 alarm(0); 231 alarm(0);
225 /* Non-ignored signals revert to SIG_DFL on exec anyway */ 232 /* Non-ignored signals revert to SIG_DFL on exec anyway */
@@ -244,6 +251,7 @@ int nc_main(int argc, char **argv)
244 IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);) 251 IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);)
245 IF_NC_EXTRA(bb_perror_msg_and_die("can't execute '%s'", execparam[0]);) 252 IF_NC_EXTRA(bb_perror_msg_and_die("can't execute '%s'", execparam[0]);)
246 } 253 }
254#endif
247 255
248 /* loop copying stdin to cfd, and cfd to stdout */ 256 /* loop copying stdin to cfd, and cfd to stdout */
249 257
diff --git a/networking/ssl_client.c b/networking/ssl_client.c
index 582fb0e71..757745896 100644
--- a/networking/ssl_client.c
+++ b/networking/ssl_client.c
@@ -15,7 +15,12 @@
15//kbuild:lib-$(CONFIG_SSL_CLIENT) += ssl_client.o 15//kbuild:lib-$(CONFIG_SSL_CLIENT) += ssl_client.o
16 16
17//usage:#define ssl_client_trivial_usage 17//usage:#define ssl_client_trivial_usage
18//usage: IF_NOT_PLATFORM_MINGW32(
18//usage: "[-e] -s FD [-r FD] [-n SNI]" 19//usage: "[-e] -s FD [-r FD] [-n SNI]"
20//usage: )
21//usage: IF_PLATFORM_MINGW32(
22//usage: "[-e] -h handle [-n SNI]"
23//usage: )
19//usage:#define ssl_client_full_usage "" 24//usage:#define ssl_client_full_usage ""
20 25
21#include "libbb.h" 26#include "libbb.h"
@@ -26,15 +31,23 @@ int ssl_client_main(int argc UNUSED_PARAM, char **argv)
26 tls_state_t *tls; 31 tls_state_t *tls;
27 const char *sni = NULL; 32 const char *sni = NULL;
28 int opt; 33 int opt;
34#if ENABLE_PLATFORM_MINGW32
35 char *hstr = NULL;
36 HANDLE h;
37#endif
29 38
30 // INIT_G(); 39 // INIT_G();
31 40
32 tls = new_tls_state(); 41 tls = new_tls_state();
42#if !ENABLE_PLATFORM_MINGW32
33 opt = getopt32(argv, "es:+r:+n:", &tls->ofd, &tls->ifd, &sni); 43 opt = getopt32(argv, "es:+r:+n:", &tls->ofd, &tls->ifd, &sni);
34 if (!(opt & (1<<2))) { 44 if (!(opt & (1<<2))) {
35 /* -r N defaults to -s N */ 45 /* -r N defaults to -s N */
36 tls->ifd = tls->ofd; 46 tls->ifd = tls->ofd;
37 } 47 }
48#else
49 opt = getopt32(argv, "eh:n:", &hstr, &sni);
50#endif
38 51
39 if (!(opt & (3<<1))) { 52 if (!(opt & (3<<1))) {
40 if (!argv[1]) 53 if (!argv[1])
@@ -47,6 +60,14 @@ int ssl_client_main(int argc UNUSED_PARAM, char **argv)
47 sni = argv[1]; 60 sni = argv[1];
48 tls->ifd = tls->ofd = create_and_connect_stream_or_die(argv[1], 443); 61 tls->ifd = tls->ofd = create_and_connect_stream_or_die(argv[1], 443);
49 } 62 }
63#if ENABLE_PLATFORM_MINGW32
64 else {
65 if (!hstr || sscanf(hstr, "%p", &h) != 1)
66 bb_error_msg_and_die("invalid handle");
67 init_winsock();
68 tls->ifd = tls->ofd = _open_osfhandle((intptr_t)h, _O_RDWR|_O_BINARY);
69 }
70#endif
50 71
51 tls_handshake(tls, sni); 72 tls_handshake(tls, sni);
52 73
diff --git a/networking/tls.c b/networking/tls.c
index 8d074c058..9f1dd67ec 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -331,7 +331,7 @@ static void dump_tls_record(const void *vp, int len)
331 331
332void FAST_FUNC tls_get_random(void *buf, unsigned len) 332void FAST_FUNC tls_get_random(void *buf, unsigned len)
333{ 333{
334 if (len != open_read_close("/dev/urandom", buf, len)) 334 if (len != MINGW_SPECIAL(open_read_close)("/dev/urandom", buf, len))
335 xfunc_die(); 335 xfunc_die();
336} 336}
337 337
diff --git a/networking/wget.c b/networking/wget.c
index ec3767793..6a64836fb 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -214,6 +214,9 @@ enum {
214 HDR_CONTENT_TYPE = (1<<3), 214 HDR_CONTENT_TYPE = (1<<3),
215 HDR_AUTH = (1<<4) * ENABLE_FEATURE_WGET_AUTHENTICATION, 215 HDR_AUTH = (1<<4) * ENABLE_FEATURE_WGET_AUTHENTICATION,
216 HDR_PROXY_AUTH = (1<<5) * ENABLE_FEATURE_WGET_AUTHENTICATION, 216 HDR_PROXY_AUTH = (1<<5) * ENABLE_FEATURE_WGET_AUTHENTICATION,
217# if ENABLE_PLATFORM_MINGW32
218 HDR_CONTENT_LENGTH = (1<<(4 + 2 * ENABLE_FEATURE_WGET_AUTHENTICATION)),
219# endif
217}; 220};
218static const char wget_user_headers[] ALIGN1 = 221static const char wget_user_headers[] ALIGN1 =
219 "Host:\0" 222 "Host:\0"
@@ -224,6 +227,9 @@ static const char wget_user_headers[] ALIGN1 =
224 "Authorization:\0" 227 "Authorization:\0"
225 "Proxy-Authorization:\0" 228 "Proxy-Authorization:\0"
226# endif 229# endif
230# if ENABLE_PLATFORM_MINGW32
231 "Content-Length:\0"
232# endif
227 ; 233 ;
228# define USR_HEADER_HOST (G.user_headers & HDR_HOST) 234# define USR_HEADER_HOST (G.user_headers & HDR_HOST)
229# define USR_HEADER_USER_AGENT (G.user_headers & HDR_USER_AGENT) 235# define USR_HEADER_USER_AGENT (G.user_headers & HDR_USER_AGENT)
@@ -231,6 +237,7 @@ static const char wget_user_headers[] ALIGN1 =
231# define USR_HEADER_CONTENT_TYPE (G.user_headers & HDR_CONTENT_TYPE) 237# define USR_HEADER_CONTENT_TYPE (G.user_headers & HDR_CONTENT_TYPE)
232# define USR_HEADER_AUTH (G.user_headers & HDR_AUTH) 238# define USR_HEADER_AUTH (G.user_headers & HDR_AUTH)
233# define USR_HEADER_PROXY_AUTH (G.user_headers & HDR_PROXY_AUTH) 239# define USR_HEADER_PROXY_AUTH (G.user_headers & HDR_PROXY_AUTH)
240# define USR_HEADER_CONTENT_LENGTH (G.user_headers & HDR_CONTENT_LENGTH)
234#else /* No long options, no user-headers :( */ 241#else /* No long options, no user-headers :( */
235# define USR_HEADER_HOST 0 242# define USR_HEADER_HOST 0
236# define USR_HEADER_USER_AGENT 0 243# define USR_HEADER_USER_AGENT 0
@@ -238,6 +245,7 @@ static const char wget_user_headers[] ALIGN1 =
238# define USR_HEADER_CONTENT_TYPE 0 245# define USR_HEADER_CONTENT_TYPE 0
239# define USR_HEADER_AUTH 0 246# define USR_HEADER_AUTH 0
240# define USR_HEADER_PROXY_AUTH 0 247# define USR_HEADER_PROXY_AUTH 0
248# define USR_HEADER_CONTENT_LENGTH 0
241#endif 249#endif
242 250
243/* Globals */ 251/* Globals */
@@ -517,6 +525,9 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp)
517 fprintf(stderr, "--> %s%s\n\n", s1, s2); 525 fprintf(stderr, "--> %s%s\n\n", s1, s2);
518 fflush(fp); 526 fflush(fp);
519 log_io("> %s%s", s1, s2); 527 log_io("> %s%s", s1, s2);
528#if ENABLE_PLATFORM_MINGW32
529 fseek(fp, 0L, SEEK_CUR);
530#endif
520 } 531 }
521 532
522 /* Read until "Nxx something" is received */ 533 /* Read until "Nxx something" is received */
@@ -524,6 +535,9 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp)
524 do { 535 do {
525 fgets_trim_sanitize(fp, "%s\n"); 536 fgets_trim_sanitize(fp, "%s\n");
526 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' '); 537 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' ');
538#if ENABLE_PLATFORM_MINGW32
539 fseek(fp, 0L, SEEK_CUR);
540#endif
527 541
528 G.wget_buf[3] = '\0'; 542 G.wget_buf[3] = '\0';
529 result = xatoi_positive(G.wget_buf); 543 result = xatoi_positive(G.wget_buf);
@@ -766,6 +780,7 @@ static int spawn_https_helper_openssl(const char *host, unsigned port)
766#endif 780#endif
767 781
768#if ENABLE_FEATURE_WGET_HTTPS 782#if ENABLE_FEATURE_WGET_HTTPS
783# if !ENABLE_PLATFORM_MINGW32
769static void spawn_ssl_client(const char *host, int network_fd, int flags) 784static void spawn_ssl_client(const char *host, int network_fd, int flags)
770{ 785{
771 int sp[2]; 786 int sp[2];
@@ -820,6 +835,31 @@ static void spawn_ssl_client(const char *host, int network_fd, int flags)
820 close(sp[1]); 835 close(sp[1]);
821 xmove_fd(sp[0], network_fd); 836 xmove_fd(sp[0], network_fd);
822} 837}
838# else
839static void spawn_ssl_client(const char *host, int network_fd, int flags)
840{
841 int fd1;
842 char *servername, *p, *cmd;
843
844 servername = xstrdup(host);
845 p = strrchr(servername, ':');
846 if (p) *p = '\0';
847
848 fflush_all();
849
850 cmd = xasprintf("ssl_client -h %p -n %s%s",
851 (void *)_get_osfhandle(network_fd), servername,
852 flags & TLSLOOP_EXIT_ON_LOCAL_EOF ? " -e" : "");
853
854 if ((fd1=mingw_popen_fd("ssl_client", cmd, "b", -1, NULL)) == -1) {
855 bb_perror_msg_and_die("can't execute ssl_client");
856 }
857
858 free(cmd);
859 free(servername);
860 xmove_fd(fd1, network_fd);
861}
862# endif
823#endif 863#endif
824 864
825#if ENABLE_FEATURE_WGET_FTP 865#if ENABLE_FEATURE_WGET_FTP
@@ -1273,6 +1313,18 @@ static void download_one_url(const char *url)
1273 "Content-Type: application/x-www-form-urlencoded\r\n" 1313 "Content-Type: application/x-www-form-urlencoded\r\n"
1274 ); 1314 );
1275 } 1315 }
1316# if ENABLE_PLATFORM_MINGW32
1317 if (!USR_HEADER_CONTENT_LENGTH)
1318 SENDFMT(sfp, "Content-Length: %u\r\n",
1319 (int)strlen(G.post_data)
1320 );
1321 SENDFMT(sfp,
1322 "\r\n"
1323 "%s",
1324 G.post_data
1325 );
1326 } else
1327# else
1276 SENDFMT(sfp, 1328 SENDFMT(sfp,
1277 "Content-Length: %u\r\n" 1329 "Content-Length: %u\r\n"
1278 "\r\n" 1330 "\r\n"
@@ -1280,6 +1332,7 @@ static void download_one_url(const char *url)
1280 (int) strlen(G.post_data), G.post_data 1332 (int) strlen(G.post_data), G.post_data
1281 ); 1333 );
1282 } else 1334 } else
1335# endif
1283#endif 1336#endif
1284 { 1337 {
1285 SENDFMT(sfp, "\r\n"); 1338 SENDFMT(sfp, "\r\n");
diff --git a/procps/free.c b/procps/free.c
index d0c849b79..90b4af702 100644
--- a/procps/free.c
+++ b/procps/free.c
@@ -77,6 +77,7 @@ static const char *scale(struct globals *g, unsigned long d)
77 return make_human_readable_str(d, g->mem_unit, G_unit); 77 return make_human_readable_str(d, g->mem_unit, G_unit);
78} 78}
79 79
80#if !ENABLE_PLATFORM_MINGW32
80/* NOINLINE reduces main() stack usage, which makes code smaller (on x86 at least) */ 81/* NOINLINE reduces main() stack usage, which makes code smaller (on x86 at least) */
81static NOINLINE unsigned int parse_meminfo(struct globals *g) 82static NOINLINE unsigned int parse_meminfo(struct globals *g)
82{ 83{
@@ -103,6 +104,14 @@ static NOINLINE unsigned int parse_meminfo(struct globals *g)
103 104
104 return seen_cached_and_available_and_reclaimable == 0; 105 return seen_cached_and_available_and_reclaimable == 0;
105} 106}
107#else
108static unsigned int parse_meminfo(struct globals *g)
109{
110 g->cached_kb = g->available_kb = g->reclaimable_kb = 0;
111
112 return 1;
113}
114#endif
106 115
107int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 116int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
108int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM)) 117int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM))
diff --git a/procps/iostat.c b/procps/iostat.c
index d3157757f..2feb02456 100644
--- a/procps/iostat.c
+++ b/procps/iostat.c
@@ -28,7 +28,7 @@
28#if 1 28#if 1
29typedef unsigned long long cputime_t; 29typedef unsigned long long cputime_t;
30typedef long long icputime_t; 30typedef long long icputime_t;
31# define FMT_DATA "ll" 31# define FMT_DATA LL_FMT
32# define CPUTIME_MAX (~0ULL) 32# define CPUTIME_MAX (~0ULL)
33#else 33#else
34typedef unsigned long cputime_t; 34typedef unsigned long cputime_t;
diff --git a/procps/kill.c b/procps/kill.c
index d4be18dd8..6be11296e 100644
--- a/procps/kill.c
+++ b/procps/kill.c
@@ -207,6 +207,7 @@ int kill_main(int argc UNUSED_PARAM, char **argv)
207 do_it_now: 207 do_it_now:
208 pid = getpid(); 208 pid = getpid();
209 209
210#if ENABLE_KILLALL5
210 if (is_killall5) { 211 if (is_killall5) {
211 pid_t sid; 212 pid_t sid;
212 procps_status_t* p = NULL; 213 procps_status_t* p = NULL;
@@ -264,6 +265,7 @@ int kill_main(int argc UNUSED_PARAM, char **argv)
264 kill(-1, SIGCONT); 265 kill(-1, SIGCONT);
265 return errors; 266 return errors;
266 } 267 }
268#endif
267 269
268#if ENABLE_KILL || ENABLE_KILLALL 270#if ENABLE_KILL || ENABLE_KILLALL
269 /* Pid or name is required for kill/killall */ 271 /* Pid or name is required for kill/killall */
diff --git a/procps/mpstat.c b/procps/mpstat.c
index 795b4ccb7..d8158ef8f 100644
--- a/procps/mpstat.c
+++ b/procps/mpstat.c
@@ -49,7 +49,7 @@
49#if 1 49#if 1
50typedef unsigned long long data_t; 50typedef unsigned long long data_t;
51typedef long long idata_t; 51typedef long long idata_t;
52#define FMT_DATA "ll" 52#define FMT_DATA LL_FMT
53#define DATA_MAX ULLONG_MAX 53#define DATA_MAX ULLONG_MAX
54#else 54#else
55typedef unsigned long data_t; 55typedef unsigned long data_t;
diff --git a/procps/pgrep.c b/procps/pgrep.c
index 04ae92a67..9773a72c4 100644
--- a/procps/pgrep.c
+++ b/procps/pgrep.c
@@ -30,31 +30,49 @@
30//kbuild:lib-$(CONFIG_PKILL) += pgrep.o 30//kbuild:lib-$(CONFIG_PKILL) += pgrep.o
31 31
32//usage:#define pgrep_trivial_usage 32//usage:#define pgrep_trivial_usage
33//usage: IF_NOT_PLATFORM_MINGW32(
33//usage: "[-flanovx] [-s SID|-P PPID|PATTERN]" 34//usage: "[-flanovx] [-s SID|-P PPID|PATTERN]"
35//usage: )
36//usage: IF_PLATFORM_MINGW32(
37//usage: "[-lvx] [-P PPID|PATTERN]"
38//usage: )
34//usage:#define pgrep_full_usage "\n\n" 39//usage:#define pgrep_full_usage "\n\n"
35//usage: "Display process(es) selected by regex PATTERN\n" 40//usage: "Display process(es) selected by regex PATTERN\n"
36//usage: "\n -l Show command name too" 41//usage: "\n -l Show command name too"
42//usage: IF_NOT_PLATFORM_MINGW32(
37//usage: "\n -a Show command line too" 43//usage: "\n -a Show command line too"
38//usage: "\n -f Match against entire command line" 44//usage: "\n -f Match against entire command line"
39//usage: "\n -n Show the newest process only" 45//usage: "\n -n Show the newest process only"
40//usage: "\n -o Show the oldest process only" 46//usage: "\n -o Show the oldest process only"
47//usage: )
41//usage: "\n -v Negate the match" 48//usage: "\n -v Negate the match"
42//usage: "\n -x Match whole name (not substring)" 49//usage: "\n -x Match whole name (not substring)"
50//usage: IF_NOT_PLATFORM_MINGW32(
43//usage: "\n -s Match session ID (0 for current)" 51//usage: "\n -s Match session ID (0 for current)"
52//usage: )
44//usage: "\n -P Match parent process ID" 53//usage: "\n -P Match parent process ID"
45//usage: 54//usage:
46//usage:#define pkill_trivial_usage 55//usage:#define pkill_trivial_usage
56//usage: IF_NOT_PLATFORM_MINGW32(
47//usage: "[-l|-SIGNAL] [-xfvnoe] [-s SID|-P PPID|PATTERN]" 57//usage: "[-l|-SIGNAL] [-xfvnoe] [-s SID|-P PPID|PATTERN]"
58//usage: )
59//usage: IF_PLATFORM_MINGW32(
60//usage: "[-l|-SIGNAL] [-xve] [-P PPID|PATTERN]"
61//usage: )
48//usage:#define pkill_full_usage "\n\n" 62//usage:#define pkill_full_usage "\n\n"
49//usage: "Send signal to processes selected by regex PATTERN\n" 63//usage: "Send signal to processes selected by regex PATTERN\n"
50//usage: "\n -l List all signals" 64//usage: "\n -l List all signals"
51//usage: "\n -x Match whole name (not substring)" 65//usage: "\n -x Match whole name (not substring)"
66//usage: IF_NOT_PLATFORM_MINGW32(
52//usage: "\n -f Match against entire command line" 67//usage: "\n -f Match against entire command line"
53//usage: "\n -s SID Match session ID (0 for current)" 68//usage: "\n -s SID Match session ID (0 for current)"
69//usage: )
54//usage: "\n -P PPID Match parent process ID" 70//usage: "\n -P PPID Match parent process ID"
55//usage: "\n -v Negate the match" 71//usage: "\n -v Negate the match"
72//usage: IF_NOT_PLATFORM_MINGW32(
56//usage: "\n -n Signal the newest process only" 73//usage: "\n -n Signal the newest process only"
57//usage: "\n -o Signal the oldest process only" 74//usage: "\n -o Signal the oldest process only"
75//usage: )
58//usage: "\n -e Display name and PID of the process being killed" 76//usage: "\n -e Display name and PID of the process being killed"
59 77
60#include "libbb.h" 78#include "libbb.h"
@@ -68,25 +86,47 @@ enum {
68 /* "vlafxones:+P:+" */ 86 /* "vlafxones:+P:+" */
69 OPTBIT_V = 0, /* must be first, we need OPT_INVERT = 0/1 */ 87 OPTBIT_V = 0, /* must be first, we need OPT_INVERT = 0/1 */
70 OPTBIT_L, 88 OPTBIT_L,
89#if !ENABLE_PLATFORM_MINGW32
71 OPTBIT_A, 90 OPTBIT_A,
72 OPTBIT_F, 91 OPTBIT_F,
92#else
93#define OPTBIT_A OPTBIT_L
94#endif
73 OPTBIT_X, 95 OPTBIT_X,
96#if !ENABLE_PLATFORM_MINGW32
74 OPTBIT_O, 97 OPTBIT_O,
75 OPTBIT_N, 98 OPTBIT_N,
99#endif
76 OPTBIT_E, /* should be pkill-only, do we care? */ 100 OPTBIT_E, /* should be pkill-only, do we care? */
101#if !ENABLE_PLATFORM_MINGW32
77 OPTBIT_S, 102 OPTBIT_S,
103#endif
78 OPTBIT_P, 104 OPTBIT_P,
79}; 105};
80 106
81#define OPT_INVERT (opt & (1 << OPTBIT_V)) 107#define OPT_INVERT (opt & (1 << OPTBIT_V))
82#define OPT_LIST (opt & (1 << OPTBIT_L)) 108#define OPT_LIST (opt & (1 << OPTBIT_L))
109#if ENABLE_PLATFORM_MINGW32
110#define OPT_LISTFULL (0)
111#define OPT_FULL (0)
112#else
83#define OPT_LISTFULL (opt & (1 << OPTBIT_A)) 113#define OPT_LISTFULL (opt & (1 << OPTBIT_A))
84#define OPT_FULL (opt & (1 << OPTBIT_F)) 114#define OPT_FULL (opt & (1 << OPTBIT_F))
115#endif
85#define OPT_ANCHOR (opt & (1 << OPTBIT_X)) 116#define OPT_ANCHOR (opt & (1 << OPTBIT_X))
117#if ENABLE_PLATFORM_MINGW32
118#define OPT_FIRST (0)
119#define OPT_LAST (0)
120#else
86#define OPT_FIRST (opt & (1 << OPTBIT_O)) 121#define OPT_FIRST (opt & (1 << OPTBIT_O))
87#define OPT_LAST (opt & (1 << OPTBIT_N)) 122#define OPT_LAST (opt & (1 << OPTBIT_N))
123#endif
88#define OPT_ECHO (opt & (1 << OPTBIT_E)) 124#define OPT_ECHO (opt & (1 << OPTBIT_E))
125#if ENABLE_PLATFORM_MINGW32
126#define OPT_SID (0)
127#else
89#define OPT_SID (opt & (1 << OPTBIT_S)) 128#define OPT_SID (opt & (1 << OPTBIT_S))
129#endif
90#define OPT_PPID (opt & (1 << OPTBIT_P)) 130#define OPT_PPID (opt & (1 << OPTBIT_P))
91 131
92static void act(unsigned pid, char *cmd, int signo) 132static void act(unsigned pid, char *cmd, int signo)
@@ -112,7 +152,12 @@ int pgrep_main(int argc UNUSED_PARAM, char **argv)
112 unsigned opt; 152 unsigned opt;
113 int scan_mask; 153 int scan_mask;
114 int matched_pid; 154 int matched_pid;
155#if ENABLE_PLATFORM_MINGW32
156 const int sid2match = -1;
157 int ppid2match;
158#else
115 int sid2match, ppid2match; 159 int sid2match, ppid2match;
160#endif
116 char *cmd_last; 161 char *cmd_last;
117 procps_status_t *proc; 162 procps_status_t *proc;
118 /* These are initialized to 0 */ 163 /* These are initialized to 0 */
@@ -137,8 +182,12 @@ int pgrep_main(int argc UNUSED_PARAM, char **argv)
137 182
138 /* Parse remaining options */ 183 /* Parse remaining options */
139 ppid2match = -1; 184 ppid2match = -1;
185#if !ENABLE_PLATFORM_MINGW32
140 sid2match = -1; 186 sid2match = -1;
141 opt = getopt32(argv, "vlafxones:+P:+", &sid2match, &ppid2match); 187 opt = getopt32(argv, "vlafxones:+P:+", &sid2match, &ppid2match);
188#else
189 opt = getopt32(argv, "vlxeP:+", &ppid2match);
190#endif
142 argv += optind; 191 argv += optind;
143 192
144 if (pkill && OPT_LIST) { /* -l: print the whole signal list */ 193 if (pkill && OPT_LIST) { /* -l: print the whole signal list */
@@ -147,8 +196,10 @@ int pgrep_main(int argc UNUSED_PARAM, char **argv)
147 } 196 }
148 197
149 pid = getpid(); 198 pid = getpid();
199#if !ENABLE_PLATFORM_MINGW32
150 if (sid2match == 0) 200 if (sid2match == 0)
151 sid2match = getsid(pid); 201 sid2match = getsid(pid);
202#endif
152 203
153 scan_mask = PSSCAN_COMM | PSSCAN_ARGV0; 204 scan_mask = PSSCAN_COMM | PSSCAN_ARGV0;
154 if (OPT_FULL) 205 if (OPT_FULL)
@@ -180,6 +231,9 @@ int pgrep_main(int argc UNUSED_PARAM, char **argv)
180 } 231 }
181 232
182 cmdlen = -1; 233 cmdlen = -1;
234#if ENABLE_PLATFORM_MINGW32
235 cmd = proc->comm;
236#else
183 cmd = proc->argv0; 237 cmd = proc->argv0;
184 if (!cmd) { 238 if (!cmd) {
185 cmd = proc->comm; 239 cmd = proc->comm;
@@ -199,6 +253,7 @@ int pgrep_main(int argc UNUSED_PARAM, char **argv)
199 cmd[i] = ' '; 253 cmd[i] = ' ';
200 } 254 }
201 } 255 }
256#endif
202 257
203 if (OPT_INVERT) { 258 if (OPT_INVERT) {
204 /* "pgrep -v -P1 firefox" means "not (ppid=1 AND name=firefox)" 259 /* "pgrep -v -P1 firefox" means "not (ppid=1 AND name=firefox)"
diff --git a/procps/ps.c b/procps/ps.c
index 5b521aebd..329576eb8 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -120,7 +120,7 @@ enum { MAX_WIDTH = 2*1024 };
120#if ENABLE_FEATURE_PS_TIME || ENABLE_FEATURE_PS_LONG 120#if ENABLE_FEATURE_PS_TIME || ENABLE_FEATURE_PS_LONG
121static unsigned long get_uptime(void) 121static unsigned long get_uptime(void)
122{ 122{
123#ifdef __linux__ 123#if defined __linux__ || ENABLE_PLATFORM_MINGW32
124 struct sysinfo info; 124 struct sysinfo info;
125 if (sysinfo(&info) < 0) 125 if (sysinfo(&info) < 0)
126 return 0; 126 return 0;
@@ -237,10 +237,12 @@ static void func_comm(char *buf, int size, const procps_status_t *ps)
237 safe_strncpy(buf, ps->comm, size+1); 237 safe_strncpy(buf, ps->comm, size+1);
238} 238}
239 239
240#if !ENABLE_PLATFORM_MINGW32
240static void func_state(char *buf, int size, const procps_status_t *ps) 241static void func_state(char *buf, int size, const procps_status_t *ps)
241{ 242{
242 safe_strncpy(buf, ps->state, size+1); 243 safe_strncpy(buf, ps->state, size+1);
243} 244}
245#endif
244 246
245static void func_args(char *buf, int size, const procps_status_t *ps) 247static void func_args(char *buf, int size, const procps_status_t *ps)
246{ 248{
@@ -257,6 +259,7 @@ static void func_ppid(char *buf, int size, const procps_status_t *ps)
257 sprintf(buf, "%*u", size, ps->ppid); 259 sprintf(buf, "%*u", size, ps->ppid);
258} 260}
259 261
262#if !ENABLE_PLATFORM_MINGW32
260static void func_pgid(char *buf, int size, const procps_status_t *ps) 263static void func_pgid(char *buf, int size, const procps_status_t *ps)
261{ 264{
262 sprintf(buf, "%*u", size, ps->pgid); 265 sprintf(buf, "%*u", size, ps->pgid);
@@ -293,6 +296,7 @@ static void func_tty(char *buf, int size, const procps_status_t *ps)
293 if (ps->tty_major) /* tty field of "0" means "no tty" */ 296 if (ps->tty_major) /* tty field of "0" means "no tty" */
294 snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor); 297 snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor);
295} 298}
299#endif
296 300
297#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS 301#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
298static void func_rgroup(char *buf, int size, const procps_status_t *ps) 302static void func_rgroup(char *buf, int size, const procps_status_t *ps)
@@ -379,11 +383,17 @@ static const ps_out_t out_spec[] ALIGN_PTR = {
379/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */ 383/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */
380 { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID }, 384 { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID },
381 { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID }, 385 { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID },
386#if ENABLE_PLATFORM_MINGW32
387 { COMM_LEN , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM },
388#else
382 { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM }, 389 { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM },
390#endif
383 { MAX_WIDTH , "args" ,"COMMAND",func_args ,PSSCAN_COMM }, 391 { MAX_WIDTH , "args" ,"COMMAND",func_args ,PSSCAN_COMM },
384 { 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID }, 392 { 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID },
385 { 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID }, 393 { 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID },
394#if !ENABLE_PLATFORM_MINGW32
386 { 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID }, 395 { 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID },
396#endif
387#if ENABLE_FEATURE_PS_TIME 397#if ENABLE_FEATURE_PS_TIME
388 { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME }, 398 { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME },
389#endif 399#endif
@@ -396,12 +406,14 @@ static const ps_out_t out_spec[] ALIGN_PTR = {
396#if ENABLE_FEATURE_PS_TIME 406#if ENABLE_FEATURE_PS_TIME
397 { 5 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME }, 407 { 5 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME },
398#endif 408#endif
409#if !ENABLE_PLATFORM_MINGW32
399 { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, 410 { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY },
400 { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ }, 411 { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ },
401/* Not mandated, but useful: */ 412/* Not mandated, but useful: */
402 { 5 , "sid" ,"SID" ,func_sid ,PSSCAN_SID }, 413 { 5 , "sid" ,"SID" ,func_sid ,PSSCAN_SID },
403 { 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE }, 414 { 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE },
404 { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS }, 415 { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS },
416#endif
405#if ENABLE_SELINUX 417#if ENABLE_SELINUX
406 { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT }, 418 { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT },
407#endif 419#endif
@@ -544,6 +556,8 @@ static void format_process(const procps_status_t *ps)
544#if ENABLE_SELINUX 556#if ENABLE_SELINUX
545# define SELINUX_O_PREFIX "label," 557# define SELINUX_O_PREFIX "label,"
546# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") 558# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args")
559#elif ENABLE_PLATFORM_MINGW32
560# define DEFAULT_O_STR ("pid,ppid,user" IF_FEATURE_PS_TIME(",time,etime") ",args")
547#else 561#else
548# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") 562# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args")
549#endif 563#endif
diff --git a/procps/smemcap.c b/procps/smemcap.c
index a2231788b..6839c9de0 100644
--- a/procps/smemcap.c
+++ b/procps/smemcap.c
@@ -19,6 +19,7 @@
19//kbuild:lib-$(CONFIG_SMEMCAP) += smemcap.o 19//kbuild:lib-$(CONFIG_SMEMCAP) += smemcap.o
20 20
21#include "libbb.h" 21#include "libbb.h"
22#define BB_ARCHIVE_PUBLIC
22#include "bb_archive.h" 23#include "bb_archive.h"
23 24
24struct fileblock { 25struct fileblock {
diff --git a/procps/watch.c b/procps/watch.c
index 05b72723c..d7c3ad55e 100644
--- a/procps/watch.c
+++ b/procps/watch.c
@@ -71,9 +71,16 @@ int watch_main(int argc UNUSED_PARAM, char **argv)
71 71
72 // watch from both procps 2.x and 3.x does concatenation. Example: 72 // watch from both procps 2.x and 3.x does concatenation. Example:
73 // watch ls -l "a /tmp" "2>&1" - ls won't see "a /tmp" as one param 73 // watch ls -l "a /tmp" "2>&1" - ls won't see "a /tmp" as one param
74#if ENABLE_PLATFORM_MINGW32
75 cmd = NULL;
76 do {
77 cmd = xappendword(cmd, *argv);
78 } while (*++argv);
79#else
74 cmd = *argv; 80 cmd = *argv;
75 while (*++argv) 81 while (*++argv)
76 cmd = xasprintf("%s %s", cmd, *argv); // leaks cmd 82 cmd = xasprintf("%s %s", cmd, *argv); // leaks cmd
83#endif
77 84
78 period = parse_duration_str(period_str); 85 period = parse_duration_str(period_str);
79 width = (unsigned)-1; // make sure first time new_width != width 86 width = (unsigned)-1; // make sure first time new_width != width
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 5b4db5c2c..b61ff8b42 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -52,25 +52,25 @@ endef
52# as-option 52# as-option
53# Usage: cflags-y += $(call as-option, -Wa$(comma)-isa=foo,) 53# Usage: cflags-y += $(call as-option, -Wa$(comma)-isa=foo,)
54 54
55as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \ 55as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o - \
56 -xassembler /dev/null > /dev/null 2>&1; then echo "$(1)"; \ 56 -xassembler - </dev/null > /dev/null 2>&1; then echo "$(1)"; \
57 else echo "$(2)"; fi ;) 57 else echo "$(2)"; fi ;)
58 58
59# cc-option 59# cc-option
60# Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586) 60# Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586)
61 61
62cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \ 62cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o - -xc - </dev/null \
63 > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) 63 > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
64 64
65# hostcc-option 65# hostcc-option
66# Usage: hostcflags-y += $(call hostcc-option, -march=winchip-c6, -march=i586) 66# Usage: hostcflags-y += $(call hostcc-option, -march=winchip-c6, -march=i586)
67 67
68hostcc-option = $(shell if $(HOSTCC) $(HOSTCFLAGS) $(1) -S -o /dev/null -xc /dev/null \ 68hostcc-option = $(shell if $(HOSTCC) $(HOSTCFLAGS) $(1) -S -o - -xc - </dev/null \
69 > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) 69 > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
70 70
71# cc-option-yn 71# cc-option-yn
72# Usage: flag := $(call cc-option-yn, -march=winchip-c6) 72# Usage: flag := $(call cc-option-yn, -march=winchip-c6)
73cc-option-yn = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \ 73cc-option-yn = $(shell if $(CC) $(CFLAGS) $(1) -S -o - -xc - </dev/null \
74 > /dev/null 2>&1; then echo "y"; else echo "n"; fi;) 74 > /dev/null 2>&1; then echo "y"; else echo "n"; fi;)
75 75
76# cc-option-align 76# cc-option-align
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 5eac45f91..cd5592b34 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -254,11 +254,28 @@ $(sort $(subdir-obj-y)): $(subdir-ym) ;
254# 254#
255ifdef builtin-target 255ifdef builtin-target
256quiet_cmd_link_o_target = LD $@ 256quiet_cmd_link_o_target = LD $@
257ifeq ($(CONFIG_PLATFORM_POSIX),y)
257# If the list of objects to link is empty, just create an empty built-in.o 258# If the list of objects to link is empty, just create an empty built-in.o
258# -nostdlib is added to make "make LD=gcc ..." work (some people use that) 259# -nostdlib is added to make "make LD=gcc ..." work (some people use that)
259cmd_link_o_target = $(if $(strip $(obj-y)),\ 260cmd_link_o_target = $(if $(strip $(obj-y)),\
260 $(LD) -nostdlib $(ld_flags) -r -o $@ $(filter $(obj-y), $^),\ 261 $(LD) -nostdlib $(ld_flags) -r -o $@ $(filter $(obj-y), $^),\
261 rm -f $@; $(AR) rcs $@) 262 rm -f $@; $(AR) rcs $@)
263else
264# In default builds of busybox-w32 all builtin targets have either
265# zero or one object files. In the latter case copy the object to
266# the target. This avoids the need to use the linker: the llvm
267# linker doesn't support the -r option.
268ifeq ($(words $(obj-y)),0)
269cmd_link_o_target = rm -f $@; $(AR) rcs $@
270else
271ifeq ($(words $(obj-y)),1)
272cmd_link_o_target = cp $(obj-y) $@
273else
274cmd_link_o_target = \
275 $(LD) -nostdlib $(ld_flags) -r -o $@ $(filter $(obj-y), $^))
276endif
277endif
278endif
262 279
263$(builtin-target): $(obj-y) FORCE 280$(builtin-target): $(obj-y) FORCE
264 $(call if_changed,link_o_target) 281 $(call if_changed,link_o_target)
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
index 2e628508d..7b380460a 100644
--- a/scripts/Makefile.host
+++ b/scripts/Makefile.host
@@ -92,13 +92,32 @@ endif
92hostc_flags = -Wp,-MD,$(depfile) $(__hostc_flags) 92hostc_flags = -Wp,-MD,$(depfile) $(__hostc_flags)
93hostcxx_flags = -Wp,-MD,$(depfile) $(__hostcxx_flags) 93hostcxx_flags = -Wp,-MD,$(depfile) $(__hostcxx_flags)
94 94
95# Programs built for use on the host are defined without a suffix
96# (usually '.exe' on Windows). Rather than adjust all the makefiles
97# force a suffix of '.' if the host platform is mingw32. This will
98# result in binaries with no suffix.
99#
100# It's not a big deal if this doesn't work. MSYS2 doesn't need it
101# and the downside is just that the programs will be rebuilt more
102# often than really needed.
103#
104host_target := $(shell $(HOSTCC) -v 2>&1 | grep ^Target:)
105host_platform := $(word 4,$(subst -, ,$(host_target)))
106dot :=
107ifeq ($(host_platform),mingw32)
108dot := .
109endif
110ifeq ($(host_platform),windows)
111dot := .
112endif
113
95##### 114#####
96# Compile programs on the host 115# Compile programs on the host
97 116
98# Create executable from a single .c file 117# Create executable from a single .c file
99# host-csingle -> Executable 118# host-csingle -> Executable
100quiet_cmd_host-csingle = HOSTCC $@ 119quiet_cmd_host-csingle = HOSTCC $@
101 cmd_host-csingle = $(HOSTCC) $(hostc_flags) -o $@ $< \ 120 cmd_host-csingle = $(HOSTCC) $(hostc_flags) -o $@$(dot) $< \
102 $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) 121 $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
103$(host-csingle): %: %.c FORCE 122$(host-csingle): %: %.c FORCE
104 $(call if_changed_dep,host-csingle) 123 $(call if_changed_dep,host-csingle)
@@ -106,7 +125,7 @@ $(host-csingle): %: %.c FORCE
106# Link an executable based on list of .o files, all plain c 125# Link an executable based on list of .o files, all plain c
107# host-cmulti -> executable 126# host-cmulti -> executable
108quiet_cmd_host-cmulti = HOSTLD $@ 127quiet_cmd_host-cmulti = HOSTLD $@
109 cmd_host-cmulti = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \ 128 cmd_host-cmulti = $(HOSTCC) $(HOSTLDFLAGS) -o $@$(dot) \
110 $(addprefix $(obj)/,$($(@F)-objs)) \ 129 $(addprefix $(obj)/,$($(@F)-objs)) \
111 $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) 130 $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
112$(host-cmulti): %: $(host-cobjs) $(host-cshlib) FORCE 131$(host-cmulti): %: $(host-cobjs) $(host-cshlib) FORCE
diff --git a/scripts/basic/.gitignore b/scripts/basic/.gitignore
index d91e941a4..3d20e4f15 100644
--- a/scripts/basic/.gitignore
+++ b/scripts/basic/.gitignore
@@ -2,3 +2,6 @@ hash
2fixdep 2fixdep
3docproc 3docproc
4split-include 4split-include
5/docproc.exe
6/fixdep.exe
7/split-include.exe
diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c
index 8828901a1..c488cd53e 100644
--- a/scripts/basic/docproc.c
+++ b/scripts/basic/docproc.c
@@ -38,7 +38,9 @@
38#include <unistd.h> 38#include <unistd.h>
39#include <limits.h> 39#include <limits.h>
40#include <sys/types.h> 40#include <sys/types.h>
41#ifndef __MINGW32__
41#include <sys/wait.h> 42#include <sys/wait.h>
43#endif
42//bbox disabled: #include <alloca.h> 44//bbox disabled: #include <alloca.h>
43 45
44/* exitstatus is used to keep track of any failing calls to kernel-doc, 46/* exitstatus is used to keep track of any failing calls to kernel-doc,
@@ -78,12 +80,24 @@ void usage (void)
78 */ 80 */
79void exec_kernel_doc(char **svec) 81void exec_kernel_doc(char **svec)
80{ 82{
83#ifndef __MINGW32__
81 pid_t pid; 84 pid_t pid;
82 int ret; 85 int ret;
86#endif
83 char *real_filename; 87 char *real_filename;
84 int rflen; 88 int rflen;
85 89
86 /* Make sure output generated so far are flushed */ 90 /* Make sure output generated so far are flushed */
91#ifdef __MINGW32__
92 fflush(stdout);
93 rflen = strlen(getenv("SRCTREE"));
94 rflen += strlen(KERNELDOCPATH KERNELDOC);
95 real_filename = alloca(rflen + 1);
96 strcpy(real_filename, getenv("SRCTREE"));
97 strcat(real_filename, KERNELDOCPATH KERNELDOC);
98 fprintf(stderr, "NOTIMPL: exec %s\n", real_filename);
99 exit(1);
100#else
87 fflush(stdout); 101 fflush(stdout);
88 switch(pid=fork()) { 102 switch(pid=fork()) {
89 case -1: 103 case -1:
@@ -106,6 +120,7 @@ void exec_kernel_doc(char **svec)
106 exitstatus |= WEXITSTATUS(ret); 120 exitstatus |= WEXITSTATUS(ret);
107 else 121 else
108 exitstatus = 0xff; 122 exitstatus = 0xff;
123#endif
109} 124}
110 125
111/* Types used to create list of all exported symbols in a number of files */ 126/* Types used to create list of all exported symbols in a number of files */
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index 071c3b407..47a0cee07 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -104,7 +104,9 @@
104 104
105#include <sys/types.h> 105#include <sys/types.h>
106#include <sys/stat.h> 106#include <sys/stat.h>
107#ifndef __MINGW32__
107#include <sys/mman.h> 108#include <sys/mman.h>
109#endif
108#include <errno.h> 110#include <errno.h>
109#include <unistd.h> 111#include <unistd.h>
110#include <fcntl.h> 112#include <fcntl.h>
@@ -113,7 +115,9 @@
113#include <stdio.h> 115#include <stdio.h>
114#include <limits.h> 116#include <limits.h>
115#include <ctype.h> 117#include <ctype.h>
118#ifndef __MINGW32__
116#include <arpa/inet.h> 119#include <arpa/inet.h>
120#endif
117//bbox disabled: #include <alloca.h> 121//bbox disabled: #include <alloca.h>
118 122
119/* bbox: not needed 123/* bbox: not needed
@@ -123,6 +127,57 @@
123#define INT_FIG_ ntohl(0x4649475f) 127#define INT_FIG_ ntohl(0x4649475f)
124*/ 128*/
125 129
130#ifndef O_BINARY
131#define O_BINARY 0
132#endif
133
134#ifdef __MINGW32__
135#define UNUSED __attribute__ ((__unused__))
136
137/* Workaround specifically for fixdep */
138#define PROT_READ 0
139#define MAP_PRIVATE 0
140void *mmap(void *start UNUSED, size_t size, int prot UNUSED,
141 int flags UNUSED, int fd, off_t offset UNUSED)
142{
143 void *p;
144 void *curP;
145 ssize_t readB;
146
147 p = malloc(size);
148 if (!p)
149 return (void*)((long)-1);
150
151 curP = p;
152
153 while (size > 0)
154 {
155 readB = read(fd, curP, size);
156
157 if (readB == 0)
158 {
159 /* EOF reached */
160 break;
161 }
162 else if (readB < 0)
163 {
164 perror("fixdep: read config");
165 free(p);
166 return (void*)((long)-1);
167 }
168
169 size -= readB;
170 curP += readB;
171 }
172
173 return p;
174}
175void munmap(void *p, size_t size UNUSED)
176{
177 free(p);
178}
179#endif
180
126char *target; 181char *target;
127char *depfile; 182char *depfile;
128char *cmdline; 183char *cmdline;
@@ -287,7 +342,7 @@ void do_config_file(char *filename)
287 int fd; 342 int fd;
288 void *map; 343 void *map;
289 344
290 fd = open(filename, O_RDONLY); 345 fd = open(filename, O_RDONLY | O_BINARY);
291 if (fd < 0) { 346 if (fd < 0) {
292 fprintf(stderr, "fixdep: "); 347 fprintf(stderr, "fixdep: ");
293 perror(filename); 348 perror(filename);
@@ -302,7 +357,7 @@ void do_config_file(char *filename)
302 return; 357 return;
303 } 358 }
304 map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 359 map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
305 if ((long) map == -1) { 360 if ((intptr_t) map == -1) {
306 perror("fixdep: mmap"); 361 perror("fixdep: mmap");
307 close(fd); 362 close(fd);
308 return; 363 return;
@@ -338,8 +393,9 @@ void parse_dep_file(void *map, size_t len)
338 m++; 393 m++;
339 p = m; 394 p = m;
340 while (p < end && *p != ' ') p++; 395 while (p < end && *p != ' ') p++;
396 if (p == m) break;
341 if (p == end) { 397 if (p == end) {
342 do p--; while (!isalnum((unsigned char)*p)); 398 do p--; while (p != m && !isalnum((unsigned char)*p));
343 p++; 399 p++;
344 } 400 }
345 if (p < m) { 401 if (p < m) {
@@ -354,6 +410,7 @@ void parse_dep_file(void *map, size_t len)
354 printf(" %s \\\n", s); 410 printf(" %s \\\n", s);
355 do_config_file(s); 411 do_config_file(s);
356 } 412 }
413 if (p == end) break;
357 m = p + 1; 414 m = p + 1;
358 } 415 }
359 printf("\n%s: $(deps_%s)\n\n", target, target); 416 printf("\n%s: $(deps_%s)\n\n", target, target);
@@ -366,7 +423,7 @@ void print_deps(void)
366 int fd; 423 int fd;
367 void *map; 424 void *map;
368 425
369 fd = open(depfile, O_RDONLY); 426 fd = open(depfile, O_RDONLY | O_BINARY);
370 if (fd < 0) { 427 if (fd < 0) {
371 fprintf(stderr, "fixdep: "); 428 fprintf(stderr, "fixdep: ");
372 perror(depfile); 429 perror(depfile);
@@ -382,7 +439,7 @@ void print_deps(void)
382 return; 439 return;
383 } 440 }
384 map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 441 map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
385 if ((long) map == -1) { 442 if ((intptr_t) map == -1) {
386 perror("fixdep: mmap"); 443 perror("fixdep: mmap");
387 close(fd); 444 close(fd);
388 return; 445 return;
diff --git a/scripts/basic/split-include.c b/scripts/basic/split-include.c
index 6ef29195e..a85ede8ef 100644
--- a/scripts/basic/split-include.c
+++ b/scripts/basic/split-include.c
@@ -39,8 +39,6 @@
39 exit(1); \ 39 exit(1); \
40 } 40 }
41 41
42
43
44int main(int argc, const char * argv []) 42int main(int argc, const char * argv [])
45{ 43{
46 const char * str_my_name; 44 const char * str_my_name;
@@ -89,7 +87,11 @@ int main(int argc, const char * argv [])
89 /* Make output directory if needed. */ 87 /* Make output directory if needed. */
90 if (stat(str_dir_config, &stat_buf) != 0) 88 if (stat(str_dir_config, &stat_buf) != 0)
91 { 89 {
90#ifdef __MINGW32__
91 if (mkdir(str_dir_config) != 0)
92#else
92 if (mkdir(str_dir_config, 0755) != 0) 93 if (mkdir(str_dir_config, 0755) != 0)
94#endif
93 ERROR_EXIT(str_dir_config); 95 ERROR_EXIT(str_dir_config);
94 } 96 }
95 97
@@ -149,7 +151,12 @@ int main(int argc, const char * argv [])
149 { 151 {
150 ptarget[islash] = '\0'; 152 ptarget[islash] = '\0';
151 if (stat(ptarget, &stat_buf) != 0 153 if (stat(ptarget, &stat_buf) != 0
152 && mkdir(ptarget, 0755) != 0) 154#ifdef __MINGW32__
155 && mkdir(ptarget) != 0
156#else
157 && mkdir(ptarget, 0755) != 0
158#endif
159 )
153 ERROR_EXIT( ptarget ); 160 ERROR_EXIT( ptarget );
154 ptarget[islash] = '/'; 161 ptarget[islash] = '/';
155 } 162 }
@@ -190,13 +197,21 @@ int main(int argc, const char * argv [])
190 * So by having an initial \n, strstr will find exact matches. 197 * So by having an initial \n, strstr will find exact matches.
191 */ 198 */
192 199
200#ifdef __MINGW32__
201 fp_find = popen("find . -type f -name \"*.h\" -print", "r");
202#else
193 fp_find = popen("find * -type f -name \"*.h\" -print", "r"); 203 fp_find = popen("find * -type f -name \"*.h\" -print", "r");
204#endif
194 if (fp_find == 0) 205 if (fp_find == 0)
195 ERROR_EXIT( "find" ); 206 ERROR_EXIT( "find" );
196 207
197 line[0] = '\n'; 208 line[0] = '\n';
198 while (fgets(line+1, buffer_size, fp_find)) 209 while (fgets(line+1, buffer_size, fp_find))
199 { 210 {
211#ifdef __MINGW32__
212 line[2] = '\n';
213# define line (line + 2)
214#endif
200 if (strstr(list_target, line) == NULL) 215 if (strstr(list_target, line) == NULL)
201 { 216 {
202 /* 217 /*
@@ -219,6 +234,9 @@ int main(int argc, const char * argv [])
219 ERROR_EXIT(line); 234 ERROR_EXIT(line);
220 } 235 }
221 } 236 }
237#ifdef __MINGW32__
238# undef line
239#endif
222 } 240 }
223 241
224 if (pclose(fp_find) != 0) 242 if (pclose(fp_find) != 0)
diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter
index b4a1d2811..26474595f 100755
--- a/scripts/bloat-o-meter
+++ b/scripts/bloat-o-meter
@@ -43,6 +43,8 @@ if f1 is None or f2 is None:
43 43
44sym_args = " ".join(sys.argv[3 + flag_timing + dashes:]) 44sym_args = " ".join(sys.argv[3 + flag_timing + dashes:])
45def getsizes(file): 45def getsizes(file):
46 if file.endswith(".exe"):
47 return getsizes_pe(file)
46 sym, alias, lut, section = {}, {}, {}, {} 48 sym, alias, lut, section = {}, {}, {}, {}
47 for l in os.popen("readelf -W -S " + file).readlines(): 49 for l in os.popen("readelf -W -S " + file).readlines():
48 x = l.replace("[ ", "[", 1).split() 50 x = l.replace("[ ", "[", 1).split()
@@ -80,6 +82,29 @@ def getsizes(file):
80 sym[alias[(addr, sz)]["name"]] = {"addr" : addr, "size": sz} 82 sym[alias[(addr, sz)]["name"]] = {"addr" : addr, "size": sz}
81 return sym 83 return sym
82 84
85def getsizes_pe(file):
86 sym, sections = {}, {}
87 prefix = os.getenv("CROSS_COMPILE", "")
88 for l in os.popen(prefix + "objdump -h " + file).readlines():
89 x = l.split()
90 if len(x) != 7: continue
91 sections[x[1]] = 1
92 if x[1] not in [".rdata"]: continue
93 sym[x[1]] = {"addr" : int(x[3], 16), "size" : int(x[2], 16)}
94 for l in os.popen(prefix + "nm -S --size-sort %s %s" % (sym_args, file)).readlines():
95 if len(l.split()) != 4: continue
96 value, size, typ, name = l.split()
97 if typ in ["N"]: continue # skip debug symbols
98 if name in sections: continue # bare reference to section
99 value = int(value, 16)
100 size = int(size, 16)
101 if "$" in name:
102 section, name = name.split("$")
103 if section in sym:
104 sym[section]["size"] -= size
105 sym[name] = {"addr" : value, "size": size}
106 return sym
107
83if flag_timing: 108if flag_timing:
84 start_t1 = int(time.time() * 1e9) 109 start_t1 = int(time.time() * 1e9)
85old = getsizes(f1) 110old = getsizes(f1)
diff --git a/scripts/embedded_scripts b/scripts/embedded_scripts
index 205ac591a..88c3a13cb 100755
--- a/scripts/embedded_scripts
+++ b/scripts/embedded_scripts
@@ -23,8 +23,8 @@ if test $? != 0; then
23 exit 1 23 exit 1
24fi 24fi
25 25
26bzip2 </dev/null >/dev/null 26bzip2 </dev/null >/dev/null 2>&1
27if test $? != 0; then 27if test $? = 127; then
28 echo 'bzip2 is not installed' 28 echo 'bzip2 is not installed'
29 exit 1 29 exit 1
30fi 30fi
@@ -90,6 +90,7 @@ concatenate_scripts() {
90 done 90 done
91} 91}
92 92
93(
93exec >"$target.$$" 94exec >"$target.$$"
94 95
95if [ $n -ne 0 ] 96if [ $n -ne 0 ]
@@ -127,5 +128,6 @@ then
127 -e 's/$/ \\/' 128 -e 's/$/ \\/'
128 printf '\n' 129 printf '\n'
129fi 130fi
131)
130 132
131mv -- "$target.$$" "$target" 133mv -- "$target.$$" "$target"
diff --git a/scripts/kconfig/.gitignore b/scripts/kconfig/.gitignore
index b49584c93..aa9c7d637 100644
--- a/scripts/kconfig/.gitignore
+++ b/scripts/kconfig/.gitignore
@@ -17,3 +17,4 @@ mconf
17qconf 17qconf
18gconf 18gconf
19kxgettext 19kxgettext
20/conf.exe
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 38bae809a..ed07c4c62 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -2,6 +2,17 @@
2# Kernel configuration targets 2# Kernel configuration targets
3# These targets are used from top-level makefile 3# These targets are used from top-level makefile
4 4
5# If w64devkit isn't run via w64devkit.exe W64DEVKIT won't be
6# defined. If HOSTCC targets the mingw32 platform set W64DEVKIT.
7ifndef W64DEVKIT
8 host_target := $(shell $(HOSTCC) -v 2>&1 | grep ^Target:)
9 host_platform := $(lastword $(subst -, ,$(host_target)))
10 ifeq ($(host_platform),mingw32)
11 W64DEVKIT := 1
12 export W64DEVKIT
13 endif
14endif
15
5PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config 16PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config
6 17
7xconfig: $(obj)/qconf 18xconfig: $(obj)/qconf
@@ -11,6 +22,9 @@ gconfig: $(obj)/gconf
11 $< Config.in 22 $< Config.in
12 23
13menuconfig: $(obj)/mconf 24menuconfig: $(obj)/mconf
25ifdef W64DEVKIT
26 $(Q)$(MAKE) $(build)=scripts/kconfig/libcurses
27endif
14 $(Q)$(MAKE) $(build)=scripts/kconfig/lxdialog 28 $(Q)$(MAKE) $(build)=scripts/kconfig/lxdialog
15 $< Config.in 29 $< Config.in
16 30
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 39ec1cdb6..4680932d7 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -193,9 +193,14 @@ static void conf_askvalue(struct symbol *sym, const char *def)
193 break; 193 break;
194 } 194 }
195 case set_random: 195 case set_random:
196#ifdef __MINGW32__
197 fprintf(stderr, "set_random not supported\n");
198 exit(1);
199#else
196 do { 200 do {
197 val = (tristate)(random() % 3); 201 val = (tristate)(random() % 3);
198 } while (!sym_tristate_within_range(sym, val)); 202 } while (!sym_tristate_within_range(sym, val));
203#endif
199 switch (val) { 204 switch (val) {
200 case no: line[0] = 'n'; break; 205 case no: line[0] = 'n'; break;
201 case mod: line[0] = 'm'; break; 206 case mod: line[0] = 'm'; break;
@@ -407,7 +412,12 @@ static int conf_choice(struct menu *menu)
407 continue; 412 continue;
408 break; 413 break;
409 case set_random: 414 case set_random:
415#ifdef __MINGW32__
416 fprintf(stderr, "set_random not supported\n");
417 exit(1);
418#else
410 def = (random() % cnt) + 1; 419 def = (random() % cnt) + 1;
420#endif
411 case set_default: 421 case set_default:
412 case set_yes: 422 case set_yes:
413 case set_mod: 423 case set_mod:
@@ -563,8 +573,13 @@ int main(int ac, char **av)
563 input_mode = set_yes; 573 input_mode = set_yes;
564 break; 574 break;
565 case 'r': 575 case 'r':
576#ifdef __MINGW32__
577 fprintf(stderr, "set_random not supported\n");
578 exit(1);
579#else
566 input_mode = set_random; 580 input_mode = set_random;
567 srandom(time(NULL)); 581 srandom(time(NULL));
582#endif
568 break; 583 break;
569 case 'h': 584 case 'h':
570 case '?': 585 case '?':
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 249a3195e..2f7fa6618 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -584,15 +584,24 @@ int conf_write(const char *name)
584 fclose(out); 584 fclose(out);
585 if (out_h) { 585 if (out_h) {
586 fclose(out_h); 586 fclose(out_h);
587#ifdef __MINGW32__
588 unlink("include/autoconf.h");
589#endif
587 rename(".tmpconfig.h", "include/autoconf.h"); 590 rename(".tmpconfig.h", "include/autoconf.h");
588 } 591 }
589 if (!name || basename != conf_def_filename) { 592 if (!name || basename != conf_def_filename) {
590 if (!name) 593 if (!name)
591 name = conf_def_filename; 594 name = conf_def_filename;
592 sprintf(tmpname, "%s.old", name); 595 sprintf(tmpname, "%s.old", name);
596#ifdef __MINGW32__
597 unlink(tmpname);
598#endif
593 rename(name, tmpname); 599 rename(name, tmpname);
594 } 600 }
595 sprintf(tmpname, "%s%s", dirname, basename); 601 sprintf(tmpname, "%s%s", dirname, basename);
602#ifdef __MINGW32__
603 unlink(tmpname);
604#endif
596 if (rename(newname, tmpname)) 605 if (rename(newname, tmpname))
597 return 1; 606 return 1;
598 607
diff --git a/scripts/kconfig/libcurses/Kbuild.src b/scripts/kconfig/libcurses/Kbuild.src
new file mode 100644
index 000000000..d04da63bb
--- /dev/null
+++ b/scripts/kconfig/libcurses/Kbuild.src
@@ -0,0 +1,51 @@
1lib-y :=
2
3INSERT
4
5lib-y +=addch.o
6lib-n +=addchstr.o
7lib-y +=addstr.o
8lib-y +=attr.o
9lib-y +=beep.o
10lib-y +=bkgd.o
11lib-y +=border.o
12lib-y +=clear.o
13lib-y +=color.o
14lib-n +=debug.o
15lib-n +=delch.o
16lib-n +=deleteln.o
17lib-y +=getch.o
18lib-n +=getstr.o
19lib-y +=getyx.o
20lib-y +=inch.o
21lib-n +=inchstr.o
22lib-y +=initscr.o
23lib-y +=inopts.o
24lib-n +=insch.o
25lib-n +=insstr.o
26lib-n +=instr.o
27lib-y +=kernel.o
28lib-n +=keyname.o
29lib-n +=mouse.o
30lib-y +=move.o
31lib-y +=outopts.o
32lib-y +=overlay.o
33lib-y +=pad.o
34lib-n +=panel.o
35lib-y +=pdcclip.o
36lib-y +=pdcdisp.o
37lib-y +=pdcgetsc.o
38lib-y +=pdckbd.o
39lib-y +=pdcscrn.o
40lib-y +=pdcsetsc.o
41lib-y +=pdcutil.o
42lib-y +=printw.o
43lib-y +=refresh.o
44lib-n +=scanw.o
45lib-n +=scr_dump.o
46lib-y +=scroll.o
47lib-y +=slk.o
48lib-n +=termattr.o
49lib-y +=touch.o
50lib-n +=util.o
51lib-y +=window.o
diff --git a/scripts/kconfig/libcurses/README.md b/scripts/kconfig/libcurses/README.md
new file mode 100644
index 000000000..81f5b2cbe
--- /dev/null
+++ b/scripts/kconfig/libcurses/README.md
@@ -0,0 +1,20 @@
1PDCurses for Windows console
2============================
3
4This directory contains PDCurses source code files specific to the
5Microsoft Windows console. Although historically called "Win32", this
6port can just as easily be built for 64-bit systems. Windows 95 through
7Windows 10 are covered. (Some features require later versions.)
8
9
10Acknowledgements
11----------------
12
13Windows console port was originally provided by Chris Szurgot
14<szurgot@itribe.net>
15
16
17Distribution Status
18-------------------
19
20The files in this directory are released to the public domain.
diff --git a/scripts/kconfig/libcurses/acs437.h b/scripts/kconfig/libcurses/acs437.h
new file mode 100644
index 000000000..24cbd7854
--- /dev/null
+++ b/scripts/kconfig/libcurses/acs437.h
@@ -0,0 +1,35 @@
1/* ACS definitions originally by jshumate@wrdis01.robins.af.mil -- these
2 match code page 437 and compatible pages (CP850, CP852, etc.) */
3
4chtype acs_map[128] =
5{
6 PDC_ACS(0), PDC_ACS(1), PDC_ACS(2), PDC_ACS(3), PDC_ACS(4),
7 PDC_ACS(5), PDC_ACS(6), PDC_ACS(7), PDC_ACS(8), PDC_ACS(9),
8 PDC_ACS(10), PDC_ACS(11), PDC_ACS(12), PDC_ACS(13), PDC_ACS(14),
9 PDC_ACS(15), PDC_ACS(16), PDC_ACS(17), PDC_ACS(18), PDC_ACS(19),
10 PDC_ACS(20), PDC_ACS(21), PDC_ACS(22), PDC_ACS(23), PDC_ACS(24),
11 PDC_ACS(25), PDC_ACS(26), PDC_ACS(27), PDC_ACS(28), PDC_ACS(29),
12 PDC_ACS(30), PDC_ACS(31), ' ', '!', '"', '#', '$', '%', '&', '\'',
13 '(', ')', '*',
14
15 PDC_ACS(0x1a), PDC_ACS(0x1b), PDC_ACS(0x18), PDC_ACS(0x19),
16
17 '/',
18
19 0xdb,
20
21 '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=',
22 '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
23 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
24 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
25
26 PDC_ACS(0x04), 0xb1,
27
28 'b', 'c', 'd', 'e',
29
30 0xf8, 0xf1, 0xb0, PDC_ACS(0x0f), 0xd9, 0xbf, 0xda, 0xc0, 0xc5, 0x2d,
31 0x2d, 0xc4, 0x2d, 0x5f, 0xc3, 0xb4, 0xc1, 0xc2, 0xb3, 0xf3, 0xf2,
32 0xe3, 0xd8, 0x9c, 0xf9,
33
34 PDC_ACS(127)
35};
diff --git a/scripts/kconfig/libcurses/acsuni.h b/scripts/kconfig/libcurses/acsuni.h
new file mode 100644
index 000000000..2fdad8a1c
--- /dev/null
+++ b/scripts/kconfig/libcurses/acsuni.h
@@ -0,0 +1,35 @@
1/* ACS Unicode mapping */
2
3chtype acs_map[128] =
4{
5 PDC_ACS(0), PDC_ACS(1), PDC_ACS(2), PDC_ACS(3), PDC_ACS(4),
6 PDC_ACS(5), PDC_ACS(6), PDC_ACS(7), PDC_ACS(8), PDC_ACS(9),
7 PDC_ACS(10), PDC_ACS(11), PDC_ACS(12), PDC_ACS(13), PDC_ACS(14),
8 PDC_ACS(15), PDC_ACS(16), PDC_ACS(17), PDC_ACS(18), PDC_ACS(19),
9 PDC_ACS(20), PDC_ACS(21), PDC_ACS(22), PDC_ACS(23), PDC_ACS(24),
10 PDC_ACS(25), PDC_ACS(26), PDC_ACS(27), PDC_ACS(28), PDC_ACS(29),
11 PDC_ACS(30), PDC_ACS(31), ' ', '!', '"', '#', '$', '%', '&', '\'',
12 '(', ')', '*',
13
14 0x2192, 0x2190, 0x2191, 0x2193,
15
16 '/',
17
18 0x2588,
19
20 '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=',
21 '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
22 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
23 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
24
25 0x2666, 0x2592,
26
27 'b', 'c', 'd', 'e',
28
29 0x00b0, 0x00b1, 0x2591, 0x00a4, 0x2518, 0x2510, 0x250c, 0x2514,
30 0x253c, 0x23ba, 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524,
31 0x2534, 0x252c, 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3,
32 0x00b7,
33
34 PDC_ACS(127)
35};
diff --git a/scripts/kconfig/libcurses/addch.c b/scripts/kconfig/libcurses/addch.c
new file mode 100644
index 000000000..f3c25d389
--- /dev/null
+++ b/scripts/kconfig/libcurses/addch.c
@@ -0,0 +1,408 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7addch
8-----
9
10### Synopsis
11
12 int addch(const chtype ch);
13 int waddch(WINDOW *win, const chtype ch);
14 int mvaddch(int y, int x, const chtype ch);
15 int mvwaddch(WINDOW *win, int y, int x, const chtype ch);
16 int echochar(const chtype ch);
17 int wechochar(WINDOW *win, const chtype ch);
18
19 int addrawch(chtype ch);
20 int waddrawch(WINDOW *win, chtype ch);
21 int mvaddrawch(int y, int x, chtype ch);
22 int mvwaddrawch(WINDOW *win, int y, int x, chtype ch);
23
24 int add_wch(const cchar_t *wch);
25 int wadd_wch(WINDOW *win, const cchar_t *wch);
26 int mvadd_wch(int y, int x, const cchar_t *wch);
27 int mvwadd_wch(WINDOW *win, int y, int x, const cchar_t *wch);
28 int echo_wchar(const cchar_t *wch);
29 int wecho_wchar(WINDOW *win, const cchar_t *wch);
30
31### Description
32
33 addch() adds the chtype ch to the default window (stdscr) at the
34 current cursor position, and advances the cursor. Note that chtypes
35 can convey both text (a single character) and attributes, including a
36 color pair. add_wch() is the wide-character version of this function,
37 taking a pointer to a cchar_t instead of a chtype.
38
39 waddch() is like addch(), but also lets you specify the window. (This
40 is in fact the core output routine.) wadd_wch() is the wide version.
41
42 mvaddch() moves the cursor to the specified (y, x) position, and adds
43 ch to stdscr. mvadd_wch() is the wide version.
44
45 mvwaddch() moves the cursor to the specified position and adds ch to
46 the specified window. mvwadd_wch() is the wide version.
47
48 echochar() adds ch to stdscr at the current cursor position and calls
49 refresh(). echo_wchar() is the wide version.
50
51 wechochar() adds ch to the specified window and calls wrefresh().
52 wecho_wchar() is the wide version.
53
54 addrawch(), waddrawch(), mvaddrawch() and mvwaddrawch() are PDCurses-
55 specific wrappers for addch() etc. that disable the translation of
56 control characters.
57
58 The following applies to all these functions:
59
60 If the cursor moves on to the right margin, an automatic newline is
61 performed. If scrollok is enabled, and a character is added to the
62 bottom right corner of the window, the scrolling region will be
63 scrolled up one line. If scrolling is not allowed, ERR will be
64 returned.
65
66 If ch is a tab, newline, or backspace, the cursor will be moved
67 appropriately within the window. If ch is a newline, the clrtoeol
68 routine is called before the cursor is moved to the beginning of the
69 next line. If newline mapping is off, the cursor will be moved to
70 the next line, but the x coordinate will be unchanged. If ch is a
71 tab the cursor is moved to the next tab position within the window.
72 If ch is another control character, it will be drawn in the ^X
73 notation. Calling the inch() routine after adding a control
74 character returns the representation of the control character, not
75 the control character.
76
77 Video attributes can be combined with a character by ORing them into
78 the parameter. Text, including attributes, can be copied from one
79 place to another by using inch() and addch().
80
81 Note that in PDCurses, for now, a cchar_t and a chtype are the same.
82 The text field is 16 bits wide, and is treated as Unicode (UCS-2)
83 when PDCurses is built with wide-character support (define PDC_WIDE).
84 So, in functions that take a chtype, like addch(), both the wide and
85 narrow versions will handle Unicode. But for portability, you should
86 use the wide functions.
87
88### Return Value
89
90 All functions return OK on success and ERR on error.
91
92### Portability
93 X/Open ncurses NetBSD
94 addch Y Y Y
95 waddch Y Y Y
96 mvaddch Y Y Y
97 mvwaddch Y Y Y
98 echochar Y Y Y
99 wechochar Y Y Y
100 add_wch Y Y Y
101 wadd_wch Y Y Y
102 mvadd_wch Y Y Y
103 mvwadd_wch Y Y Y
104 echo_wchar Y Y Y
105 wecho_wchar Y Y Y
106 addrawch - - -
107 waddrawch - - -
108 mvaddrawch - - -
109 mvwaddrawch - - -
110
111**man-end****************************************************************/
112
113int waddch(WINDOW *win, const chtype ch)
114{
115 int x, y;
116 chtype text, attr;
117 bool xlat;
118
119 PDC_LOG(("waddch() - called: win=%p ch=%x (text=%c attr=0x%x)\n",
120 win, ch, ch & A_CHARTEXT, ch & A_ATTRIBUTES));
121
122 if (!win || !SP)
123 return ERR;
124
125 x = win->_curx;
126 y = win->_cury;
127
128 if (y > win->_maxy || x > win->_maxx || y < 0 || x < 0)
129 return ERR;
130
131 xlat = !SP->raw_out && !(ch & A_ALTCHARSET);
132 text = ch & A_CHARTEXT;
133 attr = ch & A_ATTRIBUTES;
134
135 if (xlat && (text < ' ' || text == 0x7f))
136 {
137 int x2;
138
139 switch (text)
140 {
141 case '\t':
142 for (x2 = ((x / TABSIZE) + 1) * TABSIZE; x < x2; x++)
143 {
144 if (waddch(win, attr | ' ') == ERR)
145 return ERR;
146
147 /* if tab to next line, exit the loop */
148
149 if (!win->_curx)
150 break;
151 }
152 return OK;
153
154 case '\n':
155 /* if lf -> crlf */
156
157 if (!SP->raw_out)
158 x = 0;
159
160 wclrtoeol(win);
161
162 if (++y > win->_bmarg)
163 {
164 y--;
165
166 if (wscrl(win, 1) == ERR)
167 return ERR;
168 }
169
170 break;
171
172 case '\b':
173 /* don't back over left margin */
174
175 if (--x < 0)
176 case '\r':
177 x = 0;
178
179 break;
180
181 case 0x7f:
182 if (waddch(win, attr | '^') == ERR)
183 return ERR;
184
185 return waddch(win, attr | '?');
186
187 default:
188 /* handle control chars */
189
190 if (waddch(win, attr | '^') == ERR)
191 return ERR;
192
193 return waddch(win, ch + '@');
194 }
195 }
196 else
197 {
198 /* If the incoming character doesn't have its own attribute,
199 then use the current attributes for the window. If it has
200 attributes but not a color component, OR the attributes to
201 the current attributes for the window. If it has a color
202 component, use the attributes solely from the incoming
203 character. */
204
205 if (!(attr & A_COLOR))
206 attr |= win->_attrs;
207
208 /* wrs (4/10/93): Apply the same sort of logic for the window
209 background, in that it only takes precedence if other color
210 attributes are not there and that the background character
211 will only print if the printing character is blank. */
212
213 if (!(attr & A_COLOR))
214 attr |= win->_bkgd & A_ATTRIBUTES;
215 else
216 attr |= win->_bkgd & (A_ATTRIBUTES ^ A_COLOR);
217
218 if (text == ' ')
219 text = win->_bkgd & A_CHARTEXT;
220
221 /* Add the attribute back into the character. */
222
223 text |= attr;
224
225 /* Only change _firstch/_lastch if the character to be added is
226 different from the character/attribute that is already in
227 that position in the window. */
228
229 if (win->_y[y][x] != text)
230 {
231 if (win->_firstch[y] == _NO_CHANGE)
232 win->_firstch[y] = win->_lastch[y] = x;
233 else
234 if (x < win->_firstch[y])
235 win->_firstch[y] = x;
236 else
237 if (x > win->_lastch[y])
238 win->_lastch[y] = x;
239
240 win->_y[y][x] = text;
241 }
242
243 if (++x >= win->_maxx)
244 {
245 /* wrap around test */
246
247 x = 0;
248
249 if (++y > win->_bmarg)
250 {
251 y--;
252
253 if (wscrl(win, 1) == ERR)
254 {
255 PDC_sync(win);
256 return ERR;
257 }
258 }
259 }
260 }
261
262 win->_curx = x;
263 win->_cury = y;
264
265 if (win->_immed)
266 wrefresh(win);
267 if (win->_sync)
268 wsyncup(win);
269
270 return OK;
271}
272
273int addch(const chtype ch)
274{
275 PDC_LOG(("addch() - called: ch=%x\n", ch));
276
277 return waddch(stdscr, ch);
278}
279
280int mvaddch(int y, int x, const chtype ch)
281{
282 PDC_LOG(("mvaddch() - called: y=%d x=%d ch=%x\n", y, x, ch));
283
284 if (move(y,x) == ERR)
285 return ERR;
286
287 return waddch(stdscr, ch);
288}
289
290int mvwaddch(WINDOW *win, int y, int x, const chtype ch)
291{
292 PDC_LOG(("mvwaddch() - called: win=%p y=%d x=%d ch=%d\n", win, y, x, ch));
293
294 if (wmove(win, y, x) == ERR)
295 return ERR;
296
297 return waddch(win, ch);
298}
299
300int echochar(const chtype ch)
301{
302 PDC_LOG(("echochar() - called: ch=%x\n", ch));
303
304 return wechochar(stdscr, ch);
305}
306
307int wechochar(WINDOW *win, const chtype ch)
308{
309 PDC_LOG(("wechochar() - called: win=%p ch=%x\n", win, ch));
310
311 if (waddch(win, ch) == ERR)
312 return ERR;
313
314 return wrefresh(win);
315}
316
317int waddrawch(WINDOW *win, chtype ch)
318{
319 PDC_LOG(("waddrawch() - called: win=%p ch=%x (text=%c attr=0x%x)\n",
320 win, ch, ch & A_CHARTEXT, ch & A_ATTRIBUTES));
321
322 if ((ch & A_CHARTEXT) < ' ' || (ch & A_CHARTEXT) == 0x7f)
323 ch |= A_ALTCHARSET;
324
325 return waddch(win, ch);
326}
327
328int addrawch(chtype ch)
329{
330 PDC_LOG(("addrawch() - called: ch=%x\n", ch));
331
332 return waddrawch(stdscr, ch);
333}
334
335int mvaddrawch(int y, int x, chtype ch)
336{
337 PDC_LOG(("mvaddrawch() - called: y=%d x=%d ch=%d\n", y, x, ch));
338
339 if (move(y, x) == ERR)
340 return ERR;
341
342 return waddrawch(stdscr, ch);
343}
344
345int mvwaddrawch(WINDOW *win, int y, int x, chtype ch)
346{
347 PDC_LOG(("mvwaddrawch() - called: win=%p y=%d x=%d ch=%d\n",
348 win, y, x, ch));
349
350 if (wmove(win, y, x) == ERR)
351 return ERR;
352
353 return waddrawch(win, ch);
354}
355
356#ifdef PDC_WIDE
357int wadd_wch(WINDOW *win, const cchar_t *wch)
358{
359 PDC_LOG(("wadd_wch() - called: win=%p wch=%x\n", win, *wch));
360
361 return wch ? waddch(win, *wch) : ERR;
362}
363
364int add_wch(const cchar_t *wch)
365{
366 PDC_LOG(("add_wch() - called: wch=%x\n", *wch));
367
368 return wadd_wch(stdscr, wch);
369}
370
371int mvadd_wch(int y, int x, const cchar_t *wch)
372{
373 PDC_LOG(("mvaddch() - called: y=%d x=%d wch=%x\n", y, x, *wch));
374
375 if (move(y,x) == ERR)
376 return ERR;
377
378 return wadd_wch(stdscr, wch);
379}
380
381int mvwadd_wch(WINDOW *win, int y, int x, const cchar_t *wch)
382{
383 PDC_LOG(("mvwaddch() - called: win=%p y=%d x=%d wch=%d\n",
384 win, y, x, *wch));
385
386 if (wmove(win, y, x) == ERR)
387 return ERR;
388
389 return wadd_wch(win, wch);
390}
391
392int echo_wchar(const cchar_t *wch)
393{
394 PDC_LOG(("echo_wchar() - called: wch=%x\n", *wch));
395
396 return wecho_wchar(stdscr, wch);
397}
398
399int wecho_wchar(WINDOW *win, const cchar_t *wch)
400{
401 PDC_LOG(("wecho_wchar() - called: win=%p wch=%x\n", win, *wch));
402
403 if (!wch || (wadd_wch(win, wch) == ERR))
404 return ERR;
405
406 return wrefresh(win);
407}
408#endif
diff --git a/scripts/kconfig/libcurses/addstr.c b/scripts/kconfig/libcurses/addstr.c
new file mode 100644
index 000000000..47f8f4e10
--- /dev/null
+++ b/scripts/kconfig/libcurses/addstr.c
@@ -0,0 +1,239 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7addstr
8------
9
10### Synopsis
11
12 int addstr(const char *str);
13 int addnstr(const char *str, int n);
14 int waddstr(WINDOW *win, const char *str);
15 int waddnstr(WINDOW *win, const char *str, int n);
16 int mvaddstr(int y, int x, const char *str);
17 int mvaddnstr(int y, int x, const char *str, int n);
18 int mvwaddstr(WINDOW *win, int y, int x, const char *str);
19 int mvwaddnstr(WINDOW *win, int y, int x, const char *str, int n);
20
21 int addwstr(const wchar_t *wstr);
22 int addnwstr(const wchar_t *wstr, int n);
23 int waddwstr(WINDOW *win, const wchar_t *wstr);
24 int waddnwstr(WINDOW *win, const wchar_t *wstr, int n);
25 int mvaddwstr(int y, int x, const wchar_t *wstr);
26 int mvaddnwstr(int y, int x, const wchar_t *wstr, int n);
27 int mvwaddwstr(WINDOW *win, int y, int x, const wchar_t *wstr);
28 int mvwaddnwstr(WINDOW *win, int y, int x, const wchar_t *wstr, int n);
29
30### Description
31
32 These routines write all the characters of the null-terminated string
33 str or wide-character string wstr to the given window. The
34 functionality is similar to calling waddch() once for each character
35 in the string; except that, when PDCurses is built with wide-
36 character support enabled, the narrow-character functions treat the
37 string as a multibyte string in the current locale, and convert it.
38 The routines with n as the last argument write at most n characters;
39 if n is negative, then the entire string will be added.
40
41### Return Value
42
43 All functions return OK or ERR.
44
45### Portability
46 X/Open ncurses NetBSD
47 addstr Y Y Y
48 waddstr Y Y Y
49 mvaddstr Y Y Y
50 mvwaddstr Y Y Y
51 addnstr Y Y Y
52 waddnstr Y Y Y
53 mvaddnstr Y Y Y
54 mvwaddnstr Y Y Y
55 addwstr Y Y Y
56 waddwstr Y Y Y
57 mvaddwstr Y Y Y
58 mvwaddwstr Y Y Y
59 addnwstr Y Y Y
60 waddnwstr Y Y Y
61 mvaddnwstr Y Y Y
62 mvwaddnwstr Y Y Y
63
64**man-end****************************************************************/
65
66int waddnstr(WINDOW *win, const char *str, int n)
67{
68 int i = 0;
69
70 PDC_LOG(("waddnstr() - called: string=\"%s\" n %d \n", str, n));
71
72 if (!win || !str)
73 return ERR;
74
75 while (str[i] && (i < n || n < 0))
76 {
77#ifdef PDC_WIDE
78 wchar_t wch;
79 int retval = PDC_mbtowc(&wch, str + i, n >= 0 ? n - i : 6);
80
81 if (retval <= 0)
82 return OK;
83
84 i += retval;
85#else
86 chtype wch = (unsigned char)(str[i++]);
87#endif
88 if (waddch(win, wch) == ERR)
89 return ERR;
90 }
91
92 return OK;
93}
94
95int addstr(const char *str)
96{
97 PDC_LOG(("addstr() - called: string=\"%s\"\n", str));
98
99 return waddnstr(stdscr, str, -1);
100}
101
102int addnstr(const char *str, int n)
103{
104 PDC_LOG(("addnstr() - called: string=\"%s\" n %d \n", str, n));
105
106 return waddnstr(stdscr, str, n);
107}
108
109int waddstr(WINDOW *win, const char *str)
110{
111 PDC_LOG(("waddstr() - called: string=\"%s\"\n", str));
112
113 return waddnstr(win, str, -1);
114}
115
116int mvaddstr(int y, int x, const char *str)
117{
118 PDC_LOG(("mvaddstr() - called: y %d x %d string=\"%s\"\n", y, x, str));
119
120 if (move(y, x) == ERR)
121 return ERR;
122
123 return waddnstr(stdscr, str, -1);
124}
125
126int mvaddnstr(int y, int x, const char *str, int n)
127{
128 PDC_LOG(("mvaddnstr() - called: y %d x %d string=\"%s\" n %d \n",
129 y, x, str, n));
130
131 if (move(y, x) == ERR)
132 return ERR;
133
134 return waddnstr(stdscr, str, n);
135}
136
137int mvwaddstr(WINDOW *win, int y, int x, const char *str)
138{
139 PDC_LOG(("mvwaddstr() - called: string=\"%s\"\n", str));
140
141 if (wmove(win, y, x) == ERR)
142 return ERR;
143
144 return waddnstr(win, str, -1);
145}
146
147int mvwaddnstr(WINDOW *win, int y, int x, const char *str, int n)
148{
149 PDC_LOG(("mvwaddnstr() - called: y %d x %d string=\"%s\" n %d \n",
150 y, x, str, n));
151
152 if (wmove(win, y, x) == ERR)
153 return ERR;
154
155 return waddnstr(win, str, n);
156}
157
158#ifdef PDC_WIDE
159int waddnwstr(WINDOW *win, const wchar_t *wstr, int n)
160{
161 int i = 0;
162
163 PDC_LOG(("waddnwstr() - called\n"));
164
165 if (!win || !wstr)
166 return ERR;
167
168 while (wstr[i] && (i < n || n < 0))
169 {
170 chtype wch = wstr[i++];
171
172 if (waddch(win, wch) == ERR)
173 return ERR;
174 }
175
176 return OK;
177}
178
179int addwstr(const wchar_t *wstr)
180{
181 PDC_LOG(("addwstr() - called\n"));
182
183 return waddnwstr(stdscr, wstr, -1);
184}
185
186int addnwstr(const wchar_t *wstr, int n)
187{
188 PDC_LOG(("addnwstr() - called\n"));
189
190 return waddnwstr(stdscr, wstr, n);
191}
192
193int waddwstr(WINDOW *win, const wchar_t *wstr)
194{
195 PDC_LOG(("waddwstr() - called\n"));
196
197 return waddnwstr(win, wstr, -1);
198}
199
200int mvaddwstr(int y, int x, const wchar_t *wstr)
201{
202 PDC_LOG(("mvaddstr() - called\n"));
203
204 if (move(y, x) == ERR)
205 return ERR;
206
207 return waddnwstr(stdscr, wstr, -1);
208}
209
210int mvaddnwstr(int y, int x, const wchar_t *wstr, int n)
211{
212 PDC_LOG(("mvaddnstr() - called\n"));
213
214 if (move(y, x) == ERR)
215 return ERR;
216
217 return waddnwstr(stdscr, wstr, n);
218}
219
220int mvwaddwstr(WINDOW *win, int y, int x, const wchar_t *wstr)
221{
222 PDC_LOG(("mvwaddstr() - called\n"));
223
224 if (wmove(win, y, x) == ERR)
225 return ERR;
226
227 return waddnwstr(win, wstr, -1);
228}
229
230int mvwaddnwstr(WINDOW *win, int y, int x, const wchar_t *wstr, int n)
231{
232 PDC_LOG(("mvwaddnstr() - called\n"));
233
234 if (wmove(win, y, x) == ERR)
235 return ERR;
236
237 return waddnwstr(win, wstr, n);
238}
239#endif
diff --git a/scripts/kconfig/libcurses/attr.c b/scripts/kconfig/libcurses/attr.c
new file mode 100644
index 000000000..3ab5a5637
--- /dev/null
+++ b/scripts/kconfig/libcurses/attr.c
@@ -0,0 +1,409 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7attr
8----
9
10### Synopsis
11
12 int attroff(chtype attrs);
13 int wattroff(WINDOW *win, chtype attrs);
14 int attron(chtype attrs);
15 int wattron(WINDOW *win, chtype attrs);
16 int attrset(chtype attrs);
17 int wattrset(WINDOW *win, chtype attrs);
18 int standend(void);
19 int wstandend(WINDOW *win);
20 int standout(void);
21 int wstandout(WINDOW *win);
22
23 int color_set(short color_pair, void *opts);
24 int wcolor_set(WINDOW *win, short color_pair, void *opts);
25
26 int attr_get(attr_t *attrs, short *color_pair, void *opts);
27 int attr_off(attr_t attrs, void *opts);
28 int attr_on(attr_t attrs, void *opts);
29 int attr_set(attr_t attrs, short color_pair, void *opts);
30 int wattr_get(WINDOW *win, attr_t *attrs, short *color_pair,
31 void *opts);
32 int wattr_off(WINDOW *win, attr_t attrs, void *opts);
33 int wattr_on(WINDOW *win, attr_t attrs, void *opts);
34 int wattr_set(WINDOW *win, attr_t attrs, short color_pair,
35 void *opts);
36
37 int chgat(int n, attr_t attr, short color, const void *opts);
38 int mvchgat(int y, int x, int n, attr_t attr, short color,
39 const void *opts);
40 int mvwchgat(WINDOW *win, int y, int x, int n, attr_t attr,
41 short color, const void *opts);
42 int wchgat(WINDOW *win, int n, attr_t attr, short color,
43 const void *opts);
44
45 chtype getattrs(WINDOW *win);
46
47 int underend(void);
48 int wunderend(WINDOW *win);
49 int underscore(void);
50 int wunderscore(WINDOW *win);
51
52### Description
53
54 These functions manipulate the current attributes and/or colors of
55 the named window. These attributes can be any combination of
56 A_STANDOUT, A_REVERSE, A_BOLD, A_DIM, A_BLINK, A_UNDERLINE. These
57 constants are defined in "curses.h" and can be combined with the
58 bitwise-OR operator (|).
59
60 The current attributes of a window are applied to all chtypes that
61 are written into the window with waddch(). Attributes are a property
62 of the chtype, and move with the character through any scrolling or
63 insert/delete operations.
64
65 wattrset() sets the current attributes of the given window to attrs.
66 attrset() is the stdscr version.
67
68 wattroff() turns off the named attributes without affecting any other
69 attributes; wattron() turns them on.
70
71 wcolor_set() sets the window color to the value of color_pair. opts
72 is unused.
73
74 standout() is the same as attron(A_STANDOUT). standend() is the same
75 as attrset(A_NORMAL); that is, it turns off all attributes.
76
77 The attr_* and wattr_* functions are intended for use with the WA_*
78 attributes. In PDCurses, these are the same as A_*, and there is no
79 difference in bevahior from the chtype-based functions. In all cases,
80 opts is unused.
81
82 wattr_get() retrieves the attributes and color pair for the specified
83 window.
84
85 wchgat() sets the color pair and attributes for the next n cells on
86 the current line of a given window, without changing the existing
87 text, or alterting the window's attributes. An n of -1 extends the
88 change to the edge of the window. The changes take effect
89 immediately. opts is unused.
90
91 wunderscore() turns on the A_UNDERLINE attribute; wunderend() turns
92 it off. underscore() and underend() are the stdscr versions.
93
94### Return Value
95
96 All functions return OK on success and ERR on error.
97
98### Portability
99 X/Open ncurses NetBSD
100 attroff Y Y Y
101 wattroff Y Y Y
102 attron Y Y Y
103 wattron Y Y Y
104 attrset Y Y Y
105 wattrset Y Y Y
106 standend Y Y Y
107 wstandend Y Y Y
108 standout Y Y Y
109 wstandout Y Y Y
110 color_set Y Y Y
111 wcolor_set Y Y Y
112 attr_get Y Y Y
113 wattr_get Y Y Y
114 attr_on Y Y Y
115 wattr_on Y Y Y
116 attr_off Y Y Y
117 wattr_off Y Y Y
118 attr_set Y Y Y
119 wattr_set Y Y Y
120 chgat Y Y Y
121 wchgat Y Y Y
122 mvchgat Y Y Y
123 mvwchgat Y Y Y
124 getattrs - Y Y
125 underend - - Y
126 wunderend - - Y
127 underscore - - Y
128 wunderscore - - Y
129
130**man-end****************************************************************/
131
132int wattroff(WINDOW *win, chtype attrs)
133{
134 PDC_LOG(("wattroff() - called\n"));
135
136 if (!win)
137 return ERR;
138
139 win->_attrs &= (~attrs & A_ATTRIBUTES);
140
141 return OK;
142}
143
144int attroff(chtype attrs)
145{
146 PDC_LOG(("attroff() - called\n"));
147
148 return wattroff(stdscr, attrs);
149}
150
151int wattron(WINDOW *win, chtype attrs)
152{
153 chtype newcolr, oldcolr, newattr, oldattr;
154
155 PDC_LOG(("wattron() - called\n"));
156
157 if (!win)
158 return ERR;
159
160 if ((win->_attrs & A_COLOR) && (attrs & A_COLOR))
161 {
162 oldcolr = win->_attrs & A_COLOR;
163 oldattr = win->_attrs ^ oldcolr;
164 newcolr = attrs & A_COLOR;
165 newattr = (attrs & A_ATTRIBUTES) ^ newcolr;
166 newattr |= oldattr;
167 win->_attrs = newattr | newcolr;
168 }
169 else
170 win->_attrs |= (attrs & A_ATTRIBUTES);
171
172 return OK;
173}
174
175int attron(chtype attrs)
176{
177 PDC_LOG(("attron() - called\n"));
178
179 return wattron(stdscr, attrs);
180}
181
182int wattrset(WINDOW *win, chtype attrs)
183{
184 PDC_LOG(("wattrset() - called\n"));
185
186 if (!win)
187 return ERR;
188
189 win->_attrs = attrs & A_ATTRIBUTES;
190
191 return OK;
192}
193
194int attrset(chtype attrs)
195{
196 PDC_LOG(("attrset() - called\n"));
197
198 return wattrset(stdscr, attrs);
199}
200
201int standend(void)
202{
203 PDC_LOG(("standend() - called\n"));
204
205 return wattrset(stdscr, A_NORMAL);
206}
207
208int standout(void)
209{
210 PDC_LOG(("standout() - called\n"));
211
212 return wattrset(stdscr, A_STANDOUT);
213}
214
215int wstandend(WINDOW *win)
216{
217 PDC_LOG(("wstandend() - called\n"));
218
219 return wattrset(win, A_NORMAL);
220}
221
222int wstandout(WINDOW *win)
223{
224 PDC_LOG(("wstandout() - called\n"));
225
226 return wattrset(win, A_STANDOUT);
227}
228
229chtype getattrs(WINDOW *win)
230{
231 return win ? win->_attrs : 0;
232}
233
234int wcolor_set(WINDOW *win, short color_pair, void *opts)
235{
236 PDC_LOG(("wcolor_set() - called\n"));
237
238 if (!win)
239 return ERR;
240
241 win->_attrs = (win->_attrs & ~A_COLOR) | COLOR_PAIR(color_pair);
242
243 return OK;
244}
245
246int color_set(short color_pair, void *opts)
247{
248 PDC_LOG(("color_set() - called\n"));
249
250 return wcolor_set(stdscr, color_pair, opts);
251}
252
253int wattr_get(WINDOW *win, attr_t *attrs, short *color_pair, void *opts)
254{
255 PDC_LOG(("wattr_get() - called\n"));
256
257 if (!win)
258 return ERR;
259
260 if (attrs)
261 *attrs = win->_attrs & (A_ATTRIBUTES & ~A_COLOR);
262
263 if (color_pair)
264 *color_pair = PAIR_NUMBER(win->_attrs);
265
266 return OK;
267}
268
269int attr_get(attr_t *attrs, short *color_pair, void *opts)
270{
271 PDC_LOG(("attr_get() - called\n"));
272
273 return wattr_get(stdscr, attrs, color_pair, opts);
274}
275
276int wattr_off(WINDOW *win, attr_t attrs, void *opts)
277{
278 PDC_LOG(("wattr_off() - called\n"));
279
280 return wattroff(win, attrs);
281}
282
283int attr_off(attr_t attrs, void *opts)
284{
285 PDC_LOG(("attr_off() - called\n"));
286
287 return wattroff(stdscr, attrs);
288}
289
290int wattr_on(WINDOW *win, attr_t attrs, void *opts)
291{
292 PDC_LOG(("wattr_off() - called\n"));
293
294 return wattron(win, attrs);
295}
296
297int attr_on(attr_t attrs, void *opts)
298{
299 PDC_LOG(("attr_on() - called\n"));
300
301 return wattron(stdscr, attrs);
302}
303
304int wattr_set(WINDOW *win, attr_t attrs, short color_pair, void *opts)
305{
306 PDC_LOG(("wattr_set() - called\n"));
307
308 if (!win)
309 return ERR;
310
311 win->_attrs = (attrs & (A_ATTRIBUTES & ~A_COLOR)) | COLOR_PAIR(color_pair);
312
313 return OK;
314}
315
316int attr_set(attr_t attrs, short color_pair, void *opts)
317{
318 PDC_LOG(("attr_get() - called\n"));
319
320 return wattr_set(stdscr, attrs, color_pair, opts);
321}
322
323int wchgat(WINDOW *win, int n, attr_t attr, short color, const void *opts)
324{
325 chtype *dest, newattr;
326 int startpos, endpos;
327
328 PDC_LOG(("wchgat() - called\n"));
329
330 if (!win)
331 return ERR;
332
333 newattr = (attr & A_ATTRIBUTES) | COLOR_PAIR(color);
334
335 startpos = win->_curx;
336 endpos = ((n < 0) ? win->_maxx : min(startpos + n, win->_maxx)) - 1;
337 dest = win->_y[win->_cury];
338
339 for (n = startpos; n <= endpos; n++)
340 dest[n] = (dest[n] & A_CHARTEXT) | newattr;
341
342 n = win->_cury;
343
344 if (startpos < win->_firstch[n] || win->_firstch[n] == _NO_CHANGE)
345 win->_firstch[n] = startpos;
346
347 if (endpos > win->_lastch[n])
348 win->_lastch[n] = endpos;
349
350 PDC_sync(win);
351
352 return OK;
353}
354
355int chgat(int n, attr_t attr, short color, const void *opts)
356{
357 PDC_LOG(("chgat() - called\n"));
358
359 return wchgat(stdscr, n, attr, color, opts);
360}
361
362int mvchgat(int y, int x, int n, attr_t attr, short color, const void *opts)
363{
364 PDC_LOG(("mvchgat() - called\n"));
365
366 if (move(y, x) == ERR)
367 return ERR;
368
369 return wchgat(stdscr, n, attr, color, opts);
370}
371
372int mvwchgat(WINDOW *win, int y, int x, int n, attr_t attr, short color,
373 const void *opts)
374{
375 PDC_LOG(("mvwchgat() - called\n"));
376
377 if (wmove(win, y, x) == ERR)
378 return ERR;
379
380 return wchgat(win, n, attr, color, opts);
381}
382
383int underend(void)
384{
385 PDC_LOG(("underend() - called\n"));
386
387 return wattroff(stdscr, A_UNDERLINE);
388}
389
390int wunderend(WINDOW *win)
391{
392 PDC_LOG(("wunderend() - called\n"));
393
394 return wattroff(win, A_UNDERLINE);
395}
396
397int underscore(void)
398{
399 PDC_LOG(("underscore() - called\n"));
400
401 return wattron(stdscr, A_UNDERLINE);
402}
403
404int wunderscore(WINDOW *win)
405{
406 PDC_LOG(("wunderscore() - called\n"));
407
408 return wattron(win, A_UNDERLINE);
409}
diff --git a/scripts/kconfig/libcurses/beep.c b/scripts/kconfig/libcurses/beep.c
new file mode 100644
index 000000000..0b97137fd
--- /dev/null
+++ b/scripts/kconfig/libcurses/beep.c
@@ -0,0 +1,74 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7beep
8----
9
10### Synopsis
11
12 int beep(void);
13 int flash(void);
14
15### Description
16
17 beep() sounds the audible bell on the terminal, if possible; if not,
18 it calls flash().
19
20 flash() "flashes" the screen, by inverting the foreground and
21 background of every cell, pausing, and then restoring the original
22 attributes.
23
24### Return Value
25
26 These functions return ERR if called before initscr(), otherwise OK.
27
28### Portability
29 X/Open ncurses NetBSD
30 beep Y Y Y
31 flash Y Y Y
32
33**man-end****************************************************************/
34
35int beep(void)
36{
37 PDC_LOG(("beep() - called\n"));
38
39 if (!SP)
40 return ERR;
41
42 if (SP->audible)
43 PDC_beep();
44 else
45 flash();
46
47 return OK;
48}
49
50int flash(void)
51{
52 int z, y, x;
53
54 PDC_LOG(("flash() - called\n"));
55
56 if (!curscr)
57 return ERR;
58
59 /* Reverse each cell; wait; restore the screen */
60
61 for (z = 0; z < 2; z++)
62 {
63 for (y = 0; y < LINES; y++)
64 for (x = 0; x < COLS; x++)
65 curscr->_y[y][x] ^= A_REVERSE;
66
67 wrefresh(curscr);
68
69 if (!z)
70 napms(50);
71 }
72
73 return OK;
74}
diff --git a/scripts/kconfig/libcurses/bkgd.c b/scripts/kconfig/libcurses/bkgd.c
new file mode 100644
index 000000000..af2d0e054
--- /dev/null
+++ b/scripts/kconfig/libcurses/bkgd.c
@@ -0,0 +1,226 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7bkgd
8----
9
10### Synopsis
11
12 int bkgd(chtype ch);
13 void bkgdset(chtype ch);
14 chtype getbkgd(WINDOW *win);
15 int wbkgd(WINDOW *win, chtype ch);
16 void wbkgdset(WINDOW *win, chtype ch);
17
18 int bkgrnd(const cchar_t *wch);
19 void bkgrndset(const cchar_t *wch);
20 int getbkgrnd(cchar_t *wch);
21 int wbkgrnd(WINDOW *win, const cchar_t *wch);
22 void wbkgrndset(WINDOW *win, const cchar_t *wch);
23 int wgetbkgrnd(WINDOW *win, cchar_t *wch);
24
25### Description
26
27 bkgdset() and wbkgdset() manipulate the background of a window. The
28 background is a chtype consisting of any combination of attributes
29 and a character; it is combined with each chtype added or inserted to
30 the window by waddch() or winsch(). Only the attribute part is used
31 to set the background of non-blank characters, while both character
32 and attributes are used for blank positions.
33
34 bkgd() and wbkgd() not only change the background, but apply it
35 immediately to every cell in the window.
36
37 wbkgrnd(), wbkgrndset() and wgetbkgrnd() are the "wide-character"
38 versions of these functions, taking a pointer to a cchar_t instead of
39 a chtype. However, in PDCurses, cchar_t and chtype are the same.
40
41 The attributes that are defined with the attrset()/attron() set of
42 functions take precedence over the background attributes if there is
43 a conflict (e.g., different color pairs).
44
45### Return Value
46
47 bkgd() and wbkgd() return OK, unless the window is NULL, in which
48 case they return ERR.
49
50### Portability
51 X/Open ncurses NetBSD
52 bkgd Y Y Y
53 bkgdset Y Y Y
54 getbkgd Y Y Y
55 wbkgd Y Y Y
56 wbkgdset Y Y Y
57 bkgrnd Y Y Y
58 bkgrndset Y Y Y
59 getbkgrnd Y Y Y
60 wbkgrnd Y Y Y
61 wbkgrndset Y Y Y
62 wgetbkgrnd Y Y Y
63
64**man-end****************************************************************/
65
66int wbkgd(WINDOW *win, chtype ch)
67{
68 int x, y;
69 chtype oldcolr, oldch, newcolr, newch, colr, attr;
70 chtype oldattr = 0, newattr = 0;
71 chtype *winptr;
72
73 PDC_LOG(("wbkgd() - called\n"));
74
75 if (!win)
76 return ERR;
77
78 if (win->_bkgd == ch)
79 return OK;
80
81 oldcolr = win->_bkgd & A_COLOR;
82 if (oldcolr)
83 oldattr = (win->_bkgd & A_ATTRIBUTES) ^ oldcolr;
84
85 oldch = win->_bkgd & A_CHARTEXT;
86
87 wbkgdset(win, ch);
88
89 newcolr = win->_bkgd & A_COLOR;
90 if (newcolr)
91 newattr = (win->_bkgd & A_ATTRIBUTES) ^ newcolr;
92
93 newch = win->_bkgd & A_CHARTEXT;
94
95 /* what follows is what seems to occur in the System V
96 implementation of this routine */
97
98 for (y = 0; y < win->_maxy; y++)
99 {
100 for (x = 0; x < win->_maxx; x++)
101 {
102 winptr = win->_y[y] + x;
103
104 ch = *winptr;
105
106 /* determine the colors and attributes of the character read
107 from the window */
108
109 colr = ch & A_COLOR;
110 attr = ch & (A_ATTRIBUTES ^ A_COLOR);
111
112 /* if the color is the same as the old background color,
113 then make it the new background color, otherwise leave it */
114
115 if (colr == oldcolr)
116 colr = newcolr;
117
118 /* remove any attributes (non color) from the character that
119 were part of the old background, then combine the
120 remaining ones with the new background */
121
122 attr ^= oldattr;
123 attr |= newattr;
124
125 /* change character if it is there because it was the old
126 background character */
127
128 ch &= A_CHARTEXT;
129 if (ch == oldch)
130 ch = newch;
131
132 ch |= (attr | colr);
133
134 *winptr = ch;
135
136 }
137 }
138
139 touchwin(win);
140 PDC_sync(win);
141 return OK;
142}
143
144int bkgd(chtype ch)
145{
146 PDC_LOG(("bkgd() - called\n"));
147
148 return wbkgd(stdscr, ch);
149}
150
151void wbkgdset(WINDOW *win, chtype ch)
152{
153 PDC_LOG(("wbkgdset() - called\n"));
154
155 if (win)
156 {
157 if (!(ch & A_CHARTEXT))
158 ch |= ' ';
159
160 win->_bkgd = ch;
161 }
162}
163
164void bkgdset(chtype ch)
165{
166 PDC_LOG(("bkgdset() - called\n"));
167
168 wbkgdset(stdscr, ch);
169}
170
171chtype getbkgd(WINDOW *win)
172{
173 PDC_LOG(("getbkgd() - called\n"));
174
175 return win ? win->_bkgd : (chtype)ERR;
176}
177
178#ifdef PDC_WIDE
179int wbkgrnd(WINDOW *win, const cchar_t *wch)
180{
181 PDC_LOG(("wbkgrnd() - called\n"));
182
183 return wch ? wbkgd(win, *wch) : ERR;
184}
185
186int bkgrnd(const cchar_t *wch)
187{
188 PDC_LOG(("bkgrnd() - called\n"));
189
190 return wbkgrnd(stdscr, wch);
191}
192
193void wbkgrndset(WINDOW *win, const cchar_t *wch)
194{
195 PDC_LOG(("wbkgdset() - called\n"));
196
197 if (wch)
198 wbkgdset(win, *wch);
199}
200
201void bkgrndset(const cchar_t *wch)
202{
203 PDC_LOG(("bkgrndset() - called\n"));
204
205 wbkgrndset(stdscr, wch);
206}
207
208int wgetbkgrnd(WINDOW *win, cchar_t *wch)
209{
210 PDC_LOG(("wgetbkgrnd() - called\n"));
211
212 if (!win || !wch)
213 return ERR;
214
215 *wch = win->_bkgd;
216
217 return OK;
218}
219
220int getbkgrnd(cchar_t *wch)
221{
222 PDC_LOG(("getbkgrnd() - called\n"));
223
224 return wgetbkgrnd(stdscr, wch);
225}
226#endif
diff --git a/scripts/kconfig/libcurses/border.c b/scripts/kconfig/libcurses/border.c
new file mode 100644
index 000000000..302c46ea2
--- /dev/null
+++ b/scripts/kconfig/libcurses/border.c
@@ -0,0 +1,414 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7border
8------
9
10### Synopsis
11
12 int border(chtype ls, chtype rs, chtype ts, chtype bs, chtype tl,
13 chtype tr, chtype bl, chtype br);
14 int wborder(WINDOW *win, chtype ls, chtype rs, chtype ts,
15 chtype bs, chtype tl, chtype tr, chtype bl, chtype br);
16 int box(WINDOW *win, chtype verch, chtype horch);
17 int hline(chtype ch, int n);
18 int vline(chtype ch, int n);
19 int whline(WINDOW *win, chtype ch, int n);
20 int wvline(WINDOW *win, chtype ch, int n);
21 int mvhline(int y, int x, chtype ch, int n);
22 int mvvline(int y, int x, chtype ch, int n);
23 int mvwhline(WINDOW *win, int y, int x, chtype ch, int n);
24 int mvwvline(WINDOW *win, int y, int x, chtype ch, int n);
25
26 int border_set(const cchar_t *ls, const cchar_t *rs,
27 const cchar_t *ts, const cchar_t *bs,
28 const cchar_t *tl, const cchar_t *tr,
29 const cchar_t *bl, const cchar_t *br);
30 int wborder_set(WINDOW *win, const cchar_t *ls, const cchar_t *rs,
31 const cchar_t *ts, const cchar_t *bs,
32 const cchar_t *tl, const cchar_t *tr,
33 const cchar_t *bl, const cchar_t *br);
34 int box_set(WINDOW *win, const cchar_t *verch, const cchar_t *horch);
35 int hline_set(const cchar_t *wch, int n);
36 int vline_set(const cchar_t *wch, int n);
37 int whline_set(WINDOW *win, const cchar_t *wch, int n);
38 int wvline_set(WINDOW *win, const cchar_t *wch, int n);
39 int mvhline_set(int y, int x, const cchar_t *wch, int n);
40 int mvvline_set(int y, int x, const cchar_t *wch, int n);
41 int mvwhline_set(WINDOW *win, int y, int x, const cchar_t *wch, int n);
42 int mvwvline_set(WINDOW *win, int y, int x, const cchar_t *wch, int n);
43
44### Description
45
46 border(), wborder(), and box() draw a border around the edge of the
47 window. If any argument is zero, an appropriate default is used:
48
49 ls left side of border ACS_VLINE
50 rs right side of border ACS_VLINE
51 ts top side of border ACS_HLINE
52 bs bottom side of border ACS_HLINE
53 tl top left corner of border ACS_ULCORNER
54 tr top right corner of border ACS_URCORNER
55 bl bottom left corner of border ACS_LLCORNER
56 br bottom right corner of border ACS_LRCORNER
57
58 hline() and whline() draw a horizontal line, using ch, starting from
59 the current cursor position. The cursor position does not change. The
60 line is at most n characters long, or as many as will fit in the
61 window.
62
63 vline() and wvline() draw a vertical line, using ch, starting from
64 the current cursor position. The cursor position does not change. The
65 line is at most n characters long, or as many as will fit in the
66 window.
67
68 The *_set functions are the "wide-character" versions, taking
69 pointers to cchar_t instead of chtype. Note that in PDCurses, chtype
70 and cchar_t are the same.
71
72### Return Value
73
74 These functions return OK on success and ERR on error.
75
76### Portability
77 X/Open ncurses NetBSD
78 border Y Y Y
79 wborder Y Y Y
80 box Y Y Y
81 hline Y Y Y
82 vline Y Y Y
83 whline Y Y Y
84 wvline Y Y Y
85 mvhline Y Y Y
86 mvvline Y Y Y
87 mvwhline Y Y Y
88 mvwvline Y Y Y
89 border_set Y Y Y
90 wborder_set Y Y Y
91 box_set Y Y Y
92 hline_set Y Y Y
93 vline_set Y Y Y
94 whline_set Y Y Y
95 wvline_set Y Y Y
96 mvhline_set Y Y Y
97 mvvline_set Y Y Y
98 mvwhline_set Y Y Y
99 mvwvline_set Y Y Y
100
101**man-end****************************************************************/
102
103/* _attr_passthru() -- Takes a single chtype 'ch' and checks if the
104 current attribute of window 'win', as set by wattrset(), and/or the
105 current background of win, as set by wbkgd(), should by combined with
106 it. Attributes set explicitly in ch take precedence. */
107
108static chtype _attr_passthru(WINDOW *win, chtype ch)
109{
110 chtype attr;
111
112 /* If the incoming character doesn't have its own attribute, then
113 use the current attributes for the window. If the incoming
114 character has attributes, but not a color component, OR the
115 attributes to the current attributes for the window. If the
116 incoming character has a color component, use only the attributes
117 from the incoming character. */
118
119 attr = ch & A_ATTRIBUTES;
120 if (!(attr & A_COLOR))
121 attr |= win->_attrs;
122
123 /* wrs (4/10/93) -- Apply the same sort of logic for the window
124 background, in that it only takes precedence if other color
125 attributes are not there. */
126
127 if (!(attr & A_COLOR))
128 attr |= win->_bkgd & A_ATTRIBUTES;
129 else
130 attr |= win->_bkgd & (A_ATTRIBUTES ^ A_COLOR);
131
132 ch = (ch & A_CHARTEXT) | attr;
133
134 return ch;
135}
136
137int wborder(WINDOW *win, chtype ls, chtype rs, chtype ts, chtype bs,
138 chtype tl, chtype tr, chtype bl, chtype br)
139{
140 int i, ymax, xmax;
141
142 PDC_LOG(("wborder() - called\n"));
143
144 if (!win)
145 return ERR;
146
147 ymax = win->_maxy - 1;
148 xmax = win->_maxx - 1;
149
150 ls = _attr_passthru(win, ls ? ls : ACS_VLINE);
151 rs = _attr_passthru(win, rs ? rs : ACS_VLINE);
152 ts = _attr_passthru(win, ts ? ts : ACS_HLINE);
153 bs = _attr_passthru(win, bs ? bs : ACS_HLINE);
154 tl = _attr_passthru(win, tl ? tl : ACS_ULCORNER);
155 tr = _attr_passthru(win, tr ? tr : ACS_URCORNER);
156 bl = _attr_passthru(win, bl ? bl : ACS_LLCORNER);
157 br = _attr_passthru(win, br ? br : ACS_LRCORNER);
158
159 for (i = 1; i < xmax; i++)
160 {
161 win->_y[0][i] = ts;
162 win->_y[ymax][i] = bs;
163 }
164
165 for (i = 1; i < ymax; i++)
166 {
167 win->_y[i][0] = ls;
168 win->_y[i][xmax] = rs;
169 }
170
171 win->_y[0][0] = tl;
172 win->_y[0][xmax] = tr;
173 win->_y[ymax][0] = bl;
174 win->_y[ymax][xmax] = br;
175
176 for (i = 0; i <= ymax; i++)
177 {
178 win->_firstch[i] = 0;
179 win->_lastch[i] = xmax;
180 }
181
182 PDC_sync(win);
183
184 return OK;
185}
186
187int border(chtype ls, chtype rs, chtype ts, chtype bs, chtype tl,
188 chtype tr, chtype bl, chtype br)
189{
190 PDC_LOG(("border() - called\n"));
191
192 return wborder(stdscr, ls, rs, ts, bs, tl, tr, bl, br);
193}
194
195int box(WINDOW *win, chtype verch, chtype horch)
196{
197 PDC_LOG(("box() - called\n"));
198
199 return wborder(win, verch, verch, horch, horch, 0, 0, 0, 0);
200}
201
202int whline(WINDOW *win, chtype ch, int n)
203{
204 chtype *dest;
205 int startpos, endpos;
206
207 PDC_LOG(("whline() - called\n"));
208
209 if (!win || n < 1)
210 return ERR;
211
212 startpos = win->_curx;
213 endpos = min(startpos + n, win->_maxx) - 1;
214 dest = win->_y[win->_cury];
215 ch = _attr_passthru(win, ch ? ch : ACS_HLINE);
216
217 for (n = startpos; n <= endpos; n++)
218 dest[n] = ch;
219
220 n = win->_cury;
221
222 if (startpos < win->_firstch[n] || win->_firstch[n] == _NO_CHANGE)
223 win->_firstch[n] = startpos;
224
225 if (endpos > win->_lastch[n])
226 win->_lastch[n] = endpos;
227
228 PDC_sync(win);
229
230 return OK;
231}
232
233int hline(chtype ch, int n)
234{
235 PDC_LOG(("hline() - called\n"));
236
237 return whline(stdscr, ch, n);
238}
239
240int mvhline(int y, int x, chtype ch, int n)
241{
242 PDC_LOG(("mvhline() - called\n"));
243
244 if (move(y, x) == ERR)
245 return ERR;
246
247 return whline(stdscr, ch, n);
248}
249
250int mvwhline(WINDOW *win, int y, int x, chtype ch, int n)
251{
252 PDC_LOG(("mvwhline() - called\n"));
253
254 if (wmove(win, y, x) == ERR)
255 return ERR;
256
257 return whline(win, ch, n);
258}
259
260int wvline(WINDOW *win, chtype ch, int n)
261{
262 int endpos, x;
263
264 PDC_LOG(("wvline() - called\n"));
265
266 if (!win || n < 1)
267 return ERR;
268
269 endpos = min(win->_cury + n, win->_maxy);
270 x = win->_curx;
271
272 ch = _attr_passthru(win, ch ? ch : ACS_VLINE);
273
274 for (n = win->_cury; n < endpos; n++)
275 {
276 win->_y[n][x] = ch;
277
278 if (x < win->_firstch[n] || win->_firstch[n] == _NO_CHANGE)
279 win->_firstch[n] = x;
280
281 if (x > win->_lastch[n])
282 win->_lastch[n] = x;
283 }
284
285 PDC_sync(win);
286
287 return OK;
288}
289
290int vline(chtype ch, int n)
291{
292 PDC_LOG(("vline() - called\n"));
293
294 return wvline(stdscr, ch, n);
295}
296
297int mvvline(int y, int x, chtype ch, int n)
298{
299 PDC_LOG(("mvvline() - called\n"));
300
301 if (move(y, x) == ERR)
302 return ERR;
303
304 return wvline(stdscr, ch, n);
305}
306
307int mvwvline(WINDOW *win, int y, int x, chtype ch, int n)
308{
309 PDC_LOG(("mvwvline() - called\n"));
310
311 if (wmove(win, y, x) == ERR)
312 return ERR;
313
314 return wvline(win, ch, n);
315}
316
317#ifdef PDC_WIDE
318int wborder_set(WINDOW *win, const cchar_t *ls, const cchar_t *rs,
319 const cchar_t *ts, const cchar_t *bs, const cchar_t *tl,
320 const cchar_t *tr, const cchar_t *bl, const cchar_t *br)
321{
322 PDC_LOG(("wborder_set() - called\n"));
323
324 return wborder(win, ls ? *ls : 0, rs ? *rs : 0, ts ? *ts : 0,
325 bs ? *bs : 0, tl ? *tl : 0, tr ? *tr : 0,
326 bl ? *bl : 0, br ? *br : 0);
327}
328
329int border_set(const cchar_t *ls, const cchar_t *rs, const cchar_t *ts,
330 const cchar_t *bs, const cchar_t *tl, const cchar_t *tr,
331 const cchar_t *bl, const cchar_t *br)
332{
333 PDC_LOG(("border_set() - called\n"));
334
335 return wborder_set(stdscr, ls, rs, ts, bs, tl, tr, bl, br);
336}
337
338int box_set(WINDOW *win, const cchar_t *verch, const cchar_t *horch)
339{
340 PDC_LOG(("box_set() - called\n"));
341
342 return wborder_set(win, verch, verch, horch, horch,
343 (const cchar_t *)NULL, (const cchar_t *)NULL,
344 (const cchar_t *)NULL, (const cchar_t *)NULL);
345}
346
347int whline_set(WINDOW *win, const cchar_t *wch, int n)
348{
349 PDC_LOG(("whline_set() - called\n"));
350
351 return wch ? whline(win, *wch, n) : ERR;
352}
353
354int hline_set(const cchar_t *wch, int n)
355{
356 PDC_LOG(("hline_set() - called\n"));
357
358 return whline_set(stdscr, wch, n);
359}
360
361int mvhline_set(int y, int x, const cchar_t *wch, int n)
362{
363 PDC_LOG(("mvhline_set() - called\n"));
364
365 if (move(y, x) == ERR)
366 return ERR;
367
368 return whline_set(stdscr, wch, n);
369}
370
371int mvwhline_set(WINDOW *win, int y, int x, const cchar_t *wch, int n)
372{
373 PDC_LOG(("mvwhline_set() - called\n"));
374
375 if (wmove(win, y, x) == ERR)
376 return ERR;
377
378 return whline_set(win, wch, n);
379}
380
381int wvline_set(WINDOW *win, const cchar_t *wch, int n)
382{
383 PDC_LOG(("wvline_set() - called\n"));
384
385 return wch ? wvline(win, *wch, n) : ERR;
386}
387
388int vline_set(const cchar_t *wch, int n)
389{
390 PDC_LOG(("vline_set() - called\n"));
391
392 return wvline_set(stdscr, wch, n);
393}
394
395int mvvline_set(int y, int x, const cchar_t *wch, int n)
396{
397 PDC_LOG(("mvvline_set() - called\n"));
398
399 if (move(y, x) == ERR)
400 return ERR;
401
402 return wvline_set(stdscr, wch, n);
403}
404
405int mvwvline_set(WINDOW *win, int y, int x, const cchar_t *wch, int n)
406{
407 PDC_LOG(("mvwvline_set() - called\n"));
408
409 if (wmove(win, y, x) == ERR)
410 return ERR;
411
412 return wvline_set(win, wch, n);
413}
414#endif
diff --git a/scripts/kconfig/libcurses/clear.c b/scripts/kconfig/libcurses/clear.c
new file mode 100644
index 000000000..acb8edf81
--- /dev/null
+++ b/scripts/kconfig/libcurses/clear.c
@@ -0,0 +1,159 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7clear
8-----
9
10### Synopsis
11
12 int clear(void);
13 int wclear(WINDOW *win);
14 int erase(void);
15 int werase(WINDOW *win);
16 int clrtobot(void);
17 int wclrtobot(WINDOW *win);
18 int clrtoeol(void);
19 int wclrtoeol(WINDOW *win);
20
21### Description
22
23 erase() and werase() copy blanks (i.e. the background chtype) to
24 every cell of the window.
25
26 clear() and wclear() are similar to erase() and werase(), but they
27 also call clearok() to ensure that the the window is cleared on the
28 next wrefresh().
29
30 clrtobot() and wclrtobot() clear the window from the current cursor
31 position to the end of the window.
32
33 clrtoeol() and wclrtoeol() clear the window from the current cursor
34 position to the end of the current line.
35
36### Return Value
37
38 All functions return OK on success and ERR on error.
39
40### Portability
41 X/Open ncurses NetBSD
42 clear Y Y Y
43 wclear Y Y Y
44 erase Y Y Y
45 werase Y Y Y
46 clrtobot Y Y Y
47 wclrtobot Y Y Y
48 clrtoeol Y Y Y
49 wclrtoeol Y Y Y
50
51**man-end****************************************************************/
52
53int wclrtoeol(WINDOW *win)
54{
55 int x, y, minx;
56 chtype blank, *ptr;
57
58 PDC_LOG(("wclrtoeol() - called: Row: %d Col: %d\n",
59 win->_cury, win->_curx));
60
61 if (!win)
62 return ERR;
63
64 y = win->_cury;
65 x = win->_curx;
66
67 /* wrs (4/10/93) account for window background */
68
69 blank = win->_bkgd;
70
71 for (minx = x, ptr = &win->_y[y][x]; minx < win->_maxx; minx++, ptr++)
72 *ptr = blank;
73
74 if (x < win->_firstch[y] || win->_firstch[y] == _NO_CHANGE)
75 win->_firstch[y] = x;
76
77 win->_lastch[y] = win->_maxx - 1;
78
79 PDC_sync(win);
80 return OK;
81}
82
83int clrtoeol(void)
84{
85 PDC_LOG(("clrtoeol() - called\n"));
86
87 return wclrtoeol(stdscr);
88}
89
90int wclrtobot(WINDOW *win)
91{
92 int savey, savex;
93
94 PDC_LOG(("wclrtobot() - called\n"));
95
96 if (!win)
97 return ERR;
98
99 savey = win->_cury;
100 savex = win->_curx;
101
102 /* should this involve scrolling region somehow ? */
103
104 if (win->_cury + 1 < win->_maxy)
105 {
106 win->_curx = 0;
107 win->_cury++;
108 for (; win->_maxy > win->_cury; win->_cury++)
109 wclrtoeol(win);
110 win->_cury = savey;
111 win->_curx = savex;
112 }
113 wclrtoeol(win);
114
115 PDC_sync(win);
116 return OK;
117}
118
119int clrtobot(void)
120{
121 PDC_LOG(("clrtobot() - called\n"));
122
123 return wclrtobot(stdscr);
124}
125
126int werase(WINDOW *win)
127{
128 PDC_LOG(("werase() - called\n"));
129
130 if (wmove(win, 0, 0) == ERR)
131 return ERR;
132
133 return wclrtobot(win);
134}
135
136int erase(void)
137{
138 PDC_LOG(("erase() - called\n"));
139
140 return werase(stdscr);
141}
142
143int wclear(WINDOW *win)
144{
145 PDC_LOG(("wclear() - called\n"));
146
147 if (!win)
148 return ERR;
149
150 win->_clear = TRUE;
151 return werase(win);
152}
153
154int clear(void)
155{
156 PDC_LOG(("clear() - called\n"));
157
158 return wclear(stdscr);
159}
diff --git a/scripts/kconfig/libcurses/color.c b/scripts/kconfig/libcurses/color.c
new file mode 100644
index 000000000..3335ae082
--- /dev/null
+++ b/scripts/kconfig/libcurses/color.c
@@ -0,0 +1,362 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7color
8-----
9
10### Synopsis
11
12 bool has_colors(void);
13 int start_color(void);
14 int init_pair(short pair, short fg, short bg);
15 int pair_content(short pair, short *fg, short *bg);
16 bool can_change_color(void);
17 int init_color(short color, short red, short green, short blue);
18 int color_content(short color, short *red, short *green, short *blue);
19
20 int alloc_pair(int fg, int bg);
21 int assume_default_colors(int f, int b);
22 int find_pair(int fg, int bg);
23 int free_pair(int pair);
24 int use_default_colors(void);
25
26 int PDC_set_line_color(short color);
27
28### Description
29
30 To use these routines, first, call start_color(). Colors are always
31 used in pairs, referred to as color-pairs. A color-pair is created by
32 init_pair(), and consists of a foreground color and a background
33 color. After initialization, COLOR_PAIR(n) can be used like any other
34 video attribute.
35
36 has_colors() reports whether the terminal supports color.
37
38 start_color() initializes eight basic colors (black, red, green,
39 yellow, blue, magenta, cyan, and white), and two global variables:
40 COLORS and COLOR_PAIRS (respectively defining the maximum number of
41 colors and color-pairs the terminal is capable of displaying).
42
43 init_pair() changes the definition of a color-pair. It takes three
44 arguments: the number of the color-pair to be redefined, and the new
45 values of the foreground and background colors. The pair number must
46 be between 0 and COLOR_PAIRS - 1, inclusive. The foreground and
47 background must be between 0 and COLORS - 1, inclusive. If the color
48 pair was previously initialized, the screen is refreshed, and all
49 occurrences of that color-pair are changed to the new definition.
50
51 pair_content() is used to determine what the colors of a given color-
52 pair consist of.
53
54 can_change_color() indicates if the terminal has the capability to
55 change the definition of its colors.
56
57 init_color() is used to redefine a color, if possible. Each of the
58 components -- red, green, and blue -- is specified in a range from 0
59 to 1000, inclusive.
60
61 color_content() reports the current definition of a color in the same
62 format as used by init_color().
63
64 assume_default_colors() and use_default_colors() emulate the ncurses
65 extensions of the same names. assume_default_colors(f, b) is
66 essentially the same as init_pair(0, f, b) (which isn't allowed); it
67 redefines the default colors. use_default_colors() allows the use of
68 -1 as a foreground or background color with init_pair(), and calls
69 assume_default_colors(-1, -1); -1 represents the foreground or
70 background color that the terminal had at startup. If the environment
71 variable PDC_ORIGINAL_COLORS is set at the time start_color() is
72 called, that's equivalent to calling use_default_colors().
73
74 alloc_pair(), find_pair() and free_pair() are also from ncurses.
75 free_pair() marks a pair as unused; find_pair() returns an existing
76 pair with the specified foreground and background colors, if one
77 exists. And alloc_pair() returns such a pair whether or not it was
78 previously set, overwriting the oldest initialized pair if there are
79 no free pairs.
80
81 PDC_set_line_color() is used to set the color, globally, for the
82 color of the lines drawn for the attributes: A_UNDERLINE, A_LEFT and
83 A_RIGHT. A value of -1 (the default) indicates that the current
84 foreground color should be used.
85
86 NOTE: COLOR_PAIR() and PAIR_NUMBER() are implemented as macros.
87
88### Return Value
89
90 Most functions return OK on success and ERR on error. has_colors()
91 and can_change_colors() return TRUE or FALSE. alloc_pair() and
92 find_pair() return a pair number, or -1 on error.
93
94### Portability
95 X/Open ncurses NetBSD
96 has_colors Y Y Y
97 start_color Y Y Y
98 init_pair Y Y Y
99 pair_content Y Y Y
100 can_change_color Y Y Y
101 init_color Y Y Y
102 color_content Y Y Y
103 alloc_pair - Y -
104 assume_default_colors - Y Y
105 find_pair - Y -
106 free_pair - Y -
107 use_default_colors - Y Y
108 PDC_set_line_color - - -
109
110**man-end****************************************************************/
111
112#include <stdlib.h>
113#include <string.h>
114
115int COLORS = 0;
116int COLOR_PAIRS = PDC_COLOR_PAIRS;
117
118static bool default_colors = FALSE;
119static short first_col = 0;
120static int allocnum = 0;
121
122int start_color(void)
123{
124 PDC_LOG(("start_color() - called\n"));
125
126 if (!SP || SP->mono)
127 return ERR;
128
129 SP->color_started = TRUE;
130
131 PDC_set_blink(FALSE); /* Also sets COLORS */
132
133 if (!default_colors && SP->orig_attr && getenv("PDC_ORIGINAL_COLORS"))
134 default_colors = TRUE;
135
136 PDC_init_atrtab();
137
138 return OK;
139}
140
141static void _normalize(short *fg, short *bg)
142{
143 if (*fg == -1)
144 *fg = SP->orig_attr ? SP->orig_fore : COLOR_WHITE;
145
146 if (*bg == -1)
147 *bg = SP->orig_attr ? SP->orig_back : COLOR_BLACK;
148}
149
150static void _init_pair_core(short pair, short fg, short bg)
151{
152 PDC_PAIR *p = SP->atrtab + pair;
153
154 _normalize(&fg, &bg);
155
156 /* To allow the PDC_PRESERVE_SCREEN option to work, we only reset
157 curscr if this call to init_pair() alters a color pair created by
158 the user. */
159
160 if (p->set)
161 {
162 if (p->f != fg || p->b != bg)
163 curscr->_clear = TRUE;
164 }
165
166 p->f = fg;
167 p->b = bg;
168 p->count = allocnum++;
169 p->set = TRUE;
170}
171
172int init_pair(short pair, short fg, short bg)
173{
174 PDC_LOG(("init_pair() - called: pair %d fg %d bg %d\n", pair, fg, bg));
175
176 if (!SP || !SP->color_started || pair < 1 || pair >= COLOR_PAIRS ||
177 fg < first_col || fg >= COLORS || bg < first_col || bg >= COLORS)
178 return ERR;
179
180 _init_pair_core(pair, fg, bg);
181
182 return OK;
183}
184
185bool has_colors(void)
186{
187 PDC_LOG(("has_colors() - called\n"));
188
189 return SP ? !(SP->mono) : FALSE;
190}
191
192int init_color(short color, short red, short green, short blue)
193{
194 PDC_LOG(("init_color() - called\n"));
195
196 if (!SP || color < 0 || color >= COLORS || !PDC_can_change_color() ||
197 red < -1 || red > 1000 || green < -1 || green > 1000 ||
198 blue < -1 || blue > 1000)
199 return ERR;
200
201 SP->dirty = TRUE;
202
203 return PDC_init_color(color, red, green, blue);
204}
205
206int color_content(short color, short *red, short *green, short *blue)
207{
208 PDC_LOG(("color_content() - called\n"));
209
210 if (color < 0 || color >= COLORS || !red || !green || !blue)
211 return ERR;
212
213 if (PDC_can_change_color())
214 return PDC_color_content(color, red, green, blue);
215 else
216 {
217 /* Simulated values for platforms that don't support palette
218 changing */
219
220 short maxval = (color & 8) ? 1000 : 680;
221
222 *red = (color & COLOR_RED) ? maxval : 0;
223 *green = (color & COLOR_GREEN) ? maxval : 0;
224 *blue = (color & COLOR_BLUE) ? maxval : 0;
225
226 return OK;
227 }
228}
229
230bool can_change_color(void)
231{
232 PDC_LOG(("can_change_color() - called\n"));
233
234 return PDC_can_change_color();
235}
236
237int pair_content(short pair, short *fg, short *bg)
238{
239 PDC_LOG(("pair_content() - called\n"));
240
241 if (pair < 0 || pair >= COLOR_PAIRS || !fg || !bg)
242 return ERR;
243
244 *fg = SP->atrtab[pair].f;
245 *bg = SP->atrtab[pair].b;
246
247 return OK;
248}
249
250int assume_default_colors(int f, int b)
251{
252 PDC_LOG(("assume_default_colors() - called: f %d b %d\n", f, b));
253
254 if (f < -1 || f >= COLORS || b < -1 || b >= COLORS)
255 return ERR;
256
257 if (SP->color_started)
258 _init_pair_core(0, f, b);
259
260 return OK;
261}
262
263int use_default_colors(void)
264{
265 PDC_LOG(("use_default_colors() - called\n"));
266
267 default_colors = TRUE;
268 first_col = -1;
269
270 return assume_default_colors(-1, -1);
271}
272
273int PDC_set_line_color(short color)
274{
275 PDC_LOG(("PDC_set_line_color() - called: %d\n", color));
276
277 if (!SP || color < -1 || color >= COLORS)
278 return ERR;
279
280 SP->line_color = color;
281
282 return OK;
283}
284
285void PDC_init_atrtab(void)
286{
287 PDC_PAIR *p = SP->atrtab;
288 short i, fg, bg;
289
290 if (SP->color_started && !default_colors)
291 {
292 fg = COLOR_WHITE;
293 bg = COLOR_BLACK;
294 }
295 else
296 fg = bg = -1;
297
298 _normalize(&fg, &bg);
299
300 for (i = 0; i < PDC_COLOR_PAIRS; i++)
301 {
302 p[i].f = fg;
303 p[i].b = bg;
304 p[i].set = FALSE;
305 }
306}
307
308int free_pair(int pair)
309{
310 if (pair < 1 || pair >= PDC_COLOR_PAIRS || !(SP->atrtab[pair].set))
311 return ERR;
312
313 SP->atrtab[pair].set = FALSE;
314 return OK;
315}
316
317int find_pair(int fg, int bg)
318{
319 int i;
320 PDC_PAIR *p = SP->atrtab;
321
322 for (i = 0; i < PDC_COLOR_PAIRS; i++)
323 if (p[i].set && p[i].f == fg && p[i].b == bg)
324 return i;
325
326 return -1;
327}
328
329static int _find_oldest()
330{
331 int i, lowind = 0, lowval = 0;
332 PDC_PAIR *p = SP->atrtab;
333
334 for (i = 1; i < PDC_COLOR_PAIRS; i++)
335 {
336 if (!p[i].set)
337 return i;
338
339 if (!lowval || (p[i].count < lowval))
340 {
341 lowind = i;
342 lowval = p[i].count;
343 }
344 }
345
346 return lowind;
347}
348
349int alloc_pair(int fg, int bg)
350{
351 int i = find_pair(fg, bg);
352
353 if (-1 == i)
354 {
355 i = _find_oldest();
356
357 if (ERR == init_pair(i, fg, bg))
358 return -1;
359 }
360
361 return i;
362}
diff --git a/scripts/kconfig/libcurses/curses.h b/scripts/kconfig/libcurses/curses.h
new file mode 100644
index 000000000..e4ba3776a
--- /dev/null
+++ b/scripts/kconfig/libcurses/curses.h
@@ -0,0 +1,1440 @@
1/*----------------------------------------------------------------------*
2 * PDCurses *
3 *----------------------------------------------------------------------*/
4
5#ifndef __PDCURSES__
6#define __PDCURSES__ 1
7
8/*man-start**************************************************************
9
10Define before inclusion (only those needed):
11
12 XCURSES if building / built for X11
13 PDC_RGB if you want to use RGB color definitions
14 (Red = 1, Green = 2, Blue = 4) instead of BGR
15 PDC_WIDE if building / built with wide-character support
16 PDC_DLL_BUILD if building / built as a Windows DLL
17 PDC_NCMOUSE to use the ncurses mouse API instead
18 of PDCurses' traditional mouse API
19
20Defined by this header:
21
22 PDCURSES PDCurses-only features are available
23 PDC_BUILD API build version
24 PDC_VER_MAJOR major version number
25 PDC_VER_MINOR minor version number
26 PDC_VERDOT version string
27
28**man-end****************************************************************/
29
30#define PDCURSES 1
31#define PDC_BUILD 3907
32#define PDC_VER_MAJOR 3
33#define PDC_VER_MINOR 9
34#define PDC_VERDOT "3.9"
35
36#define CHTYPE_LONG 1 /* chtype >= 32 bits */
37
38#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
39# define PDC_99 1
40#endif
41
42#if defined(__cplusplus) && __cplusplus >= 199711L
43# define PDC_PP98 1
44#endif
45
46/*----------------------------------------------------------------------*/
47
48#include <stdarg.h>
49#include <stddef.h>
50#include <stdio.h>
51
52#ifdef PDC_WIDE
53# include <wchar.h>
54#endif
55
56#if defined(PDC_99) && !defined(__bool_true_false_are_defined)
57# include <stdbool.h>
58#endif
59
60#ifdef __cplusplus
61extern "C"
62{
63# ifndef PDC_PP98
64# define bool _bool
65# endif
66#endif
67
68/*----------------------------------------------------------------------
69 *
70 * Constants and Types
71 *
72 */
73
74#undef FALSE
75#define FALSE 0
76
77#undef TRUE
78#define TRUE 1
79
80#undef ERR
81#define ERR (-1)
82
83#undef OK
84#define OK 0
85
86#if !defined(PDC_PP98) && !defined(__bool_true_false_are_defined)
87typedef unsigned char bool;
88#endif
89
90#if _LP64
91typedef unsigned int chtype;
92#else
93typedef unsigned long chtype; /* 16-bit attr + 16-bit char */
94#endif
95
96#ifdef PDC_WIDE
97typedef chtype cchar_t;
98#endif
99
100typedef chtype attr_t;
101
102/*----------------------------------------------------------------------
103 *
104 * Version Info
105 *
106 */
107
108/* Use this structure with PDC_get_version() for run-time info about the
109 way the library was built, in case it doesn't match the header. */
110
111typedef struct
112{
113 short flags; /* flags OR'd together (see below) */
114 short build; /* PDC_BUILD at compile time */
115 unsigned char major; /* PDC_VER_MAJOR */
116 unsigned char minor; /* PDC_VER_MINOR */
117 unsigned char csize; /* sizeof chtype */
118 unsigned char bsize; /* sizeof bool */
119} PDC_VERSION;
120
121enum
122{
123 PDC_VFLAG_DEBUG = 1, /* set if built with -DPDCDEBUG */
124 PDC_VFLAG_WIDE = 2, /* -DPDC_WIDE */
125 PDC_VFLAG_UTF8 = 4, /* -DPDC_FORCE_UTF8 */
126 PDC_VFLAG_DLL = 8, /* -DPDC_DLL_BUILD */
127 PDC_VFLAG_RGB = 16 /* -DPDC_RGB */
128};
129
130/*----------------------------------------------------------------------
131 *
132 * Mouse Interface
133 *
134 */
135
136#if _LP64
137typedef unsigned int mmask_t;
138#else
139typedef unsigned long mmask_t;
140#endif
141
142typedef struct
143{
144 int x; /* absolute column, 0 based, measured in characters */
145 int y; /* absolute row, 0 based, measured in characters */
146 short button[3]; /* state of each button */
147 int changes; /* flags indicating what has changed with the mouse */
148} MOUSE_STATUS;
149
150#define BUTTON_RELEASED 0x0000
151#define BUTTON_PRESSED 0x0001
152#define BUTTON_CLICKED 0x0002
153#define BUTTON_DOUBLE_CLICKED 0x0003
154#define BUTTON_TRIPLE_CLICKED 0x0004
155#define BUTTON_MOVED 0x0005 /* PDCurses */
156#define WHEEL_SCROLLED 0x0006 /* PDCurses */
157#define BUTTON_ACTION_MASK 0x0007 /* PDCurses */
158
159#define PDC_BUTTON_SHIFT 0x0008 /* PDCurses */
160#define PDC_BUTTON_CONTROL 0x0010 /* PDCurses */
161#define PDC_BUTTON_ALT 0x0020 /* PDCurses */
162#define BUTTON_MODIFIER_MASK 0x0038 /* PDCurses */
163
164#define MOUSE_X_POS (Mouse_status.x)
165#define MOUSE_Y_POS (Mouse_status.y)
166
167/*
168 * Bits associated with the .changes field:
169 * 3 2 1 0
170 * 210987654321098765432109876543210
171 * 1 <- button 1 has changed
172 * 10 <- button 2 has changed
173 * 100 <- button 3 has changed
174 * 1000 <- mouse has moved
175 * 10000 <- mouse position report
176 * 100000 <- mouse wheel up
177 * 1000000 <- mouse wheel down
178 * 10000000 <- mouse wheel left
179 * 100000000 <- mouse wheel right
180 */
181
182#define PDC_MOUSE_MOVED 0x0008
183#define PDC_MOUSE_POSITION 0x0010
184#define PDC_MOUSE_WHEEL_UP 0x0020
185#define PDC_MOUSE_WHEEL_DOWN 0x0040
186#define PDC_MOUSE_WHEEL_LEFT 0x0080
187#define PDC_MOUSE_WHEEL_RIGHT 0x0100
188
189#define A_BUTTON_CHANGED (Mouse_status.changes & 7)
190#define MOUSE_MOVED (Mouse_status.changes & PDC_MOUSE_MOVED)
191#define MOUSE_POS_REPORT (Mouse_status.changes & PDC_MOUSE_POSITION)
192#define BUTTON_CHANGED(x) (Mouse_status.changes & (1 << ((x) - 1)))
193#define BUTTON_STATUS(x) (Mouse_status.button[(x) - 1])
194#define MOUSE_WHEEL_UP (Mouse_status.changes & PDC_MOUSE_WHEEL_UP)
195#define MOUSE_WHEEL_DOWN (Mouse_status.changes & PDC_MOUSE_WHEEL_DOWN)
196#define MOUSE_WHEEL_LEFT (Mouse_status.changes & PDC_MOUSE_WHEEL_LEFT)
197#define MOUSE_WHEEL_RIGHT (Mouse_status.changes & PDC_MOUSE_WHEEL_RIGHT)
198
199/* mouse bit-masks */
200
201#define BUTTON1_RELEASED 0x00000001L
202#define BUTTON1_PRESSED 0x00000002L
203#define BUTTON1_CLICKED 0x00000004L
204#define BUTTON1_DOUBLE_CLICKED 0x00000008L
205#define BUTTON1_TRIPLE_CLICKED 0x00000010L
206#define BUTTON1_MOVED 0x00000010L /* PDCurses */
207
208#define BUTTON2_RELEASED 0x00000020L
209#define BUTTON2_PRESSED 0x00000040L
210#define BUTTON2_CLICKED 0x00000080L
211#define BUTTON2_DOUBLE_CLICKED 0x00000100L
212#define BUTTON2_TRIPLE_CLICKED 0x00000200L
213#define BUTTON2_MOVED 0x00000200L /* PDCurses */
214
215#define BUTTON3_RELEASED 0x00000400L
216#define BUTTON3_PRESSED 0x00000800L
217#define BUTTON3_CLICKED 0x00001000L
218#define BUTTON3_DOUBLE_CLICKED 0x00002000L
219#define BUTTON3_TRIPLE_CLICKED 0x00004000L
220#define BUTTON3_MOVED 0x00004000L /* PDCurses */
221
222/* For the ncurses-compatible functions only, BUTTON4_PRESSED and
223 BUTTON5_PRESSED are returned for mouse scroll wheel up and down;
224 otherwise PDCurses doesn't support buttons 4 and 5 */
225
226#define BUTTON4_RELEASED 0x00008000L
227#define BUTTON4_PRESSED 0x00010000L
228#define BUTTON4_CLICKED 0x00020000L
229#define BUTTON4_DOUBLE_CLICKED 0x00040000L
230#define BUTTON4_TRIPLE_CLICKED 0x00080000L
231
232#define BUTTON5_RELEASED 0x00100000L
233#define BUTTON5_PRESSED 0x00200000L
234#define BUTTON5_CLICKED 0x00400000L
235#define BUTTON5_DOUBLE_CLICKED 0x00800000L
236#define BUTTON5_TRIPLE_CLICKED 0x01000000L
237
238#define MOUSE_WHEEL_SCROLL 0x02000000L /* PDCurses */
239#define BUTTON_MODIFIER_SHIFT 0x04000000L /* PDCurses */
240#define BUTTON_MODIFIER_CONTROL 0x08000000L /* PDCurses */
241#define BUTTON_MODIFIER_ALT 0x10000000L /* PDCurses */
242
243#define ALL_MOUSE_EVENTS 0x1fffffffL
244#define REPORT_MOUSE_POSITION 0x20000000L
245
246/* ncurses mouse interface */
247
248typedef struct
249{
250 short id; /* unused, always 0 */
251 int x, y, z; /* x, y same as MOUSE_STATUS; z unused */
252 mmask_t bstate; /* equivalent to changes + button[], but
253 in the same format as used for mousemask() */
254} MEVENT;
255
256#if defined(PDC_NCMOUSE) && !defined(NCURSES_MOUSE_VERSION)
257# define NCURSES_MOUSE_VERSION 2
258#endif
259
260#ifdef NCURSES_MOUSE_VERSION
261# define BUTTON_SHIFT BUTTON_MODIFIER_SHIFT
262# define BUTTON_CONTROL BUTTON_MODIFIER_CONTROL
263# define BUTTON_CTRL BUTTON_MODIFIER_CONTROL
264# define BUTTON_ALT BUTTON_MODIFIER_ALT
265#else
266# define BUTTON_SHIFT PDC_BUTTON_SHIFT
267# define BUTTON_CONTROL PDC_BUTTON_CONTROL
268# define BUTTON_ALT PDC_BUTTON_ALT
269#endif
270
271/*----------------------------------------------------------------------
272 *
273 * Window and Screen Structures
274 *
275 */
276
277typedef struct _win /* definition of a window */
278{
279 int _cury; /* current pseudo-cursor */
280 int _curx;
281 int _maxy; /* max window coordinates */
282 int _maxx;
283 int _begy; /* origin on screen */
284 int _begx;
285 int _flags; /* window properties */
286 chtype _attrs; /* standard attributes and colors */
287 chtype _bkgd; /* background, normally blank */
288 bool _clear; /* causes clear at next refresh */
289 bool _leaveit; /* leaves cursor where it is */
290 bool _scroll; /* allows window scrolling */
291 bool _nodelay; /* input character wait flag */
292 bool _immed; /* immediate update flag */
293 bool _sync; /* synchronise window ancestors */
294 bool _use_keypad; /* flags keypad key mode active */
295 chtype **_y; /* pointer to line pointer array */
296 int *_firstch; /* first changed character in line */
297 int *_lastch; /* last changed character in line */
298 int _tmarg; /* top of scrolling region */
299 int _bmarg; /* bottom of scrolling region */
300 int _delayms; /* milliseconds of delay for getch() */
301 int _parx, _pary; /* coords relative to parent (0,0) */
302 struct _win *_parent; /* subwin's pointer to parent win */
303
304 /* these are used only if this is a pad */
305 struct pdat
306 {
307 int _pad_y;
308 int _pad_x;
309 int _pad_top;
310 int _pad_left;
311 int _pad_bottom;
312 int _pad_right;
313 } _pad; /* Pad-properties structure */
314} WINDOW;
315
316/* Color pair structure */
317
318typedef struct
319{
320 short f; /* foreground color */
321 short b; /* background color */
322 int count; /* allocation order */
323 bool set; /* pair has been set */
324} PDC_PAIR;
325
326/* Avoid using the SCREEN struct directly -- use the corresponding
327 functions if possible. This struct may eventually be made private. */
328
329typedef struct
330{
331 bool alive; /* if initscr() called, and not endwin() */
332 bool autocr; /* if cr -> lf */
333 bool cbreak; /* if terminal unbuffered */
334 bool echo; /* if terminal echo */
335 bool raw_inp; /* raw input mode (v. cooked input) */
336 bool raw_out; /* raw output mode (7 v. 8 bits) */
337 bool audible; /* FALSE if the bell is visual */
338 bool mono; /* TRUE if current screen is mono */
339 bool resized; /* TRUE if TERM has been resized */
340 bool orig_attr; /* TRUE if we have the original colors */
341 short orig_fore; /* original screen foreground color */
342 short orig_back; /* original screen foreground color */
343 int cursrow; /* position of physical cursor */
344 int curscol; /* position of physical cursor */
345 int visibility; /* visibility of cursor */
346 int orig_cursor; /* original cursor size */
347 int lines; /* new value for LINES */
348 int cols; /* new value for COLS */
349 mmask_t _trap_mbe; /* trap these mouse button events */
350 int mouse_wait; /* time to wait (in ms) for a
351 button release after a press, in
352 order to count it as a click */
353 int slklines; /* lines in use by slk_init() */
354 WINDOW *slk_winptr; /* window for slk */
355 int linesrippedoff; /* lines ripped off via ripoffline() */
356 int linesrippedoffontop; /* lines ripped off on
357 top via ripoffline() */
358 int delaytenths; /* 1/10ths second to wait block
359 getch() for */
360 bool _preserve; /* TRUE if screen background
361 to be preserved */
362 int _restore; /* specifies if screen background
363 to be restored, and how */
364 unsigned long key_modifiers; /* key modifiers (SHIFT, CONTROL, etc.)
365 on last key press */
366 bool return_key_modifiers; /* TRUE if modifier keys are
367 returned as "real" keys */
368 bool key_code; /* TRUE if last key is a special key;
369 used internally by get_wch() */
370 MOUSE_STATUS mouse_status; /* last returned mouse status */
371 short line_color; /* color of line attributes - default -1 */
372 attr_t termattrs; /* attribute capabilities */
373 WINDOW *lastscr; /* the last screen image */
374 FILE *dbfp; /* debug trace file pointer */
375 bool color_started; /* TRUE after start_color() */
376 bool dirty; /* redraw on napms() after init_color() */
377 int sel_start; /* start of selection (y * COLS + x) */
378 int sel_end; /* end of selection */
379 int *c_buffer; /* character buffer */
380 int c_pindex; /* putter index */
381 int c_gindex; /* getter index */
382 int *c_ungch; /* array of ungotten chars */
383 int c_ungind; /* ungetch() push index */
384 int c_ungmax; /* allocated size of ungetch() buffer */
385 PDC_PAIR *atrtab; /* table of color pairs */
386} SCREEN;
387
388/*----------------------------------------------------------------------
389 *
390 * External Variables
391 *
392 */
393
394#ifdef PDC_DLL_BUILD
395# ifdef CURSES_LIBRARY
396# define PDCEX __declspec(dllexport) extern
397# else
398# define PDCEX __declspec(dllimport)
399# endif
400#else
401# define PDCEX extern
402#endif
403
404PDCEX int LINES; /* terminal height */
405PDCEX int COLS; /* terminal width */
406PDCEX WINDOW *stdscr; /* the default screen window */
407PDCEX WINDOW *curscr; /* the current screen image */
408PDCEX SCREEN *SP; /* curses variables */
409PDCEX MOUSE_STATUS Mouse_status;
410PDCEX int COLORS;
411PDCEX int COLOR_PAIRS;
412PDCEX int TABSIZE;
413PDCEX chtype acs_map[]; /* alternate character set map */
414PDCEX char ttytype[]; /* terminal name/description */
415
416/*man-start**************************************************************
417
418Text Attributes
419===============
420
421PDCurses uses a 32-bit integer for its chtype:
422
423 +--------------------------------------------------------------------+
424 |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|..| 2| 1| 0|
425 +--------------------------------------------------------------------+
426 color pair | modifiers | character eg 'a'
427
428There are 256 color pairs (8 bits), 8 bits for modifiers, and 16 bits
429for character data. The modifiers are bold, underline, right-line,
430left-line, italic, reverse and blink, plus the alternate character set
431indicator.
432
433**man-end****************************************************************/
434
435/*** Video attribute macros ***/
436
437#define A_NORMAL (chtype)0
438
439#define A_ALTCHARSET (chtype)0x00010000
440#define A_RIGHT (chtype)0x00020000
441#define A_LEFT (chtype)0x00040000
442#define A_ITALIC (chtype)0x00080000
443#define A_UNDERLINE (chtype)0x00100000
444#define A_REVERSE (chtype)0x00200000
445#define A_BLINK (chtype)0x00400000
446#define A_BOLD (chtype)0x00800000
447
448#define A_ATTRIBUTES (chtype)0xffff0000
449#define A_CHARTEXT (chtype)0x0000ffff
450#define A_COLOR (chtype)0xff000000
451
452#define PDC_COLOR_SHIFT 24
453
454#define A_LEFTLINE A_LEFT
455#define A_RIGHTLINE A_RIGHT
456#define A_STANDOUT (A_REVERSE | A_BOLD) /* X/Open */
457
458#define A_DIM A_NORMAL
459#define A_INVIS A_NORMAL
460#define A_PROTECT A_NORMAL
461
462#define A_HORIZONTAL A_NORMAL
463#define A_LOW A_NORMAL
464#define A_TOP A_NORMAL
465#define A_VERTICAL A_NORMAL
466
467#define CHR_MSK A_CHARTEXT /* Obsolete */
468#define ATR_MSK A_ATTRIBUTES /* Obsolete */
469#define ATR_NRM A_NORMAL /* Obsolete */
470
471/* For use with attr_t -- X/Open says, "these shall be distinct", so
472 this is a non-conforming implementation. */
473
474#define WA_NORMAL A_NORMAL
475
476#define WA_ALTCHARSET A_ALTCHARSET
477#define WA_BLINK A_BLINK
478#define WA_BOLD A_BOLD
479#define WA_DIM A_DIM
480#define WA_INVIS A_INVIS
481#define WA_ITALIC A_ITALIC
482#define WA_LEFT A_LEFT
483#define WA_PROTECT A_PROTECT
484#define WA_REVERSE A_REVERSE
485#define WA_RIGHT A_RIGHT
486#define WA_STANDOUT A_STANDOUT
487#define WA_UNDERLINE A_UNDERLINE
488
489#define WA_HORIZONTAL A_HORIZONTAL
490#define WA_LOW A_LOW
491#define WA_TOP A_TOP
492#define WA_VERTICAL A_VERTICAL
493
494#define WA_ATTRIBUTES A_ATTRIBUTES
495
496/*** Alternate character set macros ***/
497
498#define PDC_ACS(w) ((chtype)w | A_ALTCHARSET)
499
500/* VT100-compatible symbols -- box chars */
501
502#define ACS_ULCORNER PDC_ACS('l')
503#define ACS_LLCORNER PDC_ACS('m')
504#define ACS_URCORNER PDC_ACS('k')
505#define ACS_LRCORNER PDC_ACS('j')
506#define ACS_RTEE PDC_ACS('u')
507#define ACS_LTEE PDC_ACS('t')
508#define ACS_BTEE PDC_ACS('v')
509#define ACS_TTEE PDC_ACS('w')
510#define ACS_HLINE PDC_ACS('q')
511#define ACS_VLINE PDC_ACS('x')
512#define ACS_PLUS PDC_ACS('n')
513
514/* VT100-compatible symbols -- other */
515
516#define ACS_S1 PDC_ACS('o')
517#define ACS_S9 PDC_ACS('s')
518#define ACS_DIAMOND PDC_ACS('`')
519#define ACS_CKBOARD PDC_ACS('a')
520#define ACS_DEGREE PDC_ACS('f')
521#define ACS_PLMINUS PDC_ACS('g')
522#define ACS_BULLET PDC_ACS('~')
523
524/* Teletype 5410v1 symbols -- these are defined in SysV curses, but
525 are not well-supported by most terminals. Stick to VT100 characters
526 for optimum portability. */
527
528#define ACS_LARROW PDC_ACS(',')
529#define ACS_RARROW PDC_ACS('+')
530#define ACS_DARROW PDC_ACS('.')
531#define ACS_UARROW PDC_ACS('-')
532#define ACS_BOARD PDC_ACS('h')
533#define ACS_LANTERN PDC_ACS('i')
534#define ACS_BLOCK PDC_ACS('0')
535
536/* That goes double for these -- undocumented SysV symbols. Don't use
537 them. */
538
539#define ACS_S3 PDC_ACS('p')
540#define ACS_S7 PDC_ACS('r')
541#define ACS_LEQUAL PDC_ACS('y')
542#define ACS_GEQUAL PDC_ACS('z')
543#define ACS_PI PDC_ACS('{')
544#define ACS_NEQUAL PDC_ACS('|')
545#define ACS_STERLING PDC_ACS('}')
546
547/* Box char aliases */
548
549#define ACS_BSSB ACS_ULCORNER
550#define ACS_SSBB ACS_LLCORNER
551#define ACS_BBSS ACS_URCORNER
552#define ACS_SBBS ACS_LRCORNER
553#define ACS_SBSS ACS_RTEE
554#define ACS_SSSB ACS_LTEE
555#define ACS_SSBS ACS_BTEE
556#define ACS_BSSS ACS_TTEE
557#define ACS_BSBS ACS_HLINE
558#define ACS_SBSB ACS_VLINE
559#define ACS_SSSS ACS_PLUS
560
561/* cchar_t aliases */
562
563#ifdef PDC_WIDE
564# define WACS_ULCORNER (&(acs_map['l']))
565# define WACS_LLCORNER (&(acs_map['m']))
566# define WACS_URCORNER (&(acs_map['k']))
567# define WACS_LRCORNER (&(acs_map['j']))
568# define WACS_RTEE (&(acs_map['u']))
569# define WACS_LTEE (&(acs_map['t']))
570# define WACS_BTEE (&(acs_map['v']))
571# define WACS_TTEE (&(acs_map['w']))
572# define WACS_HLINE (&(acs_map['q']))
573# define WACS_VLINE (&(acs_map['x']))
574# define WACS_PLUS (&(acs_map['n']))
575
576# define WACS_S1 (&(acs_map['o']))
577# define WACS_S9 (&(acs_map['s']))
578# define WACS_DIAMOND (&(acs_map['`']))
579# define WACS_CKBOARD (&(acs_map['a']))
580# define WACS_DEGREE (&(acs_map['f']))
581# define WACS_PLMINUS (&(acs_map['g']))
582# define WACS_BULLET (&(acs_map['~']))
583
584# define WACS_LARROW (&(acs_map[',']))
585# define WACS_RARROW (&(acs_map['+']))
586# define WACS_DARROW (&(acs_map['.']))
587# define WACS_UARROW (&(acs_map['-']))
588# define WACS_BOARD (&(acs_map['h']))
589# define WACS_LANTERN (&(acs_map['i']))
590# define WACS_BLOCK (&(acs_map['0']))
591
592# define WACS_S3 (&(acs_map['p']))
593# define WACS_S7 (&(acs_map['r']))
594# define WACS_LEQUAL (&(acs_map['y']))
595# define WACS_GEQUAL (&(acs_map['z']))
596# define WACS_PI (&(acs_map['{']))
597# define WACS_NEQUAL (&(acs_map['|']))
598# define WACS_STERLING (&(acs_map['}']))
599
600# define WACS_BSSB WACS_ULCORNER
601# define WACS_SSBB WACS_LLCORNER
602# define WACS_BBSS WACS_URCORNER
603# define WACS_SBBS WACS_LRCORNER
604# define WACS_SBSS WACS_RTEE
605# define WACS_SSSB WACS_LTEE
606# define WACS_SSBS WACS_BTEE
607# define WACS_BSSS WACS_TTEE
608# define WACS_BSBS WACS_HLINE
609# define WACS_SBSB WACS_VLINE
610# define WACS_SSSS WACS_PLUS
611#endif
612
613/*** Color macros ***/
614
615#define COLOR_BLACK 0
616
617#ifdef PDC_RGB /* RGB */
618# define COLOR_RED 1
619# define COLOR_GREEN 2
620# define COLOR_BLUE 4
621#else /* BGR */
622# define COLOR_BLUE 1
623# define COLOR_GREEN 2
624# define COLOR_RED 4
625#endif
626
627#define COLOR_CYAN (COLOR_BLUE | COLOR_GREEN)
628#define COLOR_MAGENTA (COLOR_RED | COLOR_BLUE)
629#define COLOR_YELLOW (COLOR_RED | COLOR_GREEN)
630
631#define COLOR_WHITE 7
632
633/*----------------------------------------------------------------------
634 *
635 * Function and Keypad Key Definitions
636 * Many are just for compatibility
637 *
638 */
639
640#define KEY_CODE_YES 0x100 /* If get_wch() gives a key code */
641
642#define KEY_BREAK 0x101 /* Not on PC KBD */
643#define KEY_DOWN 0x102 /* Down arrow key */
644#define KEY_UP 0x103 /* Up arrow key */
645#define KEY_LEFT 0x104 /* Left arrow key */
646#define KEY_RIGHT 0x105 /* Right arrow key */
647#define KEY_HOME 0x106 /* home key */
648#define KEY_BACKSPACE 0x107 /* not on pc */
649#define KEY_F0 0x108 /* function keys; 64 reserved */
650
651#define KEY_DL 0x148 /* delete line */
652#define KEY_IL 0x149 /* insert line */
653#define KEY_DC 0x14a /* delete character */
654#define KEY_IC 0x14b /* insert char or enter ins mode */
655#define KEY_EIC 0x14c /* exit insert char mode */
656#define KEY_CLEAR 0x14d /* clear screen */
657#define KEY_EOS 0x14e /* clear to end of screen */
658#define KEY_EOL 0x14f /* clear to end of line */
659#define KEY_SF 0x150 /* scroll 1 line forward */
660#define KEY_SR 0x151 /* scroll 1 line back (reverse) */
661#define KEY_NPAGE 0x152 /* next page */
662#define KEY_PPAGE 0x153 /* previous page */
663#define KEY_STAB 0x154 /* set tab */
664#define KEY_CTAB 0x155 /* clear tab */
665#define KEY_CATAB 0x156 /* clear all tabs */
666#define KEY_ENTER 0x157 /* enter or send (unreliable) */
667#define KEY_SRESET 0x158 /* soft/reset (partial/unreliable) */
668#define KEY_RESET 0x159 /* reset/hard reset (unreliable) */
669#define KEY_PRINT 0x15a /* print/copy */
670#define KEY_LL 0x15b /* home down/bottom (lower left) */
671#define KEY_ABORT 0x15c /* abort/terminate key (any) */
672#define KEY_SHELP 0x15d /* short help */
673#define KEY_LHELP 0x15e /* long help */
674#define KEY_BTAB 0x15f /* Back tab key */
675#define KEY_BEG 0x160 /* beg(inning) key */
676#define KEY_CANCEL 0x161 /* cancel key */
677#define KEY_CLOSE 0x162 /* close key */
678#define KEY_COMMAND 0x163 /* cmd (command) key */
679#define KEY_COPY 0x164 /* copy key */
680#define KEY_CREATE 0x165 /* create key */
681#define KEY_END 0x166 /* end key */
682#define KEY_EXIT 0x167 /* exit key */
683#define KEY_FIND 0x168 /* find key */
684#define KEY_HELP 0x169 /* help key */
685#define KEY_MARK 0x16a /* mark key */
686#define KEY_MESSAGE 0x16b /* message key */
687#define KEY_MOVE 0x16c /* move key */
688#define KEY_NEXT 0x16d /* next object key */
689#define KEY_OPEN 0x16e /* open key */
690#define KEY_OPTIONS 0x16f /* options key */
691#define KEY_PREVIOUS 0x170 /* previous object key */
692#define KEY_REDO 0x171 /* redo key */
693#define KEY_REFERENCE 0x172 /* ref(erence) key */
694#define KEY_REFRESH 0x173 /* refresh key */
695#define KEY_REPLACE 0x174 /* replace key */
696#define KEY_RESTART 0x175 /* restart key */
697#define KEY_RESUME 0x176 /* resume key */
698#define KEY_SAVE 0x177 /* save key */
699#define KEY_SBEG 0x178 /* shifted beginning key */
700#define KEY_SCANCEL 0x179 /* shifted cancel key */
701#define KEY_SCOMMAND 0x17a /* shifted command key */
702#define KEY_SCOPY 0x17b /* shifted copy key */
703#define KEY_SCREATE 0x17c /* shifted create key */
704#define KEY_SDC 0x17d /* shifted delete char key */
705#define KEY_SDL 0x17e /* shifted delete line key */
706#define KEY_SELECT 0x17f /* select key */
707#define KEY_SEND 0x180 /* shifted end key */
708#define KEY_SEOL 0x181 /* shifted clear line key */
709#define KEY_SEXIT 0x182 /* shifted exit key */
710#define KEY_SFIND 0x183 /* shifted find key */
711#define KEY_SHOME 0x184 /* shifted home key */
712#define KEY_SIC 0x185 /* shifted input key */
713
714#define KEY_SLEFT 0x187 /* shifted left arrow key */
715#define KEY_SMESSAGE 0x188 /* shifted message key */
716#define KEY_SMOVE 0x189 /* shifted move key */
717#define KEY_SNEXT 0x18a /* shifted next key */
718#define KEY_SOPTIONS 0x18b /* shifted options key */
719#define KEY_SPREVIOUS 0x18c /* shifted prev key */
720#define KEY_SPRINT 0x18d /* shifted print key */
721#define KEY_SREDO 0x18e /* shifted redo key */
722#define KEY_SREPLACE 0x18f /* shifted replace key */
723#define KEY_SRIGHT 0x190 /* shifted right arrow */
724#define KEY_SRSUME 0x191 /* shifted resume key */
725#define KEY_SSAVE 0x192 /* shifted save key */
726#define KEY_SSUSPEND 0x193 /* shifted suspend key */
727#define KEY_SUNDO 0x194 /* shifted undo key */
728#define KEY_SUSPEND 0x195 /* suspend key */
729#define KEY_UNDO 0x196 /* undo key */
730
731/* PDCurses-specific key definitions -- PC only */
732
733#define ALT_0 0x197
734#define ALT_1 0x198
735#define ALT_2 0x199
736#define ALT_3 0x19a
737#define ALT_4 0x19b
738#define ALT_5 0x19c
739#define ALT_6 0x19d
740#define ALT_7 0x19e
741#define ALT_8 0x19f
742#define ALT_9 0x1a0
743#define ALT_A 0x1a1
744#define ALT_B 0x1a2
745#define ALT_C 0x1a3
746#define ALT_D 0x1a4
747#define ALT_E 0x1a5
748#define ALT_F 0x1a6
749#define ALT_G 0x1a7
750#define ALT_H 0x1a8
751#define ALT_I 0x1a9
752#define ALT_J 0x1aa
753#define ALT_K 0x1ab
754#define ALT_L 0x1ac
755#define ALT_M 0x1ad
756#define ALT_N 0x1ae
757#define ALT_O 0x1af
758#define ALT_P 0x1b0
759#define ALT_Q 0x1b1
760#define ALT_R 0x1b2
761#define ALT_S 0x1b3
762#define ALT_T 0x1b4
763#define ALT_U 0x1b5
764#define ALT_V 0x1b6
765#define ALT_W 0x1b7
766#define ALT_X 0x1b8
767#define ALT_Y 0x1b9
768#define ALT_Z 0x1ba
769
770#define CTL_LEFT 0x1bb /* Control-Left-Arrow */
771#define CTL_RIGHT 0x1bc
772#define CTL_PGUP 0x1bd
773#define CTL_PGDN 0x1be
774#define CTL_HOME 0x1bf
775#define CTL_END 0x1c0
776
777#define KEY_A1 0x1c1 /* upper left on Virtual keypad */
778#define KEY_A2 0x1c2 /* upper middle on Virt. keypad */
779#define KEY_A3 0x1c3 /* upper right on Vir. keypad */
780#define KEY_B1 0x1c4 /* middle left on Virt. keypad */
781#define KEY_B2 0x1c5 /* center on Virt. keypad */
782#define KEY_B3 0x1c6 /* middle right on Vir. keypad */
783#define KEY_C1 0x1c7 /* lower left on Virt. keypad */
784#define KEY_C2 0x1c8 /* lower middle on Virt. keypad */
785#define KEY_C3 0x1c9 /* lower right on Vir. keypad */
786
787#define PADSLASH 0x1ca /* slash on keypad */
788#define PADENTER 0x1cb /* enter on keypad */
789#define CTL_PADENTER 0x1cc /* ctl-enter on keypad */
790#define ALT_PADENTER 0x1cd /* alt-enter on keypad */
791#define PADSTOP 0x1ce /* stop on keypad */
792#define PADSTAR 0x1cf /* star on keypad */
793#define PADMINUS 0x1d0 /* minus on keypad */
794#define PADPLUS 0x1d1 /* plus on keypad */
795#define CTL_PADSTOP 0x1d2 /* ctl-stop on keypad */
796#define CTL_PADCENTER 0x1d3 /* ctl-enter on keypad */
797#define CTL_PADPLUS 0x1d4 /* ctl-plus on keypad */
798#define CTL_PADMINUS 0x1d5 /* ctl-minus on keypad */
799#define CTL_PADSLASH 0x1d6 /* ctl-slash on keypad */
800#define CTL_PADSTAR 0x1d7 /* ctl-star on keypad */
801#define ALT_PADPLUS 0x1d8 /* alt-plus on keypad */
802#define ALT_PADMINUS 0x1d9 /* alt-minus on keypad */
803#define ALT_PADSLASH 0x1da /* alt-slash on keypad */
804#define ALT_PADSTAR 0x1db /* alt-star on keypad */
805#define ALT_PADSTOP 0x1dc /* alt-stop on keypad */
806#define CTL_INS 0x1dd /* ctl-insert */
807#define ALT_DEL 0x1de /* alt-delete */
808#define ALT_INS 0x1df /* alt-insert */
809#define CTL_UP 0x1e0 /* ctl-up arrow */
810#define CTL_DOWN 0x1e1 /* ctl-down arrow */
811#define CTL_TAB 0x1e2 /* ctl-tab */
812#define ALT_TAB 0x1e3
813#define ALT_MINUS 0x1e4
814#define ALT_EQUAL 0x1e5
815#define ALT_HOME 0x1e6
816#define ALT_PGUP 0x1e7
817#define ALT_PGDN 0x1e8
818#define ALT_END 0x1e9
819#define ALT_UP 0x1ea /* alt-up arrow */
820#define ALT_DOWN 0x1eb /* alt-down arrow */
821#define ALT_RIGHT 0x1ec /* alt-right arrow */
822#define ALT_LEFT 0x1ed /* alt-left arrow */
823#define ALT_ENTER 0x1ee /* alt-enter */
824#define ALT_ESC 0x1ef /* alt-escape */
825#define ALT_BQUOTE 0x1f0 /* alt-back quote */
826#define ALT_LBRACKET 0x1f1 /* alt-left bracket */
827#define ALT_RBRACKET 0x1f2 /* alt-right bracket */
828#define ALT_SEMICOLON 0x1f3 /* alt-semi-colon */
829#define ALT_FQUOTE 0x1f4 /* alt-forward quote */
830#define ALT_COMMA 0x1f5 /* alt-comma */
831#define ALT_STOP 0x1f6 /* alt-stop */
832#define ALT_FSLASH 0x1f7 /* alt-forward slash */
833#define ALT_BKSP 0x1f8 /* alt-backspace */
834#define CTL_BKSP 0x1f9 /* ctl-backspace */
835#define PAD0 0x1fa /* keypad 0 */
836
837#define CTL_PAD0 0x1fb /* ctl-keypad 0 */
838#define CTL_PAD1 0x1fc
839#define CTL_PAD2 0x1fd
840#define CTL_PAD3 0x1fe
841#define CTL_PAD4 0x1ff
842#define CTL_PAD5 0x200
843#define CTL_PAD6 0x201
844#define CTL_PAD7 0x202
845#define CTL_PAD8 0x203
846#define CTL_PAD9 0x204
847
848#define ALT_PAD0 0x205 /* alt-keypad 0 */
849#define ALT_PAD1 0x206
850#define ALT_PAD2 0x207
851#define ALT_PAD3 0x208
852#define ALT_PAD4 0x209
853#define ALT_PAD5 0x20a
854#define ALT_PAD6 0x20b
855#define ALT_PAD7 0x20c
856#define ALT_PAD8 0x20d
857#define ALT_PAD9 0x20e
858
859#define CTL_DEL 0x20f /* clt-delete */
860#define ALT_BSLASH 0x210 /* alt-back slash */
861#define CTL_ENTER 0x211 /* ctl-enter */
862
863#define SHF_PADENTER 0x212 /* shift-enter on keypad */
864#define SHF_PADSLASH 0x213 /* shift-slash on keypad */
865#define SHF_PADSTAR 0x214 /* shift-star on keypad */
866#define SHF_PADPLUS 0x215 /* shift-plus on keypad */
867#define SHF_PADMINUS 0x216 /* shift-minus on keypad */
868#define SHF_UP 0x217 /* shift-up on keypad */
869#define SHF_DOWN 0x218 /* shift-down on keypad */
870#define SHF_IC 0x219 /* shift-insert on keypad */
871#define SHF_DC 0x21a /* shift-delete on keypad */
872
873#define KEY_MOUSE 0x21b /* "mouse" key */
874#define KEY_SHIFT_L 0x21c /* Left-shift */
875#define KEY_SHIFT_R 0x21d /* Right-shift */
876#define KEY_CONTROL_L 0x21e /* Left-control */
877#define KEY_CONTROL_R 0x21f /* Right-control */
878#define KEY_ALT_L 0x220 /* Left-alt */
879#define KEY_ALT_R 0x221 /* Right-alt */
880#define KEY_RESIZE 0x222 /* Window resize */
881#define KEY_SUP 0x223 /* Shifted up arrow */
882#define KEY_SDOWN 0x224 /* Shifted down arrow */
883
884#define KEY_MIN KEY_BREAK /* Minimum curses key value */
885#define KEY_MAX KEY_SDOWN /* Maximum curses key */
886
887#define KEY_F(n) (KEY_F0 + (n))
888
889/*----------------------------------------------------------------------
890 *
891 * Functions
892 *
893 */
894
895/* Standard */
896
897PDCEX int addch(const chtype);
898PDCEX int addchnstr(const chtype *, int);
899PDCEX int addchstr(const chtype *);
900PDCEX int addnstr(const char *, int);
901PDCEX int addstr(const char *);
902PDCEX int attroff(chtype);
903PDCEX int attron(chtype);
904PDCEX int attrset(chtype);
905PDCEX int attr_get(attr_t *, short *, void *);
906PDCEX int attr_off(attr_t, void *);
907PDCEX int attr_on(attr_t, void *);
908PDCEX int attr_set(attr_t, short, void *);
909PDCEX int baudrate(void);
910PDCEX int beep(void);
911PDCEX int bkgd(chtype);
912PDCEX void bkgdset(chtype);
913PDCEX int border(chtype, chtype, chtype, chtype,
914 chtype, chtype, chtype, chtype);
915PDCEX int box(WINDOW *, chtype, chtype);
916PDCEX bool can_change_color(void);
917PDCEX int cbreak(void);
918PDCEX int chgat(int, attr_t, short, const void *);
919PDCEX int clearok(WINDOW *, bool);
920PDCEX int clear(void);
921PDCEX int clrtobot(void);
922PDCEX int clrtoeol(void);
923PDCEX int color_content(short, short *, short *, short *);
924PDCEX int color_set(short, void *);
925PDCEX int copywin(const WINDOW *, WINDOW *, int, int, int,
926 int, int, int, int);
927PDCEX int curs_set(int);
928PDCEX int def_prog_mode(void);
929PDCEX int def_shell_mode(void);
930PDCEX int delay_output(int);
931PDCEX int delch(void);
932PDCEX int deleteln(void);
933PDCEX void delscreen(SCREEN *);
934PDCEX int delwin(WINDOW *);
935PDCEX WINDOW *derwin(WINDOW *, int, int, int, int);
936PDCEX int doupdate(void);
937PDCEX WINDOW *dupwin(WINDOW *);
938PDCEX int echochar(const chtype);
939PDCEX int echo(void);
940PDCEX int endwin(void);
941PDCEX char erasechar(void);
942PDCEX int erase(void);
943PDCEX void filter(void);
944PDCEX int flash(void);
945PDCEX int flushinp(void);
946PDCEX chtype getbkgd(WINDOW *);
947PDCEX int getnstr(char *, int);
948PDCEX int getstr(char *);
949PDCEX WINDOW *getwin(FILE *);
950PDCEX int halfdelay(int);
951PDCEX bool has_colors(void);
952PDCEX bool has_ic(void);
953PDCEX bool has_il(void);
954PDCEX int hline(chtype, int);
955PDCEX void idcok(WINDOW *, bool);
956PDCEX int idlok(WINDOW *, bool);
957PDCEX void immedok(WINDOW *, bool);
958PDCEX int inchnstr(chtype *, int);
959PDCEX int inchstr(chtype *);
960PDCEX chtype inch(void);
961PDCEX int init_color(short, short, short, short);
962PDCEX int init_pair(short, short, short);
963PDCEX WINDOW *initscr(void);
964PDCEX int innstr(char *, int);
965PDCEX int insch(chtype);
966PDCEX int insdelln(int);
967PDCEX int insertln(void);
968PDCEX int insnstr(const char *, int);
969PDCEX int insstr(const char *);
970PDCEX int instr(char *);
971PDCEX int intrflush(WINDOW *, bool);
972PDCEX bool isendwin(void);
973PDCEX bool is_linetouched(WINDOW *, int);
974PDCEX bool is_wintouched(WINDOW *);
975PDCEX char *keyname(int);
976PDCEX int keypad(WINDOW *, bool);
977PDCEX char killchar(void);
978PDCEX int leaveok(WINDOW *, bool);
979PDCEX char *longname(void);
980PDCEX int meta(WINDOW *, bool);
981PDCEX int move(int, int);
982PDCEX int mvaddch(int, int, const chtype);
983PDCEX int mvaddchnstr(int, int, const chtype *, int);
984PDCEX int mvaddchstr(int, int, const chtype *);
985PDCEX int mvaddnstr(int, int, const char *, int);
986PDCEX int mvaddstr(int, int, const char *);
987PDCEX int mvchgat(int, int, int, attr_t, short, const void *);
988PDCEX int mvcur(int, int, int, int);
989PDCEX int mvdelch(int, int);
990PDCEX int mvderwin(WINDOW *, int, int);
991PDCEX int mvgetch(int, int);
992PDCEX int mvgetnstr(int, int, char *, int);
993PDCEX int mvgetstr(int, int, char *);
994PDCEX int mvhline(int, int, chtype, int);
995PDCEX chtype mvinch(int, int);
996PDCEX int mvinchnstr(int, int, chtype *, int);
997PDCEX int mvinchstr(int, int, chtype *);
998PDCEX int mvinnstr(int, int, char *, int);
999PDCEX int mvinsch(int, int, chtype);
1000PDCEX int mvinsnstr(int, int, const char *, int);
1001PDCEX int mvinsstr(int, int, const char *);
1002PDCEX int mvinstr(int, int, char *);
1003PDCEX int mvprintw(int, int, const char *, ...);
1004PDCEX int mvscanw(int, int, const char *, ...);
1005PDCEX int mvvline(int, int, chtype, int);
1006PDCEX int mvwaddchnstr(WINDOW *, int, int, const chtype *, int);
1007PDCEX int mvwaddchstr(WINDOW *, int, int, const chtype *);
1008PDCEX int mvwaddch(WINDOW *, int, int, const chtype);
1009PDCEX int mvwaddnstr(WINDOW *, int, int, const char *, int);
1010PDCEX int mvwaddstr(WINDOW *, int, int, const char *);
1011PDCEX int mvwchgat(WINDOW *, int, int, int, attr_t, short, const void *);
1012PDCEX int mvwdelch(WINDOW *, int, int);
1013PDCEX int mvwgetch(WINDOW *, int, int);
1014PDCEX int mvwgetnstr(WINDOW *, int, int, char *, int);
1015PDCEX int mvwgetstr(WINDOW *, int, int, char *);
1016PDCEX int mvwhline(WINDOW *, int, int, chtype, int);
1017PDCEX int mvwinchnstr(WINDOW *, int, int, chtype *, int);
1018PDCEX int mvwinchstr(WINDOW *, int, int, chtype *);
1019PDCEX chtype mvwinch(WINDOW *, int, int);
1020PDCEX int mvwinnstr(WINDOW *, int, int, char *, int);
1021PDCEX int mvwinsch(WINDOW *, int, int, chtype);
1022PDCEX int mvwinsnstr(WINDOW *, int, int, const char *, int);
1023PDCEX int mvwinsstr(WINDOW *, int, int, const char *);
1024PDCEX int mvwinstr(WINDOW *, int, int, char *);
1025PDCEX int mvwin(WINDOW *, int, int);
1026PDCEX int mvwprintw(WINDOW *, int, int, const char *, ...);
1027PDCEX int mvwscanw(WINDOW *, int, int, const char *, ...);
1028PDCEX int mvwvline(WINDOW *, int, int, chtype, int);
1029PDCEX int napms(int);
1030PDCEX WINDOW *newpad(int, int);
1031PDCEX SCREEN *newterm(const char *, FILE *, FILE *);
1032PDCEX WINDOW *newwin(int, int, int, int);
1033PDCEX int nl(void);
1034PDCEX int nocbreak(void);
1035PDCEX int nodelay(WINDOW *, bool);
1036PDCEX int noecho(void);
1037PDCEX int nonl(void);
1038PDCEX void noqiflush(void);
1039PDCEX int noraw(void);
1040PDCEX int notimeout(WINDOW *, bool);
1041PDCEX int overlay(const WINDOW *, WINDOW *);
1042PDCEX int overwrite(const WINDOW *, WINDOW *);
1043PDCEX int pair_content(short, short *, short *);
1044PDCEX int pechochar(WINDOW *, chtype);
1045PDCEX int pnoutrefresh(WINDOW *, int, int, int, int, int, int);
1046PDCEX int prefresh(WINDOW *, int, int, int, int, int, int);
1047PDCEX int printw(const char *, ...);
1048PDCEX int putwin(WINDOW *, FILE *);
1049PDCEX void qiflush(void);
1050PDCEX int raw(void);
1051PDCEX int redrawwin(WINDOW *);
1052PDCEX int refresh(void);
1053PDCEX int reset_prog_mode(void);
1054PDCEX int reset_shell_mode(void);
1055PDCEX int resetty(void);
1056PDCEX int ripoffline(int, int (*)(WINDOW *, int));
1057PDCEX int savetty(void);
1058PDCEX int scanw(const char *, ...);
1059PDCEX int scr_dump(const char *);
1060PDCEX int scr_init(const char *);
1061PDCEX int scr_restore(const char *);
1062PDCEX int scr_set(const char *);
1063PDCEX int scrl(int);
1064PDCEX int scroll(WINDOW *);
1065PDCEX int scrollok(WINDOW *, bool);
1066PDCEX SCREEN *set_term(SCREEN *);
1067PDCEX int setscrreg(int, int);
1068PDCEX int slk_attroff(const chtype);
1069PDCEX int slk_attr_off(const attr_t, void *);
1070PDCEX int slk_attron(const chtype);
1071PDCEX int slk_attr_on(const attr_t, void *);
1072PDCEX int slk_attrset(const chtype);
1073PDCEX int slk_attr_set(const attr_t, short, void *);
1074PDCEX int slk_clear(void);
1075PDCEX int slk_color(short);
1076PDCEX int slk_init(int);
1077PDCEX char *slk_label(int);
1078PDCEX int slk_noutrefresh(void);
1079PDCEX int slk_refresh(void);
1080PDCEX int slk_restore(void);
1081PDCEX int slk_set(int, const char *, int);
1082PDCEX int slk_touch(void);
1083PDCEX int standend(void);
1084PDCEX int standout(void);
1085PDCEX int start_color(void);
1086PDCEX WINDOW *subpad(WINDOW *, int, int, int, int);
1087PDCEX WINDOW *subwin(WINDOW *, int, int, int, int);
1088PDCEX int syncok(WINDOW *, bool);
1089PDCEX chtype termattrs(void);
1090PDCEX attr_t term_attrs(void);
1091PDCEX char *termname(void);
1092PDCEX void timeout(int);
1093PDCEX int touchline(WINDOW *, int, int);
1094PDCEX int touchwin(WINDOW *);
1095PDCEX int typeahead(int);
1096PDCEX int untouchwin(WINDOW *);
1097PDCEX void use_env(bool);
1098PDCEX int vidattr(chtype);
1099PDCEX int vid_attr(attr_t, short, void *);
1100PDCEX int vidputs(chtype, int (*)(int));
1101PDCEX int vid_puts(attr_t, short, void *, int (*)(int));
1102PDCEX int vline(chtype, int);
1103PDCEX int vw_printw(WINDOW *, const char *, va_list);
1104PDCEX int vwprintw(WINDOW *, const char *, va_list);
1105PDCEX int vw_scanw(WINDOW *, const char *, va_list);
1106PDCEX int vwscanw(WINDOW *, const char *, va_list);
1107PDCEX int waddchnstr(WINDOW *, const chtype *, int);
1108PDCEX int waddchstr(WINDOW *, const chtype *);
1109PDCEX int waddch(WINDOW *, const chtype);
1110PDCEX int waddnstr(WINDOW *, const char *, int);
1111PDCEX int waddstr(WINDOW *, const char *);
1112PDCEX int wattroff(WINDOW *, chtype);
1113PDCEX int wattron(WINDOW *, chtype);
1114PDCEX int wattrset(WINDOW *, chtype);
1115PDCEX int wattr_get(WINDOW *, attr_t *, short *, void *);
1116PDCEX int wattr_off(WINDOW *, attr_t, void *);
1117PDCEX int wattr_on(WINDOW *, attr_t, void *);
1118PDCEX int wattr_set(WINDOW *, attr_t, short, void *);
1119PDCEX void wbkgdset(WINDOW *, chtype);
1120PDCEX int wbkgd(WINDOW *, chtype);
1121PDCEX int wborder(WINDOW *, chtype, chtype, chtype, chtype,
1122 chtype, chtype, chtype, chtype);
1123PDCEX int wchgat(WINDOW *, int, attr_t, short, const void *);
1124PDCEX int wclear(WINDOW *);
1125PDCEX int wclrtobot(WINDOW *);
1126PDCEX int wclrtoeol(WINDOW *);
1127PDCEX int wcolor_set(WINDOW *, short, void *);
1128PDCEX void wcursyncup(WINDOW *);
1129PDCEX int wdelch(WINDOW *);
1130PDCEX int wdeleteln(WINDOW *);
1131PDCEX int wechochar(WINDOW *, const chtype);
1132PDCEX int werase(WINDOW *);
1133PDCEX int wgetch(WINDOW *);
1134PDCEX int wgetnstr(WINDOW *, char *, int);
1135PDCEX int wgetstr(WINDOW *, char *);
1136PDCEX int whline(WINDOW *, chtype, int);
1137PDCEX int winchnstr(WINDOW *, chtype *, int);
1138PDCEX int winchstr(WINDOW *, chtype *);
1139PDCEX chtype winch(WINDOW *);
1140PDCEX int winnstr(WINDOW *, char *, int);
1141PDCEX int winsch(WINDOW *, chtype);
1142PDCEX int winsdelln(WINDOW *, int);
1143PDCEX int winsertln(WINDOW *);
1144PDCEX int winsnstr(WINDOW *, const char *, int);
1145PDCEX int winsstr(WINDOW *, const char *);
1146PDCEX int winstr(WINDOW *, char *);
1147PDCEX int wmove(WINDOW *, int, int);
1148PDCEX int wnoutrefresh(WINDOW *);
1149PDCEX int wprintw(WINDOW *, const char *, ...);
1150PDCEX int wredrawln(WINDOW *, int, int);
1151PDCEX int wrefresh(WINDOW *);
1152PDCEX int wscanw(WINDOW *, const char *, ...);
1153PDCEX int wscrl(WINDOW *, int);
1154PDCEX int wsetscrreg(WINDOW *, int, int);
1155PDCEX int wstandend(WINDOW *);
1156PDCEX int wstandout(WINDOW *);
1157PDCEX void wsyncdown(WINDOW *);
1158PDCEX void wsyncup(WINDOW *);
1159PDCEX void wtimeout(WINDOW *, int);
1160PDCEX int wtouchln(WINDOW *, int, int, int);
1161PDCEX int wvline(WINDOW *, chtype, int);
1162
1163/* Wide-character functions */
1164
1165#ifdef PDC_WIDE
1166PDCEX int addnwstr(const wchar_t *, int);
1167PDCEX int addwstr(const wchar_t *);
1168PDCEX int add_wch(const cchar_t *);
1169PDCEX int add_wchnstr(const cchar_t *, int);
1170PDCEX int add_wchstr(const cchar_t *);
1171PDCEX int bkgrnd(const cchar_t *);
1172PDCEX void bkgrndset(const cchar_t *);
1173PDCEX int border_set(const cchar_t *, const cchar_t *, const cchar_t *,
1174 const cchar_t *, const cchar_t *, const cchar_t *,
1175 const cchar_t *, const cchar_t *);
1176PDCEX int box_set(WINDOW *, const cchar_t *, const cchar_t *);
1177PDCEX int echo_wchar(const cchar_t *);
1178PDCEX int erasewchar(wchar_t *);
1179PDCEX int getbkgrnd(cchar_t *);
1180PDCEX int getcchar(const cchar_t *, wchar_t *, attr_t *, short *, void *);
1181PDCEX int getn_wstr(wint_t *, int);
1182PDCEX int get_wch(wint_t *);
1183PDCEX int get_wstr(wint_t *);
1184PDCEX int hline_set(const cchar_t *, int);
1185PDCEX int innwstr(wchar_t *, int);
1186PDCEX int ins_nwstr(const wchar_t *, int);
1187PDCEX int ins_wch(const cchar_t *);
1188PDCEX int ins_wstr(const wchar_t *);
1189PDCEX int inwstr(wchar_t *);
1190PDCEX int in_wch(cchar_t *);
1191PDCEX int in_wchnstr(cchar_t *, int);
1192PDCEX int in_wchstr(cchar_t *);
1193PDCEX char *key_name(wchar_t);
1194PDCEX int killwchar(wchar_t *);
1195PDCEX int mvaddnwstr(int, int, const wchar_t *, int);
1196PDCEX int mvaddwstr(int, int, const wchar_t *);
1197PDCEX int mvadd_wch(int, int, const cchar_t *);
1198PDCEX int mvadd_wchnstr(int, int, const cchar_t *, int);
1199PDCEX int mvadd_wchstr(int, int, const cchar_t *);
1200PDCEX int mvgetn_wstr(int, int, wint_t *, int);
1201PDCEX int mvget_wch(int, int, wint_t *);
1202PDCEX int mvget_wstr(int, int, wint_t *);
1203PDCEX int mvhline_set(int, int, const cchar_t *, int);
1204PDCEX int mvinnwstr(int, int, wchar_t *, int);
1205PDCEX int mvins_nwstr(int, int, const wchar_t *, int);
1206PDCEX int mvins_wch(int, int, const cchar_t *);
1207PDCEX int mvins_wstr(int, int, const wchar_t *);
1208PDCEX int mvinwstr(int, int, wchar_t *);
1209PDCEX int mvin_wch(int, int, cchar_t *);
1210PDCEX int mvin_wchnstr(int, int, cchar_t *, int);
1211PDCEX int mvin_wchstr(int, int, cchar_t *);
1212PDCEX int mvvline_set(int, int, const cchar_t *, int);
1213PDCEX int mvwaddnwstr(WINDOW *, int, int, const wchar_t *, int);
1214PDCEX int mvwaddwstr(WINDOW *, int, int, const wchar_t *);
1215PDCEX int mvwadd_wch(WINDOW *, int, int, const cchar_t *);
1216PDCEX int mvwadd_wchnstr(WINDOW *, int, int, const cchar_t *, int);
1217PDCEX int mvwadd_wchstr(WINDOW *, int, int, const cchar_t *);
1218PDCEX int mvwgetn_wstr(WINDOW *, int, int, wint_t *, int);
1219PDCEX int mvwget_wch(WINDOW *, int, int, wint_t *);
1220PDCEX int mvwget_wstr(WINDOW *, int, int, wint_t *);
1221PDCEX int mvwhline_set(WINDOW *, int, int, const cchar_t *, int);
1222PDCEX int mvwinnwstr(WINDOW *, int, int, wchar_t *, int);
1223PDCEX int mvwins_nwstr(WINDOW *, int, int, const wchar_t *, int);
1224PDCEX int mvwins_wch(WINDOW *, int, int, const cchar_t *);
1225PDCEX int mvwins_wstr(WINDOW *, int, int, const wchar_t *);
1226PDCEX int mvwin_wch(WINDOW *, int, int, cchar_t *);
1227PDCEX int mvwin_wchnstr(WINDOW *, int, int, cchar_t *, int);
1228PDCEX int mvwin_wchstr(WINDOW *, int, int, cchar_t *);
1229PDCEX int mvwinwstr(WINDOW *, int, int, wchar_t *);
1230PDCEX int mvwvline_set(WINDOW *, int, int, const cchar_t *, int);
1231PDCEX int pecho_wchar(WINDOW *, const cchar_t*);
1232PDCEX int setcchar(cchar_t*, const wchar_t*, const attr_t,
1233 short, const void*);
1234PDCEX int slk_wset(int, const wchar_t *, int);
1235PDCEX int unget_wch(const wchar_t);
1236PDCEX int vline_set(const cchar_t *, int);
1237PDCEX int waddnwstr(WINDOW *, const wchar_t *, int);
1238PDCEX int waddwstr(WINDOW *, const wchar_t *);
1239PDCEX int wadd_wch(WINDOW *, const cchar_t *);
1240PDCEX int wadd_wchnstr(WINDOW *, const cchar_t *, int);
1241PDCEX int wadd_wchstr(WINDOW *, const cchar_t *);
1242PDCEX int wbkgrnd(WINDOW *, const cchar_t *);
1243PDCEX void wbkgrndset(WINDOW *, const cchar_t *);
1244PDCEX int wborder_set(WINDOW *, const cchar_t *, const cchar_t *,
1245 const cchar_t *, const cchar_t *, const cchar_t *,
1246 const cchar_t *, const cchar_t *, const cchar_t *);
1247PDCEX int wecho_wchar(WINDOW *, const cchar_t *);
1248PDCEX int wgetbkgrnd(WINDOW *, cchar_t *);
1249PDCEX int wgetn_wstr(WINDOW *, wint_t *, int);
1250PDCEX int wget_wch(WINDOW *, wint_t *);
1251PDCEX int wget_wstr(WINDOW *, wint_t *);
1252PDCEX int whline_set(WINDOW *, const cchar_t *, int);
1253PDCEX int winnwstr(WINDOW *, wchar_t *, int);
1254PDCEX int wins_nwstr(WINDOW *, const wchar_t *, int);
1255PDCEX int wins_wch(WINDOW *, const cchar_t *);
1256PDCEX int wins_wstr(WINDOW *, const wchar_t *);
1257PDCEX int winwstr(WINDOW *, wchar_t *);
1258PDCEX int win_wch(WINDOW *, cchar_t *);
1259PDCEX int win_wchnstr(WINDOW *, cchar_t *, int);
1260PDCEX int win_wchstr(WINDOW *, cchar_t *);
1261PDCEX wchar_t *wunctrl(cchar_t *);
1262PDCEX int wvline_set(WINDOW *, const cchar_t *, int);
1263#endif
1264
1265/* Quasi-standard */
1266
1267PDCEX chtype getattrs(WINDOW *);
1268PDCEX int getbegx(WINDOW *);
1269PDCEX int getbegy(WINDOW *);
1270PDCEX int getmaxx(WINDOW *);
1271PDCEX int getmaxy(WINDOW *);
1272PDCEX int getparx(WINDOW *);
1273PDCEX int getpary(WINDOW *);
1274PDCEX int getcurx(WINDOW *);
1275PDCEX int getcury(WINDOW *);
1276PDCEX void traceoff(void);
1277PDCEX void traceon(void);
1278PDCEX char *unctrl(chtype);
1279
1280PDCEX int crmode(void);
1281PDCEX int nocrmode(void);
1282PDCEX int draino(int);
1283PDCEX int resetterm(void);
1284PDCEX int fixterm(void);
1285PDCEX int saveterm(void);
1286PDCEX void setsyx(int, int);
1287
1288PDCEX int mouse_set(mmask_t);
1289PDCEX int mouse_on(mmask_t);
1290PDCEX int mouse_off(mmask_t);
1291PDCEX int request_mouse_pos(void);
1292PDCEX void wmouse_position(WINDOW *, int *, int *);
1293PDCEX mmask_t getmouse(void);
1294
1295/* ncurses */
1296
1297PDCEX int alloc_pair(int, int);
1298PDCEX int assume_default_colors(int, int);
1299PDCEX const char *curses_version(void);
1300PDCEX int find_pair(int, int);
1301PDCEX int free_pair(int);
1302PDCEX bool has_key(int);
1303PDCEX bool is_cleared(const WINDOW *);
1304PDCEX bool is_idcok(const WINDOW *);
1305PDCEX bool is_idlok(const WINDOW *);
1306PDCEX bool is_immedok(const WINDOW *);
1307PDCEX bool is_keypad(const WINDOW *);
1308PDCEX bool is_leaveok(const WINDOW *);
1309PDCEX bool is_nodelay(const WINDOW *);
1310PDCEX bool is_notimeout(const WINDOW *);
1311PDCEX bool is_pad(const WINDOW *);
1312PDCEX bool is_scrollok(const WINDOW *);
1313PDCEX bool is_subwin(const WINDOW *);
1314PDCEX bool is_syncok(const WINDOW *);
1315PDCEX int set_tabsize(int);
1316PDCEX int use_default_colors(void);
1317PDCEX int wgetdelay(const WINDOW *);
1318PDCEX WINDOW *wgetparent(const WINDOW *);
1319PDCEX int wgetscrreg(const WINDOW *, int *, int *);
1320PDCEX int wresize(WINDOW *, int, int);
1321
1322PDCEX bool has_mouse(void);
1323PDCEX int mouseinterval(int);
1324PDCEX mmask_t mousemask(mmask_t, mmask_t *);
1325PDCEX bool mouse_trafo(int *, int *, bool);
1326PDCEX int nc_getmouse(MEVENT *);
1327PDCEX int ungetmouse(MEVENT *);
1328PDCEX bool wenclose(const WINDOW *, int, int);
1329PDCEX bool wmouse_trafo(const WINDOW *, int *, int *, bool);
1330
1331/* PDCurses */
1332
1333PDCEX int addrawch(chtype);
1334PDCEX int insrawch(chtype);
1335PDCEX bool is_termresized(void);
1336PDCEX int mvaddrawch(int, int, chtype);
1337PDCEX int mvdeleteln(int, int);
1338PDCEX int mvinsertln(int, int);
1339PDCEX int mvinsrawch(int, int, chtype);
1340PDCEX int mvwaddrawch(WINDOW *, int, int, chtype);
1341PDCEX int mvwdeleteln(WINDOW *, int, int);
1342PDCEX int mvwinsertln(WINDOW *, int, int);
1343PDCEX int mvwinsrawch(WINDOW *, int, int, chtype);
1344PDCEX int raw_output(bool);
1345PDCEX int resize_term(int, int);
1346PDCEX WINDOW *resize_window(WINDOW *, int, int);
1347PDCEX int waddrawch(WINDOW *, chtype);
1348PDCEX int winsrawch(WINDOW *, chtype);
1349PDCEX char wordchar(void);
1350
1351#ifdef PDC_WIDE
1352PDCEX wchar_t *slk_wlabel(int);
1353#endif
1354
1355PDCEX void PDC_debug(const char *, ...);
1356PDCEX void PDC_get_version(PDC_VERSION *);
1357PDCEX int PDC_ungetch(int);
1358PDCEX int PDC_set_blink(bool);
1359PDCEX int PDC_set_bold(bool);
1360PDCEX int PDC_set_line_color(short);
1361PDCEX void PDC_set_title(const char *);
1362
1363PDCEX int PDC_clearclipboard(void);
1364PDCEX int PDC_freeclipboard(char *);
1365PDCEX int PDC_getclipboard(char **, long *);
1366PDCEX int PDC_setclipboard(const char *, long);
1367
1368PDCEX unsigned long PDC_get_key_modifiers(void);
1369PDCEX int PDC_return_key_modifiers(bool);
1370
1371#ifdef XCURSES
1372PDCEX WINDOW *Xinitscr(int, char **);
1373PDCEX void XCursesExit(void);
1374PDCEX int sb_init(void);
1375PDCEX int sb_set_horz(int, int, int);
1376PDCEX int sb_set_vert(int, int, int);
1377PDCEX int sb_get_horz(int *, int *, int *);
1378PDCEX int sb_get_vert(int *, int *, int *);
1379PDCEX int sb_refresh(void);
1380#endif
1381
1382/* NetBSD */
1383
1384PDCEX int touchoverlap(const WINDOW *, WINDOW *);
1385PDCEX int underend(void);
1386PDCEX int underscore(void);
1387PDCEX int wunderend(WINDOW *);
1388PDCEX int wunderscore(WINDOW *);
1389
1390/*** Functions defined as macros ***/
1391
1392/* getch() and ungetch() conflict with some DOS libraries */
1393
1394#define getch() wgetch(stdscr)
1395#define ungetch(ch) PDC_ungetch(ch)
1396
1397#define COLOR_PAIR(n) (((chtype)(n) << PDC_COLOR_SHIFT) & A_COLOR)
1398#define PAIR_NUMBER(n) (((n) & A_COLOR) >> PDC_COLOR_SHIFT)
1399
1400/* These will _only_ work as macros */
1401
1402#define getbegyx(w, y, x) (y = getbegy(w), x = getbegx(w))
1403#define getmaxyx(w, y, x) (y = getmaxy(w), x = getmaxx(w))
1404#define getparyx(w, y, x) (y = getpary(w), x = getparx(w))
1405#define getyx(w, y, x) (y = getcury(w), x = getcurx(w))
1406
1407#define getsyx(y, x) { if (curscr->_leaveit) (y)=(x)=-1; \
1408 else getyx(curscr,(y),(x)); }
1409
1410#ifdef NCURSES_MOUSE_VERSION
1411# define getmouse(x) nc_getmouse(x)
1412#endif
1413
1414/* Deprecated */
1415
1416#define PDC_save_key_modifiers(x) (OK)
1417#define PDC_get_input_fd() 0
1418
1419/* return codes from PDC_getclipboard() and PDC_setclipboard() calls */
1420
1421#define PDC_CLIP_SUCCESS 0
1422#define PDC_CLIP_ACCESS_ERROR 1
1423#define PDC_CLIP_EMPTY 2
1424#define PDC_CLIP_MEMORY_ERROR 3
1425
1426/* PDCurses key modifier masks */
1427
1428#define PDC_KEY_MODIFIER_SHIFT 1
1429#define PDC_KEY_MODIFIER_CONTROL 2
1430#define PDC_KEY_MODIFIER_ALT 4
1431#define PDC_KEY_MODIFIER_NUMLOCK 8
1432
1433#ifdef __cplusplus
1434# ifndef PDC_PP98
1435# undef bool
1436# endif
1437}
1438#endif
1439
1440#endif /* __PDCURSES__ */
diff --git a/scripts/kconfig/libcurses/curspriv.h b/scripts/kconfig/libcurses/curspriv.h
new file mode 100644
index 000000000..5a6ec1550
--- /dev/null
+++ b/scripts/kconfig/libcurses/curspriv.h
@@ -0,0 +1,133 @@
1/* Private definitions and declarations for use within PDCurses.
2 These should generally not be referenced by applications. */
3
4#ifndef __CURSES_INTERNALS__
5#define __CURSES_INTERNALS__ 1
6
7#define CURSES_LIBRARY
8#include "curses.h"
9
10#ifdef __cplusplus
11extern "C" {
12#endif
13
14#if defined(__TURBOC__) || defined(__EMX__) || defined(__DJGPP__) || \
15 defined(PDC_99) || defined(__WATCOMC__)
16# ifndef HAVE_VSSCANF
17# define HAVE_VSSCANF 1 /* have vsscanf() */
18# endif
19#endif
20
21#if defined(PDC_99) || defined(__WATCOMC__)
22# ifndef HAVE_SNPRINTF
23# define HAVE_SNPRINTF 1 /* have snprintf() */
24# endif
25# ifndef HAVE_VSNPRINTF
26# define HAVE_VSNPRINTF 1 /* have vsnprintf() */
27# endif
28#endif
29
30/*----------------------------------------------------------------------*/
31
32typedef struct /* structure for ripped off lines */
33{
34 int line;
35 int (*init)(WINDOW *, int);
36} RIPPEDOFFLINE;
37
38/* Window properties */
39
40#define _SUBWIN 0x01 /* window is a subwindow */
41#define _PAD 0x10 /* X/Open Pad. */
42#define _SUBPAD 0x20 /* X/Open subpad. */
43
44/* Miscellaneous */
45
46#define _NO_CHANGE -1 /* flags line edge unchanged */
47
48#define _ECHAR 0x08 /* Erase char (^H) */
49#define _DWCHAR 0x17 /* Delete Word char (^W) */
50#define _DLCHAR 0x15 /* Delete Line char (^U) */
51
52/*----------------------------------------------------------------------*/
53
54/* Platform implementation functions */
55
56void PDC_beep(void);
57bool PDC_can_change_color(void);
58int PDC_color_content(short, short *, short *, short *);
59bool PDC_check_key(void);
60int PDC_curs_set(int);
61void PDC_doupdate(void);
62void PDC_flushinp(void);
63int PDC_get_columns(void);
64int PDC_get_cursor_mode(void);
65int PDC_get_key(void);
66int PDC_get_rows(void);
67void PDC_gotoyx(int, int);
68bool PDC_has_mouse(void);
69int PDC_init_color(short, short, short, short);
70int PDC_modifiers_set(void);
71int PDC_mouse_set(void);
72void PDC_napms(int);
73void PDC_reset_prog_mode(void);
74void PDC_reset_shell_mode(void);
75int PDC_resize_screen(int, int);
76void PDC_restore_screen_mode(int);
77void PDC_save_screen_mode(int);
78#ifdef XCURSES
79void PDC_set_args(int, char **);
80#endif
81void PDC_scr_close(void);
82void PDC_scr_free(void);
83int PDC_scr_open(void);
84void PDC_set_keyboard_binary(bool);
85void PDC_transform_line(int, int, int, const chtype *);
86const char *PDC_sysname(void);
87
88/* Internal cross-module functions */
89
90void PDC_init_atrtab(void);
91WINDOW *PDC_makelines(WINDOW *);
92WINDOW *PDC_makenew(int, int, int, int);
93int PDC_mouse_in_slk(int, int);
94void PDC_slk_free(void);
95void PDC_slk_initialize(void);
96void PDC_sync(WINDOW *);
97
98#ifdef PDC_WIDE
99int PDC_mbtowc(wchar_t *, const char *, size_t);
100size_t PDC_mbstowcs(wchar_t *, const char *, size_t);
101size_t PDC_wcstombs(char *, const wchar_t *, size_t);
102#endif
103
104#ifdef PDCDEBUG
105# define PDC_LOG(x) if (SP && SP->dbfp) PDC_debug x
106#else
107# define PDC_LOG(x)
108#endif
109
110/* Internal macros for attributes */
111
112#ifndef max
113# define max(a,b) (((a) > (b)) ? (a) : (b))
114#endif
115#ifndef min
116# define min(a,b) (((a) < (b)) ? (a) : (b))
117#endif
118
119#define DIVROUND(num, divisor) ((num) + ((divisor) >> 1)) / (divisor)
120
121#define PDC_CLICK_PERIOD 150 /* time to wait for a click, if
122 not set by mouseinterval() */
123#define PDC_COLOR_PAIRS 256
124#define PDC_MAXCOL 768 /* maximum possible COLORS; may be less */
125
126#define _INBUFSIZ 512 /* size of terminal input buffer */
127#define NUNGETCH 256 /* max # chars to ungetch() */
128
129#ifdef __cplusplus
130}
131#endif
132
133#endif /* __CURSES_INTERNALS__ */
diff --git a/scripts/kconfig/libcurses/getch.c b/scripts/kconfig/libcurses/getch.c
new file mode 100644
index 000000000..8719ca39c
--- /dev/null
+++ b/scripts/kconfig/libcurses/getch.c
@@ -0,0 +1,589 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7getch
8-----
9
10### Synopsis
11
12 int getch(void);
13 int wgetch(WINDOW *win);
14 int mvgetch(int y, int x);
15 int mvwgetch(WINDOW *win, int y, int x);
16 int ungetch(int ch);
17 int flushinp(void);
18
19 int get_wch(wint_t *wch);
20 int wget_wch(WINDOW *win, wint_t *wch);
21 int mvget_wch(int y, int x, wint_t *wch);
22 int mvwget_wch(WINDOW *win, int y, int x, wint_t *wch);
23 int unget_wch(const wchar_t wch);
24
25 unsigned long PDC_get_key_modifiers(void);
26 int PDC_return_key_modifiers(bool flag);
27
28### Description
29
30 With the getch(), wgetch(), mvgetch(), and mvwgetch() functions, a
31 character is read from the terminal associated with the window. In
32 nodelay mode, if there is no input waiting, the value ERR is
33 returned. In delay mode, the program will hang until the system
34 passes text through to the program. Depending on the setting of
35 cbreak(), this will be after one character or after the first
36 newline. Unless noecho() has been set, the character will also be
37 echoed into the designated window.
38
39 If keypad() is TRUE, and a function key is pressed, the token for
40 that function key will be returned instead of the raw characters.
41 Possible function keys are defined in "curses.h" with integers
42 beginning with 0401, whose names begin with KEY_.
43
44 If nodelay(win, TRUE) has been called on the window and no input is
45 waiting, the value ERR is returned.
46
47 ungetch() places ch back onto the input queue to be returned by the
48 next call to wgetch().
49
50 flushinp() throws away any type-ahead that has been typed by the user
51 and has not yet been read by the program.
52
53 wget_wch() is the wide-character version of wgetch(), available when
54 PDCurses is built with the PDC_WIDE option. It takes a pointer to a
55 wint_t rather than returning the key as an int, and instead returns
56 KEY_CODE_YES if the key is a function key. Otherwise, it returns OK
57 or ERR. It's important to check for KEY_CODE_YES, since regular wide
58 characters can have the same values as function key codes.
59
60 unget_wch() puts a wide character on the input queue.
61
62 PDC_get_key_modifiers() returns the keyboard modifiers (shift,
63 control, alt, numlock) effective at the time of the last getch()
64 call. Use the macros PDC_KEY_MODIFIER_* to determine which
65 modifier(s) were set. PDC_return_key_modifiers() tells getch() to
66 return modifier keys pressed alone as keystrokes (KEY_ALT_L, etc.).
67 These may not work on all platforms.
68
69 NOTE: getch() and ungetch() are implemented as macros, to avoid
70 conflict with many DOS compiler's runtime libraries.
71
72### Return Value
73
74 These functions return ERR or the value of the character, meta
75 character or function key token.
76
77### Portability
78 X/Open ncurses NetBSD
79 getch Y Y Y
80 wgetch Y Y Y
81 mvgetch Y Y Y
82 mvwgetch Y Y Y
83 ungetch Y Y Y
84 flushinp Y Y Y
85 get_wch Y Y Y
86 wget_wch Y Y Y
87 mvget_wch Y Y Y
88 mvwget_wch Y Y Y
89 unget_wch Y Y Y
90 PDC_get_key_modifiers - - -
91
92**man-end****************************************************************/
93
94#include <stdlib.h>
95
96static int _get_box(int *y_start, int *y_end, int *x_start, int *x_end)
97{
98 int start, end;
99
100 if (SP->sel_start < SP->sel_end)
101 {
102 start = SP->sel_start;
103 end = SP->sel_end;
104 }
105 else
106 {
107 start = SP->sel_end;
108 end = SP->sel_start;
109 }
110
111 *y_start = start / COLS;
112 *x_start = start % COLS;
113
114 *y_end = end / COLS;
115 *x_end = end % COLS;
116
117 return (end - start) + (*y_end - *y_start);
118}
119
120static void _highlight(void)
121{
122 int i, j, y_start, y_end, x_start, x_end;
123
124 if (-1 == SP->sel_start)
125 return;
126
127 _get_box(&y_start, &y_end, &x_start, &x_end);
128
129 for (j = y_start; j <= y_end; j++)
130 for (i = (j == y_start ? x_start : 0);
131 i < (j == y_end ? x_end : COLS); i++)
132 curscr->_y[j][i] ^= A_REVERSE;
133
134 wrefresh(curscr);
135}
136
137static void _copy(void)
138{
139#ifdef PDC_WIDE
140 wchar_t *wtmp;
141# define TMP wtmp
142# define MASK A_CHARTEXT
143#else
144# define TMP tmp
145# define MASK 0xff
146#endif
147 char *tmp;
148 long pos;
149 int i, j, y_start, y_end, x_start, x_end, len;
150
151 if (-1 == SP->sel_start)
152 return;
153
154 len = _get_box(&y_start, &y_end, &x_start, &x_end);
155
156 if (!len)
157 return;
158
159#ifdef PDC_WIDE
160 wtmp = malloc((len + 1) * sizeof(wchar_t));
161 len *= 4;
162#endif
163 tmp = malloc(len + 1);
164
165 for (j = y_start, pos = 0; j <= y_end; j++)
166 {
167 for (i = (j == y_start ? x_start : 0);
168 i < (j == y_end ? x_end : COLS); i++)
169 TMP[pos++] = curscr->_y[j][i] & MASK;
170
171 while (y_start != y_end && pos > 0 && TMP[pos - 1] == 32)
172 pos--;
173
174 if (j < y_end)
175 TMP[pos++] = 10;
176 }
177 TMP[pos] = 0;
178
179#ifdef PDC_WIDE
180 pos = PDC_wcstombs(tmp, wtmp, len);
181#endif
182
183 PDC_setclipboard(tmp, pos);
184 free(tmp);
185#ifdef PDC_WIDE
186 free(wtmp);
187#endif
188}
189
190static int _paste(void)
191{
192#ifdef PDC_WIDE
193 wchar_t *wpaste;
194# define PASTE wpaste
195#else
196# define PASTE paste
197#endif
198 char *paste;
199 long len, newmax;
200 int key;
201
202 key = PDC_getclipboard(&paste, &len);
203 if (PDC_CLIP_SUCCESS != key || !len)
204 return -1;
205
206#ifdef PDC_WIDE
207 wpaste = malloc(len * sizeof(wchar_t));
208 len = PDC_mbstowcs(wpaste, paste, len);
209#endif
210 newmax = len + SP->c_ungind;
211 if (newmax > SP->c_ungmax)
212 {
213 SP->c_ungch = realloc(SP->c_ungch, newmax * sizeof(int));
214 if (!SP->c_ungch)
215 return -1;
216 SP->c_ungmax = newmax;
217 }
218 while (len > 1)
219 PDC_ungetch(PASTE[--len]);
220 key = *PASTE;
221#ifdef PDC_WIDE
222 free(wpaste);
223#endif
224 PDC_freeclipboard(paste);
225 SP->key_modifiers = 0;
226
227 return key;
228}
229
230static int _mouse_key(void)
231{
232 int i, key = KEY_MOUSE, changes = SP->mouse_status.changes;
233 unsigned long mbe = SP->_trap_mbe;
234
235 /* Selection highlighting? */
236
237 if ((!mbe || SP->mouse_status.button[0] & BUTTON_SHIFT) && changes & 1)
238 {
239 i = SP->mouse_status.y * COLS + SP->mouse_status.x;
240 switch (SP->mouse_status.button[0] & BUTTON_ACTION_MASK)
241 {
242 case BUTTON_PRESSED:
243 _highlight();
244 SP->sel_start = SP->sel_end = i;
245 return -1;
246 case BUTTON_MOVED:
247 _highlight();
248 SP->sel_end = i;
249 _highlight();
250 return -1;
251 case BUTTON_RELEASED:
252 _copy();
253 return -1;
254 }
255 }
256 else if ((!mbe || SP->mouse_status.button[1] & BUTTON_SHIFT) &&
257 changes & 2 && (SP->mouse_status.button[1] &
258 BUTTON_ACTION_MASK) == BUTTON_CLICKED)
259 {
260 SP->key_code = FALSE;
261 return _paste();
262 }
263
264 /* Filter unwanted mouse events */
265
266 for (i = 0; i < 3; i++)
267 {
268 if (changes & (1 << i))
269 {
270 int shf = i * 5;
271 short button = SP->mouse_status.button[i] & BUTTON_ACTION_MASK;
272
273 if ( (!(mbe & (BUTTON1_PRESSED << shf)) &&
274 (button == BUTTON_PRESSED))
275
276 || (!(mbe & (BUTTON1_CLICKED << shf)) &&
277 (button == BUTTON_CLICKED))
278
279 || (!(mbe & (BUTTON1_DOUBLE_CLICKED << shf)) &&
280 (button == BUTTON_DOUBLE_CLICKED))
281
282 || (!(mbe & (BUTTON1_MOVED << shf)) &&
283 (button == BUTTON_MOVED))
284
285 || (!(mbe & (BUTTON1_RELEASED << shf)) &&
286 (button == BUTTON_RELEASED))
287 )
288 SP->mouse_status.changes ^= (1 << i);
289 }
290 }
291
292 if (changes & PDC_MOUSE_MOVED)
293 {
294 if (!(mbe & (BUTTON1_MOVED|BUTTON2_MOVED|BUTTON3_MOVED)))
295 SP->mouse_status.changes ^= PDC_MOUSE_MOVED;
296 }
297
298 if (changes & (PDC_MOUSE_WHEEL_UP|PDC_MOUSE_WHEEL_DOWN))
299 {
300 if (!(mbe & MOUSE_WHEEL_SCROLL))
301 SP->mouse_status.changes &=
302 ~(PDC_MOUSE_WHEEL_UP|PDC_MOUSE_WHEEL_DOWN);
303 }
304
305 if (!changes)
306 return -1;
307
308 /* Check for click in slk area */
309
310 i = PDC_mouse_in_slk(SP->mouse_status.y, SP->mouse_status.x);
311
312 if (i)
313 {
314 if (SP->mouse_status.button[0] & (BUTTON_PRESSED|BUTTON_CLICKED))
315 key = KEY_F(i);
316 else
317 key = -1;
318 }
319
320 return key;
321}
322
323int wgetch(WINDOW *win)
324{
325 int key, waitcount;
326
327 PDC_LOG(("wgetch() - called\n"));
328
329 if (!win || !SP)
330 return ERR;
331
332 waitcount = 0;
333
334 /* set the number of 1/20th second napms() calls */
335
336 if (SP->delaytenths)
337 waitcount = 2 * SP->delaytenths;
338 else
339 if (win->_delayms)
340 {
341 /* Can't really do millisecond intervals, so delay in
342 1/20ths of a second (50ms) */
343
344 waitcount = win->_delayms / 50;
345 if (!waitcount)
346 waitcount = 1;
347 }
348
349 /* refresh window when wgetch is called if there have been changes
350 to it and it is not a pad */
351
352 if (!(win->_flags & _PAD) && ((!win->_leaveit &&
353 (win->_begx + win->_curx != SP->curscol ||
354 win->_begy + win->_cury != SP->cursrow)) || is_wintouched(win)))
355 wrefresh(win);
356
357 /* if ungotten char exists, remove and return it */
358
359 if (SP->c_ungind)
360 return SP->c_ungch[--(SP->c_ungind)];
361
362 /* if normal and data in buffer */
363
364 if ((!SP->raw_inp && !SP->cbreak) && (SP->c_gindex < SP->c_pindex))
365 return SP->c_buffer[SP->c_gindex++];
366
367 /* prepare to buffer data */
368
369 SP->c_pindex = 0;
370 SP->c_gindex = 0;
371
372 /* to get here, no keys are buffered. go and get one. */
373
374 for (;;) /* loop for any buffering */
375 {
376 /* is there a keystroke ready? */
377
378 if (!PDC_check_key())
379 {
380 /* if not, handle timeout() and halfdelay() */
381
382 if (SP->delaytenths || win->_delayms)
383 {
384 if (!waitcount)
385 return ERR;
386
387 waitcount--;
388 }
389 else
390 if (win->_nodelay)
391 return ERR;
392
393 napms(50); /* sleep for 1/20th second */
394 continue; /* then check again */
395 }
396
397 /* if there is, fetch it */
398
399 key = PDC_get_key();
400
401 /* copy or paste? */
402
403 if (SP->key_modifiers & PDC_KEY_MODIFIER_SHIFT)
404 {
405 if (0x03 == key)
406 {
407 _copy();
408 continue;
409 }
410 else if (0x16 == key)
411 key = _paste();
412 }
413
414 /* filter mouse events; translate mouse clicks in the slk
415 area to function keys */
416
417 if (SP->key_code && key == KEY_MOUSE)
418 key = _mouse_key();
419
420 /* filter special keys if not in keypad mode */
421
422 if (SP->key_code && !win->_use_keypad)
423 key = -1;
424
425 /* unwanted key? loop back */
426
427 if (key == -1)
428 continue;
429
430 _highlight();
431 SP->sel_start = SP->sel_end = -1;
432
433 /* translate CR */
434
435 if (key == '\r' && SP->autocr && !SP->raw_inp)
436 key = '\n';
437
438 /* if echo is enabled */
439
440 if (SP->echo && !SP->key_code)
441 {
442 waddch(win, key);
443 wrefresh(win);
444 }
445
446 /* if no buffering */
447
448 if (SP->raw_inp || SP->cbreak)
449 return key;
450
451 /* if no overflow, put data in buffer */
452
453 if (key == '\b')
454 {
455 if (SP->c_pindex > SP->c_gindex)
456 SP->c_pindex--;
457 }
458 else
459 if (SP->c_pindex < _INBUFSIZ - 2)
460 SP->c_buffer[SP->c_pindex++] = key;
461
462 /* if we got a line */
463
464 if (key == '\n' || key == '\r')
465 return SP->c_buffer[SP->c_gindex++];
466 }
467}
468
469int mvgetch(int y, int x)
470{
471 PDC_LOG(("mvgetch() - called\n"));
472
473 if (move(y, x) == ERR)
474 return ERR;
475
476 return wgetch(stdscr);
477}
478
479int mvwgetch(WINDOW *win, int y, int x)
480{
481 PDC_LOG(("mvwgetch() - called\n"));
482
483 if (wmove(win, y, x) == ERR)
484 return ERR;
485
486 return wgetch(win);
487}
488
489int PDC_ungetch(int ch)
490{
491 PDC_LOG(("ungetch() - called\n"));
492
493 if (SP->c_ungind >= SP->c_ungmax) /* pushback stack full */
494 return ERR;
495
496 SP->c_ungch[SP->c_ungind++] = ch;
497
498 return OK;
499}
500
501int flushinp(void)
502{
503 PDC_LOG(("flushinp() - called\n"));
504
505 if (!SP)
506 return ERR;
507
508 PDC_flushinp();
509
510 SP->c_gindex = 1; /* set indices to kill buffer */
511 SP->c_pindex = 0;
512 SP->c_ungind = 0; /* clear SP->c_ungch array */
513
514 return OK;
515}
516
517unsigned long PDC_get_key_modifiers(void)
518{
519 PDC_LOG(("PDC_get_key_modifiers() - called\n"));
520
521 if (!SP)
522 return ERR;
523
524 return SP->key_modifiers;
525}
526
527int PDC_return_key_modifiers(bool flag)
528{
529 PDC_LOG(("PDC_return_key_modifiers() - called\n"));
530
531 if (!SP)
532 return ERR;
533
534 SP->return_key_modifiers = flag;
535 return PDC_modifiers_set();
536}
537
538#ifdef PDC_WIDE
539int wget_wch(WINDOW *win, wint_t *wch)
540{
541 int key;
542
543 PDC_LOG(("wget_wch() - called\n"));
544
545 if (!wch)
546 return ERR;
547
548 key = wgetch(win);
549
550 if (key == ERR)
551 return ERR;
552
553 *wch = key;
554
555 return SP->key_code ? KEY_CODE_YES : OK;
556}
557
558int get_wch(wint_t *wch)
559{
560 PDC_LOG(("get_wch() - called\n"));
561
562 return wget_wch(stdscr, wch);
563}
564
565int mvget_wch(int y, int x, wint_t *wch)
566{
567 PDC_LOG(("mvget_wch() - called\n"));
568
569 if (move(y, x) == ERR)
570 return ERR;
571
572 return wget_wch(stdscr, wch);
573}
574
575int mvwget_wch(WINDOW *win, int y, int x, wint_t *wch)
576{
577 PDC_LOG(("mvwget_wch() - called\n"));
578
579 if (wmove(win, y, x) == ERR)
580 return ERR;
581
582 return wget_wch(win, wch);
583}
584
585int unget_wch(const wchar_t wch)
586{
587 return PDC_ungetch(wch);
588}
589#endif
diff --git a/scripts/kconfig/libcurses/getyx.c b/scripts/kconfig/libcurses/getyx.c
new file mode 100644
index 000000000..5f104df99
--- /dev/null
+++ b/scripts/kconfig/libcurses/getyx.c
@@ -0,0 +1,142 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7getyx
8-----
9
10### Synopsis
11
12 void getyx(WINDOW *win, int y, int x);
13 void getparyx(WINDOW *win, int y, int x);
14 void getbegyx(WINDOW *win, int y, int x);
15 void getmaxyx(WINDOW *win, int y, int x);
16
17 void getsyx(int y, int x);
18 void setsyx(int y, int x);
19
20 int getbegy(WINDOW *win);
21 int getbegx(WINDOW *win);
22 int getcury(WINDOW *win);
23 int getcurx(WINDOW *win);
24 int getpary(WINDOW *win);
25 int getparx(WINDOW *win);
26 int getmaxy(WINDOW *win);
27 int getmaxx(WINDOW *win);
28
29### Description
30
31 The getyx() macro (defined in curses.h -- the prototypes here are
32 merely illustrative) puts the current cursor position of the
33 specified window into y and x. getbegyx() and getmaxyx() return the
34 starting coordinates and size of the specified window, respectively.
35 getparyx() returns the starting coordinates of the parent's window,
36 if the specified window is a subwindow; otherwise it sets y and x to
37 -1. These are all macros.
38
39 getsyx() gets the coordinates of the virtual screen cursor, and
40 stores them in y and x. If leaveok() is TRUE, it returns -1, -1. If
41 lines have been removed with ripoffline(), then getsyx() includes
42 these lines in its count; so, the returned y and x values should only
43 be used with setsyx().
44
45 setsyx() sets the virtual screen cursor to the y, x coordinates. If
46 either y or x is -1, leaveok() is set TRUE, else it's set FALSE.
47
48 getsyx() and setsyx() are meant to be used by a library routine that
49 manipulates curses windows without altering the position of the
50 cursor. Note that getsyx() is defined only as a macro.
51
52 getbegy(), getbegx(), getcurx(), getcury(), getmaxy(), getmaxx(),
53 getpary(), and getparx() return the appropriate coordinate or size
54 values, or ERR in the case of a NULL window.
55
56### Portability
57 X/Open ncurses NetBSD
58 getyx Y Y Y
59 getparyx Y Y Y
60 getbegyx Y Y Y
61 getmaxyx Y Y Y
62 getsyx - Y Y
63 setsyx - Y Y
64 getbegy - Y Y
65 getbegx - Y Y
66 getcury - Y Y
67 getcurx - Y Y
68 getpary - Y Y
69 getparx - Y Y
70 getmaxy - Y Y
71 getmaxx - Y Y
72
73**man-end****************************************************************/
74
75int getbegy(WINDOW *win)
76{
77 PDC_LOG(("getbegy() - called\n"));
78
79 return win ? win->_begy : ERR;
80}
81
82int getbegx(WINDOW *win)
83{
84 PDC_LOG(("getbegx() - called\n"));
85
86 return win ? win->_begx : ERR;
87}
88
89int getcury(WINDOW *win)
90{
91 PDC_LOG(("getcury() - called\n"));
92
93 return win ? win->_cury : ERR;
94}
95
96int getcurx(WINDOW *win)
97{
98 PDC_LOG(("getcurx() - called\n"));
99
100 return win ? win->_curx : ERR;
101}
102
103int getpary(WINDOW *win)
104{
105 PDC_LOG(("getpary() - called\n"));
106
107 return win ? win->_pary : ERR;
108}
109
110int getparx(WINDOW *win)
111{
112 PDC_LOG(("getparx() - called\n"));
113
114 return win ? win->_parx : ERR;
115}
116
117int getmaxy(WINDOW *win)
118{
119 PDC_LOG(("getmaxy() - called\n"));
120
121 return win ? win->_maxy : ERR;
122}
123
124int getmaxx(WINDOW *win)
125{
126 PDC_LOG(("getmaxx() - called\n"));
127
128 return win ? win->_maxx : ERR;
129}
130
131void setsyx(int y, int x)
132{
133 PDC_LOG(("setsyx() - called\n"));
134
135 if (curscr)
136 {
137 curscr->_leaveit = y == -1 || x == -1;
138
139 if (!curscr->_leaveit)
140 wmove(curscr, y, x);
141 }
142}
diff --git a/scripts/kconfig/libcurses/inch.c b/scripts/kconfig/libcurses/inch.c
new file mode 100644
index 000000000..2bd4430f6
--- /dev/null
+++ b/scripts/kconfig/libcurses/inch.c
@@ -0,0 +1,126 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7inch
8----
9
10### Synopsis
11
12 chtype inch(void);
13 chtype winch(WINDOW *win);
14 chtype mvinch(int y, int x);
15 chtype mvwinch(WINDOW *win, int y, int x);
16
17 int in_wch(cchar_t *wcval);
18 int win_wch(WINDOW *win, cchar_t *wcval);
19 int mvin_wch(int y, int x, cchar_t *wcval);
20 int mvwin_wch(WINDOW *win, int y, int x, cchar_t *wcval);
21
22### Description
23
24 The inch() functions retrieve the character and attribute from the
25 current or specified window position, in the form of a chtype. If a
26 NULL window is specified, (chtype)ERR is returned.
27
28 The in_wch() functions are the wide-character versions; instead of
29 returning a chtype, they store a cchar_t at the address specified by
30 wcval, and return OK or ERR. (No value is stored when ERR is
31 returned.) Note that in PDCurses, chtype and cchar_t are the same.
32
33### Portability
34 X/Open ncurses NetBSD
35 inch Y Y Y
36 winch Y Y Y
37 mvinch Y Y Y
38 mvwinch Y Y Y
39 in_wch Y Y Y
40 win_wch Y Y Y
41 mvin_wch Y Y Y
42 mvwin_wch Y Y Y
43
44**man-end****************************************************************/
45
46chtype winch(WINDOW *win)
47{
48 PDC_LOG(("winch() - called\n"));
49
50 if (!win)
51 return (chtype)ERR;
52
53 return win->_y[win->_cury][win->_curx];
54}
55
56chtype inch(void)
57{
58 PDC_LOG(("inch() - called\n"));
59
60 return winch(stdscr);
61}
62
63chtype mvinch(int y, int x)
64{
65 PDC_LOG(("mvinch() - called\n"));
66
67 if (move(y, x) == ERR)
68 return (chtype)ERR;
69
70 return stdscr->_y[stdscr->_cury][stdscr->_curx];
71}
72
73chtype mvwinch(WINDOW *win, int y, int x)
74{
75 PDC_LOG(("mvwinch() - called\n"));
76
77 if (wmove(win, y, x) == ERR)
78 return (chtype)ERR;
79
80 return win->_y[win->_cury][win->_curx];
81}
82
83#ifdef PDC_WIDE
84int win_wch(WINDOW *win, cchar_t *wcval)
85{
86 PDC_LOG(("win_wch() - called\n"));
87
88 if (!win || !wcval)
89 return ERR;
90
91 *wcval = win->_y[win->_cury][win->_curx];
92
93 return OK;
94}
95
96int in_wch(cchar_t *wcval)
97{
98 PDC_LOG(("in_wch() - called\n"));
99
100 return win_wch(stdscr, wcval);
101}
102
103int mvin_wch(int y, int x, cchar_t *wcval)
104{
105 PDC_LOG(("mvin_wch() - called\n"));
106
107 if (!wcval || (move(y, x) == ERR))
108 return ERR;
109
110 *wcval = stdscr->_y[stdscr->_cury][stdscr->_curx];
111
112 return OK;
113}
114
115int mvwin_wch(WINDOW *win, int y, int x, cchar_t *wcval)
116{
117 PDC_LOG(("mvwin_wch() - called\n"));
118
119 if (!wcval || (wmove(win, y, x) == ERR))
120 return ERR;
121
122 *wcval = win->_y[win->_cury][win->_curx];
123
124 return OK;
125}
126#endif
diff --git a/scripts/kconfig/libcurses/initscr.c b/scripts/kconfig/libcurses/initscr.c
new file mode 100644
index 000000000..66940a3cf
--- /dev/null
+++ b/scripts/kconfig/libcurses/initscr.c
@@ -0,0 +1,431 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7initscr
8-------
9
10### Synopsis
11
12 WINDOW *initscr(void);
13 WINDOW *Xinitscr(int argc, char **argv);
14 int endwin(void);
15 bool isendwin(void);
16 SCREEN *newterm(const char *type, FILE *outfd, FILE *infd);
17 SCREEN *set_term(SCREEN *new);
18 void delscreen(SCREEN *sp);
19
20 int resize_term(int nlines, int ncols);
21 bool is_termresized(void);
22 const char *curses_version(void);
23 void PDC_get_version(PDC_VERSION *ver);
24
25 int set_tabsize(int tabsize);
26
27### Description
28
29 initscr() should be the first curses routine called. It will
30 initialize all curses data structures, and arrange that the first
31 call to refresh() will clear the screen. In case of error, initscr()
32 will write a message to standard error and end the program.
33
34 endwin() should be called before exiting or escaping from curses mode
35 temporarily. It will restore tty modes, move the cursor to the lower
36 left corner of the screen and reset the terminal into the proper
37 non-visual mode. To resume curses after a temporary escape, call
38 refresh() or doupdate().
39
40 isendwin() returns TRUE if endwin() has been called without a
41 subsequent refresh, unless SP is NULL.
42
43 In some implementations of curses, newterm() allows the use of
44 multiple terminals. Here, it's just an alternative interface for
45 initscr(). It always returns SP, or NULL.
46
47 delscreen() frees the memory allocated by newterm() or initscr(),
48 since it's not freed by endwin(). This function is usually not
49 needed. In PDCurses, the parameter must be the value of SP, and
50 delscreen() sets SP to NULL.
51
52 set_term() does nothing meaningful in PDCurses, but is included for
53 compatibility with other curses implementations.
54
55 resize_term() is effectively two functions: When called with nonzero
56 values for nlines and ncols, it attempts to resize the screen to the
57 given size. When called with (0, 0), it merely adjusts the internal
58 structures to match the current size after the screen is resized by
59 the user. On the currently supported platforms, SDL, Windows console,
60 and X11 allow user resizing, while DOS, OS/2, SDL and Windows console
61 allow programmatic resizing. If you want to support user resizing,
62 you should check for getch() returning KEY_RESIZE, and/or call
63 is_termresized() at appropriate times; if either condition occurs,
64 call resize_term(0, 0). Then, with either user or programmatic
65 resizing, you'll have to resize any windows you've created, as
66 appropriate; resize_term() only handles stdscr and curscr.
67
68 is_termresized() returns TRUE if the curses screen has been resized
69 by the user, and a call to resize_term() is needed. Checking for
70 KEY_RESIZE is generally preferable, unless you're not handling the
71 keyboard.
72
73 curses_version() returns a string describing the version of PDCurses.
74
75 PDC_get_version() fills a PDC_VERSION structure provided by the user
76 with more detailed version info (see curses.h).
77
78 set_tabsize() sets the tab interval, stored in TABSIZE.
79
80### Return Value
81
82 All functions return NULL on error, except endwin(), which always
83 returns OK, and resize_term(), which returns either OK or ERR.
84
85### Portability
86 X/Open ncurses NetBSD
87 initscr Y Y Y
88 endwin Y Y Y
89 isendwin Y Y Y
90 newterm Y Y Y
91 set_term Y Y Y
92 delscreen Y Y Y
93 resize_term - Y Y
94 set_tabsize - Y Y
95 curses_version - Y -
96 is_termresized - - -
97
98**man-end****************************************************************/
99
100#include <stdlib.h>
101
102char ttytype[128];
103
104const char *_curses_notice = "PDCurses " PDC_VERDOT " - " __DATE__;
105
106SCREEN *SP = (SCREEN*)NULL; /* curses variables */
107WINDOW *curscr = (WINDOW *)NULL; /* the current screen image */
108WINDOW *stdscr = (WINDOW *)NULL; /* the default screen window */
109
110int LINES = 0; /* current terminal height */
111int COLS = 0; /* current terminal width */
112int TABSIZE = 8;
113
114MOUSE_STATUS Mouse_status;
115
116extern RIPPEDOFFLINE linesripped[5];
117extern char linesrippedoff;
118
119WINDOW *initscr(void)
120{
121 int i;
122
123 PDC_LOG(("initscr() - called\n"));
124
125 if (SP && SP->alive)
126 return NULL;
127
128 SP = calloc(1, sizeof(SCREEN));
129 if (!SP)
130 return NULL;
131
132 if (PDC_scr_open() == ERR)
133 {
134 fprintf(stderr, "initscr(): Unable to create SP\n");
135 exit(8);
136 }
137
138 SP->autocr = TRUE; /* cr -> lf by default */
139 SP->raw_out = FALSE; /* tty I/O modes */
140 SP->raw_inp = FALSE; /* tty I/O modes */
141 SP->cbreak = TRUE;
142 SP->key_modifiers = 0L;
143 SP->return_key_modifiers = FALSE;
144 SP->echo = TRUE;
145 SP->visibility = 1;
146 SP->resized = FALSE;
147 SP->_trap_mbe = 0L;
148 SP->linesrippedoff = 0;
149 SP->linesrippedoffontop = 0;
150 SP->delaytenths = 0;
151 SP->line_color = -1;
152 SP->lastscr = (WINDOW *)NULL;
153 SP->dbfp = NULL;
154 SP->color_started = FALSE;
155 SP->dirty = FALSE;
156 SP->sel_start = -1;
157 SP->sel_end = -1;
158
159 SP->orig_cursor = PDC_get_cursor_mode();
160
161 LINES = SP->lines = PDC_get_rows();
162 COLS = SP->cols = PDC_get_columns();
163
164 if (LINES < 2 || COLS < 2)
165 {
166 fprintf(stderr, "initscr(): LINES=%d COLS=%d: too small.\n",
167 LINES, COLS);
168 exit(4);
169 }
170
171 curscr = newwin(LINES, COLS, 0, 0);
172 if (!curscr)
173 {
174 fprintf(stderr, "initscr(): Unable to create curscr.\n");
175 exit(2);
176 }
177
178 SP->lastscr = newwin(LINES, COLS, 0, 0);
179 if (!SP->lastscr)
180 {
181 fprintf(stderr, "initscr(): Unable to create SP->lastscr.\n");
182 exit(2);
183 }
184
185 wattrset(SP->lastscr, (chtype)(-1));
186 werase(SP->lastscr);
187
188 PDC_slk_initialize();
189 LINES -= SP->slklines;
190
191 /* We have to sort out ripped off lines here, and reduce the height
192 of stdscr by the number of lines ripped off */
193
194 for (i = 0; i < linesrippedoff; i++)
195 {
196 if (linesripped[i].line < 0)
197 (*linesripped[i].init)(newwin(1, COLS, LINES - 1, 0), COLS);
198 else
199 (*linesripped[i].init)(newwin(1, COLS,
200 SP->linesrippedoffontop++, 0), COLS);
201
202 SP->linesrippedoff++;
203 LINES--;
204 }
205
206 linesrippedoff = 0;
207
208 stdscr = newwin(LINES, COLS, SP->linesrippedoffontop, 0);
209 if (!stdscr)
210 {
211 fprintf(stderr, "initscr(): Unable to create stdscr.\n");
212 exit(1);
213 }
214
215 wclrtobot(stdscr);
216
217 /* If preserving the existing screen, don't allow a screen clear */
218
219 if (SP->_preserve)
220 {
221 untouchwin(curscr);
222 untouchwin(stdscr);
223 stdscr->_clear = FALSE;
224 curscr->_clear = FALSE;
225 }
226 else
227 curscr->_clear = TRUE;
228
229 SP->atrtab = calloc(PDC_COLOR_PAIRS, sizeof(PDC_PAIR));
230 if (!SP->atrtab)
231 return NULL;
232 PDC_init_atrtab(); /* set up default colors */
233
234 MOUSE_X_POS = MOUSE_Y_POS = -1;
235 BUTTON_STATUS(1) = BUTTON_RELEASED;
236 BUTTON_STATUS(2) = BUTTON_RELEASED;
237 BUTTON_STATUS(3) = BUTTON_RELEASED;
238 Mouse_status.changes = 0;
239
240 SP->alive = TRUE;
241
242 def_shell_mode();
243
244 sprintf(ttytype, "pdcurses|PDCurses for %s", PDC_sysname());
245
246 SP->c_buffer = malloc(_INBUFSIZ * sizeof(int));
247 if (!SP->c_buffer)
248 return NULL;
249 SP->c_pindex = 0;
250 SP->c_gindex = 1;
251
252 SP->c_ungch = malloc(NUNGETCH * sizeof(int));
253 if (!SP->c_ungch)
254 return NULL;
255 SP->c_ungind = 0;
256 SP->c_ungmax = NUNGETCH;
257
258 return stdscr;
259}
260
261#ifdef XCURSES
262WINDOW *Xinitscr(int argc, char **argv)
263{
264 PDC_LOG(("Xinitscr() - called\n"));
265
266 PDC_set_args(argc, argv);
267 return initscr();
268}
269#endif
270
271int endwin(void)
272{
273 PDC_LOG(("endwin() - called\n"));
274
275 /* Allow temporary exit from curses using endwin() */
276
277 def_prog_mode();
278 PDC_scr_close();
279
280 SP->alive = FALSE;
281
282 return OK;
283}
284
285bool isendwin(void)
286{
287 PDC_LOG(("isendwin() - called\n"));
288
289 return SP ? !(SP->alive) : FALSE;
290}
291
292SCREEN *newterm(const char *type, FILE *outfd, FILE *infd)
293{
294 PDC_LOG(("newterm() - called\n"));
295
296 return initscr() ? SP : NULL;
297}
298
299SCREEN *set_term(SCREEN *new)
300{
301 PDC_LOG(("set_term() - called\n"));
302
303 /* We only support one screen */
304
305 return (new == SP) ? SP : NULL;
306}
307
308void delscreen(SCREEN *sp)
309{
310 PDC_LOG(("delscreen() - called\n"));
311
312 if (!SP || sp != SP)
313 return;
314
315 free(SP->c_ungch);
316 free(SP->c_buffer);
317 free(SP->atrtab);
318
319 PDC_slk_free(); /* free the soft label keys, if needed */
320
321 delwin(stdscr);
322 delwin(curscr);
323 delwin(SP->lastscr);
324 stdscr = (WINDOW *)NULL;
325 curscr = (WINDOW *)NULL;
326 SP->lastscr = (WINDOW *)NULL;
327
328 SP->alive = FALSE;
329
330 PDC_scr_free();
331
332 free(SP);
333 SP = (SCREEN *)NULL;
334}
335
336int resize_term(int nlines, int ncols)
337{
338 PDC_LOG(("resize_term() - called: nlines %d\n", nlines));
339
340 if (!stdscr || PDC_resize_screen(nlines, ncols) == ERR)
341 return ERR;
342
343 SP->resized = FALSE;
344
345 SP->lines = PDC_get_rows();
346 LINES = SP->lines - SP->linesrippedoff - SP->slklines;
347 SP->cols = COLS = PDC_get_columns();
348
349 if (SP->cursrow >= SP->lines)
350 SP->cursrow = SP->lines - 1;
351 if (SP->curscol >= SP->cols)
352 SP->curscol = SP->cols - 1;
353
354 if (wresize(curscr, SP->lines, SP->cols) == ERR ||
355 wresize(stdscr, LINES, COLS) == ERR ||
356 wresize(SP->lastscr, SP->lines, SP->cols) == ERR)
357 return ERR;
358
359 werase(SP->lastscr);
360 curscr->_clear = TRUE;
361
362 if (SP->slk_winptr)
363 {
364 if (wresize(SP->slk_winptr, SP->slklines, COLS) == ERR)
365 return ERR;
366
367 wmove(SP->slk_winptr, 0, 0);
368 wclrtobot(SP->slk_winptr);
369 PDC_slk_initialize();
370 slk_noutrefresh();
371 }
372
373 touchwin(stdscr);
374 wnoutrefresh(stdscr);
375
376 return OK;
377}
378
379bool is_termresized(void)
380{
381 PDC_LOG(("is_termresized() - called\n"));
382
383 return SP->resized;
384}
385
386const char *curses_version(void)
387{
388 return _curses_notice;
389}
390
391void PDC_get_version(PDC_VERSION *ver)
392{
393 if (!ver)
394 return;
395
396 ver->flags = 0
397#ifdef PDCDEBUG
398 | PDC_VFLAG_DEBUG
399#endif
400#ifdef PDC_WIDE
401 | PDC_VFLAG_WIDE
402#endif
403#ifdef PDC_FORCE_UTF8
404 | PDC_VFLAG_UTF8
405#endif
406#ifdef PDC_DLL_BUILD
407 | PDC_VFLAG_DLL
408#endif
409#ifdef PDC_RGB
410 | PDC_VFLAG_RGB
411#endif
412 ;
413
414 ver->build = PDC_BUILD;
415 ver->major = PDC_VER_MAJOR;
416 ver->minor = PDC_VER_MINOR;
417 ver->csize = sizeof(chtype);
418 ver->bsize = sizeof(bool);
419}
420
421int set_tabsize(int tabsize)
422{
423 PDC_LOG(("set_tabsize() - called: tabsize %d\n", tabsize));
424
425 if (tabsize < 1)
426 return ERR;
427
428 TABSIZE = tabsize;
429
430 return OK;
431}
diff --git a/scripts/kconfig/libcurses/inopts.c b/scripts/kconfig/libcurses/inopts.c
new file mode 100644
index 000000000..30e18f611
--- /dev/null
+++ b/scripts/kconfig/libcurses/inopts.c
@@ -0,0 +1,408 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7inopts
8------
9
10### Synopsis
11
12 int cbreak(void);
13 int nocbreak(void);
14 int echo(void);
15 int noecho(void);
16 int halfdelay(int tenths);
17 int intrflush(WINDOW *win, bool bf);
18 int keypad(WINDOW *win, bool bf);
19 int meta(WINDOW *win, bool bf);
20 int nl(void);
21 int nonl(void);
22 int nodelay(WINDOW *win, bool bf);
23 int notimeout(WINDOW *win, bool bf);
24 int raw(void);
25 int noraw(void);
26 void noqiflush(void);
27 void qiflush(void);
28 void timeout(int delay);
29 void wtimeout(WINDOW *win, int delay);
30 int wgetdelay(const WINDOW *win);
31 int typeahead(int fildes);
32
33 int crmode(void);
34 int nocrmode(void);
35
36 bool is_keypad(const WINDOW *win);
37 bool is_nodelay(const WINDOW *win);
38 bool is_notimeout(const WINDOW *win);
39
40### Description
41
42 cbreak() and nocbreak() toggle cbreak mode. In cbreak mode,
43 characters typed by the user are made available immediately, and
44 erase/kill character processing is not performed. In nocbreak mode,
45 typed characters are buffered until a newline or carriage return.
46 Interrupt and flow control characters are unaffected by this mode.
47 PDCurses always starts in cbreak mode.
48
49 echo() and noecho() control whether typed characters are echoed by
50 the input routine. Initially, input characters are echoed. Subsequent
51 calls to echo() and noecho() do not flush type-ahead.
52
53 halfdelay() is similar to cbreak(), but allows for a time limit to be
54 specified, in tenths of a second. This causes getch() to block for
55 that period before returning ERR if no key has been received. tenths
56 must be between 1 and 255.
57
58 keypad() controls whether getch() returns function/special keys as
59 single key codes (e.g., the left arrow key as KEY_LEFT). Per X/Open,
60 the default for keypad mode is OFF. You'll probably want it on. With
61 keypad mode off, if a special key is pressed, getch() does nothing or
62 returns ERR.
63
64 nodelay() controls whether wgetch() is a non-blocking call. If the
65 option is enabled, and no input is ready, wgetch() will return ERR.
66 If disabled, wgetch() will hang until input is ready.
67
68 nl() enables the translation of a carriage return into a newline on
69 input. nonl() disables this. Initially, the translation does occur.
70
71 raw() and noraw() toggle raw mode. Raw mode is similar to cbreak
72 mode, in that characters typed are immediately passed through to the
73 user program. The difference is that in raw mode, the INTR, QUIT,
74 SUSP, and STOP characters are passed through without being
75 interpreted, and without generating a signal.
76
77 In PDCurses, the meta() function sets raw mode on or off.
78
79 timeout() and wtimeout() set blocking or non-blocking reads for the
80 specified window. If the delay is negative, a blocking read is used;
81 if zero, then non-blocking reads are done -- if no input is waiting,
82 ERR is returned immediately. If the delay is positive, the read
83 blocks for the delay period; if the period expires, ERR is returned.
84 The delay is given in milliseconds, but this is rounded down to 50ms
85 (1/20th sec) intervals, with a minimum of one interval if a postive
86 delay is given; i.e., 1-99 will wait 50ms, 100-149 will wait 100ms,
87 etc.
88
89 wgetdelay() returns the delay timeout as set in wtimeout().
90
91 intrflush(), notimeout(), noqiflush(), qiflush() and typeahead() do
92 nothing in PDCurses, but are included for compatibility with other
93 curses implementations.
94
95 crmode() and nocrmode() are archaic equivalents to cbreak() and
96 nocbreak(), respectively.
97
98 is_keypad() reports whether the specified window is in keypad mode.
99
100 is_nodelay() reports whether the specified window is in nodelay mode.
101
102### Return Value
103
104 is_keypad() and is_nodelay() return TRUE or FALSE. is_notimeout() is
105 provided for compatibility with other curses implementations, and
106 always returns FALSE. All others return OK on success and ERR on error.
107
108### Portability
109 X/Open ncurses NetBSD
110 cbreak Y Y Y
111 nocbreak Y Y Y
112 echo Y Y Y
113 noecho Y Y Y
114 halfdelay Y Y Y
115 intrflush Y Y Y
116 keypad Y Y Y
117 meta Y Y Y
118 nl Y Y Y
119 nonl Y Y Y
120 nodelay Y Y Y
121 notimeout Y Y Y
122 raw Y Y Y
123 noraw Y Y Y
124 noqiflush Y Y Y
125 qiflush Y Y Y
126 timeout Y Y Y
127 wtimeout Y Y Y
128 wgetdelay - Y -
129 typeahead Y Y Y
130 crmode Y Y Y
131 nocrmode Y Y Y
132 is_keypad - Y Y
133 is_nodelay - Y -
134 is_notimeout - Y -
135
136**man-end****************************************************************/
137
138int cbreak(void)
139{
140 PDC_LOG(("cbreak() - called\n"));
141
142 if (!SP)
143 return ERR;
144
145 SP->cbreak = TRUE;
146
147 return OK;
148}
149
150int nocbreak(void)
151{
152 PDC_LOG(("nocbreak() - called\n"));
153
154 if (!SP)
155 return ERR;
156
157 SP->cbreak = FALSE;
158 SP->delaytenths = 0;
159
160 return OK;
161}
162
163int echo(void)
164{
165 PDC_LOG(("echo() - called\n"));
166
167 if (!SP)
168 return ERR;
169
170 SP->echo = TRUE;
171
172 return OK;
173}
174
175int noecho(void)
176{
177 PDC_LOG(("noecho() - called\n"));
178
179 if (!SP)
180 return ERR;
181
182 SP->echo = FALSE;
183
184 return OK;
185}
186
187int halfdelay(int tenths)
188{
189 PDC_LOG(("halfdelay() - called\n"));
190
191 if (!SP || tenths < 1 || tenths > 255)
192 return ERR;
193
194 SP->delaytenths = tenths;
195
196 return OK;
197}
198
199int intrflush(WINDOW *win, bool bf)
200{
201 PDC_LOG(("intrflush() - called\n"));
202
203 return OK;
204}
205
206int keypad(WINDOW *win, bool bf)
207{
208 PDC_LOG(("keypad() - called\n"));
209
210 if (!win)
211 return ERR;
212
213 win->_use_keypad = bf;
214
215 return OK;
216}
217
218int meta(WINDOW *win, bool bf)
219{
220 PDC_LOG(("meta() - called\n"));
221
222 if (!SP)
223 return ERR;
224
225 SP->raw_inp = bf;
226
227 return OK;
228}
229
230int nl(void)
231{
232 PDC_LOG(("nl() - called\n"));
233
234 if (!SP)
235 return ERR;
236
237 SP->autocr = TRUE;
238
239 return OK;
240}
241
242int nonl(void)
243{
244 PDC_LOG(("nonl() - called\n"));
245
246 if (!SP)
247 return ERR;
248
249 SP->autocr = FALSE;
250
251 return OK;
252}
253
254int nodelay(WINDOW *win, bool flag)
255{
256 PDC_LOG(("nodelay() - called\n"));
257
258 if (!win)
259 return ERR;
260
261 win->_nodelay = flag;
262
263 return OK;
264}
265
266int notimeout(WINDOW *win, bool flag)
267{
268 PDC_LOG(("notimeout() - called\n"));
269
270 return OK;
271}
272
273int raw(void)
274{
275 PDC_LOG(("raw() - called\n"));
276
277 if (!SP)
278 return ERR;
279
280 PDC_set_keyboard_binary(TRUE);
281 SP->raw_inp = TRUE;
282
283 return OK;
284}
285
286int noraw(void)
287{
288 PDC_LOG(("noraw() - called\n"));
289
290 if (!SP)
291 return ERR;
292
293 PDC_set_keyboard_binary(FALSE);
294 SP->raw_inp = FALSE;
295
296 return OK;
297}
298
299void noqiflush(void)
300{
301 PDC_LOG(("noqiflush() - called\n"));
302}
303
304void qiflush(void)
305{
306 PDC_LOG(("qiflush() - called\n"));
307}
308
309void timeout(int delay)
310{
311 PDC_LOG(("timeout() - called\n"));
312
313 wtimeout(stdscr, delay);
314}
315
316void wtimeout(WINDOW *win, int delay)
317{
318 PDC_LOG(("wtimeout() - called\n"));
319
320 if (!win)
321 return;
322
323 if (delay < 0)
324 {
325 /* This causes a blocking read on the window, so turn on delay
326 mode */
327
328 win->_nodelay = FALSE;
329 win->_delayms = 0;
330 }
331 else if (!delay)
332 {
333 /* This causes a non-blocking read on the window, so turn off
334 delay mode */
335
336 win->_nodelay = TRUE;
337 win->_delayms = 0;
338 }
339 else
340 {
341 /* This causes the read on the window to delay for the number of
342 milliseconds. Also forces the window into non-blocking read
343 mode */
344
345 /*win->_nodelay = TRUE;*/
346 win->_delayms = delay;
347 }
348}
349
350int wgetdelay(const WINDOW *win)
351{
352 PDC_LOG(("wgetdelay() - called\n"));
353
354 if (!win)
355 return 0;
356
357 return win->_delayms;
358}
359
360int typeahead(int fildes)
361{
362 PDC_LOG(("typeahead() - called\n"));
363
364 return OK;
365}
366
367int crmode(void)
368{
369 PDC_LOG(("crmode() - called\n"));
370
371 return cbreak();
372}
373
374int nocrmode(void)
375{
376 PDC_LOG(("nocrmode() - called\n"));
377
378 return nocbreak();
379}
380
381bool is_keypad(const WINDOW *win)
382{
383 PDC_LOG(("is_keypad() - called\n"));
384
385 if (!win)
386 return FALSE;
387
388 return win->_use_keypad;
389}
390
391bool is_nodelay(const WINDOW *win)
392{
393 PDC_LOG(("is_nodelay() - called\n"));
394
395 if (!win)
396 return FALSE;
397
398 return win->_nodelay;
399}
400
401bool is_notimeout(const WINDOW *win)
402{
403 (void) win;
404
405 PDC_LOG(("is_notimeout() - called - returning FALSE...\n"));
406
407 return FALSE;
408}
diff --git a/scripts/kconfig/libcurses/kernel.c b/scripts/kconfig/libcurses/kernel.c
new file mode 100644
index 000000000..afb2d0661
--- /dev/null
+++ b/scripts/kconfig/libcurses/kernel.c
@@ -0,0 +1,297 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7kernel
8------
9
10### Synopsis
11
12 int def_prog_mode(void);
13 int def_shell_mode(void);
14 int reset_prog_mode(void);
15 int reset_shell_mode(void);
16 int resetty(void);
17 int savetty(void);
18 int ripoffline(int line, int (*init)(WINDOW *, int));
19 int curs_set(int visibility);
20 int napms(int ms);
21
22 int draino(int ms);
23 int resetterm(void);
24 int fixterm(void);
25 int saveterm(void);
26
27### Description
28
29 def_prog_mode() and def_shell_mode() save the current terminal modes
30 as the "program" (in curses) or "shell" (not in curses) state for use
31 by the reset_prog_mode() and reset_shell_mode() functions. This is
32 done automatically by initscr().
33
34 reset_prog_mode() and reset_shell_mode() restore the terminal to
35 "program" (in curses) or "shell" (not in curses) state. These are
36 done automatically by endwin() and doupdate() after an endwin(), so
37 they would normally not be called before these functions.
38
39 savetty() and resetty() save and restore the state of the terminal
40 modes. savetty() saves the current state in a buffer, and resetty()
41 restores the state to what it was at the last call to savetty().
42
43 curs_set() alters the appearance of the cursor. A visibility of 0
44 makes it disappear; 1 makes it appear "normal" (usually an underline)
45 and 2 makes it "highly visible" (usually a block).
46
47 ripoffline() reduces the size of stdscr by one line. If the "line"
48 parameter is positive, the line is removed from the top of the
49 screen; if negative, from the bottom. Up to 5 lines can be ripped off
50 stdscr by calling ripoffline() repeatedly. The function argument,
51 init, is called from within initscr() or newterm(), so ripoffline()
52 must be called before either of these functions. The init function
53 receives a pointer to a one-line WINDOW, and the width of the window.
54 Calling ripoffline() with a NULL init function pointer is an error.
55
56 napms() suspends the program for the specified number of
57 milliseconds. draino() is an archaic equivalent. Note that since
58 napms() attempts to give up a time slice and yield control back to
59 the OS, all times are approximate. (In DOS, the delay is actually
60 rounded down to 50ms (1/20th sec) intervals, with a minimum of one
61 interval; i.e., 1-99 will wait 50ms, 100-149 will wait 100ms, etc.)
62 0 returns immediately.
63
64 resetterm(), fixterm() and saveterm() are archaic equivalents for
65 reset_shell_mode(), reset_prog_mode() and def_prog_mode(),
66 respectively.
67
68### Return Value
69
70 All functions return OK on success and ERR on error, except
71 curs_set(), which returns the previous visibility.
72
73### Portability
74 X/Open ncurses NetBSD
75 def_prog_mode Y Y Y
76 def_shell_mode Y Y Y
77 reset_prog_mode Y Y Y
78 reset_shell_mode Y Y Y
79 resetty Y Y Y
80 savetty Y Y Y
81 ripoffline Y Y Y
82 curs_set Y Y Y
83 napms Y Y Y
84 fixterm - Y -
85 resetterm - Y -
86 saveterm - Y -
87 draino - - -
88
89**man-end****************************************************************/
90
91#include <string.h>
92
93RIPPEDOFFLINE linesripped[5];
94char linesrippedoff = 0;
95
96static struct cttyset
97{
98 bool been_set;
99 SCREEN saved;
100} ctty[3];
101
102enum { PDC_SH_TTY, PDC_PR_TTY, PDC_SAVE_TTY };
103
104static void _save_mode(int i)
105{
106 ctty[i].been_set = TRUE;
107
108 memcpy(&(ctty[i].saved), SP, sizeof(SCREEN));
109
110 PDC_save_screen_mode(i);
111}
112
113static int _restore_mode(int i)
114{
115 if (ctty[i].been_set == TRUE)
116 {
117 memcpy(SP, &(ctty[i].saved), sizeof(SCREEN));
118
119 if (ctty[i].saved.raw_out)
120 raw();
121
122 PDC_restore_screen_mode(i);
123
124 if ((LINES != ctty[i].saved.lines) ||
125 (COLS != ctty[i].saved.cols))
126 resize_term(ctty[i].saved.lines, ctty[i].saved.cols);
127
128 PDC_curs_set(ctty[i].saved.visibility);
129
130 PDC_gotoyx(ctty[i].saved.cursrow, ctty[i].saved.curscol);
131 }
132
133 return ctty[i].been_set ? OK : ERR;
134}
135
136int def_prog_mode(void)
137{
138 PDC_LOG(("def_prog_mode() - called\n"));
139
140 if (!SP)
141 return ERR;
142
143 _save_mode(PDC_PR_TTY);
144
145 return OK;
146}
147
148int def_shell_mode(void)
149{
150 PDC_LOG(("def_shell_mode() - called\n"));
151
152 if (!SP)
153 return ERR;
154
155 _save_mode(PDC_SH_TTY);
156
157 return OK;
158}
159
160int reset_prog_mode(void)
161{
162 PDC_LOG(("reset_prog_mode() - called\n"));
163
164 if (!SP)
165 return ERR;
166
167 _restore_mode(PDC_PR_TTY);
168 PDC_reset_prog_mode();
169
170 return OK;
171}
172
173int reset_shell_mode(void)
174{
175 PDC_LOG(("reset_shell_mode() - called\n"));
176
177 if (!SP)
178 return ERR;
179
180 _restore_mode(PDC_SH_TTY);
181 PDC_reset_shell_mode();
182
183 return OK;
184}
185
186int resetty(void)
187{
188 PDC_LOG(("resetty() - called\n"));
189
190 if (!SP)
191 return ERR;
192
193 return _restore_mode(PDC_SAVE_TTY);
194}
195
196int savetty(void)
197{
198 PDC_LOG(("savetty() - called\n"));
199
200 if (!SP)
201 return ERR;
202
203 _save_mode(PDC_SAVE_TTY);
204
205 return OK;
206}
207
208int curs_set(int visibility)
209{
210 int ret_vis;
211
212 PDC_LOG(("curs_set() - called: visibility=%d\n", visibility));
213
214 if (!SP || visibility < 0 || visibility > 2)
215 return ERR;
216
217 ret_vis = PDC_curs_set(visibility);
218
219 /* If the cursor is changing from invisible to visible, update
220 its position */
221
222 if (visibility && !ret_vis)
223 PDC_gotoyx(SP->cursrow, SP->curscol);
224
225 return ret_vis;
226}
227
228int napms(int ms)
229{
230 PDC_LOG(("napms() - called: ms=%d\n", ms));
231
232 if (!SP)
233 return ERR;
234
235 if (SP->dirty)
236 {
237 int curs_state = SP->visibility;
238 bool leave_state = is_leaveok(curscr);
239
240 SP->dirty = FALSE;
241
242 leaveok(curscr, TRUE);
243
244 wrefresh(curscr);
245
246 leaveok(curscr, leave_state);
247 curs_set(curs_state);
248 }
249
250 if (ms)
251 PDC_napms(ms);
252
253 return OK;
254}
255
256int ripoffline(int line, int (*init)(WINDOW *, int))
257{
258 PDC_LOG(("ripoffline() - called: line=%d\n", line));
259
260 if (linesrippedoff < 5 && line && init)
261 {
262 linesripped[(int)linesrippedoff].line = line;
263 linesripped[(int)linesrippedoff++].init = init;
264
265 return OK;
266 }
267
268 return ERR;
269}
270
271int draino(int ms)
272{
273 PDC_LOG(("draino() - called\n"));
274
275 return napms(ms);
276}
277
278int resetterm(void)
279{
280 PDC_LOG(("resetterm() - called\n"));
281
282 return reset_shell_mode();
283}
284
285int fixterm(void)
286{
287 PDC_LOG(("fixterm() - called\n"));
288
289 return reset_prog_mode();
290}
291
292int saveterm(void)
293{
294 PDC_LOG(("saveterm() - called\n"));
295
296 return def_prog_mode();
297}
diff --git a/scripts/kconfig/libcurses/move.c b/scripts/kconfig/libcurses/move.c
new file mode 100644
index 000000000..96496445e
--- /dev/null
+++ b/scripts/kconfig/libcurses/move.c
@@ -0,0 +1,77 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7move
8----
9
10### Synopsis
11
12 int move(int y, int x);
13 int mvcur(int oldrow, int oldcol, int newrow, int newcol);
14 int wmove(WINDOW *win, int y, int x);
15
16### Description
17
18 move() and wmove() move the cursor associated with the window to the
19 given location. This does not move the physical cursor of the
20 terminal until refresh() is called. The position specified is
21 relative to the upper left corner of the window, which is (0,0).
22
23 mvcur() moves the physical cursor without updating any window cursor
24 positions.
25
26### Return Value
27
28 All functions return OK on success and ERR on error.
29
30### Portability
31 X/Open ncurses NetBSD
32 move Y Y Y
33 mvcur Y Y Y
34 wmove Y Y Y
35
36**man-end****************************************************************/
37
38int move(int y, int x)
39{
40 PDC_LOG(("move() - called: y=%d x=%d\n", y, x));
41
42 if (!stdscr || x < 0 || y < 0 || x >= stdscr->_maxx || y >= stdscr->_maxy)
43 return ERR;
44
45 stdscr->_curx = x;
46 stdscr->_cury = y;
47
48 return OK;
49}
50
51int mvcur(int oldrow, int oldcol, int newrow, int newcol)
52{
53 PDC_LOG(("mvcur() - called: oldrow %d oldcol %d newrow %d newcol %d\n",
54 oldrow, oldcol, newrow, newcol));
55
56 if (!SP || newrow < 0 || newrow >= LINES || newcol < 0 || newcol >= COLS)
57 return ERR;
58
59 PDC_gotoyx(newrow, newcol);
60 SP->cursrow = newrow;
61 SP->curscol = newcol;
62
63 return OK;
64}
65
66int wmove(WINDOW *win, int y, int x)
67{
68 PDC_LOG(("wmove() - called: y=%d x=%d\n", y, x));
69
70 if (!win || x < 0 || y < 0 || x >= win->_maxx || y >= win->_maxy)
71 return ERR;
72
73 win->_curx = x;
74 win->_cury = y;
75
76 return OK;
77}
diff --git a/scripts/kconfig/libcurses/outopts.c b/scripts/kconfig/libcurses/outopts.c
new file mode 100644
index 000000000..e0a55e437
--- /dev/null
+++ b/scripts/kconfig/libcurses/outopts.c
@@ -0,0 +1,260 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7outopts
8-------
9
10### Synopsis
11
12 int clearok(WINDOW *win, bool bf);
13 int idlok(WINDOW *win, bool bf);
14 void idcok(WINDOW *win, bool bf);
15 void immedok(WINDOW *win, bool bf);
16 int leaveok(WINDOW *win, bool bf);
17 int setscrreg(int top, int bot);
18 int wsetscrreg(WINDOW *win, int top, int bot);
19 int wgetscrreg(const WINDOW *win, int *top, int *bot);
20 int scrollok(WINDOW *win, bool bf);
21
22 int raw_output(bool bf);
23
24 bool is_cleared(const WINDOW *win);
25 bool is_idlok(const WINDOW *win);
26 bool is_idcok(const WINDOW *win);
27 bool is_immedok(const WINDOW *win);
28 bool is_leaveok(const WINDOW *win);
29 bool is_scrollok(const WINDOW *win);
30
31### Description
32
33 With clearok(), if bf is TRUE, the next call to wrefresh() with this
34 window will clear the screen completely and redraw the entire screen.
35
36 immedok(), called with a second argument of TRUE, causes an automatic
37 wrefresh() every time a change is made to the specified window.
38
39 Normally, the hardware cursor is left at the location of the window
40 being refreshed. leaveok() allows the cursor to be left wherever the
41 update happens to leave it. It's useful for applications where the
42 cursor is not used, since it reduces the need for cursor motions. If
43 possible, the cursor is made invisible when this option is enabled.
44
45 wsetscrreg() sets a scrolling region in a window; "top" and "bot" are
46 the line numbers for the top and bottom margins. If this option and
47 scrollok() are enabled, any attempt to move off the bottom margin
48 will cause all lines in the scrolling region to scroll up one line.
49 setscrreg() is the stdscr version.
50
51 wgetscrreg() gets the top and bottom margins as set in wsetscrreg().
52
53 idlok() and idcok() do nothing in PDCurses, but are provided for
54 compatibility with other curses implementations, likewise is_idlok()
55 and is_idcok().
56
57 raw_output() enables the output of raw characters using the standard
58 *add* and *ins* curses functions (that is, it disables translation of
59 control characters).
60
61 is_cleared() reports whether the specified window causes clear at next
62 refresh.
63
64 is_immedok() reports whether the specified window is in immedok mode.
65
66 is_leaveok() reports whether the specified window is in leaveok mode.
67
68 is_scrollok() reports whether the specified window allows scrolling.
69
70### Return Value
71
72 is_cleared(), is_immedok(), is_leaveok() and is_scrollok() return TRUE
73 or FALSE. is_idlok() and is_idcok() are provided for compatibility with
74 other curses implementations, and always return FALSE. All others
75 return OK on success and ERR on error.
76
77### Portability
78 X/Open ncurses NetBSD
79 clearok Y Y Y
80 idlok Y Y Y
81 idcok Y Y Y
82 immedok Y Y Y
83 leaveok Y Y Y
84 setscrreg Y Y Y
85 wsetscrreg Y Y Y
86 wgetscrreg - Y -
87 scrollok Y Y Y
88 is_cleared - Y -
89 is_idlok - Y -
90 is_idcok - Y -
91 is_immedok - Y -
92 is_leaveok - Y Y
93 is_scrollok - Y -
94 raw_output - - -
95
96**man-end****************************************************************/
97
98int clearok(WINDOW *win, bool bf)
99{
100 PDC_LOG(("clearok() - called\n"));
101
102 if (!win)
103 return ERR;
104
105 win->_clear = bf;
106
107 return OK;
108}
109
110int idlok(WINDOW *win, bool bf)
111{
112 PDC_LOG(("idlok() - called\n"));
113
114 return OK;
115}
116
117void idcok(WINDOW *win, bool bf)
118{
119 PDC_LOG(("idcok() - called\n"));
120}
121
122void immedok(WINDOW *win, bool bf)
123{
124 PDC_LOG(("immedok() - called\n"));
125
126 if (win)
127 win->_immed = bf;
128}
129
130int leaveok(WINDOW *win, bool bf)
131{
132 PDC_LOG(("leaveok() - called\n"));
133
134 if (!win)
135 return ERR;
136
137 win->_leaveit = bf;
138
139 curs_set(!bf);
140
141 return OK;
142}
143
144int setscrreg(int top, int bottom)
145{
146 PDC_LOG(("setscrreg() - called: top %d bottom %d\n", top, bottom));
147
148 return wsetscrreg(stdscr, top, bottom);
149}
150
151int wsetscrreg(WINDOW *win, int top, int bottom)
152{
153 PDC_LOG(("wsetscrreg() - called: top %d bottom %d\n", top, bottom));
154
155 if (win && 0 <= top && top <= win->_cury &&
156 win->_cury <= bottom && bottom < win->_maxy)
157 {
158 win->_tmarg = top;
159 win->_bmarg = bottom;
160
161 return OK;
162 }
163 else
164 return ERR;
165}
166
167int wgetscrreg(const WINDOW *win, int *top, int *bot)
168{
169 PDC_LOG(("wgetscrreg() - called\n"));
170
171 if (!win || !top || !bot)
172 return ERR;
173
174 *top = win->_tmarg;
175 *bot = win->_bmarg;
176
177 return OK;
178}
179
180int scrollok(WINDOW *win, bool bf)
181{
182 PDC_LOG(("scrollok() - called\n"));
183
184 if (!win)
185 return ERR;
186
187 win->_scroll = bf;
188
189 return OK;
190}
191
192int raw_output(bool bf)
193{
194 PDC_LOG(("raw_output() - called\n"));
195
196 if (!SP)
197 return ERR;
198
199 SP->raw_out = bf;
200
201 return OK;
202}
203
204bool is_cleared(const WINDOW *win)
205{
206 PDC_LOG(("is_cleared() - called\n"));
207
208 if (!win)
209 return FALSE;
210
211 return win->_clear;
212}
213
214bool is_idlok(const WINDOW *win)
215{
216 (void) win;
217
218 PDC_LOG(("is_idlok() - called\n"));
219
220 return FALSE;
221}
222
223bool is_idcok(const WINDOW *win)
224{
225 (void) win;
226
227 PDC_LOG(("is_idcok() - called\n"));
228
229 return FALSE;
230}
231
232bool is_immedok(const WINDOW *win)
233{
234 PDC_LOG(("is_immedok() - called\n"));
235
236 if (!win)
237 return FALSE;
238
239 return win->_immed;
240}
241
242bool is_leaveok(const WINDOW *win)
243{
244 PDC_LOG(("is_leaveok() - called\n"));
245
246 if (!win)
247 return FALSE;
248
249 return win->_leaveit;
250}
251
252bool is_scrollok(const WINDOW *win)
253{
254 PDC_LOG(("is_scrollok() - called\n"));
255
256 if (!win)
257 return FALSE;
258
259 return win->_scroll;
260}
diff --git a/scripts/kconfig/libcurses/overlay.c b/scripts/kconfig/libcurses/overlay.c
new file mode 100644
index 000000000..ae1903da8
--- /dev/null
+++ b/scripts/kconfig/libcurses/overlay.c
@@ -0,0 +1,214 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7overlay
8-------
9
10### Synopsis
11
12 int overlay(const WINDOW *src_w, WINDOW *dst_w)
13 int overwrite(const WINDOW *src_w, WINDOW *dst_w)
14 int copywin(const WINDOW *src_w, WINDOW *dst_w, int src_tr,
15 int src_tc, int dst_tr, int dst_tc, int dst_br,
16 int dst_bc, int _overlay)
17
18### Description
19
20 overlay() and overwrite() copy all the text from src_w into dst_w.
21 The windows need not be the same size. Those characters in the source
22 window that intersect with the destination window are copied, so that
23 the characters appear in the same physical position on the screen.
24 The difference between the two functions is that overlay() is non-
25 destructive (blanks are not copied) while overwrite() is destructive
26 (blanks are copied).
27
28 copywin() is similar, but doesn't require that the two windows
29 overlap. The arguments src_tc and src_tr specify the top left corner
30 of the region to be copied. dst_tc, dst_tr, dst_br, and dst_bc
31 specify the region within the destination window to copy to. The
32 argument "overlay", if TRUE, indicates that the copy is done non-
33 destructively (as in overlay()); blanks in the source window are not
34 copied to the destination window. When overlay is FALSE, blanks are
35 copied.
36
37### Return Value
38
39 All functions return OK on success and ERR on error.
40
41### Portability
42 X/Open ncurses NetBSD
43 overlay Y Y Y
44 overwrite Y Y Y
45 copywin Y Y Y
46
47**man-end****************************************************************/
48
49/* Thanks to Andreas Otte <venn@@uni-paderborn.de> for the
50 corrected overlay()/overwrite() behavior. */
51
52static int _copy_win(const WINDOW *src_w, WINDOW *dst_w, int src_tr,
53 int src_tc, int src_br, int src_bc, int dst_tr,
54 int dst_tc, bool _overlay)
55{
56 int col, line, y1, fc, *minchng, *maxchng;
57 chtype *w1ptr, *w2ptr;
58
59 int lc = 0;
60 int xdiff = src_bc - src_tc;
61 int ydiff = src_br - src_tr;
62
63 if (!src_w || !dst_w)
64 return ERR;
65
66 minchng = dst_w->_firstch;
67 maxchng = dst_w->_lastch;
68
69 for (y1 = 0; y1 < dst_tr; y1++)
70 {
71 minchng++;
72 maxchng++;
73 }
74
75 for (line = 0; line < ydiff; line++)
76 {
77 w1ptr = src_w->_y[line + src_tr] + src_tc;
78 w2ptr = dst_w->_y[line + dst_tr] + dst_tc;
79
80 fc = _NO_CHANGE;
81
82 for (col = 0; col < xdiff; col++)
83 {
84 if ((*w1ptr) != (*w2ptr) &&
85 !((*w1ptr & A_CHARTEXT) == ' ' && _overlay))
86 {
87 *w2ptr = *w1ptr;
88
89 if (fc == _NO_CHANGE)
90 fc = col + dst_tc;
91
92 lc = col + dst_tc;
93 }
94
95 w1ptr++;
96 w2ptr++;
97 }
98
99 if (*minchng == _NO_CHANGE)
100 {
101 *minchng = fc;
102 *maxchng = lc;
103 }
104 else if (fc != _NO_CHANGE)
105 {
106 if (fc < *minchng)
107 *minchng = fc;
108 if (lc > *maxchng)
109 *maxchng = lc;
110 }
111
112 minchng++;
113 maxchng++;
114 }
115
116 return OK;
117}
118
119int _copy_overlap(const WINDOW *src_w, WINDOW *dst_w, bool overlay)
120{
121 int first_line, first_col, last_line, last_col;
122 int src_start_x, src_start_y, dst_start_x, dst_start_y;
123 int xdiff, ydiff;
124
125 if (!src_w || !dst_w)
126 return ERR;
127
128 first_col = max(dst_w->_begx, src_w->_begx);
129 first_line = max(dst_w->_begy, src_w->_begy);
130
131 last_col = min(src_w->_begx + src_w->_maxx, dst_w->_begx + dst_w->_maxx);
132 last_line = min(src_w->_begy + src_w->_maxy, dst_w->_begy + dst_w->_maxy);
133
134 /* determine the overlapping region of the two windows in real
135 coordinates */
136
137 /* if no overlapping region, do nothing */
138
139 if ((last_col < first_col) || (last_line < first_line))
140 return OK;
141
142 /* size of overlapping region */
143
144 xdiff = last_col - first_col;
145 ydiff = last_line - first_line;
146
147 if (src_w->_begx <= dst_w->_begx)
148 {
149 src_start_x = dst_w->_begx - src_w->_begx;
150 dst_start_x = 0;
151 }
152 else
153 {
154 dst_start_x = src_w->_begx - dst_w->_begx;
155 src_start_x = 0;
156 }
157
158 if (src_w->_begy <= dst_w->_begy)
159 {
160 src_start_y = dst_w->_begy - src_w->_begy;
161 dst_start_y = 0;
162 }
163 else
164 {
165 dst_start_y = src_w->_begy - dst_w->_begy;
166 src_start_y = 0;
167 }
168
169 return _copy_win(src_w, dst_w, src_start_y, src_start_x,
170 src_start_y + ydiff, src_start_x + xdiff,
171 dst_start_y, dst_start_x, overlay);
172}
173
174int overlay(const WINDOW *src_w, WINDOW *dst_w)
175{
176 PDC_LOG(("overlay() - called\n"));
177
178 return _copy_overlap(src_w, dst_w, TRUE);
179}
180
181int overwrite(const WINDOW *src_w, WINDOW *dst_w)
182{
183 PDC_LOG(("overwrite() - called\n"));
184
185 return _copy_overlap(src_w, dst_w, FALSE);
186}
187
188int copywin(const WINDOW *src_w, WINDOW *dst_w, int src_tr, int src_tc,
189 int dst_tr, int dst_tc, int dst_br, int dst_bc, int _overlay)
190{
191 int src_end_x, src_end_y;
192 int src_rows, src_cols, dst_rows, dst_cols;
193 int min_rows, min_cols;
194
195 PDC_LOG(("copywin() - called\n"));
196
197 if (!src_w || !dst_w || dst_w == curscr || dst_br >= dst_w->_maxy
198 || dst_bc >= dst_w->_maxx || dst_tr < 0 || dst_tc < 0)
199 return ERR;
200
201 src_rows = src_w->_maxy - src_tr;
202 src_cols = src_w->_maxx - src_tc;
203 dst_rows = dst_br - dst_tr + 1;
204 dst_cols = dst_bc - dst_tc + 1;
205
206 min_rows = min(src_rows, dst_rows);
207 min_cols = min(src_cols, dst_cols);
208
209 src_end_y = src_tr + min_rows;
210 src_end_x = src_tc + min_cols;
211
212 return _copy_win(src_w, dst_w, src_tr, src_tc, src_end_y, src_end_x,
213 dst_tr, dst_tc, _overlay);
214}
diff --git a/scripts/kconfig/libcurses/pad.c b/scripts/kconfig/libcurses/pad.c
new file mode 100644
index 000000000..3dfdfe5d6
--- /dev/null
+++ b/scripts/kconfig/libcurses/pad.c
@@ -0,0 +1,274 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7pad
8---
9
10### Synopsis
11
12 WINDOW *newpad(int nlines, int ncols);
13 WINDOW *subpad(WINDOW *orig, int nlines, int ncols,
14 int begy, int begx);
15 int prefresh(WINDOW *win, int py, int px, int sy1, int sx1,
16 int sy2, int sx2);
17 int pnoutrefresh(WINDOW *w, int py, int px, int sy1, int sx1,
18 int sy2, int sx2);
19 int pechochar(WINDOW *pad, chtype ch);
20 int pecho_wchar(WINDOW *pad, const cchar_t *wch);
21
22 bool is_pad(const WINDOW *pad);
23
24### Description
25
26 A pad is a special kind of window, which is not restricted by the
27 screen size, and is not necessarily associated with a particular part
28 of the screen. You can use a pad when you need a large window, and
29 only a part of the window will be on the screen at one time. Pads are
30 not refreshed automatically (e.g., from scrolling or echoing of
31 input). You can't call wrefresh() with a pad as an argument; use
32 prefresh() or pnoutrefresh() instead. Note that these routines
33 require additional parameters to specify the part of the pad to be
34 displayed, and the location to use on the screen.
35
36 newpad() creates a new pad data structure.
37
38 subpad() creates a new sub-pad within a pad, at position (begy,
39 begx), with dimensions of nlines lines and ncols columns. This
40 position is relative to the pad, and not to the screen as with
41 subwin. Changes to either the parent pad or sub-pad will affect both.
42 When using sub-pads, you may need to call touchwin() before calling
43 prefresh().
44
45 pnoutrefresh() copies the specified pad to the virtual screen.
46
47 prefresh() calls pnoutrefresh(), followed by doupdate().
48
49 These routines are analogous to wnoutrefresh() and wrefresh(). (py,
50 px) specifies the upper left corner of the part of the pad to be
51 displayed; (sy1, sx1) and (sy2, sx2) describe the screen rectangle
52 that will contain the selected part of the pad.
53
54 pechochar() is functionally equivalent to addch() followed by a call
55 to prefresh(), with the last-used coordinates and dimensions.
56 pecho_wchar() is the wide-character version.
57
58 is_pad() reports whether the specified window is a pad.
59
60### Return Value
61
62 All functions except is_pad() return OK on success and ERR on error.
63
64### Portability
65 X/Open ncurses NetBSD
66 newpad Y Y Y
67 subpad Y Y Y
68 prefresh Y Y Y
69 pnoutrefresh Y Y Y
70 pechochar Y Y Y
71 pecho_wchar Y Y Y
72 is_pad - Y Y
73
74**man-end****************************************************************/
75
76#include <string.h>
77
78WINDOW *newpad(int nlines, int ncols)
79{
80 WINDOW *win;
81
82 PDC_LOG(("newpad() - called: lines=%d cols=%d\n", nlines, ncols));
83
84 win = PDC_makenew(nlines, ncols, 0, 0);
85 if (win)
86 win = PDC_makelines(win);
87
88 if (!win)
89 return (WINDOW *)NULL;
90
91 werase(win);
92
93 win->_flags = _PAD;
94 win->_pad._pad_y = 0;
95 win->_pad._pad_x = 0;
96 win->_pad._pad_top = 0;
97 win->_pad._pad_left = 0;
98 win->_pad._pad_bottom = min(LINES, nlines) - 1;
99 win->_pad._pad_right = min(COLS, ncols) - 1;
100
101 return win;
102}
103
104WINDOW *subpad(WINDOW *orig, int nlines, int ncols, int begy, int begx)
105{
106 WINDOW *win;
107 int i;
108
109 PDC_LOG(("subpad() - called: lines=%d cols=%d begy=%d begx=%d\n",
110 nlines, ncols, begy, begx));
111
112 if (!orig || !(orig->_flags & _PAD))
113 return (WINDOW *)NULL;
114
115 /* make sure window fits inside the original one */
116
117 if (begy < 0 || begx < 0 ||
118 (begy + nlines) > orig->_maxy ||
119 (begx + ncols) > orig->_maxx)
120 return (WINDOW *)NULL;
121
122 if (!nlines)
123 nlines = orig->_maxy - begy;
124
125 if (!ncols)
126 ncols = orig->_maxx - begx;
127
128 win = PDC_makenew(nlines, ncols, begy, begx);
129 if (!win)
130 return (WINDOW *)NULL;
131
132 /* initialize window variables */
133
134 win->_attrs = orig->_attrs;
135 win->_leaveit = orig->_leaveit;
136 win->_scroll = orig->_scroll;
137 win->_nodelay = orig->_nodelay;
138 win->_use_keypad = orig->_use_keypad;
139 win->_parent = orig;
140
141 for (i = 0; i < nlines; i++)
142 win->_y[i] = orig->_y[begy + i] + begx;
143
144 win->_flags = _SUBPAD;
145 win->_pad._pad_y = 0;
146 win->_pad._pad_x = 0;
147 win->_pad._pad_top = 0;
148 win->_pad._pad_left = 0;
149 win->_pad._pad_bottom = min(LINES, nlines) - 1;
150 win->_pad._pad_right = min(COLS, ncols) - 1;
151
152 return win;
153}
154
155int prefresh(WINDOW *win, int py, int px, int sy1, int sx1, int sy2, int sx2)
156{
157 PDC_LOG(("prefresh() - called\n"));
158
159 if (pnoutrefresh(win, py, px, sy1, sx1, sy2, sx2) == ERR)
160 return ERR;
161
162 doupdate();
163 return OK;
164}
165
166int pnoutrefresh(WINDOW *w, int py, int px, int sy1, int sx1, int sy2, int sx2)
167{
168 int num_cols;
169 int sline;
170 int pline;
171
172 PDC_LOG(("pnoutrefresh() - called\n"));
173
174 if (py < 0)
175 py = 0;
176 if (px < 0)
177 px = 0;
178 if (sy1 < 0)
179 sy1 = 0;
180 if (sx1 < 0)
181 sx1 = 0;
182
183 if ((!w || !(w->_flags & (_PAD|_SUBPAD)) ||
184 (sy2 >= LINES) || (sx2 >= COLS)) ||
185 (sy2 < sy1) || (sx2 < sx1))
186 return ERR;
187
188 sline = sy1;
189 pline = py;
190
191 num_cols = min((sx2 - sx1 + 1), (w->_maxx - px));
192
193 while (sline <= sy2)
194 {
195 if (pline < w->_maxy)
196 {
197 memcpy(curscr->_y[sline] + sx1, w->_y[pline] + px,
198 num_cols * sizeof(chtype));
199
200 if ((curscr->_firstch[sline] == _NO_CHANGE)
201 || (curscr->_firstch[sline] > sx1))
202 curscr->_firstch[sline] = sx1;
203
204 if (sx2 > curscr->_lastch[sline])
205 curscr->_lastch[sline] = sx2;
206
207 w->_firstch[pline] = _NO_CHANGE; /* updated now */
208 w->_lastch[pline] = _NO_CHANGE; /* updated now */
209 }
210
211 sline++;
212 pline++;
213 }
214
215 if (w->_clear)
216 {
217 w->_clear = FALSE;
218 curscr->_clear = TRUE;
219 }
220
221 /* position the cursor to the pad's current position if possible --
222 is the pad current position going to end up displayed? if not,
223 then don't move the cursor; if so, move it to the correct place */
224
225 if (!w->_leaveit && w->_cury >= py && w->_curx >= px &&
226 w->_cury <= py + (sy2 - sy1) && w->_curx <= px + (sx2 - sx1))
227 {
228 curscr->_cury = (w->_cury - py) + sy1;
229 curscr->_curx = (w->_curx - px) + sx1;
230 }
231
232 w->_pad._pad_y = py;
233 w->_pad._pad_x = px;
234 w->_pad._pad_top = sy1;
235 w->_pad._pad_left = sx1;
236 w->_pad._pad_bottom = sy2;
237 w->_pad._pad_right = sx2;
238
239 return OK;
240}
241
242int pechochar(WINDOW *pad, chtype ch)
243{
244 PDC_LOG(("pechochar() - called\n"));
245
246 if (waddch(pad, ch) == ERR)
247 return ERR;
248
249 return prefresh(pad, pad->_pad._pad_y, pad->_pad._pad_x, pad->_pad._pad_top,
250 pad->_pad._pad_left, pad->_pad._pad_bottom, pad->_pad._pad_right);
251}
252
253#ifdef PDC_WIDE
254int pecho_wchar(WINDOW *pad, const cchar_t *wch)
255{
256 PDC_LOG(("pecho_wchar() - called\n"));
257
258 if (!wch || (waddch(pad, *wch) == ERR))
259 return ERR;
260
261 return prefresh(pad, pad->_pad._pad_y, pad->_pad._pad_x, pad->_pad._pad_top,
262 pad->_pad._pad_left, pad->_pad._pad_bottom, pad->_pad._pad_right);
263}
264#endif
265
266bool is_pad(const WINDOW *pad)
267{
268 PDC_LOG(("is_pad() - called\n"));
269
270 if (!pad)
271 return FALSE;
272
273 return (pad->_flags & _PAD) ? TRUE : FALSE;
274}
diff --git a/scripts/kconfig/libcurses/pdcclip.c b/scripts/kconfig/libcurses/pdcclip.c
new file mode 100644
index 000000000..740221280
--- /dev/null
+++ b/scripts/kconfig/libcurses/pdcclip.c
@@ -0,0 +1,149 @@
1/* PDCurses */
2
3#include "pdcwin.h"
4
5#include <string.h>
6
7/*man-start**************************************************************
8
9clipboard
10---------
11
12### Synopsis
13
14 int PDC_getclipboard(char **contents, long *length);
15 int PDC_setclipboard(const char *contents, long length);
16 int PDC_freeclipboard(char *contents);
17 int PDC_clearclipboard(void);
18
19### Description
20
21 PDC_getclipboard() gets the textual contents of the system's
22 clipboard. This function returns the contents of the clipboard in the
23 contents argument. It is the responsibility of the caller to free the
24 memory returned, via PDC_freeclipboard(). The length of the clipboard
25 contents is returned in the length argument.
26
27 PDC_setclipboard copies the supplied text into the system's
28 clipboard, emptying the clipboard prior to the copy.
29
30 PDC_clearclipboard() clears the internal clipboard.
31
32### Return Values
33
34 indicator of success/failure of call.
35 PDC_CLIP_SUCCESS the call was successful
36 PDC_CLIP_MEMORY_ERROR unable to allocate sufficient memory for
37 the clipboard contents
38 PDC_CLIP_EMPTY the clipboard contains no text
39 PDC_CLIP_ACCESS_ERROR no clipboard support
40
41### Portability
42 X/Open ncurses NetBSD
43 PDC_getclipboard - - -
44 PDC_setclipboard - - -
45 PDC_freeclipboard - - -
46 PDC_clearclipboard - - -
47
48**man-end****************************************************************/
49
50#ifdef PDC_WIDE
51# define PDC_TEXT CF_UNICODETEXT
52#else
53# define PDC_TEXT CF_OEMTEXT
54#endif
55
56int PDC_getclipboard(char **contents, long *length)
57{
58 HANDLE handle;
59 long len;
60
61 PDC_LOG(("PDC_getclipboard() - called\n"));
62
63 if (!OpenClipboard(NULL))
64 return PDC_CLIP_ACCESS_ERROR;
65
66 if ((handle = GetClipboardData(PDC_TEXT)) == NULL)
67 {
68 CloseClipboard();
69 return PDC_CLIP_EMPTY;
70 }
71
72#ifdef PDC_WIDE
73 len = wcslen((wchar_t *)handle) * 3;
74#else
75 len = strlen((char *)handle);
76#endif
77 *contents = (char *)GlobalAlloc(GMEM_FIXED, len + 1);
78
79 if (!*contents)
80 {
81 CloseClipboard();
82 return PDC_CLIP_MEMORY_ERROR;
83 }
84
85#ifdef PDC_WIDE
86 len = PDC_wcstombs((char *)*contents, (wchar_t *)handle, len);
87#else
88 strcpy((char *)*contents, (char *)handle);
89#endif
90 *length = len;
91 CloseClipboard();
92
93 return PDC_CLIP_SUCCESS;
94}
95
96int PDC_setclipboard(const char *contents, long length)
97{
98 HGLOBAL ptr1;
99 LPTSTR ptr2;
100
101 PDC_LOG(("PDC_setclipboard() - called\n"));
102
103 if (!OpenClipboard(NULL))
104 return PDC_CLIP_ACCESS_ERROR;
105
106 ptr1 = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE,
107 (length + 1) * sizeof(TCHAR));
108
109 if (!ptr1)
110 return PDC_CLIP_MEMORY_ERROR;
111
112 ptr2 = GlobalLock(ptr1);
113
114#ifdef PDC_WIDE
115 PDC_mbstowcs((wchar_t *)ptr2, contents, length);
116#else
117 memcpy((char *)ptr2, contents, length + 1);
118#endif
119 GlobalUnlock(ptr1);
120 EmptyClipboard();
121
122 if (!SetClipboardData(PDC_TEXT, ptr1))
123 {
124 GlobalFree(ptr1);
125 return PDC_CLIP_ACCESS_ERROR;
126 }
127
128 CloseClipboard();
129 GlobalFree(ptr1);
130
131 return PDC_CLIP_SUCCESS;
132}
133
134int PDC_freeclipboard(char *contents)
135{
136 PDC_LOG(("PDC_freeclipboard() - called\n"));
137
138 GlobalFree(contents);
139 return PDC_CLIP_SUCCESS;
140}
141
142int PDC_clearclipboard(void)
143{
144 PDC_LOG(("PDC_clearclipboard() - called\n"));
145
146 EmptyClipboard();
147
148 return PDC_CLIP_SUCCESS;
149}
diff --git a/scripts/kconfig/libcurses/pdcdisp.c b/scripts/kconfig/libcurses/pdcdisp.c
new file mode 100644
index 000000000..f6115ecb0
--- /dev/null
+++ b/scripts/kconfig/libcurses/pdcdisp.c
@@ -0,0 +1,329 @@
1/* PDCurses */
2
3#include "pdcwin.h"
4
5#include <stdlib.h>
6#include <string.h>
7
8#ifdef PDC_WIDE
9# include "acsuni.h"
10#else
11# include "acs437.h"
12#endif
13
14DWORD pdc_last_blink;
15static bool blinked_off = FALSE;
16static bool in_italic = FALSE;
17
18/* position hardware cursor at (y, x) */
19
20void PDC_gotoyx(int row, int col)
21{
22 COORD coord;
23
24 PDC_LOG(("PDC_gotoyx() - called: row %d col %d from row %d col %d\n",
25 row, col, SP->cursrow, SP->curscol));
26
27 coord.X = col;
28 coord.Y = row;
29
30 SetConsoleCursorPosition(pdc_con_out, coord);
31}
32
33void _set_ansi_color(short f, short b, attr_t attr)
34{
35 char esc[64], *p;
36 short tmp, underline;
37 bool italic;
38
39 if (f < 16 && !pdc_color[f].mapped)
40 f = pdc_curstoansi[f];
41
42 if (b < 16 && !pdc_color[b].mapped)
43 b = pdc_curstoansi[b];
44
45 if (attr & A_REVERSE)
46 {
47 tmp = f;
48 f = b;
49 b = tmp;
50 }
51 attr &= SP->termattrs;
52 italic = !!(attr & A_ITALIC);
53 underline = !!(attr & A_UNDERLINE);
54
55 p = esc + sprintf(esc, "\x1b[");
56
57 if (f != pdc_oldf)
58 {
59 if (f < 8 && !pdc_color[f].mapped)
60 p += sprintf(p, "%d", f + 30);
61 else if (f < 16 && !pdc_color[f].mapped)
62 p += sprintf(p, "%d", f + 82);
63 else if (f < 256 && !pdc_color[f].mapped)
64 p += sprintf(p, "38;5;%d", f);
65 else
66 {
67 short red = DIVROUND(pdc_color[f].r * 255, 1000);
68 short green = DIVROUND(pdc_color[f].g * 255, 1000);
69 short blue = DIVROUND(pdc_color[f].b * 255, 1000);
70
71 p += sprintf(p, "38;2;%d;%d;%d", red, green, blue);
72 }
73
74 pdc_oldf = f;
75 }
76
77 if (b != pdc_oldb)
78 {
79 if (strlen(esc) > 2)
80 p += sprintf(p, ";");
81
82 if (b < 8 && !pdc_color[b].mapped)
83 p += sprintf(p, "%d", b + 40);
84 else if (b < 16 && !pdc_color[b].mapped)
85 p += sprintf(p, "%d", b + 92);
86 else if (b < 256 && !pdc_color[b].mapped)
87 p += sprintf(p, "48;5;%d", b);
88 else
89 {
90 short red = DIVROUND(pdc_color[b].r * 255, 1000);
91 short green = DIVROUND(pdc_color[b].g * 255, 1000);
92 short blue = DIVROUND(pdc_color[b].b * 255, 1000);
93
94 p += sprintf(p, "48;2;%d;%d;%d", red, green, blue);
95 }
96
97 pdc_oldb = b;
98 }
99
100 if (italic != in_italic)
101 {
102 if (strlen(esc) > 2)
103 p += sprintf(p, ";");
104
105 if (italic)
106 p += sprintf(p, "3");
107 else
108 p += sprintf(p, "23");
109
110 in_italic = italic;
111 }
112
113 if (underline != pdc_oldu)
114 {
115 if (strlen(esc) > 2)
116 p += sprintf(p, ";");
117
118 if (underline)
119 p += sprintf(p, "4");
120 else
121 p += sprintf(p, "24");
122
123 pdc_oldu = underline;
124 }
125
126 if (strlen(esc) > 2)
127 {
128 sprintf(p, "m");
129 if (!pdc_conemu)
130 SetConsoleMode(pdc_con_out, 0x0015);
131
132 WriteConsoleA(pdc_con_out, esc, strlen(esc), NULL, NULL);
133
134 if (!pdc_conemu)
135 SetConsoleMode(pdc_con_out, 0x0010);
136 }
137}
138
139void _new_packet(attr_t attr, int lineno, int x, int len, const chtype *srcp)
140{
141 int j;
142 short fore, back;
143 bool blink, ansi;
144
145 if (pdc_ansi && (lineno == (SP->lines - 1)) && ((x + len) == SP->cols))
146 {
147 len--;
148 if (len)
149 _new_packet(attr, lineno, x, len, srcp);
150 pdc_ansi = FALSE;
151 _new_packet(attr, lineno, x + len, 1, srcp + len);
152 pdc_ansi = TRUE;
153 return;
154 }
155
156 pair_content(PAIR_NUMBER(attr), &fore, &back);
157 ansi = pdc_ansi || (fore >= 16 || back >= 16);
158 blink = (SP->termattrs & A_BLINK) && (attr & A_BLINK);
159
160 if (blink)
161 {
162 attr &= ~A_BLINK;
163 if (blinked_off)
164 attr &= ~(A_UNDERLINE | A_RIGHT | A_LEFT);
165 }
166
167 if (attr & A_BOLD)
168 fore |= 8;
169 if (attr & A_BLINK)
170 back |= 8;
171
172 if (ansi)
173 {
174#ifdef PDC_WIDE
175 WCHAR buffer[512];
176#else
177 char buffer[512];
178#endif
179 for (j = 0; j < len; j++)
180 {
181 chtype ch = srcp[j];
182
183 if (ch & A_ALTCHARSET && !(ch & 0xff80))
184 {
185 ch = acs_map[ch & 0x7f];
186
187 if (pdc_wt && (ch & A_CHARTEXT) < ' ')
188 goto NONANSI;
189 }
190
191 if (blink && blinked_off)
192 ch = ' ';
193
194 buffer[j] = ch & A_CHARTEXT;
195 }
196
197 PDC_gotoyx(lineno, x);
198 _set_ansi_color(fore, back, attr);
199#ifdef PDC_WIDE
200 WriteConsoleW(pdc_con_out, buffer, len, NULL, NULL);
201#else
202 WriteConsoleA(pdc_con_out, buffer, len, NULL, NULL);
203#endif
204 }
205 else
206NONANSI:
207 {
208 CHAR_INFO buffer[512];
209 COORD bufSize, bufPos;
210 SMALL_RECT sr;
211 WORD mapped_attr;
212
213 fore = pdc_curstoreal[fore];
214 back = pdc_curstoreal[back];
215
216 if (attr & A_REVERSE)
217 mapped_attr = back | (fore << 4);
218 else
219 mapped_attr = fore | (back << 4);
220
221 if (attr & A_UNDERLINE)
222 mapped_attr |= 0x8000; /* COMMON_LVB_UNDERSCORE */
223 if (attr & A_LEFT)
224 mapped_attr |= 0x0800; /* COMMON_LVB_GRID_LVERTICAL */
225 if (attr & A_RIGHT)
226 mapped_attr |= 0x1000; /* COMMON_LVB_GRID_RVERTICAL */
227
228 for (j = 0; j < len; j++)
229 {
230 chtype ch = srcp[j];
231
232 if (ch & A_ALTCHARSET && !(ch & 0xff80))
233 ch = acs_map[ch & 0x7f];
234
235 if (blink && blinked_off)
236 ch = ' ';
237
238 buffer[j].Attributes = mapped_attr;
239 buffer[j].Char.UnicodeChar = ch & A_CHARTEXT;
240 }
241
242 bufPos.X = bufPos.Y = 0;
243 bufSize.X = len;
244 bufSize.Y = 1;
245
246 sr.Top = sr.Bottom = lineno;
247 sr.Left = x;
248 sr.Right = x + len - 1;
249
250 WriteConsoleOutput(pdc_con_out, buffer, bufSize, bufPos, &sr);
251 }
252}
253
254/* update the given physical line to look like the corresponding line in
255 curscr */
256
257void PDC_transform_line(int lineno, int x, int len, const chtype *srcp)
258{
259 attr_t old_attr, attr;
260 int i, j;
261
262 PDC_LOG(("PDC_transform_line() - called: lineno=%d\n", lineno));
263
264 old_attr = *srcp & (A_ATTRIBUTES ^ A_ALTCHARSET);
265
266 for (i = 1, j = 1; j < len; i++, j++)
267 {
268 attr = srcp[i] & (A_ATTRIBUTES ^ A_ALTCHARSET);
269
270 if (attr != old_attr)
271 {
272 _new_packet(old_attr, lineno, x, i, srcp);
273 old_attr = attr;
274 srcp += i;
275 x += i;
276 i = 0;
277 }
278 }
279
280 _new_packet(old_attr, lineno, x, i, srcp);
281}
282
283void PDC_blink_text(void)
284{
285 CONSOLE_CURSOR_INFO cci;
286 int i, j, k;
287 bool oldvis;
288
289 GetConsoleCursorInfo(pdc_con_out, &cci);
290 oldvis = cci.bVisible;
291 if (oldvis)
292 {
293 cci.bVisible = FALSE;
294 SetConsoleCursorInfo(pdc_con_out, &cci);
295 }
296
297 if (!(SP->termattrs & A_BLINK))
298 blinked_off = FALSE;
299 else
300 blinked_off = !blinked_off;
301
302 for (i = 0; i < SP->lines; i++)
303 {
304 const chtype *srcp = curscr->_y[i];
305
306 for (j = 0; j < SP->cols; j++)
307 if (srcp[j] & A_BLINK)
308 {
309 k = j;
310 while (k < SP->cols && (srcp[k] & A_BLINK))
311 k++;
312 PDC_transform_line(i, j, k - j, srcp + j);
313 j = k;
314 }
315 }
316
317 PDC_gotoyx(SP->cursrow, SP->curscol);
318 if (oldvis)
319 {
320 cci.bVisible = TRUE;
321 SetConsoleCursorInfo(pdc_con_out, &cci);
322 }
323
324 pdc_last_blink = GetTickCount();
325}
326
327void PDC_doupdate(void)
328{
329}
diff --git a/scripts/kconfig/libcurses/pdcgetsc.c b/scripts/kconfig/libcurses/pdcgetsc.c
new file mode 100644
index 000000000..a8323ebc1
--- /dev/null
+++ b/scripts/kconfig/libcurses/pdcgetsc.c
@@ -0,0 +1,42 @@
1/* PDCurses */
2
3#include "pdcwin.h"
4
5/* get the cursor size/shape */
6
7int PDC_get_cursor_mode(void)
8{
9 CONSOLE_CURSOR_INFO ci;
10
11 PDC_LOG(("PDC_get_cursor_mode() - called\n"));
12
13 GetConsoleCursorInfo(pdc_con_out, &ci);
14
15 return ci.dwSize;
16}
17
18/* return number of screen rows */
19
20int PDC_get_rows(void)
21{
22 CONSOLE_SCREEN_BUFFER_INFO scr;
23
24 PDC_LOG(("PDC_get_rows() - called\n"));
25
26 GetConsoleScreenBufferInfo(pdc_con_out, &scr);
27
28 return scr.srWindow.Bottom - scr.srWindow.Top + 1;
29}
30
31/* return width of screen/viewport */
32
33int PDC_get_columns(void)
34{
35 CONSOLE_SCREEN_BUFFER_INFO scr;
36
37 PDC_LOG(("PDC_get_columns() - called\n"));
38
39 GetConsoleScreenBufferInfo(pdc_con_out, &scr);
40
41 return scr.srWindow.Right - scr.srWindow.Left + 1;
42}
diff --git a/scripts/kconfig/libcurses/pdckbd.c b/scripts/kconfig/libcurses/pdckbd.c
new file mode 100644
index 000000000..cbab60d63
--- /dev/null
+++ b/scripts/kconfig/libcurses/pdckbd.c
@@ -0,0 +1,693 @@
1/* PDCurses */
2
3#include "pdcwin.h"
4
5/* These variables are used to store information about the next
6 Input Event. */
7
8static INPUT_RECORD save_ip;
9static MOUSE_STATUS old_mouse_status;
10static DWORD event_count = 0;
11static SHORT left_key;
12static int key_count = 0;
13static int save_press = 0;
14
15#define KEV save_ip.Event.KeyEvent
16#define MEV save_ip.Event.MouseEvent
17#define REV save_ip.Event.WindowBufferSizeEvent
18
19/************************************************************************
20 * Table for key code translation of function keys in keypad mode *
21 * These values are for strict IBM keyboard compatibles only *
22 ************************************************************************/
23
24typedef struct
25{
26 unsigned short normal;
27 unsigned short shift;
28 unsigned short control;
29 unsigned short alt;
30 unsigned short extended;
31} KPTAB;
32
33static KPTAB kptab[] =
34{
35 {0, 0, 0, 0, 0 }, /* 0 */
36 {0, 0, 0, 0, 0 }, /* 1 VK_LBUTTON */
37 {0, 0, 0, 0, 0 }, /* 2 VK_RBUTTON */
38 {0, 0, 0, 0, 0 }, /* 3 VK_CANCEL */
39 {0, 0, 0, 0, 0 }, /* 4 VK_MBUTTON */
40 {0, 0, 0, 0, 0 }, /* 5 */
41 {0, 0, 0, 0, 0 }, /* 6 */
42 {0, 0, 0, 0, 0 }, /* 7 */
43 {0x08, 0x08, 0x7F, ALT_BKSP, 0 }, /* 8 VK_BACK */
44 {0x09, KEY_BTAB, CTL_TAB, ALT_TAB, 999 }, /* 9 VK_TAB */
45 {0, 0, 0, 0, 0 }, /* 10 */
46 {0, 0, 0, 0, 0 }, /* 11 */
47 {KEY_B2, 0x35, CTL_PAD5, ALT_PAD5, 0 }, /* 12 VK_CLEAR */
48 {0x0D, 0x0D, CTL_ENTER, ALT_ENTER, 1 }, /* 13 VK_RETURN */
49 {0, 0, 0, 0, 0 }, /* 14 */
50 {0, 0, 0, 0, 0 }, /* 15 */
51 {0, 0, 0, 0, 0 }, /* 16 VK_SHIFT HANDLED SEPARATELY */
52 {0, 0, 0, 0, 0 }, /* 17 VK_CONTROL HANDLED SEPARATELY */
53 {0, 0, 0, 0, 0 }, /* 18 VK_MENU HANDLED SEPARATELY */
54 {0, 0, 0, 0, 0 }, /* 19 VK_PAUSE */
55 {0, 0, 0, 0, 0 }, /* 20 VK_CAPITAL HANDLED SEPARATELY */
56 {0, 0, 0, 0, 0 }, /* 21 VK_HANGUL */
57 {0, 0, 0, 0, 0 }, /* 22 */
58 {0, 0, 0, 0, 0 }, /* 23 VK_JUNJA */
59 {0, 0, 0, 0, 0 }, /* 24 VK_FINAL */
60 {0, 0, 0, 0, 0 }, /* 25 VK_HANJA */
61 {0, 0, 0, 0, 0 }, /* 26 */
62 {0x1B, 0x1B, 0x1B, ALT_ESC, 0 }, /* 27 VK_ESCAPE */
63 {0, 0, 0, 0, 0 }, /* 28 VK_CONVERT */
64 {0, 0, 0, 0, 0 }, /* 29 VK_NONCONVERT */
65 {0, 0, 0, 0, 0 }, /* 30 VK_ACCEPT */
66 {0, 0, 0, 0, 0 }, /* 31 VK_MODECHANGE */
67 {0x20, 0x20, 0x20, 0x20, 0 }, /* 32 VK_SPACE */
68 {KEY_A3, 0x39, CTL_PAD9, ALT_PAD9, 3 }, /* 33 VK_PRIOR */
69 {KEY_C3, 0x33, CTL_PAD3, ALT_PAD3, 4 }, /* 34 VK_NEXT */
70 {KEY_C1, 0x31, CTL_PAD1, ALT_PAD1, 5 }, /* 35 VK_END */
71 {KEY_A1, 0x37, CTL_PAD7, ALT_PAD7, 6 }, /* 36 VK_HOME */
72 {KEY_B1, 0x34, CTL_PAD4, ALT_PAD4, 7 }, /* 37 VK_LEFT */
73 {KEY_A2, 0x38, CTL_PAD8, ALT_PAD8, 8 }, /* 38 VK_UP */
74 {KEY_B3, 0x36, CTL_PAD6, ALT_PAD6, 9 }, /* 39 VK_RIGHT */
75 {KEY_C2, 0x32, CTL_PAD2, ALT_PAD2, 10 }, /* 40 VK_DOWN */
76 {0, 0, 0, 0, 0 }, /* 41 VK_SELECT */
77 {0, 0, 0, 0, 0 }, /* 42 VK_PRINT */
78 {0, 0, 0, 0, 0 }, /* 43 VK_EXECUTE */
79 {0, 0, 0, 0, 0 }, /* 44 VK_SNAPSHOT*/
80 {PAD0, 0x30, CTL_PAD0, ALT_PAD0, 11 }, /* 45 VK_INSERT */
81 {PADSTOP, 0x2E, CTL_PADSTOP, ALT_PADSTOP,12 }, /* 46 VK_DELETE */
82 {0, 0, 0, 0, 0 }, /* 47 VK_HELP */
83 {0x30, 0x29, 0, ALT_0, 0 }, /* 48 */
84 {0x31, 0x21, 0, ALT_1, 0 }, /* 49 */
85 {0x32, 0x40, 0, ALT_2, 0 }, /* 50 */
86 {0x33, 0x23, 0, ALT_3, 0 }, /* 51 */
87 {0x34, 0x24, 0, ALT_4, 0 }, /* 52 */
88 {0x35, 0x25, 0, ALT_5, 0 }, /* 53 */
89 {0x36, 0x5E, 0, ALT_6, 0 }, /* 54 */
90 {0x37, 0x26, 0, ALT_7, 0 }, /* 55 */
91 {0x38, 0x2A, 0, ALT_8, 0 }, /* 56 */
92 {0x39, 0x28, 0, ALT_9, 0 }, /* 57 */
93 {0, 0, 0, 0, 0 }, /* 58 */
94 {0, 0, 0, 0, 0 }, /* 59 */
95 {0, 0, 0, 0, 0 }, /* 60 */
96 {0, 0, 0, 0, 0 }, /* 61 */
97 {0, 0, 0, 0, 0 }, /* 62 */
98 {0, 0, 0, 0, 0 }, /* 63 */
99 {0, 0, 0, 0, 0 }, /* 64 */
100 {0x61, 0x41, 0x01, ALT_A, 0 }, /* 65 */
101 {0x62, 0x42, 0x02, ALT_B, 0 }, /* 66 */
102 {0x63, 0x43, 0x03, ALT_C, 0 }, /* 67 */
103 {0x64, 0x44, 0x04, ALT_D, 0 }, /* 68 */
104 {0x65, 0x45, 0x05, ALT_E, 0 }, /* 69 */
105 {0x66, 0x46, 0x06, ALT_F, 0 }, /* 70 */
106 {0x67, 0x47, 0x07, ALT_G, 0 }, /* 71 */
107 {0x68, 0x48, 0x08, ALT_H, 0 }, /* 72 */
108 {0x69, 0x49, 0x09, ALT_I, 0 }, /* 73 */
109 {0x6A, 0x4A, 0x0A, ALT_J, 0 }, /* 74 */
110 {0x6B, 0x4B, 0x0B, ALT_K, 0 }, /* 75 */
111 {0x6C, 0x4C, 0x0C, ALT_L, 0 }, /* 76 */
112 {0x6D, 0x4D, 0x0D, ALT_M, 0 }, /* 77 */
113 {0x6E, 0x4E, 0x0E, ALT_N, 0 }, /* 78 */
114 {0x6F, 0x4F, 0x0F, ALT_O, 0 }, /* 79 */
115 {0x70, 0x50, 0x10, ALT_P, 0 }, /* 80 */
116 {0x71, 0x51, 0x11, ALT_Q, 0 }, /* 81 */
117 {0x72, 0x52, 0x12, ALT_R, 0 }, /* 82 */
118 {0x73, 0x53, 0x13, ALT_S, 0 }, /* 83 */
119 {0x74, 0x54, 0x14, ALT_T, 0 }, /* 84 */
120 {0x75, 0x55, 0x15, ALT_U, 0 }, /* 85 */
121 {0x76, 0x56, 0x16, ALT_V, 0 }, /* 86 */
122 {0x77, 0x57, 0x17, ALT_W, 0 }, /* 87 */
123 {0x78, 0x58, 0x18, ALT_X, 0 }, /* 88 */
124 {0x79, 0x59, 0x19, ALT_Y, 0 }, /* 89 */
125 {0x7A, 0x5A, 0x1A, ALT_Z, 0 }, /* 90 */
126 {0, 0, 0, 0, 0 }, /* 91 VK_LWIN */
127 {0, 0, 0, 0, 0 }, /* 92 VK_RWIN */
128 {0, 0, 0, 0, 0 }, /* 93 VK_APPS */
129 {0, 0, 0, 0, 0 }, /* 94 */
130 {0, 0, 0, 0, 0 }, /* 95 */
131 {0x30, 0, CTL_PAD0, ALT_PAD0, 0 }, /* 96 VK_NUMPAD0 */
132 {0x31, 0, CTL_PAD1, ALT_PAD1, 0 }, /* 97 VK_NUMPAD1 */
133 {0x32, 0, CTL_PAD2, ALT_PAD2, 0 }, /* 98 VK_NUMPAD2 */
134 {0x33, 0, CTL_PAD3, ALT_PAD3, 0 }, /* 99 VK_NUMPAD3 */
135 {0x34, 0, CTL_PAD4, ALT_PAD4, 0 }, /* 100 VK_NUMPAD4 */
136 {0x35, 0, CTL_PAD5, ALT_PAD5, 0 }, /* 101 VK_NUMPAD5 */
137 {0x36, 0, CTL_PAD6, ALT_PAD6, 0 }, /* 102 VK_NUMPAD6 */
138 {0x37, 0, CTL_PAD7, ALT_PAD7, 0 }, /* 103 VK_NUMPAD7 */
139 {0x38, 0, CTL_PAD8, ALT_PAD8, 0 }, /* 104 VK_NUMPAD8 */
140 {0x39, 0, CTL_PAD9, ALT_PAD9, 0 }, /* 105 VK_NUMPAD9 */
141 {PADSTAR, SHF_PADSTAR,CTL_PADSTAR, ALT_PADSTAR,999 }, /* 106 VK_MULTIPLY*/
142 {PADPLUS, SHF_PADPLUS,CTL_PADPLUS, ALT_PADPLUS,999 }, /* 107 VK_ADD */
143 {0, 0, 0, 0, 0 }, /* 108 VK_SEPARATOR */
144 {PADMINUS, SHF_PADMINUS,CTL_PADMINUS,ALT_PADMINUS,999}, /* 109 VK_SUBTRACT*/
145 {0x2E, 0, CTL_PADSTOP, ALT_PADSTOP,0 }, /* 110 VK_DECIMAL */
146 {PADSLASH, SHF_PADSLASH,CTL_PADSLASH,ALT_PADSLASH,2 }, /* 111 VK_DIVIDE */
147 {KEY_F(1), KEY_F(13), KEY_F(25), KEY_F(37), 0 }, /* 112 VK_F1 */
148 {KEY_F(2), KEY_F(14), KEY_F(26), KEY_F(38), 0 }, /* 113 VK_F2 */
149 {KEY_F(3), KEY_F(15), KEY_F(27), KEY_F(39), 0 }, /* 114 VK_F3 */
150 {KEY_F(4), KEY_F(16), KEY_F(28), KEY_F(40), 0 }, /* 115 VK_F4 */
151 {KEY_F(5), KEY_F(17), KEY_F(29), KEY_F(41), 0 }, /* 116 VK_F5 */
152 {KEY_F(6), KEY_F(18), KEY_F(30), KEY_F(42), 0 }, /* 117 VK_F6 */
153 {KEY_F(7), KEY_F(19), KEY_F(31), KEY_F(43), 0 }, /* 118 VK_F7 */
154 {KEY_F(8), KEY_F(20), KEY_F(32), KEY_F(44), 0 }, /* 119 VK_F8 */
155 {KEY_F(9), KEY_F(21), KEY_F(33), KEY_F(45), 0 }, /* 120 VK_F9 */
156 {KEY_F(10), KEY_F(22), KEY_F(34), KEY_F(46), 0 }, /* 121 VK_F10 */
157 {KEY_F(11), KEY_F(23), KEY_F(35), KEY_F(47), 0 }, /* 122 VK_F11 */
158 {KEY_F(12), KEY_F(24), KEY_F(36), KEY_F(48), 0 }, /* 123 VK_F12 */
159
160 /* 124 through 218 */
161
162 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
163 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
164 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
165 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
166 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
167 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
168 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
169 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
170 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
171 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
172 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
173 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
174 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
175 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
176 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
177 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
178 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
179 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
180 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
181 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
182 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
183 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
184 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
185 {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
186
187 {0x5B, 0x7B, 0x1B, ALT_LBRACKET,0 }, /* 219 */
188 {0x5C, 0x7C, 0x1C, ALT_BSLASH, 0 }, /* 220 */
189 {0x5D, 0x7D, 0x1D, ALT_RBRACKET,0 }, /* 221 */
190 {0, 0, 0x27, ALT_FQUOTE, 0 }, /* 222 */
191 {0, 0, 0, 0, 0 }, /* 223 */
192 {0, 0, 0, 0, 0 }, /* 224 */
193 {0, 0, 0, 0, 0 }, /* 225 */
194 {0, 0, 0, 0, 0 }, /* 226 */
195 {0, 0, 0, 0, 0 }, /* 227 */
196 {0, 0, 0, 0, 0 }, /* 228 */
197 {0, 0, 0, 0, 0 }, /* 229 */
198 {0, 0, 0, 0, 0 }, /* 230 */
199 {0, 0, 0, 0, 0 }, /* 231 */
200 {0, 0, 0, 0, 0 }, /* 232 */
201 {0, 0, 0, 0, 0 }, /* 233 */
202 {0, 0, 0, 0, 0 }, /* 234 */
203 {0, 0, 0, 0, 0 }, /* 235 */
204 {0, 0, 0, 0, 0 }, /* 236 */
205 {0, 0, 0, 0, 0 }, /* 237 */
206 {0, 0, 0, 0, 0 }, /* 238 */
207 {0, 0, 0, 0, 0 }, /* 239 */
208 {0, 0, 0, 0, 0 }, /* 240 */
209 {0, 0, 0, 0, 0 }, /* 241 */
210 {0, 0, 0, 0, 0 }, /* 242 */
211 {0, 0, 0, 0, 0 }, /* 243 */
212 {0, 0, 0, 0, 0 }, /* 244 */
213 {0, 0, 0, 0, 0 }, /* 245 */
214 {0, 0, 0, 0, 0 }, /* 246 */
215 {0, 0, 0, 0, 0 }, /* 247 */
216 {0, 0, 0, 0, 0 }, /* 248 */
217 {0, 0, 0, 0, 0 }, /* 249 */
218 {0, 0, 0, 0, 0 }, /* 250 */
219 {0, 0, 0, 0, 0 }, /* 251 */
220 {0, 0, 0, 0, 0 }, /* 252 */
221 {0, 0, 0, 0, 0 }, /* 253 */
222 {0, 0, 0, 0, 0 }, /* 254 */
223 {0, 0, 0, 0, 0 } /* 255 */
224};
225
226static KPTAB ext_kptab[] =
227{
228 {0, 0, 0, 0, }, /* MUST BE EMPTY */
229 {PADENTER, SHF_PADENTER, CTL_PADENTER, ALT_PADENTER}, /* 13 */
230 {PADSLASH, SHF_PADSLASH, CTL_PADSLASH, ALT_PADSLASH}, /* 111 */
231 {KEY_PPAGE, KEY_SPREVIOUS, CTL_PGUP, ALT_PGUP }, /* 33 */
232 {KEY_NPAGE, KEY_SNEXT, CTL_PGDN, ALT_PGDN }, /* 34 */
233 {KEY_END, KEY_SEND, CTL_END, ALT_END }, /* 35 */
234 {KEY_HOME, KEY_SHOME, CTL_HOME, ALT_HOME }, /* 36 */
235 {KEY_LEFT, KEY_SLEFT, CTL_LEFT, ALT_LEFT }, /* 37 */
236 {KEY_UP, KEY_SUP, CTL_UP, ALT_UP }, /* 38 */
237 {KEY_RIGHT, KEY_SRIGHT, CTL_RIGHT, ALT_RIGHT }, /* 39 */
238 {KEY_DOWN, KEY_SDOWN, CTL_DOWN, ALT_DOWN }, /* 40 */
239 {KEY_IC, KEY_SIC, CTL_INS, ALT_INS }, /* 45 */
240 {KEY_DC, KEY_SDC, CTL_DEL, ALT_DEL }, /* 46 */
241 {PADSLASH, SHF_PADSLASH, CTL_PADSLASH, ALT_PADSLASH}, /* 191 */
242};
243
244/* End of kptab[] */
245
246void PDC_set_keyboard_binary(bool on)
247{
248 DWORD mode;
249
250 PDC_LOG(("PDC_set_keyboard_binary() - called\n"));
251
252 GetConsoleMode(pdc_con_in, &mode);
253 SetConsoleMode(pdc_con_in, !on ? (mode | ENABLE_PROCESSED_INPUT) :
254 (mode & ~ENABLE_PROCESSED_INPUT));
255}
256
257/* check if a key or mouse event is waiting */
258
259bool PDC_check_key(void)
260{
261 if (key_count > 0)
262 return TRUE;
263
264 GetNumberOfConsoleInputEvents(pdc_con_in, &event_count);
265
266 return (event_count != 0);
267}
268
269/* _get_key_count returns 0 if save_ip doesn't contain an event which
270 should be passed back to the user. This function filters "useless"
271 events.
272
273 The function returns the number of keys waiting. This may be > 1
274 if the repetition of real keys pressed so far are > 1.
275
276 Returns 0 on NUMLOCK, CAPSLOCK, SCROLLLOCK.
277
278 Returns 1 for SHIFT, ALT, CTRL only if no other key has been pressed
279 in between, and SP->return_key_modifiers is set; these are returned
280 on keyup.
281
282 Normal keys are returned on keydown only. The number of repetitions
283 are returned. Dead keys (diacritics) are omitted. See below for a
284 description.
285*/
286
287static int _get_key_count(void)
288{
289 int num_keys = 0, vk;
290
291 PDC_LOG(("_get_key_count() - called\n"));
292
293 vk = KEV.wVirtualKeyCode;
294
295 if (KEV.bKeyDown)
296 {
297 /* key down */
298
299 save_press = 0;
300
301 if (vk == VK_CAPITAL || vk == VK_NUMLOCK || vk == VK_SCROLL)
302 {
303 /* throw away these modifiers */
304 }
305 else if (vk == VK_SHIFT || vk == VK_CONTROL || vk == VK_MENU)
306 {
307 /* These keys are returned on keyup only. */
308
309 save_press = vk;
310 switch (vk)
311 {
312 case VK_SHIFT:
313 left_key = GetKeyState(VK_LSHIFT);
314 break;
315 case VK_CONTROL:
316 left_key = GetKeyState(VK_LCONTROL);
317 break;
318 case VK_MENU:
319 left_key = GetKeyState(VK_LMENU);
320 }
321 }
322 else
323 {
324 /* Check for diacritics. These are dead keys. Some locales
325 have modified characters like umlaut-a, which is an "a"
326 with two dots on it. In some locales you have to press a
327 special key (the dead key) immediately followed by the
328 "a" to get a composed umlaut-a. The special key may have
329 a normal meaning with different modifiers. */
330
331 if (KEV.uChar.UnicodeChar || !(MapVirtualKey(vk, 2) & 0x80000000))
332 num_keys = KEV.wRepeatCount;
333 }
334 }
335 else
336 {
337 /* key up */
338
339 /* Only modifier keys or the results of ALT-numpad entry are
340 returned on keyup */
341
342 if ((vk == VK_MENU && KEV.uChar.UnicodeChar) ||
343 ((vk == VK_SHIFT || vk == VK_CONTROL || vk == VK_MENU) &&
344 vk == save_press))
345 {
346 save_press = 0;
347 num_keys = 1;
348 }
349 }
350
351 PDC_LOG(("_get_key_count() - returning: num_keys %d\n", num_keys));
352
353 return num_keys;
354}
355
356/* _process_key_event returns -1 if the key in save_ip should be
357 ignored. Otherwise it returns the keycode which should be returned
358 by PDC_get_key(). save_ip must be a key event.
359
360 CTRL-ALT support has been disabled, when is it emitted plainly? */
361
362static int _process_key_event(void)
363{
364 int key =
365#ifdef PDC_WIDE
366 KEV.uChar.UnicodeChar;
367#else
368 KEV.uChar.AsciiChar;
369#endif
370 WORD vk = KEV.wVirtualKeyCode;
371 DWORD state = KEV.dwControlKeyState;
372
373 int idx;
374 BOOL enhanced;
375
376 SP->key_code = TRUE;
377
378 /* Save the key modifiers. Do this first to allow to detect e.g. a
379 pressed CTRL key after a hit of NUMLOCK. */
380
381 if (state & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))
382 SP->key_modifiers |= PDC_KEY_MODIFIER_ALT;
383
384 if (state & SHIFT_PRESSED)
385 SP->key_modifiers |= PDC_KEY_MODIFIER_SHIFT;
386
387 if (state & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
388 SP->key_modifiers |= PDC_KEY_MODIFIER_CONTROL;
389
390 if (state & NUMLOCK_ON)
391 SP->key_modifiers |= PDC_KEY_MODIFIER_NUMLOCK;
392
393 /* Handle modifier keys hit by themselves */
394
395 switch (vk)
396 {
397 case VK_SHIFT: /* shift */
398 if (!SP->return_key_modifiers)
399 return -1;
400
401 return (left_key & 0x8000) ? KEY_SHIFT_L : KEY_SHIFT_R;
402
403 case VK_CONTROL: /* control */
404 if (!SP->return_key_modifiers)
405 return -1;
406
407 return (left_key & 0x8000) ? KEY_CONTROL_L : KEY_CONTROL_R;
408
409 case VK_MENU: /* alt */
410 if (!key)
411 {
412 if (!SP->return_key_modifiers)
413 return -1;
414
415 return (left_key & 0x8000) ? KEY_ALT_L : KEY_ALT_R;
416 }
417 }
418
419 /* The system may emit Ascii or Unicode characters depending on
420 whether ReadConsoleInputA or ReadConsoleInputW is used.
421
422 Normally, if key != 0 then the system did the translation
423 successfully. But this is not true for LEFT_ALT (different to
424 RIGHT_ALT). In case of LEFT_ALT we can get key != 0. So
425 check for this first. */
426
427 if (key && ( !(state & LEFT_ALT_PRESSED) ||
428 (state & RIGHT_ALT_PRESSED) ))
429 {
430 /* This code should catch all keys returning a printable
431 character. Characters above 0x7F should be returned as
432 positive codes. */
433
434 if (kptab[vk].extended == 0)
435 {
436 SP->key_code = FALSE;
437 return key;
438 }
439 }
440
441 /* This case happens if a functional key has been entered. */
442
443 if ((state & ENHANCED_KEY) && (kptab[vk].extended != 999))
444 {
445 enhanced = TRUE;
446 idx = kptab[vk].extended;
447 }
448 else
449 {
450 enhanced = FALSE;
451 idx = vk;
452 }
453
454 if (state & SHIFT_PRESSED)
455 key = enhanced ? ext_kptab[idx].shift : kptab[idx].shift;
456
457 else if (state & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
458 key = enhanced ? ext_kptab[idx].control : kptab[idx].control;
459
460 else if (state & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))
461 key = enhanced ? ext_kptab[idx].alt : kptab[idx].alt;
462
463 else
464 key = enhanced ? ext_kptab[idx].normal : kptab[idx].normal;
465
466 if (key < KEY_CODE_YES)
467 SP->key_code = FALSE;
468
469 return key;
470}
471
472static int _process_mouse_event(void)
473{
474 static const DWORD button_mask[] = {1, 4, 2};
475 short action, shift_flags = 0;
476 int i;
477
478 save_press = 0;
479 SP->key_code = TRUE;
480
481 memset(&SP->mouse_status, 0, sizeof(MOUSE_STATUS));
482
483 SP->mouse_status.x = MEV.dwMousePosition.X;
484 SP->mouse_status.y = MEV.dwMousePosition.Y;
485
486 /* Handle scroll wheel */
487
488 if (MEV.dwEventFlags == 4)
489 {
490 SP->mouse_status.changes = (MEV.dwButtonState & 0xFF000000) ?
491 PDC_MOUSE_WHEEL_DOWN : PDC_MOUSE_WHEEL_UP;
492
493 memset(&old_mouse_status, 0, sizeof(old_mouse_status));
494
495 return KEY_MOUSE;
496 }
497
498 if (MEV.dwEventFlags == 8)
499 {
500 SP->mouse_status.changes = (MEV.dwButtonState & 0xFF000000) ?
501 PDC_MOUSE_WHEEL_RIGHT : PDC_MOUSE_WHEEL_LEFT;
502
503 memset(&old_mouse_status, 0, sizeof(old_mouse_status));
504
505 return KEY_MOUSE;
506 }
507
508 action = (MEV.dwEventFlags == 2) ? BUTTON_DOUBLE_CLICKED :
509 ((MEV.dwEventFlags == 1) ? BUTTON_MOVED : BUTTON_PRESSED);
510
511 for (i = 0; i < 3; i++)
512 SP->mouse_status.button[i] =
513 (MEV.dwButtonState & button_mask[i]) ? action : 0;
514
515 if (action == BUTTON_PRESSED && MEV.dwButtonState & 7 && SP->mouse_wait)
516 {
517 /* Check for a click -- a PRESS followed immediately by a release */
518
519 if (!event_count)
520 {
521 napms(SP->mouse_wait);
522
523 GetNumberOfConsoleInputEvents(pdc_con_in, &event_count);
524 }
525
526 if (event_count)
527 {
528 INPUT_RECORD ip;
529 DWORD count;
530 bool have_click = FALSE;
531
532 PeekConsoleInput(pdc_con_in, &ip, 1, &count);
533
534 for (i = 0; i < 3; i++)
535 {
536 if (SP->mouse_status.button[i] == BUTTON_PRESSED &&
537 !(ip.Event.MouseEvent.dwButtonState & button_mask[i]))
538 {
539 SP->mouse_status.button[i] = BUTTON_CLICKED;
540 have_click = TRUE;
541 }
542 }
543
544 /* If a click was found, throw out the event */
545
546 if (have_click)
547 ReadConsoleInput(pdc_con_in, &ip, 1, &count);
548 }
549 }
550
551 SP->mouse_status.changes = 0;
552
553 for (i = 0; i < 3; i++)
554 {
555 if (old_mouse_status.button[i] != SP->mouse_status.button[i])
556 SP->mouse_status.changes |= (1 << i);
557
558 if (SP->mouse_status.button[i] == BUTTON_MOVED)
559 {
560 /* Discard non-moved "moves" */
561
562 if (SP->mouse_status.x == old_mouse_status.x &&
563 SP->mouse_status.y == old_mouse_status.y)
564 return -1;
565
566 /* Motion events always flag the button as changed */
567
568 SP->mouse_status.changes |= (1 << i);
569 SP->mouse_status.changes |= PDC_MOUSE_MOVED;
570 break;
571 }
572 }
573
574 old_mouse_status = SP->mouse_status;
575
576 /* Treat click events as release events for comparison purposes */
577
578 for (i = 0; i < 3; i++)
579 {
580 if (old_mouse_status.button[i] == BUTTON_CLICKED ||
581 old_mouse_status.button[i] == BUTTON_DOUBLE_CLICKED)
582 old_mouse_status.button[i] = BUTTON_RELEASED;
583 }
584
585 /* Check for SHIFT/CONTROL/ALT */
586
587 if (MEV.dwControlKeyState & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))
588 shift_flags |= BUTTON_ALT;
589
590 if (MEV.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
591 shift_flags |= BUTTON_CONTROL;
592
593 if (MEV.dwControlKeyState & SHIFT_PRESSED)
594 shift_flags |= BUTTON_SHIFT;
595
596 if (shift_flags)
597 {
598 for (i = 0; i < 3; i++)
599 {
600 if (SP->mouse_status.changes & (1 << i))
601 SP->mouse_status.button[i] |= shift_flags;
602 }
603 }
604
605 return KEY_MOUSE;
606}
607
608/* return the next available key or mouse event */
609
610int PDC_get_key(void)
611{
612 SP->key_modifiers = 0L;
613
614 if (!key_count)
615 {
616 DWORD count;
617
618 ReadConsoleInput(pdc_con_in, &save_ip, 1, &count);
619 event_count--;
620
621 if (save_ip.EventType == MOUSE_EVENT ||
622 save_ip.EventType == WINDOW_BUFFER_SIZE_EVENT)
623 key_count = 1;
624 else if (save_ip.EventType == KEY_EVENT)
625 key_count = _get_key_count();
626 }
627
628 if (key_count)
629 {
630 key_count--;
631
632 switch (save_ip.EventType)
633 {
634 case KEY_EVENT:
635 return _process_key_event();
636
637 case MOUSE_EVENT:
638 return _process_mouse_event();
639
640 case WINDOW_BUFFER_SIZE_EVENT:
641 if (REV.dwSize.Y != LINES || REV.dwSize.X != COLS)
642 {
643 if (!SP->resized)
644 {
645 SP->resized = TRUE;
646 SP->key_code = TRUE;
647 return KEY_RESIZE;
648 }
649 }
650 }
651 }
652
653 return -1;
654}
655
656/* discard any pending keyboard or mouse input -- this is the core
657 routine for flushinp() */
658
659void PDC_flushinp(void)
660{
661 PDC_LOG(("PDC_flushinp() - called\n"));
662
663 FlushConsoleInputBuffer(pdc_con_in);
664}
665
666bool PDC_has_mouse(void)
667{
668 return TRUE;
669}
670
671int PDC_mouse_set(void)
672{
673 DWORD mode;
674
675 /* If turning on mouse input: Set ENABLE_MOUSE_INPUT, and clear
676 all other flags, except processed input mode;
677 If turning off the mouse: Set QuickEdit Mode to the status it
678 had on startup, and clear all other flags, except etc. */
679
680 GetConsoleMode(pdc_con_in, &mode);
681 mode = (mode & 1) | 0x0088;
682 SetConsoleMode(pdc_con_in, mode | (SP->_trap_mbe ?
683 ENABLE_MOUSE_INPUT : pdc_quick_edit));
684
685 memset(&old_mouse_status, 0, sizeof(old_mouse_status));
686
687 return OK;
688}
689
690int PDC_modifiers_set(void)
691{
692 return OK;
693}
diff --git a/scripts/kconfig/libcurses/pdcscrn.c b/scripts/kconfig/libcurses/pdcscrn.c
new file mode 100644
index 000000000..e2f4ddd90
--- /dev/null
+++ b/scripts/kconfig/libcurses/pdcscrn.c
@@ -0,0 +1,686 @@
1/* PDCurses */
2
3#include "pdcwin.h"
4
5#include <stdlib.h>
6
7/* Color component table */
8
9PDCCOLOR pdc_color[PDC_MAXCOL];
10
11HANDLE std_con_out = INVALID_HANDLE_VALUE;
12HANDLE pdc_con_out = INVALID_HANDLE_VALUE;
13HANDLE pdc_con_in = INVALID_HANDLE_VALUE;
14
15DWORD pdc_quick_edit;
16
17static short realtocurs[16] =
18{
19 COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, COLOR_RED,
20 COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE, COLOR_BLACK + 8,
21 COLOR_BLUE + 8, COLOR_GREEN + 8, COLOR_CYAN + 8, COLOR_RED + 8,
22 COLOR_MAGENTA + 8, COLOR_YELLOW + 8, COLOR_WHITE + 8
23};
24
25static short ansitocurs[16] =
26{
27 COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE,
28 COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE, COLOR_BLACK + 8,
29 COLOR_RED + 8, COLOR_GREEN + 8, COLOR_YELLOW + 8, COLOR_BLUE + 8,
30 COLOR_MAGENTA + 8, COLOR_CYAN + 8, COLOR_WHITE + 8
31};
32
33short pdc_curstoreal[16], pdc_curstoansi[16];
34short pdc_oldf, pdc_oldb, pdc_oldu;
35bool pdc_conemu, pdc_wt, pdc_ansi;
36
37enum { PDC_RESTORE_NONE, PDC_RESTORE_BUFFER };
38
39/* Struct for storing console registry keys, and for use with the
40 undocumented WM_SETCONSOLEINFO message. Originally by James Brown,
41 www.catch22.net. */
42
43static struct
44{
45 ULONG Length;
46 COORD ScreenBufferSize;
47 COORD WindowSize;
48 ULONG WindowPosX;
49 ULONG WindowPosY;
50
51 COORD FontSize;
52 ULONG FontFamily;
53 ULONG FontWeight;
54 WCHAR FaceName[32];
55
56 ULONG CursorSize;
57 ULONG FullScreen;
58 ULONG QuickEdit;
59 ULONG AutoPosition;
60 ULONG InsertMode;
61
62 USHORT ScreenColors;
63 USHORT PopupColors;
64 ULONG HistoryNoDup;
65 ULONG HistoryBufferSize;
66 ULONG NumberOfHistoryBuffers;
67
68 COLORREF ColorTable[16];
69
70 ULONG CodePage;
71 HWND Hwnd;
72
73 WCHAR ConsoleTitle[0x100];
74} console_info;
75
76#ifdef HAVE_NO_INFOEX
77/* Console screen buffer information (extended version) */
78typedef struct _CONSOLE_SCREEN_BUFFER_INFOEX {
79 ULONG cbSize;
80 COORD dwSize;
81 COORD dwCursorPosition;
82 WORD wAttributes;
83 SMALL_RECT srWindow;
84 COORD dwMaximumWindowSize;
85 WORD wPopupAttributes;
86 BOOL bFullscreenSupported;
87 COLORREF ColorTable[16];
88} CONSOLE_SCREEN_BUFFER_INFOEX;
89typedef CONSOLE_SCREEN_BUFFER_INFOEX *PCONSOLE_SCREEN_BUFFER_INFOEX;
90#endif
91
92typedef BOOL (WINAPI *SetConsoleScreenBufferInfoExFn)(HANDLE hConsoleOutput,
93 PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx);
94typedef BOOL (WINAPI *GetConsoleScreenBufferInfoExFn)(HANDLE hConsoleOutput,
95 PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx);
96
97static SetConsoleScreenBufferInfoExFn pSetConsoleScreenBufferInfoEx = NULL;
98static GetConsoleScreenBufferInfoExFn pGetConsoleScreenBufferInfoEx = NULL;
99
100static CONSOLE_SCREEN_BUFFER_INFO orig_scr;
101static CONSOLE_SCREEN_BUFFER_INFOEX console_infoex;
102
103static LPTOP_LEVEL_EXCEPTION_FILTER xcpt_filter;
104
105static DWORD old_console_mode = 0;
106
107static bool is_nt;
108
109static void _reset_old_colors(void)
110{
111 pdc_oldf = -1;
112 pdc_oldb = -1;
113 pdc_oldu = 0;
114}
115
116static HWND _find_console_handle(void)
117{
118 TCHAR orgtitle[1024], temptitle[1024];
119 HWND wnd;
120
121 GetConsoleTitle(orgtitle, 1024);
122
123 wsprintf(temptitle, TEXT("%d/%d"), GetTickCount(), GetCurrentProcessId());
124 SetConsoleTitle(temptitle);
125
126 Sleep(40);
127
128 wnd = FindWindow(NULL, temptitle);
129
130 SetConsoleTitle(orgtitle);
131
132 return wnd;
133}
134
135/* Undocumented console message */
136
137#define WM_SETCONSOLEINFO (WM_USER + 201)
138
139/* Wrapper around WM_SETCONSOLEINFO. We need to create the necessary
140 section (file-mapping) object in the context of the process which
141 owns the console, before posting the message. Originally by JB. */
142
143static void _set_console_info(void)
144{
145 CONSOLE_SCREEN_BUFFER_INFO csbi;
146 CONSOLE_CURSOR_INFO cci;
147 DWORD dwConsoleOwnerPid;
148 HANDLE hProcess;
149 HANDLE hSection, hDupSection;
150 PVOID ptrView;
151
152 /* Each-time initialization for console_info */
153
154 GetConsoleCursorInfo(pdc_con_out, &cci);
155 console_info.CursorSize = cci.dwSize;
156
157 GetConsoleScreenBufferInfo(pdc_con_out, &csbi);
158 console_info.ScreenBufferSize = csbi.dwSize;
159
160 console_info.WindowSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
161 console_info.WindowSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
162
163 console_info.WindowPosX = csbi.srWindow.Left;
164 console_info.WindowPosY = csbi.srWindow.Top;
165
166 /* Open the process which "owns" the console */
167
168 GetWindowThreadProcessId(console_info.Hwnd, &dwConsoleOwnerPid);
169
170 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwConsoleOwnerPid);
171
172 /* Create a SECTION object backed by page-file, then map a view of
173 this section into the owner process so we can write the contents
174 of the CONSOLE_INFO buffer into it */
175
176 hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE,
177 0, sizeof(console_info), 0);
178
179 /* Copy our console structure into the section-object */
180
181 ptrView = MapViewOfFile(hSection, FILE_MAP_WRITE|FILE_MAP_READ,
182 0, 0, sizeof(console_info));
183
184 memcpy(ptrView, &console_info, sizeof(console_info));
185
186 UnmapViewOfFile(ptrView);
187
188 /* Map the memory into owner process */
189
190 DuplicateHandle(GetCurrentProcess(), hSection, hProcess, &hDupSection,
191 0, FALSE, DUPLICATE_SAME_ACCESS);
192
193 /* Send console window the "update" message */
194
195 SendMessage(console_info.Hwnd, WM_SETCONSOLEINFO, (WPARAM)hDupSection, 0);
196
197 CloseHandle(hSection);
198 CloseHandle(hProcess);
199}
200
201static int _set_console_infoex(void)
202{
203 if (!pSetConsoleScreenBufferInfoEx(pdc_con_out, &console_infoex))
204 return ERR;
205
206 return OK;
207}
208
209static int _set_colors(void)
210{
211 SetConsoleTextAttribute(pdc_con_out, 7);
212 _reset_old_colors();
213
214 if (pSetConsoleScreenBufferInfoEx)
215 return _set_console_infoex();
216 else
217 {
218 _set_console_info();
219 return OK;
220 }
221}
222
223/* One-time initialization for console_info -- color table and font info
224 from the registry; other values from functions. */
225
226static void _init_console_info(void)
227{
228 DWORD scrnmode, len;
229 HKEY reghnd;
230 int i;
231
232 console_info.Hwnd = _find_console_handle();
233 console_info.Length = sizeof(console_info);
234
235 GetConsoleMode(pdc_con_in, &scrnmode);
236 console_info.QuickEdit = !!(scrnmode & 0x0040);
237 console_info.InsertMode = !!(scrnmode & 0x0020);
238
239 console_info.FullScreen = FALSE;
240 console_info.AutoPosition = 0x10000;
241 console_info.ScreenColors = SP->orig_back << 4 | SP->orig_fore;
242 console_info.PopupColors = 0xf5;
243
244 console_info.HistoryNoDup = FALSE;
245 console_info.HistoryBufferSize = 50;
246 console_info.NumberOfHistoryBuffers = 4;
247
248 console_info.CodePage = GetConsoleOutputCP();
249
250 RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Console"), 0,
251 KEY_QUERY_VALUE, &reghnd);
252
253 len = sizeof(DWORD);
254
255 /* Default color table */
256
257 for (i = 0; i < 16; i++)
258 {
259 char tname[13];
260
261 sprintf(tname, "ColorTable%02d", i);
262 RegQueryValueExA(reghnd, tname, NULL, NULL,
263 (LPBYTE)(&(console_info.ColorTable[i])), &len);
264 }
265
266 /* Font info */
267
268 RegQueryValueEx(reghnd, TEXT("FontSize"), NULL, NULL,
269 (LPBYTE)(&console_info.FontSize), &len);
270 RegQueryValueEx(reghnd, TEXT("FontFamily"), NULL, NULL,
271 (LPBYTE)(&console_info.FontFamily), &len);
272 RegQueryValueEx(reghnd, TEXT("FontWeight"), NULL, NULL,
273 (LPBYTE)(&console_info.FontWeight), &len);
274
275 len = sizeof(WCHAR) * 32;
276 RegQueryValueExW(reghnd, L"FaceName", NULL, NULL,
277 (LPBYTE)(console_info.FaceName), &len);
278
279 RegCloseKey(reghnd);
280}
281
282static int _init_console_infoex(void)
283{
284 console_infoex.cbSize = sizeof(console_infoex);
285
286 if (!pGetConsoleScreenBufferInfoEx(pdc_con_out, &console_infoex))
287 return ERR;
288
289 console_infoex.srWindow.Right++;
290 console_infoex.srWindow.Bottom++;
291
292 return OK;
293}
294
295static COLORREF *_get_colors(void)
296{
297 if (pGetConsoleScreenBufferInfoEx)
298 {
299 int status = OK;
300 if (!console_infoex.cbSize)
301 status = _init_console_infoex();
302 return (status == ERR) ? NULL :
303 (COLORREF *)(&(console_infoex.ColorTable));
304 }
305 else
306 {
307 if (!console_info.Hwnd)
308 _init_console_info();
309 return (COLORREF *)(&(console_info.ColorTable));
310 }
311}
312
313/* restore the original console buffer in the event of a crash */
314
315static LONG WINAPI _restore_console(LPEXCEPTION_POINTERS ep)
316{
317 PDC_scr_close();
318
319 return EXCEPTION_CONTINUE_SEARCH;
320}
321
322/* restore the original console buffer on Ctrl+Break (or Ctrl+C,
323 if it gets re-enabled) */
324
325static BOOL WINAPI _ctrl_break(DWORD dwCtrlType)
326{
327 if (dwCtrlType == CTRL_BREAK_EVENT || dwCtrlType == CTRL_C_EVENT)
328 PDC_scr_close();
329
330 return FALSE;
331}
332
333/* close the physical screen -- may restore the screen to its state
334 before PDC_scr_open(); miscellaneous cleanup */
335
336void PDC_scr_close(void)
337{
338 PDC_LOG(("PDC_scr_close() - called\n"));
339
340 if (SP->visibility != 1)
341 curs_set(1);
342
343 PDC_reset_shell_mode();
344
345 /* Position cursor to the bottom left of the screen. */
346
347 if (SP->_restore == PDC_RESTORE_NONE)
348 {
349 SMALL_RECT win;
350
351 win.Left = orig_scr.srWindow.Left;
352 win.Right = orig_scr.srWindow.Right;
353 win.Top = 0;
354 win.Bottom = orig_scr.srWindow.Bottom - orig_scr.srWindow.Top;
355 SetConsoleWindowInfo(pdc_con_out, TRUE, &win);
356 PDC_gotoyx(win.Bottom, 0);
357 }
358}
359
360void PDC_scr_free(void)
361{
362 if (pdc_con_out != std_con_out)
363 {
364 CloseHandle(pdc_con_out);
365 pdc_con_out = std_con_out;
366 }
367
368 SetUnhandledExceptionFilter(xcpt_filter);
369 SetConsoleCtrlHandler(_ctrl_break, FALSE);
370}
371
372/* open the physical screen -- miscellaneous initialization, may save
373 the existing screen for later restoration */
374
375int PDC_scr_open(void)
376{
377 const char *str;
378 CONSOLE_SCREEN_BUFFER_INFO csbi;
379 HMODULE h_kernel;
380 BOOL result;
381 int i;
382
383 PDC_LOG(("PDC_scr_open() - called\n"));
384
385 for (i = 0; i < 16; i++)
386 {
387 pdc_curstoreal[realtocurs[i]] = i;
388 pdc_curstoansi[ansitocurs[i]] = i;
389 }
390 _reset_old_colors();
391
392 std_con_out =
393 pdc_con_out = GetStdHandle(STD_OUTPUT_HANDLE);
394 pdc_con_in = GetStdHandle(STD_INPUT_HANDLE);
395
396 if (GetFileType(pdc_con_in) != FILE_TYPE_CHAR)
397 {
398 fprintf(stderr, "\nRedirection is not supported.\n");
399 exit(1);
400 }
401
402 is_nt = !(GetVersion() & 0x80000000);
403
404 pdc_wt = !!getenv("WT_SESSION");
405 str = pdc_wt ? NULL : getenv("ConEmuANSI");
406 pdc_conemu = !!str;
407 pdc_ansi = pdc_wt ? TRUE : pdc_conemu ? !strcmp(str, "ON") : FALSE;
408
409 GetConsoleScreenBufferInfo(pdc_con_out, &csbi);
410 GetConsoleScreenBufferInfo(pdc_con_out, &orig_scr);
411 GetConsoleMode(pdc_con_in, &old_console_mode);
412
413 /* preserve QuickEdit Mode setting for use in PDC_mouse_set() when
414 the mouse is not enabled -- other console input settings are
415 cleared */
416
417 pdc_quick_edit = old_console_mode & 0x0040;
418
419 SP->mouse_wait = PDC_CLICK_PERIOD;
420 SP->audible = TRUE;
421
422 SP->termattrs = A_COLOR | A_REVERSE;
423 if (pdc_ansi)
424 SP->termattrs |= A_UNDERLINE | A_ITALIC;
425
426 SP->orig_fore = csbi.wAttributes & 0x0f;
427 SP->orig_back = (csbi.wAttributes & 0xf0) >> 4;
428
429 SP->orig_attr = TRUE;
430
431 SP->_restore = PDC_RESTORE_NONE;
432
433 if ((str = getenv("PDC_RESTORE_SCREEN")) == NULL || *str != '0')
434 {
435 /* Create a new console buffer */
436
437 pdc_con_out =
438 CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
439 FILE_SHARE_READ | FILE_SHARE_WRITE,
440 NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
441
442 if (pdc_con_out == INVALID_HANDLE_VALUE)
443 {
444 PDC_LOG(("PDC_scr_open() - screen buffer failure\n"));
445
446 pdc_con_out = std_con_out;
447 }
448 else
449 SP->_restore = PDC_RESTORE_BUFFER;
450 }
451
452 xcpt_filter = SetUnhandledExceptionFilter(_restore_console);
453 SetConsoleCtrlHandler(_ctrl_break, TRUE);
454
455 SP->_preserve = (getenv("PDC_PRESERVE_SCREEN") != NULL);
456
457 /* ENABLE_LVB_GRID_WORLDWIDE */
458 result = SetConsoleMode(pdc_con_out, 0x0010);
459 if (result)
460 SP->termattrs |= A_UNDERLINE | A_LEFT | A_RIGHT;
461
462 PDC_reset_prog_mode();
463
464 SP->mono = FALSE;
465
466 h_kernel = GetModuleHandleA("kernel32.dll");
467 pGetConsoleScreenBufferInfoEx =
468 (GetConsoleScreenBufferInfoExFn)GetProcAddress(h_kernel,
469 "GetConsoleScreenBufferInfoEx");
470 pSetConsoleScreenBufferInfoEx =
471 (SetConsoleScreenBufferInfoExFn)GetProcAddress(h_kernel,
472 "SetConsoleScreenBufferInfoEx");
473
474 return OK;
475}
476
477 /* Calls SetConsoleWindowInfo with the given parameters, but fits them
478 if a scoll bar shrinks the maximum possible value. The rectangle
479 must at least fit in a half-sized window. */
480
481static BOOL _fit_console_window(HANDLE con_out, CONST SMALL_RECT *rect)
482{
483 SMALL_RECT run;
484 SHORT mx, my;
485
486 if (SetConsoleWindowInfo(con_out, TRUE, rect))
487 return TRUE;
488
489 run = *rect;
490 run.Right /= 2;
491 run.Bottom /= 2;
492
493 mx = run.Right;
494 my = run.Bottom;
495
496 if (!SetConsoleWindowInfo(con_out, TRUE, &run))
497 return FALSE;
498
499 for (run.Right = rect->Right; run.Right >= mx; run.Right--)
500 if (SetConsoleWindowInfo(con_out, TRUE, &run))
501 break;
502
503 if (run.Right < mx)
504 return FALSE;
505
506 for (run.Bottom = rect->Bottom; run.Bottom >= my; run.Bottom--)
507 if (SetConsoleWindowInfo(con_out, TRUE, &run))
508 return TRUE;
509
510 return FALSE;
511}
512
513/* the core of resize_term() */
514
515int PDC_resize_screen(int nlines, int ncols)
516{
517 SMALL_RECT rect;
518 COORD size, max;
519
520 bool prog_resize = nlines || ncols;
521
522 if (!prog_resize)
523 {
524 nlines = PDC_get_rows();
525 ncols = PDC_get_columns();
526 }
527
528 if (nlines < 2 || ncols < 2)
529 return ERR;
530
531 max = GetLargestConsoleWindowSize(pdc_con_out);
532
533 rect.Left = rect.Top = 0;
534 rect.Right = ncols - 1;
535
536 if (rect.Right > max.X)
537 rect.Right = max.X;
538
539 rect.Bottom = nlines - 1;
540
541 if (rect.Bottom > max.Y)
542 rect.Bottom = max.Y;
543
544 size.X = rect.Right + 1;
545 size.Y = rect.Bottom + 1;
546
547 _fit_console_window(pdc_con_out, &rect);
548 SetConsoleScreenBufferSize(pdc_con_out, size);
549
550 if (prog_resize)
551 {
552 _fit_console_window(pdc_con_out, &rect);
553 SetConsoleScreenBufferSize(pdc_con_out, size);
554 }
555 SetConsoleActiveScreenBuffer(pdc_con_out);
556
557 PDC_flushinp();
558
559 return OK;
560}
561
562void PDC_reset_prog_mode(void)
563{
564 PDC_LOG(("PDC_reset_prog_mode() - called.\n"));
565
566 if (pdc_con_out != std_con_out)
567 SetConsoleActiveScreenBuffer(pdc_con_out);
568 else if (is_nt)
569 {
570 COORD bufsize;
571 SMALL_RECT rect;
572
573 bufsize.X = orig_scr.srWindow.Right - orig_scr.srWindow.Left + 1;
574 bufsize.Y = orig_scr.srWindow.Bottom - orig_scr.srWindow.Top + 1;
575
576 rect.Top = rect.Left = 0;
577 rect.Bottom = bufsize.Y - 1;
578 rect.Right = bufsize.X - 1;
579
580 SetConsoleScreenBufferSize(pdc_con_out, bufsize);
581 SetConsoleWindowInfo(pdc_con_out, TRUE, &rect);
582 SetConsoleScreenBufferSize(pdc_con_out, bufsize);
583 SetConsoleActiveScreenBuffer(pdc_con_out);
584 }
585
586 PDC_mouse_set();
587}
588
589void PDC_reset_shell_mode(void)
590{
591 PDC_LOG(("PDC_reset_shell_mode() - called.\n"));
592
593 if (pdc_con_out != std_con_out)
594 SetConsoleActiveScreenBuffer(std_con_out);
595 else if (is_nt)
596 {
597 SetConsoleScreenBufferSize(pdc_con_out, orig_scr.dwSize);
598 SetConsoleWindowInfo(pdc_con_out, TRUE, &orig_scr.srWindow);
599 SetConsoleScreenBufferSize(pdc_con_out, orig_scr.dwSize);
600 SetConsoleWindowInfo(pdc_con_out, TRUE, &orig_scr.srWindow);
601 SetConsoleActiveScreenBuffer(pdc_con_out);
602 }
603
604 SetConsoleMode(pdc_con_in, old_console_mode | 0x0080);
605}
606
607void PDC_restore_screen_mode(int i)
608{
609}
610
611void PDC_save_screen_mode(int i)
612{
613}
614
615bool PDC_can_change_color(void)
616{
617 return is_nt;
618}
619
620int PDC_color_content(short color, short *red, short *green, short *blue)
621{
622 if (color < 16 && !(pdc_conemu || pdc_wt))
623 {
624 COLORREF *color_table = _get_colors();
625
626 if (color_table)
627 {
628 DWORD col = color_table[pdc_curstoreal[color]];
629
630 *red = DIVROUND(GetRValue(col) * 1000, 255);
631 *green = DIVROUND(GetGValue(col) * 1000, 255);
632 *blue = DIVROUND(GetBValue(col) * 1000, 255);
633 }
634 else
635 return ERR;
636 }
637 else
638 {
639 if (!pdc_color[color].mapped)
640 {
641 *red = *green = *blue = -1;
642 return ERR;
643 }
644
645 *red = pdc_color[color].r;
646 *green = pdc_color[color].g;
647 *blue = pdc_color[color].b;
648 }
649
650 return OK;
651}
652
653int PDC_init_color(short color, short red, short green, short blue)
654{
655 if (red == -1 && green == -1 && blue == -1)
656 {
657 pdc_color[color].mapped = FALSE;
658 return OK;
659 }
660
661 if (color < 16 && !(pdc_conemu || pdc_wt))
662 {
663 COLORREF *color_table = _get_colors();
664
665 if (color_table)
666 {
667 color_table[pdc_curstoreal[color]] =
668 RGB(DIVROUND(red * 255, 1000),
669 DIVROUND(green * 255, 1000),
670 DIVROUND(blue * 255, 1000));
671
672 return _set_colors();
673 }
674
675 return ERR;
676 }
677 else
678 {
679 pdc_color[color].r = red;
680 pdc_color[color].g = green;
681 pdc_color[color].b = blue;
682 pdc_color[color].mapped = TRUE;
683 }
684
685 return OK;
686}
diff --git a/scripts/kconfig/libcurses/pdcsetsc.c b/scripts/kconfig/libcurses/pdcsetsc.c
new file mode 100644
index 000000000..a2d1b6dc3
--- /dev/null
+++ b/scripts/kconfig/libcurses/pdcsetsc.c
@@ -0,0 +1,130 @@
1/* PDCurses */
2
3#include "pdcwin.h"
4
5/*man-start**************************************************************
6
7pdcsetsc
8--------
9
10### Synopsis
11
12 int PDC_set_blink(bool blinkon);
13 int PDC_set_bold(bool boldon);
14 void PDC_set_title(const char *title);
15
16### Description
17
18 PDC_set_blink() toggles whether the A_BLINK attribute sets an actual
19 blink mode (TRUE), or sets the background color to high intensity
20 (FALSE). The default is platform-dependent (FALSE in most cases). It
21 returns OK if it could set the state to match the given parameter,
22 ERR otherwise.
23
24 PDC_set_bold() toggles whether the A_BOLD attribute selects an actual
25 bold font (TRUE), or sets the foreground color to high intensity
26 (FALSE). It returns OK if it could set the state to match the given
27 parameter, ERR otherwise.
28
29 PDC_set_title() sets the title of the window in which the curses
30 program is running. This function may not do anything on some
31 platforms.
32
33### Portability
34 X/Open ncurses NetBSD
35 PDC_set_blink - - -
36 PDC_set_title - - -
37
38**man-end****************************************************************/
39
40int PDC_curs_set(int visibility)
41{
42 CONSOLE_CURSOR_INFO cci;
43 int ret_vis;
44
45 PDC_LOG(("PDC_curs_set() - called: visibility=%d\n", visibility));
46
47 ret_vis = SP->visibility;
48
49 if (GetConsoleCursorInfo(pdc_con_out, &cci) == FALSE)
50 return ERR;
51
52 switch(visibility)
53 {
54 case 0: /* invisible */
55 cci.bVisible = FALSE;
56 break;
57 case 2: /* highly visible */
58 cci.bVisible = TRUE;
59 cci.dwSize = 95;
60 break;
61 default: /* normal visibility */
62 cci.bVisible = TRUE;
63 cci.dwSize = SP->orig_cursor;
64 break;
65 }
66
67 if (SetConsoleCursorInfo(pdc_con_out, &cci) == FALSE)
68 return ERR;
69
70 SP->visibility = visibility;
71 return ret_vis;
72}
73
74void PDC_set_title(const char *title)
75{
76#ifdef PDC_WIDE
77 wchar_t wtitle[512];
78#endif
79 PDC_LOG(("PDC_set_title() - called:<%s>\n", title));
80
81#ifdef PDC_WIDE
82 PDC_mbstowcs(wtitle, title, 511);
83 SetConsoleTitleW(wtitle);
84#else
85 SetConsoleTitleA(title);
86#endif
87}
88
89int PDC_set_blink(bool blinkon)
90{
91 if (!SP)
92 return ERR;
93
94 if (SP->color_started)
95 {
96 COLORS = 16;
97 if (PDC_can_change_color()) /* is_nt */
98 {
99 if (pdc_conemu || SetConsoleMode(pdc_con_out, 0x0004)) /* VT */
100 COLORS = PDC_MAXCOL;
101
102 if (!pdc_conemu)
103 SetConsoleMode(pdc_con_out, 0x0010); /* LVB */
104 }
105 }
106
107 if (blinkon)
108 {
109 if (!(SP->termattrs & A_BLINK))
110 {
111 SP->termattrs |= A_BLINK;
112 pdc_last_blink = GetTickCount();
113 }
114 }
115 else
116 {
117 if (SP->termattrs & A_BLINK)
118 {
119 SP->termattrs &= ~A_BLINK;
120 PDC_blink_text();
121 }
122 }
123
124 return OK;
125}
126
127int PDC_set_bold(bool boldon)
128{
129 return boldon ? ERR : OK;
130}
diff --git a/scripts/kconfig/libcurses/pdcutil.c b/scripts/kconfig/libcurses/pdcutil.c
new file mode 100644
index 000000000..a40cf4518
--- /dev/null
+++ b/scripts/kconfig/libcurses/pdcutil.c
@@ -0,0 +1,26 @@
1/* PDCurses */
2
3#include "pdcwin.h"
4
5void PDC_beep(void)
6{
7 PDC_LOG(("PDC_beep() - called\n"));
8
9/* MessageBeep(MB_OK); */
10 MessageBeep(0XFFFFFFFF);
11}
12
13void PDC_napms(int ms)
14{
15 PDC_LOG(("PDC_napms() - called: ms=%d\n", ms));
16
17 if ((SP->termattrs & A_BLINK) && (GetTickCount() >= pdc_last_blink + 500))
18 PDC_blink_text();
19
20 Sleep(ms);
21}
22
23const char *PDC_sysname(void)
24{
25 return "Windows";
26}
diff --git a/scripts/kconfig/libcurses/pdcwin.h b/scripts/kconfig/libcurses/pdcwin.h
new file mode 100644
index 000000000..cee76931b
--- /dev/null
+++ b/scripts/kconfig/libcurses/pdcwin.h
@@ -0,0 +1,27 @@
1/* PDCurses */
2
3#if defined(PDC_WIDE) && !defined(UNICODE)
4# define UNICODE
5#endif
6
7#define WIN32_LEAN_AND_MEAN
8#include <windows.h>
9#undef MOUSE_MOVED
10#include "curspriv.h"
11
12#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
13# define _CRT_SECURE_NO_DEPRECATE 1 /* kill nonsense warnings */
14#endif
15
16typedef struct {short r, g, b; bool mapped;} PDCCOLOR;
17
18extern PDCCOLOR pdc_color[PDC_MAXCOL];
19
20extern HANDLE pdc_con_out, pdc_con_in;
21extern DWORD pdc_quick_edit;
22extern DWORD pdc_last_blink;
23extern short pdc_curstoreal[16], pdc_curstoansi[16];
24extern short pdc_oldf, pdc_oldb, pdc_oldu;
25extern bool pdc_conemu, pdc_wt, pdc_ansi;
26
27extern void PDC_blink_text(void);
diff --git a/scripts/kconfig/libcurses/printw.c b/scripts/kconfig/libcurses/printw.c
new file mode 100644
index 000000000..38e7fd112
--- /dev/null
+++ b/scripts/kconfig/libcurses/printw.c
@@ -0,0 +1,129 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7printw
8------
9
10### Synopsis
11
12 int printw(const char *fmt, ...);
13 int wprintw(WINDOW *win, const char *fmt, ...);
14 int mvprintw(int y, int x, const char *fmt, ...);
15 int mvwprintw(WINDOW *win, int y, int x, const char *fmt,...);
16 int vwprintw(WINDOW *win, const char *fmt, va_list varglist);
17 int vw_printw(WINDOW *win, const char *fmt, va_list varglist);
18
19### Description
20
21 The printw() functions add a formatted string to the window at the
22 current or specified cursor position. The format strings are the same
23 as used in the standard C library's printf(). (printw() can be used
24 as a drop-in replacement for printf().)
25
26 The duplication between vwprintw() and vw_printw() is for historic
27 reasons. In PDCurses, they're the same.
28
29### Return Value
30
31 All functions return the number of characters printed, or ERR on
32 error.
33
34### Portability
35 X/Open ncurses NetBSD
36 printw Y Y Y
37 wprintw Y Y Y
38 mvprintw Y Y Y
39 mvwprintw Y Y Y
40 vwprintw Y Y Y
41 vw_printw Y Y Y
42
43**man-end****************************************************************/
44
45#include <string.h>
46
47int vwprintw(WINDOW *win, const char *fmt, va_list varglist)
48{
49 char printbuf[513];
50 int len;
51
52 PDC_LOG(("vwprintw() - called\n"));
53
54#ifdef HAVE_VSNPRINTF
55 len = vsnprintf(printbuf, 512, fmt, varglist);
56#else
57 len = vsprintf(printbuf, fmt, varglist);
58#endif
59 return (waddstr(win, printbuf) == ERR) ? ERR : len;
60}
61
62int printw(const char *fmt, ...)
63{
64 va_list args;
65 int retval;
66
67 PDC_LOG(("printw() - called\n"));
68
69 va_start(args, fmt);
70 retval = vwprintw(stdscr, fmt, args);
71 va_end(args);
72
73 return retval;
74}
75
76int wprintw(WINDOW *win, const char *fmt, ...)
77{
78 va_list args;
79 int retval;
80
81 PDC_LOG(("wprintw() - called\n"));
82
83 va_start(args, fmt);
84 retval = vwprintw(win, fmt, args);
85 va_end(args);
86
87 return retval;
88}
89
90int mvprintw(int y, int x, const char *fmt, ...)
91{
92 va_list args;
93 int retval;
94
95 PDC_LOG(("mvprintw() - called\n"));
96
97 if (move(y, x) == ERR)
98 return ERR;
99
100 va_start(args, fmt);
101 retval = vwprintw(stdscr, fmt, args);
102 va_end(args);
103
104 return retval;
105}
106
107int mvwprintw(WINDOW *win, int y, int x, const char *fmt, ...)
108{
109 va_list args;
110 int retval;
111
112 PDC_LOG(("mvwprintw() - called\n"));
113
114 if (wmove(win, y, x) == ERR)
115 return ERR;
116
117 va_start(args, fmt);
118 retval = vwprintw(win, fmt, args);
119 va_end(args);
120
121 return retval;
122}
123
124int vw_printw(WINDOW *win, const char *fmt, va_list varglist)
125{
126 PDC_LOG(("vw_printw() - called\n"));
127
128 return vwprintw(win, fmt, varglist);
129}
diff --git a/scripts/kconfig/libcurses/refresh.c b/scripts/kconfig/libcurses/refresh.c
new file mode 100644
index 000000000..306f4efb3
--- /dev/null
+++ b/scripts/kconfig/libcurses/refresh.c
@@ -0,0 +1,287 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7refresh
8-------
9
10### Synopsis
11
12 int refresh(void);
13 int wrefresh(WINDOW *win);
14 int wnoutrefresh(WINDOW *win);
15 int doupdate(void);
16 int redrawwin(WINDOW *win);
17 int wredrawln(WINDOW *win, int beg_line, int num_lines);
18
19### Description
20
21 wrefresh() copies the named window to the physical terminal screen,
22 taking into account what is already there in order to optimize cursor
23 movement. refresh() does the same, using stdscr. These routines must
24 be called to get any output on the terminal, as other routines only
25 manipulate data structures. Unless leaveok() has been enabled, the
26 physical cursor of the terminal is left at the location of the
27 window's cursor.
28
29 wnoutrefresh() and doupdate() allow multiple updates with more
30 efficiency than wrefresh() alone. wrefresh() works by first calling
31 wnoutrefresh(), which copies the named window to the virtual screen.
32 It then calls doupdate(), which compares the virtual screen to the
33 physical screen and does the actual update. A series of calls to
34 wrefresh() will result in alternating calls to wnoutrefresh() and
35 doupdate(), causing several bursts of output to the screen. By first
36 calling wnoutrefresh() for each window, it is then possible to call
37 doupdate() only once.
38
39 In PDCurses, redrawwin() is equivalent to touchwin(), and wredrawln()
40 is the same as touchline(). In some other curses implementations,
41 there's a subtle distinction, but it has no meaning in PDCurses.
42
43### Return Value
44
45 All functions return OK on success and ERR on error.
46
47### Portability
48 X/Open ncurses NetBSD
49 refresh Y Y Y
50 wrefresh Y Y Y
51 wnoutrefresh Y Y Y
52 doupdate Y Y Y
53 redrawwin Y Y Y
54 wredrawln Y Y Y
55
56**man-end****************************************************************/
57
58#include <string.h>
59
60int wnoutrefresh(WINDOW *win)
61{
62 int begy, begx; /* window's place on screen */
63 int i, j;
64
65 PDC_LOG(("wnoutrefresh() - called: win=%p\n", win));
66
67 if (!win)
68 return ERR;
69 if (is_pad(win))
70 return pnoutrefresh(win,
71 win->_pad._pad_y,
72 win->_pad._pad_x,
73 win->_pad._pad_top,
74 win->_pad._pad_left,
75 win->_pad._pad_bottom,
76 win->_pad._pad_right);
77
78 begy = win->_begy;
79 begx = win->_begx;
80
81 for (i = 0, j = begy; i < win->_maxy; i++, j++)
82 {
83 if (win->_firstch[i] != _NO_CHANGE)
84 {
85 chtype *src = win->_y[i];
86 chtype *dest = curscr->_y[j] + begx;
87
88 int first = win->_firstch[i]; /* first changed */
89 int last = win->_lastch[i]; /* last changed */
90
91 /* ignore areas on the outside that are marked as changed,
92 but really aren't */
93
94 while (first <= last && src[first] == dest[first])
95 first++;
96
97 while (last >= first && src[last] == dest[last])
98 last--;
99
100 /* if any have really changed... */
101
102 if (first <= last)
103 {
104 memcpy(dest + first, src + first,
105 (last - first + 1) * sizeof(chtype));
106
107 first += begx;
108 last += begx;
109
110 if (first < curscr->_firstch[j] ||
111 curscr->_firstch[j] == _NO_CHANGE)
112 curscr->_firstch[j] = first;
113
114 if (last > curscr->_lastch[j])
115 curscr->_lastch[j] = last;
116 }
117
118 win->_firstch[i] = _NO_CHANGE; /* updated now */
119 }
120
121 win->_lastch[i] = _NO_CHANGE; /* updated now */
122 }
123
124 if (win->_clear)
125 win->_clear = FALSE;
126
127 if (!win->_leaveit)
128 {
129 curscr->_cury = win->_cury + begy;
130 curscr->_curx = win->_curx + begx;
131 }
132
133 return OK;
134}
135
136int doupdate(void)
137{
138 int y;
139 bool clearall;
140
141 PDC_LOG(("doupdate() - called\n"));
142
143 if (!SP || !curscr)
144 return ERR;
145
146 if (isendwin()) /* coming back after endwin() called */
147 {
148 reset_prog_mode();
149 clearall = TRUE;
150 SP->alive = TRUE; /* so isendwin() result is correct */
151 }
152 else
153 clearall = curscr->_clear;
154
155 for (y = 0; y < SP->lines; y++)
156 {
157 PDC_LOG(("doupdate() - Transforming line %d of %d: %s\n",
158 y, SP->lines, (curscr->_firstch[y] != _NO_CHANGE) ?
159 "Yes" : "No"));
160
161 if (clearall || curscr->_firstch[y] != _NO_CHANGE)
162 {
163 int first, last;
164
165 chtype *src = curscr->_y[y];
166 chtype *dest = SP->lastscr->_y[y];
167
168 if (clearall)
169 {
170 first = 0;
171 last = COLS - 1;
172 }
173 else
174 {
175 first = curscr->_firstch[y];
176 last = curscr->_lastch[y];
177 }
178
179 while (first <= last)
180 {
181 int len = 0;
182
183 /* build up a run of changed cells; if two runs are
184 separated by a single unchanged cell, ignore the
185 break */
186
187 if (clearall)
188 len = last - first + 1;
189 else
190 while (first + len <= last &&
191 (src[first + len] != dest[first + len] ||
192 (len && first + len < last &&
193 src[first + len + 1] != dest[first + len + 1])
194 )
195 )
196 len++;
197
198 /* update the screen, and SP->lastscr */
199
200 if (len)
201 {
202 PDC_transform_line(y, first, len, src + first);
203 memcpy(dest + first, src + first, len * sizeof(chtype));
204 first += len;
205 }
206
207 /* skip over runs of unchanged cells */
208
209 while (first <= last && src[first] == dest[first])
210 first++;
211 }
212
213 curscr->_firstch[y] = _NO_CHANGE;
214 curscr->_lastch[y] = _NO_CHANGE;
215 }
216 }
217
218 curscr->_clear = FALSE;
219
220 if (SP->visibility)
221 PDC_gotoyx(curscr->_cury, curscr->_curx);
222
223 SP->cursrow = curscr->_cury;
224 SP->curscol = curscr->_curx;
225
226 PDC_doupdate();
227
228 return OK;
229}
230
231int wrefresh(WINDOW *win)
232{
233 bool save_clear;
234
235 PDC_LOG(("wrefresh() - called\n"));
236
237 if ( !win || (win->_flags & (_PAD|_SUBPAD)) )
238 return ERR;
239
240 save_clear = win->_clear;
241
242 if (win == curscr)
243 curscr->_clear = TRUE;
244 else
245 wnoutrefresh(win);
246
247 if (save_clear && win->_maxy == SP->lines && win->_maxx == SP->cols)
248 curscr->_clear = TRUE;
249
250 return doupdate();
251}
252
253int refresh(void)
254{
255 PDC_LOG(("refresh() - called\n"));
256
257 return wrefresh(stdscr);
258}
259
260int wredrawln(WINDOW *win, int start, int num)
261{
262 int i;
263
264 PDC_LOG(("wredrawln() - called: win=%p start=%d num=%d\n",
265 win, start, num));
266
267 if (!win || start > win->_maxy || start + num > win->_maxy)
268 return ERR;
269
270 for (i = start; i < start + num; i++)
271 {
272 win->_firstch[i] = 0;
273 win->_lastch[i] = win->_maxx - 1;
274 }
275
276 return OK;
277}
278
279int redrawwin(WINDOW *win)
280{
281 PDC_LOG(("redrawwin() - called: win=%p\n", win));
282
283 if (!win)
284 return ERR;
285
286 return wredrawln(win, 0, win->_maxy);
287}
diff --git a/scripts/kconfig/libcurses/scroll.c b/scripts/kconfig/libcurses/scroll.c
new file mode 100644
index 000000000..d2f3d1704
--- /dev/null
+++ b/scripts/kconfig/libcurses/scroll.c
@@ -0,0 +1,101 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7scroll
8------
9
10### Synopsis
11
12 int scroll(WINDOW *win);
13 int scrl(int n);
14 int wscrl(WINDOW *win, int n);
15
16### Description
17
18 scroll() causes the window to scroll up one line. This involves
19 moving the lines in the window data strcture.
20
21 With a positive n, scrl() and wscrl() scroll the window up n lines
22 (line i + n becomes i); otherwise they scroll the window down n
23 lines.
24
25 For these functions to work, scrolling must be enabled via
26 scrollok(). Note also that scrolling is not allowed if the supplied
27 window is a pad.
28
29### Return Value
30
31 All functions return OK on success and ERR on error.
32
33### Portability
34 X/Open ncurses NetBSD
35 scroll Y Y Y
36 scrl Y Y Y
37 wscrl Y Y Y
38
39**man-end****************************************************************/
40
41int wscrl(WINDOW *win, int n)
42{
43 int i, l, dir, start, end;
44 chtype blank, *temp;
45
46 /* Check if window scrolls. Valid for window AND pad */
47
48 if (!win || !win->_scroll || !n)
49 return ERR;
50
51 blank = win->_bkgd;
52
53 if (n > 0)
54 {
55 start = win->_tmarg;
56 end = win->_bmarg;
57 dir = 1;
58 }
59 else
60 {
61 start = win->_bmarg;
62 end = win->_tmarg;
63 dir = -1;
64 }
65
66 for (l = 0; l < (n * dir); l++)
67 {
68 temp = win->_y[start];
69
70 /* re-arrange line pointers */
71
72 for (i = start; i != end; i += dir)
73 win->_y[i] = win->_y[i + dir];
74
75 win->_y[end] = temp;
76
77 /* make a blank line */
78
79 for (i = 0; i < win->_maxx; i++)
80 *temp++ = blank;
81 }
82
83 touchline(win, win->_tmarg, win->_bmarg - win->_tmarg + 1);
84
85 PDC_sync(win);
86 return OK;
87}
88
89int scrl(int n)
90{
91 PDC_LOG(("scrl() - called\n"));
92
93 return wscrl(stdscr, n);
94}
95
96int scroll(WINDOW *win)
97{
98 PDC_LOG(("scroll() - called\n"));
99
100 return wscrl(win, 1);
101}
diff --git a/scripts/kconfig/libcurses/slk.c b/scripts/kconfig/libcurses/slk.c
new file mode 100644
index 000000000..a9fca13d3
--- /dev/null
+++ b/scripts/kconfig/libcurses/slk.c
@@ -0,0 +1,671 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7slk
8---
9
10### Synopsis
11
12 int slk_init(int fmt);
13 int slk_set(int labnum, const char *label, int justify);
14 int slk_refresh(void);
15 int slk_noutrefresh(void);
16 char *slk_label(int labnum);
17 int slk_clear(void);
18 int slk_restore(void);
19 int slk_touch(void);
20 int slk_attron(const chtype attrs);
21 int slk_attr_on(const attr_t attrs, void *opts);
22 int slk_attrset(const chtype attrs);
23 int slk_attr_set(const attr_t attrs, short color_pair, void *opts);
24 int slk_attroff(const chtype attrs);
25 int slk_attr_off(const attr_t attrs, void *opts);
26 int slk_color(short color_pair);
27
28 int slk_wset(int labnum, const wchar_t *label, int justify);
29
30 int PDC_mouse_in_slk(int y, int x);
31 void PDC_slk_free(void);
32 void PDC_slk_initialize(void);
33
34 wchar_t *slk_wlabel(int labnum)
35
36### Description
37
38 These functions manipulate a window that contain Soft Label Keys
39 (SLK). To use the SLK functions, a call to slk_init() must be made
40 BEFORE initscr() or newterm(). slk_init() removes 1 or 2 lines from
41 the useable screen, depending on the format selected.
42
43 The line(s) removed from the screen are used as a separate window, in
44 which SLKs are displayed.
45
46 slk_init() requires a single parameter which describes the format of
47 the SLKs as follows:
48
49 0 3-2-3 format
50 1 4-4 format
51 2 4-4-4 format (ncurses extension)
52 3 4-4-4 format with index line (ncurses extension)
53 2 lines used
54 55 5-5 format (pdcurses format)
55
56 slk_refresh(), slk_noutrefresh() and slk_touch() are analogous to
57 refresh(), noutrefresh() and touch().
58
59### Return Value
60
61 All functions return OK on success and ERR on error.
62
63### Portability
64 X/Open ncurses NetBSD
65 slk_init Y Y Y
66 slk_set Y Y Y
67 slk_refresh Y Y Y
68 slk_noutrefresh Y Y Y
69 slk_label Y Y Y
70 slk_clear Y Y Y
71 slk_restore Y Y Y
72 slk_touch Y Y Y
73 slk_attron Y Y Y
74 slk_attrset Y Y Y
75 slk_attroff Y Y Y
76 slk_attr_on Y Y Y
77 slk_attr_set Y Y Y
78 slk_attr_off Y Y Y
79 slk_wset Y Y Y
80 PDC_mouse_in_slk - - -
81 PDC_slk_free - - -
82 PDC_slk_initialize - - -
83 slk_wlabel - - -
84
85**man-end****************************************************************/
86
87#include <stdlib.h>
88
89enum { LABEL_NORMAL = 8, LABEL_EXTENDED = 10, LABEL_NCURSES_EXTENDED = 12 };
90
91static int label_length = 0;
92static int labels = 0;
93static int label_fmt = 0;
94static int label_line = 0;
95static bool hidden = FALSE;
96
97static struct SLK {
98 chtype label[32];
99 int len;
100 int format;
101 int start_col;
102} *slk = (struct SLK *)NULL;
103
104/* slk_init() is the slk initialization routine.
105 This must be called before initscr().
106
107 label_fmt = 0, 1 or 55.
108 0 = 3-2-3 format
109 1 = 4 - 4 format
110 2 = 4-4-4 format (ncurses extension for PC 12 function keys)
111 3 = 4-4-4 format (ncurses extension for PC 12 function keys -
112 with index line)
113 55 = 5 - 5 format (extended for PC, 10 function keys) */
114
115int slk_init(int fmt)
116{
117 PDC_LOG(("slk_init() - called\n"));
118
119 if (SP)
120 return ERR;
121
122 switch (fmt)
123 {
124 case 0: /* 3 - 2 - 3 */
125 labels = LABEL_NORMAL;
126 break;
127
128 case 1: /* 4 - 4 */
129 labels = LABEL_NORMAL;
130 break;
131
132 case 2: /* 4 4 4 */
133 labels = LABEL_NCURSES_EXTENDED;
134 break;
135
136 case 3: /* 4 4 4 with index */
137 labels = LABEL_NCURSES_EXTENDED;
138 break;
139
140 case 55: /* 5 - 5 */
141 labels = LABEL_EXTENDED;
142 break;
143
144 default:
145 return ERR;
146 }
147
148 label_fmt = fmt;
149
150 slk = calloc(labels, sizeof(struct SLK));
151
152 if (!slk)
153 labels = 0;
154
155 return slk ? OK : ERR;
156}
157
158/* draw a single button */
159
160static void _drawone(int num)
161{
162 int i, col, slen;
163
164 if (hidden)
165 return;
166
167 slen = slk[num].len;
168
169 switch (slk[num].format)
170 {
171 case 0: /* LEFT */
172 col = 0;
173 break;
174
175 case 1: /* CENTER */
176 col = (label_length - slen) / 2;
177
178 if (col + slen > label_length)
179 --col;
180 break;
181
182 default: /* RIGHT */
183 col = label_length - slen;
184 }
185
186 wmove(SP->slk_winptr, label_line, slk[num].start_col);
187
188 for (i = 0; i < label_length; ++i)
189 waddch(SP->slk_winptr, (i >= col && i < (col + slen)) ?
190 slk[num].label[i - col] : ' ');
191}
192
193/* redraw each button */
194
195static void _redraw(void)
196{
197 int i;
198
199 for (i = 0; i < labels; ++i)
200 _drawone(i);
201}
202
203/* slk_set() Used to set a slk label to a string.
204
205 labnum = 1 - 8 (or 10) (number of the label)
206 label = string (8 or 7 bytes total), or NULL
207 justify = 0 : left, 1 : center, 2 : right */
208
209int slk_set(int labnum, const char *label, int justify)
210{
211#ifdef PDC_WIDE
212 wchar_t wlabel[32];
213
214 PDC_mbstowcs(wlabel, label, 31);
215 return slk_wset(labnum, wlabel, justify);
216#else
217 PDC_LOG(("slk_set() - called\n"));
218
219 if (labnum < 1 || labnum > labels || justify < 0 || justify > 2)
220 return ERR;
221
222 labnum--;
223
224 if (!label || !(*label))
225 {
226 /* Clear the label */
227
228 *slk[labnum].label = 0;
229 slk[labnum].format = 0;
230 slk[labnum].len = 0;
231 }
232 else
233 {
234 int i, j = 0;
235
236 /* Skip leading spaces */
237
238 while (label[j] == ' ')
239 j++;
240
241 /* Copy it */
242
243 for (i = 0; i < label_length; i++)
244 {
245 chtype ch = label[i + j];
246
247 slk[labnum].label[i] = ch;
248
249 if (!ch)
250 break;
251 }
252
253 /* Drop trailing spaces */
254
255 while ((i + j) && (label[i + j - 1] == ' '))
256 i--;
257
258 slk[labnum].label[i] = 0;
259 slk[labnum].format = justify;
260 slk[labnum].len = i;
261 }
262
263 _drawone(labnum);
264
265 return OK;
266#endif
267}
268
269int slk_refresh(void)
270{
271 PDC_LOG(("slk_refresh() - called\n"));
272
273 return (slk_noutrefresh() == ERR) ? ERR : doupdate();
274}
275
276int slk_noutrefresh(void)
277{
278 PDC_LOG(("slk_noutrefresh() - called\n"));
279
280 if (!SP)
281 return ERR;
282
283 return wnoutrefresh(SP->slk_winptr);
284}
285
286char *slk_label(int labnum)
287{
288 static char temp[33];
289#ifdef PDC_WIDE
290 wchar_t *wtemp = slk_wlabel(labnum);
291
292 PDC_wcstombs(temp, wtemp, 32);
293#else
294 chtype *p;
295 int i;
296
297 PDC_LOG(("slk_label() - called\n"));
298
299 if (labnum < 1 || labnum > labels)
300 return (char *)0;
301
302 for (i = 0, p = slk[labnum - 1].label; *p; i++)
303 temp[i] = *p++;
304
305 temp[i] = '\0';
306#endif
307 return temp;
308}
309
310int slk_clear(void)
311{
312 PDC_LOG(("slk_clear() - called\n"));
313
314 if (!SP)
315 return ERR;
316
317 hidden = TRUE;
318 werase(SP->slk_winptr);
319 return wrefresh(SP->slk_winptr);
320}
321
322int slk_restore(void)
323{
324 PDC_LOG(("slk_restore() - called\n"));
325
326 if (!SP)
327 return ERR;
328
329 hidden = FALSE;
330 _redraw();
331 return wrefresh(SP->slk_winptr);
332}
333
334int slk_touch(void)
335{
336 PDC_LOG(("slk_touch() - called\n"));
337
338 if (!SP)
339 return ERR;
340
341 return touchwin(SP->slk_winptr);
342}
343
344int slk_attron(const chtype attrs)
345{
346 int rc;
347
348 PDC_LOG(("slk_attron() - called\n"));
349
350 if (!SP)
351 return ERR;
352
353 rc = wattron(SP->slk_winptr, attrs);
354 _redraw();
355
356 return rc;
357}
358
359int slk_attr_on(const attr_t attrs, void *opts)
360{
361 PDC_LOG(("slk_attr_on() - called\n"));
362
363 return slk_attron(attrs);
364}
365
366int slk_attroff(const chtype attrs)
367{
368 int rc;
369
370 PDC_LOG(("slk_attroff() - called\n"));
371
372 if (!SP)
373 return ERR;
374
375 rc = wattroff(SP->slk_winptr, attrs);
376 _redraw();
377
378 return rc;
379}
380
381int slk_attr_off(const attr_t attrs, void *opts)
382{
383 PDC_LOG(("slk_attr_off() - called\n"));
384
385 return slk_attroff(attrs);
386}
387
388int slk_attrset(const chtype attrs)
389{
390 int rc;
391
392 PDC_LOG(("slk_attrset() - called\n"));
393
394 if (!SP)
395 return ERR;
396
397 rc = wattrset(SP->slk_winptr, attrs);
398 _redraw();
399
400 return rc;
401}
402
403int slk_color(short color_pair)
404{
405 int rc;
406
407 PDC_LOG(("slk_color() - called\n"));
408
409 if (!SP)
410 return ERR;
411
412 rc = wcolor_set(SP->slk_winptr, color_pair, NULL);
413 _redraw();
414
415 return rc;
416}
417
418int slk_attr_set(const attr_t attrs, short color_pair, void *opts)
419{
420 PDC_LOG(("slk_attr_set() - called\n"));
421
422 return slk_attrset(attrs | COLOR_PAIR(color_pair));
423}
424
425static void _slk_calc(void)
426{
427 int i, center, col = 0;
428 label_length = COLS / labels;
429
430 if (label_length > 31)
431 label_length = 31;
432
433 switch (label_fmt)
434 {
435 case 0: /* 3 - 2 - 3 F-Key layout */
436
437 --label_length;
438
439 slk[0].start_col = col;
440 slk[1].start_col = (col += label_length);
441 slk[2].start_col = (col += label_length);
442
443 center = COLS / 2;
444
445 slk[3].start_col = center - label_length + 1;
446 slk[4].start_col = center + 1;
447
448 col = COLS - (label_length * 3) + 1;
449
450 slk[5].start_col = col;
451 slk[6].start_col = (col += label_length);
452 slk[7].start_col = (col += label_length);
453 break;
454
455 case 1: /* 4 - 4 F-Key layout */
456
457 for (i = 0; i < 8; i++)
458 {
459 slk[i].start_col = col;
460 col += label_length;
461
462 if (i == 3)
463 col = COLS - (label_length * 4) + 1;
464 }
465
466 break;
467
468 case 2: /* 4 4 4 F-Key layout */
469 case 3: /* 4 4 4 F-Key layout with index */
470
471 for (i = 0; i < 4; i++)
472 {
473 slk[i].start_col = col;
474 col += label_length;
475 }
476
477 center = COLS / 2;
478
479 slk[4].start_col = center - (label_length * 2) + 1;
480 slk[5].start_col = center - label_length + 1;
481 slk[6].start_col = center + 1;
482 slk[7].start_col = center + label_length + 1;
483
484 col = COLS - (label_length * 4) + 1;
485
486 for (i = 8; i < 12; i++)
487 {
488 slk[i].start_col = col;
489 col += label_length;
490 }
491
492 break;
493
494 default: /* 5 - 5 F-Key layout */
495
496 for (i = 0; i < 10; i++)
497 {
498 slk[i].start_col = col;
499 col += label_length;
500
501 if (i == 4)
502 col = COLS - (label_length * 5) + 1;
503 }
504 }
505
506 --label_length;
507
508 /* make sure labels are all in window */
509
510 _redraw();
511}
512
513void PDC_slk_initialize(void)
514{
515 if (slk)
516 {
517 if (label_fmt == 3)
518 {
519 SP->slklines = 2;
520 label_line = 1;
521 }
522 else
523 SP->slklines = 1;
524
525 if (!SP->slk_winptr)
526 {
527 SP->slk_winptr = newwin(SP->slklines, COLS,
528 LINES - SP->slklines, 0);
529 if (!SP->slk_winptr)
530 return;
531
532 wattrset(SP->slk_winptr, A_REVERSE);
533 }
534
535 _slk_calc();
536
537 /* if we have an index line, display it now */
538
539 if (label_fmt == 3)
540 {
541 chtype save_attr;
542 int i;
543
544 save_attr = SP->slk_winptr->_attrs;
545 wattrset(SP->slk_winptr, A_NORMAL);
546 wmove(SP->slk_winptr, 0, 0);
547 whline(SP->slk_winptr, 0, COLS);
548
549 for (i = 0; i < labels; i++)
550 mvwprintw(SP->slk_winptr, 0, slk[i].start_col, "F%d", i + 1);
551
552 SP->slk_winptr->_attrs = save_attr;
553 }
554
555 touchwin(SP->slk_winptr);
556 }
557}
558
559void PDC_slk_free(void)
560{
561 if (slk)
562 {
563 if (SP->slk_winptr)
564 {
565 delwin(SP->slk_winptr);
566 SP->slk_winptr = (WINDOW *)NULL;
567 }
568
569 free(slk);
570 slk = (struct SLK *)NULL;
571
572 label_length = 0;
573 labels = 0;
574 label_fmt = 0;
575 label_line = 0;
576 hidden = FALSE;
577 }
578}
579
580int PDC_mouse_in_slk(int y, int x)
581{
582 int i;
583
584 PDC_LOG(("PDC_mouse_in_slk() - called: y->%d x->%d\n", y, x));
585
586 /* If the line on which the mouse was clicked is NOT the last line
587 of the screen, we are not interested in it. */
588
589 if (!slk || !SP->slk_winptr || (y != SP->slk_winptr->_begy + label_line))
590 return 0;
591
592 for (i = 0; i < labels; i++)
593 if (x >= slk[i].start_col && x < (slk[i].start_col + label_length))
594 return i + 1;
595
596 return 0;
597}
598
599#ifdef PDC_WIDE
600int slk_wset(int labnum, const wchar_t *label, int justify)
601{
602 PDC_LOG(("slk_wset() - called\n"));
603
604 if (labnum < 1 || labnum > labels || justify < 0 || justify > 2)
605 return ERR;
606
607 labnum--;
608
609 if (!label || !(*label))
610 {
611 /* Clear the label */
612
613 *slk[labnum].label = 0;
614 slk[labnum].format = 0;
615 slk[labnum].len = 0;
616 }
617 else
618 {
619 int i, j = 0;
620
621 /* Skip leading spaces */
622
623 while (label[j] == L' ')
624 j++;
625
626 /* Copy it */
627
628 for (i = 0; i < label_length; i++)
629 {
630 chtype ch = label[i + j];
631
632 slk[labnum].label[i] = ch;
633
634 if (!ch)
635 break;
636 }
637
638 /* Drop trailing spaces */
639
640 while ((i + j) && (label[i + j - 1] == L' '))
641 i--;
642
643 slk[labnum].label[i] = 0;
644 slk[labnum].format = justify;
645 slk[labnum].len = i;
646 }
647
648 _drawone(labnum);
649
650 return OK;
651}
652
653wchar_t *slk_wlabel(int labnum)
654{
655 static wchar_t temp[33];
656 chtype *p;
657 int i;
658
659 PDC_LOG(("slk_wlabel() - called\n"));
660
661 if (labnum < 1 || labnum > labels)
662 return (wchar_t *)0;
663
664 for (i = 0, p = slk[labnum - 1].label; *p; i++)
665 temp[i] = *p++;
666
667 temp[i] = '\0';
668
669 return temp;
670}
671#endif
diff --git a/scripts/kconfig/libcurses/touch.c b/scripts/kconfig/libcurses/touch.c
new file mode 100644
index 000000000..2fd03cce5
--- /dev/null
+++ b/scripts/kconfig/libcurses/touch.c
@@ -0,0 +1,208 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7touch
8-----
9
10### Synopsis
11
12 int touchwin(WINDOW *win);
13 int touchline(WINDOW *win, int start, int count);
14 int untouchwin(WINDOW *win);
15 int wtouchln(WINDOW *win, int y, int n, int changed);
16 bool is_linetouched(WINDOW *win, int line);
17 bool is_wintouched(WINDOW *win);
18
19 int touchoverlap(const WINDOW *win1, WINDOW *win2);
20
21### Description
22
23 touchwin() and touchline() throw away all information about which
24 parts of the window have been touched, pretending that the entire
25 window has been drawn on. This is sometimes necessary when using
26 overlapping windows, since a change to one window will affect the
27 other window, but the records of which lines have been changed in the
28 other window will not reflect the change.
29
30 untouchwin() marks all lines in the window as unchanged since the
31 last call to wrefresh().
32
33 wtouchln() makes n lines in the window, starting at line y, look as
34 if they have (changed == 1) or have not (changed == 0) been changed
35 since the last call to wrefresh().
36
37 is_linetouched() returns TRUE if the specified line in the specified
38 window has been changed since the last call to wrefresh().
39
40 is_wintouched() returns TRUE if the specified window has been changed
41 since the last call to wrefresh().
42
43 touchoverlap(win1, win2) marks the portion of win2 which overlaps
44 with win1 as modified.
45
46### Return Value
47
48 All functions return OK on success and ERR on error except
49 is_wintouched() and is_linetouched().
50
51### Portability
52 X/Open ncurses NetBSD
53 touchwin Y Y Y
54 touchline Y Y Y
55 untouchwin Y Y Y
56 wtouchln Y Y Y
57 is_linetouched Y Y Y
58 is_wintouched Y Y Y
59 touchoverlap - - Y
60
61**man-end****************************************************************/
62
63int touchwin(WINDOW *win)
64{
65 int i;
66
67 PDC_LOG(("touchwin() - called: Win=%x\n", win));
68
69 if (!win)
70 return ERR;
71
72 for (i = 0; i < win->_maxy; i++)
73 {
74 win->_firstch[i] = 0;
75 win->_lastch[i] = win->_maxx - 1;
76 }
77
78 return OK;
79}
80
81int touchline(WINDOW *win, int start, int count)
82{
83 int i;
84
85 PDC_LOG(("touchline() - called: win=%p start %d count %d\n",
86 win, start, count));
87
88 if (!win || start > win->_maxy || start + count > win->_maxy)
89 return ERR;
90
91 for (i = start; i < start + count; i++)
92 {
93 win->_firstch[i] = 0;
94 win->_lastch[i] = win->_maxx - 1;
95 }
96
97 return OK;
98}
99
100int untouchwin(WINDOW *win)
101{
102 int i;
103
104 PDC_LOG(("untouchwin() - called: win=%p", win));
105
106 if (!win)
107 return ERR;
108
109 for (i = 0; i < win->_maxy; i++)
110 {
111 win->_firstch[i] = _NO_CHANGE;
112 win->_lastch[i] = _NO_CHANGE;
113 }
114
115 return OK;
116}
117
118int wtouchln(WINDOW *win, int y, int n, int changed)
119{
120 int i;
121
122 PDC_LOG(("wtouchln() - called: win=%p y=%d n=%d changed=%d\n",
123 win, y, n, changed));
124
125 if (!win || y > win->_maxy || y + n > win->_maxy)
126 return ERR;
127
128 for (i = y; i < y + n; i++)
129 {
130 if (changed)
131 {
132 win->_firstch[i] = 0;
133 win->_lastch[i] = win->_maxx - 1;
134 }
135 else
136 {
137 win->_firstch[i] = _NO_CHANGE;
138 win->_lastch[i] = _NO_CHANGE;
139 }
140 }
141
142 return OK;
143}
144
145bool is_linetouched(WINDOW *win, int line)
146{
147 PDC_LOG(("is_linetouched() - called: win=%p line=%d\n", win, line));
148
149 if (!win || line > win->_maxy || line < 0)
150 return FALSE;
151
152 return (win->_firstch[line] != _NO_CHANGE) ? TRUE : FALSE;
153}
154
155bool is_wintouched(WINDOW *win)
156{
157 int i;
158
159 PDC_LOG(("is_wintouched() - called: win=%p\n", win));
160
161 if (win)
162 for (i = 0; i < win->_maxy; i++)
163 if (win->_firstch[i] != _NO_CHANGE)
164 return TRUE;
165
166 return FALSE;
167}
168
169int touchoverlap(const WINDOW *win1, WINDOW *win2)
170{
171 int y, endy, endx, starty, startx, begy1, begx1, begy2, begx2;
172
173 PDC_LOG(("touchoverlap() - called: win1=%p win2=%p\n", win1, win2));
174
175 if (!win1 || !win2)
176 return ERR;
177
178 begy1 = win1->_begy;
179 begx1 = win1->_begx;
180 begy2 = win2->_begy;
181 begx2 = win2->_begy;
182
183 starty = max(begy1, begy2);
184 startx = max(begx1, begx2);
185 endy = min(win1->_maxy + begy1, win2->_maxy + begy2);
186 endx = min(win1->_maxx + begx1, win2->_maxx + begx2);
187
188 if (starty >= endy || startx >= endx)
189 return OK;
190
191 starty -= begy2;
192 startx -= begx2;
193 endy -= begy2;
194 endx -= begx2;
195 endx -= 1;
196
197 for (y = starty; y < endy; y++)
198 {
199 int first = win2->_firstch[y];
200
201 if (first == _NO_CHANGE || win2->_lastch[y] < endx)
202 win2->_lastch[y] = endx;
203 if (first == _NO_CHANGE || first > startx)
204 win2->_firstch[y] = startx;
205 }
206
207 return OK;
208}
diff --git a/scripts/kconfig/libcurses/window.c b/scripts/kconfig/libcurses/window.c
new file mode 100644
index 000000000..4ae5b0861
--- /dev/null
+++ b/scripts/kconfig/libcurses/window.c
@@ -0,0 +1,637 @@
1/* PDCurses */
2
3#include "curspriv.h"
4
5/*man-start**************************************************************
6
7window
8------
9
10### Synopsis
11
12 WINDOW *newwin(int nlines, int ncols, int begy, int begx);
13 WINDOW *derwin(WINDOW* orig, int nlines, int ncols,
14 int begy, int begx);
15 WINDOW *subwin(WINDOW* orig, int nlines, int ncols,
16 int begy, int begx);
17 WINDOW *dupwin(WINDOW *win);
18 WINDOW *wgetparent(const WINDOW *win);
19 int delwin(WINDOW *win);
20 int mvwin(WINDOW *win, int y, int x);
21 int mvderwin(WINDOW *win, int pary, int parx);
22 int syncok(WINDOW *win, bool bf);
23 bool is_subwin(const WINDOW *win);
24 bool is_syncok(const WINDOW *win);
25 void wsyncup(WINDOW *win);
26 void wcursyncup(WINDOW *win);
27 void wsyncdown(WINDOW *win);
28
29 WINDOW *resize_window(WINDOW *win, int nlines, int ncols);
30 int wresize(WINDOW *win, int nlines, int ncols);
31 WINDOW *PDC_makelines(WINDOW *win);
32 WINDOW *PDC_makenew(int nlines, int ncols, int begy, int begx);
33 void PDC_sync(WINDOW *win);
34
35### Description
36
37 newwin() creates a new window with the given number of lines, nlines
38 and columns, ncols. The upper left corner of the window is at line
39 begy, column begx. If nlines is zero, it defaults to LINES - begy;
40 ncols to COLS - begx. Create a new full-screen window by calling
41 newwin(0, 0, 0, 0).
42
43 delwin() deletes the named window, freeing all associated memory. In
44 the case of overlapping windows, subwindows should be deleted before
45 the main window.
46
47 mvwin() moves the window so that the upper left-hand corner is at
48 position (y,x). If the move would cause the window to be off the
49 screen, it is an error and the window is not moved. Moving subwindows
50 is allowed.
51
52 subwin() creates a new subwindow within a window. The dimensions of
53 the subwindow are nlines lines and ncols columns. The subwindow is at
54 position (begy, begx) on the screen. This position is relative to the
55 screen, and not to the window orig. Changes made to either window
56 will affect both. When using this routine, you will often need to
57 call touchwin() before calling wrefresh().
58
59 derwin() is the same as subwin(), except that begy and begx are
60 relative to the origin of the window orig rather than the screen.
61 There is no difference between subwindows and derived windows.
62
63 mvderwin() moves a derived window (or subwindow) inside its parent
64 window. The screen-relative parameters of the window are not changed.
65 This routine is used to display different parts of the parent window
66 at the same physical position on the screen.
67
68 dupwin() creates an exact duplicate of the window win.
69
70 wgetparent() returns the parent WINDOW pointer for subwindows, or NULL
71 for windows having no parent.
72
73 wsyncup() causes a touchwin() of all of the window's parents.
74
75 If syncok() is called with a second argument of TRUE, this causes a
76 wsyncup() to be called every time the window is changed.
77
78 is_subwin() reports whether the specified window is a subwindow,
79 created by subwin() or derwin().
80
81 is_syncok() reports whether the specified window is in syncok mode.
82
83 wcursyncup() causes the current cursor position of all of a window's
84 ancestors to reflect the current cursor position of the current
85 window.
86
87 wsyncdown() causes a touchwin() of the current window if any of its
88 parent's windows have been touched.
89
90 resize_window() allows the user to resize an existing window. It
91 returns the pointer to the new window, or NULL on failure.
92
93 wresize() is an ncurses-compatible wrapper for resize_window(). Note
94 that, unlike ncurses, it will NOT process any subwindows of the
95 window. (However, you still can call it _on_ subwindows.) It returns
96 OK or ERR.
97
98 PDC_makenew() allocates all data for a new WINDOW * except the actual
99 lines themselves. If it's unable to allocate memory for the window
100 structure, it will free all allocated memory and return a NULL
101 pointer.
102
103 PDC_makelines() allocates the memory for the lines.
104
105 PDC_sync() handles wrefresh() and wsyncup() calls when a window is
106 changed.
107
108### Return Value
109
110 newwin(), subwin(), derwin() and dupwin() return a pointer to the new
111 window, or NULL on failure. delwin(), mvwin(), mvderwin() and
112 syncok() return OK or ERR. wsyncup(), wcursyncup() and wsyncdown()
113 return nothing.
114
115 is_subwin() and is_syncok() returns TRUE or FALSE.
116
117### Errors
118
119 It is an error to call resize_window() before calling initscr().
120 Also, an error will be generated if we fail to create a newly sized
121 replacement window for curscr, or stdscr. This could happen when
122 increasing the window size. NOTE: If this happens, the previously
123 successfully allocated windows are left alone; i.e., the resize is
124 NOT cancelled for those windows.
125
126### Portability
127 X/Open ncurses NetBSD
128 newwin Y Y Y
129 delwin Y Y Y
130 mvwin Y Y Y
131 subwin Y Y Y
132 derwin Y Y Y
133 mvderwin Y Y Y
134 dupwin Y Y Y
135 wgetparent - Y -
136 wsyncup Y Y Y
137 syncok Y Y Y
138 is_subwin - Y -
139 is_syncok - Y -
140 wcursyncup Y Y Y
141 wsyncdown Y Y Y
142 wresize - Y Y
143 resize_window - - -
144 PDC_makelines - - -
145 PDC_makenew - - -
146 PDC_sync - - -
147
148**man-end****************************************************************/
149
150#include <stdlib.h>
151
152WINDOW *PDC_makenew(int nlines, int ncols, int begy, int begx)
153{
154 WINDOW *win;
155
156 PDC_LOG(("PDC_makenew() - called: lines %d cols %d begy %d begx %d\n",
157 nlines, ncols, begy, begx));
158
159 /* allocate the window structure itself */
160
161 win = calloc(1, sizeof(WINDOW));
162 if (!win)
163 return win;
164
165 /* allocate the line pointer array */
166
167 win->_y = malloc(nlines * sizeof(chtype *));
168 if (!win->_y)
169 {
170 free(win);
171 return (WINDOW *)NULL;
172 }
173
174 /* allocate the minchng and maxchng arrays */
175
176 win->_firstch = malloc(nlines * sizeof(int));
177 if (!win->_firstch)
178 {
179 free(win->_y);
180 free(win);
181 return (WINDOW *)NULL;
182 }
183
184 win->_lastch = malloc(nlines * sizeof(int));
185 if (!win->_lastch)
186 {
187 free(win->_firstch);
188 free(win->_y);
189 free(win);
190 return (WINDOW *)NULL;
191 }
192
193 /* initialize window variables */
194
195 win->_maxy = nlines; /* real max screen size */
196 win->_maxx = ncols; /* real max screen size */
197 win->_begy = begy;
198 win->_begx = begx;
199 win->_bkgd = ' '; /* wrs 4/10/93 -- initialize background to blank */
200 win->_clear = (bool) ((nlines == LINES) && (ncols == COLS));
201 win->_bmarg = nlines - 1;
202 win->_parx = win->_pary = -1;
203
204 /* initialize pad variables*/
205
206 win->_pad._pad_y = -1;
207 win->_pad._pad_x = -1;
208 win->_pad._pad_top = -1;
209 win->_pad._pad_left = -1;
210 win->_pad._pad_bottom = -1;
211 win->_pad._pad_right = -1;
212
213 /* init to say window all changed */
214
215 touchwin(win);
216
217 return win;
218}
219
220WINDOW *PDC_makelines(WINDOW *win)
221{
222 int i, j, nlines, ncols;
223
224 PDC_LOG(("PDC_makelines() - called\n"));
225
226 if (!win)
227 return (WINDOW *)NULL;
228
229 nlines = win->_maxy;
230 ncols = win->_maxx;
231
232 for (i = 0; i < nlines; i++)
233 {
234 win->_y[i] = malloc(ncols * sizeof(chtype));
235 if (!win->_y[i])
236 {
237 /* if error, free all the data */
238
239 for (j = 0; j < i; j++)
240 free(win->_y[j]);
241
242 free(win->_firstch);
243 free(win->_lastch);
244 free(win->_y);
245 free(win);
246
247 return (WINDOW *)NULL;
248 }
249 }
250
251 return win;
252}
253
254void PDC_sync(WINDOW *win)
255{
256 PDC_LOG(("PDC_sync() - called:\n"));
257
258 if (win->_immed)
259 wrefresh(win);
260 if (win->_sync)
261 wsyncup(win);
262}
263
264WINDOW *newwin(int nlines, int ncols, int begy, int begx)
265{
266 WINDOW *win;
267
268 PDC_LOG(("newwin() - called:lines=%d cols=%d begy=%d begx=%d\n",
269 nlines, ncols, begy, begx));
270
271 if (!nlines)
272 nlines = LINES - begy;
273 if (!ncols)
274 ncols = COLS - begx;
275
276 if (!SP || begy + nlines > SP->lines || begx + ncols > SP->cols)
277 return (WINDOW *)NULL;
278
279 win = PDC_makenew(nlines, ncols, begy, begx);
280 if (win)
281 win = PDC_makelines(win);
282
283 if (win)
284 werase(win);
285
286 return win;
287}
288
289int delwin(WINDOW *win)
290{
291 int i;
292
293 PDC_LOG(("delwin() - called\n"));
294
295 if (!win)
296 return ERR;
297
298 /* subwindows use parents' lines */
299
300 if (!(win->_flags & (_SUBWIN|_SUBPAD)))
301 for (i = 0; i < win->_maxy && win->_y[i]; i++)
302 if (win->_y[i])
303 free(win->_y[i]);
304
305 free(win->_firstch);
306 free(win->_lastch);
307 free(win->_y);
308 free(win);
309
310 return OK;
311}
312
313int mvwin(WINDOW *win, int y, int x)
314{
315 PDC_LOG(("mvwin() - called\n"));
316
317 if (!win || (y + win->_maxy > LINES || y < 0)
318 || (x + win->_maxx > COLS || x < 0))
319 return ERR;
320
321 win->_begy = y;
322 win->_begx = x;
323 touchwin(win);
324
325 return OK;
326}
327
328WINDOW *subwin(WINDOW *orig, int nlines, int ncols, int begy, int begx)
329{
330 WINDOW *win;
331 int i, j, k;
332
333 PDC_LOG(("subwin() - called: lines %d cols %d begy %d begx %d\n",
334 nlines, ncols, begy, begx));
335
336 /* make sure window fits inside the original one */
337
338 if (!orig || (begy < orig->_begy) || (begx < orig->_begx) ||
339 (begy + nlines) > (orig->_begy + orig->_maxy) ||
340 (begx + ncols) > (orig->_begx + orig->_maxx))
341 return (WINDOW *)NULL;
342
343 j = begy - orig->_begy;
344 k = begx - orig->_begx;
345
346 if (!nlines)
347 nlines = orig->_maxy - j;
348 if (!ncols)
349 ncols = orig->_maxx - k;
350
351 win = PDC_makenew(nlines, ncols, begy, begx);
352 if (!win)
353 return (WINDOW *)NULL;
354
355 /* initialize window variables */
356
357 win->_attrs = orig->_attrs;
358 win->_bkgd = orig->_bkgd;
359 win->_leaveit = orig->_leaveit;
360 win->_scroll = orig->_scroll;
361 win->_nodelay = orig->_nodelay;
362 win->_delayms = orig->_delayms;
363 win->_use_keypad = orig->_use_keypad;
364 win->_immed = orig->_immed;
365 win->_sync = orig->_sync;
366 win->_pary = j;
367 win->_parx = k;
368 win->_parent = orig;
369
370 for (i = 0; i < nlines; i++, j++)
371 win->_y[i] = orig->_y[j] + k;
372
373 win->_flags |= _SUBWIN;
374
375 return win;
376}
377
378WINDOW *derwin(WINDOW *orig, int nlines, int ncols, int begy, int begx)
379{
380 return subwin(orig, nlines, ncols, begy + orig->_begy, begx + orig->_begx);
381}
382
383int mvderwin(WINDOW *win, int pary, int parx)
384{
385 int i, j;
386 WINDOW *mypar;
387
388 if (!win || !(win->_parent))
389 return ERR;
390
391 mypar = win->_parent;
392
393 if (pary < 0 || parx < 0 || (pary + win->_maxy) > mypar->_maxy ||
394 (parx + win->_maxx) > mypar->_maxx)
395 return ERR;
396
397 j = pary;
398
399 for (i = 0; i < win->_maxy; i++)
400 win->_y[i] = (mypar->_y[j++]) + parx;
401
402 win->_pary = pary;
403 win->_parx = parx;
404
405 return OK;
406}
407
408WINDOW *dupwin(WINDOW *win)
409{
410 WINDOW *new;
411 chtype *ptr, *ptr1;
412 int nlines, ncols, begy, begx, i;
413
414 if (!win)
415 return (WINDOW *)NULL;
416
417 nlines = win->_maxy;
418 ncols = win->_maxx;
419 begy = win->_begy;
420 begx = win->_begx;
421
422 new = PDC_makenew(nlines, ncols, begy, begx);
423 if (new)
424 new = PDC_makelines(new);
425
426 if (!new)
427 return (WINDOW *)NULL;
428
429 /* copy the contents of win into new */
430
431 for (i = 0; i < nlines; i++)
432 {
433 for (ptr = new->_y[i], ptr1 = win->_y[i];
434 ptr < new->_y[i] + ncols; ptr++, ptr1++)
435 *ptr = *ptr1;
436
437 new->_firstch[i] = 0;
438 new->_lastch[i] = ncols - 1;
439 }
440
441 new->_curx = win->_curx;
442 new->_cury = win->_cury;
443 new->_maxy = win->_maxy;
444 new->_maxx = win->_maxx;
445 new->_begy = win->_begy;
446 new->_begx = win->_begx;
447 new->_flags = win->_flags;
448 new->_attrs = win->_attrs;
449 new->_clear = win->_clear;
450 new->_leaveit = win->_leaveit;
451 new->_scroll = win->_scroll;
452 new->_nodelay = win->_nodelay;
453 new->_delayms = win->_delayms;
454 new->_use_keypad = win->_use_keypad;
455 new->_tmarg = win->_tmarg;
456 new->_bmarg = win->_bmarg;
457 new->_parx = win->_parx;
458 new->_pary = win->_pary;
459 new->_parent = win->_parent;
460 new->_bkgd = win->_bkgd;
461 new->_flags = win->_flags;
462
463 return new;
464}
465
466WINDOW *wgetparent(const WINDOW *win)
467{
468 PDC_LOG(("wgetparent() - called\n"));
469
470 if (!win || !win->_parent)
471 return NULL;
472
473 return win->_parent;
474}
475
476WINDOW *resize_window(WINDOW *win, int nlines, int ncols)
477{
478 WINDOW *new;
479 int i, save_cury, save_curx, new_begy, new_begx;
480
481 PDC_LOG(("resize_window() - called: nlines %d ncols %d\n",
482 nlines, ncols));
483
484 if (!win || !SP)
485 return (WINDOW *)NULL;
486
487 if (win->_flags & _SUBPAD)
488 {
489 new = subpad(win->_parent, nlines, ncols, win->_begy, win->_begx);
490 if (!new)
491 return (WINDOW *)NULL;
492 }
493 else if (win->_flags & _SUBWIN)
494 {
495 new = subwin(win->_parent, nlines, ncols, win->_begy, win->_begx);
496 if (!new)
497 return (WINDOW *)NULL;
498 }
499 else
500 {
501 if (win == SP->slk_winptr)
502 {
503 new_begy = SP->lines - SP->slklines;
504 new_begx = 0;
505 }
506 else
507 {
508 new_begy = win->_begy;
509 new_begx = win->_begx;
510 }
511
512 new = PDC_makenew(nlines, ncols, new_begy, new_begx);
513 if (!new)
514 return (WINDOW *)NULL;
515 }
516
517 save_curx = min(win->_curx, (new->_maxx - 1));
518 save_cury = min(win->_cury, (new->_maxy - 1));
519
520 if (!(win->_flags & (_SUBPAD|_SUBWIN)))
521 {
522 new = PDC_makelines(new);
523 if (!new)
524 return (WINDOW *)NULL;
525
526 new->_bkgd = win->_bkgd;
527 werase(new);
528
529 copywin(win, new, 0, 0, 0, 0, min(win->_maxy, new->_maxy) - 1,
530 min(win->_maxx, new->_maxx) - 1, FALSE);
531
532 for (i = 0; i < win->_maxy && win->_y[i]; i++)
533 if (win->_y[i])
534 free(win->_y[i]);
535 }
536
537 new->_flags = win->_flags;
538 new->_attrs = win->_attrs;
539 new->_clear = win->_clear;
540 new->_leaveit = win->_leaveit;
541 new->_scroll = win->_scroll;
542 new->_nodelay = win->_nodelay;
543 new->_delayms = win->_delayms;
544 new->_use_keypad = win->_use_keypad;
545 new->_tmarg = (win->_tmarg > new->_maxy - 1) ? 0 : win->_tmarg;
546 new->_bmarg = (win->_bmarg == win->_maxy - 1) ?
547 new->_maxy - 1 : min(win->_bmarg, (new->_maxy - 1));
548 new->_parent = win->_parent;
549 new->_immed = win->_immed;
550 new->_sync = win->_sync;
551 new->_bkgd = win->_bkgd;
552
553 new->_curx = save_curx;
554 new->_cury = save_cury;
555
556 free(win->_firstch);
557 free(win->_lastch);
558 free(win->_y);
559
560 *win = *new;
561 free(new);
562
563 return win;
564}
565
566int wresize(WINDOW *win, int nlines, int ncols)
567{
568 return (resize_window(win, nlines, ncols) ? OK : ERR);
569}
570
571void wsyncup(WINDOW *win)
572{
573 WINDOW *tmp;
574
575 PDC_LOG(("wsyncup() - called\n"));
576
577 for (tmp = win; tmp; tmp = tmp->_parent)
578 touchwin(tmp);
579}
580
581int syncok(WINDOW *win, bool bf)
582{
583 PDC_LOG(("syncok() - called\n"));
584
585 if (!win)
586 return ERR;
587
588 win->_sync = bf;
589
590 return OK;
591}
592
593bool is_subwin(const WINDOW *win)
594{
595 PDC_LOG(("is_subwin() - called\n"));
596
597 if (!win)
598 return FALSE;
599
600 return ((win->_flags & _SUBWIN) ? TRUE : FALSE);
601}
602
603bool is_syncok(const WINDOW *win)
604{
605 PDC_LOG(("is_syncok() - called\n"));
606
607 if (!win)
608 return FALSE;
609
610 return win->_sync;
611}
612
613void wcursyncup(WINDOW *win)
614{
615 WINDOW *tmp;
616
617 PDC_LOG(("wcursyncup() - called\n"));
618
619 for (tmp = win; tmp && tmp->_parent; tmp = tmp->_parent)
620 wmove(tmp->_parent, tmp->_pary + tmp->_cury, tmp->_parx + tmp->_curx);
621}
622
623void wsyncdown(WINDOW *win)
624{
625 WINDOW *tmp;
626
627 PDC_LOG(("wsyncdown() - called\n"));
628
629 for (tmp = win; tmp; tmp = tmp->_parent)
630 {
631 if (is_wintouched(tmp))
632 {
633 touchwin(win);
634 break;
635 }
636 }
637}
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 527f60c99..b88b89d2d 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -11,9 +11,9 @@
11#ifndef KBUILD_NO_NLS 11#ifndef KBUILD_NO_NLS
12# include <libintl.h> 12# include <libintl.h>
13#else 13#else
14# define gettext(Msgid) ((const char *) (Msgid)) 14static inline const char *gettext(const char *txt) { return txt; }
15# define textdomain(Domainname) ((const char *) (Domainname)) 15static inline void textdomain(const char *domainname) {}
16# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) 16static inline void bindtextdomain(const char *name, const char *dir) {}
17#endif 17#endif
18 18
19#ifdef __cplusplus 19#ifdef __cplusplus
diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh
index 5075ebf2d..a608d4c5e 100755
--- a/scripts/kconfig/lxdialog/check-lxdialog.sh
+++ b/scripts/kconfig/lxdialog/check-lxdialog.sh
@@ -6,6 +6,10 @@ ldflags()
6{ 6{
7 pkg-config --libs ncursesw 2>/dev/null && exit 7 pkg-config --libs ncursesw 2>/dev/null && exit
8 pkg-config --libs ncurses 2>/dev/null && exit 8 pkg-config --libs ncurses 2>/dev/null && exit
9 if [ -n "$W64DEVKIT" ]
10 then
11 echo "./scripts/kconfig/libcurses/lib.a" && exit
12 fi
9 for ext in so a dll.a dylib ; do 13 for ext in so a dll.a dylib ; do
10 for lib in ncursesw ncurses curses ; do 14 for lib in ncursesw ncurses curses ; do
11 $cc -print-file-name=lib${lib}.${ext} | grep -q / 15 $cc -print-file-name=lib${lib}.${ext} | grep -q /
@@ -34,6 +38,8 @@ ccflags()
34 echo '-I/usr/include/ncurses -DCURSES_LOC="<curses.h>"' 38 echo '-I/usr/include/ncurses -DCURSES_LOC="<curses.h>"'
35 elif [ -f /usr/include/ncurses.h ]; then 39 elif [ -f /usr/include/ncurses.h ]; then
36 echo '-DCURSES_LOC="<ncurses.h>"' 40 echo '-DCURSES_LOC="<ncurses.h>"'
41 elif [ -n "$W64DEVKIT" ]; then
42 echo '-I./scripts/kconfig/libcurses -DCURSES_LOC="<curses.h>"'
37 else 43 else
38 echo '-DCURSES_LOC="<curses.h>"' 44 echo '-DCURSES_LOC="<curses.h>"'
39 fi 45 fi
@@ -47,7 +53,7 @@ trap "rm -f $tmp" 0 1 2 3 15
47check() { 53check() {
48 $cc -x c - -o $tmp 2>/dev/null <<'EOF' 54 $cc -x c - -o $tmp 2>/dev/null <<'EOF'
49#include CURSES_LOC 55#include CURSES_LOC
50main() {} 56int main() {}
51EOF 57EOF
52 if [ $? != 0 ]; then 58 if [ $? != 0 ]; then
53 echo " *** Unable to find the ncurses libraries or the" 1>&2 59 echo " *** Unable to find the ncurses libraries or the" 1>&2
diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h
index af3cf716e..10a3292e1 100644
--- a/scripts/kconfig/lxdialog/dialog.h
+++ b/scripts/kconfig/lxdialog/dialog.h
@@ -24,6 +24,7 @@
24#include <ctype.h> 24#include <ctype.h>
25#include <stdlib.h> 25#include <stdlib.h>
26#include <string.h> 26#include <string.h>
27#include <strings.h>
27 28
28#ifdef __sun__ 29#ifdef __sun__
29#define CURS_MACROS 30#define CURS_MACROS
diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c
index 072d3eecc..ea3ee4a95 100644
--- a/scripts/kconfig/lxdialog/util.c
+++ b/scripts/kconfig/lxdialog/util.c
@@ -138,6 +138,9 @@ void dialog_clear(void)
138 */ 138 */
139void init_dialog(void) 139void init_dialog(void)
140{ 140{
141 char *colors = getenv("COLORS");
142 use_colors = !(colors && *colors == '0');
143
141 initscr(); /* Init curses */ 144 initscr(); /* Init curses */
142 keypad(stdscr, TRUE); 145 keypad(stdscr, TRUE);
143 cbreak(); 146 cbreak();
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index aaf82820e..62baa82b0 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -12,8 +12,12 @@
12/* On Darwin, this may be needed to get SIGWINCH: */ 12/* On Darwin, this may be needed to get SIGWINCH: */
13#define _DARWIN_C_SOURCE 1 13#define _DARWIN_C_SOURCE 1
14 14
15#ifndef __MINGW32__
15#include <sys/ioctl.h> 16#include <sys/ioctl.h>
16#include <sys/wait.h> 17#include <sys/wait.h>
18#else
19#include <windows.h>
20#endif
17#include <ctype.h> 21#include <ctype.h>
18#include <errno.h> 22#include <errno.h>
19#include <fcntl.h> 23#include <fcntl.h>
@@ -23,13 +27,17 @@
23#include <stdlib.h> 27#include <stdlib.h>
24#include <string.h> 28#include <string.h>
25#include <strings.h> /* for strcasecmp */ 29#include <strings.h> /* for strcasecmp */
30#ifndef __MINGW32__
26#include <termios.h> 31#include <termios.h>
32#endif
27#include <unistd.h> 33#include <unistd.h>
28#include <locale.h> 34#include <locale.h>
29 35
36#ifndef __MINGW32__
30#ifndef SIGWINCH 37#ifndef SIGWINCH
31#define SIGWINCH 28 38#define SIGWINCH 28
32#endif 39#endif
40#endif
33 41
34#define LKC_DIRECT_LINK 42#define LKC_DIRECT_LINK
35#include "lkc.h" 43#include "lkc.h"
@@ -270,11 +278,15 @@ static char input_buf[4096];
270static const char filename[] = ".config"; 278static const char filename[] = ".config";
271static char *args[1024], **argptr = args; 279static char *args[1024], **argptr = args;
272static int indent; 280static int indent;
281#ifndef __MINGW32__
273static struct termios ios_org; 282static struct termios ios_org;
283#endif
274static int rows = 0, cols = 0; 284static int rows = 0, cols = 0;
275static struct menu *current_menu; 285static struct menu *current_menu;
276static int child_count; 286static int child_count;
287#ifndef __MINGW32__
277static int do_resize; 288static int do_resize;
289#endif
278static int single_menu_mode; 290static int single_menu_mode;
279 291
280static void conf(struct menu *menu); 292static void conf(struct menu *menu);
@@ -292,12 +304,45 @@ static int cprint1(const char *fmt, ...);
292static void cprint_done(void); 304static void cprint_done(void);
293static int cprint(const char *fmt, ...); 305static int cprint(const char *fmt, ...);
294 306
307#ifdef __MINGW32__
308struct winsize {
309 unsigned short ws_row, ws_col;
310 unsigned short ws_xpixel, ws_ypixel;
311};
312
313static int mingw_get_terminal_width_height(struct winsize *win)
314{
315 int fd;
316 HANDLE handle;
317 CONSOLE_SCREEN_BUFFER_INFO sbi;
318
319 win->ws_row = 0;
320 win->ws_col = 0;
321
322 for (fd=STDOUT_FILENO; fd<=STDERR_FILENO; ++fd) {
323 handle = (HANDLE)_get_osfhandle(fd);
324 if (handle != INVALID_HANDLE_VALUE &&
325 GetConsoleScreenBufferInfo(handle, &sbi) != 0) {
326 win->ws_row = sbi.srWindow.Bottom - sbi.srWindow.Top + 1;
327 win->ws_col = sbi.srWindow.Right - sbi.srWindow.Left + 1;
328 return 0;
329 }
330 }
331
332 return -1;
333}
334#endif
335
295static void init_wsize(void) 336static void init_wsize(void)
296{ 337{
297 struct winsize ws; 338 struct winsize ws;
298 char *env; 339 char *env;
299 340
341#ifndef __MINGW32__
300 if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) { 342 if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
343#else
344 if (mingw_get_terminal_width_height(&ws) == 0) {
345#endif
301 rows = ws.ws_row; 346 rows = ws.ws_row;
302 cols = ws.ws_col; 347 cols = ws.ws_col;
303 } 348 }
@@ -459,8 +504,198 @@ static void winch_handler(int sig)
459} 504}
460#endif 505#endif
461 506
507#ifdef __MINGW32__
508static char *
509quote_arg(const char *arg)
510{
511 int len = 0, n = 0;
512 int force_quotes = 0;
513 char *q, *d;
514 const char *p = arg;
515
516 /* empty arguments must be quoted */
517 if (!*p) {
518 force_quotes = 1;
519 }
520
521 while (*p) {
522 if (isspace(*p)) {
523 /* arguments containing whitespace must be quoted */
524 force_quotes = 1;
525 }
526 else if (*p == '"') {
527 /* double quotes in arguments need to be escaped */
528 n++;
529 }
530 else if (*p == '\\') {
531 /* count contiguous backslashes */
532 int count = 0;
533 while (*p == '\\') {
534 count++;
535 p++;
536 len++;
537 }
538
539 /*
540 * Only escape backslashes before explicit double quotes or
541 * or where the backslashes are at the end of an argument
542 * that is scheduled to be quoted.
543 */
544 if (*p == '"' || (force_quotes && *p == '\0')) {
545 n += count*2 + 1;
546 }
547
548 if (*p == '\0') {
549 break;
550 }
551 continue;
552 }
553 len++;
554 p++;
555 }
556
557 if (!force_quotes && n == 0) {
558 return (char*)strdup(arg);
559 }
560
561 /* insert double quotes and backslashes where necessary */
562 d = q = malloc(len+n+3);
563 if (q == NULL)
564 return NULL;
565 if (force_quotes) {
566 *d++ = '"';
567 }
568
569 while (*arg) {
570 if (*arg == '"') {
571 *d++ = '\\';
572 }
573 else if (*arg == '\\') {
574 int count = 0;
575 while (*arg == '\\') {
576 count++;
577 *d++ = *arg++;
578 }
579
580 if (*arg == '"' || (force_quotes && *arg == '\0')) {
581 while (count-- > 0) {
582 *d++ = '\\';
583 }
584 if (*arg == '"') {
585 *d++ = '\\';
586 }
587 }
588 }
589 if (*arg != '\0') {
590 *d++ = *arg++;
591 }
592 }
593 if (force_quotes) {
594 *d++ = '"';
595 }
596 *d = '\0';
597
598 return q;
599}
600
601static int mingw_pipe(HANDLE *pipe)
602{
603 SECURITY_ATTRIBUTES sa;
604
605 sa.nLength = sizeof(sa); /* Length in bytes */
606 sa.bInheritHandle = 1; /* the child must inherit these handles */
607 sa.lpSecurityDescriptor = NULL;
608
609 /* pipe[0] is the read handle, pipe[i] the write handle */
610 if ( !CreatePipe (&pipe[0], &pipe[1], &sa, 1 << 13) ) {
611 return -1;
612 }
613
614 return (pipe[0] == INVALID_HANDLE_VALUE ||
615 pipe[1] == INVALID_HANDLE_VALUE) ? -1 : 0;
616}
617#endif
618
462static int exec_conf(void) 619static int exec_conf(void)
463{ 620{
621#ifdef __MINGW32__
622 char **a, *cmd;
623 int fd, size, len = 0;
624 STARTUPINFO siStartInfo;
625 PROCESS_INFORMATION piProcInfo;
626 HANDLE hPipe[2];
627 DWORD stat = 0;
628
629 // Quote each argument if necessary
630 *argptr++ = NULL;
631 for (a = args; *a; a++) {
632 *a = quote_arg(*a);
633 if (*a == NULL)
634 _exit(EXIT_FAILURE);
635 len += strlen(*a) + 1;
636 }
637
638 // Make a command line from the arguments
639 cmd = malloc(len + 1);
640 if (cmd == NULL)
641 _exit(EXIT_FAILURE);
642 for (a = args; *a; a++) {
643 if (a == args) {
644 strcpy(cmd, *a);
645 } else {
646 strcat(cmd, " ");
647 strcat(cmd, *a);
648 }
649 free(*a);
650 }
651
652 // Create a pipe to communicate with the dialog
653 if (mingw_pipe(hPipe) == -1)
654 _exit(EXIT_FAILURE);
655
656 // Make the parent end of the pipe non-inheritable
657 SetHandleInformation(hPipe[0], HANDLE_FLAG_INHERIT, 0);
658
659 ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
660 siStartInfo.cb = sizeof(STARTUPINFO);
661 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
662 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
663 siStartInfo.hStdError = hPipe[1];
664 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
665 CreateProcess(NULL, (LPSTR)cmd, NULL, NULL, TRUE, 0, NULL, NULL,
666 &siStartInfo, &piProcInfo);
667 free(cmd);
668
669 // Close child end of pipe
670 CloseHandle(hPipe[1]);
671 hPipe[1] = INVALID_HANDLE_VALUE;
672
673 fd = _open_osfhandle((intptr_t)hPipe[0], _O_RDONLY | _O_BINARY);
674 if (fd == -1)
675 _exit(EXIT_FAILURE);
676
677 bufptr = input_buf;
678 while (1) {
679 size = input_buf + sizeof(input_buf) - bufptr;
680 size = _read(fd, bufptr, size);
681 if (size <= 0) {
682 if (size < 0) {
683 if (errno == EINTR || errno == EAGAIN)
684 continue;
685 perror("read");
686 }
687 break;
688 }
689 bufptr += size;
690 }
691 *bufptr++ = 0;
692 close(fd);
693
694 WaitForSingleObject(piProcInfo.hProcess, INFINITE);
695 GetExitCodeProcess(piProcInfo.hProcess, &stat);
696
697 return (int)(stat &0xff);
698#else
464 int pipefd[2], stat, size; 699 int pipefd[2], stat, size;
465 sigset_t sset, osset; 700 sigset_t sset, osset;
466 701
@@ -535,6 +770,7 @@ static int exec_conf(void)
535 sigprocmask(SIG_SETMASK, &osset, NULL); 770 sigprocmask(SIG_SETMASK, &osset, NULL);
536 771
537 return WEXITSTATUS(stat); 772 return WEXITSTATUS(stat);
773#endif
538} 774}
539 775
540static void search_conf(void) 776static void search_conf(void)
@@ -788,7 +1024,7 @@ static void conf(struct menu *menu)
788 switch (type) { 1024 switch (type) {
789 case 'm': 1025 case 'm':
790 if (single_menu_mode) 1026 if (single_menu_mode)
791 submenu->data = (void *) (long) !submenu->data; 1027 submenu->data = (void *) (intptr_t) !submenu->data;
792 else 1028 else
793 conf(submenu); 1029 conf(submenu);
794 break; 1030 break;
@@ -1051,7 +1287,9 @@ static void conf_save(void)
1051 1287
1052static void conf_cleanup(void) 1288static void conf_cleanup(void)
1053{ 1289{
1290#ifndef __MINGW32__
1054 tcsetattr(1, TCSAFLUSH, &ios_org); 1291 tcsetattr(1, TCSAFLUSH, &ios_org);
1292#endif
1055 unlink(".help.tmp"); 1293 unlink(".help.tmp");
1056 unlink("lxdialog.scrltmp"); 1294 unlink("lxdialog.scrltmp");
1057} 1295}
@@ -1080,7 +1318,9 @@ int main(int ac, char **av)
1080 single_menu_mode = 1; 1318 single_menu_mode = 1;
1081 } 1319 }
1082 1320
1321#ifndef __MINGW32__
1083 tcgetattr(1, &ios_org); 1322 tcgetattr(1, &ios_org);
1323#endif
1084 atexit(conf_cleanup); 1324 atexit(conf_cleanup);
1085 init_wsize(); 1325 init_wsize();
1086 conf(&rootmenu); 1326 conf(&rootmenu);
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 3d7877afc..31d5fbbfc 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -6,8 +6,10 @@
6#include <ctype.h> 6#include <ctype.h>
7#include <stdlib.h> 7#include <stdlib.h>
8#include <string.h> 8#include <string.h>
9#ifndef __MINGW32__
9#include <regex.h> 10#include <regex.h>
10#include <sys/utsname.h> 11#include <sys/utsname.h>
12#endif
11 13
12#define LKC_DIRECT_LINK 14#define LKC_DIRECT_LINK
13#include "lkc.h" 15#include "lkc.h"
@@ -44,7 +46,9 @@ void sym_add_default(struct symbol *sym, const char *def)
44void sym_init(void) 46void sym_init(void)
45{ 47{
46 struct symbol *sym; 48 struct symbol *sym;
49#ifndef __MINGW32__
47 struct utsname uts; 50 struct utsname uts;
51#endif
48 char *p; 52 char *p;
49 static bool inited = false; 53 static bool inited = false;
50 54
@@ -52,7 +56,9 @@ void sym_init(void)
52 return; 56 return;
53 inited = true; 57 inited = true;
54 58
59#ifndef __MINGW32__
55 uname(&uts); 60 uname(&uts);
61#endif
56 62
57 sym = sym_lookup("ARCH", 0); 63 sym = sym_lookup("ARCH", 0);
58 sym->type = S_STRING; 64 sym->type = S_STRING;
@@ -71,7 +77,11 @@ void sym_init(void)
71 sym = sym_lookup("UNAME_RELEASE", 0); 77 sym = sym_lookup("UNAME_RELEASE", 0);
72 sym->type = S_STRING; 78 sym->type = S_STRING;
73 sym->flags |= SYMBOL_AUTO; 79 sym->flags |= SYMBOL_AUTO;
80#ifdef __MINGW32__
81 sym_add_default(sym, "UNKNOWN");
82#else
74 sym_add_default(sym, uts.release); 83 sym_add_default(sym, uts.release);
84#endif
75} 85}
76 86
77enum symbol_type sym_get_type(struct symbol *sym) 87enum symbol_type sym_get_type(struct symbol *sym)
@@ -718,24 +728,43 @@ struct symbol *sym_find(const char *name)
718 return symbol; 728 return symbol;
719} 729}
720 730
731#if !defined HAVE_RE && !defined __MINGW32__
732#define HAVE_RE 1
733#endif
734
721struct symbol **sym_re_search(const char *pattern) 735struct symbol **sym_re_search(const char *pattern)
722{ 736{
723 struct symbol *sym, **sym_arr = NULL; 737 struct symbol *sym, **sym_arr = NULL;
724 int i, cnt, size; 738 int i, cnt, size;
739#if HAVE_RE
725 regex_t re; 740 regex_t re;
741#else
742 /* without re support use: strstr(sym->name, upper(pattern)) */
743 /* sym->name is a config, e.g. "SHELL_ASH" or "FEATURE_UTMP" */
744 char upat[256] = {0};
745 for (i = 0; i < 255 && pattern[i]; ++i)
746 upat[i] = toupper(pattern[i]);
747#endif
726 748
727 cnt = size = 0; 749 cnt = size = 0;
728 /* Skip if empty */ 750 /* Skip if empty */
729 if (strlen(pattern) == 0) 751 if (strlen(pattern) == 0)
730 return NULL; 752 return NULL;
753#if HAVE_RE
731 if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE)) 754 if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
732 return NULL; 755 return NULL;
756#endif
733 757
734 for_all_symbols(i, sym) { 758 for_all_symbols(i, sym) {
735 if (sym->flags & SYMBOL_CONST || !sym->name) 759 if (sym->flags & SYMBOL_CONST || !sym->name)
736 continue; 760 continue;
761#if HAVE_RE
737 if (regexec(&re, sym->name, 0, NULL, 0)) 762 if (regexec(&re, sym->name, 0, NULL, 0))
738 continue; 763 continue;
764#else
765 if (!strstr(sym->name, upat))
766 continue;
767#endif
739 if (cnt + 1 >= size) { 768 if (cnt + 1 >= size) {
740 void *tmp = sym_arr; 769 void *tmp = sym_arr;
741 size += 16; 770 size += 16;
@@ -749,7 +778,9 @@ struct symbol **sym_re_search(const char *pattern)
749 } 778 }
750 if (sym_arr) 779 if (sym_arr)
751 sym_arr[cnt] = NULL; 780 sym_arr[cnt] = NULL;
781#if HAVE_RE
752 regfree(&re); 782 regfree(&re);
783#endif
753 784
754 return sym_arr; 785 return sym_arr;
755} 786}
diff --git a/scripts/kconfig/zconf.hash.c_shipped b/scripts/kconfig/zconf.hash.c_shipped
index 29d9cf6cc..6996aba7f 100644
--- a/scripts/kconfig/zconf.hash.c_shipped
+++ b/scripts/kconfig/zconf.hash.c_shipped
@@ -161,43 +161,43 @@ kconf_id_lookup (register const char *str, register unsigned int len)
161 static struct kconf_id wordlist[] = 161 static struct kconf_id wordlist[] =
162 { 162 {
163 {-1}, {-1}, 163 {-1}, {-1},
164 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_IF, TF_COMMAND|TF_PARAM}, 164 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_IF, TF_COMMAND|TF_PARAM},
165 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_TYPE, TF_COMMAND, S_INT}, 165 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_TYPE, TF_COMMAND, S_INT},
166 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str4, T_HELP, TF_COMMAND}, 166 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str4, T_HELP, TF_COMMAND},
167 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND}, 167 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND},
168 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6, T_SELECT, TF_COMMAND}, 168 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6, T_SELECT, TF_COMMAND},
169 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_ENDMENU, TF_COMMAND}, 169 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_ENDMENU, TF_COMMAND},
170 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_TYPE, TF_COMMAND, S_TRISTATE}, 170 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_TYPE, TF_COMMAND, S_TRISTATE},
171 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND}, 171 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND},
172 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10, T_RANGE, TF_COMMAND}, 172 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10, T_RANGE, TF_COMMAND},
173 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11, T_TYPE, TF_COMMAND, S_STRING}, 173 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11, T_TYPE, TF_COMMAND, S_STRING},
174 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_UNKNOWN}, 174 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_UNKNOWN},
175 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, 175 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN},
176 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_MENU, TF_COMMAND}, 176 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_MENU, TF_COMMAND},
177 {-1}, 177 {-1},
178 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, 178 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_DEFAULT, TF_COMMAND, S_BOOLEAN},
179 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_DEFAULT, TF_COMMAND, S_TRISTATE}, 179 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_DEFAULT, TF_COMMAND, S_TRISTATE},
180 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_MAINMENU, TF_COMMAND}, 180 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_MAINMENU, TF_COMMAND},
181 {-1}, 181 {-1},
182 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20, T_MENUCONFIG, TF_COMMAND}, 182 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20, T_MENUCONFIG, TF_COMMAND},
183 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_CONFIG, TF_COMMAND}, 183 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_CONFIG, TF_COMMAND},
184 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ON, TF_PARAM}, 184 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ON, TF_PARAM},
185 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_HEX}, 185 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_HEX},
186 {-1}, {-1}, 186 {-1}, {-1},
187 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26, T_SOURCE, TF_COMMAND}, 187 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26, T_SOURCE, TF_COMMAND},
188 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_DEPENDS, TF_COMMAND}, 188 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_DEPENDS, TF_COMMAND},
189 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_OPTIONAL, TF_COMMAND}, 189 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_OPTIONAL, TF_COMMAND},
190 {-1}, {-1}, 190 {-1}, {-1},
191 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND}, 191 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND},
192 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND}, 192 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND},
193 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_REQUIRES, TF_COMMAND}, 193 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_REQUIRES, TF_COMMAND},
194 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str34, T_TYPE, TF_COMMAND, S_BOOLEAN}, 194 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str34, T_TYPE, TF_COMMAND, S_BOOLEAN},
195 {-1}, {-1}, 195 {-1}, {-1},
196 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_TYPE, TF_COMMAND, S_BOOLEAN}, 196 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_TYPE, TF_COMMAND, S_BOOLEAN},
197 {-1}, {-1}, {-1}, 197 {-1}, {-1}, {-1},
198 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_CHOICE, TF_COMMAND}, 198 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_CHOICE, TF_COMMAND},
199 {-1}, {-1}, {-1}, {-1}, 199 {-1}, {-1}, {-1}, {-1},
200 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_PROMPT, TF_COMMAND} 200 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_PROMPT, TF_COMMAND}
201 }; 201 };
202 202
203 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) 203 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped
index a27d256d6..863f375be 100644
--- a/scripts/kconfig/zconf.tab.c_shipped
+++ b/scripts/kconfig/zconf.tab.c_shipped
@@ -143,6 +143,7 @@
143#include <stdarg.h> 143#include <stdarg.h>
144#include <stdio.h> 144#include <stdio.h>
145#include <stdlib.h> 145#include <stdlib.h>
146#include <stdint.h>
146#include <string.h> 147#include <string.h>
147#include <stdbool.h> 148#include <stdbool.h>
148 149
diff --git a/scripts/mk_mingw64u_defconfig b/scripts/mk_mingw64u_defconfig
new file mode 100755
index 000000000..19124d735
--- /dev/null
+++ b/scripts/mk_mingw64u_defconfig
@@ -0,0 +1,38 @@
1#!/bin/sh
2
3configs=$(dirname -- "$0")/../configs
4
5# replace each FOO=bar argument with -e 's/.*FOO.*/FOO=bar/', then sed "$@"
6set_build_opts() {
7 for v; do
8 set -- "$@" -e "s/.*${v%%=*}.*/$v/"
9 shift
10 done
11 sed "$@"
12}
13
14
15# Create unicode configs/mingw64u_defconfig from configs/mingw64_defconfig
16# by flipping some build options to enable:
17# - UTF8 manifest to support unicode on win 10 (filenames, etc).
18# - UTF8 terminal input (shell prompt, read).
19# - UTF8 editing - codepoint awareness (prompt, read):
20# - Builtin libc unicode functions (mbstowcs etc - no UNICODE_USING_LOCALE).
21# - Dynamic unicode based on ANSI codepage and ENV (CHECK_UNICODE_IN_ENV).
22# - Screen-width awareness (COMBINING_WCHARS, WIDE_WCHARS)
23# - Full unicode range (U+10FFFF - LAST_SUPPORTED_WCHAR=1114111)
24
25set_build_opts \
26 CONFIG_FEATURE_UTF8_MANIFEST=y \
27 CONFIG_FEATURE_UTF8_INPUT=y \
28 CONFIG_FEATURE_UTF8_OUTPUT=y \
29 CONFIG_UNICODE_SUPPORT=y \
30 CONFIG_FEATURE_CHECK_UNICODE_IN_ENV=y \
31 CONFIG_SUBST_WCHAR=63 \
32 CONFIG_LAST_SUPPORTED_WCHAR=1114111 \
33 CONFIG_UNICODE_COMBINING_WCHARS=y \
34 CONFIG_UNICODE_WIDE_WCHARS=y \
35 < "$configs"/mingw64_defconfig \
36 > "$configs"/mingw64u_defconfig
37
38sed -i 's/CONFIG_FEATURE_APP_MANIFEST=y/# CONFIG_FEATURE_APP_MANIFEST is not set/' "$configs"/mingw64u_defconfig
diff --git a/scripts/mkconfigs b/scripts/mkconfigs
index 1bbf10c3a..9e4be6199 100755
--- a/scripts/mkconfigs
+++ b/scripts/mkconfigs
@@ -33,8 +33,8 @@ if test $? != 0; then
33 echo 'od tool is not installed or cannot accept "-v -b" options' 33 echo 'od tool is not installed or cannot accept "-v -b" options'
34 exit 1 34 exit 1
35fi 35fi
36bzip2 </dev/null >/dev/null 36bzip2 </dev/null >/dev/null 2>&1
37if test $? != 0; then 37if test $? = 127; then
38 echo 'bzip2 is not installed' 38 echo 'bzip2 is not installed'
39 exit 1 39 exit 1
40fi 40fi
diff --git a/scripts/mkwcwidth b/scripts/mkwcwidth
new file mode 100755
index 000000000..792045a29
--- /dev/null
+++ b/scripts/mkwcwidth
@@ -0,0 +1,169 @@
1#!/bin/sh
2#
3# Generate a C implementation of wcwidth, with latest unicode data
4# from a local clone of https://github.com/jquast/wcwidth
5#
6# The MIT License (MIT)
7#
8# Copyright (C) 2024 Avi Halachmi <avihpit at yahoo.com>
9#
10# Permission is hereby granted, free of charge, to any person obtaining a copy
11# of this software and associated documentation files (the "Software"), to deal
12# in the Software without restriction, including without limitation the rights
13# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14# copies of the Software, and to permit persons to whom the Software is
15# furnished to do so, subject to the following conditions:
16#
17# The above copyright notice and this permission notice shall be included in all
18# copies or substantial portions of the Software.
19#
20# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26# SOFTWARE.
27
28export LC_ALL=C
29self=${0##*/}
30
31# c-types (bigger types work but waste memory. uintN_t need <stdint.h>)
32u32=uint32_t # "unsigned" is also typically 32 bit
33u16=uint16_t # "unsigned short" is also typically 16 bits
34FUNC_ATTR=FAST_FUNC # delete this line if not generating a busybox function
35
36
37err() { >&2 printf %s\\n "$self: $*"; exit 1; }
38
39case ${1-} in -h | --help)
40 echo "Usage: $self [path/to/python-wcwidth] (default path is '.')"
41 echo "Prints a wcwidth C implementation, with latest Unicode data"
42 echo "imported from a local https://github.com/jquast/wcwidth repo."
43 echo "Assumptions about table_zero.py and table_wide.py at the repo:"
44 echo "- Each range is in one Unicode plane (a>>16 == b>>16) (enforced)."
45 echo "- Commit 04d6d90c (2023-10-30) or later, where table_zero.py"
46 echo " includes zero-width Cf chars (else need to add manual tests)."
47esac
48
49[ "${1-}" != -- ] || shift
50
51pwc_root=${1:-.}
52pwc_git() { git -C "$pwc_root" "$@"; }
53
54zerowidth_py=$pwc_root/wcwidth/table_zero.py
55widewidth_py=$pwc_root/wcwidth/table_wide.py
56
57[ -r "$zerowidth_py" ] && [ -r "$widewidth_py" ] \
58 || err "missing $zerowidth_py or $widewidth_py. abort."
59
60# latest unicode version from table_wide.py (e.g. from " '10.0.0': (")
61ver=$(grep "^\s*'[0-9]" < "$widewidth_py" | tail -n1 | sed "s/.*'\(.*\)'.*/\1/")
62
63# stdin -> stdout: extract the data of the last table (latest spec) from
64# wcwidth/table_{wide,zero}.py (from https://github.com/jquast/wcwidth)
65last_table() {
66 awk "/^\s*'[0-9]/ { i=0 } # new table -> reset
67 /^\s*\(0x/ { arr[++i] = \$0 } # range (first, last)
68 END { for (j=1; j <= i; ++j) print arr[j] }"
69}
70
71# stdin -> stdout, $1 is the range's (wc)width (0 or 2), e.g.
72# from: (0x0123a, 0x0123c,), # comment
73# to : R(0x00123a, 0x00123c, 2), /* comment */
74# ranges bigger than half-plane (32769+ codepoints) are split to two.
75py_data_to_c() {
76 sed -e 's/[(),]/ /g' -e 's|#\(.*\)|/*\1 */|' | while read a b c; do
77 # to support cross-plane ranges, we'd need to split them here,
78 # but unlikely required, as all planes end in non-characters.
79 [ $(($a>>16)) = $(($b>>16)) ] || err "not same plane -- $a $b"
80
81 a=$(($a)) b=$(($b)) # some shells want decimal vars in $(())
82 if [ "$((b-a))" -ge 32768 ]; then # split to 15 bit ranges
83 printf "R(0x%06x, 0x%06x, $1), %s\n" $a $((a+32767)) "$c"
84 a=$((a+32768)) c="/* (continued...) */"
85 fi
86 printf "R(0x%06x, 0x%06x, $1), %s\n" $a $b "$c"
87 done
88}
89
90data=$(last_table < "$zerowidth_py" | py_data_to_c 0 &&
91 last_table < "$widewidth_py" | py_data_to_c 2) || err abort
92data=$(printf %s\\n "$data" | sort) # lexicographic here is also numeric
93
94# sorted hex ranges and their (wc)width: R(first, last, {0|2}),[ /* ... */]
95data() { printf %s\\n "$data"; }
96
97repeat() { R=$2; while [ "$R" -gt 0 ]; do printf %s "$1"; R=$((R-1)); done; }
98
99# data -> stdout: array such that a[p], a[p+1] are [from, to) of plane p data
100mkplanes() {
101 i=0 lastp=-1
102 while read a b c; do
103 p=$((${b%?} >> 16)) # plane (last >> 16)
104 repeat "$i, " $((p-lastp))
105 i=$((i+1)) lastp=$p
106 done
107 repeat "$i, " $((17-lastp))
108}
109
110indent() { sed -e 's/^/\t\t/' -e 's/\s*$//'; } # also trim trailing spaces
111
112cat << CFUNCTION
113/* wcwidth - Unicode $ver, generated by $0.
114 * Copyright (C) 2024 Avi Halachmi <avihpit at yahoo.com>
115 * License: MIT
116 *
117 * Data imported on $(date -u -I) from https://github.com/jquast/wcwidth
118 * commit $(pwc_git describe --tags) ($(pwc_git show --no-patch --format=%ci))
119 */
120int ${FUNC_ATTR-} wcwidth($u32 ucs)
121{
122 /* sorted ranges, "first" is clipped to 16 bit, and its high bits
123 * (plane) are deduced from the "planes" array below.
124 * (imported from ${zerowidth_py##*/} and ${widewidth_py##*/})
125 */
126 static const struct range {
127 uint16_t first;
128 uint16_t iswide: 1; /* bitfield order empirically faster */
129 uint16_t difflast: 15;
130 } ranges[] = {
131 #define R(first, last, width) {first & 0xffff, width/2, last-first}
132$(data | indent)
133 #undef R
134 };
135
136 /* planes[p], planes[p+1] are [from, to) at "ranges" for plane p */
137 static const $u16 planes[/* 18 */] = {
138$(data | mkplanes | fold -s -w 60 | indent)
139 };
140
141 /******* END OF STATIC DATA *******/
142
143 $u32 p, bot, top;
144
145 /* 0:0, 1..31:-1 (C0), 32..126:1 (isprint), 127..159:-1 (DEL, C1) */
146 if (ucs < 160)
147 return ((ucs + 1) & 127) > 32 ? 1 : ucs ? -1 : 0;
148
149 /* out of range for "planes" (and non-unicode), non-characters. */
150 /* (some also test surrogate halves, but not required by POSIX) */
151 if (ucs > 0x10ffff || (ucs & 0xfffe) == 0xfffe)
152 return -1;
153
154 p = ucs >> 16;
155 ucs &= 0xffff;
156
157 for (bot = planes[p], top = planes[p+1]; bot < top; ) {
158 $u32 mid = (bot + top) / 2;
159 if (ucs < ranges[mid].first)
160 top = mid;
161 else if (ucs > ranges[mid].first + ranges[mid].difflast)
162 bot = mid + 1;
163 else
164 return 2 * ranges[mid].iswide;
165 }
166
167 return 1;
168} /* wcwidth - Unicode $ver */
169CFUNCTION
diff --git a/scripts/trylink b/scripts/trylink
index 2255deee7..2456252a3 100755
--- a/scripts/trylink
+++ b/scripts/trylink
@@ -93,10 +93,16 @@ if ! check_cc "-Wl,--sort-section,alignment"; then
93 SORT_SECTION="" 93 SORT_SECTION=""
94fi 94fi
95 95
96WARN_COMMON="-Wl,--warn-common"
97if ! check_cc "-Wl,--warn-common"; then
98 echo "Your linker does not support --warn-common"
99 WARN_COMMON=""
100fi
101
96START_GROUP="-Wl,--start-group" 102START_GROUP="-Wl,--start-group"
97END_GROUP="-Wl,--end-group" 103END_GROUP="-Wl,--end-group"
98INFO_OPTS() { 104INFO_OPTS() {
99 echo "-Wl,--warn-common -Wl,-Map,$EXE.map -Wl,--verbose" 105 echo "$WARN_COMMON -Wl,-Map,$EXE.map -Wl,--verbose"
100} 106}
101 107
102# gold may not support --sort-common (yet) 108# gold may not support --sort-common (yet)
diff --git a/shell/Kbuild.src b/shell/Kbuild.src
index 6bba4989f..a287fce4e 100644
--- a/shell/Kbuild.src
+++ b/shell/Kbuild.src
@@ -9,3 +9,4 @@ lib-y:=
9INSERT 9INSERT
10 10
11lib-$(CONFIG_FEATURE_SH_MATH) += math.o 11lib-$(CONFIG_FEATURE_SH_MATH) += math.o
12lib-$(CONFIG_FEATURE_PRNG_SHELL) += random.o
diff --git a/shell/ash.c b/shell/ash.c
index 9173b8608..3919118f0 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -15,6 +15,20 @@
15 * 15 *
16 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
17 */ 17 */
18
19/*
20 * MinGW notes
21 *
22 * - Environment variables from Windows will all be turned to uppercase.
23 * - PATH accepts both ; and : as separator, but can't be mixed
24 * - command without ".exe" extension is still understood as executable
25 * - shell scripts on the path are detected by the presence of '#!'
26 * - both / and \ are supported in PATH. Usually you must use /
27 * - job control doesn't work, though the jobs builtin is available
28 * - trap doesn't work for signals, only EXIT
29 * - /dev/null is supported for redirection
30 */
31
18//config:config SHELL_ASH 32//config:config SHELL_ASH
19//config: bool #hidden option 33//config: bool #hidden option
20//config: depends on !NOMMU 34//config: depends on !NOMMU
@@ -170,11 +184,36 @@
170//config: you to run the specified command or builtin, 184//config: you to run the specified command or builtin,
171//config: even when there is a function with the same name. 185//config: even when there is a function with the same name.
172//config: 186//config:
187//config:
188//config:config ASH_NOCONSOLE
189//config: bool "'noconsole' option"
190//config: default y
191//config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32
192//config: help
193//config: Enable support for the 'noconsole' option, which attempts to
194//config: conceal the console normally associated with a command line
195//config: application. This may be useful when running a shell script
196//config: from a GUI application. Also the 'noiconify' option, which
197//config: controls whether the console is iconified or hidden.
198//config:
199//config:config ASH_GLOB_OPTIONS
200//config: bool "Globbing options"
201//config: default y
202//config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32
203//config: help
204//config: Enable support for options to control globbing:
205//config: - 'nocaseglob' allows case-insensitive filename globbing
206//config: - 'nohiddenglob' allows hidden files to be omitted from globbing
207//config: - 'nohidsysglob' allows hidden system files to be omitted
208//config:
173//config:endif # ash options 209//config:endif # ash options
174 210
175//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) 211//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
176// APPLET_ODDNAME:name main location suid_type help 212// APPLET_ODDNAME:name main location suid_type help
177//applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) 213//applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
214//applet:IF_PLATFORM_MINGW32(
215//applet:IF_SH_IS_ASH( APPLET_ODDNAME(lash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
216//applet:)
178//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) 217//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
179 218
180//kbuild:lib-$(CONFIG_SHELL_ASH) += ash.o ash_ptr_hack.o shell_common.o 219//kbuild:lib-$(CONFIG_SHELL_ASH) += ash.o ash_ptr_hack.o shell_common.o
@@ -195,7 +234,17 @@
195 234
196#define PROFILE 0 235#define PROFILE 0
197 236
237/*
238 * Only one of JOBS or JOBS_WIN32 is enabled at a time (or neither).
239 * JOBS_WIN32 doesn't enable job control, just some job-related features.
240 */
241#if ENABLE_PLATFORM_MINGW32
242#define JOBS_WIN32 ENABLE_ASH_JOB_CONTROL
243#define JOBS 0
244#else
245#define JOBS_WIN32 0
198#define JOBS ENABLE_ASH_JOB_CONTROL 246#define JOBS ENABLE_ASH_JOB_CONTROL
247#endif
199 248
200#include <fnmatch.h> 249#include <fnmatch.h>
201#include <sys/times.h> 250#include <sys/times.h>
@@ -206,6 +255,10 @@
206#else 255#else
207# define NUM_SCRIPTS 0 256# define NUM_SCRIPTS 0
208#endif 257#endif
258#if ENABLE_PLATFORM_MINGW32
259# include <conio.h>
260# include "lazyload.h"
261#endif
209 262
210/* So far, all bash compat is controlled by one config option */ 263/* So far, all bash compat is controlled by one config option */
211/* Separate defines document which part of code implements what */ 264/* Separate defines document which part of code implements what */
@@ -316,10 +369,89 @@ typedef long arith_t;
316# define unlikely(cond) (cond) 369# define unlikely(cond) (cond)
317#endif 370#endif
318 371
372#if !ENABLE_PLATFORM_MINGW32
373# define is_relative_path(path) ((path)[0] != '/')
374#endif
375
319#if !BB_MMU 376#if !BB_MMU
320# error "Do not even bother, ash will not run on NOMMU machine" 377# error "Do not even bother, ash will not run on NOMMU machine"
321#endif 378#endif
322 379
380#if ENABLE_PLATFORM_MINGW32
381# define FORKSHELL_DEBUG 0
382
383union node;
384struct strlist;
385struct job;
386
387struct forkshell {
388 /* filled by forkshell_copy() */
389 struct globals_var *gvp;
390 struct globals_misc *gmp;
391 struct tblentry **cmdtable;
392#if ENABLE_ASH_ALIAS
393 struct alias **atab;
394#endif
395#if MAX_HISTORY
396 char **history;
397 int cnt_history;
398#endif
399#if JOBS_WIN32
400 struct job *jobtab;
401 unsigned njobs;
402 struct job *curjob;
403#endif
404 /* struct parsefile *g_parsefile; */
405 HANDLE hMapFile;
406 char *old_base;
407 int size;
408# if FORKSHELL_DEBUG
409 int funcblocksize;
410 int funcstringsize;
411# endif
412 int relocatesize;
413
414 /* type of forkshell */
415 int fpid;
416
417 /* generic data, used by forkshell_child */
418 int mode;
419 int nprocs;
420#if JOBS_WIN32
421 int jpnull;
422#endif
423
424 /* optional data, used by forkshell_child */
425 int flags;
426 int fd[3];
427 union node *n;
428 char **argv;
429 char *path;
430};
431
432enum {
433 FS_OPENHERE,
434 FS_EVALBACKCMD,
435 FS_EVALSUBSHELL,
436 FS_EVALPIPE,
437 FS_SHELLEXEC
438};
439
440static struct forkshell* forkshell_prepare(struct forkshell *fs);
441static void forkshell_init(const char *idstr);
442static void *sticky_mem_start, *sticky_mem_end;
443static void sticky_free(void *p);
444# define free(p) sticky_free(p)
445#if !JOBS && !JOBS_WIN32
446#define spawn_forkshell(fs, jp, n, mode) spawn_forkshell(fs, jp, mode)
447#endif
448static void spawn_forkshell(struct forkshell *fs, struct job *jp,
449 union node *n, int mode);
450# if FORKSHELL_DEBUG
451static void forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes);
452# endif
453#endif
454
323/* ============ Hash table sizes. Configurable. */ 455/* ============ Hash table sizes. Configurable. */
324 456
325#define VTABSIZE 39 457#define VTABSIZE 39
@@ -347,7 +479,11 @@ static const char *const optletters_optnames[] ALIGN_PTR = {
347 "m" "monitor", 479 "m" "monitor",
348 "n" "noexec", 480 "n" "noexec",
349/* Ditto: bash has no "set -s", "set -c" */ 481/* Ditto: bash has no "set -s", "set -c" */
482#if !ENABLE_PLATFORM_MINGW32
350 "s" "", 483 "s" "",
484#else
485 "s" "stdin",
486#endif
351 "c" "", 487 "c" "",
352 "x" "xtrace", 488 "x" "xtrace",
353 "v" "verbose", 489 "v" "verbose",
@@ -364,6 +500,18 @@ static const char *const optletters_optnames[] ALIGN_PTR = {
364 ,"\0" "nolog" 500 ,"\0" "nolog"
365 ,"\0" "debug" 501 ,"\0" "debug"
366#endif 502#endif
503#if ENABLE_PLATFORM_MINGW32
504 ,"X" "winxp"
505#endif
506#if ENABLE_ASH_NOCONSOLE
507 ,"\0" "noconsole"
508 ,"\0" "noiconify"
509#endif
510#if ENABLE_ASH_GLOB_OPTIONS
511 ,"\0" "nocaseglob"
512 ,"\0" "nohiddenglob"
513 ,"\0" "nohidsysglob"
514#endif
367}; 515};
368//bash 4.4.23 also has these opts (with these defaults): 516//bash 4.4.23 also has these opts (with these defaults):
369//braceexpand on 517//braceexpand on
@@ -406,21 +554,36 @@ struct jmploc {
406struct globals_misc { 554struct globals_misc {
407 uint8_t exitstatus; /* exit status of last command */ 555 uint8_t exitstatus; /* exit status of last command */
408 uint8_t back_exitstatus;/* exit status of backquoted command */ 556 uint8_t back_exitstatus;/* exit status of backquoted command */
557#if !ENABLE_PLATFORM_MINGW32
409 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ 558 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
559#endif
410 smallint inps4; /* Prevent PS4 nesting. */ 560 smallint inps4; /* Prevent PS4 nesting. */
411 int savestatus; /* exit status of last command outside traps */ 561 int savestatus; /* exit status of last command outside traps */
412 int rootpid; /* pid of main shell */ 562 int rootpid; /* pid of main shell */
413 /* shell level: 0 for the main shell, 1 for its children, and so on */ 563 /* shell level: 0 for the main shell, 1 for its children, and so on */
414 int shlvl; 564 int shlvl;
565#if ENABLE_PLATFORM_MINGW32
566 int loopnest; /* current loop nesting level */
567#endif
415#define rootshell (!shlvl) 568#define rootshell (!shlvl)
416 int errlinno; 569 int errlinno;
417 570
418 char *minusc; /* argument to -c option */ 571 char *minusc; /* argument to -c option */
572#if ENABLE_PLATFORM_MINGW32
573 char *dirarg; /* argument to -d option */
574 char *title; /* argument to -t option */
575#if ENABLE_SUW32
576 int delayexit; /* set by -N option */
577# endif
578#endif
419 579
420 char *curdir; // = nullstr; /* current working directory */ 580 char *curdir; // = nullstr; /* current working directory */
421 char *physdir; // = nullstr; /* physical working directory */ 581 char *physdir; // = nullstr; /* physical working directory */
422 582
423 char *arg0; /* value of $0 */ 583 char *arg0; /* value of $0 */
584#if ENABLE_PLATFORM_MINGW32
585 char *commandname;
586#endif
424 587
425 struct jmploc *exception_handler; 588 struct jmploc *exception_handler;
426 589
@@ -431,8 +594,10 @@ struct globals_misc {
431 * but we do read it async. 594 * but we do read it async.
432 */ 595 */
433 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ 596 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
597#if !ENABLE_PLATFORM_MINGW32
434 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ 598 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
435 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ 599 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
600#endif
436 smallint exception_type; /* kind of exception: */ 601 smallint exception_type; /* kind of exception: */
437#define EXINT 0 /* SIGINT received */ 602#define EXINT 0 /* SIGINT received */
438#define EXERROR 1 /* a generic error */ 603#define EXERROR 1 /* a generic error */
@@ -467,8 +632,21 @@ struct globals_misc {
467# define nolog optlist[16 + BASH_PIPEFAIL] 632# define nolog optlist[16 + BASH_PIPEFAIL]
468# define debug optlist[17 + BASH_PIPEFAIL] 633# define debug optlist[17 + BASH_PIPEFAIL]
469#endif 634#endif
635#if ENABLE_PLATFORM_MINGW32
636# define winxp optlist[16 + BASH_PIPEFAIL + 2*(DEBUG != 0)]
637# if ENABLE_ASH_NOCONSOLE
638# define noconsole optlist[17 + BASH_PIPEFAIL + 2*(DEBUG != 0)]
639# define noiconify optlist[18 + BASH_PIPEFAIL + 2*(DEBUG != 0)]
640# endif
641# if ENABLE_ASH_GLOB_OPTIONS
642# define nocaseglob optlist[17 + BASH_PIPEFAIL + 2*(DEBUG != 0) + 2*ENABLE_ASH_NOCONSOLE]
643# define nohiddenglob optlist[18 + BASH_PIPEFAIL + 2*(DEBUG != 0) + 2*ENABLE_ASH_NOCONSOLE]
644# define nohidsysglob optlist[19 + BASH_PIPEFAIL + 2*(DEBUG != 0) + 2*ENABLE_ASH_NOCONSOLE]
645# endif
646#endif
470 647
471 /* trap handler commands */ 648 /* trap handler commands */
649#if !ENABLE_PLATFORM_MINGW32
472 /* 650 /*
473 * Sigmode records the current value of the signal handlers for the various 651 * Sigmode records the current value of the signal handlers for the various
474 * modes. A value of zero means that the current handler is not known. 652 * modes. A value of zero means that the current handler is not known.
@@ -482,6 +660,7 @@ struct globals_misc {
482 660
483 /* indicates specified signal received */ 661 /* indicates specified signal received */
484 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ 662 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
663#endif
485 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ 664 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
486 char *trap[NSIG + 1]; 665 char *trap[NSIG + 1];
487/* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */ 666/* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */
@@ -510,10 +689,21 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
510#define rootpid (G_misc.rootpid ) 689#define rootpid (G_misc.rootpid )
511#define shlvl (G_misc.shlvl ) 690#define shlvl (G_misc.shlvl )
512#define errlinno (G_misc.errlinno ) 691#define errlinno (G_misc.errlinno )
692#if ENABLE_PLATFORM_MINGW32
693#define loopnest (G_misc.loopnest )
694#endif
513#define minusc (G_misc.minusc ) 695#define minusc (G_misc.minusc )
696#if ENABLE_PLATFORM_MINGW32
697#define dirarg (G_misc.dirarg )
698#define title (G_misc.title )
699#define delayexit (G_misc.delayexit )
700#endif
514#define curdir (G_misc.curdir ) 701#define curdir (G_misc.curdir )
515#define physdir (G_misc.physdir ) 702#define physdir (G_misc.physdir )
516#define arg0 (G_misc.arg0 ) 703#define arg0 (G_misc.arg0 )
704#if ENABLE_PLATFORM_MINGW32
705#define commandname (G_misc.commandname)
706#endif
517#define exception_handler (G_misc.exception_handler) 707#define exception_handler (G_misc.exception_handler)
518#define exception_type (G_misc.exception_type ) 708#define exception_type (G_misc.exception_type )
519#define suppress_int (G_misc.suppress_int ) 709#define suppress_int (G_misc.suppress_int )
@@ -530,6 +720,13 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
530#define groupinfo (G_misc.groupinfo ) 720#define groupinfo (G_misc.groupinfo )
531#define random_gen (G_misc.random_gen ) 721#define random_gen (G_misc.random_gen )
532#define backgndpid (G_misc.backgndpid ) 722#define backgndpid (G_misc.backgndpid )
723
724#if ENABLE_PLATFORM_MINGW32
725#undef got_sigchld
726#undef pending_sig
727#define pending_sig (0)
728#endif
729
533#define INIT_G_misc() do { \ 730#define INIT_G_misc() do { \
534 XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \ 731 XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \
535 savestatus = -1; \ 732 savestatus = -1; \
@@ -547,6 +744,9 @@ static void trace_printf(const char *fmt, ...);
547static void trace_vprintf(const char *fmt, va_list va); 744static void trace_vprintf(const char *fmt, va_list va);
548# define TRACE(param) trace_printf param 745# define TRACE(param) trace_printf param
549# define TRACEV(param) trace_vprintf param 746# define TRACEV(param) trace_vprintf param
747# if ENABLE_PLATFORM_MINGW32 && defined(close)
748# undef close
749# endif
550# define close(fd) do { \ 750# define close(fd) do { \
551 int dfd = (fd); \ 751 int dfd = (fd); \
552 if (close(dfd) < 0) \ 752 if (close(dfd) < 0) \
@@ -635,11 +835,18 @@ struct parsefile {
635 835
636 /* Number of outstanding calls to pungetc. */ 836 /* Number of outstanding calls to pungetc. */
637 int unget; 837 int unget;
838
839#if ENABLE_PLATFORM_MINGW32
840 /* True if a trailing CR from a previous read was left unprocessed. */
841 int cr;
842#endif
638}; 843};
639 844
640static struct parsefile basepf; /* top level input file */ 845static struct parsefile basepf; /* top level input file */
641static struct parsefile *g_parsefile = &basepf; /* current input file */ 846static struct parsefile *g_parsefile = &basepf; /* current input file */
847#if ENABLE_PLATFORM_POSIX
642static char *commandname; /* currently executing command */ 848static char *commandname; /* currently executing command */
849#endif
643 850
644 851
645/* ============ Interrupts / exceptions */ 852/* ============ Interrupts / exceptions */
@@ -696,21 +903,39 @@ raise_exception(int e)
696 * are held using the INT_OFF macro. (The test for iflag is just 903 * are held using the INT_OFF macro. (The test for iflag is just
697 * defensive programming.) 904 * defensive programming.)
698 */ 905 */
699static void raise_interrupt(void) NORETURN; 906static void raise_interrupt(void) IF_NOT_PLATFORM_MINGW32(NORETURN);
700static void 907static void
701raise_interrupt(void) 908raise_interrupt(void)
702{ 909{
910#if ENABLE_PLATFORM_MINGW32
911 /* Contrary to the comment above on Windows raise_interrupt() is
912 * called when SIGINT is trapped or ignored. We detect this here
913 * and return without doing anything. */
914 if (trap[SIGINT])
915 return;
916#endif
703 pending_int = 0; 917 pending_int = 0;
918#if !ENABLE_PLATFORM_MINGW32
704 /* Signal is not automatically unmasked after it is raised, 919 /* Signal is not automatically unmasked after it is raised,
705 * do it ourself - unmask all signals */ 920 * do it ourself - unmask all signals */
706 sigprocmask_allsigs(SIG_UNBLOCK); 921 sigprocmask_allsigs(SIG_UNBLOCK);
922#endif
707 /* pending_sig = 0; - now done in signal_handler() */ 923 /* pending_sig = 0; - now done in signal_handler() */
708 924
709 if (!(rootshell && iflag)) { 925 if (!(rootshell && iflag)) {
926#if !ENABLE_PLATFORM_MINGW32
710 /* Kill ourself with SIGINT */ 927 /* Kill ourself with SIGINT */
711 signal(SIGINT, SIG_DFL); 928 signal(SIGINT, SIG_DFL);
712 raise(SIGINT); 929 raise(SIGINT);
930#else
931 fflush_all();
932 _exit(SIGINT << 24);
933#endif
713 } 934 }
935#if ENABLE_PLATFORM_MINGW32
936 if (iflag)
937 write(STDOUT_FILENO, "^C", 2);
938#endif
714 /* bash: ^C even on empty command line sets $? */ 939 /* bash: ^C even on empty command line sets $? */
715 exitstatus = SIGINT + 128; 940 exitstatus = SIGINT + 128;
716 raise_exception(EXINT); 941 raise_exception(EXINT);
@@ -1998,6 +2223,18 @@ maybe_single_quote(const char *s)
1998 return single_quote(s); 2223 return single_quote(s);
1999} 2224}
2000 2225
2226#if ENABLE_PLATFORM_MINGW32
2227/* Copy path to a string on the stack long enough to allow a file extension
2228 * to be added. */
2229static char *
2230stack_add_ext_space(const char *path)
2231{
2232 char *p = growstackto(strlen(path) + 5);
2233 strcpy(p, path);
2234 return p;
2235}
2236#endif
2237
2001 2238
2002/* ============ nextopt */ 2239/* ============ nextopt */
2003 2240
@@ -2120,6 +2357,9 @@ struct localvar {
2120#else 2357#else
2121# define VDYNAMIC 0 2358# define VDYNAMIC 0
2122#endif 2359#endif
2360#if ENABLE_PLATFORM_MINGW32
2361# define VIMPORT 0x400 /* variable was imported from environment */
2362#endif
2123 2363
2124 2364
2125/* Need to be before varinit_data[] */ 2365/* Need to be before varinit_data[] */
@@ -2149,6 +2389,24 @@ static void change_seconds(const char *) FAST_FUNC;
2149static void change_realtime(const char *) FAST_FUNC; 2389static void change_realtime(const char *) FAST_FUNC;
2150#endif 2390#endif
2151 2391
2392#if ENABLE_PLATFORM_MINGW32
2393static void FAST_FUNC
2394change_terminal_mode(const char *newval UNUSED_PARAM)
2395{
2396 terminal_mode(TRUE);
2397}
2398
2399static void clearcmdentry(void);
2400static void FAST_FUNC
2401change_override_applets(const char *newval UNUSED_PARAM)
2402{
2403 clearcmdentry();
2404}
2405
2406# define LINENO_INDEX (5 + 2 * ENABLE_ASH_MAIL + ENABLE_ASH_GETOPTS)
2407# define FUNCNAME_INDEX (LINENO_INDEX + 1)
2408#endif
2409
2152static const struct { 2410static const struct {
2153 int flags; 2411 int flags;
2154 const char *var_text; 2412 const char *var_text;
@@ -2186,6 +2444,12 @@ static const struct {
2186#if ENABLE_FEATURE_EDITING_SAVEHISTORY 2444#if ENABLE_FEATURE_EDITING_SAVEHISTORY
2187 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, 2445 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
2188#endif 2446#endif
2447#if ENABLE_PLATFORM_MINGW32
2448 { VSTRFIXED|VTEXTFIXED|VUNSET, BB_SKIP_ANSI_EMULATION, change_terminal_mode },
2449 { VSTRFIXED|VTEXTFIXED|VUNSET, BB_TERMINAL_MODE, change_terminal_mode },
2450 { VSTRFIXED|VTEXTFIXED|VUNSET, BB_OVERRIDE_APPLETS, change_override_applets },
2451 { VSTRFIXED|VTEXTFIXED|VUNSET, BB_CRITICAL_ERROR_DIALOGS, change_critical_error_dialogs },
2452#endif
2189}; 2453};
2190 2454
2191struct redirtab; 2455struct redirtab;
@@ -2409,6 +2673,65 @@ bltinlookup(const char *name)
2409 return lookupvar(name); 2673 return lookupvar(name);
2410} 2674}
2411 2675
2676#if ENABLE_PLATFORM_MINGW32
2677static char *
2678fix_pathvar(const char *path, int len)
2679{
2680 char *newpath = xstrdup(path);
2681 char *p;
2682 int modified = FALSE;
2683
2684 p = newpath + len;
2685 while (*p) {
2686 if (*p != ':' && *p != ';') {
2687 /* skip drive */
2688 if (isalpha(*p) && p[1] == ':')
2689 p += 2;
2690 /* skip through path component */
2691 for (; *p != '\0' && *p != ':' && *p != ';'; ++p)
2692 continue;
2693 }
2694 /* *p is ':', ';' or '\0' here */
2695 if (*p == ':') {
2696 *p++ = ';';
2697 modified = TRUE;
2698 }
2699 else if (*p == ';') {
2700 ++p;
2701 }
2702 }
2703
2704 if (!modified) {
2705 free(newpath);
2706 newpath = NULL;
2707 }
2708 return newpath;
2709}
2710
2711#define BB_VAR_EXACT 1 /* exact match for name */
2712#define BB_VAR_ASSIGN -1 /* matches name followed by '=' */
2713
2714/* Match variables that should be placed in the environment immediately
2715 * they're exported and removed immediately they're no longer exported */
2716static int
2717is_bb_var(const char *s)
2718{
2719 const char *p;
2720 int len;
2721
2722 for (p = bbvar; *p; p += len + 1) {
2723 len = strlen(p);
2724 if (strncmp(s, p, len) == 0) {
2725 if (s[len] == '\0')
2726 return BB_VAR_EXACT;
2727 else if (s[len] == '=')
2728 return BB_VAR_ASSIGN;
2729 }
2730 }
2731 return FALSE;
2732}
2733#endif
2734
2412/* 2735/*
2413 * Same as setvar except that the variable and value are passed in 2736 * Same as setvar except that the variable and value are passed in
2414 * the first argument as name=value. Since the first argument will 2737 * the first argument as name=value. Since the first argument will
@@ -2420,6 +2743,26 @@ static struct var *
2420setvareq(char *s, int flags) 2743setvareq(char *s, int flags)
2421{ 2744{
2422 struct var *vp, **vpp; 2745 struct var *vp, **vpp;
2746#if ENABLE_PLATFORM_MINGW32
2747 const char *paths = "PATH=\0""CDPATH=\0""MANPATH=\0";
2748 const char *p;
2749 int len;
2750
2751 for (p = paths; *p; p += len + 1) {
2752 len = strlen(p);
2753 if (strncmp(s, p, len) == 0) {
2754 char *newpath = fix_pathvar(s, len);
2755 if (newpath) {
2756 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2757 free(s);
2758 flags |= VNOSAVE;
2759 flags &= ~(VTEXTFIXED|VSTACK);
2760 s = newpath;
2761 }
2762 break;
2763 }
2764 }
2765#endif
2423 2766
2424 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); 2767 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2425 vpp = findvar(s); 2768 vpp = findvar(s);
@@ -2444,6 +2787,11 @@ setvareq(char *s, int flags)
2444 if (!(vp->flags & (VTEXTFIXED|VSTACK))) 2787 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2445 free((char*)vp->var_text); 2788 free((char*)vp->var_text);
2446 2789
2790#if ENABLE_PLATFORM_MINGW32
2791 if ((flags & VUNSET) && (vp->flags & VEXPORT) &&
2792 is_bb_var(s) == BB_VAR_EXACT)
2793 unsetenv(s);
2794#endif
2447 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) { 2795 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2448 *vpp = vp->next; 2796 *vpp = vp->next;
2449 free(vp); 2797 free(vp);
@@ -2473,6 +2821,10 @@ setvareq(char *s, int flags)
2473 s = ckstrdup(s); 2821 s = ckstrdup(s);
2474 vp->var_text = s; 2822 vp->var_text = s;
2475 vp->flags = flags; 2823 vp->flags = flags;
2824#if ENABLE_PLATFORM_MINGW32
2825 if ((flags & VEXPORT) && is_bb_var(s) == BB_VAR_ASSIGN)
2826 putenv(s);
2827#endif
2476 2828
2477 out: 2829 out:
2478 return vp; 2830 return vp;
@@ -2594,6 +2946,65 @@ listvars(int on, int off, struct strlist *lp, char ***end)
2594 return grabstackstr(ep); 2946 return grabstackstr(ep);
2595} 2947}
2596 2948
2949#if ENABLE_PLATFORM_MINGW32
2950/* Adjust directory separator in variables imported from the environment */
2951static void
2952setwinxp(int on)
2953{
2954 static smallint is_winxp = 1;
2955 struct var **vpp;
2956 struct var *vp;
2957
2958 if (on == is_winxp)
2959 return;
2960 is_winxp = on;
2961
2962 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
2963 for (vp = *vpp; vp; vp = vp->next) {
2964 if ((vp->flags & VIMPORT)) {
2965 char *end = strchr(vp->var_text, '=');
2966 if (!end || is_prefixed_with(vp->var_text, "COMSPEC=") ||
2967 is_prefixed_with(vp->var_text, "SYSTEMROOT="))
2968 continue;
2969 if (!on)
2970 bs_to_slash(end + 1);
2971 else
2972 slash_to_bs(end + 1);
2973 }
2974 }
2975 }
2976}
2977
2978# if ENABLE_ASH_NOCONSOLE
2979/*
2980 * Console state is either:
2981 * 0 normal
2982 * 1 iconified/hidden
2983 * 2 unknown
2984 */
2985static int console_state(void)
2986{
2987 DECLARE_PROC_ADDR(BOOL, ShowWindow, HWND, int);
2988
2989 if (INIT_PROC_ADDR(user32.dll, ShowWindow)) {
2990 BOOL visible = IsWindowVisible(GetConsoleWindow());
2991 BOOL iconified = IsIconic(GetConsoleWindow());
2992
2993 return !visible || iconified;
2994 }
2995 return 2;
2996}
2997
2998static void hide_console(int hide)
2999{
3000 // Switch console state if it's known and isn't the required state
3001 if (console_state() == !hide)
3002 ShowWindow(GetConsoleWindow(), hide ?
3003 (noiconify ? SW_HIDE : SW_MINIMIZE) : SW_NORMAL);
3004}
3005# endif
3006#endif
3007
2597 3008
2598/* ============ Path search helper */ 3009/* ============ Path search helper */
2599static const char * 3010static const char *
@@ -2637,7 +3048,7 @@ static const char *pathopt; /* set by padvance */
2637static int 3048static int
2638padvance_magic(const char **path, const char *name, int magic) 3049padvance_magic(const char **path, const char *name, int magic)
2639{ 3050{
2640 const char *term = "%:"; 3051 const char *term = "%"PATH_SEP_STR;
2641 const char *lpathopt; 3052 const char *lpathopt;
2642 const char *p; 3053 const char *p;
2643 char *q; 3054 char *q;
@@ -2654,14 +3065,14 @@ padvance_magic(const char **path, const char *name, int magic)
2654 if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) { 3065 if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) {
2655 lpathopt = start + 1; 3066 lpathopt = start + 1;
2656 start = p; 3067 start = p;
2657 term = ":"; 3068 term = PATH_SEP_STR;
2658 } 3069 }
2659 3070
2660 len = strcspn(start, term); 3071 len = strcspn(start, term);
2661 p = start + len; 3072 p = start + len;
2662 3073
2663 if (*p == '%') { 3074 if (*p == '%') {
2664 size_t extra = strchrnul(p, ':') - p; 3075 size_t extra = strchrnul(p, PATH_SEP) - p;
2665 3076
2666 if (legal_pathopt(p + 1, term, magic)) 3077 if (legal_pathopt(p + 1, term, magic))
2667 lpathopt = p + 1; 3078 lpathopt = p + 1;
@@ -2672,14 +3083,18 @@ padvance_magic(const char **path, const char *name, int magic)
2672 } 3083 }
2673 3084
2674 pathopt = lpathopt; 3085 pathopt = lpathopt;
2675 *path = *p == ':' ? p + 1 : NULL; 3086 *path = *p == PATH_SEP ? p + 1 : NULL;
2676 3087
2677 /* "2" is for '/' and '\0' */ 3088 /* "2" is for '/' and '\0' */
2678 qlen = len + strlen(name) + 2; 3089 /* reserve space for suffix on WIN32 */
3090 qlen = len + strlen(name) + 2 IF_PLATFORM_MINGW32(+ 4);
2679 q = growstackto(qlen); 3091 q = growstackto(qlen);
2680 3092
2681 if (len) { 3093 if (len) {
2682 q = mempcpy(q, start, len); 3094 q = mempcpy(q, start, len);
3095#if ENABLE_PLATFORM_MINGW32
3096 if (q[-1] != '/' && q[-1] != '\\')
3097#endif
2683 *q++ = '/'; 3098 *q++ = '/';
2684 } 3099 }
2685 strcpy(q, name); 3100 strcpy(q, name);
@@ -2770,6 +3185,7 @@ setprompt_if(smallint do_set, int whichprompt)
2770 3185
2771#define CD_PHYSICAL 1 3186#define CD_PHYSICAL 1
2772#define CD_PRINT 2 3187#define CD_PRINT 2
3188#define CD_PRINT_ALL 4
2773 3189
2774static int 3190static int
2775cdopt(void) 3191cdopt(void)
@@ -2778,7 +3194,14 @@ cdopt(void)
2778 int i, j; 3194 int i, j;
2779 3195
2780 j = 'L'; 3196 j = 'L';
3197#if ENABLE_PLATFORM_MINGW32
3198 while ((i = nextopt("LPa")) != '\0') {
3199 if (i == 'a')
3200 flags |= CD_PRINT_ALL;
3201 else
3202#else
2781 while ((i = nextopt("LP")) != '\0') { 3203 while ((i = nextopt("LP")) != '\0') {
3204#endif
2782 if (i != j) { 3205 if (i != j) {
2783 flags ^= CD_PHYSICAL; 3206 flags ^= CD_PHYSICAL;
2784 j = i; 3207 j = i;
@@ -2795,6 +3218,130 @@ cdopt(void)
2795static const char * 3218static const char *
2796updatepwd(const char *dir) 3219updatepwd(const char *dir)
2797{ 3220{
3221#if ENABLE_PLATFORM_MINGW32
3222 /*
3223 * Due to Windows drive notion, getting pwd is a completely
3224 * different thing. Handle it in a separate routine
3225 */
3226
3227 char *new;
3228 char *p;
3229 char *cdcomppath;
3230 const char *lim;
3231 int len;
3232 char buffer[PATH_MAX];
3233 /*
3234 * There are five cases that make some kind of sense
3235 *
3236 * Absolute paths:
3237 * c:/path
3238 * //host/share
3239 *
3240 * Relative to current working directory of other drive:
3241 * c:path
3242 *
3243 * Relative to current root (drive/share):
3244 * /path
3245 *
3246 * Relative to current working directory of current root (drive/share):
3247 * path
3248 */
3249 enum {ABS_DRIVE, ABS_SHARE, REL_OTHER, REL_ROOT, REL_CWD} target;
3250
3251 /* skip multiple leading separators unless dir is a UNC path */
3252 if (is_dir_sep(*dir) && unc_root_len(dir) == 0) {
3253 while (is_dir_sep(dir[1]))
3254 ++dir;
3255 }
3256
3257 len = strlen(dir);
3258 if (len >= 2 && has_dos_drive_prefix(dir))
3259 target = len >= 3 && is_dir_sep(dir[2]) ? ABS_DRIVE : REL_OTHER;
3260 else if (unc_root_len(dir) != 0)
3261 target = ABS_SHARE;
3262 else if (is_dir_sep(*dir))
3263 target = REL_ROOT;
3264 else
3265 target = REL_CWD;
3266
3267 cdcomppath = sstrdup(dir);
3268 STARTSTACKSTR(new);
3269
3270 switch (target) {
3271 case REL_OTHER:
3272 /* c:path */
3273 if (get_drive_cwd(dir, buffer, PATH_MAX) == NULL)
3274 return 0;
3275 new = stack_putstr(buffer, new);
3276 len = 2;
3277 cdcomppath += len;
3278 dir += len;
3279 break;
3280 case REL_CWD:
3281 case REL_ROOT:
3282 /* path or /path */
3283 len = root_len(curdir);
3284 if (len == 0)
3285 return 0;
3286 new = target == REL_CWD ? stack_putstr(curdir, new) :
3287 stnputs(curdir, len, new);
3288 break;
3289 default:
3290 /* //host/share or c:/path */
3291 len = root_len(dir);
3292 if (len == 0)
3293 return 0;
3294 new = stnputs(dir, len, new);
3295 cdcomppath += len;
3296 dir += len;
3297 break;
3298 }
3299
3300 new = makestrspace(strlen(dir) + 2, new);
3301 lim = (char *)stackblock() + len + 1;
3302
3303 if (!is_dir_sep(*dir)) {
3304 if (!is_dir_sep(new[-1]))
3305 USTPUTC('/', new);
3306 if (new > lim && is_dir_sep(*lim))
3307 lim++;
3308 } else {
3309 USTPUTC('/', new);
3310 cdcomppath++;
3311 if (is_dir_sep(dir[1]) && !is_dir_sep(dir[2])) {
3312 USTPUTC('/', new);
3313 cdcomppath++;
3314 lim++;
3315 }
3316 }
3317 p = strtok(cdcomppath, "/\\");
3318 while (p) {
3319 switch (*p) {
3320 case '.':
3321 if (p[1] == '.' && p[2] == '\0') {
3322 while (new > lim) {
3323 STUNPUTC(new);
3324 if (is_dir_sep(new[-1]))
3325 break;
3326 }
3327 break;
3328 }
3329 if (p[1] == '\0')
3330 break;
3331 /* fall through */
3332 default:
3333 new = stack_putstr(p, new);
3334 USTPUTC('/', new);
3335 }
3336 p = strtok(NULL, "/\\");
3337 }
3338 if (new > lim)
3339 STUNPUTC(new);
3340 *new = 0;
3341 strip_dot_space((char *)stackblock());
3342 fix_path_case((char *)stackblock());
3343 return bs_to_slash((char *)stackblock());
3344#else
2798 char *new; 3345 char *new;
2799 char *p; 3346 char *p;
2800 char *cdcomppath; 3347 char *cdcomppath;
@@ -2848,6 +3395,7 @@ updatepwd(const char *dir)
2848 STUNPUTC(new); 3395 STUNPUTC(new);
2849 *new = 0; 3396 *new = 0;
2850 return stackblock(); 3397 return stackblock();
3398#endif
2851} 3399}
2852 3400
2853/* 3401/*
@@ -2943,7 +3491,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2943 } 3491 }
2944 if (!dest) 3492 if (!dest)
2945 dest = nullstr; 3493 dest = nullstr;
2946 if (*dest == '/') 3494 if (!is_relative_path(dest))
2947 goto step6; 3495 goto step6;
2948 if (*dest == '.') { 3496 if (*dest == '.') {
2949 c = dest[1]; 3497 c = dest[1];
@@ -2966,7 +3514,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2966 p = stalloc(len); 3514 p = stalloc(len);
2967 3515
2968 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { 3516 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2969 if (c && c != ':') 3517 if (c && c != PATH_SEP)
2970 flags |= CD_PRINT; 3518 flags |= CD_PRINT;
2971 docd: 3519 docd:
2972 if (!docd(p, flags)) 3520 if (!docd(p, flags))
@@ -2988,6 +3536,26 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2988 return 0; 3536 return 0;
2989} 3537}
2990 3538
3539#if ENABLE_PLATFORM_MINGW32
3540static void
3541print_all_cwd(void)
3542{
3543 FILE *mnt;
3544 struct mntent *entry;
3545 char buffer[PATH_MAX];
3546
3547 mnt = setmntent(bb_path_mtab_file, "r");
3548 if (mnt) {
3549 while ((entry=getmntent(mnt)) != NULL) {
3550 entry->mnt_dir[2] = '\0';
3551 if (get_drive_cwd(entry->mnt_dir, buffer, PATH_MAX) != NULL)
3552 out1fmt("%s\n", buffer);
3553 }
3554 endmntent(mnt);
3555 }
3556}
3557#endif
3558
2991static int FAST_FUNC 3559static int FAST_FUNC
2992pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 3560pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2993{ 3561{
@@ -2995,6 +3563,12 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2995 const char *dir = curdir; 3563 const char *dir = curdir;
2996 3564
2997 flags = cdopt(); 3565 flags = cdopt();
3566#if ENABLE_PLATFORM_MINGW32
3567 if (flags & CD_PRINT_ALL) {
3568 print_all_cwd();
3569 return 0;
3570 }
3571#endif
2998 if (flags) { 3572 if (flags) {
2999 if (physdir == nullstr) 3573 if (physdir == nullstr)
3000 setpwd(dir, 0); 3574 setpwd(dir, 0);
@@ -3623,7 +4197,12 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3623struct procstat { 4197struct procstat {
3624 pid_t ps_pid; /* process id */ 4198 pid_t ps_pid; /* process id */
3625 int ps_status; /* last process status from wait() */ 4199 int ps_status; /* last process status from wait() */
4200#if ENABLE_PLATFORM_POSIX || JOBS_WIN32
3626 char *ps_cmd; /* text of command being run */ 4201 char *ps_cmd; /* text of command being run */
4202#endif
4203#if ENABLE_PLATFORM_MINGW32
4204 HANDLE ps_proc;
4205#endif
3627}; 4206};
3628 4207
3629struct job { 4208struct job {
@@ -3639,8 +4218,10 @@ struct job {
3639#define JOBDONE 2 /* all procs are completed */ 4218#define JOBDONE 2 /* all procs are completed */
3640 unsigned 4219 unsigned
3641 state: 8, 4220 state: 8,
3642#if JOBS 4221#if JOBS || ENABLE_PLATFORM_MINGW32
3643 sigint: 1, /* job was killed by SIGINT */ 4222 sigint: 1, /* job was killed by SIGINT */
4223#endif
4224#if JOBS
3644 jobctl: 1, /* job running under job control */ 4225 jobctl: 1, /* job running under job control */
3645#endif 4226#endif
3646 waited: 1, /* true if this entry has been waited for */ 4227 waited: 1, /* true if this entry has been waited for */
@@ -3650,17 +4231,23 @@ struct job {
3650}; 4231};
3651 4232
3652static struct job *makejob(/*union node *,*/ int); 4233static struct job *makejob(/*union node *,*/ int);
4234#if !ENABLE_PLATFORM_MINGW32
3653static int forkshell(struct job *, union node *, int); 4235static int forkshell(struct job *, union node *, int);
4236#endif
3654static int waitforjob(struct job *); 4237static int waitforjob(struct job *);
3655 4238
3656#if !JOBS 4239#if !JOBS && !JOBS_WIN32
3657enum { doing_jobctl = 0 }; 4240enum { doing_jobctl = 0 };
3658#define setjobctl(on) do {} while (0) 4241#define setjobctl(on) do {} while (0)
3659#else 4242#elif JOBS_WIN32
4243static smallint doing_jobctl; //references:8
4244#define setjobctl(on) do { if (rootshell) doing_jobctl = on; } while (0)
4245#else /* JOBS */
3660static smallint doing_jobctl; //references:8 4246static smallint doing_jobctl; //references:8
3661static void setjobctl(int); 4247static void setjobctl(int);
3662#endif 4248#endif
3663 4249
4250#if !ENABLE_PLATFORM_MINGW32
3664/* 4251/*
3665 * Ignore a signal. 4252 * Ignore a signal.
3666 */ 4253 */
@@ -3809,6 +4396,10 @@ setsignal(int signo)
3809 4396
3810 sigaction_set(signo, &act); 4397 sigaction_set(signo, &act);
3811} 4398}
4399#else
4400#define setsignal(s)
4401#define ignoresig(s)
4402#endif
3812 4403
3813/* mode flags for set_curjob */ 4404/* mode flags for set_curjob */
3814#define CUR_DELETE 2 4405#define CUR_DELETE 2
@@ -3942,7 +4533,7 @@ set_curjob(struct job *jp, unsigned mode)
3942 } 4533 }
3943} 4534}
3944 4535
3945#if JOBS || DEBUG 4536#if JOBS || ENABLE_PLATFORM_MINGW32 || DEBUG
3946static int 4537static int
3947jobno(const struct job *jp) 4538jobno(const struct job *jp)
3948{ 4539{
@@ -3960,7 +4551,9 @@ static struct job *
3960getjob(const char *name, int getctl) 4551getjob(const char *name, int getctl)
3961{ 4552{
3962 struct job *jp; 4553 struct job *jp;
4554#if ENABLE_PLATFORM_POSIX || JOBS_WIN32
3963 struct job *found; 4555 struct job *found;
4556#endif
3964 const char *err_msg = "%s: no such job"; 4557 const char *err_msg = "%s: no such job";
3965 unsigned num; 4558 unsigned num;
3966 int c; 4559 int c;
@@ -4005,6 +4598,7 @@ getjob(const char *name, int getctl)
4005 } 4598 }
4006 } 4599 }
4007 4600
4601#if ENABLE_PLATFORM_POSIX || JOBS_WIN32
4008 found = NULL; 4602 found = NULL;
4009 while (jp) { 4603 while (jp) {
4010 if (*p == '?' 4604 if (*p == '?'
@@ -4021,6 +4615,9 @@ getjob(const char *name, int getctl)
4021 if (!found) 4615 if (!found)
4022 goto err; 4616 goto err;
4023 jp = found; 4617 jp = found;
4618#else
4619 goto err;
4620#endif
4024 4621
4025 gotit: 4622 gotit:
4026#if JOBS 4623#if JOBS
@@ -4039,14 +4636,18 @@ getjob(const char *name, int getctl)
4039static void 4636static void
4040freejob(struct job *jp) 4637freejob(struct job *jp)
4041{ 4638{
4639#if ENABLE_PLATFORM_POSIX || JOBS_WIN32
4042 struct procstat *ps; 4640 struct procstat *ps;
4043 int i; 4641 int i;
4642#endif
4044 4643
4045 INT_OFF; 4644 INT_OFF;
4645#if ENABLE_PLATFORM_POSIX || JOBS_WIN32
4046 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { 4646 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
4047 if (ps->ps_cmd != nullstr) 4647 if (ps->ps_cmd != nullstr)
4048 free(ps->ps_cmd); 4648 free(ps->ps_cmd);
4049 } 4649 }
4650#endif
4050 if (jp->ps != &jp->ps0) 4651 if (jp->ps != &jp->ps0)
4051 free(jp->ps); 4652 free(jp->ps);
4052 jp->used = 0; 4653 jp->used = 0;
@@ -4139,7 +4740,9 @@ setjobctl(int on)
4139 ttyfd = fd; 4740 ttyfd = fd;
4140 doing_jobctl = on; 4741 doing_jobctl = on;
4141} 4742}
4743#endif
4142 4744
4745#if JOBS || JOBS_WIN32
4143static int FAST_FUNC 4746static int FAST_FUNC
4144killcmd(int argc, char **argv) 4747killcmd(int argc, char **argv)
4145{ 4748{
@@ -4169,8 +4772,10 @@ killcmd(int argc, char **argv)
4169 * sh -c 'true|sleep 1 & sleep 2; kill %1' 4772 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4170 */ 4773 */
4171 n = jp->nprocs; /* can't be 0 (I hope) */ 4774 n = jp->nprocs; /* can't be 0 (I hope) */
4775#if !ENABLE_PLATFORM_MINGW32
4172 if (jp->jobctl) 4776 if (jp->jobctl)
4173 n = 1; 4777 n = 1;
4778#endif
4174 dst = alloca(n * sizeof(int)*4); 4779 dst = alloca(n * sizeof(int)*4);
4175 argv[i] = dst; 4780 argv[i] = dst;
4176 for (j = 0; j < n; j++) { 4781 for (j = 0; j < n; j++) {
@@ -4185,7 +4790,11 @@ killcmd(int argc, char **argv)
4185 * leading space. Needed to not confuse 4790 * leading space. Needed to not confuse
4186 * negative pids with "kill -SIGNAL_NO" syntax 4791 * negative pids with "kill -SIGNAL_NO" syntax
4187 */ 4792 */
4793#if !ENABLE_PLATFORM_MINGW32
4188 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); 4794 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4795#else
4796 dst += sprintf(dst, " -%u", (int)ps->ps_pid);
4797#endif
4189 } 4798 }
4190 *dst = '\0'; 4799 *dst = '\0';
4191 } 4800 }
@@ -4193,7 +4802,9 @@ killcmd(int argc, char **argv)
4193 } 4802 }
4194 return kill_main(argc, argv); 4803 return kill_main(argc, argv);
4195} 4804}
4805#endif
4196 4806
4807#if JOBS
4197static void 4808static void
4198showpipe(struct job *jp /*, FILE *out*/) 4809showpipe(struct job *jp /*, FILE *out*/)
4199{ 4810{
@@ -4298,6 +4909,65 @@ sprint_status48(char *os, int status, int sigonly)
4298 return s - os; 4909 return s - os;
4299} 4910}
4300 4911
4912#if ENABLE_PLATFORM_MINGW32
4913static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
4914{
4915 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
4916# if ENABLE_FEATURE_EDITING
4917 bb_got_signal = SIGINT; /* for read_line_input: "we got a signal" */
4918# endif
4919 if (!suppress_int && !(rootshell && iflag))
4920 raise_interrupt();
4921 pending_int = 1;
4922 return TRUE;
4923 }
4924 return FALSE;
4925}
4926
4927/*
4928 * Windows does not know about parent-child relationship
4929 * They don't support waitpid(-1)
4930 */
4931static pid_t
4932waitpid_child(int *status, int wait_flags)
4933{
4934 struct job *jb;
4935 int pid_nr = 0;
4936 static HANDLE *proclist = NULL;
4937 static int pid_max = 0;
4938 pid_t pid = -1;
4939 DWORD win_status, idx;
4940 int i;
4941
4942 for (jb = curjob; jb; jb = jb->prev_job) {
4943 if (jb->state != JOBDONE) {
4944 if (pid_nr + jb->nprocs > pid_max) {
4945 pid_max = pid_nr + jb->nprocs;
4946 proclist = ckrealloc(proclist, sizeof(*proclist) * pid_max);
4947 }
4948
4949 for (i = 0; i < jb->nprocs; ++i) {
4950 if (jb->ps[i].ps_proc) {
4951 proclist[pid_nr++] = jb->ps[i].ps_proc;
4952 }
4953 }
4954 }
4955 }
4956
4957 if (pid_nr) {
4958 idx = WaitForMultipleObjects(pid_nr, proclist, FALSE,
4959 wait_flags & WNOHANG ? 0 : INFINITE);
4960 if (idx < pid_nr) {
4961 GetExitCodeProcess(proclist[idx], &win_status);
4962 *status = exit_code_to_wait_status(win_status);
4963 pid = GetProcessId(proclist[idx]);
4964 }
4965 }
4966 return pid;
4967}
4968#define waitpid(p, s, f) waitpid_child(s, f)
4969#endif
4970
4301#define DOWAIT_NONBLOCK 0 4971#define DOWAIT_NONBLOCK 0
4302#define DOWAIT_BLOCK 1 4972#define DOWAIT_BLOCK 1
4303#define DOWAIT_BLOCK_OR_SIG 2 4973#define DOWAIT_BLOCK_OR_SIG 2
@@ -4308,6 +4978,7 @@ sprint_status48(char *os, int status, int sigonly)
4308static int 4978static int
4309waitproc(int block, int *status) 4979waitproc(int block, int *status)
4310{ 4980{
4981#if !ENABLE_PLATFORM_MINGW32
4311 sigset_t oldmask; 4982 sigset_t oldmask;
4312 int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; 4983 int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG;
4313 int err; 4984 int err;
@@ -4338,6 +5009,11 @@ waitproc(int block, int *status)
4338 } while (got_sigchld); 5009 } while (got_sigchld);
4339 5010
4340 return err; 5011 return err;
5012#else
5013 int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG;
5014 *status = 0;
5015 return waitpid(-1, status, flags);
5016#endif
4341} 5017}
4342 5018
4343static int 5019static int
@@ -4394,6 +5070,10 @@ waitone(int block, struct job *job)
4394 jobno(jp), pid, ps->ps_status, status)); 5070 jobno(jp), pid, ps->ps_status, status));
4395 ps->ps_status = status; 5071 ps->ps_status = status;
4396 thisjob = jp; 5072 thisjob = jp;
5073#if ENABLE_PLATFORM_MINGW32
5074 CloseHandle(ps->ps_proc);
5075 ps->ps_proc = NULL;
5076#endif
4397 } 5077 }
4398 if (ps->ps_status == -1) 5078 if (ps->ps_status == -1)
4399 jobstate = JOBRUNNING; 5079 jobstate = JOBRUNNING;
@@ -4456,6 +5136,7 @@ waitone(int block, struct job *job)
4456static int 5136static int
4457dowait(int block, struct job *jp) 5137dowait(int block, struct job *jp)
4458{ 5138{
5139#if !ENABLE_PLATFORM_MINGW32
4459 smallint gotchld = *(volatile smallint *)&got_sigchld; 5140 smallint gotchld = *(volatile smallint *)&got_sigchld;
4460 int rpid; 5141 int rpid;
4461 int pid; 5142 int pid;
@@ -4477,9 +5158,17 @@ dowait(int block, struct job *jp)
4477 } while (pid >= 0); 5158 } while (pid >= 0);
4478 5159
4479 return rpid; 5160 return rpid;
5161#else
5162 int pid = 1;
5163
5164 while (jp ? jp->state == JOBRUNNING : pid > 0)
5165 pid = waitone(block, jp);
5166
5167 return pid;
5168#endif
4480} 5169}
4481 5170
4482#if JOBS 5171#if JOBS || JOBS_WIN32
4483static void 5172static void
4484showjob(struct job *jp, int mode) 5173showjob(struct job *jp, int mode)
4485{ 5174{
@@ -4494,7 +5183,7 @@ showjob(struct job *jp, int mode)
4494 5183
4495 if (mode & SHOW_ONLY_PGID) { /* jobs -p */ 5184 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4496 /* just output process (group) id of pipeline */ 5185 /* just output process (group) id of pipeline */
4497 fprintf(out, "%d\n", ps->ps_pid); 5186 fprintf(out, "%"PID_FMT"d\n", ps->ps_pid);
4498 return; 5187 return;
4499 } 5188 }
4500 5189
@@ -4507,7 +5196,7 @@ showjob(struct job *jp, int mode)
4507 s[col - 3] = '-'; 5196 s[col - 3] = '-';
4508 5197
4509 if (mode & SHOW_PIDS) 5198 if (mode & SHOW_PIDS)
4510 col += fmtstr(s + col, 16, "%d ", ps->ps_pid); 5199 col += fmtstr(s + col, 16, "%"PID_FMT"d ", ps->ps_pid);
4511 5200
4512 psend = ps + jp->nprocs; 5201 psend = ps + jp->nprocs;
4513 5202
@@ -4516,8 +5205,10 @@ showjob(struct job *jp, int mode)
4516 col += sizeof("Running") - 1; 5205 col += sizeof("Running") - 1;
4517 } else { 5206 } else {
4518 int status = psend[-1].ps_status; 5207 int status = psend[-1].ps_status;
5208#if !ENABLE_PLATFORM_MINGW32
4519 if (jp->state == JOBSTOPPED) 5209 if (jp->state == JOBSTOPPED)
4520 status = jp->stopstatus; 5210 status = jp->stopstatus;
5211#endif
4521 col += sprint_status48(s + col, status, 0); 5212 col += sprint_status48(s + col, status, 0);
4522 } 5213 }
4523 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ 5214 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
@@ -4536,14 +5227,18 @@ showjob(struct job *jp, int mode)
4536 s[0] = '\0'; 5227 s[0] = '\0';
4537 col = 33; 5228 col = 33;
4538 if (mode & SHOW_PIDS) 5229 if (mode & SHOW_PIDS)
4539 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1; 5230 col = fmtstr(s, 48, "\n%*c%"PID_FMT"d ", indent_col, ' ', ps->ps_pid) - 1;
4540 start: 5231 start:
5232#if ENABLE_PLATFORM_POSIX || JOBS_WIN32
4541 fprintf(out, "%s%*c%s%s", 5233 fprintf(out, "%s%*c%s%s",
4542 s, 5234 s,
4543 33 - col >= 0 ? 33 - col : 0, ' ', 5235 33 - col >= 0 ? 33 - col : 0, ' ',
4544 ps == jp->ps ? "" : "| ", 5236 ps == jp->ps ? "" : "| ",
4545 ps->ps_cmd 5237 ps->ps_cmd
4546 ); 5238 );
5239#else
5240 fprintf(out, "%s", s);
5241#endif
4547 } while (++ps != psend); 5242 } while (++ps != psend);
4548 newline_and_flush(out); 5243 newline_and_flush(out);
4549 5244
@@ -4628,7 +5323,7 @@ getstatus(struct job *job)
4628 { 5323 {
4629 /* XXX: limits number of signals */ 5324 /* XXX: limits number of signals */
4630 retval = WTERMSIG(status); 5325 retval = WTERMSIG(status);
4631#if JOBS 5326#if JOBS || ENABLE_PLATFORM_MINGW32
4632 if (retval == SIGINT) 5327 if (retval == SIGINT)
4633 job->sigint = 1; 5328 job->sigint = 1;
4634#endif 5329#endif
@@ -4800,7 +5495,7 @@ makejob(/*union node *node,*/ int nprocs)
4800 break; 5495 break;
4801 if (jp->state != JOBDONE || !jp->waited) 5496 if (jp->state != JOBDONE || !jp->waited)
4802 continue; 5497 continue;
4803#if JOBS 5498#if JOBS || JOBS_WIN32
4804 if (doing_jobctl) 5499 if (doing_jobctl)
4805 continue; 5500 continue;
4806#endif 5501#endif
@@ -4826,7 +5521,7 @@ makejob(/*union node *node,*/ int nprocs)
4826 return jp; 5521 return jp;
4827} 5522}
4828 5523
4829#if JOBS 5524#if JOBS || JOBS_WIN32
4830/* 5525/*
4831 * Return a string identifying a command (to be printed by the 5526 * Return a string identifying a command (to be printed by the
4832 * jobs command). 5527 * jobs command).
@@ -5168,6 +5863,7 @@ clear_traps(void)
5168 INT_ON; 5863 INT_ON;
5169} 5864}
5170 5865
5866#if !ENABLE_PLATFORM_MINGW32
5171/* Lives far away from here, needed for forkchild */ 5867/* Lives far away from here, needed for forkchild */
5172static void closescript(void); 5868static void closescript(void);
5173 5869
@@ -5294,14 +5990,22 @@ forkchild(struct job *jp, union node *n, int mode)
5294 for (jp = curjob; jp; jp = jp->prev_job) 5990 for (jp = curjob; jp; jp = jp->prev_job)
5295 freejob(jp); 5991 freejob(jp);
5296} 5992}
5993#endif
5297 5994
5298/* Called after fork(), in parent */ 5995/* Called after fork(), in parent */
5299#if !JOBS 5996#if !JOBS && !JOBS_WIN32
5300#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) 5997#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5301#endif 5998#endif
5302static void 5999static void
6000#if !ENABLE_PLATFORM_MINGW32
5303forkparent(struct job *jp, union node *n, int mode, pid_t pid) 6001forkparent(struct job *jp, union node *n, int mode, pid_t pid)
6002#else
6003forkparent(struct job *jp, union node *n, int mode, HANDLE proc)
6004#endif
5304{ 6005{
6006#if ENABLE_PLATFORM_MINGW32
6007 pid_t pid = GetProcessId(proc);
6008#endif
5305 TRACE(("In parent shell: child = %d\n", pid)); 6009 TRACE(("In parent shell: child = %d\n", pid));
5306 if (!jp) /* jp is NULL when called by openhere() for heredoc support */ 6010 if (!jp) /* jp is NULL when called by openhere() for heredoc support */
5307 return; 6011 return;
@@ -5320,19 +6024,29 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5320 if (mode == FORK_BG) { 6024 if (mode == FORK_BG) {
5321 backgndpid = pid; /* set $! */ 6025 backgndpid = pid; /* set $! */
5322 set_curjob(jp, CUR_RUNNING); 6026 set_curjob(jp, CUR_RUNNING);
6027#if ENABLE_PLATFORM_MINGW32
6028 if (iflag && jp && jp->nprocs == 0)
6029 fprintf(stderr, "[%d] %"PID_FMT"d\n", jobno(jp), pid);
6030#endif
5323 } 6031 }
5324 if (jp) { 6032 if (jp) {
5325 struct procstat *ps = &jp->ps[jp->nprocs++]; 6033 struct procstat *ps = &jp->ps[jp->nprocs++];
5326 ps->ps_pid = pid; 6034 ps->ps_pid = pid;
5327 ps->ps_status = -1; 6035 ps->ps_status = -1;
6036#if ENABLE_PLATFORM_POSIX || JOBS_WIN32
5328 ps->ps_cmd = nullstr; 6037 ps->ps_cmd = nullstr;
5329#if JOBS 6038#endif
6039#if ENABLE_PLATFORM_MINGW32
6040 ps->ps_proc = proc;
6041#endif
6042#if JOBS || JOBS_WIN32
5330 if (doing_jobctl && n) 6043 if (doing_jobctl && n)
5331 ps->ps_cmd = commandtext(n); 6044 ps->ps_cmd = commandtext(n);
5332#endif 6045#endif
5333 } 6046 }
5334} 6047}
5335 6048
6049#if !ENABLE_PLATFORM_MINGW32
5336/* jp and n are NULL when called by openhere() for heredoc support */ 6050/* jp and n are NULL when called by openhere() for heredoc support */
5337static int 6051static int
5338forkshell(struct job *jp, union node *n, int mode) 6052forkshell(struct job *jp, union node *n, int mode)
@@ -5355,6 +6069,7 @@ forkshell(struct job *jp, union node *n, int mode)
5355 } 6069 }
5356 return pid; 6070 return pid;
5357} 6071}
6072#endif
5358 6073
5359/* 6074/*
5360 * Wait for job to finish. 6075 * Wait for job to finish.
@@ -5418,6 +6133,10 @@ waitforjob(struct job *jp)
5418 return exitstatus; 6133 return exitstatus;
5419 6134
5420 st = getstatus(jp); 6135 st = getstatus(jp);
6136#if ENABLE_PLATFORM_MINGW32
6137 if (!jp->sigint && iflag && rootshell)
6138 pending_int = 0;
6139#endif
5421#if JOBS 6140#if JOBS
5422 if (jp->jobctl) { 6141 if (jp->jobctl) {
5423 xtcsetpgrp(ttyfd, rootpid); 6142 xtcsetpgrp(ttyfd, rootpid);
@@ -5443,6 +6162,7 @@ waitforjob(struct job *jp)
5443/* 6162/*
5444 * return 1 if there are stopped jobs, otherwise 0 6163 * return 1 if there are stopped jobs, otherwise 0
5445 */ 6164 */
6165#if !ENABLE_PLATFORM_MINGW32
5446static int 6166static int
5447stoppedjobs(void) 6167stoppedjobs(void)
5448{ 6168{
@@ -5461,6 +6181,17 @@ stoppedjobs(void)
5461 out: 6181 out:
5462 return retval; 6182 return retval;
5463} 6183}
6184#else
6185static int
6186stoppedjobs(void)
6187{
6188 if (iflag && curjob) {
6189 out2str("You have background jobs.\n");
6190 return 1;
6191 }
6192 return 0;
6193}
6194#endif
5464 6195
5465 6196
5466/* 6197/*
@@ -5485,6 +6216,7 @@ openhere(union node *redir)
5485 char *p; 6216 char *p;
5486 int pip[2]; 6217 int pip[2];
5487 size_t len = 0; 6218 size_t len = 0;
6219 IF_PLATFORM_MINGW32(struct forkshell fs);
5488 6220
5489 if (pipe(pip) < 0) 6221 if (pipe(pip) < 0)
5490 ash_msg_and_raise_perror("can't create pipe"); 6222 ash_msg_and_raise_perror("can't create pipe");
@@ -5501,6 +6233,14 @@ openhere(union node *redir)
5501 goto out; 6233 goto out;
5502 } 6234 }
5503 6235
6236#if ENABLE_PLATFORM_MINGW32
6237 memset(&fs, 0, sizeof(fs));
6238 fs.fpid = FS_OPENHERE;
6239 fs.fd[0] = pip[0];
6240 fs.fd[1] = pip[1];
6241 fs.path = p;
6242 spawn_forkshell(&fs, NULL, NULL, FORK_NOJOB);
6243#else
5504 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 6244 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5505 /* child */ 6245 /* child */
5506 close(pip[0]); 6246 close(pip[0]);
@@ -5512,6 +6252,7 @@ openhere(union node *redir)
5512 xwrite(pip[1], p, len); 6252 xwrite(pip[1], p, len);
5513 _exit_SUCCESS(); 6253 _exit_SUCCESS();
5514 } 6254 }
6255#endif
5515 out: 6256 out:
5516 close(pip[1]); 6257 close(pip[1]);
5517 return pip[0]; 6258 return pip[0];
@@ -5589,6 +6330,9 @@ openredirect(union node *redir)
5589 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 6330 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5590 if (f < 0) 6331 if (f < 0)
5591 goto ecreate; 6332 goto ecreate;
6333#if ENABLE_PLATFORM_MINGW32
6334 lseek(f, 0, SEEK_END);
6335#endif
5592 break; 6336 break;
5593 } 6337 }
5594 6338
@@ -5799,6 +6543,12 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5799 if (fd == preverrout_fd) 6543 if (fd == preverrout_fd)
5800 preverrout_fd = new_fd; 6544 preverrout_fd = new_fd;
5801 6545
6546#if ENABLE_PLATFORM_MINGW32 && !defined(_UCRT)
6547 // Workaround for problems with stderr in MSVCRT
6548 if (fd == fileno(stderr))
6549 setvbuf(stderr, NULL, _IONBF, 0);
6550#endif
6551
5802 return 0; /* "we did not close fd" */ 6552 return 0; /* "we did not close fd" */
5803} 6553}
5804 6554
@@ -6152,6 +6902,9 @@ ifsbreakup(char *string, struct arglist *arglist)
6152 const char *ifs, *realifs; 6902 const char *ifs, *realifs;
6153 int ifsspc; 6903 int ifsspc;
6154 int nulonly; 6904 int nulonly;
6905#if ENABLE_PLATFORM_MINGW32
6906 int lshift = 0;
6907#endif
6155 6908
6156 start = string; 6909 start = string;
6157 if (ifslastp != NULL) { 6910 if (ifslastp != NULL) {
@@ -6162,7 +6915,33 @@ ifsbreakup(char *string, struct arglist *arglist)
6162 do { 6915 do {
6163 int afternul; 6916 int afternul;
6164 6917
6918#if ENABLE_PLATFORM_MINGW32
6919 /* Adjust region offsets for left-shifted string. */
6920 ifsp->begoff -= lshift;
6921 ifsp->endoff -= lshift;
6922#endif
6165 p = string + ifsp->begoff; 6923 p = string + ifsp->begoff;
6924#if ENABLE_PLATFORM_MINGW32
6925 if (ifsp->endoff > ifsp->begoff + 1) {
6926 /* Transform CRLF to LF. Skip regions having zero or
6927 * one characters: they can't contain CRLF. If the
6928 * region shrinks shift the rest of the string left. */
6929 int oldlen = ifsp->endoff - ifsp->begoff;
6930 int newlen = remove_cr(p, oldlen);
6931 int delta = oldlen - newlen;
6932
6933 if (delta > 0) {
6934 char *t = string + ifsp->endoff;
6935 char *s = string + ifsp->endoff - delta;
6936
6937 while (*t)
6938 *s++ = *t++;
6939 *s = '\0';
6940 lshift += delta;
6941 ifsp->endoff -= delta;
6942 }
6943 }
6944#endif
6166 afternul = nulonly; 6945 afternul = nulonly;
6167 nulonly = ifsp->nulonly; 6946 nulonly = ifsp->nulonly;
6168 ifs = nulonly ? nullstr : realifs; 6947 ifs = nulonly ? nullstr : realifs;
@@ -6607,6 +7386,7 @@ evalbackcmd(union node *n, struct backcmd *result
6607 const int ip = 0; 7386 const int ip = 0;
6608 const int ic = 1; 7387 const int ic = 1;
6609#endif 7388#endif
7389 IF_PLATFORM_MINGW32(struct forkshell fs);
6610 7390
6611 result->fd = -1; 7391 result->fd = -1;
6612 result->buf = NULL; 7392 result->buf = NULL;
@@ -6620,6 +7400,15 @@ evalbackcmd(union node *n, struct backcmd *result
6620 ash_msg_and_raise_perror("can't create pipe"); 7400 ash_msg_and_raise_perror("can't create pipe");
6621 /* process substitution uses NULL job, like openhere() */ 7401 /* process substitution uses NULL job, like openhere() */
6622 jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL; 7402 jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL;
7403#if ENABLE_PLATFORM_MINGW32
7404 memset(&fs, 0, sizeof(fs));
7405 fs.fpid = FS_EVALBACKCMD;
7406 fs.n = n;
7407 fs.fd[0] = pip[0];
7408 fs.fd[1] = pip[1];
7409 fs.fd[2] = ctl;
7410 spawn_forkshell(&fs, jp, n, FORK_NOJOB);
7411#else
6623 if (forkshell(jp, n, FORK_NOJOB) == 0) { 7412 if (forkshell(jp, n, FORK_NOJOB) == 0) {
6624 /* child */ 7413 /* child */
6625 FORCE_INT_ON; 7414 FORCE_INT_ON;
@@ -6643,6 +7432,7 @@ evalbackcmd(union node *n, struct backcmd *result
6643 evaltreenr(n, EV_EXIT); 7432 evaltreenr(n, EV_EXIT);
6644 /* NOTREACHED */ 7433 /* NOTREACHED */
6645 } 7434 }
7435#endif
6646 /* parent */ 7436 /* parent */
6647#if BASH_PROCESS_SUBST 7437#if BASH_PROCESS_SUBST
6648 if (ctl != CTLBACKQ) { 7438 if (ctl != CTLBACKQ) {
@@ -6721,8 +7511,14 @@ expbackq(union node *cmd, int flag IF_BASH_PROCESS_SUBST(, int ctl))
6721 7511
6722 /* Eat all trailing newlines */ 7512 /* Eat all trailing newlines */
6723 dest = expdest; 7513 dest = expdest;
6724 for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';) 7514 for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';) {
6725 STUNPUTC(dest); 7515 STUNPUTC(dest);
7516#if ENABLE_PLATFORM_MINGW32
7517 if (dest > ((char *)stackblock() + startloc) && dest[-1] == '\r') {
7518 STUNPUTC(dest);
7519 }
7520#endif
7521 }
6726 expdest = dest; 7522 expdest = dest;
6727 7523
6728 if (!(flag & EXP_QUOTED)) 7524 if (!(flag & EXP_QUOTED))
@@ -7869,6 +8665,26 @@ expandmeta(struct strlist *str /*, int flag*/)
7869#else 8665#else
7870/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */ 8666/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
7871 8667
8668#if ENABLE_ASH_GLOB_OPTIONS
8669static int FAST_FUNC
8670ash_accept_glob(const char *name)
8671{
8672 struct stat st;
8673
8674 if (nohiddenglob || nohidsysglob) {
8675 if (!lstat(name, &st)) {
8676 if ((st.st_attr & FILE_ATTRIBUTE_HIDDEN)) {
8677 if (nohiddenglob ||
8678 (st.st_attr & FILE_ATTRIBUTE_SYSTEM)) {
8679 return FALSE;
8680 }
8681 }
8682 }
8683 }
8684 return TRUE;
8685}
8686#endif
8687
7872/* 8688/*
7873 * Do metacharacter (i.e. *, ?, [...]) expansion. 8689 * Do metacharacter (i.e. *, ?, [...]) expansion.
7874 */ 8690 */
@@ -7896,6 +8712,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
7896 8712
7897 metaflag = 0; 8713 metaflag = 0;
7898 start = name; 8714 start = name;
8715#if ENABLE_PLATFORM_MINGW32
8716 if (expdir_len == 0 && has_dos_drive_prefix(start) && start[2] != '/')
8717 start += 2;
8718#endif
7899 for (p = name; esc = 0, *p; p += esc + 1) { 8719 for (p = name; esc = 0, *p; p += esc + 1) {
7900 if (*p == '*' || *p == '?') 8720 if (*p == '*' || *p == '?')
7901 metaflag = 1; 8721 metaflag = 1;
@@ -7970,8 +8790,16 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
7970 while (!pending_int && (dp = readdir(dirp)) != NULL) { 8790 while (!pending_int && (dp = readdir(dirp)) != NULL) {
7971 if (dp->d_name[0] == '.' && !matchdot) 8791 if (dp->d_name[0] == '.' && !matchdot)
7972 continue; 8792 continue;
8793#if ENABLE_ASH_GLOB_OPTIONS
8794# undef pmatch
8795# define pmatch(a, b) !fnmatch((a), (b), nocaseglob ? FNM_CASEFOLD : 0)
8796#endif
7973 if (pmatch(start, dp->d_name)) { 8797 if (pmatch(start, dp->d_name)) {
7974 if (atend) { 8798 if (atend) {
8799#if ENABLE_ASH_GLOB_OPTIONS
8800 if (!ash_accept_glob(dp->d_name))
8801 continue;
8802#endif
7975 strcpy(enddir, dp->d_name); 8803 strcpy(enddir, dp->d_name);
7976 addfname(expdir); 8804 addfname(expdir);
7977 } else { 8805 } else {
@@ -7999,6 +8827,10 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
7999 endname[-esc - 1] = esc ? '\\' : '/'; 8827 endname[-esc - 1] = esc ? '\\' : '/';
8000#undef expdir 8828#undef expdir
8001#undef expdir_max 8829#undef expdir_max
8830#if ENABLE_ASH_GLOB_OPTIONS
8831# undef pmatch
8832# define pmatch(a, b) !fnmatch((a), (b), 0)
8833#endif
8002} 8834}
8003 8835
8004static struct strlist * 8836static struct strlist *
@@ -8271,14 +9103,40 @@ static int builtinloc = -1; /* index in path of %builtin, or -1 */
8271 9103
8272 9104
8273static void 9105static void
9106#if ENABLE_PLATFORM_MINGW32
9107tryexec(IF_FEATURE_SH_STANDALONE(int applet_no, const char *path, int noexec,)
9108 const char *cmd, char **argv, char **envp)
9109#else
8274tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp) 9110tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
9111#endif
8275{ 9112{
9113#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE
9114 interp_t interp;
9115#endif
8276#if ENABLE_FEATURE_SH_STANDALONE 9116#if ENABLE_FEATURE_SH_STANDALONE
8277 if (applet_no >= 0) { 9117 if (applet_no >= 0) {
9118# if ENABLE_PLATFORM_MINGW32
9119 /* Treat all applets as NOEXEC, including the shell itself
9120 * if we were called from forkshell_shellexec(). */
9121 run_noexec:
9122 if (applet_main[applet_no] != ash_main || noexec) {
9123 /* mingw-w64's getopt() uses __argv[0] as the program name */
9124 __argv[0] = (char *)cmd;
9125 /* 'which' wants to know if it was invoked from a standalone
9126 * shell. 'Which' in argv[0] indicates this. */
9127 if (strcmp(argv[0], "which") == 0) {
9128 argv[0] = (char *)"Which";
9129 }
9130# else
8278 if (APPLET_IS_NOEXEC(applet_no)) { 9131 if (APPLET_IS_NOEXEC(applet_no)) {
9132# endif
9133#if !ENABLE_PLATFORM_MINGW32 || !defined(_UCRT)
9134 /* If building for UCRT move this up into shellexec() to
9135 * work around a bug. */
8279 clearenv(); 9136 clearenv();
8280 while (*envp) 9137 while (*envp)
8281 putenv(*envp++); 9138 putenv(*envp++);
9139#endif
8282 popredir(/*drop:*/ 1); 9140 popredir(/*drop:*/ 1);
8283 run_noexec_applet_and_exit(applet_no, cmd, argv); 9141 run_noexec_applet_and_exit(applet_no, cmd, argv);
8284 } 9142 }
@@ -8289,6 +9147,44 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c
8289 } 9147 }
8290#endif 9148#endif
8291 9149
9150#if ENABLE_PLATFORM_MINGW32
9151 /* Workaround for libtool, which assumes the host is an MSYS2
9152 * environment and requires special-case escaping for cmd.exe.
9153 * https://github.com/skeeto/w64devkit/issues/50 */
9154 if (string_array_len(argv) >= 3 &&
9155 strcmp(argv[0], "cmd") == 0 &&
9156 strcmp(argv[1], "//c") == 0 &&
9157 strcmp(argv[2], "echo") == 0) {
9158 argv[1]++; /* drop extra slash */
9159 }
9160
9161 /* cmd was allocated on the stack with room for an extension */
9162 add_win32_extension((char *)cmd);
9163
9164# if ENABLE_FEATURE_SH_STANDALONE
9165 /* If the command is a script with an interpreter which is an
9166 * applet, we can run it as if it were a noexec applet. */
9167 if (parse_interpreter(cmd, &interp)) {
9168 applet_no = find_applet_by_name_for_sh(interp.name, path);
9169 if (applet_no >= 0) {
9170 argv[0] = (char *)cmd;
9171 /* evalcommand()/spawn_forkshell() add two elements before argv */
9172 if (interp.opts) {
9173 argv--;
9174 argv[0] = (char *)interp.opts;
9175 }
9176 argv--;
9177 cmd = argv[0] = (char *)interp.name;
9178 /* Identify the index of the script file in argv */
9179 set_interp(1 + (interp.opts != NULL));
9180 goto run_noexec;
9181 }
9182 }
9183# endif
9184
9185 execve(cmd, argv, envp);
9186 /* skip POSIX-mandated retry on ENOEXEC */
9187#else /* !ENABLE_PLATFORM_MINGW32 */
8292 repeat: 9188 repeat:
8293#ifdef SYSV 9189#ifdef SYSV
8294 do { 9190 do {
@@ -8324,15 +9220,23 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c
8324 argv[0] = (char*) "ash"; 9220 argv[0] = (char*) "ash";
8325 goto repeat; 9221 goto repeat;
8326 } 9222 }
9223#endif /* !ENABLE_PLATFORM_MINGW32 */
8327} 9224}
8328 9225
9226#if !ENABLE_PLATFORM_MINGW32 || !ENABLE_FEATURE_SH_STANDALONE
9227# define shellexec(prg, a, pth, i, n) shellexec(prg, a, pth, i)
9228#endif
9229
8329/* 9230/*
8330 * Exec a program. Never returns. If you change this routine, you may 9231 * Exec a program. Never returns. If you change this routine, you may
8331 * have to change the find_command routine as well. 9232 * have to change the find_command routine as well.
8332 * argv[-1] must exist and be writable! See tryexec() for why. 9233 * argv[-1] must exist and be writable! See tryexec() for why.
8333 */ 9234 */
8334static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN; 9235static struct builtincmd *find_builtin(const char *name);
8335static void shellexec(char *prog, char **argv, const char *path, int idx) 9236static void shellexec(char *prog, char **argv, const char *path, int idx,
9237 int noexec) NORETURN;
9238static void shellexec(char *prog, char **argv, const char *path, int idx,
9239 int noexec)
8336{ 9240{
8337 char *cmdname; 9241 char *cmdname;
8338 int e; 9242 int e;
@@ -8341,12 +9245,30 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
8341 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ 9245 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
8342 9246
8343 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); 9247 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
9248#if ENABLE_FEATURE_SH_STANDALONE && ENABLE_PLATFORM_MINGW32 && defined(_UCRT)
9249 /* Avoid UCRT bug by updating parent's environment and passing a
9250 * NULL environment pointer to execve(). */
9251 clearenv();
9252 while (*envp)
9253 putenv(*envp++);
9254 envp = NULL;
9255#endif
9256#if !ENABLE_PLATFORM_MINGW32
8344 if (strchr(prog, '/') != NULL 9257 if (strchr(prog, '/') != NULL
9258#else
9259 if (has_path(prog)
9260#endif
8345#if ENABLE_FEATURE_SH_STANDALONE 9261#if ENABLE_FEATURE_SH_STANDALONE
8346 || (applet_no = find_applet_by_name(prog)) >= 0 9262 || (applet_no = find_applet_by_name_for_sh(prog, path)) >= 0
8347#endif 9263#endif
8348 ) { 9264 ) {
9265#if ENABLE_PLATFORM_MINGW32
9266 char *progext = stack_add_ext_space(prog);
9267 tryexec(IF_FEATURE_SH_STANDALONE(applet_no, path, noexec,)
9268 progext, argv, envp);
9269#else
8349 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); 9270 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
9271#endif
8350 if (applet_no >= 0) { 9272 if (applet_no >= 0) {
8351 /* We tried execing ourself, but it didn't work. 9273 /* We tried execing ourself, but it didn't work.
8352 * Maybe /proc/self/exe doesn't exist? 9274 * Maybe /proc/self/exe doesn't exist?
@@ -8355,13 +9277,33 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
8355 goto try_PATH; 9277 goto try_PATH;
8356 } 9278 }
8357 e = errno; 9279 e = errno;
9280#if ENABLE_PLATFORM_MINGW32
9281 if (unix_path(prog)) {
9282 const char *name = bb_basename(prog);
9283# if ENABLE_FEATURE_SH_STANDALONE
9284 if ((applet_no = find_applet_by_name_for_sh(name, path)) >= 0) {
9285 tryexec(applet_no, path, noexec, name, argv, envp);
9286 e = errno;
9287 }
9288# endif
9289 if (!find_builtin(name)) {
9290 argv[0] = (char *)name;
9291 goto try_PATH;
9292 }
9293 }
9294#endif
8358 } else { 9295 } else {
8359 try_PATH: 9296 try_PATH:
8360 e = ENOENT; 9297 e = ENOENT;
8361 while (padvance(&path, argv[0]) >= 0) { 9298 while (padvance(&path, argv[0]) >= 0) {
8362 cmdname = stackblock(); 9299 cmdname = stackblock();
8363 if (--idx < 0 && pathopt == NULL) { 9300 if (--idx < 0 && pathopt == NULL) {
9301#if ENABLE_PLATFORM_MINGW32
9302 tryexec(IF_FEATURE_SH_STANDALONE(-1, path, noexec,)
9303 cmdname, argv, envp);
9304#else
8364 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp); 9305 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
9306#endif
8365 if (errno != ENOENT && errno != ENOTDIR) 9307 if (errno != ENOENT && errno != ENOTDIR)
8366 e = errno; 9308 e = errno;
8367 } 9309 }
@@ -8400,6 +9342,9 @@ printentry(struct tblentry *cmdp)
8400 padvance(&path, cmdp->cmdname); 9342 padvance(&path, cmdp->cmdname);
8401 } while (--idx >= 0); 9343 } while (--idx >= 0);
8402 name = stackblock(); 9344 name = stackblock();
9345#if ENABLE_PLATFORM_MINGW32
9346 add_win32_extension(name);
9347#endif
8403 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); 9348 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8404} 9349}
8405 9350
@@ -8600,7 +9545,7 @@ changepath(const char *newval)
8600 bltin = idx; 9545 bltin = idx;
8601 break; 9546 break;
8602 } 9547 }
8603 new = strchr(new, ':'); 9548 new = strchr(new, PATH_SEP);
8604 if (!new) 9549 if (!new)
8605 break; 9550 break;
8606 idx++; 9551 idx++;
@@ -8777,14 +9722,37 @@ describe_command(char *command, const char *path, int describe_command_verbose)
8777 case CMDNORMAL: { 9722 case CMDNORMAL: {
8778 int j = entry.u.index; 9723 int j = entry.u.index;
8779 char *p; 9724 char *p;
9725#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE
9726 if (j < -1) {
9727 p = (char *)bb_basename(command);
9728 if (describe_command_verbose) {
9729 out1fmt(" is a builtin applet");
9730 } else {
9731 out1str(applet_to_exe(p));
9732 }
9733 break;
9734 }
9735#endif
8780 if (j < 0) { 9736 if (j < 0) {
9737#if ENABLE_PLATFORM_MINGW32
9738 p = stack_add_ext_space(command);
9739#else
8781 p = command; 9740 p = command;
9741#endif
8782 } else { 9742 } else {
9743#if ENABLE_PLATFORM_MINGW32
9744 if (unix_path(command))
9745 command = (char *)bb_basename(command);
9746#endif
8783 do { 9747 do {
8784 padvance(&path, command); 9748 padvance(&path, command);
8785 } while (--j >= 0); 9749 } while (--j >= 0);
8786 p = stackblock(); 9750 p = stackblock();
8787 } 9751 }
9752#if ENABLE_PLATFORM_MINGW32
9753 add_win32_extension(p);
9754 bs_to_slash(p);
9755#endif
8788 if (describe_command_verbose) { 9756 if (describe_command_verbose) {
8789 out1fmt(" is %s", p); 9757 out1fmt(" is %s", p);
8790 } else { 9758 } else {
@@ -8940,6 +9908,15 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8940/*static int funcstringsize; // size of strings in node */ 9908/*static int funcstringsize; // size of strings in node */
8941static void *funcblock; /* block to allocate function from */ 9909static void *funcblock; /* block to allocate function from */
8942static char *funcstring_end; /* end of block to allocate strings from */ 9910static char *funcstring_end; /* end of block to allocate strings from */
9911#if ENABLE_PLATFORM_MINGW32
9912static int fs_size;
9913static void *fs_start;
9914# if FORKSHELL_DEBUG
9915static void *fs_funcstring;
9916static const char **annot;
9917static char *annot_free;
9918# endif
9919#endif
8943 9920
8944static const uint8_t nodesize[N_NUMBER] ALIGN1 = { 9921static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8945 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), 9922 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
@@ -9072,14 +10049,79 @@ calcsize(int funcblocksize, union node *n)
9072} 10049}
9073 10050
9074static char * 10051static char *
9075nodeckstrdup(char *s) 10052nodeckstrdup(const char *s)
9076{ 10053{
10054#if ENABLE_PLATFORM_MINGW32
10055 if(!s)
10056 return NULL;
10057#endif
9077 funcstring_end -= SHELL_ALIGN(strlen(s) + 1); 10058 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
9078 return strcpy(funcstring_end, s); 10059 return strcpy(funcstring_end, s);
9079} 10060}
9080 10061
9081static union node *copynode(union node *); 10062static union node *copynode(union node *);
9082 10063
10064#if ENABLE_PLATFORM_MINGW32
10065# if FORKSHELL_DEBUG
10066# define MARK_PTR(dst,note,flag) forkshell_mark_ptr((void *)&dst, note, flag)
10067# else
10068# define MARK_PTR(dst,note,flag) forkshell_mark_ptr((void *)&dst)
10069# endif
10070
10071#define NO_FREE 0
10072#define FREE 1
10073
10074#if FORKSHELL_DEBUG
10075static void forkshell_mark_ptr(void *dst, const char *note, int flag)
10076#else
10077static void forkshell_mark_ptr(void *dst)
10078#endif
10079{
10080 char *lrelocate = (char *)fs_start + fs_size;
10081 int index = ((char *)dst - (char *)fs_start)/sizeof(char *);
10082
10083 lrelocate[index/8] |= 1 << (index % 8);
10084
10085#if FORKSHELL_DEBUG
10086 if (dst < fs_start || dst >= fs_funcstring) {
10087 fprintf(stderr, "dst (%p) out of range (%p %p)\n",
10088 dst, fs_start, fs_funcstring);
10089 }
10090 if (annot) {
10091 if (annot[index]) {
10092 fprintf(stderr, "duplicate annotation: %s %s\n",
10093 annot[index], note);
10094 }
10095 annot[index] = note;
10096 annot_free[index] = flag;
10097 }
10098#endif
10099}
10100
10101# define SAVE_PTR(dst,note,flag) { \
10102 if (fs_size) { \
10103 MARK_PTR(dst,note,flag); \
10104 } \
10105}
10106# define SAVE_PTR2(dst1,note1,flag1,dst2,note2,flag2) { \
10107 if (fs_size) { \
10108 MARK_PTR(dst1,note1,flag1); \
10109 MARK_PTR(dst2,note2,flag2); \
10110 } \
10111}
10112# define SAVE_PTR3(dst1,note1,flag1,dst2,note2,flag2,dst3,note3,flag3) { \
10113 if (fs_size) { \
10114 MARK_PTR(dst1,note1,flag1); \
10115 MARK_PTR(dst2,note2,flag2); \
10116 MARK_PTR(dst3,note3,flag3); \
10117 } \
10118}
10119#else
10120# define SAVE_PTR(dst,note,flag)
10121# define SAVE_PTR2(dst1,note1,flag1,dst2,note2,flag2)
10122# define SAVE_PTR3(dst1,note1,flag1,dst2,note2,flag2,dst3,note3,flag3)
10123#endif
10124
9083static struct nodelist * 10125static struct nodelist *
9084copynodelist(struct nodelist *lp) 10126copynodelist(struct nodelist *lp)
9085{ 10127{
@@ -9091,6 +10133,8 @@ copynodelist(struct nodelist *lp)
9091 *lpp = funcblock; 10133 *lpp = funcblock;
9092 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 10134 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
9093 (*lpp)->n = copynode(lp->n); 10135 (*lpp)->n = copynode(lp->n);
10136 SAVE_PTR2((*lpp)->n, "(*lpp)->next", NO_FREE,
10137 (*lpp)->next, "(*lpp)->next", NO_FREE);
9094 lp = lp->next; 10138 lp = lp->next;
9095 lpp = &(*lpp)->next; 10139 lpp = &(*lpp)->next;
9096 } 10140 }
@@ -9114,10 +10158,14 @@ copynode(union node *n)
9114 new->ncmd.args = copynode(n->ncmd.args); 10158 new->ncmd.args = copynode(n->ncmd.args);
9115 new->ncmd.assign = copynode(n->ncmd.assign); 10159 new->ncmd.assign = copynode(n->ncmd.assign);
9116 new->ncmd.linno = n->ncmd.linno; 10160 new->ncmd.linno = n->ncmd.linno;
10161 SAVE_PTR3(new->ncmd.redirect, "ncmd.redirect", NO_FREE,
10162 new->ncmd.args, "ncmd.args", NO_FREE,
10163 new->ncmd.assign, "ncmd.assign", NO_FREE);
9117 break; 10164 break;
9118 case NPIPE: 10165 case NPIPE:
9119 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 10166 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
9120 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 10167 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
10168 SAVE_PTR(new->npipe.cmdlist, "npipe.cmdlist", NO_FREE);
9121 break; 10169 break;
9122 case NREDIR: 10170 case NREDIR:
9123 case NBACKGND: 10171 case NBACKGND:
@@ -9125,6 +10173,8 @@ copynode(union node *n)
9125 new->nredir.redirect = copynode(n->nredir.redirect); 10173 new->nredir.redirect = copynode(n->nredir.redirect);
9126 new->nredir.n = copynode(n->nredir.n); 10174 new->nredir.n = copynode(n->nredir.n);
9127 new->nredir.linno = n->nredir.linno; 10175 new->nredir.linno = n->nredir.linno;
10176 SAVE_PTR2(new->nredir.redirect, "nredir.redirect", NO_FREE,
10177 new->nredir.n, "nredir.n", NO_FREE);
9128 break; 10178 break;
9129 case NAND: 10179 case NAND:
9130 case NOR: 10180 case NOR:
@@ -9133,37 +10183,58 @@ copynode(union node *n)
9133 case NUNTIL: 10183 case NUNTIL:
9134 new->nbinary.ch2 = copynode(n->nbinary.ch2); 10184 new->nbinary.ch2 = copynode(n->nbinary.ch2);
9135 new->nbinary.ch1 = copynode(n->nbinary.ch1); 10185 new->nbinary.ch1 = copynode(n->nbinary.ch1);
10186 SAVE_PTR2(new->nbinary.ch1, "nbinary.ch1", NO_FREE,
10187 new->nbinary.ch2, "nbinary.ch2", NO_FREE);
9136 break; 10188 break;
9137 case NIF: 10189 case NIF:
9138 new->nif.elsepart = copynode(n->nif.elsepart); 10190 new->nif.elsepart = copynode(n->nif.elsepart);
9139 new->nif.ifpart = copynode(n->nif.ifpart); 10191 new->nif.ifpart = copynode(n->nif.ifpart);
9140 new->nif.test = copynode(n->nif.test); 10192 new->nif.test = copynode(n->nif.test);
10193 SAVE_PTR3(new->nif.elsepart, "nif.elsepart", NO_FREE,
10194 new->nif.ifpart, "nif.ifpart", NO_FREE,
10195 new->nif.test, "nif.test", NO_FREE);
9141 break; 10196 break;
9142 case NFOR: 10197 case NFOR:
9143 new->nfor.var = nodeckstrdup(n->nfor.var); 10198 new->nfor.var = nodeckstrdup(n->nfor.var);
9144 new->nfor.body = copynode(n->nfor.body); 10199 new->nfor.body = copynode(n->nfor.body);
9145 new->nfor.args = copynode(n->nfor.args); 10200 new->nfor.args = copynode(n->nfor.args);
9146 new->nfor.linno = n->nfor.linno; 10201 new->nfor.linno = n->nfor.linno;
10202 SAVE_PTR3(new->nfor.var,
10203 xasprintf("nfor.var '%s'", n->nfor.var ?: "NULL"), FREE,
10204 new->nfor.body, "nfor.body", NO_FREE,
10205 new->nfor.args, "nfor.args", NO_FREE);
9147 break; 10206 break;
9148 case NCASE: 10207 case NCASE:
9149 new->ncase.cases = copynode(n->ncase.cases); 10208 new->ncase.cases = copynode(n->ncase.cases);
9150 new->ncase.expr = copynode(n->ncase.expr); 10209 new->ncase.expr = copynode(n->ncase.expr);
9151 new->ncase.linno = n->ncase.linno; 10210 new->ncase.linno = n->ncase.linno;
10211 SAVE_PTR2(new->ncase.cases, "ncase.cases", NO_FREE,
10212 new->ncase.expr, "ncase.expr", NO_FREE);
9152 break; 10213 break;
9153 case NCLIST: 10214 case NCLIST:
9154 new->nclist.body = copynode(n->nclist.body); 10215 new->nclist.body = copynode(n->nclist.body);
9155 new->nclist.pattern = copynode(n->nclist.pattern); 10216 new->nclist.pattern = copynode(n->nclist.pattern);
9156 new->nclist.next = copynode(n->nclist.next); 10217 new->nclist.next = copynode(n->nclist.next);
10218 SAVE_PTR3(new->nclist.body, "nclist.body", NO_FREE,
10219 new->nclist.pattern, "nclist.pattern", NO_FREE,
10220 new->nclist.next, "nclist.next", NO_FREE);
9157 break; 10221 break;
9158 case NDEFUN: 10222 case NDEFUN:
9159 new->ndefun.body = copynode(n->ndefun.body); 10223 new->ndefun.body = copynode(n->ndefun.body);
9160 new->ndefun.text = nodeckstrdup(n->ndefun.text); 10224 new->ndefun.text = nodeckstrdup(n->ndefun.text);
9161 new->ndefun.linno = n->ndefun.linno; 10225 new->ndefun.linno = n->ndefun.linno;
10226 SAVE_PTR2(new->ndefun.body, "ndefun.body", NO_FREE,
10227 new->ndefun.text,
10228 xasprintf("ndefun.text '%s'", n->ndefun.text ?: "NULL"), FREE);
9162 break; 10229 break;
9163 case NARG: 10230 case NARG:
9164 new->narg.backquote = copynodelist(n->narg.backquote); 10231 new->narg.backquote = copynodelist(n->narg.backquote);
9165 new->narg.text = nodeckstrdup(n->narg.text); 10232 new->narg.text = nodeckstrdup(n->narg.text);
9166 new->narg.next = copynode(n->narg.next); 10233 new->narg.next = copynode(n->narg.next);
10234 SAVE_PTR3(new->narg.backquote, "narg.backquote", NO_FREE,
10235 new->narg.text,
10236 xasprintf("narg.text '%s'", n->narg.text ?: "NULL"), FREE,
10237 new->narg.next, "narg.next", NO_FREE);
9167 break; 10238 break;
9168 case NTO: 10239 case NTO:
9169#if BASH_REDIR_OUTPUT 10240#if BASH_REDIR_OUTPUT
@@ -9176,6 +10247,8 @@ copynode(union node *n)
9176 new->nfile.fname = copynode(n->nfile.fname); 10247 new->nfile.fname = copynode(n->nfile.fname);
9177 new->nfile.fd = n->nfile.fd; 10248 new->nfile.fd = n->nfile.fd;
9178 new->nfile.next = copynode(n->nfile.next); 10249 new->nfile.next = copynode(n->nfile.next);
10250 SAVE_PTR2(new->nfile.fname, "nfile.fname", NO_FREE,
10251 new->nfile.next, "nfile.next", NO_FREE);
9179 break; 10252 break;
9180 case NTOFD: 10253 case NTOFD:
9181 case NFROMFD: 10254 case NFROMFD:
@@ -9183,15 +10256,20 @@ copynode(union node *n)
9183 new->ndup.dupfd = n->ndup.dupfd; 10256 new->ndup.dupfd = n->ndup.dupfd;
9184 new->ndup.fd = n->ndup.fd; 10257 new->ndup.fd = n->ndup.fd;
9185 new->ndup.next = copynode(n->ndup.next); 10258 new->ndup.next = copynode(n->ndup.next);
10259 SAVE_PTR2(new->ndup.vname, "ndup.vname", NO_FREE,
10260 new->ndup.next, "ndup.next", NO_FREE);
9186 break; 10261 break;
9187 case NHERE: 10262 case NHERE:
9188 case NXHERE: 10263 case NXHERE:
9189 new->nhere.doc = copynode(n->nhere.doc); 10264 new->nhere.doc = copynode(n->nhere.doc);
9190 new->nhere.fd = n->nhere.fd; 10265 new->nhere.fd = n->nhere.fd;
9191 new->nhere.next = copynode(n->nhere.next); 10266 new->nhere.next = copynode(n->nhere.next);
10267 SAVE_PTR2(new->nhere.doc, "nhere.doc", NO_FREE,
10268 new->nhere.next, "nhere.next", NO_FREE);
9192 break; 10269 break;
9193 case NNOT: 10270 case NNOT:
9194 new->nnot.com = copynode(n->nnot.com); 10271 new->nnot.com = copynode(n->nnot.com);
10272 SAVE_PTR(new->nnot.com, "nnot.com", NO_FREE);
9195 break; 10273 break;
9196 }; 10274 };
9197 new->type = n->type; 10275 new->type = n->type;
@@ -9212,6 +10290,7 @@ copyfunc(union node *n)
9212 f = ckzalloc(blocksize /* + funcstringsize */); 10290 f = ckzalloc(blocksize /* + funcstringsize */);
9213 funcblock = (char *) f + offsetof(struct funcnode, n); 10291 funcblock = (char *) f + offsetof(struct funcnode, n);
9214 funcstring_end = (char *) f + blocksize; 10292 funcstring_end = (char *) f + blocksize;
10293 IF_PLATFORM_MINGW32(fs_size = 0);
9215 copynode(n); 10294 copynode(n);
9216 /* f->count = 0; - ckzalloc did it */ 10295 /* f->count = 0; - ckzalloc did it */
9217 return f; 10296 return f;
@@ -9239,12 +10318,15 @@ defun(union node *func)
9239#define SKIPFUNCDEF (1 << 3) 10318#define SKIPFUNCDEF (1 << 3)
9240static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ 10319static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
9241static int skipcount; /* number of levels to skip */ 10320static int skipcount; /* number of levels to skip */
10321#if ENABLE_PLATFORM_POSIX
9242static int loopnest; /* current loop nesting level */ 10322static int loopnest; /* current loop nesting level */
10323#endif
9243static int funcline; /* starting line number of current function, or 0 if not in a function */ 10324static int funcline; /* starting line number of current function, or 0 if not in a function */
9244 10325
9245/* Forward decl way out to parsing code - dotrap needs it */ 10326/* Forward decl way out to parsing code - dotrap needs it */
9246static int evalstring(char *s, int flags); 10327static int evalstring(char *s, int flags);
9247 10328
10329#if !ENABLE_PLATFORM_MINGW32
9248/* Called to execute a trap. 10330/* Called to execute a trap.
9249 * Single callsite - at the end of evaltree(). 10331 * Single callsite - at the end of evaltree().
9250 * If we return non-zero, evaltree raises EXEXIT exception. 10332 * If we return non-zero, evaltree raises EXEXIT exception.
@@ -9303,6 +10385,45 @@ dotrap(void)
9303 savestatus = last_status; 10385 savestatus = last_status;
9304 TRACE(("dotrap returns\n")); 10386 TRACE(("dotrap returns\n"));
9305} 10387}
10388#else
10389static void
10390dotrap(void)
10391{
10392 int status, last_status;
10393 char *p;
10394
10395 if (!pending_int)
10396 return;
10397
10398 status = savestatus;
10399 last_status = status;
10400 if (status < 0) {
10401 status = exitstatus;
10402 savestatus = status;
10403 }
10404 pending_int = 0;
10405 barrier();
10406
10407 TRACE(("dotrap entered\n"));
10408 if (evalskip) {
10409 pending_int = 1;
10410 return;
10411 }
10412
10413 p = trap[SIGINT];
10414 if (p) {
10415 TRACE(("sig %d is active, will run handler '%s'\n", SIGINT, p));
10416 trap_depth++;
10417 evalstring(p, 0);
10418 trap_depth--;
10419 if (evalskip != SKIPFUNC)
10420 exitstatus = status;
10421 }
10422
10423 savestatus = last_status;
10424 TRACE(("dotrap returns\n"));
10425}
10426#endif
9306 10427
9307/* forward declarations - evaluation is fairly recursive business... */ 10428/* forward declarations - evaluation is fairly recursive business... */
9308static int evalloop(union node *, int); 10429static int evalloop(union node *, int);
@@ -9588,19 +10709,36 @@ evalcase(union node *n, int flags)
9588static int 10709static int
9589evalsubshell(union node *n, int flags) 10710evalsubshell(union node *n, int flags)
9590{ 10711{
10712 IF_PLATFORM_MINGW32(struct forkshell fs;)
9591 struct job *jp; 10713 struct job *jp;
9592 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ 10714 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
9593 int status; 10715 int status;
9594 10716
9595 errlinno = lineno = n->nredir.linno; 10717 errlinno = lineno = n->nredir.linno;
9596 10718
10719#if ENABLE_PLATFORM_MINGW32
10720 if (!backgnd && (flags & EV_EXIT) && !may_have_traps) {
10721 expredir(n->nredir.redirect);
10722 redirect(n->nredir.redirect, 0);
10723 evaltreenr(n->nredir.n, flags);
10724 /* never returns */
10725 }
10726#else
9597 expredir(n->nredir.redirect); 10727 expredir(n->nredir.redirect);
9598 if (!backgnd && (flags & EV_EXIT) && !may_have_traps) 10728 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
9599 goto nofork; 10729 goto nofork;
10730#endif
9600 INT_OFF; 10731 INT_OFF;
9601 if (backgnd == FORK_FG) 10732 if (backgnd == FORK_FG)
9602 get_tty_state(); 10733 get_tty_state();
9603 jp = makejob(/*n,*/ 1); 10734 jp = makejob(/*n,*/ 1);
10735#if ENABLE_PLATFORM_MINGW32
10736 memset(&fs, 0, sizeof(fs));
10737 fs.fpid = FS_EVALSUBSHELL;
10738 fs.n = n;
10739 fs.flags = flags;
10740 spawn_forkshell(&fs, jp, n, backgnd);
10741#else
9604 if (forkshell(jp, n, backgnd) == 0) { 10742 if (forkshell(jp, n, backgnd) == 0) {
9605 /* child */ 10743 /* child */
9606 INT_ON; 10744 INT_ON;
@@ -9612,6 +10750,7 @@ evalsubshell(union node *n, int flags)
9612 evaltreenr(n->nredir.n, flags); 10750 evaltreenr(n->nredir.n, flags);
9613 /* never returns */ 10751 /* never returns */
9614 } 10752 }
10753#endif
9615 /* parent */ 10754 /* parent */
9616 status = 0; 10755 status = 0;
9617 if (backgnd == FORK_FG) 10756 if (backgnd == FORK_FG)
@@ -9692,6 +10831,7 @@ expredir(union node *n)
9692static int 10831static int
9693evalpipe(union node *n, int flags) 10832evalpipe(union node *n, int flags)
9694{ 10833{
10834 IF_PLATFORM_MINGW32(struct forkshell fs;)
9695 struct job *jp; 10835 struct job *jp;
9696 struct nodelist *lp; 10836 struct nodelist *lp;
9697 int pipelen; 10837 int pipelen;
@@ -9718,6 +10858,16 @@ evalpipe(union node *n, int flags)
9718 ash_msg_and_raise_perror("can't create pipe"); 10858 ash_msg_and_raise_perror("can't create pipe");
9719 } 10859 }
9720 } 10860 }
10861#if ENABLE_PLATFORM_MINGW32
10862 memset(&fs, 0, sizeof(fs));
10863 fs.fpid = FS_EVALPIPE;
10864 fs.flags = flags;
10865 fs.n = lp->n;
10866 fs.fd[0] = pip[0];
10867 fs.fd[1] = pip[1];
10868 fs.fd[2] = prevfd;
10869 spawn_forkshell(&fs, jp, lp->n, n->npipe.pipe_backgnd);
10870#else
9721 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 10871 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
9722 /* child */ 10872 /* child */
9723 INT_ON; 10873 INT_ON;
@@ -9735,6 +10885,7 @@ evalpipe(union node *n, int flags)
9735 evaltreenr(lp->n, flags); 10885 evaltreenr(lp->n, flags);
9736 /* never returns */ 10886 /* never returns */
9737 } 10887 }
10888#endif
9738 /* parent */ 10889 /* parent */
9739 if (prevfd >= 0) 10890 if (prevfd >= 0)
9740 close(prevfd); 10891 close(prevfd);
@@ -9792,6 +10943,9 @@ setinteractive(int on)
9792 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); 10943 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
9793# if ENABLE_FEATURE_TAB_COMPLETION 10944# if ENABLE_FEATURE_TAB_COMPLETION
9794 line_input_state->get_exe_name = ash_command_name; 10945 line_input_state->get_exe_name = ash_command_name;
10946# if ENABLE_ASH_GLOB_OPTIONS
10947 line_input_state->sh_accept_glob = ash_accept_glob;
10948# endif
9795# endif 10949# endif
9796# if EDITING_HAS_sh_get_var 10950# if EDITING_HAS_sh_get_var
9797 line_input_state->sh_get_var = lookupvar; 10951 line_input_state->sh_get_var = lookupvar;
@@ -9819,6 +10973,12 @@ optschanged(void)
9819#else 10973#else
9820 viflag = 0; /* forcibly keep the option off */ 10974 viflag = 0; /* forcibly keep the option off */
9821#endif 10975#endif
10976#if ENABLE_ASH_NOCONSOLE
10977 hide_console(noconsole);
10978#endif
10979#if ENABLE_PLATFORM_MINGW32
10980 setwinxp(winxp);
10981#endif
9822} 10982}
9823 10983
9824struct localvar_list { 10984struct localvar_list {
@@ -9838,6 +10998,9 @@ poplocalvars(int keep)
9838 struct localvar_list *ll; 10998 struct localvar_list *ll;
9839 struct localvar *lvp, *next; 10999 struct localvar *lvp, *next;
9840 struct var *vp; 11000 struct var *vp;
11001#if ENABLE_PLATFORM_MINGW32
11002 int var_type;
11003#endif
9841 11004
9842 INT_OFF; 11005 INT_OFF;
9843 ll = localvar_stack; 11006 ll = localvar_stack;
@@ -9880,6 +11043,17 @@ poplocalvars(int keep)
9880 free((char*)vp->var_text); 11043 free((char*)vp->var_text);
9881 vp->flags = lvp->flags; 11044 vp->flags = lvp->flags;
9882 vp->var_text = lvp->text; 11045 vp->var_text = lvp->text;
11046#if ENABLE_PLATFORM_MINGW32
11047 var_type = is_bb_var(lvp->text);
11048 if (var_type == BB_VAR_ASSIGN && (lvp->flags & VEXPORT))
11049 putenv(lvp->text);
11050 else if (var_type) {
11051 char *var = xstrdup(lvp->text);
11052 *strchrnul(var, '=') = '\0';
11053 unsetenv(var);
11054 free(var);
11055 }
11056#endif
9883 } 11057 }
9884 free(lvp); 11058 free(lvp);
9885 } 11059 }
@@ -10102,7 +11276,7 @@ execcmd(int argc UNUSED_PARAM, char **argv)
10102 prog = argv[0]; 11276 prog = argv[0];
10103 if (optionarg) 11277 if (optionarg)
10104 argv[0] = optionarg; 11278 argv[0] = optionarg;
10105 shellexec(prog, argv, pathval(), 0); 11279 shellexec(prog, argv, pathval(), 0, FALSE);
10106 /* NOTREACHED */ 11280 /* NOTREACHED */
10107 } 11281 }
10108 return 0; 11282 return 0;
@@ -10155,6 +11329,9 @@ static int readcmd(int, char **) FAST_FUNC;
10155static int setcmd(int, char **) FAST_FUNC; 11329static int setcmd(int, char **) FAST_FUNC;
10156static int shiftcmd(int, char **) FAST_FUNC; 11330static int shiftcmd(int, char **) FAST_FUNC;
10157static int timescmd(int, char **) FAST_FUNC; 11331static int timescmd(int, char **) FAST_FUNC;
11332#if ENABLE_PLATFORM_MINGW32
11333static int titlecmd(int, char **) FAST_FUNC;
11334#endif
10158static int trapcmd(int, char **) FAST_FUNC; 11335static int trapcmd(int, char **) FAST_FUNC;
10159static int umaskcmd(int, char **) FAST_FUNC; 11336static int umaskcmd(int, char **) FAST_FUNC;
10160static int unsetcmd(int, char **) FAST_FUNC; 11337static int unsetcmd(int, char **) FAST_FUNC;
@@ -10227,7 +11404,7 @@ static const struct builtincmd builtintab[] = {
10227#if MAX_HISTORY 11404#if MAX_HISTORY
10228 { BUILTIN_NOSPEC "history" , historycmd }, 11405 { BUILTIN_NOSPEC "history" , historycmd },
10229#endif 11406#endif
10230#if JOBS 11407#if JOBS || JOBS_WIN32
10231 { BUILTIN_REGULAR "jobs" , jobscmd }, 11408 { BUILTIN_REGULAR "jobs" , jobscmd },
10232 { BUILTIN_REGULAR "kill" , killcmd }, 11409 { BUILTIN_REGULAR "kill" , killcmd },
10233#endif 11410#endif
@@ -10254,6 +11431,9 @@ static const struct builtincmd builtintab[] = {
10254 { BUILTIN_REGULAR "test" , testcmd }, 11431 { BUILTIN_REGULAR "test" , testcmd },
10255#endif 11432#endif
10256 { BUILTIN_SPEC_REG "times" , timescmd }, 11433 { BUILTIN_SPEC_REG "times" , timescmd },
11434#if ENABLE_PLATFORM_MINGW32
11435 { BUILTIN_REGULAR "title" , titlecmd },
11436#endif
10257 { BUILTIN_SPEC_REG "trap" , trapcmd }, 11437 { BUILTIN_SPEC_REG "trap" , trapcmd },
10258 { BUILTIN_REGULAR "true" , truecmd }, 11438 { BUILTIN_REGULAR "true" , truecmd },
10259 { BUILTIN_REGULAR "type" , typecmd }, 11439 { BUILTIN_REGULAR "type" , typecmd },
@@ -10272,7 +11452,7 @@ static const struct builtincmd builtintab[] = {
10272 /* [ */ 1 * ENABLE_ASH_TEST + \ 11452 /* [ */ 1 * ENABLE_ASH_TEST + \
10273 /* [[ */ 1 * BASH_TEST2 + \ 11453 /* [[ */ 1 * BASH_TEST2 + \
10274 /* alias */ 1 * ENABLE_ASH_ALIAS + \ 11454 /* alias */ 1 * ENABLE_ASH_ALIAS + \
10275 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \ 11455 /* bg */ 1 * JOBS + \
10276 /* break cd cddir */ 3) 11456 /* break cd cddir */ 3)
10277#define EVALCMD (COMMANDCMD + \ 11457#define EVALCMD (COMMANDCMD + \
10278 /* command */ 1 * ENABLE_ASH_CMDCMD + \ 11458 /* command */ 1 * ENABLE_ASH_CMDCMD + \
@@ -10353,6 +11533,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10353 * as POSIX mandates */ 11533 * as POSIX mandates */
10354 return back_exitstatus; 11534 return back_exitstatus;
10355} 11535}
11536
10356static int 11537static int
10357evalcommand(union node *cmd, int flags) 11538evalcommand(union node *cmd, int flags)
10358{ 11539{
@@ -10452,9 +11633,19 @@ evalcommand(union node *cmd, int flags)
10452 11633
10453 localvar_stop = pushlocalvars(vlocal); 11634 localvar_stop = pushlocalvars(vlocal);
10454 11635
11636#if ENABLE_PLATFORM_MINGW32
11637# if ENABLE_FEATURE_SH_STANDALONE
11638 /* Reserve two extra spots at the front for shellexec. */
11639 nargv = stalloc(sizeof(char *) * (argc + 3));
11640 argv = nargv = nargv + 2;
11641# else
11642 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
11643# endif
11644#else
10455 /* Reserve one extra spot at the front for shellexec. */ 11645 /* Reserve one extra spot at the front for shellexec. */
10456 nargv = stalloc(sizeof(char *) * (argc + 2)); 11646 nargv = stalloc(sizeof(char *) * (argc + 2));
10457 argv = ++nargv; 11647 argv = ++nargv;
11648#endif
10458 for (sp = arglist.list; sp; sp = sp->next) { 11649 for (sp = arglist.list; sp; sp = sp->next) {
10459 TRACE(("evalcommand arg: %s\n", sp->text)); 11650 TRACE(("evalcommand arg: %s\n", sp->text));
10460 *nargv++ = sp->text; 11651 *nargv++ = sp->text;
@@ -10563,9 +11754,11 @@ evalcommand(union node *cmd, int flags)
10563 11754
10564 default: { 11755 default: {
10565 11756
11757//TODO: find a better solution for Windows on ARM than ignoring NOFORK
10566#if ENABLE_FEATURE_SH_STANDALONE \ 11758#if ENABLE_FEATURE_SH_STANDALONE \
10567 && ENABLE_FEATURE_SH_NOFORK \ 11759 && ENABLE_FEATURE_SH_NOFORK \
10568 && NUM_APPLETS > 1 11760 && NUM_APPLETS > 1 \
11761 && !(defined(_ARM64_) && !defined(_UCRT) && ENABLE_PLATFORM_MINGW32)
10569/* (1) BUG: if variables are set, we need to fork, or save/restore them 11762/* (1) BUG: if variables are set, we need to fork, or save/restore them
10570 * around run_nofork_applet() call. 11763 * around run_nofork_applet() call.
10571 * (2) Should this check also be done in forkshell()? 11764 * (2) Should this check also be done in forkshell()?
@@ -10575,6 +11768,9 @@ evalcommand(union node *cmd, int flags)
10575 int applet_no = (- cmdentry.u.index - 2); 11768 int applet_no = (- cmdentry.u.index - 2);
10576 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { 11769 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
10577 char **sv_environ; 11770 char **sv_environ;
11771#if ENABLE_PLATFORM_MINGW32
11772 char *sv_argv0;
11773#endif
10578 11774
10579 INT_OFF; 11775 INT_OFF;
10580 sv_environ = environ; 11776 sv_environ = environ;
@@ -10587,8 +11783,16 @@ evalcommand(union node *cmd, int flags)
10587 * and/or wait for user input ineligible for NOFORK: 11783 * and/or wait for user input ineligible for NOFORK:
10588 * for example, "yes" or "rm" (rm -i waits for input). 11784 * for example, "yes" or "rm" (rm -i waits for input).
10589 */ 11785 */
11786#if ENABLE_PLATFORM_MINGW32
11787 sv_argv0 = __argv[0];
11788 argv[0] = (char *)bb_basename(argv[0]);
11789 __argv[0] = argv[0];
11790#endif
10590 exitstatus = run_nofork_applet(applet_no, argv); 11791 exitstatus = run_nofork_applet(applet_no, argv);
10591 environ = sv_environ; 11792 environ = sv_environ;
11793#if ENABLE_PLATFORM_MINGW32
11794 __argv[0] = sv_argv0;
11795#endif
10592 /* 11796 /*
10593 * Try enabling NOFORK for "yes" applet. 11797 * Try enabling NOFORK for "yes" applet.
10594 * ^C _will_ stop it (write returns EINTR), 11798 * ^C _will_ stop it (write returns EINTR),
@@ -10606,6 +11810,22 @@ evalcommand(union node *cmd, int flags)
10606 * in a script or a subshell does not need forking, 11810 * in a script or a subshell does not need forking,
10607 * we can just exec it. 11811 * we can just exec it.
10608 */ 11812 */
11813#if ENABLE_PLATFORM_MINGW32
11814 if (!(flags & EV_EXIT) || may_have_traps IF_SUW32(|| delayexit)) {
11815 /* No, forking off a child is necessary */
11816 struct forkshell fs;
11817
11818 INT_OFF;
11819 memset(&fs, 0, sizeof(fs));
11820 fs.fpid = FS_SHELLEXEC;
11821 fs.argv = argv;
11822 fs.path = (char*)path;
11823 fs.fd[0] = cmdentry.u.index;
11824 jp = makejob(/*cmd,*/ 1);
11825 spawn_forkshell(&fs, jp, cmd, FORK_FG);
11826 break;
11827 }
11828#else
10609 if (!(flags & EV_EXIT) || may_have_traps) { 11829 if (!(flags & EV_EXIT) || may_have_traps) {
10610 /* No, forking off a child is necessary */ 11830 /* No, forking off a child is necessary */
10611 INT_OFF; 11831 INT_OFF;
@@ -10619,7 +11839,8 @@ evalcommand(union node *cmd, int flags)
10619 FORCE_INT_ON; 11839 FORCE_INT_ON;
10620 /* fall through to exec'ing external program */ 11840 /* fall through to exec'ing external program */
10621 } 11841 }
10622 shellexec(argv[0], argv, path, cmdentry.u.index); 11842#endif
11843 shellexec(argv[0], argv, path, cmdentry.u.index, FALSE);
10623 /* NOTREACHED */ 11844 /* NOTREACHED */
10624 } /* default */ 11845 } /* default */
10625 case CMDBUILTIN: 11846 case CMDBUILTIN:
@@ -10831,6 +12052,54 @@ static void popstring(void)
10831 INT_ON; 12052 INT_ON;
10832} 12053}
10833 12054
12055#if ENABLE_PLATFORM_MINGW32
12056/*
12057 * Wrapper around nonblock_immune_read() to remove CRs, but only from
12058 * CRLF pairs. The tricky part is handling a CR at the end of the buffer.
12059 */
12060static inline ssize_t
12061nonblock_immune_wrapper(struct parsefile *pf, char *buffer, size_t count)
12062{
12063 int nr, injected_cr;
12064
12065 // Inject unprocessed CR from previous read into the buffer.
12066 if (pf->cr)
12067 *buffer = '\r';
12068 retry:
12069 nr = nonblock_immune_read(pf->pf_fd, buffer + pf->cr, count - pf->cr);
12070 if (nr < 0)
12071 return nr;
12072
12073 injected_cr = pf->cr;
12074 nr += pf->cr;
12075 pf->cr = 0;
12076
12077 if (nr > 0) {
12078 nr = remove_cr(buffer, nr);
12079 // remove_cr() won't reduce size to zero, so [nr - 1] is OK.
12080 if (buffer[nr - 1] == '\r') {
12081 if (nr > 1) {
12082 // Ignore trailing CR for now: we'll deal with it later.
12083 pf->cr = 1;
12084 --nr;
12085 } else if (injected_cr) { // nr == 1
12086 // Buffer only contains an injected CR. This means the
12087 // read returned EOF. Return the buffer as-is. The
12088 // next call will detect EOF.
12089 } else {
12090 // Buffer only contains a CR from the most recent read.
12091 // Try another read, treating the CR as injected. We'll
12092 // either get more characters or EOF. Either way we
12093 // won't end up here again.
12094 pf->cr = 1;
12095 goto retry;
12096 }
12097 }
12098 }
12099 return nr;
12100}
12101#endif
12102
10834static int 12103static int
10835preadfd(void) 12104preadfd(void)
10836{ 12105{
@@ -10841,7 +12110,11 @@ preadfd(void)
10841#if ENABLE_FEATURE_EDITING 12110#if ENABLE_FEATURE_EDITING
10842 /* retry: */ 12111 /* retry: */
10843 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) 12112 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
12113#if ENABLE_PLATFORM_MINGW32
12114 nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1);
12115#else
10844 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 12116 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
12117#endif
10845 else { 12118 else {
10846# if ENABLE_ASH_IDLE_TIMEOUT 12119# if ENABLE_ASH_IDLE_TIMEOUT
10847 int timeout = -1; 12120 int timeout = -1;
@@ -10880,12 +12153,21 @@ preadfd(void)
10880 INT_ON; /* here non-blocked SIGINT will longjmp */ 12153 INT_ON; /* here non-blocked SIGINT will longjmp */
10881 if (nr == 0) { 12154 if (nr == 0) {
10882 /* ^C pressed, "convert" to SIGINT */ 12155 /* ^C pressed, "convert" to SIGINT */
12156# if !ENABLE_PLATFORM_MINGW32
10883 write(STDOUT_FILENO, "^C\n", 3); 12157 write(STDOUT_FILENO, "^C\n", 3);
10884 raise(SIGINT); /* here non-blocked SIGINT will longjmp */ 12158 raise(SIGINT); /* here non-blocked SIGINT will longjmp */
10885 /* raise(SIGINT) did not work! (e.g. if SIGINT 12159 /* raise(SIGINT) did not work! (e.g. if SIGINT
10886 * is SIG_IGNed on startup, it stays SIG_IGNed) 12160 * is SIG_IGNed on startup, it stays SIG_IGNed)
10887 */ 12161 */
12162# else
12163 raise_interrupt();
12164 write(STDOUT_FILENO, "^C\n", 3);
12165# endif
10888 if (trap[SIGINT]) { 12166 if (trap[SIGINT]) {
12167# if ENABLE_PLATFORM_MINGW32
12168 pending_int = 1;
12169 dotrap();
12170# endif
10889 empty_line_input: 12171 empty_line_input:
10890 buf[0] = '\n'; 12172 buf[0] = '\n';
10891 buf[1] = '\0'; 12173 buf[1] = '\0';
@@ -10914,7 +12196,11 @@ preadfd(void)
10914 } 12196 }
10915 } 12197 }
10916#else 12198#else
12199# if ENABLE_PLATFORM_MINGW32
12200 nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1);
12201# else
10917 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 12202 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
12203# endif
10918#endif 12204#endif
10919 12205
10920#if 0 /* disabled: nonblock_immune_read() handles this problem */ 12206#if 0 /* disabled: nonblock_immune_read() handles this problem */
@@ -11213,6 +12499,7 @@ popallfiles(void)
11213 unwindfiles(&basepf); 12499 unwindfiles(&basepf);
11214} 12500}
11215 12501
12502#if !ENABLE_PLATFORM_MINGW32
11216/* 12503/*
11217 * Close the file(s) that the shell is reading commands from. Called 12504 * Close the file(s) that the shell is reading commands from. Called
11218 * after a fork is done. 12505 * after a fork is done.
@@ -11226,6 +12513,7 @@ closescript(void)
11226 g_parsefile->pf_fd = 0; 12513 g_parsefile->pf_fd = 0;
11227 } 12514 }
11228} 12515}
12516#endif
11229 12517
11230/* 12518/*
11231 * Like setinputfile, but takes an open file descriptor. Call this with 12519 * Like setinputfile, but takes an open file descriptor. Call this with
@@ -11462,8 +12750,19 @@ options(int *login_sh)
11462 int val; 12750 int val;
11463 int c; 12751 int c;
11464 12752
11465 if (login_sh != NULL) /* if we came from startup code */ 12753#if ENABLE_ASH_NOCONSOLE
12754 noconsole = console_state();
12755#endif
12756 if (login_sh != NULL) { /* if we came from startup code */
11466 minusc = NULL; 12757 minusc = NULL;
12758#if ENABLE_PLATFORM_MINGW32
12759 dirarg = NULL;
12760 title = NULL;
12761# if ENABLE_SUW32
12762 delayexit = 0;
12763# endif
12764#endif
12765 }
11467 while ((p = *argptr) != NULL) { 12766 while ((p = *argptr) != NULL) {
11468 c = *p++; 12767 c = *p++;
11469 if (c != '-' && c != '+') 12768 if (c != '-' && c != '+')
@@ -11493,6 +12792,31 @@ options(int *login_sh)
11493 cflag = 1; 12792 cflag = 1;
11494 continue; 12793 continue;
11495 } 12794 }
12795#if ENABLE_PLATFORM_MINGW32
12796 /* Undocumented flags;
12797 * -d force current directory
12798 * -t title to display in console window
12799 * -N prompt user before exit
12800 * Must appear before -s or -c. */
12801 if (c == 'd' && val == 1) {
12802 if (*argptr == NULL)
12803 ash_msg_and_raise_error(bb_msg_requires_arg, "-d");
12804 dirarg = *argptr++;
12805 continue;
12806 }
12807 if (c == 't' && val == 1) {
12808 if (*argptr == NULL)
12809 ash_msg_and_raise_error(bb_msg_requires_arg, "-t");
12810 title = *argptr++;
12811 continue;
12812 }
12813# if ENABLE_SUW32
12814 if (c == 'N' && val == 1) {
12815 delayexit = 1;
12816 continue;
12817 }
12818# endif
12819#endif
11496 if (c == 's') { /* -s, +s */ 12820 if (c == 's') { /* -s, +s */
11497 sflag = 1; 12821 sflag = 1;
11498 continue; 12822 continue;
@@ -13528,6 +14852,9 @@ evalstring(char *s, int flags)
13528 int status; 14852 int status;
13529 14853
13530 s = sstrdup(s); 14854 s = sstrdup(s);
14855#if ENABLE_PLATFORM_MINGW32
14856 remove_cr(s, strlen(s)+1);
14857#endif
13531 setinputstring(s); 14858 setinputstring(s);
13532 setstackmark(&smark); 14859 setstackmark(&smark);
13533 14860
@@ -13615,7 +14942,7 @@ cmdloop(int top)
13615 int skip; 14942 int skip;
13616 14943
13617 setstackmark(&smark); 14944 setstackmark(&smark);
13618#if JOBS 14945#if JOBS || JOBS_WIN32
13619 if (doing_jobctl) 14946 if (doing_jobctl)
13620 showjobs(SHOW_CHANGED|SHOW_STDERR); 14947 showjobs(SHOW_CHANGED|SHOW_STDERR);
13621#endif 14948#endif
@@ -13623,6 +14950,9 @@ cmdloop(int top)
13623 if (iflag && top) { 14950 if (iflag && top) {
13624 inter++; 14951 inter++;
13625 chkmail(); 14952 chkmail();
14953#if ENABLE_PLATFORM_MINGW32
14954 terminal_mode(TRUE);
14955#endif
13626 } 14956 }
13627 n = parsecmd(inter); 14957 n = parsecmd(inter);
13628#if DEBUG 14958#if DEBUG
@@ -13646,8 +14976,10 @@ cmdloop(int top)
13646 } else { 14976 } else {
13647 int i; 14977 int i;
13648 14978
14979#if !ENABLE_PLATFORM_MINGW32
13649 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ 14980 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13650 job_warning >>= 1; 14981 job_warning >>= 1;
14982#endif
13651 numeof = 0; 14983 numeof = 0;
13652 i = evaltree(n, 0); 14984 i = evaltree(n, 0);
13653 if (n) 14985 if (n)
@@ -13677,7 +15009,7 @@ find_dot_file(char *basename)
13677 int len; 15009 int len;
13678 15010
13679 /* don't try this for absolute or relative paths */ 15011 /* don't try this for absolute or relative paths */
13680 if (strchr(basename, '/')) 15012 if (strchr(basename, '/') IF_PLATFORM_MINGW32(|| strchr(basename, '\\')))
13681 return basename; 15013 return basename;
13682 15014
13683 path = pathval(); 15015 path = pathval();
@@ -13842,6 +15174,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13842 struct builtincmd *bcmd; 15174 struct builtincmd *bcmd;
13843 int len; 15175 int len;
13844 15176
15177#if !ENABLE_PLATFORM_MINGW32
13845 /* If name contains a slash, don't use PATH or hash table */ 15178 /* If name contains a slash, don't use PATH or hash table */
13846 if (strchr(name, '/') != NULL) { 15179 if (strchr(name, '/') != NULL) {
13847 entry->u.index = -1; 15180 entry->u.index = -1;
@@ -13861,6 +15194,35 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13861 entry->cmdtype = CMDNORMAL; 15194 entry->cmdtype = CMDNORMAL;
13862 return; 15195 return;
13863 } 15196 }
15197#else /* ENABLE_PLATFORM_MINGW32 */
15198 /* If name contains a slash or drive prefix, don't use PATH or hash table */
15199 if (has_path(name)) {
15200 entry->u.index = -1;
15201 entry->cmdtype = CMDNORMAL;
15202 fullname = stack_add_ext_space(name);
15203 if (add_win32_extension(fullname)) {
15204 return;
15205 } else if (unix_path(name)) {
15206 name = (char *)bb_basename(name);
15207 if (
15208# if ENABLE_FEATURE_SH_STANDALONE
15209 find_applet_by_name_for_sh(name, path) >= 0 ||
15210# endif
15211 !find_builtin(bb_basename(name))
15212 ) {
15213 act |= DO_NOFUNC;
15214 } else if (act & DO_ABS) {
15215 entry->cmdtype = CMDUNKNOWN;
15216 return;
15217 }
15218 } else if (act & DO_ABS) {
15219 entry->cmdtype = CMDUNKNOWN;
15220 return;
15221 } else {
15222 return;
15223 }
15224 }
15225#endif /* ENABLE_PLATFORM_MINGW32 */
13864 15226
13865/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ 15227/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
13866 15228
@@ -13915,7 +15277,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13915 15277
13916#if ENABLE_FEATURE_SH_STANDALONE 15278#if ENABLE_FEATURE_SH_STANDALONE
13917 { 15279 {
13918 int applet_no = find_applet_by_name(name); 15280 int applet_no = find_applet_by_name_for_sh(name, path);
13919 if (applet_no >= 0) { 15281 if (applet_no >= 0) {
13920 entry->cmdtype = CMDNORMAL; 15282 entry->cmdtype = CMDNORMAL;
13921 entry->u.index = -2 - applet_no; 15283 entry->u.index = -2 - applet_no;
@@ -13954,12 +15316,15 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13954 } 15316 }
13955 } 15317 }
13956 /* if rehash, don't redo absolute path names */ 15318 /* if rehash, don't redo absolute path names */
13957 if (fullname[0] == '/' && idx <= prev) { 15319 if (!is_relative_path(fullname) && idx <= prev) {
13958 if (idx < prev) 15320 if (idx < prev)
13959 continue; 15321 continue;
13960 TRACE(("searchexec \"%s\": no change\n", name)); 15322 TRACE(("searchexec \"%s\": no change\n", name));
13961 goto success; 15323 goto success;
13962 } 15324 }
15325#if ENABLE_PLATFORM_MINGW32
15326 add_win32_extension(fullname);
15327#endif
13963 while (stat(fullname, &statb) < 0) { 15328 while (stat(fullname, &statb) < 0) {
13964#ifdef SYSV 15329#ifdef SYSV
13965 if (errno == EINTR) 15330 if (errno == EINTR)
@@ -14098,19 +15463,45 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14098 if (LONE_DASH(action)) 15463 if (LONE_DASH(action))
14099 action = NULL; 15464 action = NULL;
14100 else { 15465 else {
15466#if !ENABLE_PLATFORM_MINGW32
14101 if (action[0]) /* not NULL and not "" and not "-" */ 15467 if (action[0]) /* not NULL and not "" and not "-" */
14102 may_have_traps = 1; 15468 may_have_traps = 1;
15469#endif
14103 action = ckstrdup(action); 15470 action = ckstrdup(action);
14104 } 15471 }
14105 } 15472 }
14106 free(trap[signo]); 15473 free(trap[signo]);
14107 trap[signo] = action; 15474 trap[signo] = action;
15475#if ENABLE_PLATFORM_MINGW32
15476 if (signo == SIGINT) {
15477 // trap '' INT disables Ctrl-C, anything else enables it
15478 if (action && action[0] == '\0') {
15479 SetConsoleCtrlHandler(NULL, TRUE);
15480# if ENABLE_FEATURE_EDITING
15481 if (line_input_state) {
15482 line_input_state->flags |= IGNORE_CTRL_C;
15483 }
15484# endif
15485 } else {
15486 SetConsoleCtrlHandler(NULL, FALSE);
15487# if ENABLE_FEATURE_EDITING
15488 if (line_input_state) {
15489 line_input_state->flags &= ~IGNORE_CTRL_C;
15490 }
15491# endif
15492 }
15493 }
15494#else
14108 if (signo != 0 && signo < NSIG) 15495 if (signo != 0 && signo < NSIG)
14109 setsignal(signo); 15496 setsignal(signo);
15497#endif
14110 INT_ON; 15498 INT_ON;
14111 next: 15499 next:
14112 ap++; 15500 ap++;
14113 } 15501 }
15502#if ENABLE_PLATFORM_MINGW32
15503 may_have_traps = trap[SIGINT] && trap[SIGINT][0] != '\0';
15504#endif
14114 return exitcode; 15505 return exitcode;
14115} 15506}
14116 15507
@@ -14139,10 +15530,12 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14139 { 15530 {
14140 const char *a = applet_names; 15531 const char *a = applet_names;
14141 while (*a) { 15532 while (*a) {
14142 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a); 15533 if (prefer_applet(a, pathval())) {
14143 if (col > 60) { 15534 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
14144 out1fmt("\n"); 15535 if (col > 60) {
14145 col = 0; 15536 out1fmt("\n");
15537 col = 0;
15538 }
14146 } 15539 }
14147 while (*a++ != '\0') 15540 while (*a++ != '\0')
14148 continue; 15541 continue;
@@ -14204,7 +15597,24 @@ exportcmd(int argc UNUSED_PARAM, char **argv)
14204 } else { 15597 } else {
14205 vp = *findvar(name); 15598 vp = *findvar(name);
14206 if (vp) { 15599 if (vp) {
15600#if ENABLE_PLATFORM_MINGW32
15601 if (is_bb_var(name) == BB_VAR_EXACT) {
15602 if (flag_off == ~VEXPORT)
15603 unsetenv(name);
15604 else if (flag == VEXPORT && !(vp->flags & VUNSET))
15605 putenv(vp->var_text);
15606 }
15607#endif
14207 vp->flags = ((vp->flags | flag) & flag_off); 15608 vp->flags = ((vp->flags | flag) & flag_off);
15609#if ENABLE_PLATFORM_MINGW32
15610 /* Unexporting a variable imported from the
15611 * environment restores its original value and
15612 * removes the VIMPORT flag. */
15613 if ((vp->flags & VIMPORT) && (flag_off == ~VEXPORT)) {
15614 vp->flags &= ~VIMPORT;
15615 p = getenv(name);
15616 } else
15617#endif
14208 continue; 15618 continue;
14209 } 15619 }
14210 } 15620 }
@@ -14295,6 +15705,21 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14295 return 0; 15705 return 0;
14296} 15706}
14297 15707
15708#if ENABLE_PLATFORM_MINGW32
15709static int FAST_FUNC
15710titlecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
15711{
15712 if (*argptr == NULL) {
15713 char buffer[256];
15714 if (get_title(buffer, sizeof(buffer)))
15715 puts(buffer);
15716 } else {
15717 set_title(*argptr);
15718 }
15719 return 0;
15720}
15721#endif
15722
14298#if ENABLE_FEATURE_SH_MATH 15723#if ENABLE_FEATURE_SH_MATH
14299/* 15724/*
14300 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell. 15725 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
@@ -14395,6 +15820,27 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14395 goto again; 15820 goto again;
14396 } 15821 }
14397 15822
15823#if ENABLE_PLATFORM_MINGW32
15824 if ((uintptr_t)r == 2) {
15825 /* ^C pressed, propagate event */
15826 if (trap[SIGINT]) {
15827 write(STDOUT_FILENO, "^C", 2);
15828 pending_int = 1;
15829 dotrap();
15830 if (!(rootshell && iflag))
15831 return (uintptr_t)0;
15832 else
15833 goto again;
15834 } else if (iflag) {
15835 raise_interrupt();
15836 } else {
15837 GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
15838 exitshell();
15839 }
15840 return (uintptr_t)r;
15841 }
15842#endif
15843
14398 if ((uintptr_t)r > 1) 15844 if ((uintptr_t)r > 1)
14399 ash_msg_and_raise_error(r); 15845 ash_msg_and_raise_error(r);
14400 15846
@@ -14455,6 +15901,9 @@ umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14455 if (!isdigit(modestr[0])) 15901 if (!isdigit(modestr[0]))
14456 mask ^= 0777; 15902 mask ^= 0777;
14457 umask(mask); 15903 umask(mask);
15904#if ENABLE_PLATFORM_MINGW32
15905 setvareq(xasprintf("BB_UMASK=0%o", mask), VEXPORT|VNOSAVE);
15906#endif
14458 } 15907 }
14459 return 0; 15908 return 0;
14460} 15909}
@@ -14538,6 +15987,13 @@ exitshell(void)
14538 /*free(p); - we'll exit soon */ 15987 /*free(p); - we'll exit soon */
14539 } 15988 }
14540 out: 15989 out:
15990#if ENABLE_SUW32
15991 if (delayexit) {
15992#define EXIT_MSG "Press any key to exit..."
15993 console_write(EXIT_MSG, sizeof(EXIT_MSG) - 1);
15994 _getch();
15995 }
15996#endif
14541 exitreset(); 15997 exitreset();
14542 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". 15998 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
14543 * our setjobctl(0) does not panic if tcsetpgrp fails inside it. 15999 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
@@ -14548,22 +16004,97 @@ exitshell(void)
14548 /* NOTREACHED */ 16004 /* NOTREACHED */
14549} 16005}
14550 16006
16007#if ENABLE_PLATFORM_MINGW32
16008/* We need to see if HOME is *really* unset */
16009# undef getenv
16010static void setvar_if_unset(const char *key, const char *value)
16011{
16012 if (!getenv(key) || getuid() == 0)
16013 setvar(key, value, VEXPORT);
16014}
16015#endif
16016
14551/* Don't inline: conserve stack of caller from having our locals too */ 16017/* Don't inline: conserve stack of caller from having our locals too */
14552static NOINLINE void 16018static NOINLINE void
14553init(void) 16019init(void)
14554{ 16020{
16021#if ENABLE_PLATFORM_MINGW32
16022 int import = 0;
16023#else
14555 /* we will never free this */ 16024 /* we will never free this */
14556 basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ); 16025 basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ);
14557 basepf.linno = 1; 16026 basepf.linno = 1;
14558 16027
14559 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ 16028 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
14560 setsignal(SIGCHLD); 16029 setsignal(SIGCHLD);
16030#endif
14561 16031
14562 { 16032 {
14563 char **envp; 16033 char **envp;
14564 const char *p; 16034 const char *p;
14565 16035
14566 initvar(); 16036 initvar();
16037
16038#if ENABLE_PLATFORM_MINGW32
16039 /*
16040 * case insensitive env names from Windows world
16041 *
16042 * Some standard env names such as PATH is named Path and so on
16043 * ash itself is case sensitive, so "Path" will confuse it, as
16044 * MSVC getenv() is case insensitive.
16045 *
16046 * We may end up having both Path and PATH. Then Path will be chosen
16047 * because it appears first.
16048 */
16049 if (windows_env()) {
16050 /*
16051 * If we get here it's because the environment suggests we
16052 * haven't been invoked from an earlier instance of BusyBox.
16053 */
16054 char *start, *end;
16055 struct passwd *pw;
16056
16057 /* mintty sets HOME: unset it */
16058 const char *tty = getenv("TERM_PROGRAM");
16059 if (tty && strcmp(tty, "mintty") == 0) {
16060 unsetenv("HOME");
16061 }
16062
16063 import = VIMPORT;
16064 for (envp = environ; envp && *envp; envp++) {
16065 if (!(end=strchr(*envp, '=')))
16066 continue;
16067
16068 /* check for invalid characters in name */
16069 start = (char *)endofname(*envp);
16070 if (*start != '=') {
16071 /* Make a copy of the original variable */
16072 setvareq(xstrdup(*envp), VEXPORT|VNOSAVE);
16073
16074 /* Replace invalid characters with underscores */
16075 for (; start < end; start++) {
16076 if (!isalnum(*start)) {
16077 *start = '_';
16078 }
16079 }
16080 }
16081
16082 /* make all variable names uppercase */
16083 for (start = *envp;start < end;start++)
16084 *start = toupper(*start);
16085 }
16086
16087 /* Initialise some variables normally set at login, but
16088 * only if someone hasn't already set them or we're root. */
16089 pw = getpwuid(getuid());
16090 if (pw) {
16091 setvar_if_unset("USER", pw->pw_name);
16092 setvar_if_unset("LOGNAME", pw->pw_name);
16093 setvar_if_unset("HOME", pw->pw_dir);
16094 }
16095 setvar_if_unset("SHELL", DEFAULT_SHELL);
16096 }
16097#endif
14567 for (envp = environ; envp && *envp; envp++) { 16098 for (envp = environ; envp && *envp; envp++) {
14568/* Used to have 16099/* Used to have
14569 * p = endofname(*envp); 16100 * p = endofname(*envp);
@@ -14577,7 +16108,11 @@ init(void)
14577 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this 16108 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
14578 */ 16109 */
14579 if (strchr(*envp, '=')) { 16110 if (strchr(*envp, '=')) {
16111#if !ENABLE_PLATFORM_MINGW32
14580 setvareq(*envp, VEXPORT|VTEXTFIXED); 16112 setvareq(*envp, VEXPORT|VTEXTFIXED);
16113#else
16114 setvareq(*envp, VEXPORT|import);
16115#endif
14581 } 16116 }
14582 } 16117 }
14583 16118
@@ -14628,7 +16163,11 @@ procargs(char **argv)
14628 int login_sh; 16163 int login_sh;
14629 16164
14630 xargv = argv; 16165 xargv = argv;
16166#if ENABLE_PLATFORM_MINGW32
16167 login_sh = applet_name[0] == 'l';
16168#else
14631 login_sh = xargv[0] && xargv[0][0] == '-'; 16169 login_sh = xargv[0] && xargv[0][0] == '-';
16170#endif
14632#if NUM_SCRIPTS > 0 16171#if NUM_SCRIPTS > 0
14633 if (minusc) 16172 if (minusc)
14634 goto setarg0; 16173 goto setarg0;
@@ -14652,7 +16191,9 @@ procargs(char **argv)
14652 } 16191 }
14653 if (iflag == 2 /* no explicit -i given */ 16192 if (iflag == 2 /* no explicit -i given */
14654 && sflag == 1 /* -s given (or implied) */ 16193 && sflag == 1 /* -s given (or implied) */
16194#if !ENABLE_PLATFORM_MINGW32
14655 && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */ 16195 && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */
16196#endif
14656 && isatty(0) && isatty(1) /* we are on tty */ 16197 && isatty(0) && isatty(1) /* we are on tty */
14657 ) { 16198 ) {
14658 iflag = 1; 16199 iflag = 1;
@@ -14672,6 +16213,9 @@ procargs(char **argv)
14672 goto setarg0; 16213 goto setarg0;
14673 } else if (!sflag) { 16214 } else if (!sflag) {
14674 setinputfile(*xargv, 0); 16215 setinputfile(*xargv, 0);
16216#if ENABLE_PLATFORM_MINGW32
16217 bs_to_slash(*xargv);
16218#endif
14675 setarg0: 16219 setarg0:
14676 arg0 = *xargv++; 16220 arg0 = *xargv++;
14677 commandname = arg0; 16221 commandname = arg0;
@@ -14695,8 +16239,10 @@ procargs(char **argv)
14695 * NB: must do it before setting up signals (in optschanged()) 16239 * NB: must do it before setting up signals (in optschanged())
14696 * and reading .profile etc (after we return from here): 16240 * and reading .profile etc (after we return from here):
14697 */ 16241 */
16242#if !ENABLE_PLATFORM_MINGW32
14698 if (iflag) 16243 if (iflag)
14699 signal(SIGHUP, SIG_DFL); 16244 signal(SIGHUP, SIG_DFL);
16245#endif
14700 16246
14701 optschanged(); 16247 optschanged();
14702 16248
@@ -14741,9 +16287,25 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
14741 struct stackmark smark; 16287 struct stackmark smark;
14742 int login_sh; 16288 int login_sh;
14743 16289
16290#if ENABLE_PLATFORM_MINGW32
16291 INIT_G_memstack();
16292
16293 /* from init() */
16294 basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ);
16295 basepf.linno = 1;
16296
16297 if (argc == 3 && !strcmp(argv[1], "--fs")) {
16298 forkshell_init(argv[2]);
16299 /* only reached in case of error */
16300 bb_error_msg_and_die("forkshell failed");
16301 }
16302#endif
16303
14744 /* Initialize global data */ 16304 /* Initialize global data */
14745 INIT_G_misc(); 16305 INIT_G_misc();
16306#if !ENABLE_PLATFORM_MINGW32
14746 INIT_G_memstack(); 16307 INIT_G_memstack();
16308#endif
14747 INIT_G_var(); 16309 INIT_G_var();
14748#if ENABLE_ASH_ALIAS 16310#if ENABLE_ASH_ALIAS
14749 INIT_G_alias(); 16311 INIT_G_alias();
@@ -14789,6 +16351,10 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
14789 init(); 16351 init();
14790 setstackmark(&smark); 16352 setstackmark(&smark);
14791 16353
16354#if ENABLE_PLATFORM_MINGW32
16355 SetConsoleCtrlHandler(ctrl_handler, TRUE);
16356#endif
16357
14792#if NUM_SCRIPTS > 0 16358#if NUM_SCRIPTS > 0
14793 if (argc < 0) 16359 if (argc < 0)
14794 /* Non-NULL minusc tells procargs that an embedded script is being run */ 16360 /* Non-NULL minusc tells procargs that an embedded script is being run */
@@ -14800,11 +16366,45 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
14800 trace_puts_args(argv); 16366 trace_puts_args(argv);
14801#endif 16367#endif
14802 16368
16369#if ENABLE_PLATFORM_MINGW32
16370 if (!dirarg && !login_sh && iflag) {
16371 char *cwd = getcwd(NULL, 0);
16372 if (cwd) {
16373 chdir(cwd);
16374 setpwd(NULL, 0);
16375 free(cwd);
16376 }
16377 }
16378
16379 if (title)
16380 set_title(title);
16381#endif
16382
14803 if (login_sh) { 16383 if (login_sh) {
14804 const char *hp; 16384 const char *hp;
14805 16385
16386#if ENABLE_PLATFORM_MINGW32
16387 if (!dirarg) {
16388 hp = lookupvar("HOME");
16389 if (hp == NULL || *hp == '\0')
16390 hp = xgetpwuid(getuid())->pw_dir;
16391 chdir(hp);
16392 setpwd(NULL, 0);
16393 }
16394#endif
16395
14806 state = 1; 16396 state = 1;
16397#if ENABLE_PLATFORM_MINGW32
16398 hp = concat_path_file(get_system_drive(), "/etc/profile");
16399 read_profile(hp);
16400 free((void *)hp);
16401
16402 hp = exe_relative_path("/etc/profile");
16403 read_profile(hp);
16404 free((void *)hp);
16405#else
14807 read_profile("/etc/profile"); 16406 read_profile("/etc/profile");
16407#endif
14808 state1: 16408 state1:
14809 state = 2; 16409 state = 2;
14810 hp = lookupvar("HOME"); 16410 hp = lookupvar("HOME");
@@ -14813,10 +16413,18 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
14813 } 16413 }
14814 state2: 16414 state2:
14815 state = 3; 16415 state = 3;
16416#if ENABLE_PLATFORM_MINGW32
16417 if (dirarg) {
16418 chdir(dirarg);
16419 setpwd(NULL, 0);
16420 }
16421#endif
14816 if (iflag 16422 if (iflag
16423#if ENABLE_PLATFORM_POSIX
14817#ifndef linux 16424#ifndef linux
14818 && getuid() == geteuid() && getgid() == getegid() 16425 && getuid() == geteuid() && getgid() == getegid()
14819#endif 16426#endif
16427#endif
14820 ) { 16428 ) {
14821 const char *shinit = lookupvar("ENV"); 16429 const char *shinit = lookupvar("ENV");
14822 if (shinit != NULL && *shinit != '\0') 16430 if (shinit != NULL && *shinit != '\0')
@@ -14841,7 +16449,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
14841 // ash -sc 'echo $-' 16449 // ash -sc 'echo $-'
14842 // continue reading input from stdin after running 'echo'. 16450 // continue reading input from stdin after running 'echo'.
14843 // bash does not do this: it prints "hBcs" and exits. 16451 // bash does not do this: it prints "hBcs" and exits.
16452#if !ENABLE_PLATFORM_MINGW32
14844 evalstring(minusc, EV_EXIT); 16453 evalstring(minusc, EV_EXIT);
16454#else
16455 evalstring(minusc, sflag ? 0 : EV_EXIT);
16456#endif
14845 } 16457 }
14846 16458
14847 if (sflag || minusc == NULL) { 16459 if (sflag || minusc == NULL) {
@@ -14884,6 +16496,1101 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
14884 /* NOTREACHED */ 16496 /* NOTREACHED */
14885} 16497}
14886 16498
16499#if ENABLE_PLATFORM_MINGW32
16500static void
16501forkshell_openhere(struct forkshell *fs)
16502{
16503 const char *p = fs->path;
16504 size_t len = strlen(p);
16505 int pip[2];
16506
16507 pip[0] = fs->fd[0];
16508 pip[1] = fs->fd[1];
16509
16510 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
16511
16512 close(pip[0]);
16513 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
16514 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
16515 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
16516 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
16517 signal(SIGPIPE, SIG_DFL);
16518 xwrite(pip[1], p, len);
16519 _exit_SUCCESS();
16520}
16521
16522static void
16523forkshell_evalbackcmd(struct forkshell *fs)
16524{
16525#if BASH_PROCESS_SUBST
16526 /* determine end of pipe used by parent (ip) and child (ic) */
16527 const int ctl = fs->fd[2];
16528 const int ip = (ctl == CTLTOPROC);
16529 const int ic = !(ctl == CTLTOPROC);
16530#else
16531 const int ip = 0;
16532 const int ic = 1;
16533#endif
16534 union node *n = fs->n;
16535 int pip[2];
16536
16537 pip[ip] = fs->fd[ip];
16538 pip[ic] = fs->fd[ic];
16539
16540 FORCE_INT_ON;
16541 close(pip[ip]);
16542 if (pip[ic] != ic) {
16543 /*close(ic);*/
16544 dup2_or_raise(pip[ic], ic);
16545 close(pip[ic]);
16546 }
16547 eflag = 0;
16548 ifsfree();
16549 evaltreenr(n, EV_EXIT);
16550 /* NOTREACHED */
16551}
16552
16553static void
16554forkshell_evalsubshell(struct forkshell *fs)
16555{
16556 union node *n = fs->n;
16557 int flags = fs->flags;
16558
16559 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
16560 INT_ON;
16561 flags |= EV_EXIT;
16562 if (fs->mode)
16563 flags &= ~EV_TESTED;
16564 expredir(n->nredir.redirect);
16565 redirect(n->nredir.redirect, 0);
16566 evaltreenr(n->nredir.n, flags);
16567 /* never returns */
16568}
16569
16570static void
16571forkshell_evalpipe(struct forkshell *fs)
16572{
16573 union node *n = fs->n;
16574 int flags = fs->flags;
16575 int prevfd = fs->fd[2];
16576 int pip[2] = {fs->fd[0], fs->fd[1]};
16577
16578 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
16579 INT_ON;
16580 if (pip[1] >= 0) {
16581 close(pip[0]);
16582 }
16583 if (prevfd > 0) {
16584 dup2(prevfd, 0);
16585 close(prevfd);
16586 }
16587 if (pip[1] > 1) {
16588 dup2(pip[1], 1);
16589 close(pip[1]);
16590 }
16591 evaltreenr(n, flags);
16592}
16593
16594static void
16595forkshell_shellexec(struct forkshell *fs)
16596{
16597 int idx = fs->fd[0];
16598 char **argv = fs->argv;
16599 char *path = fs->path;
16600
16601 FORCE_INT_ON;
16602 shellexec(argv[0], argv, path, idx, TRUE);
16603}
16604
16605static void
16606forkshell_child(struct forkshell *fs)
16607{
16608 switch ( fs->fpid ) {
16609 case FS_OPENHERE:
16610 forkshell_openhere(fs);
16611 break;
16612 case FS_EVALBACKCMD:
16613 forkshell_evalbackcmd(fs);
16614 break;
16615 case FS_EVALSUBSHELL:
16616 forkshell_evalsubshell(fs);
16617 break;
16618 case FS_EVALPIPE:
16619 forkshell_evalpipe(fs);
16620 break;
16621 case FS_SHELLEXEC:
16622 forkshell_shellexec(fs);
16623 break;
16624 }
16625}
16626
16627/*
16628 * Reinitialise the builtin environment variables in varinit. Their
16629 * current settings have been copied from the parent in vartab. Look
16630 * these up using the names from varinit_data, copy the details from
16631 * vartab to varinit and replace the old copy in vartab with the new
16632 * one in varinit.
16633 *
16634 * Also reinitialise the function pointers and line number variable.
16635 */
16636static void
16637reinitvar(void)
16638{
16639 int i;
16640 const char *name;
16641 struct var **old;
16642
16643 for (i=0; i<ARRAY_SIZE(varinit); ++i) {
16644 if (i == LINENO_INDEX)
16645 name = "LINENO=";
16646 else if (i == FUNCNAME_INDEX)
16647 name = "FUNCNAME=";
16648 else
16649 name = varinit_data[i].var_text;
16650 if ((old = findvar(name)) != NULL) {
16651 varinit[i] = **old;
16652 *old = varinit+i;
16653 }
16654 varinit[i].var_func = varinit_data[i].var_func;
16655 }
16656 vlineno.var_text = linenovar;
16657 vfuncname.var_text = funcnamevar;
16658}
16659
16660static void
16661spawn_forkshell(struct forkshell *fs, struct job *jp, union node *n, int mode)
16662{
16663 struct forkshell *new;
16664 char buf[32];
16665 const char *argv[] = { "sh", "--fs", NULL, NULL };
16666 intptr_t ret;
16667
16668 new = forkshell_prepare(fs);
16669 if (new == NULL)
16670 goto fail;
16671
16672 new->mode = mode;
16673 new->nprocs = jp == NULL ? 0 : jp->nprocs;
16674#if JOBS_WIN32
16675 new->jpnull = jp == NULL;
16676#endif
16677 sprintf(buf, "%p", new->hMapFile);
16678 argv[2] = buf;
16679 ret = spawnve(P_NOWAIT, bb_busybox_exec_path, (char *const *)argv, NULL);
16680 CloseHandle(new->hMapFile);
16681 UnmapViewOfFile(new);
16682 if (ret == -1) {
16683 fail:
16684 if (jp)
16685 freejob(jp);
16686 ash_msg_and_raise_error("unable to spawn shell");
16687 }
16688 forkparent(jp, n, mode, (HANDLE)ret);
16689}
16690
16691/*
16692 * forkshell_prepare() and friends
16693 *
16694 * The sequence is as follows:
16695 * - funcblocksize is initialized
16696 * - forkshell_size(fs) is called to calculate the exact memory needed
16697 * - a new struct is allocated
16698 * - funcblock, funcstring, relocate are initialized from the new block
16699 * - forkshell_copy(fs) is called to copy recursively everything over
16700 * it will record all relocations along the way
16701 *
16702 * When this memory is mapped elsewhere, pointer fixup will be needed
16703 */
16704
16705/* redefine without test that fs_size is nonzero */
16706#undef SAVE_PTR
16707#undef SAVE_PTR2
16708#undef SAVE_PTR3
16709#define SAVE_PTR(dst,note,flag) {MARK_PTR(dst,note,flag);}
16710
16711static int align_len(const char *s)
16712{
16713 return s ? SHELL_ALIGN(strlen(s)+1) : 0;
16714}
16715
16716struct datasize {
16717 int funcblocksize;
16718 int funcstringsize;
16719};
16720
16721#define SLIST_SIZE_BEGIN(name,type) \
16722static struct datasize \
16723name(struct datasize ds, type *p) \
16724{ \
16725 while (p) { \
16726 ds.funcblocksize += sizeof(type);
16727 /* do something here with p */
16728#define SLIST_SIZE_END() \
16729 p = p->next; \
16730 } \
16731 return ds; \
16732}
16733
16734#define SLIST_COPY_BEGIN(name,type) \
16735static type * \
16736name(type *vp) \
16737{ \
16738 type *start; \
16739 type **vpp; \
16740 vpp = &start; \
16741 while (vp) { \
16742 *vpp = funcblock; \
16743 funcblock = (char *) funcblock + sizeof(type);
16744 /* do something here with vpp and vp */
16745#define SLIST_COPY_END() \
16746 SAVE_PTR((*vpp)->next, "(*vpp)->next", NO_FREE); \
16747 vp = vp->next; \
16748 vpp = &(*vpp)->next; \
16749 } \
16750 *vpp = NULL; \
16751 return start; \
16752}
16753
16754/*
16755 * struct var
16756 */
16757SLIST_SIZE_BEGIN(var_size,struct var)
16758ds.funcstringsize += align_len(p->var_text);
16759SLIST_SIZE_END()
16760
16761SLIST_COPY_BEGIN(var_copy,struct var)
16762(*vpp)->var_text = nodeckstrdup(vp->var_text);
16763(*vpp)->flags = vp->flags;
16764(*vpp)->var_func = NULL;
16765SAVE_PTR((*vpp)->var_text, xasprintf("(*vpp)->var_text '%s'", vp->var_text ?: "NULL"), FREE);
16766SLIST_COPY_END()
16767
16768/*
16769 * struct tblentry
16770 */
16771static struct datasize
16772tblentry_size(struct datasize ds, struct tblentry *tep)
16773{
16774 while (tep) {
16775 ds.funcblocksize += sizeof(struct tblentry) + align_len(tep->cmdname);
16776 /* CMDBUILTIN, e->param.cmd needs no pointer relocation */
16777 if (tep->cmdtype == CMDFUNCTION) {
16778 ds.funcblocksize += offsetof(struct funcnode, n);
16779 ds.funcblocksize = calcsize(ds.funcblocksize, &tep->param.func->n);
16780 }
16781 tep = tep->next;
16782 }
16783 return ds;
16784}
16785
16786static struct tblentry *
16787tblentry_copy(struct tblentry *tep)
16788{
16789 struct tblentry *start;
16790 struct tblentry **newp;
16791 int size;
16792
16793 newp = &start;
16794 while (tep) {
16795 *newp = funcblock;
16796 size = sizeof(struct tblentry) + align_len(tep->cmdname);
16797
16798 funcblock = (char *) funcblock + size;
16799 memcpy(*newp, tep, sizeof(struct tblentry)+strlen(tep->cmdname));
16800 switch (tep->cmdtype) {
16801 case CMDBUILTIN:
16802 /* Save index of builtin, not pointer; fixed by forkshell_init() */
16803 (*newp)->param.index = tep->param.cmd - builtintab;
16804 break;
16805 case CMDFUNCTION:
16806 (*newp)->param.func = funcblock;
16807 funcblock = (char *) funcblock + offsetof(struct funcnode, n);
16808 copynode(&tep->param.func->n);
16809 SAVE_PTR((*newp)->param.func, "param.func", NO_FREE);
16810 break;
16811 default:
16812 break;
16813 }
16814 SAVE_PTR((*newp)->next, xasprintf("cmdname '%s'", tep->cmdname), FREE);
16815 tep = tep->next;
16816 newp = &(*newp)->next;
16817 }
16818 *newp = NULL;
16819 return start;
16820}
16821
16822static struct datasize
16823cmdtable_size(struct datasize ds)
16824{
16825 int i;
16826 ds.funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE;
16827 for (i = 0; i < CMDTABLESIZE; i++)
16828 ds = tblentry_size(ds, cmdtable[i]);
16829 return ds;
16830}
16831
16832static struct tblentry **
16833cmdtable_copy(void)
16834{
16835 struct tblentry **new = funcblock;
16836 int i;
16837
16838 funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE;
16839 for (i = 0; i < CMDTABLESIZE; i++) {
16840 new[i] = tblentry_copy(cmdtable[i]);
16841 SAVE_PTR(new[i], xasprintf("cmdtable[%d]", i), FREE);
16842 }
16843 return new;
16844}
16845
16846#if ENABLE_ASH_ALIAS
16847/*
16848 * struct alias
16849 */
16850SLIST_SIZE_BEGIN(alias_size,struct alias)
16851ds.funcstringsize += align_len(p->name);
16852ds.funcstringsize += align_len(p->val);
16853SLIST_SIZE_END()
16854
16855SLIST_COPY_BEGIN(alias_copy,struct alias)
16856(*vpp)->name = nodeckstrdup(vp->name);
16857(*vpp)->val = nodeckstrdup(vp->val);
16858(*vpp)->flag = vp->flag;
16859SAVE_PTR((*vpp)->name, xasprintf("(*vpp)->name '%s'", vp->name ?: "NULL"), FREE);
16860SAVE_PTR((*vpp)->val, xasprintf("(*vpp)->val '%s'", vp->val ?: "NULL"), FREE);
16861SLIST_COPY_END()
16862
16863static struct datasize
16864atab_size(struct datasize ds)
16865{
16866 int i;
16867 ds.funcblocksize += sizeof(struct alias *)*ATABSIZE;
16868 for (i = 0; i < ATABSIZE; i++)
16869 ds = alias_size(ds, atab[i]);
16870 return ds;
16871}
16872
16873static struct alias **
16874atab_copy(void)
16875{
16876 struct alias **new = funcblock;
16877 int i;
16878
16879 funcblock = (char *) funcblock + sizeof(struct alias *)*ATABSIZE;
16880 for (i = 0; i < ATABSIZE; i++) {
16881 new[i] = alias_copy(atab[i]);
16882 SAVE_PTR(new[i], xasprintf("atab[%d]", i), FREE);
16883 }
16884 return new;
16885}
16886#endif
16887
16888/*
16889 * char **
16890 */
16891static struct datasize
16892argv_size(struct datasize ds, char **p)
16893{
16894 if (p) {
16895 while (*p) {
16896 ds.funcblocksize += sizeof(char *);
16897 ds.funcstringsize += align_len(*p);
16898 p++;
16899 }
16900 // Allow two extra elements for tryexec().
16901 ds.funcblocksize += 3 * sizeof(char *);
16902 }
16903 return ds;
16904}
16905
16906static char **
16907argv_copy(char **p)
16908{
16909 char **new, **start = funcblock;
16910#if FORKSHELL_DEBUG
16911 int i = 0;
16912#endif
16913
16914 if (p) {
16915 // Allow two extra elements for tryexec().
16916 funcblock = (char *) funcblock + 2 * sizeof(char *);
16917 while (*p) {
16918 new = funcblock;
16919 funcblock = (char *) funcblock + sizeof(char *);
16920 *new = nodeckstrdup(*p);
16921 SAVE_PTR(*new, xasprintf("argv[%d] '%s'", i++, *p), FREE);
16922 p++;
16923 }
16924 new = funcblock;
16925 funcblock = (char *) funcblock + sizeof(char *);
16926 *new = NULL;
16927 return start + 2;
16928 }
16929 return NULL;
16930}
16931
16932#if MAX_HISTORY
16933static struct datasize
16934history_size(struct datasize ds)
16935{
16936 int i;
16937 line_input_t *st = line_input_state;
16938
16939 ds.funcblocksize += sizeof(char *) * st->cnt_history;
16940 for (i = 0; i < st->cnt_history; i++) {
16941 ds.funcstringsize += align_len(st->history[i]);
16942 }
16943 return ds;
16944}
16945
16946static char **
16947history_copy(void)
16948{
16949 line_input_t *st = line_input_state;
16950 char **new = funcblock;
16951 int i;
16952
16953 funcblock = (char *)funcblock + sizeof(char *) * st->cnt_history;
16954 for (i = 0; i < st->cnt_history; i++) {
16955 new[i] = nodeckstrdup(st->history[i]);
16956 SAVE_PTR(new[i],
16957 xasprintf("history[%d] '%s'", i, st->history[i]), FREE);
16958 }
16959 return new;
16960}
16961#endif
16962
16963#if JOBS_WIN32
16964/*
16965 * struct procstat
16966 */
16967static struct datasize
16968procstat_size(struct datasize ds, int nj)
16969{
16970 struct job *jp = jobtab + nj;
16971
16972 if (jp->ps != &jp->ps0)
16973 ds.funcblocksize += sizeof(struct procstat) * jp->nprocs;
16974
16975 for (int i = 0; i < jp->nprocs; i++)
16976 ds.funcstringsize += align_len(jp->ps[i].ps_cmd);
16977
16978 return ds;
16979}
16980
16981static struct procstat *
16982procstat_copy(int nj)
16983{
16984 struct job *jp = jobtab + nj;
16985 struct procstat *new = funcblock;
16986
16987 funcblock = (char *)funcblock + sizeof(struct procstat) * jp->nprocs;
16988 memcpy(new, jp->ps, sizeof(struct procstat) * jp->nprocs);
16989
16990 for (int i = 0; i < jp->nprocs; i++) {
16991 new[i].ps_cmd = nodeckstrdup(jp->ps[i].ps_cmd);
16992 SAVE_PTR(new[i].ps_cmd,
16993 xasprintf("jobtab[%d].ps[%d].ps_cmd '%s'",
16994 nj, i, jp->ps[i].ps_cmd), FREE);
16995 }
16996 return new;
16997}
16998
16999/*
17000 * struct jobs
17001 */
17002static struct datasize
17003jobtab_size(struct datasize ds)
17004{
17005 ds.funcblocksize += sizeof(struct job) * njobs;
17006 for (int i = 0; i < njobs; i++) {
17007 if (jobtab[i].used)
17008 ds = procstat_size(ds, i);
17009 }
17010 return ds;
17011}
17012
17013static struct job *
17014jobtab_copy(void)
17015{
17016 struct job *new = funcblock;
17017 int i;
17018
17019 funcblock = (char *)funcblock + sizeof(struct job) * njobs;
17020 memcpy(new, jobtab, sizeof(struct job) * njobs);
17021
17022 for (i = 0; i < njobs; i++) {
17023 if (!jobtab[i].used)
17024 continue;
17025
17026 if (jobtab[i].ps == &jobtab[i].ps0) {
17027 new[i].ps0.ps_cmd = nodeckstrdup(jobtab[i].ps0.ps_cmd);
17028 SAVE_PTR(new[i].ps0.ps_cmd,
17029 xasprintf("jobtab[%d].ps0.ps_cmd '%s'",
17030 i, jobtab[i].ps0.ps_cmd), FREE);
17031 new[i].ps = &new[i].ps0;
17032 } else if (jobtab[i].nprocs) {
17033 new[i].ps = procstat_copy(i);
17034 } else {
17035 new[i].ps = NULL;
17036 }
17037 SAVE_PTR(new[i].ps, xasprintf("jobtab[%d].ps", i), FREE);
17038
17039 if (jobtab[i].prev_job) {
17040 new[i].prev_job = new + (jobtab[i].prev_job - jobtab);
17041 SAVE_PTR(new[i].prev_job,
17042 xasprintf("jobtab[%d].prev_job", i), FREE);
17043 }
17044 }
17045 return new;
17046}
17047#endif
17048
17049/*
17050 * struct redirtab
17051 */
17052static int
17053redirtab_size(int funcblocksize, struct redirtab *rdtp)
17054{
17055 while (rdtp) {
17056 funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
17057 rdtp = rdtp->next;
17058 }
17059 return funcblocksize;
17060}
17061
17062static struct redirtab *
17063redirtab_copy(struct redirtab *rdtp)
17064{
17065 struct redirtab *start;
17066 struct redirtab **vpp;
17067
17068 vpp = &start;
17069 while (rdtp) {
17070 int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
17071 *vpp = funcblock;
17072 funcblock = (char *) funcblock + size;
17073 memcpy(*vpp, rdtp, size);
17074 SAVE_PTR((*vpp)->next, "(*vpp)->next", NO_FREE);
17075 rdtp = rdtp->next;
17076 vpp = &(*vpp)->next;
17077 }
17078 *vpp = NULL;
17079 return start;
17080}
17081
17082static struct datasize
17083globals_var_size(struct datasize ds)
17084{
17085 int i;
17086
17087 ds.funcblocksize += sizeof(struct globals_var);
17088 ds.funcstringsize += align_len(funcname);
17089 ds = argv_size(ds, shellparam.p);
17090 ds.funcblocksize = redirtab_size(ds.funcblocksize, redirlist);
17091 for (i = 0; i < VTABSIZE; i++)
17092 ds = var_size(ds, vartab[i]);
17093 return ds;
17094}
17095
17096#undef funcname
17097#undef shellparam
17098#undef redirlist
17099#undef vartab
17100static struct globals_var *
17101globals_var_copy(void)
17102{
17103 int i;
17104 struct globals_var *gvp, *new;
17105
17106 gvp = ash_ptr_to_globals_var;
17107 new = funcblock;
17108 funcblock = (char *) funcblock + sizeof(struct globals_var);
17109 memcpy(new, gvp, sizeof(struct globals_var));
17110
17111 new->funcname = nodeckstrdup(gvp->funcname);
17112 SAVE_PTR(new->funcname, xasprintf("funcname '%s'", gvp->funcname ?: "NULL"), FREE);
17113
17114 /* shparam */
17115 new->shellparam.malloced = 0;
17116 new->shellparam.p = argv_copy(gvp->shellparam.p);
17117 SAVE_PTR(new->shellparam.p, "shellparam.p", NO_FREE);
17118
17119 new->redirlist = redirtab_copy(gvp->redirlist);
17120 SAVE_PTR(new->redirlist, "redirlist", NO_FREE);
17121
17122 for (i = 0; i < VTABSIZE; i++) {
17123 new->vartab[i] = var_copy(gvp->vartab[i]);
17124 SAVE_PTR(new->vartab[i], xasprintf("vartab[%d]", i), FREE);
17125 }
17126
17127 return new;
17128}
17129
17130static struct datasize
17131globals_misc_size(struct datasize ds)
17132{
17133 ds.funcblocksize += sizeof(struct globals_misc);
17134 ds.funcstringsize += align_len(minusc);
17135 if (curdir != nullstr)
17136 ds.funcstringsize += align_len(curdir);
17137 if (physdir != nullstr)
17138 ds.funcstringsize += align_len(physdir);
17139 ds.funcstringsize += align_len(arg0);
17140 ds.funcstringsize += align_len(commandname);
17141 for (int i = 0; i < ARRAY_SIZE(trap); i++)
17142 ds.funcstringsize += align_len(trap[i]);
17143 return ds;
17144}
17145
17146#undef minusc
17147#undef curdir
17148#undef physdir
17149#undef arg0
17150#undef commandname
17151#undef nullstr
17152#undef trap
17153static struct globals_misc *
17154globals_misc_copy(void)
17155{
17156 struct globals_misc *p = ash_ptr_to_globals_misc;
17157 struct globals_misc *new = funcblock;
17158
17159 funcblock = (char *) funcblock + sizeof(struct globals_misc);
17160 memcpy(new, p, sizeof(struct globals_misc));
17161
17162 new->minusc = nodeckstrdup(p->minusc);
17163 new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr;
17164 new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr;
17165 new->arg0 = nodeckstrdup(p->arg0);
17166 new->commandname = nodeckstrdup(p->commandname);
17167 SAVE_PTR(new->minusc, xasprintf("minusc '%s'", p->minusc ?: "NULL"), FREE);
17168 SAVE_PTR(new->curdir,
17169 xasprintf("curdir '%s'", new->curdir ?: "NULL"), FREE);
17170 SAVE_PTR(new->physdir,
17171 xasprintf("physdir '%s'", new->physdir ?: "NULL"), FREE);
17172 SAVE_PTR(new->arg0, xasprintf("arg0 '%s'", p->arg0 ?: "NULL"), FREE);
17173 SAVE_PTR(new->commandname,
17174 xasprintf("commandname '%s'", p->commandname ?: "NULL"), FREE);
17175 for (int i = 0; i < ARRAY_SIZE(p->trap); i++) {
17176 new->trap[i] = nodeckstrdup(p->trap[i]);
17177 SAVE_PTR(new->trap[i], xasprintf("trap[%d]", i), FREE);
17178 }
17179 return new;
17180}
17181
17182static struct datasize
17183forkshell_size(struct forkshell *fs)
17184{
17185 struct datasize ds = {0, 0};
17186
17187 ds.funcstringsize += align_len(fs->path);
17188 if (fs->fpid == FS_OPENHERE)
17189 return ds;
17190
17191 ds = globals_var_size(ds);
17192 ds = globals_misc_size(ds);
17193 ds = cmdtable_size(ds);
17194
17195 ds.funcblocksize = calcsize(ds.funcblocksize, fs->n);
17196 ds = argv_size(ds, fs->argv);
17197
17198 if ((ENABLE_ASH_ALIAS || MAX_HISTORY || JOBS_WIN32) &&
17199 fs->fpid != FS_SHELLEXEC) {
17200#if ENABLE_ASH_ALIAS
17201 ds = atab_size(ds);
17202#endif
17203#if MAX_HISTORY
17204 if (line_input_state)
17205 ds = history_size(ds);
17206#endif
17207#if JOBS_WIN32
17208 ds = jobtab_size(ds);
17209#endif
17210 }
17211 return ds;
17212}
17213
17214static void
17215forkshell_copy(struct forkshell *fs, struct forkshell *new)
17216{
17217 memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */
17218
17219 new->path = nodeckstrdup(fs->path);
17220 SAVE_PTR(new->path, xasprintf("path '%s'", fs->path ?: "NULL"), FREE);
17221 if (fs->fpid == FS_OPENHERE)
17222 return;
17223
17224 new->gvp = globals_var_copy();
17225 new->gmp = globals_misc_copy();
17226 new->cmdtable = cmdtable_copy();
17227 SAVE_PTR(new->gvp, "gvp", NO_FREE);
17228 SAVE_PTR(new->gmp, "gmp", NO_FREE);
17229 SAVE_PTR(new->cmdtable, "cmdtable", NO_FREE);
17230
17231 new->n = copynode(fs->n);
17232 new->argv = argv_copy(fs->argv);
17233 SAVE_PTR(new->n, "n", NO_FREE);
17234 SAVE_PTR(new->argv, "argv", NO_FREE);
17235
17236 if ((ENABLE_ASH_ALIAS || MAX_HISTORY || JOBS_WIN32) &&
17237 fs->fpid != FS_SHELLEXEC) {
17238#if ENABLE_ASH_ALIAS
17239 new->atab = atab_copy();
17240 SAVE_PTR(new->atab, "atab", NO_FREE);
17241#endif
17242#if MAX_HISTORY
17243 if (line_input_state) {
17244 new->history = history_copy();
17245 SAVE_PTR(new->history, "history", NO_FREE);
17246 new->cnt_history = line_input_state->cnt_history;
17247 }
17248#endif
17249#if JOBS_WIN32
17250 if (njobs) {
17251 new->jobtab = jobtab_copy();
17252 SAVE_PTR(new->jobtab, "jobtab", NO_FREE);
17253 new->njobs = njobs;
17254 if (curjob) {
17255 new->curjob = new->jobtab + (curjob - jobtab);
17256 SAVE_PTR(new->curjob, "curjob", NO_FREE);
17257 }
17258 }
17259#endif
17260 }
17261}
17262
17263#if FORKSHELL_DEBUG
17264#define NUM_BLOCKS FUNCSTRING
17265enum {GVP, GMP, CMDTABLE, NODE, ARGV, ATAB, HISTORY, JOBTAB, FUNCSTRING};
17266
17267/* fp0 and notes can each be NULL */
17268static void
17269forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes)
17270{
17271 FILE *fp;
17272 void *lfuncblock;
17273 char *lfuncstring;
17274 char *lrelocate;
17275 char *s;
17276 int count, i, total, bitmapsize;
17277 int size[NUM_BLOCKS];
17278 char *lptr[NUM_BLOCKS+1];
17279 const char *fsname[] = {
17280 "FS_OPENHERE",
17281 "FS_EVALBACKCMD",
17282 "FS_EVALSUBSHELL",
17283 "FS_EVALPIPE",
17284 "FS_SHELLEXEC"
17285 };
17286
17287 if (fp0 != NULL) {
17288 fp = fp0;
17289 }
17290 else {
17291 char name[64];
17292 static int num = 0;
17293
17294 sprintf(name, "fs_%d_%03d.out", getpid(), ++num % 100);
17295 if ((fp=fopen(name, "w")) == NULL)
17296 return;
17297 }
17298
17299 bitmapsize = (fs->relocatesize + 7)/8;
17300 total = sizeof(struct forkshell) + fs->funcblocksize +
17301 fs->funcstringsize + bitmapsize;
17302 fprintf(fp, "total size %6d = %d + %d + %d + %d = %d\n",
17303 fs->size + bitmapsize,
17304 (int)sizeof(struct forkshell), fs->funcblocksize,
17305 fs->funcstringsize, bitmapsize, total);
17306
17307 lfuncblock = (char *)(fs + 1);
17308 lfuncstring = (char *)lfuncblock + fs->funcblocksize;
17309 lrelocate = (char *)lfuncstring + fs->funcstringsize;
17310
17311 /* funcblocksize is zero for FS_OPENHERE */
17312 if (fs->funcblocksize != 0) {
17313 /* Depending on the configuration and the type of forkshell
17314 * some items may not be present. */
17315 lptr[FUNCSTRING] = lfuncstring;
17316#if JOBS_WIN32
17317 lptr[JOBTAB] = fs->jobtab ? (char *)fs->jobtab : lptr[FUNCSTRING];
17318#else
17319 lptr[JOBTAB] = lptr[FUNCSTRING];
17320#endif
17321#if MAX_HISTORY
17322 lptr[HISTORY] = fs->history ? (char *)fs->history : lptr[JOBTAB];
17323#else
17324 lptr[HISTORY] = lptr[JOBTAB];
17325#endif
17326 lptr[ATAB] = IF_ASH_ALIAS(fs->atab ? (char *)fs->atab :) lptr[HISTORY];
17327 lptr[ARGV] = fs->argv ? (char *)fs->argv : lptr[ATAB];
17328 lptr[NODE] = fs->n ? (char *)fs->n : lptr[ARGV];
17329 lptr[CMDTABLE] = (char *)fs->cmdtable;
17330 lptr[GMP] = (char *)fs->gmp;
17331 lptr[GVP] = (char *)fs->gvp;
17332
17333 fprintf(fp, "funcblocksize %6d = ", fs->funcblocksize);
17334 total = 0;
17335 for (i=0; i<NUM_BLOCKS; ++i) {
17336 size[i] = (int)(lptr[i+1] - lptr[i]);
17337 total += size[i];
17338 fprintf(fp, "%d %c ", size[i], i == NUM_BLOCKS - 1 ? '=' : '+');
17339 }
17340 fprintf(fp, "%d\n\n", total);
17341 }
17342 else {
17343 fprintf(fp, "\n");
17344 }
17345
17346 fprintf(fp, "%s\n\n", fsname[fs->fpid]);
17347 fprintf(fp, "--- relocate ---\n");
17348 count = 0;
17349 for (i = 0; i < fs->relocatesize; ++i) {
17350 if (lrelocate[i/8] & (1 << i % 8)) {
17351 char **ptr = (char **)((char *)fs + i * sizeof(char *));
17352 fprintf(fp, "%p %p %s\n", ptr, *ptr,
17353 notes && notes[i] ? notes[i] : "");
17354 ++count;
17355 }
17356 }
17357 fprintf(fp, "--- %d relocations ---\n\n", count);
17358
17359 fprintf(fp, "--- funcstring ---\n");
17360 count = 0;
17361 s = lfuncstring;
17362 while (s-lfuncstring < fs->funcstringsize) {
17363 if (!*s) {
17364 ++s;
17365 continue;
17366 }
17367 fprintf(fp, "%p '%s'\n", s, s);
17368 s += strlen(s)+1;
17369 ++count;
17370 }
17371 fprintf(fp, "--- %d strings ---\n", count);
17372
17373 if (fp0 == NULL)
17374 fclose(fp);
17375}
17376#endif
17377
17378static struct forkshell *
17379forkshell_prepare(struct forkshell *fs)
17380{
17381 struct forkshell *new;
17382 struct datasize ds;
17383 int size, relocatesize, bitmapsize;
17384 HANDLE h;
17385 SECURITY_ATTRIBUTES sa;
17386#if FORKSHELL_DEBUG
17387 char *relocate;
17388 char name[64];
17389 FILE *fp;
17390 static int num = 0;
17391#endif
17392
17393 /* calculate size of structure, funcblock and funcstring */
17394 ds = forkshell_size(fs);
17395 size = sizeof(struct forkshell) + ds.funcblocksize + ds.funcstringsize;
17396 relocatesize = (sizeof(struct forkshell) + ds.funcblocksize)/sizeof(char *);
17397 bitmapsize = (relocatesize + 7)/8;
17398
17399 /* Allocate shared memory region */
17400 memset(&sa, 0, sizeof(sa));
17401 sa.nLength = sizeof(sa);
17402 sa.lpSecurityDescriptor = NULL;
17403 sa.bInheritHandle = TRUE;
17404 h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0,
17405 size+bitmapsize, NULL);
17406
17407 /* Initialise pointers */
17408 new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
17409 if (new == NULL)
17410 return NULL;
17411 fs_size = size;
17412 fs_start = new;
17413 funcblock = (char *)(new + 1);
17414 funcstring_end = (char *)new + size;
17415#if FORKSHELL_DEBUG
17416 fs_funcstring = (char *)new + sizeof(struct forkshell) + ds.funcblocksize;
17417 relocate = (char *)new + size;
17418 annot = (const char **)xzalloc(sizeof(char *)*relocatesize);
17419 annot_free = xzalloc(relocatesize);
17420#endif
17421
17422 /* Now pack them all */
17423 forkshell_copy(fs, new);
17424
17425 /* Finish it up */
17426 new->size = size;
17427 new->relocatesize = relocatesize;
17428 new->old_base = (char *)new;
17429 new->hMapFile = h;
17430#if FORKSHELL_DEBUG
17431 sprintf(name, "fs_%d_%03d.out", getpid(), ++num % 100);
17432 if ((fp=fopen(name, "w")) != NULL) {
17433 int i;
17434
17435 new->funcblocksize = (char *)funcblock - (char *)(new + 1);
17436 new->funcstringsize = (char *)new + size - funcstring_end;
17437
17438 /* perform some sanity checks on pointers */
17439 fprintf(fp, "forkshell %p %6d\n", new, (int)sizeof(*new));
17440 fprintf(fp, "funcblock %p %6d\n", new+1, new->funcblocksize);
17441 fprintf(fp, "funcstring %p %6d\n", funcstring_end,
17442 new->funcstringsize);
17443 if ((char *)funcblock != funcstring_end)
17444 fprintf(fp, " funcstring != end funcblock + 1 %p\n", funcblock);
17445 fprintf(fp, "relocate %p %6d\n\n", relocate, bitmapsize);
17446
17447 forkshell_print(fp, new, annot);
17448
17449 for (i = 0; i < relocatesize; ++i) {
17450 if (annot_free[i]) {
17451 free((void *)annot[i]);
17452 }
17453 }
17454 free(annot);
17455 free(annot_free);
17456 annot = NULL;
17457 fclose(fp);
17458 }
17459#endif
17460 return new;
17461}
17462
17463#undef trap_ptr
17464static void
17465forkshell_init(const char *idstr)
17466{
17467 struct forkshell *fs;
17468 void *map_handle;
17469 HANDLE h;
17470 int i;
17471 char **ptr;
17472 char *lrelocate;
17473 struct jmploc jmploc;
17474
17475 if (sscanf(idstr, "%p", &map_handle) != 1)
17476 return;
17477
17478 h = (HANDLE)map_handle;
17479 fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
17480 if (!fs)
17481 return;
17482
17483 /* this memory can't be freed */
17484 sticky_mem_start = fs;
17485 sticky_mem_end = (char *) fs + fs->size;
17486
17487 /* pointer fixup */
17488 lrelocate = (char *)fs + fs->size;
17489 for (i = 0; i < fs->relocatesize; i++) {
17490 if (lrelocate[i/8] & (1 << i % 8)) {
17491 ptr = (char **)((char *)fs + i * sizeof(char *));
17492 if (*ptr)
17493 *ptr = (char *)fs + (*ptr - fs->old_base);
17494 }
17495 }
17496
17497 if (fs->fpid == FS_OPENHERE)
17498 goto end;
17499
17500 /* Now fix up stuff that can't be transferred */
17501 for (i = 0; i < CMDTABLESIZE; i++) {
17502 struct tblentry *e = fs->cmdtable[i];
17503 while (e) {
17504 if (e->cmdtype == CMDBUILTIN)
17505 e->param.cmd = builtintab + e->param.index;
17506 e = e->next;
17507 }
17508 }
17509 fs->gmp->trap_ptr = fs->gmp->trap;
17510
17511 /* Set global variables */
17512 ASSIGN_CONST_PTR(&ash_ptr_to_globals_var, fs->gvp);
17513 ASSIGN_CONST_PTR(&ash_ptr_to_globals_misc, fs->gmp);
17514 cmdtable = fs->cmdtable;
17515#if ENABLE_ASH_ALIAS
17516 atab = fs->atab; /* will be NULL for FS_SHELLEXEC */
17517#endif
17518#if MAX_HISTORY
17519 if (fs->cnt_history) {
17520 line_input_state = new_line_input_t(FOR_SHELL);
17521 line_input_state->cnt_history = fs->cnt_history;
17522 for (i = 0; i < line_input_state->cnt_history; i++)
17523 line_input_state->history[i] = fs->history[i];
17524 }
17525#endif
17526#if JOBS_WIN32
17527 jobtab = fs->jobtab;
17528 njobs = fs->njobs;
17529 curjob = fs->curjob;
17530#endif
17531
17532 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
17533
17534 reinitvar();
17535
17536 if (setjmp(jmploc.loc)) {
17537 exitreset();
17538 exitshell();
17539 }
17540 exception_handler = &jmploc;
17541
17542 shlvl++;
17543 if (fs->mode == FORK_BG) {
17544 SetConsoleCtrlHandler(NULL, TRUE);
17545 if (fs->nprocs == 0) {
17546 close(0);
17547 if (open(bb_dev_null, O_RDONLY) != 0)
17548 ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
17549 }
17550 }
17551 else {
17552 SetConsoleCtrlHandler(ctrl_handler, TRUE);
17553 }
17554
17555 if (fs->n && fs->n->type == NCMD /* is it single cmd? */
17556 /* && n->ncmd.args->type == NARG - always true? */
17557 && fs->n->ncmd.args && strcmp(fs->n->ncmd.args->narg.text, "trap") == 0
17558 && fs->n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
17559 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
17560 ) {
17561 TRACE(("Trap hack\n"));
17562 /* Save trap handler strings for trap builtin to print */
17563 fs->gmp->trap_ptr = xmemdup(fs->gmp->trap, sizeof(fs->gmp->trap));
17564 /* Fall through into clearing traps */
17565 }
17566 clear_traps();
17567#if JOBS_WIN32
17568 /* do job control only in root shell */
17569 doing_jobctl = 0;
17570
17571 if (fs->n && fs->n->type == NCMD && fs->n->ncmd.args &&
17572 strcmp(fs->n->ncmd.args->narg.text, "jobs") == 0) {
17573 TRACE(("Job hack\n"));
17574 if (!fs->jpnull)
17575 freejob(curjob);
17576 goto end;
17577 }
17578 for (struct job *jp = curjob; jp; jp = jp->prev_job)
17579 freejob(jp);
17580#endif
17581 end:
17582 forkshell_child(fs);
17583}
17584
17585#undef free
17586static void
17587sticky_free(void *base)
17588{
17589 if (base >= sticky_mem_start && base < sticky_mem_end)
17590 return;
17591 free(base);
17592}
17593#endif
14887 17594
14888/*- 17595/*-
14889 * Copyright (c) 1989, 1991, 1993, 1994 17596 * Copyright (c) 1989, 1991, 1993, 1994
diff --git a/shell/math.h b/shell/math.h
index 439031828..aeb3b93c3 100644
--- a/shell/math.h
+++ b/shell/math.h
@@ -47,7 +47,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
47 47
48#if ENABLE_FEATURE_SH_MATH_64 48#if ENABLE_FEATURE_SH_MATH_64
49typedef long long arith_t; 49typedef long long arith_t;
50# define ARITH_FMT "%lld" 50#define ARITH_FMT "%"LL_FMT"d"
51#else 51#else
52typedef long arith_t; 52typedef long arith_t;
53# define ARITH_FMT "%ld" 53# define ARITH_FMT "%ld"
diff --git a/shell/random.c b/shell/random.c
index 56c7c5a3c..ffe0cc937 100644
--- a/shell/random.c
+++ b/shell/random.c
@@ -19,6 +19,17 @@
19# include "random.h" 19# include "random.h"
20# define RAND_BASH_MASK 0x7fff 20# define RAND_BASH_MASK 0x7fff
21 21
22# if ENABLE_FEATURE_PRNG_SHELL
23uint32_t FAST_FUNC
24next_random(random_t *rnd)
25{
26 return full_random(rnd) & RAND_BASH_MASK;
27}
28# undef RAND_BASH_MASK
29# define RAND_BASH_MASK 0xffffffff
30# define next_random full_random
31# endif
32
22#else 33#else
23# include <stdint.h> 34# include <stdint.h>
24# include <unistd.h> 35# include <unistd.h>
diff --git a/shell/random.h b/shell/random.h
index c4eb44c13..75fe0f69f 100644
--- a/shell/random.h
+++ b/shell/random.h
@@ -35,6 +35,9 @@ typedef struct random_t {
35 ((rnd)->galois_LFSR = 0) 35 ((rnd)->galois_LFSR = 0)
36 36
37uint32_t next_random(random_t *rnd) FAST_FUNC; 37uint32_t next_random(random_t *rnd) FAST_FUNC;
38#if ENABLE_FEATURE_PRNG_SHELL
39uint32_t full_random(random_t *rnd) FAST_FUNC;
40#endif
38 41
39POP_SAVED_FUNCTION_VISIBILITY 42POP_SAVED_FUNCTION_VISIBILITY
40 43
diff --git a/shell/shell_common.c b/shell/shell_common.c
index e5c2cefb3..7fb5f8c58 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -62,7 +62,9 @@ shell_builtin_read(struct builtin_read_params *params)
62 char **pp; 62 char **pp;
63 char *buffer; 63 char *buffer;
64 char delim; 64 char delim;
65#if !ENABLE_PLATFORM_MINGW32
65 struct termios tty, old_tty; 66 struct termios tty, old_tty;
67#endif
66 const char *retval; 68 const char *retval;
67 int bufpos; /* need to be able to hold -1 */ 69 int bufpos; /* need to be able to hold -1 */
68 int startword; 70 int startword;
@@ -158,6 +160,7 @@ shell_builtin_read(struct builtin_read_params *params)
158 ifs = defifs; 160 ifs = defifs;
159 161
160 read_flags = params->read_flags; 162 read_flags = params->read_flags;
163#if !ENABLE_PLATFORM_MINGW32
161 if (nchars || (read_flags & BUILTIN_READ_SILENT)) { 164 if (nchars || (read_flags & BUILTIN_READ_SILENT)) {
162 tcgetattr(fd, &tty); 165 tcgetattr(fd, &tty);
163 old_tty = tty; 166 old_tty = tty;
@@ -180,6 +183,7 @@ shell_builtin_read(struct builtin_read_params *params)
180 * Ignoring, it's harmless. */ 183 * Ignoring, it's harmless. */
181 tcsetattr(fd, TCSANOW, &tty); 184 tcsetattr(fd, TCSANOW, &tty);
182 } 185 }
186#endif
183 187
184 retval = (const char *)(uintptr_t)0; 188 retval = (const char *)(uintptr_t)0;
185 startword = 1; 189 startword = 1;
@@ -196,6 +200,7 @@ shell_builtin_read(struct builtin_read_params *params)
196 if ((bufpos & 0xff) == 0) 200 if ((bufpos & 0xff) == 0)
197 buffer = xrealloc(buffer, bufpos + 0x101); 201 buffer = xrealloc(buffer, bufpos + 0x101);
198 202
203 IF_PLATFORM_MINGW32(loop:)
199 timeout = -1; 204 timeout = -1;
200 if (params->opt_t) { 205 if (params->opt_t) {
201 timeout = end_ms - (unsigned)monotonic_ms(); 206 timeout = end_ms - (unsigned)monotonic_ms();
@@ -216,12 +221,48 @@ shell_builtin_read(struct builtin_read_params *params)
216 errno = 0; 221 errno = 0;
217 pfd[0].events = POLLIN; 222 pfd[0].events = POLLIN;
218//TODO race with a signal arriving just before the poll! 223//TODO race with a signal arriving just before the poll!
224#if ENABLE_PLATFORM_MINGW32
225 /* Don't poll if timeout is -1, it hurts performance. */
226 if (timeout >= 0)
227#endif
219 if (poll(pfd, 1, timeout) <= 0) { 228 if (poll(pfd, 1, timeout) <= 0) {
220 /* timed out, or EINTR */ 229 /* timed out, or EINTR */
221 err = errno; 230 err = errno;
222 retval = (const char *)(uintptr_t)1; 231 retval = (const char *)(uintptr_t)1;
223 goto ret; 232 goto ret;
224 } 233 }
234#if ENABLE_PLATFORM_MINGW32
235 if (isatty(fd)) {
236 int64_t key;
237
238 key = windows_read_key(fd, NULL, timeout);
239 if (key == 0x03) {
240 /* ^C pressed */
241 retval = (const char *)(uintptr_t)2;
242 goto ret;
243 }
244 else if (key == -1 || (key == 0x1a && bufpos == 0)) {
245 /* timeout or ^Z at start of buffer */
246 retval = (const char *)(uintptr_t)1;
247 goto ret;
248 }
249 else if (key == '\b') {
250 if (bufpos > 0) {
251 --bufpos;
252 ++nchars;
253 if (!(read_flags & BUILTIN_READ_SILENT)) {
254 console_write("\b \b", 3);
255 }
256 }
257 goto loop;
258 }
259 buffer[bufpos] = key == '\r' ? '\n' : key;
260 if (!(read_flags & BUILTIN_READ_SILENT)) {
261 /* echo input if not in silent mode */
262 console_write(buffer + bufpos, 1);
263 }
264 } else
265#endif
225 if (read(fd, &buffer[bufpos], 1) != 1) { 266 if (read(fd, &buffer[bufpos], 1) != 1) {
226 err = errno; 267 err = errno;
227 retval = (const char *)(uintptr_t)1; 268 retval = (const char *)(uintptr_t)1;
@@ -229,8 +270,31 @@ shell_builtin_read(struct builtin_read_params *params)
229 } 270 }
230 271
231 c = buffer[bufpos]; 272 c = buffer[bufpos];
273#if ENABLE_PLATFORM_MINGW32
274 if (c == '\n') {
275 if (backslash == 2 || (bufpos > 0 && buffer[bufpos - 1] == '\r')) {
276 /* We saw either:
277 * - BS CR LF: remove CR, fall through to ignore escaped LF
278 * and exit BS context.
279 * - CR LF not in BS context: replace CR with LF */
280 buffer[--bufpos] = c;
281 ++nchars;
282 }
283 } else if (backslash == 2) {
284 /* We saw BS CR ??, keep escaped CR, exit BS context,
285 * process ?? */
286 backslash = 0;
287 }
288#endif
232 if (!(read_flags & BUILTIN_READ_RAW)) { 289 if (!(read_flags & BUILTIN_READ_RAW)) {
233 if (backslash) { 290 if (backslash) {
291#if ENABLE_PLATFORM_MINGW32
292 if (c == '\r') {
293 /* We have BS CR, keep CR for now, might see LF next */
294 backslash = 2;
295 goto put;
296 }
297#endif
234 backslash = 0; 298 backslash = 0;
235 if (c != '\n') 299 if (c != '\n')
236 goto put; 300 goto put;
@@ -329,8 +393,10 @@ shell_builtin_read(struct builtin_read_params *params)
329 393
330 ret: 394 ret:
331 free(buffer); 395 free(buffer);
396#if !ENABLE_PLATFORM_MINGW32
332 if (read_flags & BUILTIN_READ_SILENT) 397 if (read_flags & BUILTIN_READ_SILENT)
333 tcsetattr(fd, TCSANOW, &old_tty); 398 tcsetattr(fd, TCSANOW, &old_tty);
399#endif
334 400
335 errno = err; 401 errno = err;
336 return retval; 402 return retval;
@@ -339,6 +405,7 @@ shell_builtin_read(struct builtin_read_params *params)
339 405
340/* ulimit builtin */ 406/* ulimit builtin */
341 407
408#if !ENABLE_PLATFORM_MINGW32
342struct limits { 409struct limits {
343 uint8_t cmd; /* RLIMIT_xxx fit into it */ 410 uint8_t cmd; /* RLIMIT_xxx fit into it */
344 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ 411 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
@@ -707,3 +774,9 @@ shell_builtin_ulimit(char **argv)
707 774
708 return EXIT_SUCCESS; 775 return EXIT_SUCCESS;
709} 776}
777#else
778int FAST_FUNC shell_builtin_ulimit(char **argv UNUSED_PARAM)
779{
780 return 1;
781}
782#endif
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index be25f6696..af9ed5359 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -480,6 +480,20 @@ testing 'awk backslash+newline eaten with no trace' \
480 "Hello world\n" \ 480 "Hello world\n" \
481 '' '' 481 '' ''
482 482
483optional PLATFORM_MINGW32
484testing 'awk match line ending' \
485 "awk '/world$/'" \
486 "world\n" \
487 "" \
488 "hello\r\nworld\r\n"
489
490testing 'awk backslash+CRLF eaten with no trace' \
491 "awk -f -" \
492 "Hello world\n" \
493 '' \
494 'BEGIN { printf "Hello\\\r\n world\\n" }\n'
495SKIP=
496
483# User-supplied bug (SEGV) example, was causing use-after-realloc 497# User-supplied bug (SEGV) example, was causing use-after-realloc
484testing 'awk assign while assign' \ 498testing 'awk assign while assign' \
485 "awk '\$5=\$\$5=\$0'; echo \$?" \ 499 "awk '\$5=\$\$5=\$0'; echo \$?" \
diff --git a/testsuite/busybox.tests b/testsuite/busybox.tests
index beb17440c..2ce09b281 100755
--- a/testsuite/busybox.tests
+++ b/testsuite/busybox.tests
@@ -7,11 +7,22 @@
7. ./testing.sh 7. ./testing.sh
8test -f "$bindir/.config" && . "$bindir/.config" 8test -f "$bindir/.config" && . "$bindir/.config"
9 9
10ln -s `which busybox` unknown 10if [ -f "$bindir/busybox.exe" ]; then
11 # Copy rather than link busybox.exe: we can only make hard
12 # links which can't be deleted because Windows sees the
13 # executable as running.
14 suffix=".exe"
15 lncmd="cp"
16else
17 suffix=""
18 lncmd="ln -s"
19fi
20
21$lncmd "$(which busybox)" unknown$suffix
11 22
12testing "busybox as unknown name" "./unknown 2>&1" \ 23testing "busybox as unknown name" "./unknown 2>&1" \
13 "unknown: applet not found\n" "" "" 24 "unknown: applet not found\n" "" ""
14rm unknown 25rm unknown$suffix
15 26
16# We need busybox --help to be enabled for the rest of tests 27# We need busybox --help to be enabled for the rest of tests
17test x"$CONFIG_BUSYBOX" = x"y" \ 28test x"$CONFIG_BUSYBOX" = x"y" \
@@ -23,7 +34,7 @@ optional FEATURE_VERBOSE_USAGE
23testing "busybox --help busybox" "true | busybox --help busybox 2>&1 | cat" "$HELPDUMP\n" "" "" 34testing "busybox --help busybox" "true | busybox --help busybox 2>&1 | cat" "$HELPDUMP\n" "" ""
24SKIP= 35SKIP=
25 36
26ln -s `which busybox` busybox-suffix 37$lncmd "$(which busybox)" busybox-suffix$suffix
27for i in busybox ./busybox-suffix 38for i in busybox ./busybox-suffix
28do 39do
29 testing "$i" "$i 2>&1 | cat" "$HELPDUMP\n" "" "" 40 testing "$i" "$i 2>&1 | cat" "$HELPDUMP\n" "" ""
@@ -42,6 +53,6 @@ do
42 testing "$i --help unknown" "$i --help unknown 2>&1" \ 53 testing "$i --help unknown" "$i --help unknown 2>&1" \
43 "unknown: applet not found\n" "" "" 54 "unknown: applet not found\n" "" ""
44done 55done
45rm busybox-suffix 56rm busybox-suffix$suffix
46 57
47exit $FAILCOUNT 58exit $FAILCOUNT
diff --git a/testsuite/diff.tests b/testsuite/diff.tests
index 0ced0f248..ee0567a80 100755
--- a/testsuite/diff.tests
+++ b/testsuite/diff.tests
@@ -123,6 +123,69 @@ testing "diff always takes context from old file" \
123 "abc\na c\ndef\n" \ 123 "abc\na c\ndef\n" \
124 "a c\n" 124 "a c\n"
125 125
126optional PLATFORM_MINGW32 LONG_OPTS
127testing "diff LF line endings" \
128 'diff -u - input' \
129"\
130--- -
131+++ input
132@@ -1,4 +1,4 @@
133 a
134 b
135+c
136 d
137-e
138" \
139 "a\nb\nc\nd\n" \
140 "a\nb\nd\ne\n"
141
142testing "diff --binary LF line endings" \
143 'diff --binary -u - input' \
144"\
145--- -
146+++ input
147@@ -1,4 +1,4 @@
148 a
149 b
150+c
151 d
152-e
153" \
154 "a\nb\nc\nd\n" \
155 "a\nb\nd\ne\n"
156
157testing "diff CRLF line endings" \
158 'diff -u - input' \
159"\
160--- -
161+++ input
162@@ -1,4 +1,4 @@
163 a
164 b
165+c
166 d
167-e
168" \
169 "a\r\nb\r\nc\r\nd\r\n" \
170 "a\r\nb\r\nd\r\ne\r\n"
171
172testing "diff --binary CRLF line endings" \
173 'diff --binary -u - input' \
174"\
175--- -
176+++ input
177@@ -1,4 +1,4 @@
178 a
179 b
180+c
181 d
182-e
183" \
184 "a\r\nb\r\nc\r\nd\r\n" \
185 "a\r\nb\r\nd\r\ne\r\n"
186
187SKIP=
188
126# testing "test name" "commands" "expected result" "file input" "stdin" 189# testing "test name" "commands" "expected result" "file input" "stdin"
127 190
128# clean up 191# clean up
diff --git a/testsuite/env.tests b/testsuite/env.tests
new file mode 100755
index 000000000..8b810e44b
--- /dev/null
+++ b/testsuite/env.tests
@@ -0,0 +1,71 @@
1#!/bin/sh
2# Copyright 2022 by Ron Yorston
3# Licensed under GPLv2, see file LICENSE in this source tree.
4
5. ./testing.sh
6
7# testing "test name" "commands" "expected result" "file input" "stdin"
8
9optional PLATFORM_MINGW32
10# Not so much a test of 'env' as of whether environment variables
11# (or the lack thereof) are correctly passed to child processes.
12testing "environment variables 1a" \
13 "V=set env sh -c 'env | grep ^V='" \
14 "V=set
15" "" ""
16
17testing "environment variables 1b" \
18 "V= env sh -c 'env | grep ^V='" \
19 "V=
20" "" ""
21
22testing "environment variables 1c" \
23 "env sh -c 'env | grep ^V='" \
24 "" "" ""
25
26testing "environment variables 2a" \
27 "V=set sh -c 'env | grep ^V='" \
28 "V=set
29" "" ""
30
31testing "environment variables 2b" \
32 "V= sh -c 'env | grep ^V='" \
33 "V=
34" "" ""
35
36testing "environment variables 2c" \
37 "sh -c 'env | grep ^V='" \
38 "" "" ""
39
40testing "environment variables 3a" \
41 "V=set env sh -c 'echo \${V-unset}'" \
42 "set
43" "" ""
44
45testing "environment variables 3b" \
46 "V= env sh -c 'echo \${V-unset}'" \
47 "
48" "" ""
49
50testing "environment variables 3c" \
51 "env sh -c 'echo \${V-unset}'" \
52 "unset
53" "" ""
54
55testing "environment variables 4a" \
56 "V=set sh -c 'echo \${V-unset}'" \
57 "set
58" "" ""
59
60testing "environment variables 4b" \
61 "V= sh -c 'echo \${V-unset}'" \
62 "
63" "" ""
64
65testing "environment variables 4c" \
66 "sh -c 'echo \${V-unset}'" \
67 "unset
68" "" ""
69SKIP=
70
71exit $FAILCOUNT
diff --git a/testsuite/make.tests b/testsuite/make.tests
new file mode 100755
index 000000000..376bdcc15
--- /dev/null
+++ b/testsuite/make.tests
@@ -0,0 +1,765 @@
1#!/bin/sh
2
3. ./testing.sh
4unset MAKEFLAGS
5rm -rf make.tempdir
6
7# testing "test name" "command" "expected result" "file input" "stdin"
8
9testing "make basic makefile" \
10 "make -f -" "target\n" "" '
11target:
12 @echo target
13'
14
15testing "make .DEFAULT rule for prerequisite" \
16 "make -f - 2>/dev/null" "source\n" "" '
17.DEFAULT:
18 @echo $@
19target: source
20'
21
22mkdir make.tempdir && cd make.tempdir || exit 1
23touch target.xyz
24testing "make empty command overrides inference rule" \
25 "make -f - target 2>/dev/null" "" "" '
26.SUFFIXES: .xyz
27.xyz:
28 @echo xyz
29target: ;
30'
31cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
32
33# Macros should be expanded before suffix substitution. The suffixes
34# can be obtained by macro expansion.
35testing "make macro expansion and suffix substitution" \
36 "make -f -" "src1.o src2.o\n" "" '
37DOTC = .c
38DOTO = .o
39SRC1 = src1.c
40SRCS = $(SRC1) src2.c
41target:
42 @echo $(SRCS:$(DOTC)=$(DOTO))
43'
44
45# Indeed, everything after the <colon> can be obtained by macro
46# macro expansion.
47testing "make macro expansion and suffix substitution 2" \
48 "make -f -" "src1.o src2.o\n" "" '
49DOTS = .c=.o
50SRC1 = src1.c
51SRCS = $(SRC1) src2.c
52target:
53 @echo $(SRCS:$(DOTS))
54'
55
56# It should be possible for an inference rule to determine that a
57# prerequisite can be created using an explicit rule.
58mkdir make.tempdir && cd make.tempdir || exit 1
59testing "make inference rule with explicit rule for prerequisite" \
60 "make -f -" "touch x.p\ncat x.p >x.q\n" "" '
61.SUFFIXES: .p .q
62x.q:
63x.p:
64 touch $@
65.p.q:
66 cat $< >$@
67'
68cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
69
70# Austin Group defect report 875 clarifies certain aspects of the
71# behaviour of inference rules. Study of this resulted in a number
72# of changes to pdpmake, though this test passed anyway.
73mkdir make.tempdir && cd make.tempdir || exit 1
74touch test.j test.k
75testing "make proper handling of inference rules 1" \
76 "make -f -" \
77 ".j.l\n" "" '
78.SUFFIXES: .j .k .l
79.j.l:
80 @echo .j.l
81.k.l:
82 @echo .k.l
83test.l: test.k
84test.j:
85test.k:
86'
87cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
88
89# There was a bug where the failure of a build command didn't result
90# in make returning a non-zero exit status.
91testing "make return error if command fails" \
92 "make -f - >/dev/null 2>&1; test \$? -gt 0 && echo OK" "OK\n" "" '
93target:
94 @exit 42
95'
96
97# An equal sign in a command on a target rule was detected as a
98# macro assignment.
99testing "make equal sign in inline command" \
100 "make -f -" "a = a\n" "" '
101a = a
102target:;@echo a = $(a)
103'
104
105# Ensure an inline command on a target rule can be detected even if
106# the semicolon is obfuscated.
107testing "make equal sign in obfuscated inline command" \
108 "make -f -" "a = a\n" "" '
109a = a
110semi = ;
111target:$(semi)@echo a = $(a)
112'
113
114# When a build command fails and the '-k' option has been provided
115# (continue execution on error) no further commands should be executed
116# for the current target.
117testing "make failure of build command with -k" \
118 "make -k -f - 2>/dev/null" "OK\n" "" '
119all: bar baz
120bar:
121 @echo OK
122 @false
123 @echo Not reached
124baz:
125 @:
126'
127# Build commands with a '+' prefix are executed even with the -q option.
128testing "make execute build command with + prefix and -q" \
129 "make -q -f - 2>/dev/null" "OK\n" "" '
130all: bar
131bar:
132 @+echo OK
133'
134
135# The -t option touches files that are out-of-date unless the target
136# has no commands or they're already up-to-date.
137mkdir make.tempdir && cd make.tempdir || exit 1
138touch baz
139testing "make check -t option" \
140 "make -t -f - 2>/dev/null" "touch bar\n" "" '
141all: foo bar baz
142foo:
143bar:
144 @echo bar
145baz:
146 @echo baz
147'
148cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
149
150# Build commands with a '+' prefix are executed even with the -t option.
151mkdir make.tempdir && cd make.tempdir || exit 1
152testing "make execute build command with + prefix and -t" \
153 "make -t -f - 2>/dev/null" "OK\n" "" '
154all: bar
155bar:
156 @+echo OK
157'
158cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
159
160# A macro created using ::= remembers it's of type immediate-expansion.
161# Immediate expansion also occurs when += is used to append to such a macro.
162testing "make appending to immediate-expansion macro" \
163 "make -f -" \
164 "hello 1 2 3\nhello 4 4\n" "" '
165world = 1
166hello ::= hello $(world)
167world = 2
168hello += $(world)
169world = 3
170hello += $(world)
171world = 4
172
173world = 1
174reset ::= hello $(world)
175world = 2
176# No longer immediate-expansion
177reset = hello $(world)
178world = 3
179reset += $(world)
180world = 4
181
182target:
183 @echo $(hello)
184 @echo $(reset)
185'
186
187# Since GNU make and bmake interpret := macro assignments differently,
188# POSIX has ::= for the GNU variant and :::= for BSD.
189testing "make different styles of := macro assignment" \
190 "make -f -" \
191 '65 a a $A\n' "" '
192A = a
193GNU ::= $A
194BSD1 :::= $A
195BSD2 :::= $$A
196A = 65
197
198target:
199 @echo '\''$(A) $(GNU) $(BSD1) $(BSD2)'\''
200'
201
202# Similar to the above but for macro assignments on the command line.
203# POSIX has ::= for the GNU variant and :::= for BSD.
204testing "make := macro assignment on command line" \
205 "make -f - A=a 'GNU::=\$A' 'BSD1:::=\$A' 'BSD2:::=\$\$A' A=65" \
206 '65 a a $A\n' "" '
207target:
208 @echo '\''$(A) $(GNU) $(BSD1) $(BSD2)'\''
209'
210
211# basic pattern macro expansion
212testing "make basic pattern macro expansion" \
213 "make -f -" \
214 "obj/util.o obj/main.o\n" "" '
215SRC = src/util.c src/main.c
216OBJ = $(SRC:src/%.c=obj/%.o)
217
218target:
219 @echo $(OBJ)
220'
221
222# pattern macro expansion; match any value
223testing "make pattern macro expansion; match any value" \
224 "make -f -" \
225 "any_value.o\n" "" '
226SRC = any_value
227OBJ = $(SRC:%=%.o)
228
229target:
230 @echo $(OBJ)
231'
232
233# pattern macro expansion with empty rvalue
234testing "make pattern macro expansion with empty rvalue" \
235 "make -f -" \
236 "\n" "" '
237SRC = util.c main.c
238OBJ = $(SRC:%.c=)
239
240target:
241 @echo $(OBJ)
242'
243
244# pattern macro expansion with multiple <percent> in rvalue
245# POSIX requires the first <percent> to be expanded, others
246# may or may not be expanded. Permit either case.
247testing "make pattern macro expansion with multiple <percent> in rvalue" \
248 "make -f - | sed 's/mainmainmain/main%%/'" \
249 "main%%\n" "" '
250SRC = main.c
251OBJ = $(SRC:%.c=%%%)
252
253target:
254 @echo $(OBJ)
255'
256
257# pattern macro expansion; zero match
258testing "make pattern macro expansion; zero match" \
259 "make -f -" \
260 "nsnp\n" "" '
261WORD = osop
262REPL = $(WORD:os%op=ns%np)
263
264target:
265 @echo $(REPL)
266'
267
268# Check that MAKE will contain argv[0], e.g make in this case
269testing "make basic MAKE macro expansion" \
270 "make -f -" \
271 "make\n" "" '
272target:
273 @echo $(MAKE)
274'
275
276# Check that MAKE defined as environment variable will overwrite default MAKE
277testing "make MAKE macro expansion; overwrite with env macro" \
278 "MAKE=hello make -f -" \
279 "hello\n" "" '
280target:
281 @echo $(MAKE)
282'
283
284# Check that MAKE defined on the command-line will overwrite MAKE defined in
285# Makefile
286testing "make MAKE macro expansion; overwrite with command-line macro" \
287 "make -f - MAKE=hello" \
288 "hello\n" "" '
289MAKE = test
290
291target:
292 @echo $(MAKE)
293'
294
295# POSIX draft states that if make was invoked using relative path, MAKE must
296# contain absolute path, not just argv[0]
297testing "make MAKE macro expansion; turn relative path into absolute" \
298 "../runtest-tempdir-links/make -f -" \
299 "ok\n" "" '
300target:
301 @test -e "$(MAKE)" && test "$(MAKE)" = "$$(env which make)" && echo ok
302'
303
304# $? contains prerequisites newer than target, file2 in this case
305# $^ has all prerequisites, file1 and file2
306touch -t 202206171200 file1
307touch -t 202206171201 target
308touch -t 202206171202 file2
309testing "make compare \$? and \$^ internal macros" \
310 "make -f -" \
311 "file2\nfile1 file2\n" "" '
312target: file1 file2
313 @echo $?
314 @echo $^
315'
316rm -f target file1 file2
317
318# Phony targets are executed (once) even if a matching file exists.
319# A .PHONY target with no prerequisites is ignored.
320touch -t 202206171201 target
321testing "make phony target" \
322 "make -f -" \
323 "phony\n" "" '
324.PHONY: target
325.PHONY:
326target:
327 @echo phony
328'
329rm -f target
330
331# Phony targets aren't touched with -t
332testing "make phony target not touched" \
333 "make -t -f - >/dev/null && test -f target && echo target" \
334 "" "" '
335.PHONY: target
336target:
337 @:
338'
339rm -f target
340
341# Include files are created or brought up-to-date
342mkdir make.tempdir && cd make.tempdir || exit 1
343testing "make create include file" \
344 "make -f -" \
345 "made\n" "" '
346target:
347 @echo $(VAR)
348mk:
349 @echo "VAR = made" >mk
350include mk
351'
352cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
353
354# Include files are created or brought up-to-date even when the -n
355# option is given.
356mkdir make.tempdir && cd make.tempdir || exit 1
357testing "make create include file even with -n" \
358 "make -n -f -" \
359 "echo made\n" "" '
360target:
361 @echo $(VAR)
362mk:
363 @echo "VAR = made" >mk
364include mk
365'
366cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
367
368# Failure to create an include file isn't an error. (Provided the
369# include line is ignoring non-existent files.)
370testing "make failure to create include file is OK" \
371 "make -f -" \
372 "OK\n" "" '
373target:
374 @echo OK
375mk:
376 @:
377-include mk
378'
379
380# $^ skips duplicate prerequisites, $+ doesn't
381mkdir make.tempdir && cd make.tempdir || exit 1
382touch file1 file2 file3
383testing "make skip duplicate entries in \$^ but not \$+" \
384 "make -f -" \
385 "file1 file2 file3\nfile1 file2 file2 file3 file3\n" "" '
386target: file1 file2 file2 file3 file3
387 @echo $^
388 @echo $+
389'
390cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
391
392# Assign the output of a shell command to a macro.
393testing "make shell assignment" \
394 "make -f -" \
395 "1 2 3 4\n" "" '
396hello != echo 1; echo 2; echo 3; echo; echo
397
398target:
399 @echo "$(hello) 4"
400'
401
402# Nested macro expansion is allowed. This should be compatible
403# with other implementations.
404testing "make nested macro expansion" \
405 "make -f -" "0 bc\n1 d\n2\n3\n4 bcd\n5 bcd\n" "" '
406a = b
407b = c
408c = d
409$(a:.q=.v)$(b:.z=.v) = bc
410bcd = bcd
411target:
412 @echo 0 $(bc)
413 @echo 1 $($($(a)))
414 @echo 2 $($(a) $(b) $(c))
415 @echo 3 $($a $b $c)
416 @echo 4 $($(a)$(b)$(c))
417 @echo 5 $($a$b$c)
418'
419
420# .WAIT is allowed as a prerequisite. Since parallel builds aren't
421# implemented it doesn't have any effect.
422mkdir make.tempdir && cd make.tempdir || exit 1
423touch file1 file2
424testing "make .WAIT is allowed as a prerequisite" \
425 "make -f -" \
426 "file1 file2\n" "" '
427target: file1 .WAIT file2
428 @echo $?
429'
430cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
431
432# Escaped newlines inside macro expansions in commands get different
433# treatment than those outside. In POSIX 2017 the output is 'a b ab'.
434testing "make replace escaped NL in macro in command with space" \
435 "make -f -" \
436 "a b a b\n" "" '
437M=word
438N=${M:word=a\\
439b}
440target:
441 @echo ${N} ${M:word=a\\
442b}
443'
444
445# The CURDIR macro is supported in POSIX 2024.
446testing "make CURDIR macro" \
447 "make -f -" \
448 "OK\n" "" '
449target:
450 @test "$(CURDIR)" = "$$(pwd -P)" && echo OK
451'
452# The CURDIR environment variable doesn't affect the macro
453export CURDIR=/you/are/here
454testing "make CURDIR macro not affected by environment" \
455 "make -f -" \
456 "OK\n" "" '
457target:
458 @test "$(CURDIR)" != "/you/are/here" && echo OK
459'
460
461# The -e option makes the CURDIR macro match the environment
462testing "make with -e CURDIR macro is affected by the environment" \
463 "make -e -f -" \
464 "/you/are/here\n" "" '
465target:
466 @echo $(CURDIR)
467'
468unset CURDIR
469
470# The fix for an equal sign in an inline command on a target rule broke
471# a complex chain of macro assignments generated by autotools.
472testing "make complex chain of macro assignments" \
473 "make -f -" "flag 1\n" "" '
474FLAG_ = $(FLAG_$(VALUE))
475FLAG_0 = flag 0
476FLAG_1 = flag 1
477MYFLAG = $(FLAG_$(VALUE))
478VALUE = 1
479
480target:
481 @echo $(MYFLAG)
482'
483
484# POSIX 2024 permits additional characters in macro and target names
485testing "make allow - and / in target names, - in macro names" \
486 "make -f -" \
487 "/hello\nhel-lo\nmac-ro\n" "" '
488target: ./hello hel-lo
489 @echo $(mac-ro)
490./hello:
491 @echo /hello
492hel-lo:
493 @echo hel-lo
494mac-ro = mac-ro
495'
496
497testing "make double-colon rule" \
498 "make -f -" "target1\ntarget2\n" "" '
499target::
500 @echo target1
501target::
502 @echo target2
503'
504
505# There was a bug whereby the modification time of a file created by
506# double-colon rules wasn't correctly updated. This test checks that
507# the bug is now fixed.
508mkdir make.tempdir && cd make.tempdir || exit 1
509touch -t 202206171200 file1
510touch -t 202206171201 intermediate
511touch -t 202206171202 target
512touch -t 202206171203 file2
513testing "make target depends on prerequisite updated by double-colon rule" \
514 "make -f -" \
515 "file2\n" "" '
516target: intermediate
517 @cat intermediate
518intermediate:: file1
519 @echo file1 >>intermediate
520intermediate:: file2
521 @echo file2 >>intermediate
522'
523cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
524
525# Use chained inference rules to determine prerequisites.
526mkdir make.tempdir && cd make.tempdir || exit 1
527touch target.p
528testing "make chained inference rules" \
529 "make -s -f - target.s" \
530 "target.q\ntarget.r\ntarget.s\n" "" '
531.SUFFIXES: .p .q .r .s
532.p.q:
533 @cp $< $*.q
534 @echo $*.q
535.q.r:
536 @cp $< $*.r
537 @echo $*.r
538.r.s:
539 @cp $< $*.s
540 @echo $*.s
541'
542cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
543
544# make supports *, ? and [] wildcards in targets and prerequisites
545mkdir make.tempdir && cd make.tempdir || exit 1
546touch -t 202206171201 t1a t2aa t3b
547touch s1a s2aa s3b
548testing "make expand wildcards in filenames" \
549 "make -f - t1a t2aa t3b" \
550 "t1a s1a s2aa s3b\nt2aa s1a s2aa s3b\nt3b s1a s2aa s3b\n" "" '
551t1? t2* t3[abc]: s1? s2* s3[abc]
552 @echo $@ $?
553'
554cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
555
556# A '#' character in a macro expansion doesn't start a comment
557testing "make hash in macro expansion isn't a comment" \
558 "make -f -" \
559 ": hash # hash\n" "" '
560HASH = hash
561hash = $(HASH:hash=#)
562target:
563 : hash $(hash) hash
564'
565
566# A '#' character can be escaped with a backslash
567testing "make backslash-escaped hash isn't a comment" \
568 "make -f -" \
569 ": hash # hash\n" "" '
570hash = \\#
571target:
572 : hash $(hash) hash
573'
574
575# A '#' character in a command line doesn't start a comment
576testing "make hash in command line isn't a comment" \
577 "make -f -" \
578 ": hash # hash\n" "" '
579target:
580 : hash # hash
581'
582
583# Austin Group defect report 875 (mentioned above) actually used
584# suffixes '.a .b .c'. This doesn't matter in POSIX mode but it
585# caused a failure (now fixed) when chained inference rules were
586# allowed. The '.a.c' and the built-in '.c.a' inference rules
587# resulted in a loop.
588mkdir make.tempdir && cd make.tempdir || exit 1
589touch test.a test.b
590testing "make proper handling of inference rules 2" \
591 "make -f -" \
592 ".a.c\n" "" '
593.SUFFIXES: .a .b .c
594.a.c:
595 @echo .a.c
596.b.c:
597 @echo .b.c
598test.c: test.b
599test.a:
600test.b:
601'
602cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
603
604# Don't use the shell -e option when running commands.
605testing "make no shell -e option when running commands" \
606 "make -f -" "OK\n" "" '
607target:
608 @false; echo OK
609'
610
611# Macros and targets may be mixed on the command line
612testing "make allow mixed macros and targets" \
613 "make -f - FOO=foo foo BAR=bar bar" "foo\nbar\nfoo\nbar\n" "" '
614foo:
615 @echo $(FOO)
616 @echo $(BAR)
617bar:
618 @echo $(FOO)
619 @echo $(BAR)
620'
621
622# $* and $< are supported for target rules
623mkdir make.tempdir && cd make.tempdir || exit 1
624touch src.c src.h
625testing 'make support $* and $< for target rules' \
626 "make -f -" "src.c src.h\nsrc.o\nsrc\nsrc.c\n" "" '
627src.o: src.c src.h
628 @echo "$?"
629 @echo "$@"
630 @echo "$*"
631 @echo "$<"
632'
633cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
634
635# ifeq/ifneq conditionals are supported
636testing 'make support ifeq and ifneq conditionals' \
637 "make -f -" "A OK\nB OK\n" "" '
638A = a
639B = b
640target:
641ifeq ($(A),a)
642 @echo A OK
643else
644 @echo A not OK
645endif
646ifneq "a" "$B"
647 @echo B OK
648endif
649'
650
651# An empty original suffix indicates that every word should have
652# the new suffix added. If neither suffix is provided the words
653# remain unchanged.
654testing "make macro expansion and suffix substitution 3" \
655 "make -f -" "src1.c src2.c\nsrc1 src2\n" "" '
656SRCS = src1 src2
657target:
658 @echo $(SRCS:=.c)
659 @echo $(SRCS:=)
660'
661
662# Skip duplicate entries in $? and $^
663mkdir make.tempdir && cd make.tempdir || exit 1
664touch -t 202206171200 file1 file3
665touch -t 202206171201 target
666touch -t 202206171202 file2
667testing "make skip duplicate entries in \$? and \$^" \
668 "make -f -" \
669 "file2\nfile1 file2 file3\n" "" '
670target: file1 file2 file2 file3 file3
671 @echo $?
672 @echo $^
673'
674cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
675
676# Skip duplicate entries in $? and $^, with each double-colon rule
677# handled separately
678mkdir make.tempdir && cd make.tempdir || exit 1
679touch -t 202206171200 file1 file3
680touch -t 202206171201 target
681touch -t 202206171202 file2
682testing "make skip duplicate entries: double-colon rules" \
683 "make -f -" \
684 "file2\nfile1 file3 file2\nfile2\nfile2 file3\n" "" '
685target:: file1 file3 file1 file2 file3
686 @echo $?
687 @echo $^
688target:: file2 file3 file3
689 @echo $?
690 @echo $^
691'
692cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
693
694# Skip duplicate entries in $? and $^, with each double-colon rule
695# handled separately. No prerequisites out-of-date in the first.
696mkdir make.tempdir && cd make.tempdir || exit 1
697touch -t 202206171200 file1 file3
698touch -t 202206171201 target
699touch -t 202206171202 file2
700testing "make skip duplicate entries: double-colon rules, only second invoked" \
701 "make -f -" \
702 "file2\nfile2 file3\n" "" '
703target:: file1 file3 file1 file3
704 @echo $?
705 @echo $^
706target:: file2 file3 file3
707 @echo $?
708 @echo $^
709'
710cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
711
712# .DEFAULT rules with no commands or some prerequisites are ignored.
713# .DEFAULT rules with commands can be redefined.
714testing "make: .DEFAULT rule" \
715 "make -f - default" "default2\n" "" '
716.DEFAULT: ignored
717.DEFAULT:
718 @echo default1
719.DEFAULT:
720 @echo default2
721target:
722'
723
724testing "make: double-colon rule" \
725 "make -f -" "target1\ntarget2\n" "" '
726target::
727 @echo target1
728target::
729 @echo target2
730'
731
732# Double-colon rules didn't work properly if their target was phony:
733# - they didn't ignore the presence of a file matching the target name;
734# - they were also invoked as if they were a single-colon rule.
735mkdir make.tempdir && cd make.tempdir || exit 1
736touch -t 202206171200 file1
737touch -t 202206171201 target
738testing "make phony target of double-colon rule" \
739 "make -f - 2>&1" \
740 "unconditional\nconditional\n" "" '
741.PHONY: target
742target::
743 @echo unconditional
744target:: file1
745 @echo conditional
746file1:
747 @touch file1
748'
749cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
750
751# GNU make and BSD make don't allow the use of inference rules
752# for phony targets. In POSIX mode the output is "phony.xyz\n".
753mkdir make.tempdir && cd make.tempdir || exit 1
754touch phony.xyz
755testing "make don't use inference rule for phony target" \
756 "make -f -" "make: nothing to be done for phony\n" "" '
757.PHONY: phony
758.SUFFIXES: .xyz
759.xyz:
760 @echo $<
761phony:
762'
763cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
764
765exit $FAILCOUNT
diff --git a/testsuite/runtest b/testsuite/runtest
index 44f9cd1a1..adbcb1178 100755
--- a/testsuite/runtest
+++ b/testsuite/runtest
@@ -99,6 +99,20 @@ if [ x"$1" = x"-v" ]; then
99 shift 99 shift
100fi 100fi
101 101
102if [ -f "$bindir/busybox.exe" ]; then
103 suffix=".exe"
104 lnflag=""
105
106 # Some tests require /bin/echo and /bin/true exist
107 test ! -d /tmp && mkdir /tmp
108 test ! -d /bin && mkdir /bin
109 test ! -f /bin/echo.exe && cp "$bindir/busybox.exe" /bin/echo.exe
110 test ! -f /bin/true.exe && cp "$bindir/busybox.exe" /bin/true.exe
111else
112 suffix=""
113 lnflag="-s"
114fi
115
102implemented=$( 116implemented=$(
103 printf "busybox " # always implemented 117 printf "busybox " # always implemented
104 "$bindir/busybox" 2>&1 | 118 "$bindir/busybox" 2>&1 |
@@ -128,7 +142,7 @@ for i in $implemented; do
128 # Note: if $LINKSDIR/applet exists, we do not overwrite it. 142 # Note: if $LINKSDIR/applet exists, we do not overwrite it.
129 # Useful if one wants to run tests against a standard utility, 143 # Useful if one wants to run tests against a standard utility,
130 # not an applet. 144 # not an applet.
131 ln -s "$bindir/busybox" "$LINKSDIR/$i" 2>/dev/null 145 ln $lnflag "$bindir/busybox$suffix" "$LINKSDIR/$i$suffix" 2>/dev/null
132done 146done
133 147
134# Set up option flags so tests can be selective. 148# Set up option flags so tests can be selective.
@@ -146,7 +160,7 @@ for applet in $applets; do
146 160
147 # Is this a new-style test? 161 # Is this a new-style test?
148 if [ -f "$applet.tests" ]; then 162 if [ -f "$applet.tests" ]; then
149 if [ ! -e "$LINKSDIR/$applet" ]; then 163 if [ ! -e "$LINKSDIR/$applet$suffix" ]; then
150 # (avoiding bash'ism "${applet:0:4}") 164 # (avoiding bash'ism "${applet:0:4}")
151 if ! echo "$applet" | grep "^all_" >/dev/null; then 165 if ! echo "$applet" | grep "^all_" >/dev/null; then
152 echo "SKIPPED: $applet (not built)" 166 echo "SKIPPED: $applet (not built)"
diff --git a/testsuite/sh.tests b/testsuite/sh.tests
new file mode 100755
index 000000000..0eccf20bc
--- /dev/null
+++ b/testsuite/sh.tests
@@ -0,0 +1,118 @@
1#!/bin/sh
2#
3# Test sh scripts
4#
5# Copyright 2019 by STMicroelectronics
6# Licensed under GPLv2, see file LICENSE in this source tree.
7
8. ./testing.sh
9
10test -f "$bindir/.config" && . "$bindir/.config"
11
12# testing "test name" "options" "expected result" "file input" "stdin"
13
14optional PLATFORM_MINGW32
15# Test case
16testing "shebang" \
17 "uudecode; sh -c './shebang.sh'; echo \$?" \
18 "Hello world
190
20" \
21"" "\
22begin-base64 755 shebang.sh
23IyEvYmluL3NoCmVjaG8gIkhlbGxvIHdvcmxkIgo=
24====
25"
26rm -f shebang.sh
27
28# Test case
29testing "shebang with whitespace" \
30 "uudecode; sh -c './shebang_trailing_space.sh'; echo \$?" \
31 "Hello world
320
33" \
34"" "\
35begin-base64 755 shebang_trailing_space.sh
36IyEvYmluL3NoIAplY2hvICJIZWxsbyB3b3JsZCIK
37====
38"
39rm -f shebang_trailing_space.sh
40
41# Test case
42testing "shebang with argument" \
43 "uudecode; sh -c './shebang_argument.sh'; echo \$?" \
44 "Hello world
450
46" \
47"" "\
48begin-base64 755 shebang_argument.sh
49IyEvYmluL3NoIC0KZWNobyAiSGVsbG8gd29ybGQiCg==
50====
51"
52rm -f shebang_argument.sh
53
54# Test case
55testing "shebang with leading whitespace and argument" \
56 "uudecode; sh -c './shebang_leading_space_argument.sh'; echo \$?" \
57 "Hello world
580
59" \
60"" "\
61begin-base64 755 shebang_leading_space_argument.sh
62IyEvYmluL3NoICAtCmVjaG8gIkhlbGxvIHdvcmxkIgo=
63====
64"
65rm -f shebang_leading_space_argument.sh
66
67# Test case
68testing "shebang with argument and trailing whitespace" \
69 "uudecode; sh -c './shebang_argument_trailing_space.sh'; echo \$?" \
70 "Hello world
710
72" \
73"" "\
74begin-base64 755 shebang_argument_trailing_space.sh
75IyEvYmluL3NoIC0gCmVjaG8gIkhlbGxvIHdvcmxkIgo=
76====
77"
78rm -f shebang_argument_trailing_space.sh
79
80# Test case
81testing "shebang with leading whitespace, argument and trailing whitespace" \
82 "uudecode; sh -c './shebang_leading_argument_trailing_space.sh'; echo \$?" \
83 "Hello world
840
85" \
86"" "\
87begin-base64 755 shebang_leading_argument_trailing_space.sh
88IyEvYmluL3NoICAtIAplY2hvICJIZWxsbyB3b3JsZCIK
89====
90"
91rm -f shebang_leading_argument_trailing_space.sh
92
93testing "sh remove CRs from string being evaluated" \
94 "sh -c \"$(printf 'set -e\r\necho Hello world\r\n')\"" \
95 "Hello world\n" "" ""
96
97testing "sh preserve lone CRs during field splitting" \
98 "sh input" \
99 "Hello\r world\n" "echo \$(printf \"Hello\\\\r\\\\r\\\\nworld\\\\r\\\\n\")" ""
100
101testing "sh read with CRLF" \
102 "printf '1 2\\r\\n' | { read var; printf \"\${var}\\\\n\"; }" \
103 "1 2\n" "" ""
104
105testing "sh read with CR" \
106 "printf '1\\r2\\r\\n' | { read var; printf \"\${var}\\\\n\"; }" \
107 "1\r2\n" "" ""
108
109testing "sh read with \\CRLF" \
110 "printf '1\\\\\r\\n2\\r\\n' | { read var; printf \"\${var}\\\\n\"; }" \
111 "12\n" "" ""
112
113testing "sh read with \\CR" \
114 "printf '1\\\\\r2\\r\\n' | { read var; printf \"\${var}\\\\n\"; }" \
115 "1\r2\n" "" ""
116SKIP=
117
118exit $FAILCOUNT
diff --git a/util-linux/getopt.c b/util-linux/getopt.c
index 213bfab0b..e61d68982 100644
--- a/util-linux/getopt.c
+++ b/util-linux/getopt.c
@@ -412,6 +412,11 @@ int getopt_main(int argc, char **argv)
412 bb_simple_error_msg_and_die("missing optstring argument"); 412 bb_simple_error_msg_and_die("missing optstring argument");
413 } 413 }
414 414
415#if ENABLE_PLATFORM_MINGW32
416 // Mingw-w64 getopt(3) uses __argv[0] in error messages, not the
417 // first element of its argument array.
418 __argv[0] =
419#endif
415 argv[n] = name ? name : argv[0]; 420 argv[n] = name ? name : argv[0];
416 return generate_output(argv + n, argc - n, optstr, long_options); 421 return generate_output(argv + n, argc - n, optstr, long_options);
417} 422}
diff --git a/util-linux/more.c b/util-linux/more.c
index bffe6ee5e..0be8e0b9b 100644
--- a/util-linux/more.c
+++ b/util-linux/more.c
@@ -35,6 +35,9 @@
35//usage:#define more_example_usage 35//usage:#define more_example_usage
36//usage: "$ dmesg | more\n" 36//usage: "$ dmesg | more\n"
37 37
38#if ENABLE_PLATFORM_MINGW32
39#include <conio.h>
40#endif
38#include "libbb.h" 41#include "libbb.h"
39#include "common_bufsiz.h" 42#include "common_bufsiz.h"
40 43
@@ -59,6 +62,7 @@ static void tcsetattr_tty_TCSANOW(struct termios *settings)
59 tcsetattr(G.tty_fileno, TCSANOW, settings); 62 tcsetattr(G.tty_fileno, TCSANOW, settings);
60} 63}
61 64
65#if !ENABLE_PLATFORM_MINGW32
62static void gotsig(int sig UNUSED_PARAM) 66static void gotsig(int sig UNUSED_PARAM)
63{ 67{
64 /* bb_putchar_stderr doesn't use stdio buffering, 68 /* bb_putchar_stderr doesn't use stdio buffering,
@@ -67,6 +71,7 @@ static void gotsig(int sig UNUSED_PARAM)
67 tcsetattr_tty_TCSANOW(&G.initial_settings); 71 tcsetattr_tty_TCSANOW(&G.initial_settings);
68 _exit_FAILURE(); 72 _exit_FAILURE();
69} 73}
74#endif
70 75
71#define CONVERTED_TAB_SIZE 8 76#define CONVERTED_TAB_SIZE 8
72 77
@@ -96,9 +101,13 @@ int more_main(int argc UNUSED_PARAM, char **argv)
96 * is not a tty and turns into cat. This makes sense. */ 101 * is not a tty and turns into cat. This makes sense. */
97 if (!isatty(STDOUT_FILENO)) 102 if (!isatty(STDOUT_FILENO))
98 return bb_cat(argv); 103 return bb_cat(argv);
104#if !ENABLE_PLATFORM_MINGW32
99 tty = fopen_for_read(CURRENT_TTY); 105 tty = fopen_for_read(CURRENT_TTY);
100 if (!tty) 106 if (!tty)
101 return bb_cat(argv); 107 return bb_cat(argv);
108#else
109 tty = stdin;
110#endif
102 111
103 G.tty_fileno = fileno(tty); 112 G.tty_fileno = fileno(tty);
104 113
@@ -153,6 +162,11 @@ int more_main(int argc UNUSED_PARAM, char **argv)
153 */ 162 */
154 for (;;) { 163 for (;;) {
155 fflush_all(); 164 fflush_all();
165#if ENABLE_PLATFORM_MINGW32
166 if (!(terminal_mode(FALSE) & VT_INPUT))
167 input = _getch();
168 else
169#endif
156 input = getc(tty); 170 input = getc(tty);
157 input = tolower(input); 171 input = tolower(input);
158 /* Erase the last message */ 172 /* Erase the last message */
@@ -167,6 +181,10 @@ int more_main(int argc UNUSED_PARAM, char **argv)
167 * commands, else we show help msg. */ 181 * commands, else we show help msg. */
168 if (input == ' ' || input == '\n' || input == 'r') 182 if (input == ' ' || input == '\n' || input == 'r')
169 break; 183 break;
184#if ENABLE_PLATFORM_MINGW32
185 if (input == '\r')
186 break;
187#endif
170 len = printf("(Enter:next line Space:next page Q:quit R:show the rest)"); 188 len = printf("(Enter:next line Space:next page Q:quit R:show the rest)");
171 } 189 }
172 len = 0; 190 len = 0;
@@ -201,6 +219,10 @@ int more_main(int argc UNUSED_PARAM, char **argv)
201 * will move us to a new line. */ 219 * will move us to a new line. */
202 if (++lines >= G.terminal_height || input == '\n') 220 if (++lines >= G.terminal_height || input == '\n')
203 please_display_more_prompt = 1; 221 please_display_more_prompt = 1;
222#if ENABLE_PLATFORM_MINGW32
223 if (input == '\r')
224 please_display_more_prompt = 1;
225#endif
204 len = 0; 226 len = 0;
205 } 227 }
206 if (c != '\n' && wrap) { 228 if (c != '\n' && wrap) {
diff --git a/util-linux/rev.c b/util-linux/rev.c
index aad53722d..9a4b887e4 100644
--- a/util-linux/rev.c
+++ b/util-linux/rev.c
@@ -39,6 +39,10 @@ static void strrev(CHAR_T *s, int len)
39 len--; 39 len--;
40 if (len != 0 && s[len] == '\n') 40 if (len != 0 && s[len] == '\n')
41 len--; 41 len--;
42#if ENABLE_PLATFORM_MINGW32
43 if (len != 0 && s[len] == '\r')
44 len--;
45#endif
42 } 46 }
43 47
44 for (i = 0; i < len; i++, len--) { 48 for (i = 0; i < len; i++, len--) {
diff --git a/win32/Kbuild b/win32/Kbuild
new file mode 100644
index 000000000..1bb79bfd3
--- /dev/null
+++ b/win32/Kbuild
@@ -0,0 +1,34 @@
1# Makefile for busybox
2#
3# Licensed under the GPL v2, see the file LICENSE in this tarball.
4
5lib-y:=
6
7lib-$(CONFIG_PLATFORM_MINGW32) += dirent.o
8lib-$(CONFIG_PLATFORM_MINGW32) += dirname.o
9lib-$(CONFIG_PLATFORM_MINGW32) += env.o
10lib-$(CONFIG_PLATFORM_MINGW32) += fnmatch.o
11lib-$(CONFIG_PLATFORM_MINGW32) += fsync.o
12lib-$(CONFIG_PLATFORM_MINGW32) += glob.o
13lib-$(CONFIG_PLATFORM_MINGW32) += inet_pton.o
14lib-$(CONFIG_PLATFORM_MINGW32) += ioctl.o
15lib-$(CONFIG_FEATURE_PRNG_ISAAC) += isaac.o
16lib-$(CONFIG_PLATFORM_MINGW32) += mingw.o
17lib-$(CONFIG_PLATFORM_MINGW32) += process.o
18lib-$(CONFIG_PLATFORM_MINGW32) += match_class.o
19lib-$(CONFIG_PLATFORM_MINGW32) += mntent.o
20lib-$(CONFIG_PLATFORM_MINGW32) += net.o
21lib-$(CONFIG_PLATFORM_MINGW32) += poll.o
22lib-$(CONFIG_PLATFORM_MINGW32) += popen.o
23lib-$(CONFIG_PLATFORM_MINGW32) += regex.o
24lib-$(CONFIG_PLATFORM_MINGW32) += select.o
25lib-$(CONFIG_FEATURE_PRNG_SHELL) += sh_random.o
26lib-$(CONFIG_PLATFORM_MINGW32) += statfs.o
27lib-$(CONFIG_PLATFORM_MINGW32) += strndup.o
28lib-$(CONFIG_PLATFORM_MINGW32) += strptime.o
29lib-$(CONFIG_PLATFORM_MINGW32) += strverscmp.o
30lib-$(CONFIG_PLATFORM_MINGW32) += system.o
31lib-$(CONFIG_PLATFORM_MINGW32) += termios.o
32lib-$(CONFIG_PLATFORM_MINGW32) += timegm.o
33lib-$(CONFIG_PLATFORM_MINGW32) += uname.o
34lib-$(CONFIG_PLATFORM_MINGW32) += winansi.o
diff --git a/win32/arpa/inet.h b/win32/arpa/inet.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/arpa/inet.h
diff --git a/win32/dirent.c b/win32/dirent.c
new file mode 100644
index 000000000..795fc779c
--- /dev/null
+++ b/win32/dirent.c
@@ -0,0 +1,106 @@
1#include "libbb.h"
2
3struct DIR {
4 struct dirent dd_dir;
5 HANDLE dd_handle; /* FindFirstFile handle */
6 int dd_stat; /* 0-based index */
7};
8
9static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
10{
11 /* copy file name from WIN32_FIND_DATA to dirent */
12 strcpy(ent->d_name, fdata->cFileName);
13
14 if ((fdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
15 (fdata->dwReserved0 == IO_REPARSE_TAG_SYMLINK ||
16 fdata->dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT ||
17 fdata->dwReserved0 == IO_REPARSE_TAG_APPEXECLINK))
18 ent->d_type = DT_LNK;
19 else if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
20 ent->d_type = DT_DIR;
21 else
22 ent->d_type = DT_REG;
23}
24
25DIR *opendir(const char *name)
26{
27 char pattern[MAX_PATH];
28 WIN32_FIND_DATAA fdata;
29 HANDLE h;
30 int len;
31 DIR *dir;
32
33 /* check that name is not NULL */
34 if (!name) {
35 errno = EINVAL;
36 return NULL;
37 }
38 /* check that the pattern won't be too long for FindFirstFileA */
39 len = strlen(name);
40 if (len + 2 >= MAX_PATH) {
41 errno = ENAMETOOLONG;
42 return NULL;
43 }
44 /* copy name to temp buffer */
45 strcpy(pattern, name);
46
47 /* append optional '/' and wildcard '*' */
48 if (len && !is_dir_sep(pattern[len - 1]))
49 pattern[len++] = '/';
50 pattern[len++] = '*';
51 pattern[len] = 0;
52
53 /* open find handle */
54 h = FindFirstFileA(pattern, &fdata);
55 if (h == INVALID_HANDLE_VALUE) {
56 DWORD err = GetLastError();
57 errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix();
58 return NULL;
59 }
60
61 /* initialize DIR structure and copy first dir entry */
62 dir = xmalloc(sizeof(DIR));
63 dir->dd_handle = h;
64 dir->dd_stat = 0;
65 finddata2dirent(&dir->dd_dir, &fdata);
66 return dir;
67}
68
69struct dirent *readdir(DIR *dir)
70{
71 if (!dir) {
72 errno = EBADF; /* No set_errno for mingw */
73 return NULL;
74 }
75
76 /* if first entry, dirent has already been set up by opendir */
77 if (dir->dd_stat) {
78 /* get next entry and convert from WIN32_FIND_DATA to dirent */
79 WIN32_FIND_DATAA fdata;
80 if (FindNextFileA(dir->dd_handle, &fdata)) {
81 finddata2dirent(&dir->dd_dir, &fdata);
82 } else {
83 DWORD lasterr = GetLastError();
84 /* POSIX says you shouldn't set errno when readdir can't
85 find any more files; so, if another error we leave it set. */
86 if (lasterr != ERROR_NO_MORE_FILES)
87 errno = err_win_to_posix();
88 return NULL;
89 }
90 }
91
92 ++dir->dd_stat;
93 return &dir->dd_dir;
94}
95
96int closedir(DIR *dir)
97{
98 if (!dir) {
99 errno = EBADF;
100 return -1;
101 }
102
103 FindClose(dir->dd_handle);
104 free(dir);
105 return 0;
106}
diff --git a/win32/dirent.h b/win32/dirent.h
new file mode 100644
index 000000000..4e7971ef6
--- /dev/null
+++ b/win32/dirent.h
@@ -0,0 +1,20 @@
1#ifndef DIRENT_H
2#define DIRENT_H
3
4typedef struct DIR DIR;
5
6#define DT_UNKNOWN 0
7#define DT_DIR 1
8#define DT_REG 2
9#define DT_LNK 3
10
11struct dirent {
12 unsigned char d_type;
13 char d_name[PATH_MAX]; // file name
14};
15
16DIR *opendir(const char *dirname);
17struct dirent *readdir(DIR *dir);
18int closedir(DIR *dir);
19
20#endif /* DIRENT_H */
diff --git a/win32/dirname.c b/win32/dirname.c
new file mode 100644
index 000000000..dd62b8b08
--- /dev/null
+++ b/win32/dirname.c
@@ -0,0 +1,287 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#ifndef WIN32_LEAN_AND_MEAN
7#define WIN32_LEAN_AND_MEAN
8#endif
9#include <stdlib.h>
10#include <libgen.h>
11#include <windows.h>
12
13#if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR > 11
14
15/* A 'directory separator' is a byte that equals 0x2F ('solidus' or more
16 * commonly 'forward slash') or 0x5C ('reverse solidus' or more commonly
17 * 'backward slash'). The byte 0x5C may look different from a backward slash
18 * in some locales; for example, it looks the same as a Yen sign in Japanese
19 * locales and a Won sign in Korean locales. Despite its appearance, it still
20 * functions as a directory separator.
21 *
22 * A 'path' comprises an optional DOS drive letter with a colon, and then an
23 * arbitrary number of possibily empty components, separated by non-empty
24 * sequences of directory separators (in other words, consecutive directory
25 * separators are treated as a single one). A path that comprises an empty
26 * component denotes the current working directory.
27 *
28 * An 'absolute path' comprises at least two components, the first of which
29 * is empty.
30 *
31 * A 'relative path' is a path that is not an absolute path. In other words,
32 * it either comprises an empty component, or begins with a non-empty
33 * component.
34 *
35 * POSIX doesn't have a concept about DOS drives. A path that does not have a
36 * drive letter starts from the same drive as the current working directory.
37 *
38 * For example:
39 * (Examples without drive letters match POSIX.)
40 *
41 * Argument dirname() returns basename() returns
42 * -------- ----------------- ------------------
43 * `` or NULL `.` `.`
44 * `usr` `.` `usr`
45 * `usr\` `.` `usr`
46 * `\` `\` `\`
47 * `\usr` `\` `usr`
48 * `\usr\lib` `\usr` `lib`
49 * `\home\\dwc\\test` `\home\\dwc` `test`
50 * `\\host\usr` `\\host\.` `usr`
51 * `\\host\usr\lib` `\\host\usr` `lib`
52 * `\\host\\usr` `\\host\\` `usr`
53 * `\\host\\usr\lib` `\\host\\usr` `lib`
54 * `C:` `C:.` `.`
55 * `C:usr` `C:.` `usr`
56 * `C:usr\` `C:.` `usr`
57 * `C:\` `C:\` `\`
58 * `C:\\` `C:\` `\`
59 * `C:\\\` `C:\` `\`
60 * `C:\usr` `C:\` `usr`
61 * `C:\usr\lib` `C:\usr` `lib`
62 * `C:\\usr\\lib\\` `C:\\usr` `lib`
63 * `C:\home\\dwc\\test` `C:\home\\dwc` `test`
64 */
65
66struct path_info
67 {
68 /* This points to end of the UNC prefix and drive letter, if any. */
69 char* prefix_end;
70
71 /* These point to the directory separator in front of the last non-empty
72 * component. */
73 char* base_sep_begin;
74 char* base_sep_end;
75
76 /* This points to the last directory separator sequence if no other
77 * non-separator characters follow it. */
78 char* term_sep_begin;
79
80 /* This points to the end of the string. */
81 char* path_end;
82 };
83
84#define IS_DIR_SEP(c) ((c) == '/' || (c) == '\\')
85
86static
87void
88do_get_path_info(struct path_info* info, char* path)
89 {
90 char* pos = path;
91 int unc_ncoms = 0;
92 DWORD cp;
93 int dbcs_tb, prev_dir_sep, dir_sep;
94
95 /* Get the code page for paths in the same way as `fopen()`. */
96 cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
97
98 /* Set the structure to 'no data'. */
99 info->prefix_end = NULL;
100 info->base_sep_begin = NULL;
101 info->base_sep_end = NULL;
102 info->term_sep_begin = NULL;
103
104 if(IS_DIR_SEP(pos[0]) && IS_DIR_SEP(pos[1])) {
105 /* The path is UNC. */
106 pos += 2;
107
108 /* Seek to the end of the share/device name. */
109 dbcs_tb = 0;
110 prev_dir_sep = 0;
111
112 while(*pos != 0) {
113 dir_sep = 0;
114
115 if(dbcs_tb)
116 dbcs_tb = 0;
117 else if(IsDBCSLeadByteEx(cp, *pos))
118 dbcs_tb = 1;
119 else
120 dir_sep = IS_DIR_SEP(*pos);
121
122 /* If a separator has been encountered and the previous character
123 * was not, mark this as the end of the current component. */
124 if(dir_sep && !prev_dir_sep) {
125 unc_ncoms ++;
126
127 /* The first component is the host name, and the second is the
128 * share name. So we stop at the end of the second component. */
129 if(unc_ncoms == 2)
130 break;
131 }
132
133 prev_dir_sep = dir_sep;
134 pos ++;
135 }
136
137 /* The UNC prefix terminates here. The terminating directory separator
138 * is not part of the prefix, and initiates a new absolute path. */
139 info->prefix_end = pos;
140 }
141 else if((pos[0] >= 'A' && pos[0] <= 'Z' && pos[1] == ':')
142 || (pos[0] >= 'a' && pos[0] <= 'z' && pos[1] == ':')) {
143 /* The path contains a DOS drive letter in the beginning. */
144 pos += 2;
145
146 /* The DOS drive prefix terminates here. Unlike UNC paths, the remaing
147 * part can be relative. For example, `C:foo` denotes `foo` in the
148 * working directory of drive `C:`. */
149 info->prefix_end = pos;
150 }
151
152 /* The remaining part of the path is almost the same as POSIX. */
153 dbcs_tb = 0;
154 prev_dir_sep = 0;
155
156 while(*pos != 0) {
157 dir_sep = 0;
158
159 if(dbcs_tb)
160 dbcs_tb = 0;
161 else if(IsDBCSLeadByteEx(cp, *pos))
162 dbcs_tb = 1;
163 else
164 dir_sep = IS_DIR_SEP(*pos);
165
166 /* If a separator has been encountered and the previous character
167 * was not, mark this as the beginning of the terminating separator
168 * sequence. */
169 if(dir_sep && !prev_dir_sep)
170 info->term_sep_begin = pos;
171
172 /* If a non-separator character has been encountered and a previous
173 * terminating separator sequence exists, start a new component. */
174 if(!dir_sep && prev_dir_sep) {
175 info->base_sep_begin = info->term_sep_begin;
176 info->base_sep_end = pos;
177 info->term_sep_begin = NULL;
178 }
179
180 prev_dir_sep = dir_sep;
181 pos ++;
182 }
183
184 /* Store the end of the path for convenience. */
185 info->path_end = pos;
186 }
187
188char*
189dirname(char* path)
190 {
191 struct path_info info;
192 char* upath;
193 const char* top;
194 static char* static_path_copy;
195
196 if(path == NULL || path[0] == 0)
197 return (char*) ".";
198
199 do_get_path_info(&info, path);
200 upath = info.prefix_end ? info.prefix_end : path;
201 /* Preserve type of top-level separator */
202 if (IS_DIR_SEP(path[0]))
203 top = path[0] == '/' ? "/" : "\\";
204 else if (IS_DIR_SEP(upath[0]))
205 top = upath[0] == '/' ? "/" : "\\";
206 else
207 top = ".";
208
209 /* If a non-terminating directory separator exists, it terminates the
210 * dirname. Truncate the path there. */
211 if(info.base_sep_begin) {
212 info.base_sep_begin[0] = 0;
213
214 /* If the unprefixed path has not been truncated to empty, it is now
215 * the dirname, so return it. */
216 if(upath[0])
217 return path;
218 }
219
220 /* The dirname is empty. In principle we return `<prefix>.` if the
221 * path is relative and `<prefix>\` if it is absolute. This can be
222 * optimized if there is no prefix. */
223 if(upath == path)
224 return (char*) top;
225
226 /* When there is a prefix, we must append a character to the prefix.
227 * If there is enough room in the original path, we just reuse its
228 * storage. */
229 if(upath != info.path_end) {
230 upath[0] = *top;
231 upath[1] = 0;
232 return path;
233 }
234
235 /* This is only the last resort. If there is no room, we have to copy
236 * the prefix elsewhere. */
237 upath = realloc(static_path_copy, info.prefix_end - path + 2);
238 if(!upath)
239 return (char*) top;
240
241 static_path_copy = upath;
242 memcpy(upath, path, info.prefix_end - path);
243 upath += info.prefix_end - path;
244 upath[0] = *top;
245 upath[1] = 0;
246 return static_path_copy;
247 }
248
249char*
250basename(char* path)
251 {
252 struct path_info info;
253 char* upath;
254
255 if(path == NULL || path[0] == 0)
256 return (char*) ".";
257
258 do_get_path_info(&info, path);
259 upath = info.prefix_end ? info.prefix_end : path;
260
261 /* If the path is non-UNC and empty, then it's relative. POSIX says '.'
262 * shall be returned. */
263 if(IS_DIR_SEP(path[0]) == 0 && upath[0] == 0)
264 return (char*) ".";
265
266 /* If a terminating separator sequence exists, it is not part of the
267 * name and shall be truncated. */
268 if(info.term_sep_begin)
269 info.term_sep_begin[0] = 0;
270
271 /* If some other separator sequence has been found, the basename
272 * immediately follows it. */
273 if(info.base_sep_end)
274 return info.base_sep_end;
275
276 /* If removal of the terminating separator sequence has caused the
277 * unprefixed path to become empty, it must have comprised only
278 * separators. POSIX says `/` shall be returned, but on Windows, we
279 * return `\` instead. */
280 if(upath[0] == 0)
281 return (char*) "\\";
282
283 /* Return the unprefixed path. */
284 return upath;
285 }
286
287#endif /* __MINGW64_VERSION_MAJOR */
diff --git a/win32/env.c b/win32/env.c
new file mode 100644
index 000000000..f30ee62f6
--- /dev/null
+++ b/win32/env.c
@@ -0,0 +1,117 @@
1#include "libbb.h"
2
3#undef getenv
4#undef putenv
5
6char *mingw_getenv(const char *name)
7{
8 char *result = getenv(name);
9 if (!result) {
10 if (!strcmp(name, "TMPDIR")) {
11 /* on Windows it is TMP and TEMP */
12 result = getenv("TMP");
13 if (!result)
14 result = getenv("TEMP");
15 } else if (!strcmp(name, "HOME")) {
16 struct passwd *p = getpwuid(getuid());
17 if (p)
18 result = p->pw_dir;
19 }
20 }
21 return result;
22}
23
24int setenv(const char *name, const char *value, int replace)
25{
26 int out;
27 char *envstr;
28
29 if (!name || !*name || strchr(name, '=') || !value) return -1;
30 if (!replace) {
31 if (getenv(name)) return 0;
32 }
33
34 envstr = xasprintf("%s=%s", name, value);
35 out = mingw_putenv(envstr);
36 free(envstr);
37
38 return out;
39}
40
41/*
42 * Removing an environment variable with WIN32 _putenv requires an argument
43 * like "NAME="; glibc omits the '='. The implementations of unsetenv and
44 * clearenv allow for this.
45 *
46 * It isn't possible to create an environment variable with an empty value
47 * using WIN32 _putenv.
48 */
49int unsetenv(const char *name)
50{
51 char *envstr;
52 int ret;
53
54 if (!name || !*name || strchr(name, '=') ) {
55 return -1;
56 }
57
58 envstr = xasprintf("%s=", name);
59 ret = _putenv(envstr);
60 free(envstr);
61
62 return ret;
63}
64
65int clearenv(void)
66{
67 char *envp, *name, *s;
68
69 while ( environ && (envp=*environ) ) {
70 if ( (s=strchr(envp, '=')) != NULL ) {
71 name = xstrndup(envp, s-envp+1);
72 if (_putenv(name) == -1) {
73 free(name);
74 return -1;
75 }
76 free(name);
77 }
78 else {
79 return -1;
80 }
81 }
82 return 0;
83}
84
85int mingw_putenv(const char *env)
86{
87 char *s, **envp;
88 int ret = 0;
89
90 if ( (s=strchr(env, '=')) == NULL ) {
91 return unsetenv(env);
92 }
93
94 if (s[1] != '\0') {
95 /* setting non-empty value is fine */
96 return _putenv(env);
97 }
98 else {
99 /* set empty value by setting a non-empty one then truncating */
100 char *envstr = xasprintf("%s0", env);
101 ret = _putenv(envstr);
102
103 for (envp = environ; *envp; ++envp) {
104 if (strcmp(*envp, envstr) == 0) {
105 (*envp)[s - env + 1] = '\0';
106 break;
107 }
108 }
109
110 /* tell the OS environment about the change */
111 envstr[s - env] = '\0';
112 SetEnvironmentVariable(envstr, "");
113 free(envstr);
114 }
115
116 return ret;
117}
diff --git a/win32/fnmatch.c b/win32/fnmatch.c
new file mode 100644
index 000000000..77b54c5f5
--- /dev/null
+++ b/win32/fnmatch.c
@@ -0,0 +1,525 @@
1/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with this library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
18
19#include <platform.h>
20#include "match_class.h"
21
22#if HAVE_CONFIG_H
23# include <config.h>
24#endif
25
26/* Enable GNU extensions in fnmatch.h. */
27#ifndef _GNU_SOURCE
28# define _GNU_SOURCE 1
29#endif
30
31#include <errno.h>
32#include <fnmatch.h>
33#include <ctype.h>
34
35#if HAVE_STRING_H || defined _LIBC
36# include <string.h>
37#else
38# include <strings.h>
39#endif
40
41#if defined STDC_HEADERS || defined _LIBC
42# include <stdlib.h>
43#endif
44
45/* For platform which support the ISO C amendement 1 functionality we
46 support user defined character classes. */
47#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
48/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
49# include <wchar.h>
50# include <wctype.h>
51#endif
52
53/* Comment out all this code if we are using the GNU C Library, and are not
54 actually compiling the library itself. This code is part of the GNU C
55 Library, but also included in many other GNU distributions. Compiling
56 and linking in this code is a waste when using the GNU C library
57 (especially if it is a shared library). Rather than having every GNU
58 program understand `configure --with-gnu-libc' and omit the object files,
59 it is simpler to just do this in the source for each such file. */
60
61#if defined _LIBC || !defined __GNU_LIBRARY__
62
63
64# if defined STDC_HEADERS || !defined isascii
65# define ISASCII(c) 1
66# else
67# define ISASCII(c) isascii(c)
68# endif
69
70# ifdef isblank
71# define ISBLANK(c) (ISASCII (c) && isblank (c))
72# else
73# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
74# endif
75# ifdef isgraph
76# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
77# else
78# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
79# endif
80
81# define ISPRINT(c) (ISASCII (c) && isprint (c))
82# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
83# define ISALNUM(c) (ISASCII (c) && isalnum (c))
84# define ISALPHA(c) (ISASCII (c) && isalpha (c))
85# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
86# define ISLOWER(c) (ISASCII (c) && islower (c))
87# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
88# define ISSPACE(c) (ISASCII (c) && isspace (c))
89# define ISUPPER(c) (ISASCII (c) && isupper (c))
90# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
91
92# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
93
94# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
95/* The GNU C library provides support for user-defined character classes
96 and the functions from ISO C amendement 1. */
97# ifdef CHARCLASS_NAME_MAX
98# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
99# else
100/* This shouldn't happen but some implementation might still have this
101 problem. Use a reasonable default value. */
102# define CHAR_CLASS_MAX_LENGTH 256
103# endif
104
105# ifdef _LIBC
106# define IS_CHAR_CLASS(string) __wctype (string)
107# else
108# define IS_CHAR_CLASS(string) wctype (string)
109# endif
110# else
111# define CHAR_CLASS_MAX_LENGTH 7 /* Namely, `xdigit'. */
112
113# define IS_CHAR_CLASS(string) \
114 (STREQ (string, "alpha") || STREQ (string, "upper") \
115 || STREQ (string, "lower") || STREQ (string, "digit") \
116 || STREQ (string, "alnum") || STREQ (string, "xdigit") \
117 || STREQ (string, "space") || STREQ (string, "print") \
118 || STREQ (string, "punct") || STREQ (string, "graph") \
119 || STREQ (string, "cntrl") || STREQ (string, "blank"))
120# endif
121
122/* Avoid depending on library functions or files
123 whose names are inconsistent. */
124
125# if !defined _LIBC && !defined getenv
126extern char *getenv (const char *);
127# endif
128
129# ifndef errno
130extern int errno;
131# endif
132
133/* This function doesn't exist on most systems. */
134
135# if !defined HAVE___STRCHRNUL && !defined _LIBC && 0
136static char *
137__strchrnul (const char *s, int c)
138{
139 char *result = strchr (s, c);
140 if (result == NULL)
141 result = strchr (s, '\0');
142 return result;
143}
144# else
145# define __strchrnul strchrnul
146# endif
147
148# ifndef internal_function
149/* Inside GNU libc we mark some function in a special way. In other
150 environments simply ignore the marking. */
151# define internal_function
152# endif
153
154/* Match STRING against the filename pattern PATTERN, returning zero if
155 it matches, nonzero if not. */
156static int internal_fnmatch __P ((const char *pattern, const char *string,
157 int no_leading_period, int flags))
158 internal_function;
159static int
160internal_function
161internal_fnmatch (const char *pattern, const char *string,
162 int no_leading_period, int flags)
163{
164 register const char *p = pattern, *n = string;
165 register unsigned char c;
166
167/* Note that this evaluates C many times. */
168# ifdef _LIBC
169# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
170# else
171# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
172# endif
173
174 while ((c = *p++) != '\0')
175 {
176 c = FOLD (c);
177
178 switch (c)
179 {
180 case '?':
181 if (*n == '\0')
182 return FNM_NOMATCH;
183 else if (*n == '/' && (flags & FNM_FILE_NAME))
184 return FNM_NOMATCH;
185 else if (*n == '.' && no_leading_period
186 && (n == string
187 || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
188 return FNM_NOMATCH;
189 break;
190
191 case '\\':
192 if (!(flags & FNM_NOESCAPE))
193 {
194 c = *p++;
195 if (c == '\0')
196 /* Trailing \ loses. */
197 return FNM_NOMATCH;
198 c = FOLD (c);
199 }
200 if (FOLD ((unsigned char) *n) != c)
201 return FNM_NOMATCH;
202 break;
203
204 case '*':
205 if (*n == '.' && no_leading_period
206 && (n == string
207 || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
208 return FNM_NOMATCH;
209
210 for (c = *p++; c == '?' || c == '*'; c = *p++)
211 {
212 if (*n == '/' && (flags & FNM_FILE_NAME))
213 /* A slash does not match a wildcard under FNM_FILE_NAME. */
214 return FNM_NOMATCH;
215 else if (c == '?')
216 {
217 /* A ? needs to match one character. */
218 if (*n == '\0')
219 /* There isn't another character; no match. */
220 return FNM_NOMATCH;
221 else
222 /* One character of the string is consumed in matching
223 this ? wildcard, so *??? won't match if there are
224 less than three characters. */
225 ++n;
226 }
227 }
228
229 if (c == '\0')
230 /* The wildcard(s) is/are the last element of the pattern.
231 If the name is a file name and contains another slash
232 this does mean it cannot match. */
233 return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL
234 ? FNM_NOMATCH : 0);
235 else
236 {
237 const char *endp;
238
239 endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0');
240
241 if (c == '[')
242 {
243 int flags2 = ((flags & FNM_FILE_NAME)
244 ? flags : (flags & ~FNM_PERIOD));
245
246 for (--p; n < endp; ++n)
247 if (internal_fnmatch (p, n,
248 (no_leading_period
249 && (n == string
250 || (n[-1] == '/'
251 && (flags
252 & FNM_FILE_NAME)))),
253 flags2)
254 == 0)
255 return 0;
256 }
257 else if (c == '/' && (flags & FNM_FILE_NAME))
258 {
259 while (*n != '\0' && *n != '/')
260 ++n;
261 if (*n == '/'
262 && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
263 flags) == 0))
264 return 0;
265 }
266 else
267 {
268 int flags2 = ((flags & FNM_FILE_NAME)
269 ? flags : (flags & ~FNM_PERIOD));
270
271 if (c == '\\' && !(flags & FNM_NOESCAPE))
272 c = *p;
273 c = FOLD (c);
274 for (--p; n < endp; ++n)
275 if (FOLD ((unsigned char) *n) == c
276 && (internal_fnmatch (p, n,
277 (no_leading_period
278 && (n == string
279 || (n[-1] == '/'
280 && (flags
281 & FNM_FILE_NAME)))),
282 flags2) == 0))
283 return 0;
284 }
285 }
286
287 /* If we come here no match is possible with the wildcard. */
288 return FNM_NOMATCH;
289
290 case '[':
291 {
292 /* Nonzero if the sense of the character class is inverted. */
293 static int posixly_correct;
294 register int not;
295 char cold;
296
297 if (posixly_correct == 0)
298 posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
299
300 if (*n == '\0')
301 return FNM_NOMATCH;
302
303 if (*n == '.' && no_leading_period && (n == string
304 || (n[-1] == '/'
305 && (flags
306 & FNM_FILE_NAME))))
307 return FNM_NOMATCH;
308
309 if (*n == '/' && (flags & FNM_FILE_NAME))
310 /* `/' cannot be matched. */
311 return FNM_NOMATCH;
312
313 not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
314 if (not)
315 ++p;
316
317 c = *p++;
318 for (;;)
319 {
320 unsigned char fn = FOLD ((unsigned char) *n);
321
322 if (!(flags & FNM_NOESCAPE) && c == '\\')
323 {
324 if (*p == '\0')
325 return FNM_NOMATCH;
326 c = FOLD ((unsigned char) *p);
327 ++p;
328
329 if (c == fn)
330 goto matched;
331 }
332 else if (c == '[' && *p == ':')
333 {
334 /* Leave room for the null. */
335 char str[CHAR_CLASS_MAX_LENGTH + 1];
336 size_t c1 = 0;
337# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
338 wctype_t wt;
339# endif
340 const char *startp = p;
341
342 for (;;)
343 {
344 if (c1 == CHAR_CLASS_MAX_LENGTH)
345 /* The name is too long and therefore the pattern
346 is ill-formed. */
347 return FNM_NOMATCH;
348
349 c = *++p;
350 if (c == ':' && p[1] == ']')
351 {
352 p += 2;
353 break;
354 }
355 if (c < 'a' || c >= 'z')
356 {
357 /* This cannot possibly be a character class name.
358 Match it as a normal range. */
359 p = startp;
360 c = '[';
361 goto normal_bracket;
362 }
363 str[c1++] = c;
364 }
365 str[c1] = '\0';
366
367# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
368 wt = IS_CHAR_CLASS (str);
369 if (wt == 0)
370 /* Invalid character class name. */
371 return FNM_NOMATCH;
372
373 if (__iswctype (__btowc ((unsigned char) *n), wt))
374 goto matched;
375# else
376 switch (match_class(str)) {
377 case CCLASS_ALNUM:
378 if (ISALNUM ((unsigned char) *n))
379 goto matched;
380 break;
381 case CCLASS_ALPHA:
382 if (ISALPHA ((unsigned char) *n))
383 goto matched;
384 break;
385 case CCLASS_BLANK:
386 if (ISBLANK ((unsigned char) *n))
387 goto matched;
388 break;
389 case CCLASS_CNTRL:
390 if (ISCNTRL ((unsigned char) *n))
391 goto matched;
392 break;
393 case CCLASS_DIGIT:
394 if (ISDIGIT ((unsigned char) *n))
395 goto matched;
396 break;
397 case CCLASS_GRAPH:
398 if (ISGRAPH ((unsigned char) *n))
399 goto matched;
400 break;
401 case CCLASS_LOWER:
402 if (ISLOWER ((unsigned char) *n))
403 goto matched;
404 break;
405 case CCLASS_PRINT:
406 if (ISPRINT ((unsigned char) *n))
407 goto matched;
408 break;
409 case CCLASS_PUNCT:
410 if (ISPUNCT ((unsigned char) *n))
411 goto matched;
412 break;
413 case CCLASS_SPACE:
414 if (ISSPACE ((unsigned char) *n))
415 goto matched;
416 break;
417 case CCLASS_UPPER:
418 if (ISUPPER ((unsigned char) *n))
419 goto matched;
420 break;
421 case CCLASS_XDIGIT:
422 if (ISXDIGIT ((unsigned char) *n))
423 goto matched;
424 break;
425 }
426 c = *p++;
427# endif
428 }
429 else if (c == '\0')
430 /* [ (unterminated) loses. */
431 return FNM_NOMATCH;
432 else
433 {
434 normal_bracket:
435 if (FOLD (c) == fn)
436 goto matched;
437
438 cold = c;
439 c = *p++;
440
441 if (c == '-' && *p != ']')
442 {
443 /* It is a range. */
444 unsigned char cend = *p++;
445 if (!(flags & FNM_NOESCAPE) && cend == '\\')
446 cend = *p++;
447 if (cend == '\0')
448 return FNM_NOMATCH;
449
450 if (cold <= fn && fn <= FOLD (cend))
451 goto matched;
452
453 c = *p++;
454 }
455 }
456
457 if (c == ']')
458 break;
459 }
460
461 if (!not)
462 return FNM_NOMATCH;
463 break;
464
465 matched:
466 /* Skip the rest of the [...] that already matched. */
467 do
468 {
469 c = *p++;
470
471 if (c == '\0')
472 /* [... (unterminated) loses. */
473 return FNM_NOMATCH;
474
475 if (!(flags & FNM_NOESCAPE) && c == '\\')
476 {
477 if (*p == '\0')
478 return FNM_NOMATCH;
479 /* XXX 1003.2d11 is unclear if this is right. */
480 ++p;
481 }
482 else if (c == '[' && *p == ':')
483 {
484 do
485 if (*++p == '\0')
486 return FNM_NOMATCH;
487 while (*p != ':' || p[1] == ']');
488 p += 2;
489 c = *p;
490 }
491 }
492 while (c != ']');
493 if (not)
494 return FNM_NOMATCH;
495 }
496 break;
497
498 default:
499 if (c != FOLD ((unsigned char) *n))
500 return FNM_NOMATCH;
501 }
502
503 ++n;
504 }
505
506 if (*n == '\0')
507 return 0;
508
509 if ((flags & FNM_LEADING_DIR) && *n == '/')
510 /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
511 return 0;
512
513 return FNM_NOMATCH;
514
515# undef FOLD
516}
517
518
519int
520fnmatch (const char *pattern, const char *string, int flags)
521{
522 return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
523}
524
525#endif /* _LIBC or not __GNU_LIBRARY__. */
diff --git a/win32/fnmatch.h b/win32/fnmatch.h
new file mode 100644
index 000000000..cc3ec3794
--- /dev/null
+++ b/win32/fnmatch.h
@@ -0,0 +1,84 @@
1/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
18
19#ifndef _FNMATCH_H
20#define _FNMATCH_H 1
21
22#ifdef __cplusplus
23extern "C" {
24#endif
25
26#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32
27# if !defined __GLIBC__ || !defined __P
28# undef __P
29# define __P(protos) protos
30# endif
31#else /* Not C++ or ANSI C. */
32# undef __P
33# define __P(protos) ()
34/* We can get away without defining `const' here only because in this file
35 it is used only inside the prototype for `fnmatch', which is elided in
36 non-ANSI C where `const' is problematical. */
37#endif /* C++ or ANSI C. */
38
39#ifndef const
40# if (defined __STDC__ && __STDC__) || defined __cplusplus
41# define __const const
42# else
43# define __const
44# endif
45#endif
46
47/* We #undef these before defining them because some losing systems
48 (HP-UX A.08.07 for example) define these in <unistd.h>. */
49#undef FNM_PATHNAME
50#undef FNM_NOESCAPE
51#undef FNM_PERIOD
52
53/* Bits set in the FLAGS argument to `fnmatch'. */
54#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
55#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
56#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
57
58#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE
59# define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
60# define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
61# define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
62#endif
63
64/* Value returned by `fnmatch' if STRING does not match PATTERN. */
65#define FNM_NOMATCH 1
66
67/* This value is returned if the implementation does not support
68 `fnmatch'. Since this is not the case here it will never be
69 returned but the conformance test suites still require the symbol
70 to be defined. */
71#ifdef _XOPEN_SOURCE
72# define FNM_NOSYS (-1)
73#endif
74
75/* Match NAME against the filename pattern PATTERN,
76 returning zero if it matches, FNM_NOMATCH if not. */
77extern int fnmatch __P ((__const char *__pattern, __const char *__name,
78 int __flags));
79
80#ifdef __cplusplus
81}
82#endif
83
84#endif /* fnmatch.h */
diff --git a/win32/fsync.c b/win32/fsync.c
new file mode 100644
index 000000000..6ab44d434
--- /dev/null
+++ b/win32/fsync.c
@@ -0,0 +1,75 @@
1/* Emulate fsync on platforms that lack it, primarily Windows and
2 cross-compilers like MinGW.
3
4 This is derived from sqlite3 sources.
5 https://www.sqlite.org/src/finfo?name=src/os_win.c
6 https://www.sqlite.org/copyright.html
7
8 Written by Richard W.M. Jones <rjones.at.redhat.com>
9
10 Copyright (C) 2008-2018 Free Software Foundation, Inc.
11
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 2.1 of the License, or (at your option) any later version.
16
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Lesser General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <https://www.gnu.org/licenses/>. */
24
25#include "libbb.h"
26#include <unistd.h>
27
28/* FlushFileBuffers */
29# define WIN32_LEAN_AND_MEAN
30# include <windows.h>
31
32# include <errno.h>
33
34/* Get _get_osfhandle. */
35# include <io.h>
36
37int
38fsync (int fd)
39{
40 HANDLE h = (HANDLE) _get_osfhandle (fd);
41 DWORD err;
42
43 if (h == INVALID_HANDLE_VALUE)
44 {
45 errno = EBADF;
46 return -1;
47 }
48
49 if (!FlushFileBuffers (h))
50 {
51 /* Translate some Windows errors into rough approximations of Unix
52 * errors. MSDN is useless as usual - in this case it doesn't
53 * document the full range of errors.
54 */
55 err = GetLastError ();
56 switch (err)
57 {
58 case ERROR_ACCESS_DENIED:
59 /* For a read-only handle, fsync should succeed, even though we have
60 no way to sync the access-time changes. */
61 return 0;
62
63 /* eg. Trying to fsync a tty. */
64 case ERROR_INVALID_HANDLE:
65 errno = EINVAL;
66 break;
67
68 default:
69 errno = EIO;
70 }
71 return -1;
72 }
73
74 return 0;
75}
diff --git a/win32/glob.c b/win32/glob.c
new file mode 100644
index 000000000..1cc6483e7
--- /dev/null
+++ b/win32/glob.c
@@ -0,0 +1,343 @@
1/*
2 glob from musl (https://www.musl-libc.org/).
3
4 MIT licensed:
5
6----------------------------------------------------------------------
7Copyright © 2005-2020 Rich Felker, et al.
8
9Permission is hereby granted, free of charge, to any person obtaining
10a copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice shall be
18included in all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27----------------------------------------------------------------------
28*/
29#include "libbb.h"
30#include <glob.h>
31#include <fnmatch.h>
32
33struct match
34{
35 struct match *next;
36 char name[];
37};
38
39static int append(struct match **tail, const char *name, size_t len, int mark)
40{
41 struct match *new = malloc(sizeof(struct match) + len + 2);
42 if (!new) return -1;
43 (*tail)->next = new;
44 new->next = NULL;
45 memcpy(new->name, name, len+1);
46 if (mark && len && name[len-1]!='/') {
47 new->name[len] = '/';
48 new->name[len+1] = 0;
49 }
50 *tail = new;
51 return 0;
52}
53
54static int do_glob(char *buf, size_t pos, int type, char *pat, int flags, int (*errfunc)(const char *path, int err), struct match **tail)
55{
56 ptrdiff_t i, j;
57 int in_bracket, overflow;
58 char *p2, saved_sep;
59 int readerr, old_errno;
60 DIR *dir;
61 struct dirent *de;
62
63 /* If GLOB_MARK is unused, we don't care about type. */
64 if (!type && !(flags & GLOB_MARK)) type = DT_REG;
65
66 /* Special-case the remaining pattern being all slashes, in
67 * which case we can use caller-passed type if it's a dir. */
68 if (*pat && type!=DT_DIR) type = 0;
69 while (pos+1 < PATH_MAX && *pat=='/') buf[pos++] = *pat++;
70
71 /* Consume maximal [escaped-]literal prefix of pattern, copying
72 * and un-escaping it to the running buffer as we go. */
73 i=0; j=0;
74 in_bracket = 0; overflow = 0;
75 for (; pat[i]!='*' && pat[i]!='?' && (!in_bracket || pat[i]!=']'); i++) {
76 if (!pat[i]) {
77 if (overflow) return 0;
78 pat += i;
79 pos += j;
80 i = j = 0;
81 break;
82 } else if (pat[i] == '[') {
83 in_bracket = 1;
84 } else if (pat[i] == '\\' && !(flags & GLOB_NOESCAPE)) {
85 /* Backslashes inside a bracket are (at least by
86 * our interpretation) non-special, so if next
87 * char is ']' we have a complete expression. */
88 if (in_bracket && pat[i+1]==']') break;
89 /* Unpaired final backslash never matches. */
90 if (!pat[i+1]) return 0;
91 i++;
92 }
93 if (pat[i] == '/') {
94 if (overflow) return 0;
95 in_bracket = 0;
96 pat += i+1;
97 i = -1;
98 pos += j+1;
99 j = -1;
100 }
101 /* Only store a character if it fits in the buffer, but if
102 * a potential bracket expression is open, the overflow
103 * must be remembered and handled later only if the bracket
104 * is unterminated (and thereby a literal), so as not to
105 * disallow long bracket expressions with short matches. */
106 if (pos+(j+1) < PATH_MAX) {
107 buf[pos+j++] = pat[i];
108 } else if (in_bracket) {
109 overflow = 1;
110 } else {
111 return 0;
112 }
113 /* If we consume any new components, the caller-passed type
114 * or dummy type from above is no longer valid. */
115 type = 0;
116 }
117 buf[pos] = 0;
118 if (!*pat) {
119 /* If we consumed any components above, or if GLOB_MARK is
120 * requested and we don't yet know if the match is a dir,
121 * we must confirm the file exists and/or determine its type.
122 *
123 * If marking dirs, symlink type is inconclusive; we need the
124 * type for the symlink target, and therefore must try stat
125 * first unless type is known not to be a symlink. Otherwise,
126 * or if that fails, use lstat for determining existence to
127 * avoid false negatives in the case of broken symlinks. */
128 struct stat st;
129 if ((flags & GLOB_MARK) && (!type||type==DT_LNK) && !stat(buf, &st)) {
130 if (S_ISDIR(st.st_mode)) type = DT_DIR;
131 else type = DT_REG;
132 }
133 if (!type && lstat(buf, &st)) {
134 if (errno!=ENOENT && (errfunc(buf, errno) || (flags & GLOB_ERR)))
135 return GLOB_ABORTED;
136 return 0;
137 }
138 if (append(tail, buf, pos, (flags & GLOB_MARK) && type==DT_DIR))
139 return GLOB_NOSPACE;
140 return 0;
141 }
142 p2 = strchr(pat, '/');
143 saved_sep = '/';
144 /* Check if the '/' was escaped and, if so, remove the escape char
145 * so that it will not be unpaired when passed to fnmatch. */
146 if (p2 && !(flags & GLOB_NOESCAPE)) {
147 char *p;
148 for (p=p2; p>pat && p[-1]=='\\'; p--);
149 if ((p2-p)%2) {
150 p2--;
151 saved_sep = '\\';
152 }
153 }
154 dir = opendir(pos ? buf : ".");
155 if (!dir) {
156 if (errfunc(buf, errno) || (flags & GLOB_ERR))
157 return GLOB_ABORTED;
158 return 0;
159 }
160 old_errno = errno;
161 while (errno=0, de=readdir(dir)) {
162 size_t l;
163 int fnm_flags, r;
164
165 /* Quickly skip non-directories when there's pattern left. */
166 if (p2 && de->d_type && de->d_type!=DT_DIR && de->d_type!=DT_LNK)
167 continue;
168
169 l = strlen(de->d_name);
170 if (l >= PATH_MAX-pos) continue;
171
172 if (p2) *p2 = 0;
173
174 fnm_flags= ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
175 | ((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0);
176
177 if (fnmatch(pat, de->d_name, fnm_flags))
178 continue;
179
180 /* With GLOB_PERIOD, don't allow matching . or .. unless
181 * fnmatch would match them with FNM_PERIOD rules in effect. */
182 if (p2 && (flags & GLOB_PERIOD) && de->d_name[0]=='.'
183 && (!de->d_name[1] || (de->d_name[1]=='.' && !de->d_name[2]))
184 && fnmatch(pat, de->d_name, fnm_flags | FNM_PERIOD))
185 continue;
186
187 memcpy(buf+pos, de->d_name, l+1);
188 if (p2) *p2 = saved_sep;
189 r = do_glob(buf, pos+l, de->d_type, p2 ? p2 : (char *)"", flags, errfunc, tail);
190 if (r) {
191 closedir(dir);
192 return r;
193 }
194 }
195 readerr = errno;
196 if (p2) *p2 = saved_sep;
197 closedir(dir);
198 if (readerr && (errfunc(buf, errno) || (flags & GLOB_ERR)))
199 return GLOB_ABORTED;
200 errno = old_errno;
201 return 0;
202}
203
204static int ignore_err(const char *path UNUSED_PARAM, int err UNUSED_PARAM)
205{
206 return 0;
207}
208
209static void freelist(struct match *head)
210{
211 struct match *match, *next;
212 for (match=head->next; match; match=next) {
213 next = match->next;
214 free(match);
215 }
216}
217
218#if !ENABLE_PLATFORM_MINGW32
219static int sort(const void *a, const void *b)
220{
221 return strcmp(*(const char **)a, *(const char **)b);
222}
223
224static int expand_tilde(char **pat, char *buf, size_t *pos)
225{
226 char *p = *pat + 1;
227 size_t i = 0;
228
229 char delim, *name_end = __strchrnul(p, '/');
230 if ((delim = *name_end)) *name_end++ = 0;
231 *pat = name_end;
232
233 char *home = *p ? NULL : getenv("HOME");
234 if (!home) {
235 struct passwd pw, *res;
236 switch (*p ? getpwnam_r(p, &pw, buf, PATH_MAX, &res)
237 : getpwuid_r(getuid(), &pw, buf, PATH_MAX, &res)) {
238 case ENOMEM:
239 return GLOB_NOSPACE;
240 case 0:
241 if (!res)
242 default:
243 return GLOB_NOMATCH;
244 }
245 home = pw.pw_dir;
246 }
247 while (i < PATH_MAX - 2 && *home)
248 buf[i++] = *home++;
249 if (*home)
250 return GLOB_NOMATCH;
251 if ((buf[i] = delim))
252 buf[++i] = 0;
253 *pos = i;
254 return 0;
255}
256#endif
257
258int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, int err), glob_t *restrict g)
259{
260 struct match head = { .next = NULL }, *tail = &head;
261 size_t cnt, i;
262 size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0;
263 int error = 0;
264 char buf[PATH_MAX];
265
266 if (!errfunc) errfunc = ignore_err;
267
268 if (!(flags & GLOB_APPEND)) {
269 g->gl_offs = offs;
270 g->gl_pathc = 0;
271 g->gl_pathv = NULL;
272 }
273
274 if (*pat) {
275 char *p = strdup(pat);
276 size_t pos = 0;
277 char *s = p;
278 if (!p) return GLOB_NOSPACE;
279 buf[0] = 0;
280#if !ENABLE_PLATFORM_MINGW32
281 if ((flags & (GLOB_TILDE | GLOB_TILDE_CHECK)) && *p == '~')
282 error = expand_tilde(&s, buf, &pos);
283 if (!error)
284#endif
285 error = do_glob(buf, pos, 0, s, flags, errfunc, &tail);
286 free(p);
287 }
288
289 if (error == GLOB_NOSPACE) {
290 freelist(&head);
291 return error;
292 }
293
294 for (cnt=0, tail=head.next; tail; tail=tail->next, cnt++);
295 if (!cnt) {
296 if (flags & GLOB_NOCHECK) {
297 tail = &head;
298 if (append(&tail, pat, strlen(pat), 0))
299 return GLOB_NOSPACE;
300 cnt++;
301 } else
302 return GLOB_NOMATCH;
303 }
304
305 if (flags & GLOB_APPEND) {
306 char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *));
307 if (!pathv) {
308 freelist(&head);
309 return GLOB_NOSPACE;
310 }
311 g->gl_pathv = pathv;
312 offs += g->gl_pathc;
313 } else {
314 g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *));
315 if (!g->gl_pathv) {
316 freelist(&head);
317 return GLOB_NOSPACE;
318 }
319 for (i=0; i<offs; i++)
320 g->gl_pathv[i] = NULL;
321 }
322 for (i=0, tail=head.next; i<cnt; tail=tail->next, i++)
323 g->gl_pathv[offs + i] = tail->name;
324 g->gl_pathv[offs + i] = NULL;
325 g->gl_pathc += cnt;
326
327#if !ENABLE_PLATFORM_MINGW32
328 if (!(flags & GLOB_NOSORT))
329 qsort(g->gl_pathv+offs, cnt, sizeof(char *), sort);
330#endif
331
332 return error;
333}
334
335void globfree(glob_t *g)
336{
337 size_t i;
338 for (i=0; i<g->gl_pathc; i++)
339 free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name));
340 free(g->gl_pathv);
341 g->gl_pathc = 0;
342 g->gl_pathv = NULL;
343}
diff --git a/win32/glob.h b/win32/glob.h
new file mode 100644
index 000000000..a8141b8bf
--- /dev/null
+++ b/win32/glob.h
@@ -0,0 +1,89 @@
1/*
2 glob from musl (https://www.musl-libc.org/).
3
4 MIT licensed:
5
6----------------------------------------------------------------------
7Copyright © 2005-2020 Rich Felker, et al.
8
9Permission is hereby granted, free of charge, to any person obtaining
10a copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice shall be
18included in all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27----------------------------------------------------------------------
28*/
29#ifndef _GLOB_H
30#define _GLOB_H
31
32#ifdef __cplusplus
33extern "C" {
34#endif
35
36typedef struct {
37 size_t gl_pathc;
38 char **gl_pathv;
39 size_t gl_offs;
40 int __dummy1;
41 void *__dummy2[5];
42} glob_t;
43
44int glob(const char *__restrict, int, int (*)(const char *, int), glob_t *__restrict);
45void globfree(glob_t *);
46
47#if ENABLE_PLATFORM_MINGW32
48// Set some flags to zero so the compiler can exclude unused code.
49#define GLOB_ERR 0
50#define GLOB_MARK 0
51#define GLOB_NOSORT 0x04
52#define GLOB_DOOFFS 0
53#define GLOB_NOCHECK 0x10
54#define GLOB_APPEND 0
55#define GLOB_NOESCAPE 0x40
56#define GLOB_PERIOD 0
57
58#define GLOB_TILDE 0
59#define GLOB_TILDE_CHECK 0
60#else
61#define GLOB_ERR 0x01
62#define GLOB_MARK 0x02
63#define GLOB_NOSORT 0x04
64#define GLOB_DOOFFS 0x08
65#define GLOB_NOCHECK 0x10
66#define GLOB_APPEND 0x20
67#define GLOB_NOESCAPE 0x40
68#define GLOB_PERIOD 0x80
69
70#define GLOB_TILDE 0x1000
71#define GLOB_TILDE_CHECK 0x4000
72#endif
73
74#define GLOB_NOSPACE 1
75#define GLOB_ABORTED 2
76#define GLOB_NOMATCH 3
77#define GLOB_NOSYS 4
78
79#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
80#define glob64 glob
81#define globfree64 globfree
82#define glob64_t glob_t
83#endif
84
85#ifdef __cplusplus
86}
87#endif
88
89#endif
diff --git a/win32/grp.h b/win32/grp.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/grp.h
diff --git a/win32/inet_pton.c b/win32/inet_pton.c
new file mode 100644
index 000000000..f229a9355
--- /dev/null
+++ b/win32/inet_pton.c
@@ -0,0 +1,95 @@
1/*
2 inet_pton from musl (https://www.musl-libc.org/).
3
4 MIT licensed:
5
6----------------------------------------------------------------------
7Copyright © 2005-2020 Rich Felker, et al.
8
9Permission is hereby granted, free of charge, to any person obtaining
10a copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice shall be
18included in all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27----------------------------------------------------------------------
28*/
29#include "libbb.h"
30
31static int hexval(unsigned c)
32{
33 if (c-'0'<10) return c-'0';
34 c |= 32;
35 if (c-'a'<6) return c-'a'+10;
36 return -1;
37}
38
39int inet_pton(int af, const char *restrict s, void *restrict a0)
40{
41 uint16_t ip[8];
42 unsigned char *a = a0;
43 int i, j, v, d, brk=-1, need_v4=0;
44
45 if (af==AF_INET) {
46 for (i=0; i<4; i++) {
47 for (v=j=0; j<3 && isdigit(s[j]); j++)
48 v = 10*v + s[j]-'0';
49 if (j==0 || (j>1 && s[0]=='0') || v>255) return 0;
50 a[i] = v;
51 if (s[j]==0 && i==3) return 1;
52 if (s[j]!='.') return 0;
53 s += j+1;
54 }
55 return 0;
56 } else if (af!=AF_INET6) {
57 errno = EAFNOSUPPORT;
58 return -1;
59 }
60
61 if (*s==':' && *++s!=':') return 0;
62
63 for (i=0; ; i++) {
64 if (s[0]==':' && brk<0) {
65 brk=i;
66 ip[i&7]=0;
67 if (!*++s) break;
68 if (i==7) return 0;
69 continue;
70 }
71 for (v=j=0; j<4 && (d=hexval(s[j]))>=0; j++)
72 v=16*v+d;
73 if (j==0) return 0;
74 ip[i&7] = v;
75 if (!s[j] && (brk>=0 || i==7)) break;
76 if (i==7) return 0;
77 if (s[j]!=':') {
78 if (s[j]!='.' || (i<6 && brk<0)) return 0;
79 need_v4=1;
80 i++;
81 break;
82 }
83 s += j+1;
84 }
85 if (brk>=0) {
86 memmove(ip+brk+7-i, ip+brk, 2*(i+1-brk));
87 for (j=0; j<7-i; j++) ip[brk+j] = 0;
88 }
89 for (j=0; j<8; j++) {
90 *a++ = ip[j]>>8;
91 *a++ = ip[j];
92 }
93 if (need_v4 && inet_pton(AF_INET, (void *)s, a-4) <= 0) return 0;
94 return 1;
95}
diff --git a/win32/ioctl.c b/win32/ioctl.c
new file mode 100644
index 000000000..93f9f504d
--- /dev/null
+++ b/win32/ioctl.c
@@ -0,0 +1,46 @@
1#include "libbb.h"
2
3static int mingw_get_terminal_width_height(struct winsize *win)
4{
5 int fd;
6 HANDLE handle;
7 CONSOLE_SCREEN_BUFFER_INFO sbi;
8
9 win->ws_row = 0;
10 win->ws_col = 0;
11
12 for (fd=STDOUT_FILENO; fd<=STDERR_FILENO; ++fd) {
13 handle = (HANDLE)_get_osfhandle(fd);
14 if (handle != INVALID_HANDLE_VALUE &&
15 GetConsoleScreenBufferInfo(handle, &sbi) != 0) {
16 win->ws_row = sbi.srWindow.Bottom - sbi.srWindow.Top + 1;
17 win->ws_col = sbi.srWindow.Right - sbi.srWindow.Left + 1;
18 return 0;
19 }
20 }
21
22 return -1;
23}
24
25int ioctl(int fd UNUSED_PARAM, int code, ...)
26{
27 va_list ap;
28 void *arg;
29 int ret = -1;
30
31 va_start(ap, code);
32
33 switch (code) {
34 case TIOCGWINSZ:
35 arg = va_arg(ap, void *);
36 ret = mingw_get_terminal_width_height((struct winsize *)arg);
37 break;
38 default:
39 ret = -1;
40 errno = EINVAL;
41 break;
42 }
43
44 va_end(ap);
45 return ret;
46}
diff --git a/win32/isaac.c b/win32/isaac.c
new file mode 100644
index 000000000..19b96de94
--- /dev/null
+++ b/win32/isaac.c
@@ -0,0 +1,192 @@
1/*
2------------------------------------------------------------------------------
3readable.c: My random number generator, ISAAC.
4(c) Bob Jenkins, March 1996, Public Domain
5You may use this code in any way you wish, and it is free. No warrantee.
6* May 2008 -- made it not depend on standard.h
7------------------------------------------------------------------------------
8
9 The original version of this file was downloaded from Bob Jenkins website:
10
11 http://burtleburtle.net/bob/rand/isaacafa.html
12
13 The isaac and randinit functions have been slightly modified to silence
14 warnings in modern compilers; the get_entropy and get_random_bytes have
15 been added.
16
17 These changes were made by R M Yorston and are also dedicated to the
18 public domain.
19*/
20#include "libbb.h"
21#include <ntsecapi.h>
22
23typedef struct {
24 /* external results */
25 uint32_t randrsl[256];
26
27 /* internal state */
28 uint32_t mm[256];
29 uint32_t aa, bb, cc;
30} isaac_t;
31
32
33static void isaac(isaac_t *t)
34{
35 register uint32_t i,x,y;
36
37 t->cc = t->cc + 1; /* cc just gets incremented once per 256 results */
38 t->bb = t->bb + t->cc; /* then combined with bb */
39
40 for (i=0; i<256; ++i)
41 {
42 x = t->mm[i];
43 switch (i%4)
44 {
45 case 0: t->aa = t->aa^(t->aa<<13); break;
46 case 1: t->aa = t->aa^(t->aa>>6); break;
47 case 2: t->aa = t->aa^(t->aa<<2); break;
48 case 3: t->aa = t->aa^(t->aa>>16); break;
49 }
50 t->aa = t->mm[(i+128)%256] + t->aa;
51 t->mm[i] = y = t->mm[(x>>2)%256] + t->aa + t->bb;
52 t->randrsl[i] = t->bb = t->mm[(y>>10)%256] + x;
53
54 /* Note that bits 2..9 are chosen from x but 10..17 are chosen
55 from y. The only important thing here is that 2..9 and 10..17
56 don't overlap. 2..9 and 10..17 were then chosen for speed in
57 the optimized version (rand.c) */
58 /* See http://burtleburtle.net/bob/rand/isaac.html
59 for further explanations and analysis. */
60 }
61}
62
63
64/* if (flag!=0), then use the contents of randrsl[] to initialize mm[]. */
65#define mix(a,b,c,d,e,f,g,h) \
66{ \
67 a^=b<<11; d+=a; b+=c; \
68 b^=c>>2; e+=b; c+=d; \
69 c^=d<<8; f+=c; d+=e; \
70 d^=e>>16; g+=d; e+=f; \
71 e^=f<<10; h+=e; f+=g; \
72 f^=g>>4; a+=f; g+=h; \
73 g^=h<<8; b+=g; h+=a; \
74 h^=a>>9; c+=h; a+=b; \
75}
76
77static void randinit(isaac_t *t, int flag)
78{
79 int i;
80 uint32_t a,b,c,d,e,f,g,h;
81 t->aa = t->bb = t->cc = 0;
82 a=b=c=d=e=f=g=h=0x9e3779b9; /* the golden ratio */
83
84 for (i=0; i<4; ++i) /* scramble it */
85 {
86 mix(a,b,c,d,e,f,g,h);
87 }
88
89 for (i=0; i<256; i+=8) /* fill in mm[] with messy stuff */
90 {
91 if (flag) /* use all the information in the seed */
92 {
93 a+=t->randrsl[i ]; b+=t->randrsl[i+1]; c+=t->randrsl[i+2];
94 d+=t->randrsl[i+3]; e+=t->randrsl[i+4]; f+=t->randrsl[i+5];
95 g+=t->randrsl[i+6]; h+=t->randrsl[i+7];
96 }
97 mix(a,b,c,d,e,f,g,h);
98 t->mm[i ]=a; t->mm[i+1]=b; t->mm[i+2]=c; t->mm[i+3]=d;
99 t->mm[i+4]=e; t->mm[i+5]=f; t->mm[i+6]=g; t->mm[i+7]=h;
100 }
101
102 if (flag)
103 { /* do a second pass to make all of the seed affect all of mm */
104 for (i=0; i<256; i+=8)
105 {
106 a+=t->mm[i ]; b+=t->mm[i+1]; c+=t->mm[i+2]; d+=t->mm[i+3];
107 e+=t->mm[i+4]; f+=t->mm[i+5]; g+=t->mm[i+6]; h+=t->mm[i+7];
108 mix(a,b,c,d,e,f,g,h);
109 t->mm[i ]=a; t->mm[i+1]=b; t->mm[i+2]=c; t->mm[i+3]=d;
110 t->mm[i+4]=e; t->mm[i+5]=f; t->mm[i+6]=g; t->mm[i+7]=h;
111 }
112 }
113
114 isaac(t); /* fill in the first set of results */
115}
116
117/*
118 * Stuff a few bytes of random-ish data into the generator state.
119 * This is unlikely to be very robust: don't rely on it for
120 * anything that needs to be secure.
121 */
122static void get_entropy(isaac_t *t)
123{
124 if (!RtlGenRandom(t->randrsl, sizeof(uint32_t)*256))
125 GetSystemTimeAsFileTime((FILETIME *)t->randrsl);
126
127#if 0
128 {
129 unsigned char *p = (unsigned char *)t->randrsl;
130 int j;
131
132 for (j=0; j<256; ++j) {
133 fprintf(stderr, "%02x", p[j]);
134 if ((j&31) == 31) {
135 fprintf(stderr, "\n");
136 }
137 else if ((j&3) == 3) {
138 fprintf(stderr, " ");
139 }
140 }
141 fprintf(stderr, "\n");
142 }
143#endif
144}
145
146#define RAND_BYTES sizeof(t->randrsl)
147#define RAND_WORDS (sizeof(t->randrsl)/sizeof(t->randrsl[0]))
148
149/*
150 * Place 'count' random bytes in the buffer 'buf'. You're responsible
151 * for ensuring the buffer is big enough.
152 */
153ssize_t get_random_bytes(void *buf, ssize_t count)
154{
155 static isaac_t *t = NULL;
156 static int rand_index = 0;
157 ssize_t save_count = count;
158 unsigned char *ptr;
159
160 if (buf == NULL || count < 0) {
161 errno = EINVAL;
162 return -1;
163 }
164
165 if (!t) {
166 t = xzalloc(sizeof(isaac_t));
167
168 get_entropy(t);
169 randinit(t, 1);
170 isaac(t);
171 rand_index = 0;
172 }
173
174 ptr = (unsigned char *)t->randrsl;
175 while (count > 0) {
176 int bytes_left = RAND_BYTES - rand_index;
177 ssize_t delta = MIN(bytes_left, count);
178
179 memcpy(buf, ptr+rand_index, delta);
180 buf += delta;
181 count -= delta;
182 rand_index += delta;
183
184 if (rand_index >= RAND_BYTES) {
185 /* generate more */
186 isaac(t);
187 rand_index = 0;
188 }
189 }
190
191 return save_count;
192}
diff --git a/win32/lazyload.h b/win32/lazyload.h
new file mode 100644
index 000000000..034bc7e45
--- /dev/null
+++ b/win32/lazyload.h
@@ -0,0 +1,27 @@
1#ifndef LAZYLOAD_H
2#define LAZYLOAD_H
3
4/* simplify loading of DLL functions */
5
6struct proc_addr {
7 FARPROC pfunction;
8 unsigned initialized;
9};
10
11/* Declares a function to be loaded dynamically from a DLL. */
12#define DECLARE_PROC_ADDR(rettype, function, ...) \
13 static struct proc_addr proc_addr_##function = { NULL, 0 }; \
14 rettype (WINAPI *function)(__VA_ARGS__)
15
16/*
17 * Loads a function from a DLL (once-only).
18 * Returns non-NULL function pointer on success.
19 * Returns NULL and sets errno == ENOSYS on failure.
20 */
21#define INIT_PROC_ADDR(dll, function) \
22 (function = get_proc_addr(#dll, #function, &proc_addr_##function))
23
24void *get_proc_addr(const char *dll, const char *function,
25 struct proc_addr *proc);
26
27#endif
diff --git a/win32/match_class.c b/win32/match_class.c
new file mode 100644
index 000000000..789e0df02
--- /dev/null
+++ b/win32/match_class.c
@@ -0,0 +1,7 @@
1#include "libbb.h"
2#include "match_class.h"
3
4int match_class(const char *name)
5{
6 return index_in_strings(CHAR_CLASSES, name);
7}
diff --git a/win32/match_class.h b/win32/match_class.h
new file mode 100644
index 000000000..92fd1323f
--- /dev/null
+++ b/win32/match_class.h
@@ -0,0 +1,11 @@
1#define CHAR_CLASSES \
2 "alnum\0alpha\0blank\0cntrl\0digit\0graph\0" \
3 "lower\0print\0punct\0space\0upper\0xdigit\0"
4
5enum {
6 CCLASS_ALNUM, CCLASS_ALPHA, CCLASS_BLANK, CCLASS_CNTRL,
7 CCLASS_DIGIT, CCLASS_GRAPH, CCLASS_LOWER, CCLASS_PRINT,
8 CCLASS_PUNCT, CCLASS_SPACE, CCLASS_UPPER, CCLASS_XDIGIT
9};
10
11extern int match_class(const char *name);
diff --git a/win32/mingw.c b/win32/mingw.c
new file mode 100644
index 000000000..7a5198ccf
--- /dev/null
+++ b/win32/mingw.c
@@ -0,0 +1,2540 @@
1#include "libbb.h"
2#include <userenv.h>
3#include "lazyload.h"
4#if ENABLE_FEATURE_EXTRA_FILE_DATA
5#include <aclapi.h>
6#endif
7#include <ntdef.h>
8#include <psapi.h>
9
10#if defined(__MINGW64_VERSION_MAJOR)
11#if ENABLE_GLOBBING
12extern int _setargv(void);
13int _setargv(void)
14{
15 extern int _dowildcard;
16 char *glob;
17
18 _dowildcard = -1;
19 glob = getenv("BB_GLOBBING");
20 if (glob) {
21 if (strcmp(glob, "0") == 0)
22 _dowildcard = 0;
23 }
24 else {
25 setenv("BB_GLOBBING", "0", TRUE);
26 }
27 return 0;
28}
29#else
30int _dowildcard = 0;
31#endif
32
33#undef _fmode
34int _fmode = _O_BINARY;
35#endif
36
37#if !defined(__MINGW64_VERSION_MAJOR)
38#if ENABLE_GLOBBING
39int _CRT_glob = 1;
40#else
41int _CRT_glob = 0;
42#endif
43
44unsigned int _CRT_fmode = _O_BINARY;
45#endif
46
47smallint bb_got_signal;
48static mode_t current_umask = DEFAULT_UMASK;
49
50#pragma GCC optimize ("no-if-conversion")
51int err_win_to_posix(void)
52{
53 int error = ENOSYS;
54 switch(GetLastError()) {
55 case ERROR_ACCESS_DENIED: error = EACCES; break;
56 case ERROR_ACCOUNT_DISABLED: error = EACCES; break;
57 case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break;
58 case ERROR_ALREADY_ASSIGNED: error = EBUSY; break;
59 case ERROR_ALREADY_EXISTS: error = EEXIST; break;
60 case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break;
61 case ERROR_BAD_COMMAND: error = EIO; break;
62 case ERROR_BAD_DEVICE: error = ENODEV; break;
63 case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break;
64 case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break;
65 case ERROR_BAD_FORMAT: error = ENOEXEC; break;
66 case ERROR_BAD_LENGTH: error = EINVAL; break;
67 case ERROR_BAD_PATHNAME: error = ENOENT; break;
68 case ERROR_BAD_NET_NAME: error = ENOENT; break;
69 case ERROR_BAD_NETPATH: error = ENOENT; break;
70 case ERROR_BAD_PIPE: error = EPIPE; break;
71 case ERROR_BAD_UNIT: error = ENODEV; break;
72 case ERROR_BAD_USERNAME: error = EINVAL; break;
73 case ERROR_BROKEN_PIPE: error = EPIPE; break;
74 case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break;
75 case ERROR_BUSY: error = EBUSY; break;
76 case ERROR_BUSY_DRIVE: error = EBUSY; break;
77 case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break;
78 case ERROR_CANNOT_MAKE: error = EACCES; break;
79 case ERROR_CANTOPEN: error = EIO; break;
80 case ERROR_CANTREAD: error = EIO; break;
81 case ERROR_CANTWRITE: error = EIO; break;
82 case ERROR_CRC: error = EIO; break;
83 case ERROR_CURRENT_DIRECTORY: error = EACCES; break;
84 case ERROR_DEVICE_IN_USE: error = EBUSY; break;
85 case ERROR_DEV_NOT_EXIST: error = ENODEV; break;
86 case ERROR_DIRECTORY: error = EINVAL; break;
87 case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break;
88 case ERROR_DISK_CHANGE: error = EIO; break;
89 case ERROR_DISK_FULL: error = ENOSPC; break;
90 case ERROR_DRIVE_LOCKED: error = EBUSY; break;
91 case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break;
92 case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break;
93 case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break;
94 case ERROR_FILE_EXISTS: error = EEXIST; break;
95 case ERROR_FILE_INVALID: error = ENODEV; break;
96 case ERROR_FILE_NOT_FOUND: error = ENOENT; break;
97 case ERROR_GEN_FAILURE: error = EIO; break;
98 case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break;
99 case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break;
100 case ERROR_INVALID_ACCESS: error = EACCES; break;
101 case ERROR_INVALID_ADDRESS: error = EFAULT; break;
102 case ERROR_INVALID_BLOCK: error = EFAULT; break;
103 case ERROR_INVALID_DATA: error = EINVAL; break;
104 case ERROR_INVALID_DRIVE: error = ENODEV; break;
105 case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break;
106 case ERROR_INVALID_FLAGS: error = EINVAL; break;
107 case ERROR_INVALID_FUNCTION: error = ENOSYS; break;
108 case ERROR_INVALID_HANDLE: error = EBADF; break;
109 case ERROR_INVALID_LOGON_HOURS: error = EACCES; break;
110 case ERROR_INVALID_NAME: error = EINVAL; break;
111 case ERROR_INVALID_OWNER: error = EINVAL; break;
112 case ERROR_INVALID_PARAMETER: error = EINVAL; break;
113 case ERROR_INVALID_PASSWORD: error = EPERM; break;
114 case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break;
115 case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break;
116 case ERROR_INVALID_TARGET_HANDLE: error = EIO; break;
117 case ERROR_INVALID_WORKSTATION: error = EACCES; break;
118 case ERROR_IO_DEVICE: error = EIO; break;
119 case ERROR_IO_INCOMPLETE: error = EINTR; break;
120 case ERROR_LOCKED: error = EBUSY; break;
121 case ERROR_LOCK_VIOLATION: error = EACCES; break;
122 case ERROR_LOGON_FAILURE: error = EACCES; break;
123 case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break;
124 case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break;
125 case ERROR_MORE_DATA: error = EPIPE; break;
126 case ERROR_NEGATIVE_SEEK: error = ESPIPE; break;
127 case ERROR_NOACCESS: error = EFAULT; break;
128 case ERROR_NONE_MAPPED: error = EINVAL; break;
129 case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break;
130 case ERROR_NOT_READY: error = EAGAIN; break;
131 case ERROR_NOT_SAME_DEVICE: error = EXDEV; break;
132 case ERROR_NO_DATA: error = EPIPE; break;
133 case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break;
134 case ERROR_NO_PROC_SLOTS: error = EAGAIN; break;
135 case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break;
136 case ERROR_OPEN_FAILED: error = EIO; break;
137 case ERROR_OPEN_FILES: error = EBUSY; break;
138 case ERROR_OPERATION_ABORTED: error = EINTR; break;
139 case ERROR_OUTOFMEMORY: error = ENOMEM; break;
140 case ERROR_PASSWORD_EXPIRED: error = EACCES; break;
141 case ERROR_PATH_BUSY: error = EBUSY; break;
142 case ERROR_PATH_NOT_FOUND: error = ENOENT; break;
143 case ERROR_PIPE_BUSY: error = EBUSY; break;
144 case ERROR_PIPE_CONNECTED: error = EPIPE; break;
145 case ERROR_PIPE_LISTENING: error = EPIPE; break;
146 case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break;
147 case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break;
148 case ERROR_READ_FAULT: error = EIO; break;
149 case ERROR_SEEK: error = EIO; break;
150 case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break;
151 case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
152 case ERROR_SHARING_VIOLATION: error = EACCES; break;
153 case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
154 case ERROR_SWAPERROR: error = ENOENT; break;
155 case ERROR_TOO_MANY_LINKS: error = EMLINK; break;
156 case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
157 case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
158 case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break;
159 case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break;
160 case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break;
161 case ERROR_WRITE_FAULT: error = EIO; break;
162 case ERROR_WRITE_PROTECT: error = EROFS; break;
163 case ERROR_CANT_RESOLVE_FILENAME: error = ELOOP; break;
164 }
165 return error;
166}
167#pragma GCC reset_options
168
169#undef strerror
170char *mingw_strerror(int errnum)
171{
172 if (errnum == ELOOP)
173 return (char *)"Too many levels of symbolic links";
174 return strerror(errnum);
175}
176
177char *strsignal(int sig)
178{
179 if (sig == SIGTERM)
180 return (char *)"Terminated";
181 else if (sig == SIGKILL)
182 return (char *)"Killed";
183 return (char *)get_signame(sig);
184}
185
186static int zero_fd = -1;
187static int rand_fd = -1;
188
189/*
190 * Determine if 'filename' corresponds to one of the supported
191 * device files. Constants for these are defined as an enum
192 * in mingw.h.
193 */
194int get_dev_type(const char *filename)
195{
196 if (filename && is_prefixed_with(filename, "/dev/"))
197 return index_in_strings("null\0zero\0urandom\0", filename+5);
198
199 return NOT_DEVICE;
200}
201
202void update_special_fd(int dev, int fd)
203{
204 if (dev == DEV_ZERO)
205 zero_fd = fd;
206 else if (dev == DEV_URANDOM)
207 rand_fd = fd;
208}
209
210#define PREFIX_LEN (sizeof(DEV_FD_PREFIX)-1)
211static int get_dev_fd(const char *filename)
212{
213 int fd;
214
215 if (filename && is_prefixed_with(filename, DEV_FD_PREFIX)) {
216 fd = bb_strtou(filename+PREFIX_LEN, NULL, 10);
217 if (errno == 0 && (HANDLE)_get_osfhandle(fd) != INVALID_HANDLE_VALUE)
218 return fd;
219 }
220 return -1;
221}
222
223static int mingw_is_directory(const char *path);
224#undef open
225int mingw_open (const char *filename, int oflags, ...)
226{
227 va_list args;
228 int pmode, mode = 0666;
229 int fd;
230 int special = (oflags & O_SPECIAL);
231 int dev = get_dev_type(filename);
232
233 /* /dev/null is always allowed, others only if O_SPECIAL is set */
234 if (dev == DEV_NULL || (special && dev != NOT_DEVICE)) {
235 filename = "nul";
236 oflags = O_RDWR;
237 }
238 else if ((fd=get_dev_fd(filename)) >= 0) {
239 return fd;
240 }
241
242 if ((oflags & O_CREAT)) {
243 va_start(args, oflags);
244 mode = va_arg(args, int);
245 va_end(args);
246 }
247
248 pmode = ((mode & S_IWUSR) ? _S_IWRITE : 0) |
249 ((mode & S_IRUSR) ? _S_IREAD : 0);
250
251 fd = open(filename, oflags&~O_SPECIAL, pmode);
252 if (fd >= 0) {
253 update_special_fd(dev, fd);
254 }
255 else if ((oflags & O_ACCMODE) != O_RDONLY && errno == EACCES) {
256 if (mingw_is_directory(filename))
257 errno = EISDIR;
258 }
259 return fd;
260}
261
262int mingw_xopen(const char *pathname, int flags)
263{
264 int ret;
265
266 /* allow use of special devices */
267 ret = mingw_open(pathname, flags|O_SPECIAL);
268 if (ret < 0) {
269 bb_perror_msg_and_die("can't open '%s'", pathname);
270 }
271 return ret;
272}
273
274ssize_t FAST_FUNC mingw_open_read_close(const char *fn, void *buf, size_t size)
275{
276 /* allow use of special devices */
277 int fd = mingw_open(fn, O_RDONLY|O_SPECIAL);
278 if (fd < 0)
279 return fd;
280 return read_close(fd, buf, size);
281}
282
283#undef fopen
284FILE *mingw_fopen (const char *filename, const char *otype)
285{
286 int fd;
287
288 if (get_dev_type(filename) == DEV_NULL)
289 filename = "nul";
290 else if ((fd=get_dev_fd(filename)) >= 0)
291 return fdopen(fd, otype);
292 return fopen(filename, otype);
293}
294
295#undef read
296ssize_t mingw_read(int fd, void *buf, size_t count)
297{
298 if (fd == zero_fd) {
299 memset(buf, 0, count);
300 return count;
301 }
302 else if (fd == rand_fd) {
303 return get_random_bytes(buf, count);
304 }
305 return read(fd, buf, count);
306}
307
308#undef close
309int mingw_close(int fd)
310{
311 if (fd == zero_fd) {
312 zero_fd = -1;
313 }
314 if (fd == rand_fd) {
315 rand_fd = -1;
316 }
317 return close(fd);
318}
319
320#undef dup2
321int mingw_dup2 (int fd, int fdto)
322{
323 int ret = dup2(fd, fdto);
324 return ret != -1 ? fdto : -1;
325}
326
327/*
328 * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
329 * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
330 */
331static inline long long filetime_to_hnsec(const FILETIME *ft)
332{
333 long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
334 /* Windows to Unix Epoch conversion */
335 return winTime - 116444736000000000LL;
336}
337
338static inline struct timespec filetime_to_timespec(const FILETIME *ft)
339{
340 struct timespec ts;
341 long long winTime = filetime_to_hnsec(ft);
342
343 ts.tv_sec = (time_t)(winTime / 10000000);
344 ts.tv_nsec = (long)(winTime % 10000000) * 100;
345
346 return ts;
347}
348
349static inline mode_t file_attr_to_st_mode(DWORD attr)
350{
351 mode_t fMode = S_IRUSR|S_IRGRP|S_IROTH;
352 if (attr & FILE_ATTRIBUTE_DIRECTORY)
353 fMode |= (S_IFDIR|S_IRWXU|S_IRWXG|S_IRWXO) & ~(current_umask & 0022);
354 else if (attr & FILE_ATTRIBUTE_DEVICE)
355 fMode |= S_IFCHR|S_IWUSR|S_IWGRP|S_IWOTH;
356 else
357 fMode |= S_IFREG;
358 if (!(attr & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_DEVICE)))
359 fMode |= (S_IWUSR|S_IWGRP|S_IWOTH) & ~(current_umask & 0022);
360 return fMode;
361}
362
363static int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata)
364{
365 char *want_dir;
366
367 if (get_dev_type(fname) == DEV_NULL || get_dev_fd(fname) >= 0) {
368 /* Fake attributes for special devices */
369 /* Though not /dev/zero or /dev/urandom */
370 FILETIME epoch = {0xd53e8000, 0x019db1de}; // Unix epoch as FILETIME
371 fdata->dwFileAttributes = FILE_ATTRIBUTE_DEVICE;
372 fdata->ftCreationTime = fdata->ftLastAccessTime =
373 fdata->ftLastWriteTime = epoch;
374 fdata->nFileSizeHigh = fdata->nFileSizeLow = 0;
375 return 0;
376 }
377
378 want_dir = last_char_is_dir_sep(fname);
379 if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata)) {
380 if (!(fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && want_dir)
381 return ENOTDIR;
382 fdata->dwFileAttributes &= ~FILE_ATTRIBUTE_DEVICE;
383 return 0;
384 }
385
386 if (GetLastError() == ERROR_SHARING_VIOLATION) {
387 HANDLE hnd;
388 WIN32_FIND_DATA fd;
389
390 if ((hnd=FindFirstFile(fname, &fd)) != INVALID_HANDLE_VALUE) {
391 fdata->dwFileAttributes =
392 fd.dwFileAttributes & ~FILE_ATTRIBUTE_DEVICE;
393 fdata->ftCreationTime = fd.ftCreationTime;
394 fdata->ftLastAccessTime = fd.ftLastAccessTime;
395 fdata->ftLastWriteTime = fd.ftLastWriteTime;
396 fdata->nFileSizeHigh = fd.nFileSizeHigh;
397 fdata->nFileSizeLow = fd.nFileSizeLow;
398 FindClose(hnd);
399 return 0;
400 }
401 }
402
403 switch (GetLastError()) {
404 case ERROR_ACCESS_DENIED:
405 case ERROR_SHARING_VIOLATION:
406 case ERROR_LOCK_VIOLATION:
407 case ERROR_SHARING_BUFFER_EXCEEDED:
408 return EACCES;
409 case ERROR_BUFFER_OVERFLOW:
410 return ENAMETOOLONG;
411 case ERROR_NOT_ENOUGH_MEMORY:
412 return ENOMEM;
413 case ERROR_INVALID_NAME:
414 if (want_dir)
415 return ENOTDIR;
416 default:
417 return ENOENT;
418 }
419}
420
421#undef umask
422mode_t mingw_umask(mode_t new_mode)
423{
424 mode_t tmp_mode;
425
426 tmp_mode = current_umask;
427 current_umask = new_mode & 0777;
428
429 umask((new_mode & S_IWUSR) ? _S_IWRITE : 0);
430
431 return tmp_mode;
432}
433
434/*
435 * Examine a file's contents to determine if it can be executed. This
436 * should be a last resort: in most cases it's much more efficient to
437 * check the file extension.
438 *
439 * We look for two types of file: shell scripts and binary executables.
440 */
441static int has_exec_format(const char *name)
442{
443 HANDLE fh;
444 int fd = -1;
445 ssize_t n;
446 int sig;
447 unsigned int offset;
448 unsigned char buf[1024];
449
450 /* special case: skip DLLs, there are thousands of them! */
451 if (is_suffixed_with_case(name, ".dll"))
452 return 0;
453
454 /* Open file and try to avoid updating access time */
455 fh = CreateFileA(name, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
456 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
457 if (fh != INVALID_HANDLE_VALUE) {
458 FILETIME last_access = { 0xffffffff, 0xffffffff };
459
460 SetFileTime(fh, NULL, &last_access, NULL);
461 fd = _open_osfhandle((intptr_t)fh, O_RDONLY);
462 }
463
464 if (fd < 0)
465 n = open_read_close(name, buf, sizeof(buf));
466 else
467 n = read_close(fd, buf, sizeof(buf));
468
469 if (n < 4) /* Need at least a few bytes and no error */
470 return 0;
471
472 /* shell script */
473 if (buf[0] == '#' && buf[1] == '!') {
474 return 1;
475 }
476
477 /*
478 * Poke about in file to see if it's a PE binary. I've just copied
479 * the magic from the file command.
480 */
481 if (buf[0] == 'M' && buf[1] == 'Z') {
482/* Convert four unsigned bytes to an unsigned int (little-endian) */
483#define LE4(b, o) (((unsigned)b[o+3] << 24) + (b[o+2] << 16) + \
484 (b[o+1] << 8) + b[o])
485
486 /* Actually Portable Executable */
487 /* See ape/ape.S at https://github.com/jart/cosmopolitan */
488 const unsigned char *qFpD = (unsigned char *)"qFpD";
489 if (n > 6 && LE4(buf, 2) == LE4(qFpD, 0))
490 return 1;
491
492 if (n > 0x3f) {
493 offset = (buf[0x19] << 8) + buf[0x18];
494 if (offset > 0x3f) {
495 offset = LE4(buf, 0x3c);
496 if (offset < sizeof(buf)-100) {
497 if (memcmp(buf+offset, "PE\0\0", 4) == 0) {
498 sig = (buf[offset+25] << 8) + buf[offset+24];
499 if (sig == 0x10b || sig == 0x20b) {
500 sig = (buf[offset+23] << 8) + buf[offset+22];
501 if ((sig & 0x2000) != 0) {
502 /* DLL */
503 return 0;
504 }
505 sig = buf[offset+92];
506 return (sig == 1 || sig == 2 || sig == 3
507 || sig == 7);
508 }
509 }
510 }
511 }
512 }
513 }
514
515 return 0;
516}
517
518#if ENABLE_FEATURE_EXTRA_FILE_DATA
519static uid_t file_owner(HANDLE fh, struct mingw_stat *buf)
520{
521 PSID pSidOwner;
522 PACL pDACL;
523 PSECURITY_DESCRIPTOR pSD;
524 static PTOKEN_USER user = NULL;
525 static HANDLE impersonate = INVALID_HANDLE_VALUE;
526 static int initialised = 0;
527 uid_t uid = 0;
528 DWORD *ptr;
529 unsigned char prefix[] = {
530 0x01, 0x05, 0x00, 0x00,
531 0x00, 0x00, 0x00, 0x05,
532 0x15, 0x00, 0x00, 0x00
533 };
534 unsigned char nullsid[] = {
535 0x01, 0x01, 0x00, 0x00,
536 0x00, 0x00, 0x00, 0x01,
537 0x00, 0x00, 0x00, 0x00
538 };
539
540 /* get SID of current user */
541 if (!initialised) {
542 HANDLE token;
543 DWORD ret = 0;
544
545 initialised = 1;
546 if (OpenProcessToken(GetCurrentProcess(),
547 TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE |
548 STANDARD_RIGHTS_READ, &token)) {
549 GetTokenInformation(token, TokenUser, NULL, 0, &ret);
550 if (ret <= 0 || (user=malloc(ret)) == NULL ||
551 !GetTokenInformation(token, TokenUser, user, ret, &ret)) {
552 free(user);
553 user = NULL;
554 }
555 DuplicateToken(token, SecurityImpersonation, &impersonate);
556 CloseHandle(token);
557 }
558 }
559
560 if (user == NULL)
561 return DEFAULT_UID;
562
563 /* get SID of file's owner */
564 if (GetSecurityInfo(fh, SE_FILE_OBJECT,
565 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
566 DACL_SECURITY_INFORMATION,
567 &pSidOwner, NULL, &pDACL, NULL, &pSD) != ERROR_SUCCESS)
568 return 0;
569
570 if (EqualSid(pSidOwner, user->User.Sid)) {
571 uid = DEFAULT_UID;
572 } else if (memcmp(pSidOwner, nullsid, sizeof(nullsid)) == 0) {
573 uid = DEFAULT_UID;
574 } else if (memcmp(pSidOwner, prefix, sizeof(prefix)) == 0) {
575 /* for local or domain users use the RID as uid */
576 ptr = (DWORD *)pSidOwner;
577 if (ptr[6] >= 500 && ptr[6] < DEFAULT_UID)
578 uid = (uid_t)ptr[6];
579 }
580
581 if (uid != DEFAULT_UID && impersonate != INVALID_HANDLE_VALUE &&
582 getuid() != 0) {
583 static GENERIC_MAPPING mapping = {
584 FILE_GENERIC_READ, FILE_GENERIC_WRITE,
585 FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS
586 };
587 PRIVILEGE_SET privileges;
588 DWORD grantedAccess;
589 DWORD privilegesLength = sizeof(privileges);
590 DWORD genericAccessRights = MAXIMUM_ALLOWED;
591 BOOL result;
592
593 if (AccessCheck(pSD, impersonate, genericAccessRights,
594 &mapping, &privileges, &privilegesLength,
595 &grantedAccess, &result)) {
596 if (result && (grantedAccess & 0x1200af) == 0x1200af) {
597 buf->st_mode |= (buf->st_mode & S_IRWXU) >> 6;
598 }
599 }
600 }
601 LocalFree(pSD);
602 return uid;
603}
604#endif
605
606static DWORD get_symlink_data(DWORD attr, const char *pathname,
607 WIN32_FIND_DATAA *fbuf)
608{
609 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
610 HANDLE handle = FindFirstFileA(pathname, fbuf);
611 if (handle != INVALID_HANDLE_VALUE) {
612 FindClose(handle);
613 if ((fbuf->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
614 switch (fbuf->dwReserved0) {
615 case IO_REPARSE_TAG_SYMLINK:
616 case IO_REPARSE_TAG_MOUNT_POINT:
617 case IO_REPARSE_TAG_APPEXECLINK:
618 return fbuf->dwReserved0;
619 }
620 }
621 }
622 }
623 return 0;
624}
625
626static DWORD is_symlink(const char *pathname)
627{
628 WIN32_FILE_ATTRIBUTE_DATA fdata;
629 WIN32_FIND_DATAA fbuf;
630
631 if (!get_file_attr(pathname, &fdata))
632 return get_symlink_data(fdata.dwFileAttributes, pathname, &fbuf);
633 return 0;
634}
635
636static int mingw_is_directory(const char *path)
637{
638 WIN32_FILE_ATTRIBUTE_DATA fdata;
639
640 return get_file_attr(path, &fdata) == 0 &&
641 (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
642}
643
644#if ENABLE_FEATURE_EXTRA_FILE_DATA
645/*
646 * By default we don't count subdirectories. Counting can be enabled
647 * in specific cases by calling 'count_subdirs(NULL)' before making
648 * any calls to stat(2) or lstat(2) that require accurate values of
649 * st_nlink for directories.
650 */
651int count_subdirs(const char *pathname)
652{
653 int count = 0;
654 DIR *dirp;
655 struct dirent *dp;
656 static int do_count = FALSE;
657
658 if (pathname == NULL) {
659 do_count = TRUE;
660 return 0;
661 }
662
663 if (do_count && (dirp = opendir(pathname))) {
664 while ((dp = readdir(dirp)) != NULL) {
665 if (dp->d_type == DT_DIR)
666 count++;
667 }
668 closedir(dirp);
669 } else {
670 count = 2;
671 }
672 return count;
673}
674#endif
675
676#ifndef FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS
677# define FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS 0x00400000
678#endif
679
680/* If follow is true then act like stat() and report on the link
681 * target. Otherwise report on the link itself.
682 */
683static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf)
684{
685 int err;
686 WIN32_FILE_ATTRIBUTE_DATA fdata;
687 WIN32_FIND_DATAA findbuf;
688 DWORD low, high;
689 off64_t size;
690 char *lname = NULL;
691
692 while (!(err=get_file_attr(file_name, &fdata))) {
693 buf->st_ino = 0;
694 buf->st_uid = DEFAULT_UID;
695 buf->st_gid = DEFAULT_GID;
696 buf->st_dev = buf->st_rdev = 0;
697 buf->st_attr = fdata.dwFileAttributes;
698 buf->st_tag = get_symlink_data(buf->st_attr, file_name, &findbuf);
699
700 if (buf->st_tag) {
701 char *content;
702
703 if (follow) {
704 /* The file size and times are wrong when Windows follows
705 * a symlink. Use the symlink target instead. */
706 file_name = lname = xmalloc_follow_symlinks(file_name);
707 if (!lname)
708 return -1;
709 continue;
710 }
711
712 /* Get the contents of a symlink, not its target. */
713 buf->st_mode = S_IFLNK|S_IRWXU|S_IRWXG|S_IRWXO;
714 content = xmalloc_readlink(file_name);
715 buf->st_size = content ? strlen(content) : 0;
716 free(content);
717 buf->st_atim = filetime_to_timespec(&(findbuf.ftLastAccessTime));
718 buf->st_mtim = filetime_to_timespec(&(findbuf.ftLastWriteTime));
719 buf->st_ctim = filetime_to_timespec(&(findbuf.ftCreationTime));
720 }
721 else {
722 /* The file is not a symlink. */
723 buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
724 if (S_ISREG(buf->st_mode) &&
725 (has_exe_suffix(file_name) ||
726 (!(buf->st_attr & FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS) &&
727 has_exec_format(file_name))))
728 buf->st_mode |= S_IXUSR|S_IXGRP|S_IXOTH;
729 buf->st_size = fdata.nFileSizeLow |
730 (((off64_t)fdata.nFileSizeHigh)<<32);
731 buf->st_atim = filetime_to_timespec(&(fdata.ftLastAccessTime));
732 buf->st_mtim = filetime_to_timespec(&(fdata.ftLastWriteTime));
733 buf->st_ctim = filetime_to_timespec(&(fdata.ftCreationTime));
734 }
735 buf->st_nlink = (buf->st_attr & FILE_ATTRIBUTE_DIRECTORY) ? 2 : 1;
736
737#if ENABLE_FEATURE_EXTRA_FILE_DATA
738 if (!(buf->st_attr &
739 (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS))) {
740 DWORD flags;
741 HANDLE fh;
742 BY_HANDLE_FILE_INFORMATION hdata;
743
744 flags = FILE_FLAG_BACKUP_SEMANTICS;
745 if (S_ISLNK(buf->st_mode))
746 flags |= FILE_FLAG_OPEN_REPARSE_POINT;
747 fh = CreateFile(file_name, READ_CONTROL, 0, NULL,
748 OPEN_EXISTING, flags, NULL);
749 if (fh != INVALID_HANDLE_VALUE) {
750 if (GetFileInformationByHandle(fh, &hdata)) {
751 buf->st_dev = hdata.dwVolumeSerialNumber;
752 buf->st_ino = hdata.nFileIndexLow |
753 (((ino_t)hdata.nFileIndexHigh)<<32);
754 buf->st_nlink = (buf->st_attr & FILE_ATTRIBUTE_DIRECTORY) ?
755 count_subdirs(file_name) :
756 hdata.nNumberOfLinks;
757 }
758 buf->st_uid = buf->st_gid = file_owner(fh, buf);
759 CloseHandle(fh);
760 } else {
761 buf->st_uid = buf->st_gid = 0;
762 buf->st_mode &= ~S_IRWXO;
763 }
764 }
765#endif
766
767 /* Get actual size of compressed/sparse files. Only regular
768 * files need to be considered. */
769 size = buf->st_size;
770 if (S_ISREG(buf->st_mode)) {
771 low = GetCompressedFileSize(file_name, &high);
772 if (low != INVALID_FILE_SIZE || GetLastError() == NO_ERROR) {
773 size = low | (((off64_t)high)<<32);
774 }
775 }
776
777 /*
778 * Assume a block is 4096 bytes and calculate number of 512 byte
779 * sectors.
780 */
781 buf->st_blksize = 4096;
782 buf->st_blocks = ((size+4095)>>12)<<3;
783 return 0;
784 }
785 free(lname);
786 errno = err;
787 return -1;
788}
789
790int mingw_lstat(const char *file_name, struct mingw_stat *buf)
791{
792 return do_lstat(0, file_name, buf);
793}
794
795int mingw_stat(const char *file_name, struct mingw_stat *buf)
796{
797 return do_lstat(1, file_name, buf);
798}
799
800#undef st_atime
801#undef st_mtime
802#undef st_ctime
803int mingw_fstat(int fd, struct mingw_stat *buf)
804{
805 HANDLE fh = (HANDLE)_get_osfhandle(fd);
806 BY_HANDLE_FILE_INFORMATION fdata;
807
808 if (fh == INVALID_HANDLE_VALUE)
809 goto fail;
810
811 /* direct non-file handles to MS's fstat() */
812 if (GetFileType(fh) != FILE_TYPE_DISK) {
813 struct _stati64 buf64;
814
815 if (_fstati64(fd, &buf64) != 0)
816 return -1;
817
818 buf->st_mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
819 & ~(current_umask & 0022);
820 buf->st_attr = FILE_ATTRIBUTE_NORMAL;
821 buf->st_size = buf64.st_size;
822 buf->st_atim.tv_sec = buf64.st_atime;
823 buf->st_atim.tv_nsec = 0;
824 buf->st_mtim.tv_sec = buf64.st_mtime;
825 buf->st_mtim.tv_nsec = 0;
826 buf->st_ctim.tv_sec = buf64.st_ctime;
827 buf->st_ctim.tv_nsec = 0;
828#if ENABLE_FEATURE_EXTRA_FILE_DATA
829 buf->st_dev = 0;
830 buf->st_ino = 0;
831 buf->st_nlink = 1;
832#endif
833 goto success;
834 }
835
836 if (GetFileInformationByHandle(fh, &fdata)) {
837 buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
838 buf->st_attr = fdata.dwFileAttributes;
839 buf->st_size = fdata.nFileSizeLow |
840 (((off64_t)fdata.nFileSizeHigh)<<32);
841 buf->st_atim = filetime_to_timespec(&(fdata.ftLastAccessTime));
842 buf->st_mtim = filetime_to_timespec(&(fdata.ftLastWriteTime));
843 buf->st_ctim = filetime_to_timespec(&(fdata.ftCreationTime));
844#if ENABLE_FEATURE_EXTRA_FILE_DATA
845 buf->st_dev = fdata.dwVolumeSerialNumber;
846 buf->st_ino = fdata.nFileIndexLow |
847 (((uint64_t)fdata.nFileIndexHigh)<<32);
848 buf->st_nlink = (buf->st_attr & FILE_ATTRIBUTE_DIRECTORY) ?
849 2 : fdata.nNumberOfLinks;
850#endif
851 success:
852#if !ENABLE_FEATURE_EXTRA_FILE_DATA
853 buf->st_dev = 0;
854 buf->st_ino = 0;
855 buf->st_nlink = (buf->st_attr & FILE_ATTRIBUTE_DIRECTORY) ? 2 : 1;
856#endif
857 buf->st_tag = 0;
858 buf->st_rdev = 0;
859 buf->st_uid = DEFAULT_UID;
860 buf->st_gid = DEFAULT_GID;
861 buf->st_blksize = 4096;
862 buf->st_blocks = ((buf->st_size+4095)>>12)<<3;
863 return 0;
864 }
865 fail:
866 errno = EBADF;
867 return -1;
868}
869
870static inline void timespec_to_filetime(const struct timespec tv, FILETIME *ft)
871{
872 long long winTime = tv.tv_sec * 10000000LL + tv.tv_nsec / 100LL +
873 116444736000000000LL;
874 ft->dwLowDateTime = winTime;
875 ft->dwHighDateTime = winTime >> 32;
876}
877
878static int hutimens(HANDLE fh, const struct timespec times[2])
879{
880 FILETIME now, aft, mft;
881 FILETIME *pft[2] = {&aft, &mft};
882 int i;
883
884 GetSystemTimeAsFileTime(&now);
885
886 if (times) {
887 for (i = 0; i < 2; ++i) {
888 if (times[i].tv_nsec == UTIME_NOW)
889 *pft[i] = now;
890 else if (times[i].tv_nsec == UTIME_OMIT)
891 pft[i] = NULL;
892 else if (times[i].tv_nsec >= 0 && times[i].tv_nsec < 1000000000L)
893 timespec_to_filetime(times[i], pft[i]);
894 else {
895 errno = EINVAL;
896 return -1;
897 }
898 }
899 } else {
900 aft = mft = now;
901 }
902
903 if (!SetFileTime(fh, NULL, pft[0], pft[1])) {
904 errno = err_win_to_posix();
905 return -1;
906 }
907 return 0;
908}
909
910int futimens(int fd, const struct timespec times[2])
911{
912 HANDLE fh;
913
914 fh = (HANDLE)_get_osfhandle(fd);
915 if (fh == INVALID_HANDLE_VALUE) {
916 errno = EBADF;
917 return -1;
918 }
919
920 return hutimens(fh, times);
921}
922
923int utimensat(int fd, const char *path, const struct timespec times[2],
924 int flags)
925{
926 int rc = -1;
927 HANDLE fh;
928 DWORD cflag = FILE_FLAG_BACKUP_SEMANTICS;
929
930 if (is_relative_path(path) && fd != AT_FDCWD) {
931 errno = ENOSYS; // partial implementation
932 return rc;
933 }
934
935 if (flags & AT_SYMLINK_NOFOLLOW)
936 cflag |= FILE_FLAG_OPEN_REPARSE_POINT;
937
938 fh = CreateFile(path, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
939 cflag, NULL);
940 if (fh == INVALID_HANDLE_VALUE) {
941 errno = err_win_to_posix();
942 return rc;
943 }
944
945 rc = hutimens(fh, times);
946 CloseHandle(fh);
947 return rc;
948}
949
950int utimes(const char *file_name, const struct timeval tv[2])
951{
952 struct timespec ts[2];
953
954 if (tv) {
955 if (tv[0].tv_usec < 0 || tv[0].tv_usec >= 1000000 ||
956 tv[1].tv_usec < 0 || tv[1].tv_usec >= 1000000) {
957 errno = EINVAL;
958 return -1;
959 }
960 ts[0].tv_sec = tv[0].tv_sec;
961 ts[0].tv_nsec = tv[0].tv_usec * 1000;
962 ts[1].tv_sec = tv[1].tv_sec;
963 ts[1].tv_nsec = tv[1].tv_usec * 1000;
964 }
965 return utimensat(AT_FDCWD, file_name, tv ? ts : NULL, 0);
966}
967
968unsigned int sleep (unsigned int seconds)
969{
970 Sleep(seconds*1000);
971 return 0;
972}
973
974int nanosleep(const struct timespec *req, struct timespec *rem)
975{
976 if (req->tv_nsec < 0 || 1000000000 <= req->tv_nsec) {
977 errno = EINVAL;
978 return -1;
979 }
980
981 Sleep(req->tv_sec*1000 + req->tv_nsec/1000000);
982
983 /* Sleep is not interruptible. So there is no remaining delay. */
984 if (rem != NULL) {
985 rem->tv_sec = 0;
986 rem->tv_nsec = 0;
987 }
988
989 return 0;
990}
991
992/*
993 * Windows' mktemp returns NULL on error whereas POSIX always returns the
994 * template and signals an error by making it an empty string.
995 */
996#undef mktemp
997char *mingw_mktemp(char *template)
998{
999 if ( mktemp(template) == NULL ) {
1000 template[0] = '\0';
1001 }
1002
1003 return template;
1004}
1005
1006int mkstemp(char *template)
1007{
1008 char *filename = mktemp(template);
1009 if (filename == NULL)
1010 return -1;
1011 return open(filename, O_RDWR | O_CREAT, 0600);
1012}
1013
1014int gettimeofday(struct timeval *tv, void *tz UNUSED_PARAM)
1015{
1016 FILETIME ft;
1017 long long hnsec;
1018
1019 GetSystemTimeAsFileTime(&ft);
1020 hnsec = filetime_to_hnsec(&ft);
1021 tv->tv_sec = hnsec / 10000000;
1022 tv->tv_usec = (hnsec % 10000000) / 10;
1023 return 0;
1024}
1025
1026int clock_gettime(clockid_t clockid, struct timespec *tp)
1027{
1028 FILETIME ft;
1029
1030 if (clockid != CLOCK_REALTIME) {
1031 errno = ENOSYS;
1032 return -1;
1033 }
1034 GetSystemTimeAsFileTime(&ft);
1035 *tp = filetime_to_timespec(&ft);
1036 return 0;
1037}
1038
1039int clock_settime(clockid_t clockid, const struct timespec *tp)
1040{
1041 SYSTEMTIME st;
1042 FILETIME ft;
1043
1044 if (clockid != CLOCK_REALTIME) {
1045 errno = ENOSYS;
1046 return -1;
1047 }
1048
1049 timespec_to_filetime(*tp, &ft);
1050 if (FileTimeToSystemTime(&ft, &st) == 0) {
1051 errno = EINVAL;
1052 return -1;
1053 }
1054
1055 if (SetSystemTime(&st) == 0) {
1056 errno = EPERM;
1057 return -1;
1058 }
1059 return 0;
1060}
1061
1062int pipe(int filedes[2])
1063{
1064 if (_pipe(filedes, PIPE_BUF, 0) < 0)
1065 return -1;
1066 return 0;
1067}
1068
1069struct tm *gmtime_r(const time_t *timep, struct tm *result)
1070{
1071 /* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */
1072 memcpy(result, gmtime(timep), sizeof(struct tm));
1073 return result;
1074}
1075
1076struct tm *localtime_r(const time_t *timep, struct tm *result)
1077{
1078 /* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */
1079 memcpy(result, localtime(timep), sizeof(struct tm));
1080 return result;
1081}
1082
1083#undef getcwd
1084char *mingw_getcwd(char *pointer, int len)
1085{
1086 char *ret = getcwd(pointer, len);
1087 if (!ret)
1088 return ret;
1089 return bs_to_slash(ret);
1090}
1091
1092#undef rename
1093int mingw_rename(const char *pold, const char *pnew)
1094{
1095 DWORD attrs;
1096
1097 /*
1098 * For non-symlinks, try native rename() first to get errno right.
1099 * It is based on MoveFile(), which cannot overwrite existing files.
1100 */
1101 if (!is_symlink(pold)) {
1102 if (!rename(pold, pnew))
1103 return 0;
1104 if (errno != EEXIST)
1105 return -1;
1106 }
1107 if (MoveFileEx(pold, pnew,
1108 MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
1109 return 0;
1110 /* TODO: translate more errors */
1111 if (GetLastError() == ERROR_ACCESS_DENIED &&
1112 (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
1113 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
1114 errno = EISDIR;
1115 return -1;
1116 }
1117 if ((attrs & FILE_ATTRIBUTE_READONLY) &&
1118 SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
1119 if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
1120 return 0;
1121 /* revert file attributes on failure */
1122 SetFileAttributes(pnew, attrs);
1123 }
1124 }
1125 errno = EACCES;
1126 return -1;
1127}
1128
1129static char *gethomedir(void)
1130{
1131 static char *buf = NULL;
1132 DECLARE_PROC_ADDR(BOOL, GetUserProfileDirectoryA, HANDLE, LPSTR, LPDWORD);
1133
1134 if (!buf) {
1135 DWORD len = PATH_MAX;
1136 HANDLE h;
1137
1138 buf = xzalloc(len);
1139 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &h)) {
1140 if (INIT_PROC_ADDR(userenv.dll, GetUserProfileDirectoryA)) {
1141 GetUserProfileDirectoryA(h, buf, &len);
1142 bs_to_slash(buf);
1143 }
1144 CloseHandle(h);
1145 }
1146 }
1147 return buf;
1148}
1149
1150#define NAME_LEN 100
1151char *get_user_name(void)
1152{
1153 static char *user_name = NULL;
1154 char *s;
1155 DWORD len = NAME_LEN;
1156
1157 if ( user_name == NULL ) {
1158 user_name = xzalloc(NAME_LEN);
1159 }
1160
1161 if ( user_name[0] != '\0' ) {
1162 return user_name;
1163 }
1164
1165 if ( !GetUserName(user_name, &len) ) {
1166 return NULL;
1167 }
1168
1169 for ( s=user_name; *s; ++s ) {
1170 if ( *s == ' ' ) {
1171 *s = '_';
1172 }
1173 }
1174
1175 return user_name;
1176}
1177
1178/*
1179 * When 'drop' drops privileges TokenIsElevated is still TRUE.
1180 * Find out if we're really privileged by checking if the group
1181 * BUILTIN\Administrators is enabled.
1182 */
1183int
1184elevation_state(void)
1185{
1186 int elevated = FALSE;
1187 int enabled = TRUE;
1188 HANDLE h;
1189#if ENABLE_DROP || ENABLE_CDROP || ENABLE_PDROP
1190 BOOL admin_enabled = TRUE;
1191 unsigned char admin[16] = {
1192 0x01, 0x02, 0x00, 0x00,
1193 0x00, 0x00, 0x00, 0x05,
1194 0x20, 0x00, 0x00, 0x00,
1195 0x20, 0x02, 0x00, 0x00
1196 };
1197#endif
1198
1199 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &h)) {
1200 TOKEN_ELEVATION elevation = { 0 };
1201 DWORD size;
1202
1203 if (GetTokenInformation(h, TokenElevation, &elevation,
1204 sizeof(elevation), &size))
1205 elevated = elevation.TokenIsElevated != 0;
1206 CloseHandle(h);
1207 }
1208
1209#if ENABLE_DROP || ENABLE_CDROP || ENABLE_PDROP
1210 if (CheckTokenMembership(NULL, (PSID)admin, &admin_enabled))
1211 enabled = admin_enabled != 0;
1212#endif
1213
1214 return elevated | (enabled << 1);
1215}
1216
1217int getuid(void)
1218{
1219 return elevation_state() == (ELEVATED_PRIVILEGE | ADMIN_ENABLED) ?
1220 0 : DEFAULT_UID;
1221}
1222
1223struct passwd *getpwnam(const char *name)
1224{
1225 const char *myname;
1226
1227 if ( (myname=get_user_name()) != NULL &&
1228 strcmp(myname, name) == 0 ) {
1229 return getpwuid(DEFAULT_UID);
1230 }
1231 else if (strcmp(name, "root") == 0) {
1232 return getpwuid(0);
1233 }
1234
1235 return NULL;
1236}
1237
1238struct passwd *getpwuid(uid_t uid)
1239{
1240 static struct passwd p;
1241
1242 if (uid == 0)
1243 p.pw_name = (char *)"root";
1244 else if (uid != DEFAULT_UID || (p.pw_name=get_user_name()) == NULL)
1245 return NULL;
1246
1247 p.pw_dir = gethomedir();
1248 p.pw_passwd = (char *)"";
1249 p.pw_gecos = p.pw_name;
1250 p.pw_shell = NULL;
1251 p.pw_uid = uid;
1252 p.pw_gid = uid;
1253
1254 return &p;
1255}
1256
1257struct group *getgrgid(gid_t gid)
1258{
1259 static char *members[2] = { NULL, NULL };
1260 static struct group g;
1261
1262 if (gid == 0) {
1263 g.gr_name = (char *)"root";
1264 }
1265 else if (gid != DEFAULT_GID || (g.gr_name=get_user_name()) == NULL) {
1266 return NULL;
1267 }
1268 g.gr_passwd = (char *)"";
1269 g.gr_gid = gid;
1270 members[0] = g.gr_name;
1271 g.gr_mem = members;
1272
1273 return &g;
1274}
1275
1276#if 0
1277int getgrouplist(const char *user UNUSED_PARAM, gid_t group,
1278 gid_t *groups, int *ngroups)
1279{
1280 if ( *ngroups == 0 ) {
1281 *ngroups = 1;
1282 return -1;
1283 }
1284
1285 *ngroups = 1;
1286 groups[0] = group;
1287 return 1;
1288}
1289
1290int getgroups(int n, gid_t *groups)
1291{
1292 if ( n == 0 ) {
1293 return 1;
1294 }
1295
1296 groups[0] = getgid();
1297 return 1;
1298}
1299#endif
1300
1301int getlogin_r(char *buf, size_t len)
1302{
1303 char *name;
1304
1305 if ( (name=get_user_name()) == NULL ) {
1306 return -1;
1307 }
1308
1309 if ( strlen(name) >= len ) {
1310 errno = ERANGE;
1311 return -1;
1312 }
1313
1314 strcpy(buf, name);
1315 return 0;
1316}
1317
1318long sysconf(int name)
1319{
1320 if ( name == _SC_CLK_TCK ) {
1321 return TICKS_PER_SECOND;
1322 }
1323 errno = EINVAL;
1324 return -1;
1325}
1326
1327clock_t times(struct tms *buf)
1328{
1329 memset(buf, 0, sizeof(*buf));
1330 return 0;
1331}
1332
1333int link(const char *oldpath, const char *newpath)
1334{
1335 DECLARE_PROC_ADDR(BOOL, CreateHardLinkA, LPCSTR, LPCSTR,
1336 LPSECURITY_ATTRIBUTES);
1337
1338 if (!INIT_PROC_ADDR(kernel32.dll, CreateHardLinkA)) {
1339 errno = ENOSYS;
1340 return -1;
1341 }
1342 if (!CreateHardLinkA(newpath, oldpath, NULL)) {
1343 errno = err_win_to_posix();
1344 return -1;
1345 }
1346 return 0;
1347}
1348
1349#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
1350# define SYMBOLIC_LINK_FLAG_DIRECTORY (0x1)
1351#endif
1352#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
1353# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2)
1354#endif
1355
1356int symlink(const char *target, const char *linkpath)
1357{
1358 DWORD flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
1359 DECLARE_PROC_ADDR(BOOLEAN, CreateSymbolicLinkA, LPCSTR, LPCSTR, DWORD);
1360 char *targ, *relative = NULL;
1361
1362 if (!INIT_PROC_ADDR(kernel32.dll, CreateSymbolicLinkA)) {
1363 errno = ENOSYS;
1364 return -1;
1365 }
1366
1367 if (is_relative_path(target) && has_path(linkpath)) {
1368 /* make target's path relative to current directory */
1369 const char *name = bb_get_last_path_component_nostrip(linkpath);
1370 relative = xasprintf("%.*s%s",
1371 (int)(name - linkpath), linkpath, target);
1372 }
1373
1374 if (mingw_is_directory(relative ?: target))
1375 flag |= SYMBOLIC_LINK_FLAG_DIRECTORY;
1376 free(relative);
1377
1378 targ = auto_string(strdup(target));
1379 slash_to_bs(targ);
1380
1381 retry:
1382 if (!CreateSymbolicLinkA(linkpath, targ, flag)) {
1383 /* Old Windows versions see 'UNPRIVILEGED_CREATE' as an invalid
1384 * parameter. Retry without it. */
1385 if ((flag & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) &&
1386 GetLastError() == ERROR_INVALID_PARAMETER) {
1387 flag &= ~SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
1388 goto retry;
1389 }
1390 errno = err_win_to_posix();
1391 return -1;
1392 }
1393 return 0;
1394}
1395
1396/* Create a directory junction */
1397#define MRPB rptr->MountPointReparseBuffer
1398#if 0
1399static void print_junction(REPARSE_DATA_BUFFER *rptr)
1400{
1401 int i;
1402#define MRPB_HEADER_SIZE \
1403 (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) - \
1404 FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer))
1405
1406 fprintf(stderr, "---\n");
1407 fprintf(stderr, "Tag: %lx\n", rptr->ReparseTag);
1408 fprintf(stderr, "ReparseDataLength: %d (%d + %d + %d + %d + %d = %d)\n",
1409 rptr->ReparseDataLength, MRPB_HEADER_SIZE,
1410 MRPB.SubstituteNameLength, sizeof(WCHAR),
1411 MRPB.PrintNameLength, sizeof(WCHAR),
1412 MRPB_HEADER_SIZE + MRPB.SubstituteNameLength + sizeof(WCHAR) +
1413 MRPB.PrintNameLength + sizeof(WCHAR));
1414 fprintf(stderr, "Reserved: %d\n", rptr->Reserved);
1415 fprintf(stderr, "---\n");
1416 fprintf(stderr, "SubstituteNameOffset: %d\n", MRPB.SubstituteNameOffset);
1417 fprintf(stderr, "SubstituteNameLength: %d\n", MRPB.SubstituteNameLength);
1418 fprintf(stderr, "PrintNameOffset: %d\n", MRPB.PrintNameOffset);
1419 fprintf(stderr, "PrintNameLength: %d\n", MRPB.PrintNameLength);
1420 fprintf(stderr, "SubstituteName: ");
1421 for (i = 0; i < MRPB.SubstituteNameLength/sizeof(WCHAR); i++)
1422 fprintf(stderr, "%c",
1423 MRPB.PathBuffer[MRPB.SubstituteNameOffset/sizeof(WCHAR) + i]);
1424 fprintf(stderr, " (%x)",
1425 MRPB.PathBuffer[MRPB.SubstituteNameOffset/sizeof(WCHAR) + i]);
1426 fprintf(stderr, "\n");
1427 fprintf(stderr, "PrintName: ");
1428 for (i = 0; i < MRPB.PrintNameLength/sizeof(WCHAR); i++)
1429 fprintf(stderr, "%c",
1430 MRPB.PathBuffer[MRPB.PrintNameOffset/sizeof(WCHAR) + i]);
1431 fprintf(stderr, " (%x)",
1432 MRPB.PathBuffer[MRPB.PrintNameOffset/sizeof(WCHAR) + i]);
1433 fprintf(stderr, "\n");
1434 fprintf(stderr, "---\n");
1435}
1436#endif
1437
1438static REPARSE_DATA_BUFFER *make_junction_data_buffer(char *rpath)
1439{
1440 WCHAR pbuf[PATH_MAX];
1441 int plen, slen, rbufsize;
1442 REPARSE_DATA_BUFFER *rptr;
1443
1444 /* We need two strings for the reparse data. The PrintName is the
1445 * target path in Win32 format, the SubstituteName is the same in
1446 * NT format.
1447 *
1448 * The return value from MultiByteToWideChar includes the trailing
1449 * L'\0' character.
1450 */
1451 slash_to_bs(rpath);
1452 plen = MultiByteToWideChar(CP_ACP, 0, rpath, -1, pbuf, PATH_MAX);
1453 if (plen == 0) {
1454 errno = err_win_to_posix();
1455 return NULL;
1456 }
1457 slen = plen + 4;
1458
1459 rbufsize = (slen + plen) * sizeof(WCHAR) +
1460 FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer);
1461 rptr = xzalloc(rbufsize);
1462
1463 rptr->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
1464 rptr->ReparseDataLength = rbufsize -
1465 FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer);
1466 /* rptr->Reserved = 0; */
1467 /* MRPB.SubstituteNameOffset = 0; */
1468 MRPB.SubstituteNameLength = (slen - 1) * sizeof(WCHAR);
1469 MRPB.PrintNameOffset = MRPB.SubstituteNameLength + sizeof(WCHAR);
1470 MRPB.PrintNameLength = (plen - 1) * sizeof(WCHAR);
1471
1472 wcscpy(MRPB.PathBuffer, L"\\??\\");
1473 wcscpy(MRPB.PathBuffer + 4, pbuf);
1474 wcscpy(MRPB.PathBuffer + slen, pbuf);
1475 return rptr;
1476}
1477
1478int create_junction(const char *oldpath, const char *newpath)
1479{
1480 char rpath[PATH_MAX];
1481 struct stat statbuf;
1482 REPARSE_DATA_BUFFER *rptr = NULL;
1483 HANDLE h;
1484 int error = 0;
1485 DWORD bytes;
1486
1487 if (realpath(oldpath, rpath) == NULL || stat(rpath, &statbuf) < 0)
1488 return -1;
1489
1490 if (!has_dos_drive_prefix(rpath)) {
1491 errno = EINVAL;
1492 return -1;
1493 }
1494
1495 if (!S_ISDIR(statbuf.st_mode)) {
1496 errno = ENOTDIR;
1497 return -1;
1498 }
1499
1500 if (!(rptr = make_junction_data_buffer(rpath))) {
1501 return -1;
1502 }
1503
1504 if (mkdir(newpath, 0777) < 0) {
1505 free(rptr);
1506 return -1;
1507 }
1508
1509 h = CreateFileA(newpath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
1510 OPEN_EXISTING,
1511 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
1512 if (h != INVALID_HANDLE_VALUE) {
1513 if (DeviceIoControl(h, FSCTL_SET_REPARSE_POINT, rptr,
1514 rptr->ReparseDataLength + REPARSE_DATA_BUFFER_HEADER_SIZE,
1515 NULL, 0, &bytes, NULL) != 0) {
1516 CloseHandle(h);
1517 free(rptr);
1518 return 0;
1519 }
1520 error = err_win_to_posix();
1521 CloseHandle(h);
1522 } else {
1523 error = err_win_to_posix();
1524 }
1525
1526 rmdir(newpath);
1527 free(rptr);
1528 errno = error;
1529 return -1;
1530}
1531
1532static char *normalize_ntpathA(char *buf)
1533{
1534 /* fix absolute path prefixes */
1535 if (buf[0] == '\\') {
1536 /* strip NT namespace prefixes */
1537 if (is_prefixed_with(buf, "\\??\\") ||
1538 is_prefixed_with(buf, "\\\\?\\"))
1539 buf += 4;
1540 else if (is_prefixed_with_case(buf, "\\DosDevices\\"))
1541 buf += 12;
1542 /* replace remaining '...UNC\' with '\\' */
1543 if (is_prefixed_with_case(buf, "UNC\\")) {
1544 buf += 2;
1545 *buf = '\\';
1546 }
1547 }
1548 return buf;
1549}
1550
1551static char *resolve_symlinks(char *path)
1552{
1553 HANDLE h;
1554 DWORD status;
1555 char *ptr = NULL;
1556 DECLARE_PROC_ADDR(DWORD, GetFinalPathNameByHandleA, HANDLE,
1557 LPSTR, DWORD, DWORD);
1558 char *resolve = NULL;
1559
1560 if (GetFileAttributesA(path) & FILE_ATTRIBUTE_REPARSE_POINT) {
1561 resolve = xmalloc_follow_symlinks(path);
1562 if (!resolve)
1563 return NULL;
1564 }
1565
1566 /* need a file handle to resolve symlinks */
1567 h = CreateFileA(resolve ?: path, 0, 0, NULL, OPEN_EXISTING,
1568 FILE_FLAG_BACKUP_SEMANTICS, NULL);
1569 if (h != INVALID_HANDLE_VALUE) {
1570 if (!INIT_PROC_ADDR(kernel32.dll, GetFinalPathNameByHandleA)) {
1571 if (resolve)
1572 strcpy(path, resolve);
1573 ptr = path;
1574 goto end;
1575 }
1576
1577 /* normalize the path and return it on success */
1578 status = GetFinalPathNameByHandleA(h, path, MAX_PATH,
1579 FILE_NAME_NORMALIZED|VOLUME_NAME_DOS);
1580 if (status != 0 && status < MAX_PATH) {
1581 ptr = normalize_ntpathA(path);
1582 goto end;
1583 } else if (err_win_to_posix() == ENOSYS) {
1584 if (resolve)
1585 strcpy(path, resolve);
1586 ptr = path;
1587 goto end;
1588 }
1589 }
1590
1591 errno = err_win_to_posix();
1592 end:
1593 CloseHandle(h);
1594 free(resolve);
1595 return ptr;
1596}
1597
1598/*
1599 * Emulate realpath in two stages:
1600 *
1601 * - _fullpath handles './', '../' and extra '/' characters. The
1602 * resulting path may not refer to an actual file.
1603 *
1604 * - resolve_symlinks checks that the file exists (by opening it) and
1605 * resolves symlinks by calling GetFinalPathNameByHandleA.
1606 */
1607char *realpath(const char *path, char *resolved_path)
1608{
1609 char buffer[MAX_PATH];
1610 char *real_path, *p;
1611
1612 /* enforce glibc pre-2.3 behaviour */
1613 if (path == NULL || resolved_path == NULL) {
1614 errno = EINVAL;
1615 return NULL;
1616 }
1617
1618 if (_fullpath(buffer, path, MAX_PATH) &&
1619 (real_path=resolve_symlinks(buffer))) {
1620 bs_to_slash(strcpy(resolved_path, real_path));
1621 p = last_char_is(resolved_path, '/');
1622 if (p && p > resolved_path && p[-1] != ':')
1623 *p = '\0';
1624 return resolved_path;
1625 }
1626 return NULL;
1627}
1628
1629static wchar_t *normalize_ntpath(wchar_t *wbuf)
1630{
1631 int i;
1632 /* fix absolute path prefixes */
1633 if (wbuf[0] == '\\') {
1634 /* strip NT namespace prefixes */
1635 if (!wcsncmp(wbuf, L"\\??\\", 4) ||
1636 !wcsncmp(wbuf, L"\\\\?\\", 4))
1637 wbuf += 4;
1638 else if (!wcsnicmp(wbuf, L"\\DosDevices\\", 12))
1639 wbuf += 12;
1640 /* replace remaining '...UNC\' with '\\' */
1641 if (!wcsnicmp(wbuf, L"UNC\\", 4)) {
1642 wbuf += 2;
1643 *wbuf = '\\';
1644 }
1645 }
1646 /* convert backslashes to slashes */
1647 for (i = 0; wbuf[i]; i++)
1648 if (wbuf[i] == '\\')
1649 wbuf[i] = '/';
1650 return wbuf;
1651}
1652
1653/*
1654 * This is the stucture required for reparse points with the tag
1655 * IO_REPARSE_TAG_APPEXECLINK. The Buffer member contains four
1656 * NUL-terminated, concatentated strings:
1657 *
1658 * package id, entry point, executable path and application type.
1659 *
1660 * https://www.tiraniddo.dev/2019/09/overview-of-windows-execution-aliases.html
1661 */
1662typedef struct {
1663 DWORD ReparseTag;
1664 USHORT ReparseDataLength;
1665 USHORT Reserved;
1666 ULONG Version;
1667 WCHAR Buffer[1];
1668} APPEXECLINK_BUFFER;
1669
1670#define SRPB rptr->SymbolicLinkReparseBuffer
1671char * FAST_FUNC xmalloc_readlink(const char *pathname)
1672{
1673 HANDLE h;
1674 char *buf;
1675 int bufsiz;
1676
1677 h = CreateFile(pathname, 0, 0, NULL, OPEN_EXISTING,
1678 FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
1679 if (h != INVALID_HANDLE_VALUE) {
1680 DWORD nbytes;
1681 BYTE rbuf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
1682 PREPARSE_DATA_BUFFER rptr = (PREPARSE_DATA_BUFFER)rbuf;
1683 APPEXECLINK_BUFFER *aptr = (APPEXECLINK_BUFFER *)rptr;
1684 BOOL status;
1685 size_t len;
1686 WCHAR *name = NULL, *str[4], *s;
1687 int i;
1688
1689 status = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0,
1690 rptr, sizeof(rbuf), &nbytes, NULL);
1691 CloseHandle(h);
1692
1693 if (status && rptr->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
1694 len = SRPB.SubstituteNameLength/sizeof(WCHAR);
1695 name = SRPB.PathBuffer + SRPB.SubstituteNameOffset/sizeof(WCHAR);
1696 } else if (status && rptr->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
1697 len = MRPB.SubstituteNameLength/sizeof(WCHAR);
1698 name = MRPB.PathBuffer + MRPB.SubstituteNameOffset/sizeof(WCHAR);
1699 } else if (status && rptr->ReparseTag == IO_REPARSE_TAG_APPEXECLINK) {
1700 // We only need the executable path but we determine all of
1701 // the strings as a sanity check.
1702 i = 0;
1703 s = aptr->Buffer;
1704 do {
1705 str[i] = s;
1706 while (*s++)
1707 ;
1708 } while (++i < 4);
1709
1710 if (s - aptr->Buffer < MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
1711 len = wcslen(str[2]);
1712 name = str[2];
1713 }
1714 }
1715
1716 if (name) {
1717 name[len] = 0;
1718 name = normalize_ntpath(name);
1719 bufsiz = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, 0, 0);
1720 if (bufsiz) {
1721 buf = xmalloc(bufsiz);
1722 if (WideCharToMultiByte(CP_ACP, 0, name, -1, buf, bufsiz, 0, 0))
1723 return buf;
1724 free(buf);
1725 }
1726 }
1727 }
1728 errno = err_win_to_posix();
1729 return NULL;
1730}
1731
1732const char *get_busybox_exec_path(void)
1733{
1734 static char *path = NULL;
1735
1736 if (!path) {
1737 path = xzalloc(PATH_MAX);
1738 }
1739
1740 if (!*path) {
1741 GetModuleFileName(NULL, path, PATH_MAX);
1742 bs_to_slash(path);
1743 }
1744 return path;
1745}
1746
1747#undef mkdir
1748int mingw_mkdir(const char *path, int mode UNUSED_PARAM)
1749{
1750 int ret;
1751 struct stat st;
1752 int lerrno = 0;
1753
1754 if ( (ret=mkdir(path)) < 0 ) {
1755 lerrno = errno;
1756 if ( lerrno == EACCES && stat(path, &st) == 0 ) {
1757 ret = 0;
1758 lerrno = 0;
1759 }
1760 }
1761
1762 errno = lerrno;
1763 return ret;
1764}
1765
1766#undef chdir
1767int mingw_chdir(const char *dirname)
1768{
1769 int ret = -1;
1770 char *realdir;
1771
1772 if (is_symlink(dirname))
1773 realdir = xmalloc_realpath(dirname);
1774 else
1775 realdir = xstrdup(dirname);
1776
1777 if (realdir) {
1778 fix_path_case(realdir);
1779 ret = chdir(realdir);
1780 }
1781 free(realdir);
1782
1783 return ret;
1784}
1785
1786#undef chmod
1787int mingw_chmod(const char *path, int mode)
1788{
1789 if (mingw_is_directory(path))
1790 mode |= 0222;
1791
1792 return chmod(path, mode);
1793}
1794
1795int fcntl(int fd, int cmd, ...)
1796{
1797 va_list arg;
1798 int result = -1;
1799 char *fds;
1800 int target, i, newfd;
1801
1802 va_start(arg, cmd);
1803
1804 switch (cmd) {
1805 case F_GETFD:
1806 case F_SETFD:
1807 case F_GETFL:
1808 /*
1809 * Our fake F_GETFL won't matter if the return value is used as
1810 * fcntl(fd, F_SETFL, ret|something);
1811 * because F_SETFL isn't supported either.
1812 */
1813 result = 0;
1814 break;
1815 case F_DUPFD:
1816 target = va_arg(arg, int);
1817 fds = xzalloc(target);
1818 while ((newfd = dup(fd)) < target && newfd >= 0) {
1819 fds[newfd] = 1;
1820 }
1821 for (i = 0; i < target; ++i) {
1822 if (fds[i]) {
1823 close(i);
1824 }
1825 }
1826 free(fds);
1827 result = newfd;
1828 break;
1829 default:
1830 errno = ENOSYS;
1831 break;
1832 }
1833
1834 va_end(arg);
1835 return result;
1836}
1837
1838#undef unlink
1839#undef rmdir
1840int mingw_unlink(const char *pathname)
1841{
1842 int ret;
1843
1844 /* read-only files cannot be removed */
1845 chmod(pathname, 0666);
1846
1847 ret = unlink(pathname);
1848 if (ret == -1 && errno == EACCES) {
1849 /* a symlink to a directory needs to be removed by calling rmdir */
1850 /* (the *real* Windows rmdir, not mingw_rmdir) */
1851 if (is_symlink(pathname)) {
1852 return rmdir(pathname);
1853 }
1854 }
1855 return ret;
1856}
1857
1858struct pagefile_info {
1859 SIZE_T total;
1860 SIZE_T in_use;
1861};
1862
1863static BOOL CALLBACK
1864pagefile_cb(LPVOID context, PENUM_PAGE_FILE_INFORMATION info,
1865 LPCSTR name UNUSED_PARAM)
1866{
1867 struct pagefile_info *pfinfo = (struct pagefile_info *)context;
1868
1869 pfinfo->total += info->TotalSize;
1870 pfinfo->in_use += info->TotalInUse;
1871 return TRUE;
1872}
1873
1874int sysinfo(struct sysinfo *info)
1875{
1876 PERFORMANCE_INFORMATION perf;
1877 struct pagefile_info pfinfo;
1878 DECLARE_PROC_ADDR(BOOL, GetPerformanceInfo, PPERFORMANCE_INFORMATION,
1879 DWORD);
1880 DECLARE_PROC_ADDR(BOOL, EnumPageFilesA, PENUM_PAGE_FILE_CALLBACKA, LPVOID);
1881
1882 memset((void *)info, 0, sizeof(struct sysinfo));
1883 memset((void *)&perf, 0, sizeof(PERFORMANCE_INFORMATION));
1884 memset((void *)&pfinfo, 0, sizeof(struct pagefile_info));
1885 info->mem_unit = 4096;
1886
1887 if (INIT_PROC_ADDR(psapi.dll, GetPerformanceInfo)) {
1888 perf.cb = sizeof(PERFORMANCE_INFORMATION);
1889 GetPerformanceInfo(&perf, perf.cb);
1890 }
1891
1892 if (INIT_PROC_ADDR(psapi.dll, EnumPageFilesA)) {
1893 EnumPageFilesA((PENUM_PAGE_FILE_CALLBACK)pagefile_cb, (LPVOID)&pfinfo);
1894 }
1895
1896 info->totalram = perf.PhysicalTotal * perf.PageSize / 4096;
1897 info->bufferram = perf.SystemCache * perf.PageSize / 4096;
1898 if (perf.PhysicalAvailable > perf.SystemCache)
1899 info->freeram = perf.PhysicalAvailable * perf.PageSize / 4096 -
1900 info->bufferram;
1901 info->totalswap = pfinfo.total * perf.PageSize / 4096;
1902 info->freeswap = (pfinfo.total - pfinfo.in_use) * perf.PageSize / 4096;
1903
1904 info->uptime = GetTickCount64() / 1000;
1905 info->procs = perf.ProcessCount;
1906
1907 return 0;
1908}
1909
1910#undef strftime
1911size_t mingw_strftime(char *buf, size_t max, const char *format, const struct tm *tm)
1912{
1913 size_t ret;
1914 char buffer[64];
1915 const char *replace;
1916 char *t;
1917 char *fmt;
1918 struct tm tm2;
1919
1920 /*
1921 * Emulate some formats that Windows' strftime lacks.
1922 * - '%e' day of the month with space padding
1923 * - '%s' number of seconds since the Unix epoch
1924 * - '%T' same as %H:%M:%S
1925 * - '%z' timezone offset
1926 * Also, permit the '-' modifier to omit padding. Windows uses '#'.
1927 */
1928 fmt = xstrdup(format);
1929 for ( t=fmt; *t; ++t ) {
1930 if ( *t == '%' ) {
1931 replace = NULL;
1932 if ( t[1] == 'e' ) {
1933 if ( tm->tm_mday >= 0 && tm->tm_mday <= 99 ) {
1934 sprintf(buffer, "%2d", tm->tm_mday);
1935 }
1936 else {
1937 strcpy(buffer, " ");
1938 }
1939 replace = buffer;
1940 }
1941 else if ( t[1] == 's' ) {
1942 tm2 = *tm;
1943 sprintf(buffer, "%"LL_FMT"d", (long long)mktime(&tm2));
1944 replace = buffer;
1945 }
1946 else if ( t[1] == 'T' ) {
1947 replace = "%H:%M:%S";
1948 }
1949 else if ( t[1] == 'z' ) {
1950 _tzset();
1951 if ( tm->tm_isdst >= 0 ) {
1952 int offset = (int)_timezone - (tm->tm_isdst > 0 ? 3600 : 0);
1953 int hr, min;
1954
1955 if ( offset > 0 ) {
1956 buffer[0] = '-';
1957 }
1958 else {
1959 buffer[0] = '+';
1960 offset = -offset;
1961 }
1962
1963 hr = offset / 3600;
1964 min = (offset % 3600) / 60;
1965 sprintf(buffer+1, "%04d", hr*100 + min);
1966 }
1967 else {
1968 buffer[0] = '\0';
1969 }
1970 replace = buffer;
1971 }
1972 else if ( t[1] == '-' && t[2] != '\0' &&
1973 strchr("dHIjmMSUwWyY", t[2]) ) {
1974 /* Microsoft uses '#' rather than '-' to remove padding */
1975 t[1] = '#';
1976 }
1977 else if ( t[1] != '\0' ) {
1978 ++t;
1979 }
1980
1981 if (replace) {
1982 int m;
1983 char *newfmt;
1984
1985 *t = '\0';
1986 m = t - fmt;
1987 newfmt = xasprintf("%s%s%s", fmt, replace, t+2);
1988 free(fmt);
1989 t = newfmt + m + strlen(replace) - 1;
1990 fmt = newfmt;
1991 }
1992 }
1993 }
1994
1995 ret = strftime(buf, max, fmt, tm);
1996 free(fmt);
1997
1998 return ret;
1999}
2000
2001#undef access
2002int mingw_access(const char *name, int mode)
2003{
2004 int ret;
2005 struct stat s;
2006
2007 /* Windows can only handle test for existence, read or write */
2008 if (mode == F_OK || (mode & ~X_OK)) {
2009 ret = _access(name, mode & ~X_OK);
2010 if (ret < 0 || !(mode & X_OK)) {
2011 return ret;
2012 }
2013 }
2014
2015 if (!mingw_stat(name, &s)) {
2016 if ((s.st_mode&S_IXUSR)) {
2017 return 0;
2018 }
2019 errno = EACCES;
2020 }
2021
2022 return -1;
2023}
2024
2025int mingw_rmdir(const char *path)
2026{
2027 /* On Linux rmdir(2) doesn't remove symlinks */
2028 if (is_symlink(path)) {
2029 errno = ENOTDIR;
2030 return -1;
2031 }
2032
2033 /* read-only directories cannot be removed */
2034 chmod(path, 0666);
2035 return rmdir(path);
2036}
2037
2038void mingw_sync(void)
2039{
2040 HANDLE h;
2041 FILE *mnt;
2042 struct mntent *entry;
2043 char name[] = "\\\\.\\C:";
2044
2045 mnt = setmntent(bb_path_mtab_file, "r");
2046 if (mnt) {
2047 while ((entry=getmntent(mnt)) != NULL) {
2048 name[4] = entry->mnt_dir[0];
2049 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
2050 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2051 OPEN_EXISTING, 0, NULL);
2052 if (h != INVALID_HANDLE_VALUE) {
2053 FlushFileBuffers(h);
2054 CloseHandle(h);
2055 }
2056 }
2057 endmntent(mnt);
2058 }
2059}
2060
2061#define NUMEXT 5
2062static const char win_suffix[NUMEXT][4] = { "com", "exe", "sh", "bat", "cmd" };
2063
2064static int has_win_suffix(const char *name, int start)
2065{
2066 const char *dot = strrchr(bb_basename(name), '.');
2067 int i;
2068
2069 if (dot != NULL && strlen(dot) < 5) {
2070 for (i=start; i<NUMEXT; ++i) {
2071 if (!strcasecmp(dot+1, win_suffix[i])) {
2072 return 1;
2073 }
2074 }
2075 }
2076 return 0;
2077}
2078
2079int has_bat_suffix(const char *name)
2080{
2081 return has_win_suffix(name, 3);
2082}
2083
2084int has_exe_suffix(const char *name)
2085{
2086 return has_win_suffix(name, 0);
2087}
2088
2089int has_exe_suffix_or_dot(const char *name)
2090{
2091 return last_char_is(name, '.') || has_win_suffix(name, 0);
2092}
2093
2094/* Copy path to an allocated string long enough to allow a file extension
2095 * to be added. */
2096char *alloc_ext_space(const char *path)
2097{
2098 char *s = xmalloc(strlen(path) + 5);
2099 strcpy(s, path);
2100 return s;
2101}
2102
2103/* Check if path is an executable or can be made into one by adding
2104 * a suffix. The suffix is added to the end of the argument which
2105 * must be long enough to allow this.
2106 *
2107 * If the return value is TRUE the argument contains the new path,
2108 * if FALSE the argument is unchanged.
2109 */
2110int
2111add_win32_extension(char *p)
2112{
2113 if (file_is_executable(p))
2114 return TRUE;
2115
2116 if (!has_exe_suffix_or_dot(p)) {
2117 int i, len = strlen(p);
2118
2119 p[len] = '.';
2120 for (i = 0; i < NUMEXT; ++i) {
2121 strcpy(p + len + 1, win_suffix[i]);
2122 if (file_is_executable(p))
2123 return TRUE;
2124 }
2125 p[len] = '\0';
2126 }
2127 return FALSE;
2128}
2129
2130/*
2131 * Determine if a path represents a WIN32 executable, adding a suffix
2132 * if necessary. Returns an allocated string if it does, NULL if not.
2133 */
2134char *
2135file_is_win32_exe(const char *name)
2136{
2137 char *path = alloc_ext_space(name);
2138
2139 if (add_win32_extension(path))
2140 return path;
2141
2142 free(path);
2143 return NULL;
2144}
2145
2146char * FAST_FUNC bs_to_slash(char *str)
2147{
2148 char *p;
2149
2150 for (p=str; *p; ++p) {
2151 if ( *p == '\\' ) {
2152 *p = '/';
2153 }
2154 }
2155 return str;
2156}
2157
2158#if ENABLE_UNICODE_SUPPORT
2159MINGW_BB_WCHAR_T * FAST_FUNC bs_to_slash_u(MINGW_BB_WCHAR_T *str)
2160{
2161 MINGW_BB_WCHAR_T *p;
2162
2163 for (p=str; *p; ++p) {
2164 if ( *p == '\\' ) {
2165 *p = '/';
2166 }
2167 }
2168 return str;
2169}
2170#endif
2171
2172void FAST_FUNC slash_to_bs(char *p)
2173{
2174 for (; *p; ++p) {
2175 if ( *p == '/' ) {
2176 *p = '\\';
2177 }
2178 }
2179}
2180
2181/* Windows strips trailing dots and spaces from the last component of
2182 * a file path. This routine emulates that behaviour so we can preempt
2183 * Windows if necessary. */
2184void FAST_FUNC strip_dot_space(char *p)
2185{
2186 char *start = (char *)bb_basename(p);
2187 char *end = start + strlen(start);
2188
2189 while (end > start && (end[-1] == '.' || end[-1] == ' ')) {
2190 *--end = '\0';
2191 }
2192
2193 // Strip trailing slash, but not from a drive root (C:/)
2194 if (--end != start && (*end == '/' || *end == '\\') &&
2195 !(end == p + 2 && root_len(p) == 2))
2196 *end = '\0';
2197}
2198
2199size_t FAST_FUNC remove_cr(char *p, size_t len)
2200{
2201 ssize_t i, j;
2202
2203 for (i=j=0; i<len; ++i) {
2204 if (p[i] == '\r' && i < len - 1 && p[i+1] == '\n')
2205 continue;
2206 p[j++] = p[i];
2207 }
2208 return j;
2209}
2210
2211off_t mingw_lseek(int fd, off_t offset, int whence)
2212{
2213 DWORD ftype;
2214 HANDLE h = (HANDLE)_get_osfhandle(fd);
2215 if (h == INVALID_HANDLE_VALUE) {
2216 errno = EBADF;
2217 return -1;
2218 }
2219 ftype = GetFileType(h);
2220 if (ftype != FILE_TYPE_DISK && ftype != FILE_TYPE_CHAR) {
2221 errno = ESPIPE;
2222 return -1;
2223 }
2224 return _lseeki64(fd, offset, whence);
2225}
2226
2227#undef GetTickCount64
2228ULONGLONG CompatGetTickCount64(void)
2229{
2230 DECLARE_PROC_ADDR(ULONGLONG, GetTickCount64, void);
2231
2232 if (!INIT_PROC_ADDR(kernel32.dll, GetTickCount64)) {
2233 return (ULONGLONG)GetTickCount();
2234 }
2235
2236 return GetTickCount64();
2237}
2238
2239#if ENABLE_FEATURE_INSTALLER
2240/*
2241 * Enumerate the names of all hard links to a file. The first call
2242 * provides the file name as the first argument; subsequent calls must
2243 * set the first argument to NULL. Returns 0 on error or when there are
2244 * no more links.
2245 */
2246int enumerate_links(const char *file, char *name)
2247{
2248 static HANDLE h = INVALID_HANDLE_VALUE;
2249 char aname[PATH_MAX];
2250 wchar_t wname[PATH_MAX];
2251 DWORD length = PATH_MAX;
2252 DECLARE_PROC_ADDR(HANDLE, FindFirstFileNameW, LPCWSTR, DWORD, LPDWORD,
2253 PWSTR);
2254 DECLARE_PROC_ADDR(BOOL, FindNextFileNameW, HANDLE, LPDWORD, PWSTR);
2255
2256 if (!INIT_PROC_ADDR(kernel32.dll, FindFirstFileNameW) ||
2257 !INIT_PROC_ADDR(kernel32.dll, FindNextFileNameW))
2258 return 0;
2259
2260 if (file != NULL) {
2261 wchar_t wfile[PATH_MAX];
2262 MultiByteToWideChar(CP_ACP, 0, file, -1, wfile, PATH_MAX);
2263 h = FindFirstFileNameW(wfile, 0, &length, wname);
2264 if (h == INVALID_HANDLE_VALUE)
2265 return 0;
2266 }
2267 else if (!FindNextFileNameW(h, &length, wname)) {
2268 FindClose(h);
2269 h = INVALID_HANDLE_VALUE;
2270 return 0;
2271 }
2272 WideCharToMultiByte(CP_ACP, 0, wname, -1, aname, PATH_MAX, NULL, NULL);
2273 realpath(aname, name);
2274 return 1;
2275}
2276#endif
2277
2278/* Return the length of the root of a UNC path, i.e. the '//host/share'
2279 * component, or 0 if the path doesn't look like that. */
2280int FAST_FUNC unc_root_len(const char *dir)
2281{
2282 const char *s = dir + 2;
2283 int len;
2284
2285 if (!is_unc_path(dir))
2286 return 0;
2287 len = strcspn(s, "/\\");
2288 if (len == 0)
2289 return 0;
2290 s += len + 1;
2291 len = strcspn(s, "/\\");
2292 if (len == 0)
2293 return 0;
2294 s += len;
2295
2296 return s - dir;
2297}
2298
2299/* Return the length of the root of a path, i.e. either the drive or
2300 * UNC '//host/share', or 0 if the path doesn't look like that. */
2301int FAST_FUNC root_len(const char *path)
2302{
2303 if (path == NULL)
2304 return 0;
2305 if (isalpha(*path) && path[1] == ':')
2306 return 2;
2307 return unc_root_len(path);
2308}
2309
2310const char * FAST_FUNC get_system_drive(void)
2311{
2312 static const char *drive = NULL;
2313 char sysdir[PATH_MAX];
2314 int len;
2315
2316 if (drive == NULL) {
2317 UINT ret = GetSystemDirectory(sysdir, PATH_MAX);
2318 if ((ret != 0 && ret < PATH_MAX) && (len=root_len(sysdir)))
2319 drive = xstrndup(sysdir, len);
2320 else
2321 drive = "";
2322 }
2323
2324 return getenv(BB_SYSTEMROOT) ?: drive;
2325}
2326
2327int chdir_system_drive(void)
2328{
2329 const char *sd = get_system_drive();
2330 int ret = -1;
2331
2332 if (*sd)
2333 ret = chdir(auto_string(concat_path_file(sd, "")));
2334 return ret;
2335}
2336
2337/*
2338 * This function is used to make relative paths absolute before a call
2339 * to chdir_system_drive(). It's unlikely to be useful in other cases.
2340 *
2341 * If the argument is an absolute path return 'path', otherwise return
2342 * an allocated string containing the resolved path. Die on failure,
2343 * which is most likely because the file doesn't exist.
2344 */
2345char * FAST_FUNC xabsolute_path(char *path)
2346{
2347 char *rpath;
2348
2349 if (root_len(path) != 0)
2350 return path; // absolute path
2351 rpath = xmalloc_realpath(path);
2352 if (rpath)
2353 return rpath;
2354 bb_perror_msg_and_die("can't open '%s'", path);
2355}
2356
2357char * FAST_FUNC get_drive_cwd(const char *path, char *buffer, int size)
2358{
2359 char drive[3] = { *path, ':', '\0' };
2360 DWORD ret;
2361
2362 ret = GetFullPathName(drive, size, buffer, NULL);
2363 if (ret == 0 || ret > size)
2364 return NULL;
2365 return bs_to_slash(buffer);
2366}
2367
2368void FAST_FUNC fix_path_case(char *path)
2369{
2370 char resolved[PATH_MAX];
2371 int len;
2372
2373 // Canonicalise path: for physical drives this makes case match
2374 // what's stored on disk. For mapped drives, not so much.
2375 if (realpath(path, resolved) && strcasecmp(path, resolved) == 0)
2376 strcpy(path, resolved);
2377
2378 // make drive letter or UNC hostname uppercase
2379 len = root_len(path);
2380 if (len == 2) {
2381 *path = toupper(*path);
2382 }
2383 else if (len != 0) {
2384 for (path+=2; !is_dir_sep(*path); ++path) {
2385 *path = toupper(*path);
2386 }
2387 }
2388}
2389
2390void FAST_FUNC make_sparse(int fd, off_t start, off_t end)
2391{
2392 DWORD dwTemp;
2393 HANDLE fh;
2394 FILE_ZERO_DATA_INFORMATION fzdi;
2395
2396 if ((fh=(HANDLE)_get_osfhandle(fd)) == INVALID_HANDLE_VALUE)
2397 return;
2398
2399 DeviceIoControl(fh, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwTemp, NULL);
2400
2401 fzdi.FileOffset.QuadPart = start;
2402 fzdi.BeyondFinalZero.QuadPart = end;
2403 DeviceIoControl(fh, FSCTL_SET_ZERO_DATA, &fzdi, sizeof(fzdi),
2404 NULL, 0, &dwTemp, NULL);
2405}
2406
2407void *get_proc_addr(const char *dll, const char *function,
2408 struct proc_addr *proc)
2409{
2410 /* only do this once */
2411 if (!proc->initialized) {
2412 HANDLE hnd = LoadLibraryExA(dll, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
2413
2414 /* The documentation for LoadLibraryEx says the above may fail
2415 * on Windows 7. If it does, retry using LoadLibrary with an
2416 * explicit, backslash-separated path. */
2417 if (!hnd) {
2418 char buf[PATH_MAX];
2419 UINT ret = GetSystemDirectory(buf, PATH_MAX);
2420 if (ret != 0 && ret < PATH_MAX) {
2421 char *path = concat_path_file(buf, dll);
2422 slash_to_bs(path);
2423 hnd = LoadLibrary(path);
2424 free(path);
2425 }
2426 }
2427
2428 if (hnd)
2429 proc->pfunction = GetProcAddress(hnd, function);
2430 proc->initialized = 1;
2431 }
2432 return proc->pfunction;
2433}
2434
2435int FAST_FUNC unix_path(const char *path)
2436{
2437 int i;
2438 char *p = xstrdup(path);
2439
2440#define UNIX_PATHS "/bin\0/usr/bin\0/sbin\0/usr/sbin\0"
2441 i = index_in_strings(UNIX_PATHS, dirname(p));
2442 free(p);
2443 return i >= 0;
2444}
2445
2446/* Return true if file is referenced using a path. This means a path
2447 * look-up isn't required. */
2448int FAST_FUNC has_path(const char *file)
2449{
2450 return strchr(file, '/') || strchr(file, '\\') ||
2451 has_dos_drive_prefix(file);
2452}
2453
2454/*
2455 * Test whether a path is relative to a known location (usually the
2456 * current working directory or a symlink). On Unix this is a path
2457 * that doesn't start with a slash but on Windows it also includes
2458 * paths that don't start with a backslash or a drive letter.
2459 *
2460 * Paths of the form /dir/file or c:dir/file aren't relative by this
2461 * definition.
2462 */
2463int FAST_FUNC is_relative_path(const char *path)
2464{
2465 return !is_dir_sep(path[0]) && !has_dos_drive_prefix(path);
2466}
2467
2468#if ENABLE_FEATURE_SH_STANDALONE
2469/*
2470 * In standalone shell mode it's possible there's no binary file
2471 * corresponding to an applet name. There's one case where it's
2472 * easy to determine the corresponding binary: if the applet name
2473 * matches the file name from bb_busybox_exec_path (with appropriate
2474 * allowance for 'busybox*.exe').
2475 */
2476const char * FAST_FUNC applet_to_exe(const char *name)
2477{
2478 const char *exefile = bb_basename(bb_busybox_exec_path);
2479 const char *exesuff = is_prefixed_with_case(exefile, name);
2480
2481 if (exesuff && (strcmp(name, "busybox") == 0 ||
2482 strcasecmp(exesuff, ".exe") == 0)) {
2483 return bb_busybox_exec_path;
2484 }
2485 return name;
2486}
2487#endif
2488
2489/*
2490 * Append a word to a space-separated string of words. The first
2491 * call should use a NULL pointer for str, subsequent calls should
2492 * pass an allocated string which will be freed.
2493 */
2494char * FAST_FUNC xappendword(const char *str, const char *word)
2495{
2496 char *newstr = str ? xasprintf("%s %s", str, word) : xstrdup(word);
2497 free((void *)str);
2498 return newstr;
2499}
2500
2501/*
2502 * Detect if the environment contains certain mixed-case names:
2503 *
2504 * Path is present in a standard Windows environment
2505 * ComSpec is present in WINE
2506 * ProgramData is present in Cygwin/MSYS2
2507 */
2508int
2509windows_env(void)
2510{
2511 const char *names = "PATH=\0""COMSPEC=\0""PROGRAMDATA=\0";
2512 const char *n;
2513
2514 for (char **envp = environ; envp && *envp; envp++) {
2515 for (n = names; *n; ) {
2516 if (is_prefixed_with_case(*envp, n) &&
2517 !is_prefixed_with(*envp, n)) {
2518 return TRUE;
2519 }
2520 while (*n++)
2521 ;
2522 }
2523 }
2524 return FALSE;
2525}
2526
2527void FAST_FUNC
2528change_critical_error_dialogs(const char *newval)
2529{
2530 SetErrorMode(newval && newval[0] == '1' && newval[1] == '\0' ?
2531 0 : SEM_FAILCRITICALERRORS);
2532}
2533
2534char * FAST_FUNC exe_relative_path(const char *tail)
2535{
2536 char *exepath = xstrdup(bb_busybox_exec_path);
2537 char *relpath = concat_path_file(dirname(exepath), tail);
2538 free(exepath);
2539 return relpath;
2540}
diff --git a/win32/mntent.c b/win32/mntent.c
new file mode 100644
index 000000000..7f142b485
--- /dev/null
+++ b/win32/mntent.c
@@ -0,0 +1,94 @@
1/*
2 * A simple WIN32 implementation of mntent routines. It only handles
3 * logical drives.
4 */
5#define MNTENT_PRIVATE
6#include "libbb.h"
7
8struct mntstate {
9 DWORD drives;
10 int index;
11};
12
13int fill_mntdata(struct mntdata *data, int index)
14{
15 UINT drive_type;
16 char buf[PATH_MAX];
17
18 // initialise pointers and scalar data
19 data->me.mnt_fsname = data->mnt_fsname;
20 data->me.mnt_dir = data->mnt_dir;
21 data->me.mnt_type = data->mnt_type;
22 data->me.mnt_opts = data->mnt_opts;
23 data->me.mnt_freq = 0;
24 data->me.mnt_passno = 0;
25
26 // initialise strings
27 data->mnt_fsname[0] = 'A' + index;
28 data->mnt_fsname[1] = ':';
29 data->mnt_fsname[2] = '\0';
30 data->mnt_dir[0] = 'A' + index;
31 data->mnt_dir[1] = ':';
32 data->mnt_dir[2] = '/';
33 data->mnt_dir[3] = '\0';
34 data->mnt_type[0] = '\0';
35 data->mnt_opts[0] = '\0';
36
37 drive_type = GetDriveType(data->mnt_dir);
38 if (drive_type == DRIVE_FIXED || drive_type == DRIVE_CDROM ||
39 drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_REMOTE) {
40 if (!GetVolumeInformation(data->mnt_dir, NULL, 0, NULL, NULL,
41 NULL, data->mnt_type, 100)) {
42 return FALSE;
43 }
44
45 if (realpath(data->mnt_dir, buf) != NULL) {
46 if (isalpha(buf[0]) && strcmp(buf+1, ":/") == 0)
47 buf[2] = '\0';
48 strcpy(data->mnt_fsname, buf);
49 }
50 return TRUE;
51 }
52 return FALSE;
53}
54
55FILE *mingw_setmntent(void)
56{
57 struct mntstate *state;
58
59 if ( (state=malloc(sizeof(struct mntstate))) == NULL ) {
60 return NULL;
61 }
62
63 state->drives = GetLogicalDrives();
64 state->index = -1;
65
66 return (FILE *)state;
67}
68
69struct mntent *getmntent(FILE *stream)
70{
71 struct mntstate *state = (struct mntstate *)stream;
72 static struct mntdata *data = NULL;
73 struct mntent *entry = NULL;
74
75 while (++state->index < 26) {
76 if ((state->drives & 1 << state->index) != 0) {
77 if (data == NULL)
78 data = xmalloc(sizeof(*data));
79
80 if (fill_mntdata(data, state->index)) {
81 entry = &data->me;
82 break;
83 }
84 }
85 }
86
87 return entry;
88}
89
90int endmntent(FILE *stream)
91{
92 free(stream);
93 return 0;
94}
diff --git a/win32/mntent.h b/win32/mntent.h
new file mode 100644
index 000000000..029f18b96
--- /dev/null
+++ b/win32/mntent.h
@@ -0,0 +1,33 @@
1#ifndef MNTENT_H
2#define MNTENT_H
3
4#include <stdio.h>
5
6struct mntent {
7 char *mnt_fsname; /* Device or server for filesystem. */
8 char *mnt_dir; /* Directory mounted on. */
9 char *mnt_type; /* Type of filesystem: ufs, nfs, etc. */
10 char *mnt_opts; /* Comma-separated options for fs. */
11 int mnt_freq; /* Dump frequency (in days). */
12 int mnt_passno; /* Pass number for `fsck'. */
13};
14
15extern FILE *mingw_setmntent(void);
16extern struct mntent *getmntent(FILE *stream);
17extern int endmntent(FILE *stream);
18
19# if defined(MNTENT_PRIVATE)
20struct mntdata {
21 struct mntent me;
22 char mnt_fsname[PATH_MAX];
23 char mnt_dir[4];
24 char mnt_type[100];
25 char mnt_opts[4];
26};
27
28extern int fill_mntdata(struct mntdata *data, int index);
29# endif
30
31#define setmntent(f, m) mingw_setmntent()
32
33#endif
diff --git a/win32/net.c b/win32/net.c
new file mode 100644
index 000000000..33dc837fa
--- /dev/null
+++ b/win32/net.c
@@ -0,0 +1,146 @@
1#include "libbb.h"
2
3int inet_aton(const char *cp, struct in_addr *inp)
4{
5 unsigned long val = inet_addr(cp);
6
7 if (val == INADDR_NONE)
8 return 0;
9 inp->S_un.S_addr = val;
10 return 1;
11}
12
13void init_winsock(void)
14{
15 WSADATA wsa;
16 static int initialized = 0;
17
18 if (initialized)
19 return;
20
21 if (WSAStartup(MAKEWORD(2,2), &wsa))
22 bb_error_msg_and_die("WSAStartup failed, error %d", WSAGetLastError());
23
24 atexit((void(*)(void)) WSACleanup);
25 initialized = 1;
26}
27
28#undef gethostname
29int mingw_gethostname(char *name, int namelen)
30{
31 init_winsock();
32 return gethostname(name, namelen);
33}
34
35#undef gethostbyaddr
36struct hostent *mingw_gethostbyaddr(const void *addr, socklen_t len, int type)
37{
38 init_winsock();
39 return gethostbyaddr(addr, len, type);
40}
41
42#undef getaddrinfo
43int mingw_getaddrinfo(const char *node, const char *service,
44 const struct addrinfo *hints, struct addrinfo **res)
45{
46 init_winsock();
47 return getaddrinfo(node, service, hints, res);
48}
49
50int mingw_socket(int domain, int type, int protocol)
51{
52 int sockfd;
53 SOCKET s;
54
55 init_winsock();
56 s = WSASocket(domain, type, protocol, NULL, 0, 0);
57 if (s == INVALID_SOCKET) {
58 /*
59 * WSAGetLastError() values are regular BSD error codes
60 * biased by WSABASEERR.
61 * However, strerror() does not know about networking
62 * specific errors, which are values beginning at 38 or so.
63 * Therefore, we choose to leave the biased error code
64 * in errno so that _if_ someone looks up the code somewhere,
65 * then it is at least the number that are usually listed.
66 */
67 errno = WSAGetLastError();
68 return -1;
69 }
70 /* convert into a file descriptor */
71 if ((sockfd = _open_osfhandle((intptr_t)s, O_RDWR|O_BINARY)) < 0) {
72 closesocket(s);
73 bb_error_msg("unable to make a socket file descriptor: %s",
74 strerror(errno));
75 return -1;
76 }
77 return sockfd;
78}
79
80#undef connect
81int mingw_connect(int sockfd, const struct sockaddr *sa, size_t sz)
82{
83 SOCKET s = (SOCKET)_get_osfhandle(sockfd);
84 return connect(s, sa, sz);
85}
86
87#undef bind
88int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
89{
90 SOCKET s = (SOCKET)_get_osfhandle(sockfd);
91 return bind(s, sa, sz);
92}
93
94#undef setsockopt
95int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
96{
97 SOCKET s = (SOCKET)_get_osfhandle(sockfd);
98 return setsockopt(s, lvl, optname, (const char*)optval, optlen);
99}
100
101#undef shutdown
102int mingw_shutdown(int sockfd, int how)
103{
104 SOCKET s = (SOCKET)_get_osfhandle(sockfd);
105 return shutdown(s, how);
106}
107
108#undef listen
109int mingw_listen(int sockfd, int backlog)
110{
111 SOCKET s = (SOCKET)_get_osfhandle(sockfd);
112 return listen(s, backlog);
113}
114
115#undef accept
116int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
117{
118 int sockfd2;
119
120 SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
121 SOCKET s2 = accept(s1, sa, sz);
122
123 /* convert into a file descriptor */
124 if ((sockfd2 = _open_osfhandle((intptr_t)s2, O_RDWR|O_BINARY)) < 0) {
125 int err = errno;
126 closesocket(s2);
127 bb_error_msg("unable to make a socket file descriptor: %s",
128 strerror(err));
129 return -1;
130 }
131 return sockfd2;
132}
133
134#undef getpeername
135int mingw_getpeername(int fd, struct sockaddr *sa, socklen_t *sz)
136{
137 SOCKET sock;
138
139 init_winsock();
140 sock = (SOCKET)_get_osfhandle(fd);
141 if (sock == INVALID_SOCKET) {
142 errno = EBADF;
143 return -1;
144 }
145 return getpeername(sock, sa, sz);
146}
diff --git a/win32/net/if.h b/win32/net/if.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/net/if.h
diff --git a/win32/netdb.h b/win32/netdb.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/netdb.h
diff --git a/win32/netinet/in.h b/win32/netinet/in.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/netinet/in.h
diff --git a/win32/paths.h b/win32/paths.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/paths.h
diff --git a/win32/poll.c b/win32/poll.c
new file mode 100644
index 000000000..8ab6bbf29
--- /dev/null
+++ b/win32/poll.c
@@ -0,0 +1,656 @@
1/* Emulation for poll(2)
2 Contributed by Paolo Bonzini.
3
4 Copyright 2001-2003, 2006-2024 Free Software Foundation, Inc.
5
6 This file is part of gnulib.
7
8 This file is free software: you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as
10 published by the Free Software Foundation; either version 2.1 of the
11 License, or (at your option) any later version.
12
13 This file is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with this program. If not, see <https://www.gnu.org/licenses/>. */
20
21/* Tell gcc not to warn about the (nfd < 0) tests, below. */
22#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
23# pragma GCC diagnostic ignored "-Wtype-limits"
24#endif
25
26#include "libbb.h"
27#include <malloc.h>
28
29#include <sys/types.h>
30
31/* Specification. */
32#include <poll.h>
33
34#include <errno.h>
35#include <limits.h>
36#include <assert.h>
37
38#if defined _WIN32 && ! defined __CYGWIN__
39# define WINDOWS_NATIVE
40# include <winsock2.h>
41# include <windows.h>
42# include <io.h>
43# include <stdio.h>
44# include <conio.h>
45#else
46# include <sys/time.h>
47# include <unistd.h>
48#endif
49
50#include <sys/select.h>
51#include <sys/socket.h>
52
53#ifdef HAVE_SYS_IOCTL_H
54# include <sys/ioctl.h>
55#endif
56#ifdef HAVE_SYS_FILIO_H
57# include <sys/filio.h>
58#endif
59
60#include <time.h>
61
62#ifndef INFTIM
63# define INFTIM (-1)
64#endif
65
66/* BeOS does not have MSG_PEEK. */
67#ifndef MSG_PEEK
68# define MSG_PEEK 0
69#endif
70
71#ifdef WINDOWS_NATIVE
72
73/* Don't assume that UNICODE is not defined. */
74# undef GetModuleHandle
75# define GetModuleHandle GetModuleHandleA
76# undef PeekConsoleInput
77# define PeekConsoleInput PeekConsoleInputA
78# undef CreateEvent
79# define CreateEvent CreateEventA
80# undef PeekMessage
81# define PeekMessage PeekMessageA
82# undef DispatchMessage
83# define DispatchMessage DispatchMessageA
84
85/* Do *not* use the function WSAPoll
86 <https://docs.microsoft.com/en-us/windows/desktop/api/winsock2/nf-winsock2-wsapoll>
87 because there is a bug named “Windows 8 Bugs 309411 - WSAPoll does not
88 report failed connections” that Microsoft won't fix.
89 See Daniel Stenberg: "WASPoll is broken"
90 <https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/>. */
91
92/* Here we need the recv() function from Windows, that takes a SOCKET as
93 first argument, not any possible gnulib override. */
94# undef recv
95
96/* Here we need the select() function from Windows, because we pass bit masks
97 of SOCKETs, not bit masks of FDs. */
98# undef select
99
100/* Here we need timeval from Windows since this is what the select() function
101 from Windows requires. */
102# undef timeval
103
104/* Avoid warnings from gcc -Wcast-function-type. */
105# define GetProcAddress \
106 (void *) GetProcAddress
107
108static BOOL IsConsoleHandle (HANDLE h)
109{
110 DWORD mode;
111 return GetConsoleMode (h, &mode) != 0;
112}
113
114static BOOL
115IsSocketHandle (HANDLE h)
116{
117 WSANETWORKEVENTS ev;
118
119 if (IsConsoleHandle (h))
120 return FALSE;
121
122 /* Under Wine, it seems that getsockopt returns 0 for pipes too.
123 WSAEnumNetworkEvents instead distinguishes the two correctly. */
124 ev.lNetworkEvents = 0xDEADBEEF;
125 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
126 return ev.lNetworkEvents != 0xDEADBEEF;
127}
128
129/* Declare data structures for ntdll functions. */
130typedef struct _FILE_PIPE_LOCAL_INFORMATION {
131 ULONG NamedPipeType;
132 ULONG NamedPipeConfiguration;
133 ULONG MaximumInstances;
134 ULONG CurrentInstances;
135 ULONG InboundQuota;
136 ULONG ReadDataAvailable;
137 ULONG OutboundQuota;
138 ULONG WriteQuotaAvailable;
139 ULONG NamedPipeState;
140 ULONG NamedPipeEnd;
141} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
142
143typedef struct _IO_STATUS_BLOCK
144{
145 union {
146 DWORD Status;
147 PVOID Pointer;
148 } u;
149 ULONG_PTR Information;
150} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
151
152typedef enum _FILE_INFORMATION_CLASS {
153 FilePipeLocalInformation = 24
154} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
155
156typedef DWORD (WINAPI *PNtQueryInformationFile)
157 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
158
159# ifndef PIPE_BUF
160# define PIPE_BUF 512
161# endif
162
163/* Compute revents values for file handle H. If some events cannot happen
164 for the handle, eliminate them from *P_SOUGHT. */
165
166static int
167windows_compute_revents (HANDLE h, int *p_sought)
168{
169 int i, ret, happened;
170 INPUT_RECORD *irbuffer;
171 DWORD avail, nbuffer;
172 BOOL bRet;
173#if 0
174 IO_STATUS_BLOCK iosb;
175 FILE_PIPE_LOCAL_INFORMATION fpli;
176 static PNtQueryInformationFile NtQueryInformationFile;
177 static BOOL once_only;
178#endif
179
180 switch (GetFileType (h))
181 {
182 case FILE_TYPE_PIPE:
183#if 0
184 if (!once_only)
185 {
186 NtQueryInformationFile = (PNtQueryInformationFile)
187 GetProcAddress (GetModuleHandle ("ntdll.dll"),
188 "NtQueryInformationFile");
189 once_only = TRUE;
190 }
191#endif
192
193 happened = 0;
194 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
195 {
196 if (avail)
197 happened |= *p_sought & (POLLIN | POLLRDNORM);
198 }
199 else if (GetLastError () == ERROR_BROKEN_PIPE)
200 happened |= POLLHUP;
201
202 else
203 {
204 /* The writability of a pipe can't be detected reliably on Windows.
205 * Just say it's OK.
206 *
207 * Details:
208 *
209 * https://github.com/git-for-windows/git/commit/94f4d01932279c419844aa708bec31a26056bc6b
210 */
211#if 0
212 /* It was the write-end of the pipe. Check if it is writable.
213 If NtQueryInformationFile fails, optimistically assume the pipe is
214 writable. This could happen on Windows 9x, where
215 NtQueryInformationFile is not available, or if we inherit a pipe
216 that doesn't permit FILE_READ_ATTRIBUTES access on the write end
217 (I think this should not happen since Windows XP SP2; WINE seems
218 fine too). Otherwise, ensure that enough space is available for
219 atomic writes. */
220 memset (&iosb, 0, sizeof (iosb));
221 memset (&fpli, 0, sizeof (fpli));
222
223 if (!NtQueryInformationFile
224 || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
225 FilePipeLocalInformation)
226 || fpli.WriteQuotaAvailable >= PIPE_BUF
227 || (fpli.OutboundQuota < PIPE_BUF &&
228 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
229#endif
230 happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
231 }
232 return happened;
233
234 case FILE_TYPE_CHAR:
235 // Fall through to default case for non-console, e.g. /dev/null.
236 if (IsConsoleHandle (h)) {
237 nbuffer = avail = 0;
238 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
239 if (bRet)
240 {
241 /* Input buffer. */
242 *p_sought &= POLLIN | POLLRDNORM;
243 if (nbuffer == 0)
244 // Having no unread events isn't an error condition.
245 return 0 /* was POLLHUP */;
246 if (!*p_sought)
247 return 0;
248
249 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
250 bRet = PeekConsoleInputW (h, irbuffer, nbuffer, &avail);
251 if (!bRet || avail == 0)
252 return POLLHUP;
253
254 for (i = 0; i < avail; i++)
255 // Ignore key release.
256 if (irbuffer[i].EventType == KEY_EVENT &&
257 irbuffer[i].Event.KeyEvent.bKeyDown)
258 return *p_sought;
259 return 0;
260 }
261 else
262 {
263 /* Screen buffer. */
264 *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
265 return *p_sought;
266 }
267 }
268 /* fall through */
269
270 default:
271 ret = WaitForSingleObject (h, 0);
272 if (ret == WAIT_OBJECT_0)
273 return *p_sought & ~(POLLPRI | POLLRDBAND);
274
275 // Add (POLLIN | POLLRDNORM). Why only support write?
276 return *p_sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND);
277 }
278}
279
280/* Convert fd_sets returned by select into revents values. */
281
282static int
283windows_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
284{
285 int happened = 0;
286
287 if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
288 happened |= (POLLIN | POLLRDNORM) & sought;
289
290 else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
291 {
292 int r, error;
293
294 char data[64];
295 WSASetLastError (0);
296 r = recv (h, data, sizeof (data), MSG_PEEK);
297 error = WSAGetLastError ();
298 WSASetLastError (0);
299
300 if (r > 0 || error == WSAENOTCONN)
301 happened |= (POLLIN | POLLRDNORM) & sought;
302
303 /* Distinguish hung-up sockets from other errors. */
304 else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
305 || error == WSAECONNABORTED || error == WSAENETRESET)
306 happened |= POLLHUP;
307
308 else
309 happened |= POLLERR;
310 }
311
312 if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
313 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
314
315 if (lNetworkEvents & FD_OOB)
316 happened |= (POLLPRI | POLLRDBAND) & sought;
317
318 return happened;
319}
320
321#else /* !MinGW */
322
323/* Convert select(2) returned fd_sets into poll(2) revents values. */
324static int
325compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
326{
327 int happened = 0;
328 if (FD_ISSET (fd, rfds))
329 {
330 int r;
331 int socket_errno;
332
333# if defined __MACH__ && defined __APPLE__
334 /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
335 for some kinds of descriptors. Detect if this descriptor is a
336 connected socket, a server socket, or something else using a
337 0-byte recv, and use ioctl(2) to detect POLLHUP. */
338 r = recv (fd, NULL, 0, MSG_PEEK);
339 socket_errno = (r < 0) ? errno : 0;
340 if (r == 0 || socket_errno == ENOTSOCK)
341 ioctl (fd, FIONREAD, &r);
342# else
343 char data[64];
344 r = recv (fd, data, sizeof (data), MSG_PEEK);
345 socket_errno = (r < 0) ? errno : 0;
346# endif
347 if (r == 0)
348 happened |= POLLHUP;
349
350 /* If the event happened on an unconnected server socket,
351 that's fine. */
352 else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
353 happened |= (POLLIN | POLLRDNORM) & sought;
354
355 /* Distinguish hung-up sockets from other errors. */
356 else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
357 || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
358 happened |= POLLHUP;
359
360 /* some systems can't use recv() on non-socket, including HP NonStop */
361 else if (socket_errno == ENOTSOCK)
362 happened |= (POLLIN | POLLRDNORM) & sought;
363
364 else
365 happened |= POLLERR;
366 }
367
368 if (FD_ISSET (fd, wfds))
369 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
370
371 if (FD_ISSET (fd, efds))
372 happened |= (POLLPRI | POLLRDBAND) & sought;
373
374 return happened;
375}
376#endif /* !MinGW */
377
378int
379poll (struct pollfd *pfd, nfds_t nfd, int timeout)
380{
381#ifndef WINDOWS_NATIVE
382 fd_set rfds, wfds, efds;
383 struct timeval tv;
384 struct timeval *ptv;
385 int maxfd, rc;
386 nfds_t i;
387
388 if (nfd > INT_MAX)
389 {
390 errno = EINVAL;
391 return -1;
392 }
393 /* Don't check directly for NFD greater than OPEN_MAX. Any practical use
394 of a too-large NFD is caught by one of the other checks below, and
395 checking directly for getdtablesize is too much of a portability
396 and/or performance and/or correctness hassle. */
397
398 /* EFAULT is not necessary to implement, but let's do it in the
399 simplest case. */
400 if (!pfd && nfd)
401 {
402 errno = EFAULT;
403 return -1;
404 }
405
406 /* convert timeout number into a timeval structure */
407 if (timeout == 0)
408 {
409 ptv = &tv;
410 tv = (struct timeval) {0};
411 }
412 else if (timeout > 0)
413 {
414 ptv = &tv;
415 tv = (struct timeval) {
416 .tv_sec = timeout / 1000,
417 .tv_usec = (timeout % 1000) * 1000
418 };
419 }
420 else if (timeout == INFTIM)
421 /* wait forever */
422 ptv = NULL;
423 else
424 {
425 errno = EINVAL;
426 return -1;
427 }
428
429 /* create fd sets and determine max fd */
430 maxfd = -1;
431 FD_ZERO (&rfds);
432 FD_ZERO (&wfds);
433 FD_ZERO (&efds);
434 for (i = 0; i < nfd; i++)
435 {
436 if (pfd[i].fd < 0)
437 continue;
438 if (maxfd < pfd[i].fd)
439 {
440 maxfd = pfd[i].fd;
441 if (FD_SETSIZE <= maxfd)
442 {
443 errno = EINVAL;
444 return -1;
445 }
446 }
447 if (pfd[i].events & (POLLIN | POLLRDNORM))
448 FD_SET (pfd[i].fd, &rfds);
449 /* see select(2): "the only exceptional condition detectable
450 is out-of-band data received on a socket", hence we push
451 POLLWRBAND events onto wfds instead of efds. */
452 if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
453 FD_SET (pfd[i].fd, &wfds);
454 if (pfd[i].events & (POLLPRI | POLLRDBAND))
455 FD_SET (pfd[i].fd, &efds);
456 }
457
458 /* examine fd sets */
459 rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
460 if (rc < 0)
461 return rc;
462
463 /* establish results */
464 rc = 0;
465 for (i = 0; i < nfd; i++)
466 {
467 pfd[i].revents = (pfd[i].fd < 0
468 ? 0
469 : compute_revents (pfd[i].fd, pfd[i].events,
470 &rfds, &wfds, &efds));
471 rc += pfd[i].revents != 0;
472 }
473
474 return rc;
475#else
476 static struct timeval tv0;
477 static HANDLE hEvent;
478 WSANETWORKEVENTS ev;
479 HANDLE h, handle_array[FD_SETSIZE + 2];
480 DWORD ret, wait_timeout, nhandles;
481 fd_set rfds, wfds, xfds;
482 BOOL poll_again;
483 MSG msg;
484 int rc = 0;
485 nfds_t i;
486 DWORD real_timeout = 0;
487 int save_timeout = timeout;
488 clock_t tend = clock () + timeout;
489
490 if (nfd > INT_MAX || timeout < -1)
491 {
492 errno = EINVAL;
493 return -1;
494 }
495
496 if (!hEvent)
497 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
498
499restart:
500 /* How much is left to wait? */
501 timeout = save_timeout;
502 if (timeout != INFTIM)
503 {
504 clock_t now = clock ();
505 real_timeout = tend > now ? tend - now : 0;
506 }
507
508 handle_array[0] = hEvent;
509 nhandles = 1;
510 FD_ZERO (&rfds);
511 FD_ZERO (&wfds);
512 FD_ZERO (&xfds);
513
514 /* Classify socket handles and create fd sets. */
515 for (i = 0; i < nfd; i++)
516 {
517 int sought = pfd[i].events;
518 pfd[i].revents = 0;
519 if (pfd[i].fd < 0)
520 continue;
521 if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
522 | POLLPRI | POLLRDBAND)))
523 continue;
524
525 h = (HANDLE) _get_osfhandle (pfd[i].fd);
526 assert (h != NULL);
527 if (IsSocketHandle (h))
528 {
529 int requested = FD_CLOSE;
530
531 /* see above; socket handles are mapped onto select. */
532 if (sought & (POLLIN | POLLRDNORM))
533 {
534 requested |= FD_READ | FD_ACCEPT;
535 FD_SET ((SOCKET) h, &rfds);
536 }
537 if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
538 {
539 requested |= FD_WRITE | FD_CONNECT;
540 FD_SET ((SOCKET) h, &wfds);
541 }
542 if (sought & (POLLPRI | POLLRDBAND))
543 {
544 requested |= FD_OOB;
545 FD_SET ((SOCKET) h, &xfds);
546 }
547
548 if (requested)
549 WSAEventSelect ((SOCKET) h, hEvent, requested);
550 }
551 else
552 {
553 /* Poll now. If we get an event, do not poll again. Also,
554 screen buffer handles are waitable, and they'll block until
555 a character is available. windows_compute_revents eliminates
556 bits for the "wrong" direction. */
557 pfd[i].revents = windows_compute_revents (h, &sought);
558 if (sought)
559 handle_array[nhandles++] = h;
560 if (pfd[i].revents)
561 timeout = 0;
562 }
563 }
564
565 if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
566 {
567 /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
568 no need to call select again. */
569 poll_again = FALSE;
570 wait_timeout = 0;
571 }
572 else
573 {
574 poll_again = TRUE;
575 if (timeout == INFTIM)
576 wait_timeout = INFINITE;
577 else
578 wait_timeout = timeout;
579 }
580
581 for (;;)
582 {
583 ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
584 wait_timeout, QS_ALLINPUT);
585
586 if (ret == WAIT_OBJECT_0 + nhandles)
587 {
588 /* new input of some other kind */
589 BOOL bRet;
590 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
591 {
592 TranslateMessage (&msg);
593 DispatchMessage (&msg);
594 }
595 }
596 else
597 break;
598 }
599
600 if (poll_again)
601 select (0, &rfds, &wfds, &xfds, &tv0);
602
603 /* Place a sentinel at the end of the array. */
604 handle_array[nhandles] = NULL;
605 nhandles = 1;
606 for (i = 0; i < nfd; i++)
607 {
608 int happened;
609
610 if (pfd[i].fd < 0)
611 continue;
612 if (!(pfd[i].events & (POLLIN | POLLRDNORM |
613 POLLOUT | POLLWRNORM | POLLWRBAND)))
614 continue;
615
616 h = (HANDLE) _get_osfhandle (pfd[i].fd);
617 if (h != handle_array[nhandles])
618 {
619 /* It's a socket. */
620 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
621 WSAEventSelect ((SOCKET) h, 0, 0);
622
623 /* If we're lucky, WSAEnumNetworkEvents already provided a way
624 to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
625 if (FD_ISSET ((SOCKET) h, &rfds)
626 && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
627 ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
628 if (FD_ISSET ((SOCKET) h, &wfds))
629 ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
630 if (FD_ISSET ((SOCKET) h, &xfds))
631 ev.lNetworkEvents |= FD_OOB;
632
633 happened = windows_compute_revents_socket ((SOCKET) h, pfd[i].events,
634 ev.lNetworkEvents);
635 }
636 else
637 {
638 /* Not a socket. */
639 int sought = pfd[i].events;
640 happened = windows_compute_revents (h, &sought);
641 nhandles++;
642 }
643
644 if ((pfd[i].revents |= happened) != 0)
645 rc++;
646 }
647
648 if (!rc && (save_timeout == INFTIM || (real_timeout != 0 && nhandles > 1)))
649 {
650 SleepEx (1, TRUE);
651 goto restart;
652 }
653
654 return rc;
655#endif
656}
diff --git a/win32/poll.h b/win32/poll.h
new file mode 100644
index 000000000..b7aa59d97
--- /dev/null
+++ b/win32/poll.h
@@ -0,0 +1,53 @@
1/* Header for poll(2) emulation
2 Contributed by Paolo Bonzini.
3
4 Copyright 2001, 2002, 2003, 2007, 2009, 2010 Free Software Foundation, Inc.
5
6 This file is part of gnulib.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation,
20 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
21
22#ifndef _GL_POLL_H
23#define _GL_POLL_H
24
25/* fake a poll(2) environment */
26#define POLLIN 0x0001 /* any readable data available */
27#define POLLPRI 0x0002 /* OOB/Urgent readable data */
28#define POLLOUT 0x0004 /* file descriptor is writeable */
29#define POLLERR 0x0008 /* some poll error occurred */
30#define POLLHUP 0x0010 /* file descriptor was "hung up" */
31#define POLLNVAL 0x0020 /* requested events "invalid" */
32#define POLLRDNORM 0x0040
33#define POLLRDBAND 0x0080
34#define POLLWRNORM 0x0100
35#define POLLWRBAND 0x0200
36
37struct pollfd
38{
39 int fd; /* which file descriptor to poll */
40 short events; /* events we are interested in */
41 short revents; /* events found on return */
42};
43
44typedef unsigned long nfds_t;
45
46extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout);
47
48/* Define INFTIM only if doing so conforms to POSIX. */
49#if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE)
50#define INFTIM (-1)
51#endif
52
53#endif /* _GL_POLL_H */
diff --git a/win32/popen.c b/win32/popen.c
new file mode 100644
index 000000000..7cf2b1893
--- /dev/null
+++ b/win32/popen.c
@@ -0,0 +1,316 @@
1#include <fcntl.h>
2#include "libbb.h"
3#include "NUM_APPLETS.h"
4
5typedef struct {
6 PROCESS_INFORMATION piProcInfo;
7 HANDLE pipe[2];
8 int fd;
9} pipe_data;
10
11static pipe_data *pipes = NULL;
12static int num_pipes = 0;
13
14static int mingw_popen_internal(pipe_data *p, const char *exe,
15 const char *cmd, const char *mode, int fd0, pid_t *pid);
16
17static int mingw_pipe(pipe_data *p, int bidi)
18{
19 SECURITY_ATTRIBUTES sa;
20
21 sa.nLength = sizeof(sa); /* Length in bytes */
22 sa.bInheritHandle = 1; /* the child must inherit these handles */
23 sa.lpSecurityDescriptor = NULL;
24
25 if (!bidi) {
26 /* pipe[0] is the read handle, pipe[i] the write handle */
27 if ( !CreatePipe (&p->pipe[0], &p->pipe[1], &sa, 1 << 13) ) {
28 return -1;
29 }
30 }
31 else {
32 char *name;
33 const int ip = 1; /* index of parent end of pipe */
34 const int ic = 0; /* index of child end of pipe */
35 static int count = 0;
36
37 name = xasprintf("\\\\.\\pipe\\bb_pipe.%d.%d", getpid(), ++count);
38
39 p->pipe[ip] = CreateNamedPipe(name,
40 PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,
41 PIPE_TYPE_BYTE|PIPE_WAIT,
42 1, 4096, 4096, 0, &sa);
43
44 p->pipe[ic] = CreateFile(name, GENERIC_READ|GENERIC_WRITE, 0, &sa,
45 OPEN_EXISTING,
46 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
47 NULL);
48 free(name);
49 }
50
51 return (p->pipe[0] == INVALID_HANDLE_VALUE ||
52 p->pipe[1] == INVALID_HANDLE_VALUE) ? -1 : 0;
53}
54
55static void clear_pipe_data(pipe_data *p)
56{
57 memset(p, 0, sizeof(pipe_data));
58 p->pipe[0] = INVALID_HANDLE_VALUE;
59 p->pipe[1] = INVALID_HANDLE_VALUE;
60 p->fd = -1;
61}
62
63static void close_pipe_data(pipe_data *p)
64{
65 if (p->pipe[0] != INVALID_HANDLE_VALUE)
66 CloseHandle(p->pipe[0]);
67 if (p->pipe[1] != INVALID_HANDLE_VALUE)
68 CloseHandle(p->pipe[1]);
69 clear_pipe_data(p);
70}
71
72/*
73 * Search for a pipe_data structure with file descriptor fd. If fd is
74 * -1 and no empty slots are available the array is extended. Return
75 * NULL if the file descriptor can't be found or the array can't be
76 * extended.
77 */
78static pipe_data *find_pipe(int fd)
79{
80 int i;
81 pipe_data *p = NULL;
82
83 /* find a matching pipe structure */
84 for ( i=0; i<num_pipes; ++i ) {
85 if (pipes[i].fd == fd) {
86 p = pipes+i;
87 break;
88 }
89 }
90
91 /* if looking for valid file descriptor return now */
92 if (fd != -1)
93 return p;
94
95 if ( p == NULL ) {
96 /* need to extend array */
97 if ( (p=realloc(pipes, sizeof(pipe_data)*(num_pipes+10))) == NULL ) {
98 return NULL;
99 }
100
101 pipes = p;
102 p = pipes + num_pipes;
103 for ( i=0; i<10; ++i ) {
104 clear_pipe_data(p+i);
105 }
106 num_pipes += 10;
107 }
108 clear_pipe_data(p);
109
110 return p;
111}
112
113FILE *mingw_popen(const char *cmd, const char *mode)
114{
115 pipe_data *p;
116 FILE *fptr = NULL;
117 int fd;
118 char *arg, *cmd_buff;
119
120 if ( cmd == NULL || *cmd == '\0' || mode == NULL ||
121 (*mode != 'r' && *mode != 'w') ) {
122 return NULL;
123 }
124
125 /* find an unused pipe structure */
126 if ((p=find_pipe(-1)) == NULL) {
127 return NULL;
128 }
129
130 arg = quote_arg(cmd);
131 cmd_buff = xasprintf("sh -c %s", arg);
132
133 /* Create the pipe */
134 if ((fd=mingw_popen_internal(p, "sh", cmd_buff, mode, -1, NULL)) != -1) {
135 fptr = _fdopen(fd, *mode == 'r' ? "rb" : "wb");
136 }
137
138 free(cmd_buff);
139 free(arg);
140
141 return fptr;
142}
143
144/*
145 * Open a pipe to a command.
146 *
147 * - mode may be "r", "w" or "b" for read-only, write-only or
148 * bidirectional (from the perspective of the parent).
149 * - if fd0 is a valid file descriptor it's used as input to the
150 * command ("r") or as the destination of the output from the
151 * command ("w"). Otherwise (and if not "b") use stdin or stdout.
152 * - the pid of the command is returned in the variable pid, which
153 * can be NULL if the pid is not required.
154 * - mode "w+" forces the use of an external program. This is required
155 * for xz and lzma compression.
156 */
157static int mingw_popen_internal(pipe_data *p, const char *exe,
158 const char *cmd, const char *mode, int fd0, pid_t *pid)
159{
160 pipe_data pd;
161 STARTUPINFO siStartInfo;
162 int success;
163 int fd = -1;
164 int ip, ic, flags;
165 char *freeme = NULL;
166
167 switch (*mode) {
168 case 'r':
169 ip = 0;
170 flags = _O_RDONLY|_O_BINARY;
171 break;
172 case 'w':
173 ip = 1;
174 flags = _O_WRONLY|_O_BINARY;
175 break;
176 case 'b':
177 ip = 1;
178 flags = _O_RDWR|_O_BINARY;
179 break;
180 default:
181 return -1;
182 }
183 ic = !ip;
184
185 if (!p) {
186 /* no struct provided, use a local one */
187 p = &pd;
188 }
189
190 /* Create the pipe */
191 if ( mingw_pipe(p, *mode == 'b') == -1 ) {
192 goto finito;
193 }
194
195#if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1
196 // "w+" mode forces a path lookup
197 if (mode[1] != '+' && find_applet_by_name(exe) >= 0) {
198 exe = bb_busybox_exec_path;
199 } else
200#endif
201 {
202 // Look up executable on PATH
203 freeme = find_first_executable(exe);
204 if (freeme == NULL)
205 bb_perror_msg_and_die("can't execute '%s'", exe);
206 exe = freeme;
207 }
208
209 /* Make the parent end of the pipe non-inheritable */
210 SetHandleInformation(p->pipe[ip], HANDLE_FLAG_INHERIT, 0);
211
212 /* Now create the child process */
213 ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
214 siStartInfo.cb = sizeof(STARTUPINFO);
215 /* default settings for a bidirectional pipe */
216 siStartInfo.hStdInput = p->pipe[ic];
217 siStartInfo.hStdOutput = p->pipe[ic];
218 /* override for read-only or write-only */
219 if ( *mode == 'r' ) {
220 siStartInfo.hStdInput = fd0 >= 0 ? (HANDLE)_get_osfhandle(fd0) :
221 GetStdHandle(STD_INPUT_HANDLE);
222 }
223 else if ( *mode == 'w' ) {
224 siStartInfo.hStdOutput = fd0 >= 0 ? (HANDLE)_get_osfhandle(fd0) :
225 GetStdHandle(STD_OUTPUT_HANDLE);
226 }
227 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
228 siStartInfo.wShowWindow = SW_HIDE;
229 siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
230
231 success = CreateProcess((LPCSTR)exe,
232 (LPSTR)cmd, /* command line */
233 NULL, /* process security attributes */
234 NULL, /* primary thread security attributes */
235 TRUE, /* handles are inherited */
236 0, /* creation flags */
237 NULL, /* use parent's environment */
238 NULL, /* use parent's current directory */
239 &siStartInfo, /* STARTUPINFO pointer */
240 &p->piProcInfo); /* receives PROCESS_INFORMATION */
241
242 if ( !success ) {
243 goto finito;
244 }
245
246 /* close child end of pipe */
247 CloseHandle(p->pipe[ic]);
248 p->pipe[ic] = INVALID_HANDLE_VALUE;
249
250 fd = _open_osfhandle((intptr_t)p->pipe[ip], flags);
251
252finito:
253 free(freeme);
254 if ( fd == -1 ) {
255 close_pipe_data(p);
256 }
257 else {
258 p->fd = fd;
259 if ( pid ) {
260 *pid = (pid_t)p->piProcInfo.dwProcessId;
261 }
262 }
263
264 return fd;
265}
266
267int mingw_popen_fd(const char *exe, const char *cmd, const char *mode,
268 int fd0, pid_t *pid)
269{
270 return mingw_popen_internal(NULL, exe, cmd, mode, fd0, pid);
271}
272
273int mingw_pclose(FILE *fp)
274{
275 int fd;
276 pipe_data *p;
277 DWORD ret;
278
279 /* find struct containing fd */
280 if (fp == NULL || (fd=fileno(fp)) == -1 || (p=find_pipe(fd)) == NULL)
281 return -1;
282
283 fclose(fp);
284
285 ret = WaitForSingleObject(p->piProcInfo.hProcess, INFINITE);
286
287 CloseHandle(p->piProcInfo.hProcess);
288 CloseHandle(p->piProcInfo.hThread);
289 close_pipe_data(p);
290
291 return (ret == WAIT_OBJECT_0) ? 0 : -1;
292}
293
294/* Used with mode "w" and a compressor when creating a compressed tar
295 * file; with mode "r" and a decompressor in open_transformer. */
296pid_t mingw_fork_compressor(int fd, const char *compressor, const char *mode)
297{
298 char *cmd;
299 int fd1;
300 pid_t pid;
301
302 cmd = xasprintf("%s -cf -", compressor);
303#if ENABLE_FEATURE_SEAMLESS_XZ || ENABLE_FEATURE_SEAMLESS_LZMA
304 // xz and lzma applets don't support compression, we must use
305 // an external command.
306 if (mode[0] == 'w' && index_in_strings("lzma\0xz\0", compressor) >= 0)
307 mode = "w+";
308#endif
309
310 if ((fd1 = mingw_popen_fd(compressor, cmd, mode, fd, &pid)) == -1)
311 bb_perror_msg_and_die("can't execute '%s'", compressor);
312
313 free(cmd);
314 xmove_fd(fd1, fd);
315 return pid;
316}
diff --git a/win32/process.c b/win32/process.c
new file mode 100644
index 000000000..e7c9ca187
--- /dev/null
+++ b/win32/process.c
@@ -0,0 +1,955 @@
1#include "libbb.h"
2#include <tlhelp32.h>
3#include <psapi.h>
4#include "lazyload.h"
5#include "NUM_APPLETS.h"
6
7pid_t waitpid(pid_t pid, int *status, int options)
8#if ENABLE_TIME
9{
10 return mingw_wait3(pid, status, options, NULL);
11}
12#endif
13
14#if ENABLE_TIME
15pid_t mingw_wait3(pid_t pid, int *status, int options, struct rusage *rusage)
16#endif
17{
18 HANDLE proc;
19 DWORD code;
20
21 /* Windows does not understand parent-child */
22 if (pid > 0 && options == 0) {
23 if ( (proc=OpenProcess(SYNCHRONIZE|PROCESS_QUERY_INFORMATION,
24 FALSE, pid)) != NULL ) {
25 WaitForSingleObject(proc, INFINITE);
26 GetExitCodeProcess(proc, &code);
27#if ENABLE_TIME
28 if (rusage != NULL) {
29 FILETIME crTime, exTime, keTime, usTime;
30
31 memset(rusage, 0, sizeof(*rusage));
32 if (GetProcessTimes(proc, &crTime, &exTime, &keTime, &usTime)) {
33 uint64_t kernel_usec =
34 (((uint64_t)keTime.dwHighDateTime << 32)
35 | (uint64_t)keTime.dwLowDateTime)/10;
36 uint64_t user_usec =
37 (((uint64_t)usTime.dwHighDateTime << 32)
38 | (uint64_t)usTime.dwLowDateTime)/10;
39
40 rusage->ru_utime.tv_sec = user_usec / 1000000U;
41 rusage->ru_utime.tv_usec = user_usec % 1000000U;
42 rusage->ru_stime.tv_sec = kernel_usec / 1000000U;
43 rusage->ru_stime.tv_usec = kernel_usec % 1000000U;
44 }
45 }
46#endif
47 CloseHandle(proc);
48 *status = exit_code_to_wait_status(code);
49 return pid;
50 }
51 }
52 errno = pid < 0 ? ENOSYS : EINVAL;
53 return -1;
54}
55
56int FAST_FUNC
57parse_interpreter(const char *cmd, interp_t *interp)
58{
59 char *path, *t;
60 int n;
61
62 while (TRUE) {
63 n = open_read_close(cmd, interp->buf, sizeof(interp->buf)-1);
64 if (n < 4) /* at least '#!/x' and not error */
65 break;
66
67 /*
68 * See http://www.in-ulm.de/~mascheck/various/shebang/ for trivia
69 * relating to '#!'. See also https://lwn.net/Articles/630727/
70 * for Linux-specific details.
71 */
72 if (interp->buf[0] != '#' || interp->buf[1] != '!')
73 break;
74 interp->buf[n] = '\0';
75 if ((t=strchr(interp->buf, '\n')) == NULL)
76 break;
77 t[1] = '\0';
78
79 if ((path=strtok(interp->buf+2, " \t\r\n")) == NULL)
80 break;
81
82 t = (char *)bb_basename(path);
83 if (*t == '\0')
84 break;
85
86 interp->path = path;
87 interp->name = t;
88 interp->opts = strtok(NULL, "\r\n");
89 /* Trim leading and trailing whitespace from the options.
90 * If the resulting string is empty return a NULL pointer. */
91 if (interp->opts && trim(interp->opts) == interp->opts)
92 interp->opts = NULL;
93 return 1;
94 }
95
96 if (n >= 0 && is_suffixed_with_case(cmd, ".sh")) {
97 interp->path = (char *)DEFAULT_SHELL;
98 interp->name = (char *)DEFAULT_SHELL_SHORT_NAME;
99 interp->opts = NULL;
100 return 1;
101 }
102 return 0;
103}
104
105/*
106 * See https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=vs-2019#parsing-c-command-line-arguments
107 * (Parsing C++ Command-Line Arguments)
108 */
109char * FAST_FUNC
110quote_arg(const char *arg)
111{
112 char *d, *r = xmalloc(2 * strlen(arg) + 3); // max-esc, quotes, \0
113 size_t nbs = 0; // consecutive backslashes before current char
114 int quoted = !*arg;
115
116 for (d = r; *arg; *d++ = *arg++) {
117 if (*arg == ' ' || *arg == '\t')
118 quoted = 1;
119
120 if (*arg == '\\' || *arg == '"')
121 *d++ = '\\';
122 else
123 d -= nbs; // undo nbs escapes, if any (not followed by DQ)
124
125 if (*arg == '\\')
126 ++nbs;
127 else
128 nbs = 0;
129 }
130
131 if (quoted) {
132 memmove(r + 1, r, d++ - r);
133 *r = *d++ = '"';
134 } else {
135 d -= nbs;
136 }
137
138 *d = 0;
139 return r;
140}
141
142char * FAST_FUNC
143find_first_executable(const char *name)
144{
145 const char *path = getenv("PATH");
146 return find_executable(name, &path);
147}
148
149static intptr_t
150spawnveq(int mode, const char *path, char *const *argv, char *const *env)
151{
152 char **new_argv;
153 char *new_path = NULL;
154 int i, argc;
155 intptr_t ret;
156 struct stat st;
157 size_t len = 0;
158
159 /*
160 * Require that the file exists, is a regular file and is executable.
161 * It may still contain garbage but we let spawnve deal with that.
162 */
163 if (stat(path, &st) == 0) {
164 if (!S_ISREG(st.st_mode) || !(st.st_mode&S_IXUSR)) {
165 errno = EACCES;
166 return -1;
167 }
168 }
169 else {
170 return -1;
171 }
172
173 argc = string_array_len((char **)argv);
174 new_argv = xzalloc(sizeof(*argv)*(argc+1));
175 for (i = 0; i < argc; i++) {
176 new_argv[i] = quote_arg(argv[i]);
177 len += strlen(new_argv[i]) + 1;
178 }
179
180 /* Special case: spawnve won't execute a batch file if the first
181 * argument is a relative path containing forward slashes. Absolute
182 * paths are fine but there's no harm in converting them too. */
183 if (has_bat_suffix(path)) {
184 slash_to_bs(new_argv[0]);
185
186 /* Another special case: spawnve returns ENOEXEC when passed an
187 * empty batch file. Pretend it worked. */
188 if (st.st_size == 0) {
189 ret = 0;
190 goto done;
191 }
192 }
193
194 /*
195 * Another special case: if a file doesn't have an extension add
196 * a '.' at the end. This forces spawnve to use precisely the
197 * file specified without trying to add an extension.
198 */
199 if (!strchr(bb_basename(path), '.')) {
200 new_path = xasprintf("%s.", path);
201 }
202
203 errno = 0;
204 ret = spawnve(mode, new_path ? new_path : path, new_argv, env);
205 if (errno == EINVAL && len > bb_arg_max())
206 errno = E2BIG;
207
208 done:
209 for (i = 0;i < argc;i++)
210 free(new_argv[i]);
211 free(new_argv);
212 free(new_path);
213
214 return ret;
215}
216
217#if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1
218static intptr_t
219mingw_spawn_applet(int mode,
220 char *const *argv,
221 char *const *envp)
222{
223 return spawnveq(mode, bb_busybox_exec_path, argv, envp);
224}
225#endif
226
227/* Make a copy of an argv array with n extra slots at the start */
228char ** FAST_FUNC
229grow_argv(char **argv, int n)
230{
231 char **new_argv;
232 int argc;
233
234 argc = string_array_len(argv) + 1;
235 new_argv = xmalloc(sizeof(*argv) * (argc + n));
236 memcpy(new_argv + n, argv, sizeof(*argv) * argc);
237 return new_argv;
238}
239
240#if ENABLE_FEATURE_HTTPD_CGI
241static int
242create_detached_process(const char *prog, char *const *argv)
243{
244 int argc, i;
245 char *command = NULL;
246 STARTUPINFO siStartInfo;
247 PROCESS_INFORMATION piProcInfo;
248 int success;
249
250 argc = string_array_len((char **)argv);
251 for (i = 0; i < argc; i++) {
252 char *qarg = quote_arg(argv[i]);
253 command = xappendword(command, qarg);
254 if (ENABLE_FEATURE_CLEAN_UP)
255 free(qarg);
256 }
257
258 ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
259 siStartInfo.cb = sizeof(STARTUPINFO);
260 siStartInfo.hStdInput = (HANDLE)_get_osfhandle(STDIN_FILENO);
261 siStartInfo.hStdOutput = (HANDLE)_get_osfhandle(STDOUT_FILENO);
262 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
263
264 success = CreateProcess((LPCSTR)prog,
265 (LPSTR)command, /* command line */
266 NULL, /* process security attributes */
267 NULL, /* primary thread security attributes */
268 TRUE, /* handles are inherited */
269 CREATE_NO_WINDOW, /* creation flags */
270 NULL, /* use parent's environment */
271 NULL, /* use parent's current directory */
272 &siStartInfo, /* STARTUPINFO pointer */
273 &piProcInfo); /* receives PROCESS_INFORMATION */
274
275 if (ENABLE_FEATURE_CLEAN_UP)
276 free(command);
277
278 if (!success)
279 return -1;
280 exit(0);
281}
282
283# define SPAWNVEQ(m, p, a, e) \
284 ((m != HTTPD_DETACH) ? spawnveq(m, p, a, e) : \
285 create_detached_process(p, a))
286#else
287# define SPAWNVEQ(m, p, a, e) spawnveq(m, p, a, e)
288#endif
289
290static intptr_t
291mingw_spawn_interpreter(int mode, const char *prog, char *const *argv,
292 char *const *envp, int level)
293{
294 intptr_t ret = -1;
295 int nopts;
296 interp_t interp;
297 char **new_argv;
298 char *path = NULL;
299 int is_unix_path;
300
301 if (!parse_interpreter(prog, &interp))
302 return SPAWNVEQ(mode, prog, argv, envp);
303
304 if (++level > 4) {
305 errno = ELOOP;
306 return -1;
307 }
308
309 nopts = interp.opts != NULL;
310 new_argv = grow_argv((char **)(argv + 1), nopts + 2);
311 new_argv[1] = interp.opts;
312 new_argv[nopts+1] = (char *)prog; /* pass absolute path */
313
314 is_unix_path = unix_path(interp.path);
315#if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1
316 if (is_unix_path && find_applet_by_name(interp.name) >= 0) {
317 /* the fake path indicates the index of the script */
318 new_argv[0] = path = xasprintf("%d:/%s", nopts+1, interp.name);
319 ret = SPAWNVEQ(mode, bb_busybox_exec_path, new_argv, envp);
320 goto done;
321 }
322#endif
323
324 path = file_is_win32_exe(interp.path);
325 if (!path && is_unix_path)
326 path = find_first_executable(interp.name);
327
328 if (path) {
329 new_argv[0] = path;
330 ret = mingw_spawn_interpreter(mode, path, new_argv, envp, level);
331 } else {
332 errno = ENOENT;
333 }
334 done:
335 free(path);
336 free(new_argv);
337 return ret;
338}
339
340static intptr_t
341mingw_spawnvp(int mode, const char *cmd, char *const *argv)
342{
343 char *path;
344 intptr_t ret;
345
346#if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1
347 if ((!has_path(cmd) || unix_path(cmd)) &&
348 find_applet_by_name(bb_basename(cmd)) >= 0)
349 return mingw_spawn_applet(mode, argv, NULL);
350#endif
351 if (has_path(cmd)) {
352 path = file_is_win32_exe(cmd);
353 if (path) {
354 ret = mingw_spawn_interpreter(mode, path, argv, NULL, 0);
355 free(path);
356 return ret;
357 }
358 if (unix_path(cmd))
359 cmd = bb_basename(cmd);
360 }
361
362 if (!has_path(cmd) && (path = find_first_executable(cmd)) != NULL) {
363 ret = mingw_spawn_interpreter(mode, path, argv, NULL, 0);
364 free(path);
365 return ret;
366 }
367
368 errno = ENOENT;
369 return -1;
370}
371
372pid_t FAST_FUNC
373mingw_spawn(char **argv)
374{
375 intptr_t ret;
376
377 ret = mingw_spawnvp(P_NOWAIT, argv[0], (char *const *)argv);
378
379 return ret == -1 ? (pid_t)-1 : (pid_t)GetProcessId((HANDLE)ret);
380}
381
382intptr_t FAST_FUNC
383mingw_spawn_detach(char **argv)
384{
385 return mingw_spawnvp(P_DETACH, argv[0], argv);
386}
387
388intptr_t FAST_FUNC
389mingw_spawn_proc(const char **argv)
390{
391 return mingw_spawnvp(P_NOWAIT, argv[0], (char *const *)argv);
392}
393
394BOOL WINAPI kill_child_ctrl_handler(DWORD dwCtrlType)
395{
396 static pid_t child_pid = 0;
397 DWORD dummy, *procs, count, rcount, i;
398 DECLARE_PROC_ADDR(DWORD, GetConsoleProcessList, LPDWORD, DWORD);
399
400 if (child_pid == 0) {
401 // First call sets child pid
402 child_pid = dwCtrlType;
403 return FALSE;
404 }
405
406 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
407 if (!INIT_PROC_ADDR(kernel32.dll, GetConsoleProcessList))
408 return TRUE;
409
410 count = GetConsoleProcessList(&dummy, 1) + 16;
411 procs = malloc(sizeof(DWORD) * count);
412 rcount = GetConsoleProcessList(procs, count);
413 if (rcount != 0 && rcount <= count) {
414 for (i = 0; i < rcount; i++) {
415 if (procs[i] == child_pid) {
416 // Child is attached to our console
417 break;
418 }
419 }
420 if (i == rcount) {
421 // Kill non-console child; console children can
422 // handle Ctrl-C as they see fit.
423 kill(-child_pid, SIGINT);
424 }
425 }
426 free(procs);
427 return TRUE;
428 }
429 return FALSE;
430}
431
432static int exit_code_to_wait_status_cmd(DWORD exit_code, const char *cmd)
433{
434 int sig, status;
435 DECLARE_PROC_ADDR(ULONG, RtlNtStatusToDosError, NTSTATUS);
436 DWORD flags, code;
437 char *msg = NULL;
438 const char *sep = ": ";
439
440 if (exit_code == 0xc0000005)
441 return SIGSEGV;
442 else if (exit_code == 0xc000013a)
443 return SIGINT;
444
445 // When a process is terminated as if by a signal the Windows
446 // exit code is zero apart from the signal in its topmost byte.
447 // This is a busybox-w32 convention.
448 sig = exit_code >> 24;
449 if (sig != 0 && exit_code == sig << 24 && is_valid_signal(sig))
450 return sig;
451
452 // The exit code may be an NTSTATUS code. Try to obtain a
453 // descriptive message for it.
454 if (exit_code > 0xff) {
455 flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM;
456 if (INIT_PROC_ADDR(ntdll.dll, RtlNtStatusToDosError)) {
457 code = RtlNtStatusToDosError(exit_code);
458 if (FormatMessage(flags, NULL, code, 0, (char *)&msg, 0, NULL)) {
459 char *cr = strrchr(msg, '\r');
460 if (cr) { // Replace CRLF with a space
461 cr[0] = ' ';
462 cr[1] = '\0';
463 }
464 }
465 }
466
467 if (!cmd)
468 cmd = sep = "";
469 bb_error_msg("%s%s%sError 0x%lx", cmd, sep, msg ?: "", exit_code);
470 LocalFree(msg);
471 }
472
473 // Use least significant byte as exit code, but not if it's zero
474 // and the Windows exit code as a whole is non-zero.
475 status = exit_code & 0xff;
476 if (exit_code != 0 && status == 0)
477 status = 255;
478 return status << 8;
479}
480
481static NORETURN void wait_for_child(HANDLE child, const char *cmd)
482{
483 DWORD code;
484 int status;
485
486 if (getppid() == 1)
487 exit(0);
488
489 kill_child_ctrl_handler(GetProcessId(child));
490 SetConsoleCtrlHandler(kill_child_ctrl_handler, TRUE);
491 WaitForSingleObject(child, INFINITE);
492 GetExitCodeProcess(child, &code);
493 // We don't need the wait status, but get it anyway so the error
494 // message can include the command. In such cases we pass the
495 // exit status to exit() so our caller won't repeat the message.
496 status = exit_code_to_wait_status_cmd(code, cmd);
497 if (!WIFSIGNALED(status) && code > 0xff)
498 code = WEXITSTATUS(status);
499 exit((int)code);
500}
501
502int
503mingw_execvp(const char *cmd, char *const *argv)
504{
505 intptr_t ret = mingw_spawnvp(P_NOWAIT, cmd, argv);
506 if (ret != -1)
507 wait_for_child((HANDLE)ret, cmd);
508 return ret;
509}
510
511int
512mingw_execve(const char *cmd, char *const *argv, char *const *envp)
513{
514 intptr_t ret = mingw_spawn_interpreter(P_NOWAIT, cmd, argv, envp, 0);
515 if (ret != -1)
516 wait_for_child((HANDLE)ret, cmd);
517 return ret;
518}
519
520int
521mingw_execv(const char *cmd, char *const *argv)
522{
523 return mingw_execve(cmd, argv, NULL);
524}
525
526#if ENABLE_FEATURE_HTTPD_CGI
527int httpd_execv_detach(const char *script, char *const *argv)
528{
529 intptr_t ret = mingw_spawn_interpreter(HTTPD_DETACH, script,
530 (char *const *)argv, NULL, 0);
531 if (ret != -1)
532 exit(0);
533 return ret;
534}
535#endif
536
537static inline long long filetime_to_ticks(const FILETIME *ft)
538{
539 return (((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime)/
540 HNSEC_PER_TICK;
541}
542
543/*
544 * Attempt to get a string from another instance of busybox.exe.
545 * This will only work if the other process is using the same binary
546 * as the current process. If anything goes wrong just give up.
547 */
548static char *get_bb_string(DWORD pid, const char *exe, char *string)
549{
550 HANDLE proc;
551 HMODULE mlist[32];
552 DWORD needed;
553 void *address;
554 char *my_base;
555 char buffer[128];
556 char exepath[PATH_MAX];
557 char *name = NULL;
558 int i;
559 DECLARE_PROC_ADDR(DWORD, GetProcessImageFileNameA, HANDLE,
560 LPSTR, DWORD);
561 DECLARE_PROC_ADDR(BOOL, EnumProcessModules, HANDLE, HMODULE *,
562 DWORD, LPDWORD);
563 DECLARE_PROC_ADDR(DWORD, GetModuleFileNameExA, HANDLE, HMODULE,
564 LPSTR, DWORD);
565
566 if (!INIT_PROC_ADDR(psapi.dll, GetProcessImageFileNameA) ||
567 !INIT_PROC_ADDR(psapi.dll, EnumProcessModules) ||
568 !INIT_PROC_ADDR(psapi.dll, GetModuleFileNameExA))
569 return NULL;
570
571 if (!(proc=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
572 FALSE, pid))) {
573 return NULL;
574 }
575
576 if (exe == NULL) {
577 if (GetProcessImageFileNameA(proc, exepath, PATH_MAX) != 0) {
578 exe = bb_basename(exepath);
579 }
580 }
581
582 /*
583 * Search for the module that matches the name of the executable.
584 * The values returned in mlist are actually the base address of
585 * the module in the other process (as noted in the documentation
586 * for the MODULEINFO structure).
587 */
588 if (!EnumProcessModules(proc, mlist, sizeof(mlist), &needed)) {
589 goto finish;
590 }
591
592 for (i=0; exe != NULL && i<needed/sizeof(HMODULE); ++i) {
593 char modname[MAX_PATH];
594 if (GetModuleFileNameExA(proc, mlist[i], modname, sizeof(modname))) {
595 if (strcasecmp(bb_basename(modname), exe) == 0) {
596 break;
597 }
598 }
599 }
600
601 if (i == needed/sizeof(HMODULE)) {
602 goto finish;
603 }
604
605 /* attempt to read the BusyBox version string */
606 my_base = (char *)GetModuleHandle(NULL);
607 address = (char *)mlist[i] + ((char *)bb_banner - my_base);
608 if (!ReadProcessMemory(proc, address, buffer, 128, NULL)) {
609 goto finish;
610 }
611
612 if (memcmp(buffer, bb_banner, strlen(bb_banner)) != 0) {
613 /* version mismatch (or not BusyBox at all) */
614 goto finish;
615 }
616
617 /* attempt to read the required string */
618 address = (char *)mlist[i] + ((char *)string - my_base);
619 if (!ReadProcessMemory(proc, address, buffer, 128, NULL)) {
620 goto finish;
621 }
622
623 buffer[127] = '\0';
624 name = auto_string(xstrdup(buffer));
625
626 finish:
627 CloseHandle(proc);
628 return name;
629}
630
631pid_t getppid(void)
632{
633 procps_status_t *sp = NULL;
634 int my_pid = getpid();
635
636 while ((sp = procps_scan(sp, 0)) != NULL) {
637 if (sp->pid == my_pid) {
638 return sp->ppid;
639 }
640 }
641 return 1;
642}
643
644#define NPIDS 128
645
646/* POSIX version in libbb/procps.c */
647procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags
648#if !ENABLE_FEATURE_PS_TIME && !ENABLE_FEATURE_PS_LONG
649UNUSED_PARAM
650#endif
651)
652{
653 PROCESSENTRY32 pe;
654 HANDLE proc;
655 const char *comm, *name;
656 BOOL ret;
657
658 pe.dwSize = sizeof(pe);
659 if (!sp) {
660 sp = xzalloc(sizeof(struct procps_status_t));
661 sp->snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
662 if (sp->snapshot == INVALID_HANDLE_VALUE) {
663 free(sp);
664 return NULL;
665 }
666 if (Process32First(sp->snapshot, &pe)) {
667 int maxpids = 0;
668 do {
669 if (sp->npids == maxpids) {
670 maxpids += NPIDS;
671 sp->pids = xrealloc(sp->pids, sizeof(DWORD) * maxpids);
672 }
673 sp->pids[sp->npids++] = pe.th32ProcessID;
674 } while (Process32Next(sp->snapshot, &pe));
675 }
676 ret = Process32First(sp->snapshot, &pe);
677 }
678 else {
679 ret = Process32Next(sp->snapshot, &pe);
680 }
681
682 if (!ret) {
683 CloseHandle(sp->snapshot);
684 free(sp->pids);
685 free(sp);
686 return NULL;
687 }
688
689 memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz));
690#if !ENABLE_DESKTOP
691 strcpy(sp->state, " ");
692#endif
693
694#if ENABLE_FEATURE_PS_TIME || ENABLE_FEATURE_PS_LONG
695 if (flags & (PSSCAN_STIME|PSSCAN_UTIME|PSSCAN_START_TIME)) {
696 FILETIME crTime, exTime, keTime, usTime;
697
698 if ((proc=OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,
699 FALSE, pe.th32ProcessID))) {
700 if (GetProcessTimes(proc, &crTime, &exTime, &keTime, &usTime)) {
701 long long ticks_since_boot, boot_time, create_time;
702 FILETIME now;
703
704 ticks_since_boot = GetTickCount64()/MS_PER_TICK;
705 GetSystemTimeAsFileTime(&now);
706 boot_time = filetime_to_ticks(&now) - ticks_since_boot;
707 create_time = filetime_to_ticks(&crTime);
708
709 sp->start_time = (unsigned long)(create_time - boot_time);
710 sp->stime = (unsigned long)filetime_to_ticks(&keTime);
711 sp->utime = (unsigned long)filetime_to_ticks(&usTime);
712 }
713 CloseHandle(proc);
714 }
715 }
716#endif
717
718 if (flags & PSSCAN_UIDGID) {
719 /* if we can open the process it belongs to us */
720 if ((proc=OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID))) {
721 sp->uid = DEFAULT_UID;
722 sp->gid = DEFAULT_GID;
723 CloseHandle(proc);
724 }
725 }
726
727 /* The parent of PID 0 is 0. If the parent is a PID we haven't
728 * seen set PPID to 1. */
729 sp->ppid = pe.th32ProcessID != 0;
730 for (int i = 0; i < sp->npids; ++i) {
731 if (sp->pids[i] == pe.th32ParentProcessID) {
732 sp->ppid = pe.th32ParentProcessID;
733 break;
734 }
735 }
736 sp->pid = pe.th32ProcessID;
737
738 if (flags & PSSCAN_COMM) {
739 if (sp->pid == getpid()) {
740 comm = applet_name;
741 }
742 else if ((name=get_bb_string(sp->pid, pe.szExeFile, bb_comm)) != NULL) {
743 comm = name;
744 }
745 else {
746 comm = pe.szExeFile;
747 }
748 safe_strncpy(sp->comm, comm, COMM_LEN);
749 }
750
751 return sp;
752}
753
754void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
755{
756 const char *str, *cmdline;
757
758 *buf = '\0';
759 if (pid == getpid())
760 cmdline = bb_command_line;
761 else if ((str=get_bb_string(pid, NULL, bb_command_line)) != NULL)
762 cmdline = str;
763 else
764 cmdline = comm;
765 safe_strncpy(buf, cmdline, col);
766}
767
768/**
769 * Determine whether a process runs in the same architecture as the current
770 * one. That test is required before we assume that GetProcAddress() returns
771 * a valid address *for the target process*.
772 */
773static inline int process_architecture_matches_current(HANDLE process)
774{
775 static BOOL current_is_wow = -1;
776 BOOL is_wow;
777
778 if (current_is_wow == -1 &&
779 !IsWow64Process (GetCurrentProcess(), &current_is_wow))
780 current_is_wow = -2;
781 if (current_is_wow == -2)
782 return 0; /* could not determine current process' WoW-ness */
783 if (!IsWow64Process (process, &is_wow))
784 return 0; /* cannot determine */
785 return is_wow == current_is_wow;
786}
787
788/**
789 * This function tries to terminate a Win32 process, as gently as possible,
790 * by injecting a thread that calls ExitProcess().
791 *
792 * Note: as kernel32.dll is loaded before any process, the other process and
793 * this process will have ExitProcess() at the same address.
794 *
795 * The idea comes from the Dr Dobb's article "A Safer Alternative to
796 * TerminateProcess()" by Andrew Tucker (July 1, 1999),
797 * http://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547
798 *
799 */
800static int kill_signal_by_handle(HANDLE process, int sig)
801{
802 DECLARE_PROC_ADDR(DWORD, ExitProcess, LPVOID);
803 PVOID arg = (PVOID)(intptr_t)(sig << 24);
804 DWORD thread_id;
805 HANDLE thread;
806
807 if (!INIT_PROC_ADDR(kernel32, ExitProcess) ||
808 !process_architecture_matches_current(process)) {
809 SetLastError(ERROR_ACCESS_DENIED);
810 return -1;
811 }
812
813 if (sig != 0 && (thread = CreateRemoteThread(process, NULL, 0,
814 ExitProcess, arg, 0, &thread_id))) {
815 CloseHandle(thread);
816 }
817 return 0;
818}
819
820static int kill_signal(pid_t pid, int sig)
821{
822 HANDLE process;
823 int ret = 0;
824 DWORD code, flags;
825
826 if (sig == SIGKILL)
827 flags = PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
828 else
829 flags = SYNCHRONIZE | PROCESS_CREATE_THREAD |
830 PROCESS_QUERY_INFORMATION |
831 PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
832 PROCESS_VM_READ;
833 process = OpenProcess(flags, FALSE, pid);
834
835 if (!process)
836 return -1;
837
838 if (!GetExitCodeProcess(process, &code) || code != STILL_ACTIVE) {
839 SetLastError(ERROR_INVALID_PARAMETER);
840 ret = -1;
841 } else if (sig == SIGKILL) {
842 /* This way of terminating processes is not gentle: they get no
843 * chance to clean up after themselves (closing file handles,
844 * removing .lock files, terminating spawned processes (if any),
845 * etc). */
846 ret = !TerminateProcess(process, SIGKILL << 24);
847 } else {
848 ret = kill_signal_by_handle(process, sig);
849 }
850 CloseHandle(process);
851
852 return ret;
853}
854
855/**
856 * If the process ID is positive signal that process only. If negative
857 * or zero signal all descendants of the indicated process. Zero
858 * indicates the current process; negative indicates the process with
859 * process ID -pid.
860 */
861int kill(pid_t pid, int sig)
862{
863 DWORD *pids;
864 int max_len, i, len, ret = 0;
865
866 if (!is_valid_signal(sig)) {
867 errno = EINVAL;
868 return -1;
869 }
870
871 max_len = NPIDS;
872 pids = xmalloc(sizeof(*pids) * max_len);
873
874 if(pid > 0)
875 pids[0] = (DWORD)pid;
876 else if (pid == 0)
877 pids[0] = (DWORD)getpid();
878 else
879 pids[0] = (DWORD)-pid;
880 len = 1;
881
882 /*
883 * Even if Process32First()/Process32Next() seem to traverse the
884 * processes in topological order (i.e. parent processes before
885 * child processes), there is nothing in the Win32 API documentation
886 * suggesting that this is guaranteed.
887 *
888 * Therefore, run through them at least twice and stop when no more
889 * process IDs were added to the list.
890 */
891 if (pid <= 0) {
892 HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
893 PROCESSENTRY32 entry;
894 int pid_added;
895
896 if (snapshot == INVALID_HANDLE_VALUE) {
897 errno = err_win_to_posix();
898 free(pids);
899 return -1;
900 }
901
902 entry.dwSize = sizeof(entry);
903 pid_added = TRUE;
904 while (pid_added && Process32First(snapshot, &entry)) {
905 pid_added = FALSE;
906
907 do {
908 for (i = len - 1; i >= 0; i--) {
909 if (pids[i] == entry.th32ProcessID)
910 break;
911 if (pids[i] == entry.th32ParentProcessID) {
912 if (len == max_len) {
913 max_len += NPIDS;
914 pids = xrealloc(pids, sizeof(*pids) * max_len);
915 }
916 pids[len++] = entry.th32ProcessID;
917 pid_added = TRUE;
918 }
919 }
920 } while (Process32Next(snapshot, &entry));
921 }
922
923 CloseHandle(snapshot);
924 }
925
926 for (i = len - 1; i >= 0; i--) {
927 SetLastError(0);
928 if (kill_signal(pids[i], sig)) {
929 errno = err_win_to_posix();
930 ret = -1;
931 }
932 }
933 free(pids);
934
935 return ret;
936}
937
938int FAST_FUNC is_valid_signal(int number)
939{
940 return isalpha(*get_signame(number));
941}
942
943int exit_code_to_wait_status(DWORD exit_code)
944{
945 return exit_code_to_wait_status_cmd(exit_code, NULL);
946}
947
948int exit_code_to_posix(DWORD exit_code)
949{
950 int status = exit_code_to_wait_status(exit_code);
951
952 if (WIFSIGNALED(status))
953 return 128 + WTERMSIG(status);
954 return WEXITSTATUS(status);
955}
diff --git a/win32/pwd.h b/win32/pwd.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/pwd.h
diff --git a/win32/regcomp.c b/win32/regcomp.c
new file mode 100644
index 000000000..e1692d341
--- /dev/null
+++ b/win32/regcomp.c
@@ -0,0 +1,3936 @@
1/* Extended regular expression matching and search library.
2 Copyright (C) 2002-2007,2009,2010 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA. */
20
21#include "match_class.h"
22
23#define UNUSED_PARAM __attribute__ ((__unused__))
24
25static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern,
26 size_t length, reg_syntax_t syntax);
27static void re_compile_fastmap_iter (regex_t *bufp,
28 const re_dfastate_t *init_state,
29 char *fastmap);
30static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len);
31#ifdef RE_ENABLE_I18N
32static void free_charset (re_charset_t *cset);
33#endif /* RE_ENABLE_I18N */
34static void free_workarea_compile (regex_t *preg);
35static reg_errcode_t create_initial_state (re_dfa_t *dfa);
36#ifdef RE_ENABLE_I18N
37static void optimize_utf8 (re_dfa_t *dfa);
38#endif
39static reg_errcode_t analyze (regex_t *preg);
40static reg_errcode_t preorder (bin_tree_t *root,
41 reg_errcode_t (fn (void *, bin_tree_t *)),
42 void *extra);
43static reg_errcode_t postorder (bin_tree_t *root,
44 reg_errcode_t (fn (void *, bin_tree_t *)),
45 void *extra);
46static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node);
47static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node);
48static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg,
49 bin_tree_t *node);
50static reg_errcode_t calc_first (void *extra, bin_tree_t *node);
51static reg_errcode_t calc_next (void *extra, bin_tree_t *node);
52static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node);
53static int duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint);
54static int search_duplicated_node (const re_dfa_t *dfa, int org_node,
55 unsigned int constraint);
56static reg_errcode_t calc_eclosure (re_dfa_t *dfa);
57static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa,
58 int node, int root);
59static reg_errcode_t calc_inveclosure (re_dfa_t *dfa);
60static int fetch_number (re_string_t *input, re_token_t *token,
61 reg_syntax_t syntax);
62static int peek_token (re_token_t *token, re_string_t *input,
63 reg_syntax_t syntax) internal_function;
64static bin_tree_t *parse (re_string_t *regexp, regex_t *preg,
65 reg_syntax_t syntax, reg_errcode_t *err);
66static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg,
67 re_token_t *token, reg_syntax_t syntax,
68 int nest, reg_errcode_t *err);
69static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg,
70 re_token_t *token, reg_syntax_t syntax,
71 int nest, reg_errcode_t *err);
72static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg,
73 re_token_t *token, reg_syntax_t syntax,
74 int nest, reg_errcode_t *err);
75static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg,
76 re_token_t *token, reg_syntax_t syntax,
77 int nest, reg_errcode_t *err);
78static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp,
79 re_dfa_t *dfa, re_token_t *token,
80 reg_syntax_t syntax, reg_errcode_t *err);
81static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa,
82 re_token_t *token, reg_syntax_t syntax,
83 reg_errcode_t *err);
84static reg_errcode_t parse_bracket_element (bracket_elem_t *elem,
85 re_string_t *regexp,
86 re_token_t *token, int token_len,
87 re_dfa_t *dfa,
88 reg_syntax_t syntax,
89 int accept_hyphen);
90static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem,
91 re_string_t *regexp,
92 re_token_t *token);
93#ifdef RE_ENABLE_I18N
94static reg_errcode_t build_equiv_class (bitset_t sbcset,
95 re_charset_t *mbcset,
96 int *equiv_class_alloc,
97 const unsigned char *name);
98static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
99 bitset_t sbcset,
100 re_charset_t *mbcset,
101 int *char_class_alloc,
102 const char *class_name,
103 reg_syntax_t syntax);
104#else /* not RE_ENABLE_I18N */
105static reg_errcode_t build_equiv_class (bitset_t sbcset,
106 const unsigned char *name);
107static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
108 bitset_t sbcset,
109 const char *class_name,
110 reg_syntax_t syntax);
111#endif /* not RE_ENABLE_I18N */
112static bin_tree_t *build_charclass_op (re_dfa_t *dfa,
113 RE_TRANSLATE_TYPE trans,
114 const char *class_name,
115 const char *extra,
116 int non_match, reg_errcode_t *err);
117static bin_tree_t *create_tree (re_dfa_t *dfa,
118 bin_tree_t *left, bin_tree_t *right,
119 re_token_type_t type);
120static bin_tree_t *create_token_tree (re_dfa_t *dfa,
121 bin_tree_t *left, bin_tree_t *right,
122 const re_token_t *token);
123static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa);
124static void free_token (re_token_t *node);
125static reg_errcode_t free_tree (void *extra, bin_tree_t *node);
126static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node);
127
128/* This table gives an error message for each of the error codes listed
129 in regex.h. Obviously the order here has to be same as there.
130 POSIX doesn't require that we do anything for REG_NOERROR,
131 but why not be nice? */
132
133const char __re_error_msgid[] attribute_hidden =
134 {
135#define REG_NOERROR_IDX 0
136 gettext_noop ("Success") /* REG_NOERROR */
137 "\0"
138#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success")
139 gettext_noop ("No match") /* REG_NOMATCH */
140 "\0"
141#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match")
142 gettext_noop ("Invalid regular expression") /* REG_BADPAT */
143 "\0"
144#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression")
145 gettext_noop ("Invalid collation character") /* REG_ECOLLATE */
146 "\0"
147#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character")
148 gettext_noop ("Invalid character class name") /* REG_ECTYPE */
149 "\0"
150#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name")
151 gettext_noop ("Trailing backslash") /* REG_EESCAPE */
152 "\0"
153#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash")
154 gettext_noop ("Invalid back reference") /* REG_ESUBREG */
155 "\0"
156#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference")
157 gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */
158 "\0"
159#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^")
160 gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */
161 "\0"
162#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(")
163 gettext_noop ("Unmatched \\{") /* REG_EBRACE */
164 "\0"
165#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{")
166 gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */
167 "\0"
168#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}")
169 gettext_noop ("Invalid range end") /* REG_ERANGE */
170 "\0"
171#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end")
172 gettext_noop ("Memory exhausted") /* REG_ESPACE */
173 "\0"
174#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted")
175 gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */
176 "\0"
177#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression")
178 gettext_noop ("Premature end of regular expression") /* REG_EEND */
179 "\0"
180#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression")
181 gettext_noop ("Regular expression too big") /* REG_ESIZE */
182 "\0"
183#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big")
184 gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */
185 };
186
187const size_t __re_error_msgid_idx[] attribute_hidden =
188 {
189 REG_NOERROR_IDX,
190 REG_NOMATCH_IDX,
191 REG_BADPAT_IDX,
192 REG_ECOLLATE_IDX,
193 REG_ECTYPE_IDX,
194 REG_EESCAPE_IDX,
195 REG_ESUBREG_IDX,
196 REG_EBRACK_IDX,
197 REG_EPAREN_IDX,
198 REG_EBRACE_IDX,
199 REG_BADBR_IDX,
200 REG_ERANGE_IDX,
201 REG_ESPACE_IDX,
202 REG_BADRPT_IDX,
203 REG_EEND_IDX,
204 REG_ESIZE_IDX,
205 REG_ERPAREN_IDX
206 };
207
208/* Entry points for GNU code. */
209
210
211#ifdef ZOS_USS
212
213/* For ZOS USS we must define btowc */
214
215wchar_t
216btowc (int c)
217{
218 wchar_t wtmp[2];
219 char tmp[2];
220
221 tmp[0] = c;
222 tmp[1] = 0;
223
224 mbtowc (wtmp, tmp, 1);
225 return wtmp[0];
226}
227#endif
228
229/* re_compile_pattern is the GNU regular expression compiler: it
230 compiles PATTERN (of length LENGTH) and puts the result in BUFP.
231 Returns 0 if the pattern was valid, otherwise an error string.
232
233 Assumes the `allocated' (and perhaps `buffer') and `translate' fields
234 are set in BUFP on entry. */
235
236const char *
237re_compile_pattern (const char *pattern,
238 size_t length,
239 struct re_pattern_buffer *bufp)
240{
241 reg_errcode_t ret;
242
243 /* And GNU code determines whether or not to get register information
244 by passing null for the REGS argument to re_match, etc., not by
245 setting no_sub, unless RE_NO_SUB is set. */
246 bufp->no_sub = !!(re_syntax_options & RE_NO_SUB);
247
248 /* Match anchors at newline. */
249 bufp->newline_anchor = 1;
250
251 ret = re_compile_internal (bufp, pattern, length, re_syntax_options);
252
253 if (!ret)
254 return NULL;
255 return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
256}
257#ifdef _LIBC
258weak_alias (__re_compile_pattern, re_compile_pattern)
259#endif
260
261/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
262 also be assigned to arbitrarily: each pattern buffer stores its own
263 syntax, so it can be changed between regex compilations. */
264/* This has no initializer because initialized variables in Emacs
265 become read-only after dumping. */
266reg_syntax_t re_syntax_options;
267
268
269/* Specify the precise syntax of regexps for compilation. This provides
270 for compatibility for various utilities which historically have
271 different, incompatible syntaxes.
272
273 The argument SYNTAX is a bit mask comprised of the various bits
274 defined in regex.h. We return the old syntax. */
275
276reg_syntax_t
277re_set_syntax (reg_syntax_t syntax)
278{
279 reg_syntax_t ret = re_syntax_options;
280
281 re_syntax_options = syntax;
282 return ret;
283}
284#ifdef _LIBC
285weak_alias (__re_set_syntax, re_set_syntax)
286#endif
287
288int
289re_compile_fastmap (struct re_pattern_buffer *bufp)
290{
291 re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
292 char *fastmap = bufp->fastmap;
293
294 memset (fastmap, '\0', sizeof (char) * SBC_MAX);
295 re_compile_fastmap_iter (bufp, dfa->init_state, fastmap);
296 if (dfa->init_state != dfa->init_state_word)
297 re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap);
298 if (dfa->init_state != dfa->init_state_nl)
299 re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap);
300 if (dfa->init_state != dfa->init_state_begbuf)
301 re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap);
302 bufp->fastmap_accurate = 1;
303 return 0;
304}
305#ifdef _LIBC
306weak_alias (__re_compile_fastmap, re_compile_fastmap)
307#endif
308
309static inline void
310__attribute ((always_inline))
311re_set_fastmap (char *fastmap, int icase, int ch)
312{
313 fastmap[ch] = 1;
314 if (icase)
315 fastmap[tolower (ch)] = 1;
316}
317
318/* Helper function for re_compile_fastmap.
319 Compile fastmap for the initial_state INIT_STATE. */
320
321static void
322re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state,
323 char *fastmap)
324{
325 volatile re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
326 int node_cnt;
327 int icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE));
328 for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt)
329 {
330 int node = init_state->nodes.elems[node_cnt];
331 re_token_type_t type = dfa->nodes[node].type;
332
333 if (type == CHARACTER)
334 {
335 re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c);
336#ifdef RE_ENABLE_I18N
337 if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
338 {
339 unsigned char *buf = re_malloc (unsigned char, dfa->mb_cur_max), *p;
340 wchar_t wc;
341 mbstate_t state;
342
343 p = buf;
344 *p++ = dfa->nodes[node].opr.c;
345 while (++node < dfa->nodes_len
346 && dfa->nodes[node].type == CHARACTER
347 && dfa->nodes[node].mb_partial)
348 *p++ = dfa->nodes[node].opr.c;
349 memset (&state, '\0', sizeof (state));
350 if (__mbrtowc (&wc, (const char *) buf, p - buf,
351 &state) == p - buf
352 && (__wcrtomb ((char *) buf, towlower (wc), &state)
353 != (size_t) -1))
354 re_set_fastmap (fastmap, 0, buf[0]);
355 re_free (buf);
356 }
357#endif
358 }
359 else if (type == SIMPLE_BRACKET)
360 {
361 int i, ch;
362 for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
363 {
364 int j;
365 bitset_word_t w = dfa->nodes[node].opr.sbcset[i];
366 for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
367 if (w & ((bitset_word_t) 1 << j))
368 re_set_fastmap (fastmap, icase, ch);
369 }
370 }
371#ifdef RE_ENABLE_I18N
372 else if (type == COMPLEX_BRACKET)
373 {
374 re_charset_t *cset = dfa->nodes[node].opr.mbcset;
375 int i;
376
377# ifdef _LIBC
378 /* See if we have to try all bytes which start multiple collation
379 elements.
380 e.g. In da_DK, we want to catch 'a' since "aa" is a valid
381 collation element, and don't catch 'b' since 'b' is
382 the only collation element which starts from 'b' (and
383 it is caught by SIMPLE_BRACKET). */
384 if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0
385 && (cset->ncoll_syms || cset->nranges))
386 {
387 const int32_t *table = (const int32_t *)
388 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
389 for (i = 0; i < SBC_MAX; ++i)
390 if (table[i] < 0)
391 re_set_fastmap (fastmap, icase, i);
392 }
393# endif /* _LIBC */
394
395 /* See if we have to start the match at all multibyte characters,
396 i.e. where we would not find an invalid sequence. This only
397 applies to multibyte character sets; for single byte character
398 sets, the SIMPLE_BRACKET again suffices. */
399 if (dfa->mb_cur_max > 1
400 && (cset->nchar_classes || cset->non_match || cset->nranges
401# ifdef _LIBC
402 || cset->nequiv_classes
403# endif /* _LIBC */
404 ))
405 {
406 unsigned char c = 0;
407 do
408 {
409 mbstate_t mbs;
410 memset (&mbs, 0, sizeof (mbs));
411 if (__mbrtowc (NULL, (char *) &c, 1, &mbs) == (size_t) -2)
412 re_set_fastmap (fastmap, false, (int) c);
413 }
414 while (++c != 0);
415 }
416
417 else
418 {
419 /* ... Else catch all bytes which can start the mbchars. */
420 for (i = 0; i < cset->nmbchars; ++i)
421 {
422 char buf[256];
423 mbstate_t state;
424 memset (&state, '\0', sizeof (state));
425 if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1)
426 re_set_fastmap (fastmap, icase, *(unsigned char *) buf);
427 if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
428 {
429 if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state)
430 != (size_t) -1)
431 re_set_fastmap (fastmap, false, *(unsigned char *) buf);
432 }
433 }
434 }
435 }
436#endif /* RE_ENABLE_I18N */
437 else if (type == OP_PERIOD
438#ifdef RE_ENABLE_I18N
439 || type == OP_UTF8_PERIOD
440#endif /* RE_ENABLE_I18N */
441 || type == END_OF_RE)
442 {
443 memset (fastmap, '\1', sizeof (char) * SBC_MAX);
444 if (type == END_OF_RE)
445 bufp->can_be_null = 1;
446 return;
447 }
448 }
449}
450
451/* Entry point for POSIX code. */
452/* regcomp takes a regular expression as a string and compiles it.
453
454 PREG is a regex_t *. We do not expect any fields to be initialized,
455 since POSIX says we shouldn't. Thus, we set
456
457 `buffer' to the compiled pattern;
458 `used' to the length of the compiled pattern;
459 `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
460 REG_EXTENDED bit in CFLAGS is set; otherwise, to
461 RE_SYNTAX_POSIX_BASIC;
462 `newline_anchor' to REG_NEWLINE being set in CFLAGS;
463 `fastmap' to an allocated space for the fastmap;
464 `fastmap_accurate' to zero;
465 `re_nsub' to the number of subexpressions in PATTERN.
466
467 PATTERN is the address of the pattern string.
468
469 CFLAGS is a series of bits which affect compilation.
470
471 If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
472 use POSIX basic syntax.
473
474 If REG_NEWLINE is set, then . and [^...] don't match newline.
475 Also, regexec will try a match beginning after every newline.
476
477 If REG_ICASE is set, then we considers upper- and lowercase
478 versions of letters to be equivalent when matching.
479
480 If REG_NOSUB is set, then when PREG is passed to regexec, that
481 routine will report only success or failure, and nothing about the
482 registers.
483
484 It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
485 the return codes and their meanings.) */
486
487int
488regcomp (regex_t *__restrict preg,
489 const char *__restrict pattern,
490 int cflags)
491{
492 reg_errcode_t ret;
493 reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED
494 : RE_SYNTAX_POSIX_BASIC);
495
496 preg->buffer = NULL;
497 preg->allocated = 0;
498 preg->used = 0;
499
500 /* Try to allocate space for the fastmap. */
501 preg->fastmap = re_malloc (char, SBC_MAX);
502 if (BE (preg->fastmap == NULL, 0))
503 return REG_ESPACE;
504
505 syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0;
506
507 /* If REG_NEWLINE is set, newlines are treated differently. */
508 if (cflags & REG_NEWLINE)
509 { /* REG_NEWLINE implies neither . nor [^...] match newline. */
510 syntax &= ~RE_DOT_NEWLINE;
511 syntax |= RE_HAT_LISTS_NOT_NEWLINE;
512 /* It also changes the matching behavior. */
513 preg->newline_anchor = 1;
514 }
515 else
516 preg->newline_anchor = 0;
517 preg->no_sub = !!(cflags & REG_NOSUB);
518 preg->translate = NULL;
519
520 ret = re_compile_internal (preg, pattern, strlen (pattern), syntax);
521
522 /* POSIX doesn't distinguish between an unmatched open-group and an
523 unmatched close-group: both are REG_EPAREN. */
524 if (ret == REG_ERPAREN)
525 ret = REG_EPAREN;
526
527 /* We have already checked preg->fastmap != NULL. */
528 if (BE (ret == REG_NOERROR, 1))
529 /* Compute the fastmap now, since regexec cannot modify the pattern
530 buffer. This function never fails in this implementation. */
531 (void) re_compile_fastmap (preg);
532 else
533 {
534 /* Some error occurred while compiling the expression. */
535 re_free (preg->fastmap);
536 preg->fastmap = NULL;
537 }
538
539 return (int) ret;
540}
541#ifdef _LIBC
542weak_alias (__regcomp, regcomp)
543#endif
544
545/* Returns a message corresponding to an error code, ERRCODE, returned
546 from either regcomp or regexec. We don't use PREG here. */
547
548size_t
549regerror(int errcode, UNUSED_PARAM const regex_t *__restrict preg,
550 char *__restrict errbuf, size_t errbuf_size)
551{
552 const char *msg;
553 size_t msg_size;
554
555 if (BE (errcode < 0
556 || errcode >= (int) (sizeof (__re_error_msgid_idx)
557 / sizeof (__re_error_msgid_idx[0])), 0))
558 /* Only error codes returned by the rest of the code should be passed
559 to this routine. If we are given anything else, or if other regex
560 code generates an invalid error code, then the program has a bug.
561 Dump core so we can fix it. */
562 abort ();
563
564 msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]);
565
566 msg_size = strlen (msg) + 1; /* Includes the null. */
567
568 if (BE (errbuf_size != 0, 1))
569 {
570 if (BE (msg_size > errbuf_size, 0))
571 {
572 memcpy (errbuf, msg, errbuf_size - 1);
573 errbuf[errbuf_size - 1] = 0;
574 }
575 else
576 memcpy (errbuf, msg, msg_size);
577 }
578
579 return msg_size;
580}
581#ifdef _LIBC
582weak_alias (__regerror, regerror)
583#endif
584
585
586#ifdef RE_ENABLE_I18N
587/* This static array is used for the map to single-byte characters when
588 UTF-8 is used. Otherwise we would allocate memory just to initialize
589 it the same all the time. UTF-8 is the preferred encoding so this is
590 a worthwhile optimization. */
591#if __GNUC__ >= 3
592static const bitset_t utf8_sb_map = {
593 /* Set the first 128 bits. */
594 [0 ... 0x80 / BITSET_WORD_BITS - 1] = BITSET_WORD_MAX
595};
596#else /* ! (__GNUC__ >= 3) */
597static bitset_t utf8_sb_map;
598#endif /* __GNUC__ >= 3 */
599#endif /* RE_ENABLE_I18N */
600
601
602static void
603free_dfa_content (re_dfa_t *dfa)
604{
605 int i, j;
606
607 if (dfa->nodes)
608 for (i = 0; i < dfa->nodes_len; ++i)
609 free_token (dfa->nodes + i);
610 re_free (dfa->nexts);
611 for (i = 0; i < dfa->nodes_len; ++i)
612 {
613 if (dfa->eclosures != NULL)
614 re_node_set_free (dfa->eclosures + i);
615 if (dfa->inveclosures != NULL)
616 re_node_set_free (dfa->inveclosures + i);
617 if (dfa->edests != NULL)
618 re_node_set_free (dfa->edests + i);
619 }
620 re_free (dfa->edests);
621 re_free (dfa->eclosures);
622 re_free (dfa->inveclosures);
623 re_free (dfa->nodes);
624
625 if (dfa->state_table)
626 for (i = 0; i <= dfa->state_hash_mask; ++i)
627 {
628 struct re_state_table_entry *entry = dfa->state_table + i;
629 for (j = 0; j < entry->num; ++j)
630 {
631 re_dfastate_t *state = entry->array[j];
632 free_state (state);
633 }
634 re_free (entry->array);
635 }
636 re_free (dfa->state_table);
637#ifdef RE_ENABLE_I18N
638 if (dfa->sb_char != utf8_sb_map)
639 re_free (dfa->sb_char);
640#endif
641 re_free (dfa->subexp_map);
642#ifdef DEBUG
643 re_free (dfa->re_str);
644#endif
645
646 re_free (dfa);
647}
648
649
650/* Free dynamically allocated space used by PREG. */
651
652void
653regfree (regex_t *preg)
654{
655 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
656 if (BE (dfa != NULL, 1))
657 free_dfa_content (dfa);
658 preg->buffer = NULL;
659 preg->allocated = 0;
660
661 re_free (preg->fastmap);
662 preg->fastmap = NULL;
663
664 re_free (preg->translate);
665 preg->translate = NULL;
666}
667#ifdef _LIBC
668weak_alias (__regfree, regfree)
669#endif
670
671/* Entry points compatible with 4.2 BSD regex library. We don't define
672 them unless specifically requested. */
673
674#if defined _REGEX_RE_COMP || defined _LIBC
675
676/* BSD has one and only one pattern buffer. */
677static struct re_pattern_buffer re_comp_buf;
678
679char *
680# ifdef _LIBC
681/* Make these definitions weak in libc, so POSIX programs can redefine
682 these names if they don't use our functions, and still use
683 regcomp/regexec above without link errors. */
684weak_function
685# endif
686re_comp (s)
687 const char *s;
688{
689 reg_errcode_t ret;
690 char *fastmap;
691
692 if (!s)
693 {
694 if (!re_comp_buf.buffer)
695 return gettext ("No previous regular expression");
696 return 0;
697 }
698
699 if (re_comp_buf.buffer)
700 {
701 fastmap = re_comp_buf.fastmap;
702 re_comp_buf.fastmap = NULL;
703 __regfree (&re_comp_buf);
704 memset (&re_comp_buf, '\0', sizeof (re_comp_buf));
705 re_comp_buf.fastmap = fastmap;
706 }
707
708 if (re_comp_buf.fastmap == NULL)
709 {
710 re_comp_buf.fastmap = (char *) malloc (SBC_MAX);
711 if (re_comp_buf.fastmap == NULL)
712 return (char *) gettext (__re_error_msgid
713 + __re_error_msgid_idx[(int) REG_ESPACE]);
714 }
715
716 /* Since `re_exec' always passes NULL for the `regs' argument, we
717 don't need to initialize the pattern buffer fields which affect it. */
718
719 /* Match anchors at newlines. */
720 re_comp_buf.newline_anchor = 1;
721
722 ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options);
723
724 if (!ret)
725 return NULL;
726
727 /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */
728 return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
729}
730
731#ifdef _LIBC
732libc_freeres_fn (free_mem)
733{
734 __regfree (&re_comp_buf);
735}
736#endif
737
738#endif /* _REGEX_RE_COMP */
739
740/* Internal entry point.
741 Compile the regular expression PATTERN, whose length is LENGTH.
742 SYNTAX indicate regular expression's syntax. */
743
744static reg_errcode_t
745re_compile_internal (regex_t *preg, const char * pattern, size_t length,
746 reg_syntax_t syntax)
747{
748 reg_errcode_t err = REG_NOERROR;
749 re_dfa_t *dfa;
750 re_string_t regexp;
751
752 /* Initialize the pattern buffer. */
753 preg->fastmap_accurate = 0;
754 preg->syntax = syntax;
755 preg->not_bol = preg->not_eol = 0;
756 preg->used = 0;
757 preg->re_nsub = 0;
758 preg->can_be_null = 0;
759 preg->regs_allocated = REGS_UNALLOCATED;
760
761 /* Initialize the dfa. */
762 dfa = (re_dfa_t *) preg->buffer;
763 if (BE (preg->allocated < sizeof (re_dfa_t), 0))
764 {
765 /* If zero allocated, but buffer is non-null, try to realloc
766 enough space. This loses if buffer's address is bogus, but
767 that is the user's responsibility. If ->buffer is NULL this
768 is a simple allocation. */
769 dfa = re_realloc (preg->buffer, re_dfa_t, 1);
770 if (dfa == NULL)
771 return REG_ESPACE;
772 preg->allocated = sizeof (re_dfa_t);
773 preg->buffer = (unsigned char *) dfa;
774 }
775 preg->used = sizeof (re_dfa_t);
776
777 err = init_dfa (dfa, length);
778 if (BE (err != REG_NOERROR, 0))
779 {
780 free_dfa_content (dfa);
781 preg->buffer = NULL;
782 preg->allocated = 0;
783 return err;
784 }
785#ifdef DEBUG
786 /* Note: length+1 will not overflow since it is checked in init_dfa. */
787 dfa->re_str = re_malloc (char, length + 1);
788 strncpy (dfa->re_str, pattern, length + 1);
789#endif
790
791 __libc_lock_init (dfa->lock);
792
793 err = re_string_construct (&regexp, pattern, length, preg->translate,
794 syntax & RE_ICASE, dfa);
795 if (BE (err != REG_NOERROR, 0))
796 {
797 re_compile_internal_free_return:
798 free_workarea_compile (preg);
799 re_string_destruct (&regexp);
800 free_dfa_content (dfa);
801 preg->buffer = NULL;
802 preg->allocated = 0;
803 return err;
804 }
805
806 /* Parse the regular expression, and build a structure tree. */
807 preg->re_nsub = 0;
808 dfa->str_tree = parse (&regexp, preg, syntax, &err);
809 if (BE (dfa->str_tree == NULL, 0))
810 goto re_compile_internal_free_return;
811
812 /* Analyze the tree and create the nfa. */
813 err = analyze (preg);
814 if (BE (err != REG_NOERROR, 0))
815 goto re_compile_internal_free_return;
816
817#ifdef RE_ENABLE_I18N
818 /* If possible, do searching in single byte encoding to speed things up. */
819 if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate == NULL)
820 optimize_utf8 (dfa);
821#endif
822
823 /* Then create the initial state of the dfa. */
824 err = create_initial_state (dfa);
825
826 /* Release work areas. */
827 free_workarea_compile (preg);
828 re_string_destruct (&regexp);
829
830 if (BE (err != REG_NOERROR, 0))
831 {
832 free_dfa_content (dfa);
833 preg->buffer = NULL;
834 preg->allocated = 0;
835 }
836
837 return err;
838}
839
840/* Initialize DFA. We use the length of the regular expression PAT_LEN
841 as the initial length of some arrays. */
842
843static reg_errcode_t
844init_dfa (re_dfa_t *dfa, size_t pat_len)
845{
846 unsigned int table_size;
847#ifndef _LIBC
848 const char *codeset_name;
849#endif
850
851 memset (dfa, '\0', sizeof (re_dfa_t));
852
853 /* Force allocation of str_tree_storage the first time. */
854 dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
855
856 /* Avoid overflows. */
857 if (pat_len == SIZE_MAX)
858 return REG_ESPACE;
859
860 dfa->nodes_alloc = pat_len + 1;
861 dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc);
862
863 /* table_size = 2 ^ ceil(log pat_len) */
864 for (table_size = 1; ; table_size <<= 1)
865 if (table_size > pat_len)
866 break;
867
868 dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size);
869 dfa->state_hash_mask = table_size - 1;
870
871 dfa->mb_cur_max = MB_CUR_MAX;
872#ifdef _LIBC
873 if (dfa->mb_cur_max == 6
874 && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0)
875 dfa->is_utf8 = 1;
876 dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII)
877 != 0);
878#else
879# ifdef HAVE_LANGINFO_CODESET
880 codeset_name = nl_langinfo (CODESET);
881# else
882 codeset_name = getenv ("LC_ALL");
883 if (codeset_name == NULL || codeset_name[0] == '\0')
884 codeset_name = getenv ("LC_CTYPE");
885 if (codeset_name == NULL || codeset_name[0] == '\0')
886 codeset_name = getenv ("LANG");
887 if (codeset_name == NULL)
888 codeset_name = "";
889 else if (strchr (codeset_name, '.') != NULL)
890 codeset_name = strchr (codeset_name, '.') + 1;
891# endif
892
893 /* strcasecmp isn't a standard interface. brute force check */
894#if 0
895 if (strcasecmp (codeset_name, "UTF-8") == 0
896 || strcasecmp (codeset_name, "UTF8") == 0)
897 dfa->is_utf8 = 1;
898#else
899 if ( (codeset_name[0] == 'U' || codeset_name[0] == 'u')
900 && (codeset_name[1] == 'T' || codeset_name[1] == 't')
901 && (codeset_name[2] == 'F' || codeset_name[2] == 'f')
902 && (codeset_name[3] == '-'
903 ? codeset_name[4] == '8' && codeset_name[5] == '\0'
904 : codeset_name[3] == '8' && codeset_name[4] == '\0'))
905 dfa->is_utf8 = 1;
906#endif
907
908 /* We check exhaustively in the loop below if this charset is a
909 superset of ASCII. */
910 dfa->map_notascii = 0;
911#endif
912
913#ifdef RE_ENABLE_I18N
914 if (dfa->mb_cur_max > 1)
915 {
916 if (dfa->is_utf8)
917 {
918#if !defined(__GNUC__) || __GNUC__ < 3
919 static short utf8_sb_map_inited = 0;
920
921 if (! utf8_sb_map_inited)
922 {
923 int i;
924
925 utf8_sb_map_inited = 0;
926 for (i = 0; i <= 0x80 / BITSET_WORD_BITS - 1; i++)
927 utf8_sb_map[i] = BITSET_WORD_MAX;
928 }
929#endif
930 dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map;
931 }
932 else
933 {
934 int i, j, ch;
935
936 dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
937 if (BE (dfa->sb_char == NULL, 0))
938 return REG_ESPACE;
939
940 /* Set the bits corresponding to single byte chars. */
941 for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
942 for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
943 {
944 wint_t wch = __btowc (ch);
945 if (wch != WEOF)
946 dfa->sb_char[i] |= (bitset_word_t) 1 << j;
947# ifndef _LIBC
948 if (isascii (ch) && wch != ch)
949 dfa->map_notascii = 1;
950# endif
951 }
952 }
953 }
954#endif
955
956 if (BE (dfa->nodes == NULL || dfa->state_table == NULL, 0))
957 return REG_ESPACE;
958 return REG_NOERROR;
959}
960
961/* Initialize WORD_CHAR table, which indicate which character is
962 "word". In this case "word" means that it is the word construction
963 character used by some operators like "\<", "\>", etc. */
964
965static void
966internal_function
967init_word_char (re_dfa_t *dfa)
968{
969 int i, j, ch;
970 dfa->word_ops_used = 1;
971 for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
972 for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
973 if (isalnum (ch) || ch == '_')
974 dfa->word_char[i] |= (bitset_word_t) 1 << j;
975}
976
977/* Free the work area which are only used while compiling. */
978
979static void
980free_workarea_compile (regex_t *preg)
981{
982 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
983 bin_tree_storage_t *storage, *next;
984 for (storage = dfa->str_tree_storage; storage; storage = next)
985 {
986 next = storage->next;
987 re_free (storage);
988 }
989 dfa->str_tree_storage = NULL;
990 dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
991 dfa->str_tree = NULL;
992 re_free (dfa->org_indices);
993 dfa->org_indices = NULL;
994}
995
996/* Create initial states for all contexts. */
997
998static reg_errcode_t
999create_initial_state (re_dfa_t *dfa)
1000{
1001 int first, i;
1002 reg_errcode_t err;
1003 re_node_set init_nodes;
1004
1005 /* Initial states have the epsilon closure of the node which is
1006 the first node of the regular expression. */
1007 first = dfa->str_tree->first->node_idx;
1008 dfa->init_node = first;
1009 err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first);
1010 if (BE (err != REG_NOERROR, 0))
1011 return err;
1012
1013 /* The back-references which are in initial states can epsilon transit,
1014 since in this case all of the subexpressions can be null.
1015 Then we add epsilon closures of the nodes which are the next nodes of
1016 the back-references. */
1017 if (dfa->nbackref > 0)
1018 for (i = 0; i < init_nodes.nelem; ++i)
1019 {
1020 int node_idx = init_nodes.elems[i];
1021 re_token_type_t type = dfa->nodes[node_idx].type;
1022
1023 int clexp_idx;
1024 if (type != OP_BACK_REF)
1025 continue;
1026 for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx)
1027 {
1028 re_token_t *clexp_node;
1029 clexp_node = dfa->nodes + init_nodes.elems[clexp_idx];
1030 if (clexp_node->type == OP_CLOSE_SUBEXP
1031 && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx)
1032 break;
1033 }
1034 if (clexp_idx == init_nodes.nelem)
1035 continue;
1036
1037 if (type == OP_BACK_REF)
1038 {
1039 int dest_idx = dfa->edests[node_idx].elems[0];
1040 if (!re_node_set_contains (&init_nodes, dest_idx))
1041 {
1042 err = re_node_set_merge (&init_nodes,
1043 dfa->eclosures + dest_idx);
1044 if (err != REG_NOERROR)
1045 return err;
1046 i = 0;
1047 }
1048 }
1049 }
1050
1051 /* It must be the first time to invoke acquire_state. */
1052 dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0);
1053 /* We don't check ERR here, since the initial state must not be NULL. */
1054 if (BE (dfa->init_state == NULL, 0))
1055 return err;
1056 if (dfa->init_state->has_constraint)
1057 {
1058 dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes,
1059 CONTEXT_WORD);
1060 dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes,
1061 CONTEXT_NEWLINE);
1062 dfa->init_state_begbuf = re_acquire_state_context (&err, dfa,
1063 &init_nodes,
1064 CONTEXT_NEWLINE
1065 | CONTEXT_BEGBUF);
1066 if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL
1067 || dfa->init_state_begbuf == NULL, 0))
1068 return err;
1069 }
1070 else
1071 dfa->init_state_word = dfa->init_state_nl
1072 = dfa->init_state_begbuf = dfa->init_state;
1073
1074 re_node_set_free (&init_nodes);
1075 return REG_NOERROR;
1076}
1077
1078#ifdef RE_ENABLE_I18N
1079/* If it is possible to do searching in single byte encoding instead of UTF-8
1080 to speed things up, set dfa->mb_cur_max to 1, clear is_utf8 and change
1081 DFA nodes where needed. */
1082
1083static void
1084optimize_utf8 (re_dfa_t *dfa)
1085{
1086 int node, i, mb_chars = 0, has_period = 0;
1087
1088 for (node = 0; node < dfa->nodes_len; ++node)
1089 switch (dfa->nodes[node].type)
1090 {
1091 case CHARACTER:
1092 if (dfa->nodes[node].opr.c >= 0x80)
1093 mb_chars = 1;
1094 break;
1095 case ANCHOR:
1096 switch (dfa->nodes[node].opr.ctx_type)
1097 {
1098 case LINE_FIRST:
1099 case LINE_LAST:
1100 case BUF_FIRST:
1101 case BUF_LAST:
1102 break;
1103 default:
1104 /* Word anchors etc. cannot be handled. It's okay to test
1105 opr.ctx_type since constraints (for all DFA nodes) are
1106 created by ORing one or more opr.ctx_type values. */
1107 return;
1108 }
1109 break;
1110 case OP_PERIOD:
1111 has_period = 1;
1112 break;
1113 case OP_BACK_REF:
1114 case OP_ALT:
1115 case END_OF_RE:
1116 case OP_DUP_ASTERISK:
1117 case OP_OPEN_SUBEXP:
1118 case OP_CLOSE_SUBEXP:
1119 break;
1120 case COMPLEX_BRACKET:
1121 return;
1122 case SIMPLE_BRACKET:
1123 /* Just double check. The non-ASCII range starts at 0x80. */
1124 assert (0x80 % BITSET_WORD_BITS == 0);
1125 for (i = 0x80 / BITSET_WORD_BITS; i < BITSET_WORDS; ++i)
1126 if (dfa->nodes[node].opr.sbcset[i])
1127 return;
1128 break;
1129 default:
1130 abort ();
1131 }
1132
1133 if (mb_chars || has_period)
1134 for (node = 0; node < dfa->nodes_len; ++node)
1135 {
1136 if (dfa->nodes[node].type == CHARACTER
1137 && dfa->nodes[node].opr.c >= 0x80)
1138 dfa->nodes[node].mb_partial = 0;
1139 else if (dfa->nodes[node].type == OP_PERIOD)
1140 dfa->nodes[node].type = OP_UTF8_PERIOD;
1141 }
1142
1143 /* The search can be in single byte locale. */
1144 dfa->mb_cur_max = 1;
1145 dfa->is_utf8 = 0;
1146 dfa->has_mb_node = dfa->nbackref > 0 || has_period;
1147}
1148#endif
1149
1150/* Analyze the structure tree, and calculate "first", "next", "edest",
1151 "eclosure", and "inveclosure". */
1152
1153static reg_errcode_t
1154analyze (regex_t *preg)
1155{
1156 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
1157 reg_errcode_t ret;
1158
1159 /* Allocate arrays. */
1160 dfa->nexts = re_malloc (int, dfa->nodes_alloc);
1161 dfa->org_indices = re_malloc (int, dfa->nodes_alloc);
1162 dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc);
1163 dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc);
1164 if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL
1165 || dfa->eclosures == NULL, 0))
1166 return REG_ESPACE;
1167
1168 dfa->subexp_map = re_malloc (int, preg->re_nsub);
1169 if (dfa->subexp_map != NULL)
1170 {
1171 int i;
1172 for (i = 0; i < preg->re_nsub; i++)
1173 dfa->subexp_map[i] = i;
1174 preorder (dfa->str_tree, optimize_subexps, dfa);
1175 for (i = 0; i < preg->re_nsub; i++)
1176 if (dfa->subexp_map[i] != i)
1177 break;
1178 if (i == preg->re_nsub)
1179 {
1180 free (dfa->subexp_map);
1181 dfa->subexp_map = NULL;
1182 }
1183 }
1184
1185 ret = postorder (dfa->str_tree, lower_subexps, preg);
1186 if (BE (ret != REG_NOERROR, 0))
1187 return ret;
1188 ret = postorder (dfa->str_tree, calc_first, dfa);
1189 if (BE (ret != REG_NOERROR, 0))
1190 return ret;
1191 preorder (dfa->str_tree, calc_next, dfa);
1192 ret = preorder (dfa->str_tree, link_nfa_nodes, dfa);
1193 if (BE (ret != REG_NOERROR, 0))
1194 return ret;
1195 ret = calc_eclosure (dfa);
1196 if (BE (ret != REG_NOERROR, 0))
1197 return ret;
1198
1199 /* We only need this during the prune_impossible_nodes pass in regexec.c;
1200 skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */
1201 if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match)
1202 || dfa->nbackref)
1203 {
1204 dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len);
1205 if (BE (dfa->inveclosures == NULL, 0))
1206 return REG_ESPACE;
1207 ret = calc_inveclosure (dfa);
1208 }
1209
1210 return ret;
1211}
1212
1213/* Our parse trees are very unbalanced, so we cannot use a stack to
1214 implement parse tree visits. Instead, we use parent pointers and
1215 some hairy code in these two functions. */
1216static reg_errcode_t
1217postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
1218 void *extra)
1219{
1220 bin_tree_t *node, *prev;
1221
1222 for (node = root; ; )
1223 {
1224 /* Descend down the tree, preferably to the left (or to the right
1225 if that's the only child). */
1226 while (node->left || node->right)
1227 if (node->left)
1228 node = node->left;
1229 else
1230 node = node->right;
1231
1232 do
1233 {
1234 reg_errcode_t err = fn (extra, node);
1235 if (BE (err != REG_NOERROR, 0))
1236 return err;
1237 if (node->parent == NULL)
1238 return REG_NOERROR;
1239 prev = node;
1240 node = node->parent;
1241 }
1242 /* Go up while we have a node that is reached from the right. */
1243 while (node->right == prev || node->right == NULL);
1244 node = node->right;
1245 }
1246}
1247
1248static reg_errcode_t
1249preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
1250 void *extra)
1251{
1252 bin_tree_t *node;
1253
1254 for (node = root; ; )
1255 {
1256 reg_errcode_t err = fn (extra, node);
1257 if (BE (err != REG_NOERROR, 0))
1258 return err;
1259
1260 /* Go to the left node, or up and to the right. */
1261 if (node->left)
1262 node = node->left;
1263 else
1264 {
1265 bin_tree_t *prev = NULL;
1266 while (node->right == prev || node->right == NULL)
1267 {
1268 prev = node;
1269 node = node->parent;
1270 if (!node)
1271 return REG_NOERROR;
1272 }
1273 node = node->right;
1274 }
1275 }
1276}
1277
1278/* Optimization pass: if a SUBEXP is entirely contained, strip it and tell
1279 re_search_internal to map the inner one's opr.idx to this one's. Adjust
1280 backreferences as well. Requires a preorder visit. */
1281static reg_errcode_t
1282optimize_subexps (void *extra, bin_tree_t *node)
1283{
1284 re_dfa_t *dfa = (re_dfa_t *) extra;
1285
1286 if (node->token.type == OP_BACK_REF && dfa->subexp_map)
1287 {
1288 int idx = node->token.opr.idx;
1289 node->token.opr.idx = dfa->subexp_map[idx];
1290 dfa->used_bkref_map |= 1 << node->token.opr.idx;
1291 }
1292
1293 else if (node->token.type == SUBEXP
1294 && node->left && node->left->token.type == SUBEXP)
1295 {
1296 int other_idx = node->left->token.opr.idx;
1297
1298 node->left = node->left->left;
1299 if (node->left)
1300 node->left->parent = node;
1301
1302 dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx];
1303 if (other_idx < BITSET_WORD_BITS)
1304 dfa->used_bkref_map &= ~((bitset_word_t) 1 << other_idx);
1305 }
1306
1307 return REG_NOERROR;
1308}
1309
1310/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation
1311 of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */
1312static reg_errcode_t
1313lower_subexps (void *extra, bin_tree_t *node)
1314{
1315 regex_t *preg = (regex_t *) extra;
1316 reg_errcode_t err = REG_NOERROR;
1317
1318 if (node->left && node->left->token.type == SUBEXP)
1319 {
1320 node->left = lower_subexp (&err, preg, node->left);
1321 if (node->left)
1322 node->left->parent = node;
1323 }
1324 if (node->right && node->right->token.type == SUBEXP)
1325 {
1326 node->right = lower_subexp (&err, preg, node->right);
1327 if (node->right)
1328 node->right->parent = node;
1329 }
1330
1331 return err;
1332}
1333
1334static bin_tree_t *
1335lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node)
1336{
1337 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
1338 bin_tree_t *body = node->left;
1339 bin_tree_t *op, *cls, *tree1, *tree;
1340
1341 if (preg->no_sub
1342 /* We do not optimize empty subexpressions, because otherwise we may
1343 have bad CONCAT nodes with NULL children. This is obviously not
1344 very common, so we do not lose much. An example that triggers
1345 this case is the sed "script" /\(\)/x. */
1346 && node->left != NULL
1347 && (node->token.opr.idx >= BITSET_WORD_BITS
1348 || !(dfa->used_bkref_map
1349 & ((bitset_word_t) 1 << node->token.opr.idx))))
1350 return node->left;
1351
1352 /* Convert the SUBEXP node to the concatenation of an
1353 OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */
1354 op = create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP);
1355 cls = create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP);
1356 tree1 = body ? create_tree (dfa, body, cls, CONCAT) : cls;
1357 tree = create_tree (dfa, op, tree1, CONCAT);
1358 if (BE (tree == NULL || tree1 == NULL || op == NULL || cls == NULL, 0))
1359 {
1360 *err = REG_ESPACE;
1361 return NULL;
1362 }
1363
1364 op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx;
1365 op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp;
1366 return tree;
1367}
1368
1369/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton
1370 nodes. Requires a postorder visit. */
1371static reg_errcode_t
1372calc_first (void *extra, bin_tree_t *node)
1373{
1374 re_dfa_t *dfa = (re_dfa_t *) extra;
1375 if (node->token.type == CONCAT)
1376 {
1377 node->first = node->left->first;
1378 node->node_idx = node->left->node_idx;
1379 }
1380 else
1381 {
1382 node->first = node;
1383 node->node_idx = re_dfa_add_node (dfa, node->token);
1384 if (BE (node->node_idx == -1, 0))
1385 return REG_ESPACE;
1386 if (node->token.type == ANCHOR)
1387 dfa->nodes[node->node_idx].constraint = node->token.opr.ctx_type;
1388 }
1389 return REG_NOERROR;
1390}
1391
1392/* Pass 2: compute NEXT on the tree. Preorder visit. */
1393static reg_errcode_t
1394calc_next (UNUSED_PARAM void *extra, bin_tree_t *node)
1395{
1396 switch (node->token.type)
1397 {
1398 case OP_DUP_ASTERISK:
1399 node->left->next = node;
1400 break;
1401 case CONCAT:
1402 node->left->next = node->right->first;
1403 node->right->next = node->next;
1404 break;
1405 default:
1406 if (node->left)
1407 node->left->next = node->next;
1408 if (node->right)
1409 node->right->next = node->next;
1410 break;
1411 }
1412 return REG_NOERROR;
1413}
1414
1415/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */
1416static reg_errcode_t
1417link_nfa_nodes (void *extra, bin_tree_t *node)
1418{
1419 re_dfa_t *dfa = (re_dfa_t *) extra;
1420 int idx = node->node_idx;
1421 reg_errcode_t err = REG_NOERROR;
1422
1423 switch (node->token.type)
1424 {
1425 case CONCAT:
1426 break;
1427
1428 case END_OF_RE:
1429 assert (node->next == NULL);
1430 break;
1431
1432 case OP_DUP_ASTERISK:
1433 case OP_ALT:
1434 {
1435 int left, right;
1436 dfa->has_plural_match = 1;
1437 if (node->left != NULL)
1438 left = node->left->first->node_idx;
1439 else
1440 left = node->next->node_idx;
1441 if (node->right != NULL)
1442 right = node->right->first->node_idx;
1443 else
1444 right = node->next->node_idx;
1445 assert (left > -1);
1446 assert (right > -1);
1447 err = re_node_set_init_2 (dfa->edests + idx, left, right);
1448 }
1449 break;
1450
1451 case ANCHOR:
1452 case OP_OPEN_SUBEXP:
1453 case OP_CLOSE_SUBEXP:
1454 err = re_node_set_init_1 (dfa->edests + idx, node->next->node_idx);
1455 break;
1456
1457 case OP_BACK_REF:
1458 dfa->nexts[idx] = node->next->node_idx;
1459 if (node->token.type == OP_BACK_REF)
1460 err = re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]);
1461 break;
1462
1463 default:
1464 assert (!IS_EPSILON_NODE (node->token.type));
1465 dfa->nexts[idx] = node->next->node_idx;
1466 break;
1467 }
1468
1469 return err;
1470}
1471
1472/* Duplicate the epsilon closure of the node ROOT_NODE.
1473 Note that duplicated nodes have constraint INIT_CONSTRAINT in addition
1474 to their own constraint. */
1475
1476static reg_errcode_t
1477internal_function
1478duplicate_node_closure (re_dfa_t *dfa, int top_org_node, int top_clone_node,
1479 int root_node, unsigned int init_constraint)
1480{
1481 int org_node, clone_node, ret;
1482 unsigned int constraint = init_constraint;
1483 for (org_node = top_org_node, clone_node = top_clone_node;;)
1484 {
1485 int org_dest, clone_dest;
1486 if (dfa->nodes[org_node].type == OP_BACK_REF)
1487 {
1488 /* If the back reference epsilon-transit, its destination must
1489 also have the constraint. Then duplicate the epsilon closure
1490 of the destination of the back reference, and store it in
1491 edests of the back reference. */
1492 org_dest = dfa->nexts[org_node];
1493 re_node_set_empty (dfa->edests + clone_node);
1494 clone_dest = duplicate_node (dfa, org_dest, constraint);
1495 if (BE (clone_dest == -1, 0))
1496 return REG_ESPACE;
1497 dfa->nexts[clone_node] = dfa->nexts[org_node];
1498 ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
1499 if (BE (ret < 0, 0))
1500 return REG_ESPACE;
1501 }
1502 else if (dfa->edests[org_node].nelem == 0)
1503 {
1504 /* In case of the node can't epsilon-transit, don't duplicate the
1505 destination and store the original destination as the
1506 destination of the node. */
1507 dfa->nexts[clone_node] = dfa->nexts[org_node];
1508 break;
1509 }
1510 else if (dfa->edests[org_node].nelem == 1)
1511 {
1512 /* In case of the node can epsilon-transit, and it has only one
1513 destination. */
1514 org_dest = dfa->edests[org_node].elems[0];
1515 re_node_set_empty (dfa->edests + clone_node);
1516 /* If the node is root_node itself, it means the epsilon clsoure
1517 has a loop. Then tie it to the destination of the root_node. */
1518 if (org_node == root_node && clone_node != org_node)
1519 {
1520 ret = re_node_set_insert (dfa->edests + clone_node, org_dest);
1521 if (BE (ret < 0, 0))
1522 return REG_ESPACE;
1523 break;
1524 }
1525 /* In case of the node has another constraint, add it. */
1526 constraint |= dfa->nodes[org_node].constraint;
1527 clone_dest = duplicate_node (dfa, org_dest, constraint);
1528 if (BE (clone_dest == -1, 0))
1529 return REG_ESPACE;
1530 ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
1531 if (BE (ret < 0, 0))
1532 return REG_ESPACE;
1533 }
1534 else /* dfa->edests[org_node].nelem == 2 */
1535 {
1536 /* In case of the node can epsilon-transit, and it has two
1537 destinations. In the bin_tree_t and DFA, that's '|' and '*'. */
1538 org_dest = dfa->edests[org_node].elems[0];
1539 re_node_set_empty (dfa->edests + clone_node);
1540 /* Search for a duplicated node which satisfies the constraint. */
1541 clone_dest = search_duplicated_node (dfa, org_dest, constraint);
1542 if (clone_dest == -1)
1543 {
1544 /* There is no such duplicated node, create a new one. */
1545 reg_errcode_t err;
1546 clone_dest = duplicate_node (dfa, org_dest, constraint);
1547 if (BE (clone_dest == -1, 0))
1548 return REG_ESPACE;
1549 ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
1550 if (BE (ret < 0, 0))
1551 return REG_ESPACE;
1552 err = duplicate_node_closure (dfa, org_dest, clone_dest,
1553 root_node, constraint);
1554 if (BE (err != REG_NOERROR, 0))
1555 return err;
1556 }
1557 else
1558 {
1559 /* There is a duplicated node which satisfies the constraint,
1560 use it to avoid infinite loop. */
1561 ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
1562 if (BE (ret < 0, 0))
1563 return REG_ESPACE;
1564 }
1565
1566 org_dest = dfa->edests[org_node].elems[1];
1567 clone_dest = duplicate_node (dfa, org_dest, constraint);
1568 if (BE (clone_dest == -1, 0))
1569 return REG_ESPACE;
1570 ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
1571 if (BE (ret < 0, 0))
1572 return REG_ESPACE;
1573 }
1574 org_node = org_dest;
1575 clone_node = clone_dest;
1576 }
1577 return REG_NOERROR;
1578}
1579
1580/* Search for a node which is duplicated from the node ORG_NODE, and
1581 satisfies the constraint CONSTRAINT. */
1582
1583static int
1584search_duplicated_node (const re_dfa_t *dfa, int org_node,
1585 unsigned int constraint)
1586{
1587 int idx;
1588 for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx)
1589 {
1590 if (org_node == dfa->org_indices[idx]
1591 && constraint == dfa->nodes[idx].constraint)
1592 return idx; /* Found. */
1593 }
1594 return -1; /* Not found. */
1595}
1596
1597/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT.
1598 Return the index of the new node, or -1 if insufficient storage is
1599 available. */
1600
1601static int
1602duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint)
1603{
1604 int dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]);
1605 if (BE (dup_idx != -1, 1))
1606 {
1607 dfa->nodes[dup_idx].constraint = constraint;
1608 dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].constraint;
1609 dfa->nodes[dup_idx].duplicated = 1;
1610
1611 /* Store the index of the original node. */
1612 dfa->org_indices[dup_idx] = org_idx;
1613 }
1614 return dup_idx;
1615}
1616
1617static reg_errcode_t
1618calc_inveclosure (re_dfa_t *dfa)
1619{
1620 int src, idx, ret;
1621 for (idx = 0; idx < dfa->nodes_len; ++idx)
1622 re_node_set_init_empty (dfa->inveclosures + idx);
1623
1624 for (src = 0; src < dfa->nodes_len; ++src)
1625 {
1626 int *elems = dfa->eclosures[src].elems;
1627 for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx)
1628 {
1629 ret = re_node_set_insert_last (dfa->inveclosures + elems[idx], src);
1630 if (BE (ret == -1, 0))
1631 return REG_ESPACE;
1632 }
1633 }
1634
1635 return REG_NOERROR;
1636}
1637
1638/* Calculate "eclosure" for all the node in DFA. */
1639
1640static reg_errcode_t
1641calc_eclosure (re_dfa_t *dfa)
1642{
1643 int node_idx, incomplete;
1644#ifdef DEBUG
1645 assert (dfa->nodes_len > 0);
1646#endif
1647 incomplete = 0;
1648 /* For each nodes, calculate epsilon closure. */
1649 for (node_idx = 0; ; ++node_idx)
1650 {
1651 reg_errcode_t err;
1652 re_node_set eclosure_elem;
1653 if (node_idx == dfa->nodes_len)
1654 {
1655 if (!incomplete)
1656 break;
1657 incomplete = 0;
1658 node_idx = 0;
1659 }
1660
1661#ifdef DEBUG
1662 assert (dfa->eclosures[node_idx].nelem != -1);
1663#endif
1664
1665 /* If we have already calculated, skip it. */
1666 if (dfa->eclosures[node_idx].nelem != 0)
1667 continue;
1668 /* Calculate epsilon closure of `node_idx'. */
1669 err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, 1);
1670 if (BE (err != REG_NOERROR, 0))
1671 return err;
1672
1673 if (dfa->eclosures[node_idx].nelem == 0)
1674 {
1675 incomplete = 1;
1676 re_node_set_free (&eclosure_elem);
1677 }
1678 }
1679 return REG_NOERROR;
1680}
1681
1682/* Calculate epsilon closure of NODE. */
1683
1684static reg_errcode_t
1685calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, int node, int root)
1686{
1687 reg_errcode_t err;
1688 int i;
1689 re_node_set eclosure;
1690 int ret;
1691 int incomplete = 0;
1692 err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1);
1693 if (BE (err != REG_NOERROR, 0))
1694 return err;
1695
1696 /* This indicates that we are calculating this node now.
1697 We reference this value to avoid infinite loop. */
1698 dfa->eclosures[node].nelem = -1;
1699
1700 /* If the current node has constraints, duplicate all nodes
1701 since they must inherit the constraints. */
1702 if (dfa->nodes[node].constraint
1703 && dfa->edests[node].nelem
1704 && !dfa->nodes[dfa->edests[node].elems[0]].duplicated)
1705 {
1706 err = duplicate_node_closure (dfa, node, node, node,
1707 dfa->nodes[node].constraint);
1708 if (BE (err != REG_NOERROR, 0))
1709 return err;
1710 }
1711
1712 /* Expand each epsilon destination nodes. */
1713 if (IS_EPSILON_NODE(dfa->nodes[node].type))
1714 for (i = 0; i < dfa->edests[node].nelem; ++i)
1715 {
1716 re_node_set eclosure_elem;
1717 int edest = dfa->edests[node].elems[i];
1718 /* If calculating the epsilon closure of `edest' is in progress,
1719 return intermediate result. */
1720 if (dfa->eclosures[edest].nelem == -1)
1721 {
1722 incomplete = 1;
1723 continue;
1724 }
1725 /* If we haven't calculated the epsilon closure of `edest' yet,
1726 calculate now. Otherwise use calculated epsilon closure. */
1727 if (dfa->eclosures[edest].nelem == 0)
1728 {
1729 err = calc_eclosure_iter (&eclosure_elem, dfa, edest, 0);
1730 if (BE (err != REG_NOERROR, 0))
1731 return err;
1732 }
1733 else
1734 eclosure_elem = dfa->eclosures[edest];
1735 /* Merge the epsilon closure of `edest'. */
1736 err = re_node_set_merge (&eclosure, &eclosure_elem);
1737 if (BE (err != REG_NOERROR, 0))
1738 return err;
1739 /* If the epsilon closure of `edest' is incomplete,
1740 the epsilon closure of this node is also incomplete. */
1741 if (dfa->eclosures[edest].nelem == 0)
1742 {
1743 incomplete = 1;
1744 re_node_set_free (&eclosure_elem);
1745 }
1746 }
1747
1748 /* An epsilon closure includes itself. */
1749 ret = re_node_set_insert (&eclosure, node);
1750 if (BE (ret < 0, 0))
1751 return REG_ESPACE;
1752 if (incomplete && !root)
1753 dfa->eclosures[node].nelem = 0;
1754 else
1755 dfa->eclosures[node] = eclosure;
1756 *new_set = eclosure;
1757 return REG_NOERROR;
1758}
1759
1760/* Functions for token which are used in the parser. */
1761
1762/* Fetch a token from INPUT.
1763 We must not use this function inside bracket expressions. */
1764
1765static void
1766internal_function
1767fetch_token (re_token_t *result, re_string_t *input, reg_syntax_t syntax)
1768{
1769 re_string_skip_bytes (input, peek_token (result, input, syntax));
1770}
1771
1772/* Peek a token from INPUT, and return the length of the token.
1773 We must not use this function inside bracket expressions. */
1774
1775static int
1776internal_function
1777peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
1778{
1779 unsigned char c;
1780
1781 if (re_string_eoi (input))
1782 {
1783 token->type = END_OF_RE;
1784 return 0;
1785 }
1786
1787 c = re_string_peek_byte (input, 0);
1788 token->opr.c = c;
1789
1790 token->word_char = 0;
1791#ifdef RE_ENABLE_I18N
1792 token->mb_partial = 0;
1793 if (input->mb_cur_max > 1 &&
1794 !re_string_first_byte (input, re_string_cur_idx (input)))
1795 {
1796 token->type = CHARACTER;
1797 token->mb_partial = 1;
1798 return 1;
1799 }
1800#endif
1801 if (c == '\\')
1802 {
1803 unsigned char c2;
1804 if (re_string_cur_idx (input) + 1 >= re_string_length (input))
1805 {
1806 token->type = BACK_SLASH;
1807 return 1;
1808 }
1809
1810 c2 = re_string_peek_byte_case (input, 1);
1811 token->opr.c = c2;
1812 token->type = CHARACTER;
1813#ifdef RE_ENABLE_I18N
1814 if (input->mb_cur_max > 1)
1815 {
1816 wint_t wc = re_string_wchar_at (input,
1817 re_string_cur_idx (input) + 1);
1818 token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
1819 }
1820 else
1821#endif
1822 token->word_char = IS_WORD_CHAR (c2) != 0;
1823
1824 switch (c2)
1825 {
1826 case '|':
1827 if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR))
1828 token->type = OP_ALT;
1829 break;
1830 case '1': case '2': case '3': case '4': case '5':
1831 case '6': case '7': case '8': case '9':
1832 if (!(syntax & RE_NO_BK_REFS))
1833 {
1834 token->type = OP_BACK_REF;
1835 token->opr.idx = c2 - '1';
1836 }
1837 break;
1838 case '<':
1839 if (!(syntax & RE_NO_GNU_OPS))
1840 {
1841 token->type = ANCHOR;
1842 token->opr.ctx_type = WORD_FIRST;
1843 }
1844 break;
1845 case '>':
1846 if (!(syntax & RE_NO_GNU_OPS))
1847 {
1848 token->type = ANCHOR;
1849 token->opr.ctx_type = WORD_LAST;
1850 }
1851 break;
1852 case 'b':
1853 if (!(syntax & RE_NO_GNU_OPS))
1854 {
1855 token->type = ANCHOR;
1856 token->opr.ctx_type = WORD_DELIM;
1857 }
1858 break;
1859 case 'B':
1860 if (!(syntax & RE_NO_GNU_OPS))
1861 {
1862 token->type = ANCHOR;
1863 token->opr.ctx_type = NOT_WORD_DELIM;
1864 }
1865 break;
1866 case 'w':
1867 if (!(syntax & RE_NO_GNU_OPS))
1868 token->type = OP_WORD;
1869 break;
1870 case 'W':
1871 if (!(syntax & RE_NO_GNU_OPS))
1872 token->type = OP_NOTWORD;
1873 break;
1874 case 's':
1875 if (!(syntax & RE_NO_GNU_OPS))
1876 token->type = OP_SPACE;
1877 break;
1878 case 'S':
1879 if (!(syntax & RE_NO_GNU_OPS))
1880 token->type = OP_NOTSPACE;
1881 break;
1882 case '`':
1883 if (!(syntax & RE_NO_GNU_OPS))
1884 {
1885 token->type = ANCHOR;
1886 token->opr.ctx_type = BUF_FIRST;
1887 }
1888 break;
1889 case '\'':
1890 if (!(syntax & RE_NO_GNU_OPS))
1891 {
1892 token->type = ANCHOR;
1893 token->opr.ctx_type = BUF_LAST;
1894 }
1895 break;
1896 case '(':
1897 if (!(syntax & RE_NO_BK_PARENS))
1898 token->type = OP_OPEN_SUBEXP;
1899 break;
1900 case ')':
1901 if (!(syntax & RE_NO_BK_PARENS))
1902 token->type = OP_CLOSE_SUBEXP;
1903 break;
1904 case '+':
1905 if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
1906 token->type = OP_DUP_PLUS;
1907 break;
1908 case '?':
1909 if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
1910 token->type = OP_DUP_QUESTION;
1911 break;
1912 case '{':
1913 if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
1914 token->type = OP_OPEN_DUP_NUM;
1915 break;
1916 case '}':
1917 if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
1918 token->type = OP_CLOSE_DUP_NUM;
1919 break;
1920 default:
1921 break;
1922 }
1923 return 2;
1924 }
1925
1926 token->type = CHARACTER;
1927#ifdef RE_ENABLE_I18N
1928 if (input->mb_cur_max > 1)
1929 {
1930 wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input));
1931 token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
1932 }
1933 else
1934#endif
1935 token->word_char = IS_WORD_CHAR (token->opr.c);
1936
1937 switch (c)
1938 {
1939 case '\n':
1940 if (syntax & RE_NEWLINE_ALT)
1941 token->type = OP_ALT;
1942 break;
1943 case '|':
1944 if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR))
1945 token->type = OP_ALT;
1946 break;
1947 case '*':
1948 token->type = OP_DUP_ASTERISK;
1949 break;
1950 case '+':
1951 if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
1952 token->type = OP_DUP_PLUS;
1953 break;
1954 case '?':
1955 if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
1956 token->type = OP_DUP_QUESTION;
1957 break;
1958 case '{':
1959 if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
1960 token->type = OP_OPEN_DUP_NUM;
1961 break;
1962 case '}':
1963 if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
1964 token->type = OP_CLOSE_DUP_NUM;
1965 break;
1966 case '(':
1967 if (syntax & RE_NO_BK_PARENS)
1968 token->type = OP_OPEN_SUBEXP;
1969 break;
1970 case ')':
1971 if (syntax & RE_NO_BK_PARENS)
1972 token->type = OP_CLOSE_SUBEXP;
1973 break;
1974 case '[':
1975 token->type = OP_OPEN_BRACKET;
1976 break;
1977 case '.':
1978 token->type = OP_PERIOD;
1979 break;
1980 case '^':
1981 if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) &&
1982 re_string_cur_idx (input) != 0)
1983 {
1984 char prev = re_string_peek_byte (input, -1);
1985 if (!(syntax & RE_NEWLINE_ALT) || prev != '\n')
1986 break;
1987 }
1988 token->type = ANCHOR;
1989 token->opr.ctx_type = LINE_FIRST;
1990 break;
1991 case '$':
1992 if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) &&
1993 re_string_cur_idx (input) + 1 != re_string_length (input))
1994 {
1995 re_token_t next;
1996 re_string_skip_bytes (input, 1);
1997 peek_token (&next, input, syntax);
1998 re_string_skip_bytes (input, -1);
1999 if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP)
2000 break;
2001 }
2002 token->type = ANCHOR;
2003 token->opr.ctx_type = LINE_LAST;
2004 break;
2005 default:
2006 break;
2007 }
2008 return 1;
2009}
2010
2011/* Peek a token from INPUT, and return the length of the token.
2012 We must not use this function out of bracket expressions. */
2013
2014static int
2015internal_function
2016peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
2017{
2018 unsigned char c;
2019 if (re_string_eoi (input))
2020 {
2021 token->type = END_OF_RE;
2022 return 0;
2023 }
2024 c = re_string_peek_byte (input, 0);
2025 token->opr.c = c;
2026
2027#ifdef RE_ENABLE_I18N
2028 if (input->mb_cur_max > 1 &&
2029 !re_string_first_byte (input, re_string_cur_idx (input)))
2030 {
2031 token->type = CHARACTER;
2032 return 1;
2033 }
2034#endif /* RE_ENABLE_I18N */
2035
2036 if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS)
2037 && re_string_cur_idx (input) + 1 < re_string_length (input))
2038 {
2039 /* In this case, '\' escape a character. */
2040 unsigned char c2;
2041 re_string_skip_bytes (input, 1);
2042 c2 = re_string_peek_byte (input, 0);
2043 token->opr.c = c2;
2044 token->type = CHARACTER;
2045 return 1;
2046 }
2047 if (c == '[') /* '[' is a special char in a bracket exps. */
2048 {
2049 unsigned char c2;
2050 int token_len;
2051 if (re_string_cur_idx (input) + 1 < re_string_length (input))
2052 c2 = re_string_peek_byte (input, 1);
2053 else
2054 c2 = 0;
2055 token->opr.c = c2;
2056 token_len = 2;
2057 switch (c2)
2058 {
2059 case '.':
2060 token->type = OP_OPEN_COLL_ELEM;
2061 break;
2062 case '=':
2063 token->type = OP_OPEN_EQUIV_CLASS;
2064 break;
2065 case ':':
2066 if (syntax & RE_CHAR_CLASSES)
2067 {
2068 token->type = OP_OPEN_CHAR_CLASS;
2069 break;
2070 }
2071 /* else fall through. */
2072 default:
2073 token->type = CHARACTER;
2074 token->opr.c = c;
2075 token_len = 1;
2076 break;
2077 }
2078 return token_len;
2079 }
2080 switch (c)
2081 {
2082 case '-':
2083 token->type = OP_CHARSET_RANGE;
2084 break;
2085 case ']':
2086 token->type = OP_CLOSE_BRACKET;
2087 break;
2088 case '^':
2089 token->type = OP_NON_MATCH_LIST;
2090 break;
2091 default:
2092 token->type = CHARACTER;
2093 }
2094 return 1;
2095}
2096
2097/* Functions for parser. */
2098
2099/* Entry point of the parser.
2100 Parse the regular expression REGEXP and return the structure tree.
2101 If an error has occurred, ERR is set by error code, and return NULL.
2102 This function build the following tree, from regular expression <reg_exp>:
2103 CAT
2104 / \
2105 / \
2106 <reg_exp> EOR
2107
2108 CAT means concatenation.
2109 EOR means end of regular expression. */
2110
2111static bin_tree_t *
2112parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax,
2113 reg_errcode_t *err)
2114{
2115 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
2116 bin_tree_t *tree, *eor, *root;
2117 re_token_t current_token;
2118 dfa->syntax = syntax;
2119 fetch_token (&current_token, regexp, syntax | RE_CARET_ANCHORS_HERE);
2120 tree = parse_reg_exp (regexp, preg, &current_token, syntax, 0, err);
2121 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2122 return NULL;
2123 eor = create_tree (dfa, NULL, NULL, END_OF_RE);
2124 if (tree != NULL)
2125 root = create_tree (dfa, tree, eor, CONCAT);
2126 else
2127 root = eor;
2128 if (BE (eor == NULL || root == NULL, 0))
2129 {
2130 *err = REG_ESPACE;
2131 return NULL;
2132 }
2133 return root;
2134}
2135
2136/* This function build the following tree, from regular expression
2137 <branch1>|<branch2>:
2138 ALT
2139 / \
2140 / \
2141 <branch1> <branch2>
2142
2143 ALT means alternative, which represents the operator `|'. */
2144
2145static bin_tree_t *
2146parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
2147 reg_syntax_t syntax, int nest, reg_errcode_t *err)
2148{
2149 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
2150 bin_tree_t *tree, *branch = NULL;
2151 tree = parse_branch (regexp, preg, token, syntax, nest, err);
2152 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2153 return NULL;
2154
2155 while (token->type == OP_ALT)
2156 {
2157 fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
2158 if (token->type != OP_ALT && token->type != END_OF_RE
2159 && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
2160 {
2161 branch = parse_branch (regexp, preg, token, syntax, nest, err);
2162 if (BE (*err != REG_NOERROR && branch == NULL, 0))
2163 return NULL;
2164 }
2165 else
2166 branch = NULL;
2167 tree = create_tree (dfa, tree, branch, OP_ALT);
2168 if (BE (tree == NULL, 0))
2169 {
2170 *err = REG_ESPACE;
2171 return NULL;
2172 }
2173 }
2174 return tree;
2175}
2176
2177/* This function build the following tree, from regular expression
2178 <exp1><exp2>:
2179 CAT
2180 / \
2181 / \
2182 <exp1> <exp2>
2183
2184 CAT means concatenation. */
2185
2186static bin_tree_t *
2187parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token,
2188 reg_syntax_t syntax, int nest, reg_errcode_t *err)
2189{
2190 bin_tree_t *tree, *exp;
2191 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
2192 tree = parse_expression (regexp, preg, token, syntax, nest, err);
2193 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2194 return NULL;
2195
2196 while (token->type != OP_ALT && token->type != END_OF_RE
2197 && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
2198 {
2199 exp = parse_expression (regexp, preg, token, syntax, nest, err);
2200 if (BE (*err != REG_NOERROR && exp == NULL, 0))
2201 {
2202 return NULL;
2203 }
2204 if (tree != NULL && exp != NULL)
2205 {
2206 tree = create_tree (dfa, tree, exp, CONCAT);
2207 if (tree == NULL)
2208 {
2209 *err = REG_ESPACE;
2210 return NULL;
2211 }
2212 }
2213 else if (tree == NULL)
2214 tree = exp;
2215 /* Otherwise exp == NULL, we don't need to create new tree. */
2216 }
2217 return tree;
2218}
2219
2220/* This function build the following tree, from regular expression a*:
2221 *
2222 |
2223 a
2224*/
2225
2226static bin_tree_t *
2227parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token,
2228 reg_syntax_t syntax, int nest, reg_errcode_t *err)
2229{
2230 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
2231 bin_tree_t *tree;
2232 switch (token->type)
2233 {
2234 case CHARACTER:
2235 tree = create_token_tree (dfa, NULL, NULL, token);
2236 if (BE (tree == NULL, 0))
2237 {
2238 *err = REG_ESPACE;
2239 return NULL;
2240 }
2241#ifdef RE_ENABLE_I18N
2242 if (dfa->mb_cur_max > 1)
2243 {
2244 while (!re_string_eoi (regexp)
2245 && !re_string_first_byte (regexp, re_string_cur_idx (regexp)))
2246 {
2247 bin_tree_t *mbc_remain;
2248 fetch_token (token, regexp, syntax);
2249 mbc_remain = create_token_tree (dfa, NULL, NULL, token);
2250 tree = create_tree (dfa, tree, mbc_remain, CONCAT);
2251 if (BE (mbc_remain == NULL || tree == NULL, 0))
2252 {
2253 *err = REG_ESPACE;
2254 return NULL;
2255 }
2256 }
2257 }
2258#endif
2259 break;
2260 case OP_OPEN_SUBEXP:
2261 tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err);
2262 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2263 return NULL;
2264 break;
2265 case OP_OPEN_BRACKET:
2266 tree = parse_bracket_exp (regexp, dfa, token, syntax, err);
2267 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2268 return NULL;
2269 break;
2270 case OP_BACK_REF:
2271 if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1))
2272 {
2273 *err = REG_ESUBREG;
2274 return NULL;
2275 }
2276 dfa->used_bkref_map |= 1 << token->opr.idx;
2277 tree = create_token_tree (dfa, NULL, NULL, token);
2278 if (BE (tree == NULL, 0))
2279 {
2280 *err = REG_ESPACE;
2281 return NULL;
2282 }
2283 ++dfa->nbackref;
2284 dfa->has_mb_node = 1;
2285 break;
2286 case OP_OPEN_DUP_NUM:
2287 if (syntax & RE_CONTEXT_INVALID_DUP)
2288 {
2289 *err = REG_BADRPT;
2290 return NULL;
2291 }
2292 /* FALLTHROUGH */
2293 case OP_DUP_ASTERISK:
2294 case OP_DUP_PLUS:
2295 case OP_DUP_QUESTION:
2296 if (syntax & RE_CONTEXT_INVALID_OPS)
2297 {
2298 *err = REG_BADRPT;
2299 return NULL;
2300 }
2301 else if (syntax & RE_CONTEXT_INDEP_OPS)
2302 {
2303 fetch_token (token, regexp, syntax);
2304 return parse_expression (regexp, preg, token, syntax, nest, err);
2305 }
2306 /* else fall through */
2307 case OP_CLOSE_SUBEXP:
2308 if ((token->type == OP_CLOSE_SUBEXP) &&
2309 !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD))
2310 {
2311 *err = REG_ERPAREN;
2312 return NULL;
2313 }
2314 /* else fall through */
2315 case OP_CLOSE_DUP_NUM:
2316 /* We treat it as a normal character. */
2317
2318 /* Then we can these characters as normal characters. */
2319 token->type = CHARACTER;
2320 /* mb_partial and word_char bits should be initialized already
2321 by peek_token. */
2322 tree = create_token_tree (dfa, NULL, NULL, token);
2323 if (BE (tree == NULL, 0))
2324 {
2325 *err = REG_ESPACE;
2326 return NULL;
2327 }
2328 break;
2329 case ANCHOR:
2330 if ((token->opr.ctx_type
2331 & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST))
2332 && dfa->word_ops_used == 0)
2333 init_word_char (dfa);
2334 if (token->opr.ctx_type == WORD_DELIM
2335 || token->opr.ctx_type == NOT_WORD_DELIM)
2336 {
2337 bin_tree_t *tree_first, *tree_last;
2338 if (token->opr.ctx_type == WORD_DELIM)
2339 {
2340 token->opr.ctx_type = WORD_FIRST;
2341 tree_first = create_token_tree (dfa, NULL, NULL, token);
2342 token->opr.ctx_type = WORD_LAST;
2343 }
2344 else
2345 {
2346 token->opr.ctx_type = INSIDE_WORD;
2347 tree_first = create_token_tree (dfa, NULL, NULL, token);
2348 token->opr.ctx_type = INSIDE_NOTWORD;
2349 }
2350 tree_last = create_token_tree (dfa, NULL, NULL, token);
2351 tree = create_tree (dfa, tree_first, tree_last, OP_ALT);
2352 if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0))
2353 {
2354 *err = REG_ESPACE;
2355 return NULL;
2356 }
2357 }
2358 else
2359 {
2360 tree = create_token_tree (dfa, NULL, NULL, token);
2361 if (BE (tree == NULL, 0))
2362 {
2363 *err = REG_ESPACE;
2364 return NULL;
2365 }
2366 }
2367 /* We must return here, since ANCHORs can't be followed
2368 by repetition operators.
2369 eg. RE"^*" is invalid or "<ANCHOR(^)><CHAR(*)>",
2370 it must not be "<ANCHOR(^)><REPEAT(*)>". */
2371 fetch_token (token, regexp, syntax);
2372 return tree;
2373 case OP_PERIOD:
2374 tree = create_token_tree (dfa, NULL, NULL, token);
2375 if (BE (tree == NULL, 0))
2376 {
2377 *err = REG_ESPACE;
2378 return NULL;
2379 }
2380 if (dfa->mb_cur_max > 1)
2381 dfa->has_mb_node = 1;
2382 break;
2383 case OP_WORD:
2384 case OP_NOTWORD:
2385 tree = build_charclass_op (dfa, regexp->trans,
2386 "alnum",
2387 "_",
2388 token->type == OP_NOTWORD, err);
2389 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2390 return NULL;
2391 break;
2392 case OP_SPACE:
2393 case OP_NOTSPACE:
2394 tree = build_charclass_op (dfa, regexp->trans,
2395 "space",
2396 "",
2397 token->type == OP_NOTSPACE, err);
2398 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2399 return NULL;
2400 break;
2401 case OP_ALT:
2402 case END_OF_RE:
2403 return NULL;
2404 case BACK_SLASH:
2405 *err = REG_EESCAPE;
2406 return NULL;
2407 default:
2408 /* Must not happen? */
2409#ifdef DEBUG
2410 assert (0);
2411#endif
2412 return NULL;
2413 }
2414 fetch_token (token, regexp, syntax);
2415
2416 while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS
2417 || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM)
2418 {
2419 tree = parse_dup_op (tree, regexp, dfa, token, syntax, err);
2420 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2421 return NULL;
2422 /* In BRE consecutive duplications are not allowed. */
2423 if ((syntax & RE_CONTEXT_INVALID_DUP)
2424 && (token->type == OP_DUP_ASTERISK
2425 || token->type == OP_OPEN_DUP_NUM))
2426 {
2427 *err = REG_BADRPT;
2428 return NULL;
2429 }
2430 }
2431
2432 return tree;
2433}
2434
2435/* This function build the following tree, from regular expression
2436 (<reg_exp>):
2437 SUBEXP
2438 |
2439 <reg_exp>
2440*/
2441
2442static bin_tree_t *
2443parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
2444 reg_syntax_t syntax, int nest, reg_errcode_t *err)
2445{
2446 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
2447 bin_tree_t *tree;
2448 size_t cur_nsub;
2449 cur_nsub = preg->re_nsub++;
2450
2451 fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
2452
2453 /* The subexpression may be a null string. */
2454 if (token->type == OP_CLOSE_SUBEXP)
2455 tree = NULL;
2456 else
2457 {
2458 tree = parse_reg_exp (regexp, preg, token, syntax, nest, err);
2459 if (BE (*err == REG_NOERROR && token->type != OP_CLOSE_SUBEXP, 0))
2460 *err = REG_EPAREN;
2461 if (BE (*err != REG_NOERROR, 0))
2462 return NULL;
2463 }
2464
2465 if (cur_nsub <= '9' - '1')
2466 dfa->completed_bkref_map |= 1 << cur_nsub;
2467
2468 tree = create_tree (dfa, tree, NULL, SUBEXP);
2469 if (BE (tree == NULL, 0))
2470 {
2471 *err = REG_ESPACE;
2472 return NULL;
2473 }
2474 tree->token.opr.idx = cur_nsub;
2475 return tree;
2476}
2477
2478/* This function parse repetition operators like "*", "+", "{1,3}" etc. */
2479
2480static bin_tree_t *
2481parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa,
2482 re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err)
2483{
2484 bin_tree_t *tree = NULL, *old_tree = NULL;
2485 int i, start, end, start_idx = re_string_cur_idx (regexp);
2486#ifndef RE_TOKEN_INIT_BUG
2487 re_token_t start_token = *token;
2488#else
2489 re_token_t start_token;
2490
2491 memcpy ((void *) &start_token, (void *) token, sizeof start_token);
2492#endif
2493
2494 if (token->type == OP_OPEN_DUP_NUM)
2495 {
2496 end = 0;
2497 start = fetch_number (regexp, token, syntax);
2498 if (start == -1)
2499 {
2500 if (token->type == CHARACTER && token->opr.c == ',')
2501 start = 0; /* We treat "{,m}" as "{0,m}". */
2502 else
2503 {
2504 *err = REG_BADBR; /* <re>{} is invalid. */
2505 return NULL;
2506 }
2507 }
2508 if (BE (start != -2, 1))
2509 {
2510 /* We treat "{n}" as "{n,n}". */
2511 end = ((token->type == OP_CLOSE_DUP_NUM) ? start
2512 : ((token->type == CHARACTER && token->opr.c == ',')
2513 ? fetch_number (regexp, token, syntax) : -2));
2514 }
2515 if (BE (start == -2 || end == -2, 0))
2516 {
2517 /* Invalid sequence. */
2518 if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0))
2519 {
2520 if (token->type == END_OF_RE)
2521 *err = REG_EBRACE;
2522 else
2523 *err = REG_BADBR;
2524
2525 return NULL;
2526 }
2527
2528 /* If the syntax bit is set, rollback. */
2529 re_string_set_index (regexp, start_idx);
2530 *token = start_token;
2531 token->type = CHARACTER;
2532 /* mb_partial and word_char bits should be already initialized by
2533 peek_token. */
2534 return elem;
2535 }
2536
2537 if (BE ((end != -1 && start > end) || token->type != OP_CLOSE_DUP_NUM, 0))
2538 {
2539 /* First number greater than second. */
2540 *err = REG_BADBR;
2541 return NULL;
2542 }
2543 }
2544 else
2545 {
2546 start = (token->type == OP_DUP_PLUS) ? 1 : 0;
2547 end = (token->type == OP_DUP_QUESTION) ? 1 : -1;
2548 }
2549
2550 fetch_token (token, regexp, syntax);
2551
2552 if (BE (elem == NULL, 0))
2553 return NULL;
2554 if (BE (start == 0 && end == 0, 0))
2555 {
2556 postorder (elem, free_tree, NULL);
2557 return NULL;
2558 }
2559
2560 /* Extract "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */
2561 if (BE (start > 0, 0))
2562 {
2563 tree = elem;
2564 for (i = 2; i <= start; ++i)
2565 {
2566 elem = duplicate_tree (elem, dfa);
2567 tree = create_tree (dfa, tree, elem, CONCAT);
2568 if (BE (elem == NULL || tree == NULL, 0))
2569 goto parse_dup_op_espace;
2570 }
2571
2572 if (start == end)
2573 return tree;
2574
2575 /* Duplicate ELEM before it is marked optional. */
2576 elem = duplicate_tree (elem, dfa);
2577 old_tree = tree;
2578 }
2579 else
2580 old_tree = NULL;
2581
2582 if (elem->token.type == SUBEXP)
2583 postorder (elem, mark_opt_subexp, (void *) (intptr_t) elem->token.opr.idx);
2584
2585 tree = create_tree (dfa, elem, NULL, (end == -1 ? OP_DUP_ASTERISK : OP_ALT));
2586 if (BE (tree == NULL, 0))
2587 goto parse_dup_op_espace;
2588
2589 /* This loop is actually executed only when end != -1,
2590 to rewrite <re>{0,n} as (<re>(<re>...<re>?)?)?... We have
2591 already created the start+1-th copy. */
2592 for (i = start + 2; i <= end; ++i)
2593 {
2594 elem = duplicate_tree (elem, dfa);
2595 tree = create_tree (dfa, tree, elem, CONCAT);
2596 if (BE (elem == NULL || tree == NULL, 0))
2597 goto parse_dup_op_espace;
2598
2599 tree = create_tree (dfa, tree, NULL, OP_ALT);
2600 if (BE (tree == NULL, 0))
2601 goto parse_dup_op_espace;
2602 }
2603
2604 if (old_tree)
2605 tree = create_tree (dfa, old_tree, tree, CONCAT);
2606
2607 return tree;
2608
2609 parse_dup_op_espace:
2610 *err = REG_ESPACE;
2611 return NULL;
2612}
2613
2614/* Size of the names for collating symbol/equivalence_class/character_class.
2615 I'm not sure, but maybe enough. */
2616#define BRACKET_NAME_BUF_SIZE 32
2617
2618#ifndef _LIBC
2619 /* Local function for parse_bracket_exp only used in case of NOT _LIBC.
2620 Build the range expression which starts from START_ELEM, and ends
2621 at END_ELEM. The result are written to MBCSET and SBCSET.
2622 RANGE_ALLOC is the allocated size of mbcset->range_starts, and
2623 mbcset->range_ends, is a pointer argument since we may
2624 update it. */
2625
2626static reg_errcode_t
2627internal_function
2628# ifdef RE_ENABLE_I18N
2629build_range_exp (bitset_t sbcset, re_charset_t *mbcset, int *range_alloc,
2630 bracket_elem_t *start_elem, bracket_elem_t *end_elem)
2631# else /* not RE_ENABLE_I18N */
2632build_range_exp (bitset_t sbcset, bracket_elem_t *start_elem,
2633 bracket_elem_t *end_elem)
2634# endif /* not RE_ENABLE_I18N */
2635{
2636 unsigned int start_ch, end_ch;
2637 /* Equivalence Classes and Character Classes can't be a range start/end. */
2638 if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
2639 || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
2640 0))
2641 return REG_ERANGE;
2642
2643 /* We can handle no multi character collating elements without libc
2644 support. */
2645 if (BE ((start_elem->type == COLL_SYM
2646 && strlen ((char *) start_elem->opr.name) > 1)
2647 || (end_elem->type == COLL_SYM
2648 && strlen ((char *) end_elem->opr.name) > 1), 0))
2649 return REG_ECOLLATE;
2650
2651# ifdef RE_ENABLE_I18N
2652 {
2653 wchar_t wc;
2654 wint_t start_wc;
2655 wint_t end_wc;
2656 wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
2657
2658 start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch
2659 : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
2660 : 0));
2661 end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch
2662 : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
2663 : 0));
2664#ifdef GAWK
2665 /*
2666 * Fedora Core 2, maybe others, have broken `btowc' that returns -1
2667 * for any value > 127. Sigh. Note that `start_ch' and `end_ch' are
2668 * unsigned, so we don't have sign extension problems.
2669 */
2670 start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM)
2671 ? start_ch : start_elem->opr.wch);
2672 end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM)
2673 ? end_ch : end_elem->opr.wch);
2674#else
2675 start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM)
2676 ? __btowc (start_ch) : start_elem->opr.wch);
2677 end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM)
2678 ? __btowc (end_ch) : end_elem->opr.wch);
2679#endif
2680 if (start_wc == WEOF || end_wc == WEOF)
2681 return REG_ECOLLATE;
2682 cmp_buf[0] = start_wc;
2683 cmp_buf[4] = end_wc;
2684 if (wcscoll (cmp_buf, cmp_buf + 4) > 0)
2685 return REG_ERANGE;
2686
2687 /* Got valid collation sequence values, add them as a new entry.
2688 However, for !_LIBC we have no collation elements: if the
2689 character set is single byte, the single byte character set
2690 that we build below suffices. parse_bracket_exp passes
2691 no MBCSET if dfa->mb_cur_max == 1. */
2692 if (mbcset)
2693 {
2694 /* Check the space of the arrays. */
2695 if (BE (*range_alloc == mbcset->nranges, 0))
2696 {
2697 /* There is not enough space, need realloc. */
2698 wchar_t *new_array_start, *new_array_end;
2699 int new_nranges;
2700
2701 /* +1 in case of mbcset->nranges is 0. */
2702 new_nranges = 2 * mbcset->nranges + 1;
2703 /* Use realloc since mbcset->range_starts and mbcset->range_ends
2704 are NULL if *range_alloc == 0. */
2705 new_array_start = re_realloc (mbcset->range_starts, wchar_t,
2706 new_nranges);
2707 new_array_end = re_realloc (mbcset->range_ends, wchar_t,
2708 new_nranges);
2709
2710 if (BE (new_array_start == NULL || new_array_end == NULL, 0))
2711 return REG_ESPACE;
2712
2713 mbcset->range_starts = new_array_start;
2714 mbcset->range_ends = new_array_end;
2715 *range_alloc = new_nranges;
2716 }
2717
2718 mbcset->range_starts[mbcset->nranges] = start_wc;
2719 mbcset->range_ends[mbcset->nranges++] = end_wc;
2720 }
2721
2722 /* Build the table for single byte characters. */
2723 for (wc = 0; wc < SBC_MAX; ++wc)
2724 {
2725 cmp_buf[2] = wc;
2726 if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
2727 && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
2728 bitset_set (sbcset, wc);
2729 }
2730 }
2731# else /* not RE_ENABLE_I18N */
2732 {
2733 unsigned int ch;
2734 start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch
2735 : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
2736 : 0));
2737 end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch
2738 : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
2739 : 0));
2740 if (start_ch > end_ch)
2741 return REG_ERANGE;
2742 /* Build the table for single byte characters. */
2743 for (ch = 0; ch < SBC_MAX; ++ch)
2744 if (start_ch <= ch && ch <= end_ch)
2745 bitset_set (sbcset, ch);
2746 }
2747# endif /* not RE_ENABLE_I18N */
2748 return REG_NOERROR;
2749}
2750#endif /* not _LIBC */
2751
2752#ifndef _LIBC
2753/* Helper function for parse_bracket_exp only used in case of NOT _LIBC..
2754 Build the collating element which is represented by NAME.
2755 The result are written to MBCSET and SBCSET.
2756 COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
2757 pointer argument since we may update it. */
2758
2759static reg_errcode_t
2760internal_function
2761# ifdef RE_ENABLE_I18N
2762build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset,
2763 int *coll_sym_alloc, const unsigned char *name)
2764# else /* not RE_ENABLE_I18N */
2765build_collating_symbol (bitset_t sbcset, const unsigned char *name)
2766# endif /* not RE_ENABLE_I18N */
2767{
2768 size_t name_len = strlen ((const char *) name);
2769 if (BE (name_len != 1, 0))
2770 return REG_ECOLLATE;
2771 else
2772 {
2773 bitset_set (sbcset, name[0]);
2774 return REG_NOERROR;
2775 }
2776}
2777#endif /* not _LIBC */
2778
2779/* This function parse bracket expression like "[abc]", "[a-c]",
2780 "[[.a-a.]]" etc. */
2781
2782static bin_tree_t *
2783parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
2784 reg_syntax_t syntax, reg_errcode_t *err)
2785{
2786#ifdef _LIBC
2787 const unsigned char *collseqmb;
2788 const char *collseqwc;
2789 uint32_t nrules;
2790 int32_t table_size;
2791 const int32_t *symb_table;
2792 const unsigned char *extra;
2793
2794 /* Local function for parse_bracket_exp used in _LIBC environment.
2795 Seek the collating symbol entry correspondings to NAME.
2796 Return the index of the symbol in the SYMB_TABLE. */
2797
2798 auto inline int32_t
2799 __attribute ((always_inline))
2800 seek_collating_symbol_entry (name, name_len)
2801 const unsigned char *name;
2802 size_t name_len;
2803 {
2804 int32_t hash = elem_hash ((const char *) name, name_len);
2805 int32_t elem = hash % table_size;
2806 if (symb_table[2 * elem] != 0)
2807 {
2808 int32_t second = hash % (table_size - 2) + 1;
2809
2810 do
2811 {
2812 /* First compare the hashing value. */
2813 if (symb_table[2 * elem] == hash
2814 /* Compare the length of the name. */
2815 && name_len == extra[symb_table[2 * elem + 1]]
2816 /* Compare the name. */
2817 && memcmp (name, &extra[symb_table[2 * elem + 1] + 1],
2818 name_len) == 0)
2819 {
2820 /* Yep, this is the entry. */
2821 break;
2822 }
2823
2824 /* Next entry. */
2825 elem += second;
2826 }
2827 while (symb_table[2 * elem] != 0);
2828 }
2829 return elem;
2830 }
2831
2832 /* Local function for parse_bracket_exp used in _LIBC environment.
2833 Look up the collation sequence value of BR_ELEM.
2834 Return the value if succeeded, UINT_MAX otherwise. */
2835
2836 auto inline unsigned int
2837 __attribute ((always_inline))
2838 lookup_collation_sequence_value (br_elem)
2839 bracket_elem_t *br_elem;
2840 {
2841 if (br_elem->type == SB_CHAR)
2842 {
2843 /*
2844 if (MB_CUR_MAX == 1)
2845 */
2846 if (nrules == 0)
2847 return collseqmb[br_elem->opr.ch];
2848 else
2849 {
2850 wint_t wc = __btowc (br_elem->opr.ch);
2851 return __collseq_table_lookup (collseqwc, wc);
2852 }
2853 }
2854 else if (br_elem->type == MB_CHAR)
2855 {
2856 if (nrules != 0)
2857 return __collseq_table_lookup (collseqwc, br_elem->opr.wch);
2858 }
2859 else if (br_elem->type == COLL_SYM)
2860 {
2861 size_t sym_name_len = strlen ((char *) br_elem->opr.name);
2862 if (nrules != 0)
2863 {
2864 int32_t elem, idx;
2865 elem = seek_collating_symbol_entry (br_elem->opr.name,
2866 sym_name_len);
2867 if (symb_table[2 * elem] != 0)
2868 {
2869 /* We found the entry. */
2870 idx = symb_table[2 * elem + 1];
2871 /* Skip the name of collating element name. */
2872 idx += 1 + extra[idx];
2873 /* Skip the byte sequence of the collating element. */
2874 idx += 1 + extra[idx];
2875 /* Adjust for the alignment. */
2876 idx = (idx + 3) & ~3;
2877 /* Skip the multibyte collation sequence value. */
2878 idx += sizeof (unsigned int);
2879 /* Skip the wide char sequence of the collating element. */
2880 idx += sizeof (unsigned int) *
2881 (1 + *(unsigned int *) (extra + idx));
2882 /* Return the collation sequence value. */
2883 return *(unsigned int *) (extra + idx);
2884 }
2885 else if (symb_table[2 * elem] == 0 && sym_name_len == 1)
2886 {
2887 /* No valid character. Match it as a single byte
2888 character. */
2889 return collseqmb[br_elem->opr.name[0]];
2890 }
2891 }
2892 else if (sym_name_len == 1)
2893 return collseqmb[br_elem->opr.name[0]];
2894 }
2895 return UINT_MAX;
2896 }
2897
2898 /* Local function for parse_bracket_exp used in _LIBC environment.
2899 Build the range expression which starts from START_ELEM, and ends
2900 at END_ELEM. The result are written to MBCSET and SBCSET.
2901 RANGE_ALLOC is the allocated size of mbcset->range_starts, and
2902 mbcset->range_ends, is a pointer argument since we may
2903 update it. */
2904
2905 auto inline reg_errcode_t
2906 __attribute ((always_inline))
2907 build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem)
2908 re_charset_t *mbcset;
2909 int *range_alloc;
2910 bitset_t sbcset;
2911 bracket_elem_t *start_elem, *end_elem;
2912 {
2913 unsigned int ch;
2914 uint32_t start_collseq;
2915 uint32_t end_collseq;
2916
2917 /* Equivalence Classes and Character Classes can't be a range
2918 start/end. */
2919 if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
2920 || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
2921 0))
2922 return REG_ERANGE;
2923
2924 start_collseq = lookup_collation_sequence_value (start_elem);
2925 end_collseq = lookup_collation_sequence_value (end_elem);
2926 /* Check start/end collation sequence values. */
2927 if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0))
2928 return REG_ECOLLATE;
2929 if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0))
2930 return REG_ERANGE;
2931
2932 /* Got valid collation sequence values, add them as a new entry.
2933 However, if we have no collation elements, and the character set
2934 is single byte, the single byte character set that we
2935 build below suffices. */
2936 if (nrules > 0 || dfa->mb_cur_max > 1)
2937 {
2938 /* Check the space of the arrays. */
2939 if (BE (*range_alloc == mbcset->nranges, 0))
2940 {
2941 /* There is not enough space, need realloc. */
2942 uint32_t *new_array_start;
2943 uint32_t *new_array_end;
2944 int new_nranges;
2945
2946 /* +1 in case of mbcset->nranges is 0. */
2947 new_nranges = 2 * mbcset->nranges + 1;
2948 new_array_start = re_realloc (mbcset->range_starts, uint32_t,
2949 new_nranges);
2950 new_array_end = re_realloc (mbcset->range_ends, uint32_t,
2951 new_nranges);
2952
2953 if (BE (new_array_start == NULL || new_array_end == NULL, 0))
2954 return REG_ESPACE;
2955
2956 mbcset->range_starts = new_array_start;
2957 mbcset->range_ends = new_array_end;
2958 *range_alloc = new_nranges;
2959 }
2960
2961 mbcset->range_starts[mbcset->nranges] = start_collseq;
2962 mbcset->range_ends[mbcset->nranges++] = end_collseq;
2963 }
2964
2965 /* Build the table for single byte characters. */
2966 for (ch = 0; ch < SBC_MAX; ch++)
2967 {
2968 uint32_t ch_collseq;
2969 /*
2970 if (MB_CUR_MAX == 1)
2971 */
2972 if (nrules == 0)
2973 ch_collseq = collseqmb[ch];
2974 else
2975 ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch));
2976 if (start_collseq <= ch_collseq && ch_collseq <= end_collseq)
2977 bitset_set (sbcset, ch);
2978 }
2979 return REG_NOERROR;
2980 }
2981
2982 /* Local function for parse_bracket_exp used in _LIBC environment.
2983 Build the collating element which is represented by NAME.
2984 The result are written to MBCSET and SBCSET.
2985 COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
2986 pointer argument since we may update it. */
2987
2988 auto inline reg_errcode_t
2989 __attribute ((always_inline))
2990 build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name)
2991 re_charset_t *mbcset;
2992 int *coll_sym_alloc;
2993 bitset_t sbcset;
2994 const unsigned char *name;
2995 {
2996 int32_t elem, idx;
2997 size_t name_len = strlen ((const char *) name);
2998 if (nrules != 0)
2999 {
3000 elem = seek_collating_symbol_entry (name, name_len);
3001 if (symb_table[2 * elem] != 0)
3002 {
3003 /* We found the entry. */
3004 idx = symb_table[2 * elem + 1];
3005 /* Skip the name of collating element name. */
3006 idx += 1 + extra[idx];
3007 }
3008 else if (symb_table[2 * elem] == 0 && name_len == 1)
3009 {
3010 /* No valid character, treat it as a normal
3011 character. */
3012 bitset_set (sbcset, name[0]);
3013 return REG_NOERROR;
3014 }
3015 else
3016 return REG_ECOLLATE;
3017
3018 /* Got valid collation sequence, add it as a new entry. */
3019 /* Check the space of the arrays. */
3020 if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0))
3021 {
3022 /* Not enough, realloc it. */
3023 /* +1 in case of mbcset->ncoll_syms is 0. */
3024 int new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1;
3025 /* Use realloc since mbcset->coll_syms is NULL
3026 if *alloc == 0. */
3027 int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t,
3028 new_coll_sym_alloc);
3029 if (BE (new_coll_syms == NULL, 0))
3030 return REG_ESPACE;
3031 mbcset->coll_syms = new_coll_syms;
3032 *coll_sym_alloc = new_coll_sym_alloc;
3033 }
3034 mbcset->coll_syms[mbcset->ncoll_syms++] = idx;
3035 return REG_NOERROR;
3036 }
3037 else
3038 {
3039 if (BE (name_len != 1, 0))
3040 return REG_ECOLLATE;
3041 else
3042 {
3043 bitset_set (sbcset, name[0]);
3044 return REG_NOERROR;
3045 }
3046 }
3047 }
3048#endif
3049
3050 re_token_t br_token;
3051 re_bitset_ptr_t sbcset;
3052#ifdef RE_ENABLE_I18N
3053 re_charset_t *mbcset;
3054 int coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0;
3055 int equiv_class_alloc = 0, char_class_alloc = 0;
3056#endif /* not RE_ENABLE_I18N */
3057 int non_match = 0;
3058 bin_tree_t *work_tree;
3059 int token_len;
3060 int first_round = 1;
3061#ifdef _LIBC
3062 collseqmb = (const unsigned char *)
3063 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
3064 nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
3065 if (nrules)
3066 {
3067 /*
3068 if (MB_CUR_MAX > 1)
3069 */
3070 collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
3071 table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB);
3072 symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE,
3073 _NL_COLLATE_SYMB_TABLEMB);
3074 extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
3075 _NL_COLLATE_SYMB_EXTRAMB);
3076 }
3077#endif
3078 sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
3079#ifdef RE_ENABLE_I18N
3080 mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
3081#endif /* RE_ENABLE_I18N */
3082#ifdef RE_ENABLE_I18N
3083 if (BE (sbcset == NULL || mbcset == NULL, 0))
3084#else
3085 if (BE (sbcset == NULL, 0))
3086#endif /* RE_ENABLE_I18N */
3087 {
3088 *err = REG_ESPACE;
3089 return NULL;
3090 }
3091
3092 token_len = peek_token_bracket (token, regexp, syntax);
3093 if (BE (token->type == END_OF_RE, 0))
3094 {
3095 *err = REG_BADPAT;
3096 goto parse_bracket_exp_free_return;
3097 }
3098 if (token->type == OP_NON_MATCH_LIST)
3099 {
3100#ifdef RE_ENABLE_I18N
3101 mbcset->non_match = 1;
3102#endif /* not RE_ENABLE_I18N */
3103 non_match = 1;
3104 if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
3105 bitset_set (sbcset, '\n');
3106 re_string_skip_bytes (regexp, token_len); /* Skip a token. */
3107 token_len = peek_token_bracket (token, regexp, syntax);
3108 if (BE (token->type == END_OF_RE, 0))
3109 {
3110 *err = REG_BADPAT;
3111 goto parse_bracket_exp_free_return;
3112 }
3113 }
3114
3115 /* We treat the first ']' as a normal character. */
3116 if (token->type == OP_CLOSE_BRACKET)
3117 token->type = CHARACTER;
3118
3119 while (1)
3120 {
3121 bracket_elem_t start_elem, end_elem;
3122 unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE];
3123 unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE];
3124 reg_errcode_t ret;
3125 int token_len2 = 0, is_range_exp = 0;
3126 re_token_t token2;
3127
3128 start_elem.opr.name = start_name_buf;
3129 ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa,
3130 syntax, first_round);
3131 if (BE (ret != REG_NOERROR, 0))
3132 {
3133 *err = ret;
3134 goto parse_bracket_exp_free_return;
3135 }
3136 first_round = 0;
3137
3138 /* Get information about the next token. We need it in any case. */
3139 token_len = peek_token_bracket (token, regexp, syntax);
3140
3141 /* Do not check for ranges if we know they are not allowed. */
3142 if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS)
3143 {
3144 if (BE (token->type == END_OF_RE, 0))
3145 {
3146 *err = REG_EBRACK;
3147 goto parse_bracket_exp_free_return;
3148 }
3149 if (token->type == OP_CHARSET_RANGE)
3150 {
3151 re_string_skip_bytes (regexp, token_len); /* Skip '-'. */
3152 token_len2 = peek_token_bracket (&token2, regexp, syntax);
3153 if (BE (token2.type == END_OF_RE, 0))
3154 {
3155 *err = REG_EBRACK;
3156 goto parse_bracket_exp_free_return;
3157 }
3158 if (token2.type == OP_CLOSE_BRACKET)
3159 {
3160 /* We treat the last '-' as a normal character. */
3161 re_string_skip_bytes (regexp, -token_len);
3162 token->type = CHARACTER;
3163 }
3164 else
3165 is_range_exp = 1;
3166 }
3167 }
3168
3169 if (is_range_exp == 1)
3170 {
3171 end_elem.opr.name = end_name_buf;
3172 ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2,
3173 dfa, syntax, 1);
3174 if (BE (ret != REG_NOERROR, 0))
3175 {
3176 *err = ret;
3177 goto parse_bracket_exp_free_return;
3178 }
3179
3180 token_len = peek_token_bracket (token, regexp, syntax);
3181
3182#ifdef _LIBC
3183 *err = build_range_exp (sbcset, mbcset, &range_alloc,
3184 &start_elem, &end_elem);
3185#else
3186# ifdef RE_ENABLE_I18N
3187 *err = build_range_exp (sbcset,
3188 dfa->mb_cur_max > 1 ? mbcset : NULL,
3189 &range_alloc, &start_elem, &end_elem);
3190# else
3191 *err = build_range_exp (sbcset, &start_elem, &end_elem);
3192# endif
3193#endif /* RE_ENABLE_I18N */
3194 if (BE (*err != REG_NOERROR, 0))
3195 goto parse_bracket_exp_free_return;
3196 }
3197 else
3198 {
3199 switch (start_elem.type)
3200 {
3201 case SB_CHAR:
3202 bitset_set (sbcset, start_elem.opr.ch);
3203 break;
3204#ifdef RE_ENABLE_I18N
3205 case MB_CHAR:
3206 /* Check whether the array has enough space. */
3207 if (BE (mbchar_alloc == mbcset->nmbchars, 0))
3208 {
3209 wchar_t *new_mbchars;
3210 /* Not enough, realloc it. */
3211 /* +1 in case of mbcset->nmbchars is 0. */
3212 mbchar_alloc = 2 * mbcset->nmbchars + 1;
3213 /* Use realloc since array is NULL if *alloc == 0. */
3214 new_mbchars = re_realloc (mbcset->mbchars, wchar_t,
3215 mbchar_alloc);
3216 if (BE (new_mbchars == NULL, 0))
3217 goto parse_bracket_exp_espace;
3218 mbcset->mbchars = new_mbchars;
3219 }
3220 mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch;
3221 break;
3222#endif /* RE_ENABLE_I18N */
3223 case EQUIV_CLASS:
3224 *err = build_equiv_class (sbcset,
3225#ifdef RE_ENABLE_I18N
3226 mbcset, &equiv_class_alloc,
3227#endif /* RE_ENABLE_I18N */
3228 start_elem.opr.name);
3229 if (BE (*err != REG_NOERROR, 0))
3230 goto parse_bracket_exp_free_return;
3231 break;
3232 case COLL_SYM:
3233 *err = build_collating_symbol (sbcset,
3234#ifdef RE_ENABLE_I18N
3235 mbcset, &coll_sym_alloc,
3236#endif /* RE_ENABLE_I18N */
3237 start_elem.opr.name);
3238 if (BE (*err != REG_NOERROR, 0))
3239 goto parse_bracket_exp_free_return;
3240 break;
3241 case CHAR_CLASS:
3242 *err = build_charclass (regexp->trans, sbcset,
3243#ifdef RE_ENABLE_I18N
3244 mbcset, &char_class_alloc,
3245#endif /* RE_ENABLE_I18N */
3246 (const char *) start_elem.opr.name, syntax);
3247 if (BE (*err != REG_NOERROR, 0))
3248 goto parse_bracket_exp_free_return;
3249 break;
3250 default:
3251 assert (0);
3252 break;
3253 }
3254 }
3255 if (BE (token->type == END_OF_RE, 0))
3256 {
3257 *err = REG_EBRACK;
3258 goto parse_bracket_exp_free_return;
3259 }
3260 if (token->type == OP_CLOSE_BRACKET)
3261 break;
3262 }
3263
3264 re_string_skip_bytes (regexp, token_len); /* Skip a token. */
3265
3266 /* If it is non-matching list. */
3267 if (non_match)
3268 bitset_not (sbcset);
3269
3270#ifdef RE_ENABLE_I18N
3271 /* Ensure only single byte characters are set. */
3272 if (dfa->mb_cur_max > 1)
3273 bitset_mask (sbcset, dfa->sb_char);
3274
3275 if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes
3276 || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes
3277 || mbcset->non_match)))
3278 {
3279 bin_tree_t *mbc_tree;
3280 int sbc_idx;
3281 /* Build a tree for complex bracket. */
3282 dfa->has_mb_node = 1;
3283 br_token.type = COMPLEX_BRACKET;
3284 br_token.opr.mbcset = mbcset;
3285 mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
3286 if (BE (mbc_tree == NULL, 0))
3287 goto parse_bracket_exp_espace;
3288 for (sbc_idx = 0; sbc_idx < BITSET_WORDS; ++sbc_idx)
3289 if (sbcset[sbc_idx])
3290 break;
3291 /* If there are no bits set in sbcset, there is no point
3292 of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */
3293 if (sbc_idx < BITSET_WORDS)
3294 {
3295 /* Build a tree for simple bracket. */
3296 br_token.type = SIMPLE_BRACKET;
3297 br_token.opr.sbcset = sbcset;
3298 work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
3299 if (BE (work_tree == NULL, 0))
3300 goto parse_bracket_exp_espace;
3301
3302 /* Then join them by ALT node. */
3303 work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT);
3304 if (BE (work_tree == NULL, 0))
3305 goto parse_bracket_exp_espace;
3306 }
3307 else
3308 {
3309 re_free (sbcset);
3310 work_tree = mbc_tree;
3311 }
3312 }
3313 else
3314#endif /* not RE_ENABLE_I18N */
3315 {
3316#ifdef RE_ENABLE_I18N
3317 free_charset (mbcset);
3318#endif
3319 /* Build a tree for simple bracket. */
3320 br_token.type = SIMPLE_BRACKET;
3321 br_token.opr.sbcset = sbcset;
3322 work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
3323 if (BE (work_tree == NULL, 0))
3324 goto parse_bracket_exp_espace;
3325 }
3326 return work_tree;
3327
3328 parse_bracket_exp_espace:
3329 *err = REG_ESPACE;
3330 parse_bracket_exp_free_return:
3331 re_free (sbcset);
3332#ifdef RE_ENABLE_I18N
3333 free_charset (mbcset);
3334#endif /* RE_ENABLE_I18N */
3335 return NULL;
3336}
3337
3338/* Parse an element in the bracket expression. */
3339
3340static reg_errcode_t
3341parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp,
3342 re_token_t *token, int token_len,
3343 UNUSED_PARAM re_dfa_t *dfa, reg_syntax_t syntax,
3344 int accept_hyphen)
3345{
3346#ifdef RE_ENABLE_I18N
3347 int cur_char_size;
3348 cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp));
3349 if (cur_char_size > 1)
3350 {
3351 elem->type = MB_CHAR;
3352 elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp));
3353 re_string_skip_bytes (regexp, cur_char_size);
3354 return REG_NOERROR;
3355 }
3356#endif /* RE_ENABLE_I18N */
3357 re_string_skip_bytes (regexp, token_len); /* Skip a token. */
3358 if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS
3359 || token->type == OP_OPEN_EQUIV_CLASS)
3360 return parse_bracket_symbol (elem, regexp, token);
3361 if (BE (token->type == OP_CHARSET_RANGE, 0) && !accept_hyphen)
3362 {
3363 /* A '-' must only appear as anything but a range indicator before
3364 the closing bracket. Everything else is an error. */
3365 re_token_t token2;
3366 (void) peek_token_bracket (&token2, regexp, syntax);
3367 if (token2.type != OP_CLOSE_BRACKET)
3368 /* The actual error value is not standardized since this whole
3369 case is undefined. But ERANGE makes good sense. */
3370 return REG_ERANGE;
3371 }
3372 elem->type = SB_CHAR;
3373 elem->opr.ch = token->opr.c;
3374 return REG_NOERROR;
3375}
3376
3377/* Parse a bracket symbol in the bracket expression. Bracket symbols are
3378 such as [:<character_class>:], [.<collating_element>.], and
3379 [=<equivalent_class>=]. */
3380
3381static reg_errcode_t
3382parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp,
3383 re_token_t *token)
3384{
3385 unsigned char ch, delim = token->opr.c;
3386 int i = 0;
3387 if (re_string_eoi(regexp))
3388 return REG_EBRACK;
3389 for (;; ++i)
3390 {
3391 if (i >= BRACKET_NAME_BUF_SIZE)
3392 return REG_EBRACK;
3393 if (token->type == OP_OPEN_CHAR_CLASS)
3394 ch = re_string_fetch_byte_case (regexp);
3395 else
3396 ch = re_string_fetch_byte (regexp);
3397 if (re_string_eoi(regexp))
3398 return REG_EBRACK;
3399 if (ch == delim && re_string_peek_byte (regexp, 0) == ']')
3400 break;
3401 elem->opr.name[i] = ch;
3402 }
3403 re_string_skip_bytes (regexp, 1);
3404 elem->opr.name[i] = '\0';
3405 switch (token->type)
3406 {
3407 case OP_OPEN_COLL_ELEM:
3408 elem->type = COLL_SYM;
3409 break;
3410 case OP_OPEN_EQUIV_CLASS:
3411 elem->type = EQUIV_CLASS;
3412 break;
3413 case OP_OPEN_CHAR_CLASS:
3414 elem->type = CHAR_CLASS;
3415 break;
3416 default:
3417 break;
3418 }
3419 return REG_NOERROR;
3420}
3421
3422 /* Helper function for parse_bracket_exp.
3423 Build the equivalence class which is represented by NAME.
3424 The result are written to MBCSET and SBCSET.
3425 EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes,
3426 is a pointer argument since we may update it. */
3427
3428static reg_errcode_t
3429#ifdef RE_ENABLE_I18N
3430build_equiv_class (bitset_t sbcset, re_charset_t *mbcset,
3431 int *equiv_class_alloc, const unsigned char *name)
3432#else /* not RE_ENABLE_I18N */
3433build_equiv_class (bitset_t sbcset, const unsigned char *name)
3434#endif /* not RE_ENABLE_I18N */
3435{
3436#ifdef _LIBC
3437 uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
3438 if (nrules != 0)
3439 {
3440 const int32_t *table, *indirect;
3441 const unsigned char *weights, *extra, *cp;
3442 unsigned char char_buf[2];
3443 int32_t idx1, idx2;
3444 unsigned int ch;
3445 size_t len;
3446 /* This #include defines a local function! */
3447# include <locale/weight.h>
3448 /* Calculate the index for equivalence class. */
3449 cp = name;
3450 table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
3451 weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
3452 _NL_COLLATE_WEIGHTMB);
3453 extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
3454 _NL_COLLATE_EXTRAMB);
3455 indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
3456 _NL_COLLATE_INDIRECTMB);
3457 idx1 = findidx (&cp);
3458 if (BE (idx1 == 0 || cp < name + strlen ((const char *) name), 0))
3459 /* This isn't a valid character. */
3460 return REG_ECOLLATE;
3461
3462 /* Build single byte matcing table for this equivalence class. */
3463 char_buf[1] = (unsigned char) '\0';
3464 len = weights[idx1 & 0xffffff];
3465 for (ch = 0; ch < SBC_MAX; ++ch)
3466 {
3467 char_buf[0] = ch;
3468 cp = char_buf;
3469 idx2 = findidx (&cp);
3470/*
3471 idx2 = table[ch];
3472*/
3473 if (idx2 == 0)
3474 /* This isn't a valid character. */
3475 continue;
3476 /* Compare only if the length matches and the collation rule
3477 index is the same. */
3478 if (len == weights[idx2 & 0xffffff] && (idx1 >> 24) == (idx2 >> 24))
3479 {
3480 int cnt = 0;
3481
3482 while (cnt <= len &&
3483 weights[(idx1 & 0xffffff) + 1 + cnt]
3484 == weights[(idx2 & 0xffffff) + 1 + cnt])
3485 ++cnt;
3486
3487 if (cnt > len)
3488 bitset_set (sbcset, ch);
3489 }
3490 }
3491 /* Check whether the array has enough space. */
3492 if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0))
3493 {
3494 /* Not enough, realloc it. */
3495 /* +1 in case of mbcset->nequiv_classes is 0. */
3496 int new_equiv_class_alloc = 2 * mbcset->nequiv_classes + 1;
3497 /* Use realloc since the array is NULL if *alloc == 0. */
3498 int32_t *new_equiv_classes = re_realloc (mbcset->equiv_classes,
3499 int32_t,
3500 new_equiv_class_alloc);
3501 if (BE (new_equiv_classes == NULL, 0))
3502 return REG_ESPACE;
3503 mbcset->equiv_classes = new_equiv_classes;
3504 *equiv_class_alloc = new_equiv_class_alloc;
3505 }
3506 mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1;
3507 }
3508 else
3509#endif /* _LIBC */
3510 {
3511 if (BE (strlen ((const char *) name) != 1, 0))
3512 return REG_ECOLLATE;
3513 bitset_set (sbcset, *name);
3514 }
3515 return REG_NOERROR;
3516}
3517
3518 /* Helper function for parse_bracket_exp.
3519 Build the character class which is represented by NAME.
3520 The result are written to MBCSET and SBCSET.
3521 CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes,
3522 is a pointer argument since we may update it. */
3523
3524static reg_errcode_t
3525#ifdef RE_ENABLE_I18N
3526build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
3527 re_charset_t *mbcset, int *char_class_alloc,
3528 const char *class_name, reg_syntax_t syntax)
3529#else /* not RE_ENABLE_I18N */
3530build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
3531 const char *class_name, reg_syntax_t syntax)
3532#endif /* not RE_ENABLE_I18N */
3533{
3534 int i;
3535
3536 /* In case of REG_ICASE "upper" and "lower" match the both of
3537 upper and lower cases. */
3538 if ((syntax & RE_ICASE)
3539 && (strcmp (class_name, "upper") == 0 || strcmp (class_name, "lower") == 0))
3540 class_name = "alpha";
3541
3542#ifdef RE_ENABLE_I18N
3543 /* Check the space of the arrays. */
3544 if (BE (*char_class_alloc == mbcset->nchar_classes, 0))
3545 {
3546 /* Not enough, realloc it. */
3547 /* +1 in case of mbcset->nchar_classes is 0. */
3548 int new_char_class_alloc = 2 * mbcset->nchar_classes + 1;
3549 /* Use realloc since array is NULL if *alloc == 0. */
3550 wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t,
3551 new_char_class_alloc);
3552 if (BE (new_char_classes == NULL, 0))
3553 return REG_ESPACE;
3554 mbcset->char_classes = new_char_classes;
3555 *char_class_alloc = new_char_class_alloc;
3556 }
3557 mbcset->char_classes[mbcset->nchar_classes++] = __wctype (class_name);
3558#endif /* RE_ENABLE_I18N */
3559
3560#define BUILD_CHARCLASS_LOOP(ctype_func) \
3561 do { \
3562 if (BE (trans != NULL, 0)) \
3563 { \
3564 for (i = 0; i < SBC_MAX; ++i) \
3565 if (ctype_func (i)) \
3566 bitset_set (sbcset, trans[i]); \
3567 } \
3568 else \
3569 { \
3570 for (i = 0; i < SBC_MAX; ++i) \
3571 if (ctype_func (i)) \
3572 bitset_set (sbcset, i); \
3573 } \
3574 } while (0)
3575
3576#if 0
3577 if (strcmp (class_name, "alnum") == 0)
3578 BUILD_CHARCLASS_LOOP (isalnum);
3579 else if (strcmp (class_name, "cntrl") == 0)
3580 BUILD_CHARCLASS_LOOP (iscntrl);
3581 else if (strcmp (class_name, "lower") == 0)
3582 BUILD_CHARCLASS_LOOP (islower);
3583 else if (strcmp (class_name, "space") == 0)
3584 BUILD_CHARCLASS_LOOP (isspace);
3585 else if (strcmp (class_name, "alpha") == 0)
3586 BUILD_CHARCLASS_LOOP (isalpha);
3587 else if (strcmp (class_name, "digit") == 0)
3588 BUILD_CHARCLASS_LOOP (isdigit);
3589 else if (strcmp (class_name, "print") == 0)
3590 BUILD_CHARCLASS_LOOP (isprint);
3591 else if (strcmp (class_name, "upper") == 0)
3592 BUILD_CHARCLASS_LOOP (isupper);
3593 else if (strcmp (class_name, "blank") == 0)
3594#ifndef GAWK
3595 BUILD_CHARCLASS_LOOP (isblank);
3596#else
3597 /* see comments above */
3598 BUILD_CHARCLASS_LOOP (is_blank);
3599#endif
3600 else if (strcmp (class_name, "graph") == 0)
3601 BUILD_CHARCLASS_LOOP (isgraph);
3602 else if (strcmp (class_name, "punct") == 0)
3603 BUILD_CHARCLASS_LOOP (ispunct);
3604 else if (strcmp (class_name, "xdigit") == 0)
3605 BUILD_CHARCLASS_LOOP (isxdigit);
3606 else
3607 return REG_ECTYPE;
3608#else
3609 switch (match_class(class_name)) {
3610 case CCLASS_ALNUM:
3611 BUILD_CHARCLASS_LOOP (isalnum);
3612 break;
3613 case CCLASS_CNTRL:
3614 BUILD_CHARCLASS_LOOP (iscntrl);
3615 break;
3616 case CCLASS_LOWER:
3617 BUILD_CHARCLASS_LOOP (islower);
3618 break;
3619 case CCLASS_SPACE:
3620 BUILD_CHARCLASS_LOOP (isspace);
3621 break;
3622 case CCLASS_ALPHA:
3623 BUILD_CHARCLASS_LOOP (isalpha);
3624 break;
3625 case CCLASS_DIGIT:
3626 BUILD_CHARCLASS_LOOP (isdigit);
3627 break;
3628 case CCLASS_PRINT:
3629 BUILD_CHARCLASS_LOOP (isprint);
3630 break;
3631 case CCLASS_UPPER:
3632 BUILD_CHARCLASS_LOOP (isupper);
3633 break;
3634 case CCLASS_BLANK:
3635#ifndef GAWK
3636 BUILD_CHARCLASS_LOOP (isblank);
3637#else
3638 /* see comments above */
3639 BUILD_CHARCLASS_LOOP (is_blank);
3640#endif
3641 break;
3642 case CCLASS_GRAPH:
3643 BUILD_CHARCLASS_LOOP (isgraph);
3644 break;
3645 case CCLASS_PUNCT:
3646 BUILD_CHARCLASS_LOOP (ispunct);
3647 break;
3648 case CCLASS_XDIGIT:
3649 BUILD_CHARCLASS_LOOP (isxdigit);
3650 break;
3651 default:
3652 return REG_ECTYPE;
3653 }
3654#endif
3655
3656 return REG_NOERROR;
3657}
3658
3659static bin_tree_t *
3660build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans,
3661 const char *class_name,
3662 const char *extra, int non_match,
3663 reg_errcode_t *err)
3664{
3665 re_bitset_ptr_t sbcset;
3666#ifdef RE_ENABLE_I18N
3667 re_charset_t *mbcset;
3668 int alloc = 0;
3669#endif /* not RE_ENABLE_I18N */
3670 reg_errcode_t ret;
3671 re_token_t br_token;
3672 bin_tree_t *tree;
3673
3674 sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
3675#ifdef RE_ENABLE_I18N
3676 mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
3677#endif /* RE_ENABLE_I18N */
3678
3679#ifdef RE_ENABLE_I18N
3680 if (BE (sbcset == NULL || mbcset == NULL, 0))
3681#else /* not RE_ENABLE_I18N */
3682 if (BE (sbcset == NULL, 0))
3683#endif /* not RE_ENABLE_I18N */
3684 {
3685 *err = REG_ESPACE;
3686 return NULL;
3687 }
3688
3689 if (non_match)
3690 {
3691#ifdef RE_ENABLE_I18N
3692 mbcset->non_match = 1;
3693#endif /* not RE_ENABLE_I18N */
3694 }
3695
3696 /* We don't care the syntax in this case. */
3697 ret = build_charclass (trans, sbcset,
3698#ifdef RE_ENABLE_I18N
3699 mbcset, &alloc,
3700#endif /* RE_ENABLE_I18N */
3701 class_name, 0);
3702
3703 if (BE (ret != REG_NOERROR, 0))
3704 {
3705 re_free (sbcset);
3706#ifdef RE_ENABLE_I18N
3707 free_charset (mbcset);
3708#endif /* RE_ENABLE_I18N */
3709 *err = ret;
3710 return NULL;
3711 }
3712 /* \w match '_' also. */
3713 for (; *extra; extra++)
3714 bitset_set (sbcset, *extra);
3715
3716 /* If it is non-matching list. */
3717 if (non_match)
3718 bitset_not (sbcset);
3719
3720#ifdef RE_ENABLE_I18N
3721 /* Ensure only single byte characters are set. */
3722 if (dfa->mb_cur_max > 1)
3723 bitset_mask (sbcset, dfa->sb_char);
3724#endif
3725
3726 /* Build a tree for simple bracket. */
3727 br_token.type = SIMPLE_BRACKET;
3728 br_token.opr.sbcset = sbcset;
3729 tree = create_token_tree (dfa, NULL, NULL, &br_token);
3730 if (BE (tree == NULL, 0))
3731 goto build_word_op_espace;
3732
3733#ifdef RE_ENABLE_I18N
3734 if (dfa->mb_cur_max > 1)
3735 {
3736 bin_tree_t *mbc_tree;
3737 /* Build a tree for complex bracket. */
3738 br_token.type = COMPLEX_BRACKET;
3739 br_token.opr.mbcset = mbcset;
3740 dfa->has_mb_node = 1;
3741 mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
3742 if (BE (mbc_tree == NULL, 0))
3743 goto build_word_op_espace;
3744 /* Then join them by ALT node. */
3745 tree = create_tree (dfa, tree, mbc_tree, OP_ALT);
3746 if (BE (mbc_tree != NULL, 1))
3747 return tree;
3748 }
3749 else
3750 {
3751 free_charset (mbcset);
3752 return tree;
3753 }
3754#else /* not RE_ENABLE_I18N */
3755 return tree;
3756#endif /* not RE_ENABLE_I18N */
3757
3758 build_word_op_espace:
3759 re_free (sbcset);
3760#ifdef RE_ENABLE_I18N
3761 free_charset (mbcset);
3762#endif /* RE_ENABLE_I18N */
3763 *err = REG_ESPACE;
3764 return NULL;
3765}
3766
3767/* This is intended for the expressions like "a{1,3}".
3768 Fetch a number from `input', and return the number.
3769 Return -1, if the number field is empty like "{,1}".
3770 Return -2, if an error has occurred. */
3771
3772static int
3773fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax)
3774{
3775 int num = -1;
3776 unsigned char c;
3777 while (1)
3778 {
3779 fetch_token (token, input, syntax);
3780 c = token->opr.c;
3781 if (BE (token->type == END_OF_RE, 0))
3782 return -2;
3783 if (token->type == OP_CLOSE_DUP_NUM || c == ',')
3784 break;
3785 num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2)
3786 ? -2 : ((num == -1) ? c - '0' : num * 10 + c - '0'));
3787 num = (num > RE_DUP_MAX) ? -2 : num;
3788 }
3789 return num;
3790}
3791
3792#ifdef RE_ENABLE_I18N
3793static void
3794free_charset (re_charset_t *cset)
3795{
3796 re_free (cset->mbchars);
3797# ifdef _LIBC
3798 re_free (cset->coll_syms);
3799 re_free (cset->equiv_classes);
3800 re_free (cset->range_starts);
3801 re_free (cset->range_ends);
3802# endif
3803 re_free (cset->char_classes);
3804 re_free (cset);
3805}
3806#endif /* RE_ENABLE_I18N */
3807
3808/* Functions for binary tree operation. */
3809
3810/* Create a tree node. */
3811
3812static bin_tree_t *
3813create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
3814 re_token_type_t type)
3815{
3816 re_token_t t;
3817 t.type = type;
3818 return create_token_tree (dfa, left, right, &t);
3819}
3820
3821static bin_tree_t *
3822create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
3823 const re_token_t *token)
3824{
3825 bin_tree_t *tree;
3826 if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0))
3827 {
3828 bin_tree_storage_t *storage = re_malloc (bin_tree_storage_t, 1);
3829
3830 if (storage == NULL)
3831 return NULL;
3832 storage->next = dfa->str_tree_storage;
3833 dfa->str_tree_storage = storage;
3834 dfa->str_tree_storage_idx = 0;
3835 }
3836 tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++];
3837
3838 tree->parent = NULL;
3839 tree->left = left;
3840 tree->right = right;
3841 tree->token = *token;
3842 tree->token.duplicated = 0;
3843 tree->token.opt_subexp = 0;
3844 tree->first = NULL;
3845 tree->next = NULL;
3846 tree->node_idx = -1;
3847
3848 if (left != NULL)
3849 left->parent = tree;
3850 if (right != NULL)
3851 right->parent = tree;
3852 return tree;
3853}
3854
3855/* Mark the tree SRC as an optional subexpression.
3856 To be called from preorder or postorder. */
3857
3858static reg_errcode_t
3859mark_opt_subexp (void *extra, bin_tree_t *node)
3860{
3861 int idx = (int) (intptr_t) extra;
3862 if (node->token.type == SUBEXP && node->token.opr.idx == idx)
3863 node->token.opt_subexp = 1;
3864
3865 return REG_NOERROR;
3866}
3867
3868/* Free the allocated memory inside NODE. */
3869
3870static void
3871free_token (re_token_t *node)
3872{
3873#ifdef RE_ENABLE_I18N
3874 if (node->type == COMPLEX_BRACKET && node->duplicated == 0)
3875 free_charset (node->opr.mbcset);
3876 else
3877#endif /* RE_ENABLE_I18N */
3878 if (node->type == SIMPLE_BRACKET && node->duplicated == 0)
3879 re_free (node->opr.sbcset);
3880}
3881
3882/* Worker function for tree walking. Free the allocated memory inside NODE
3883 and its children. */
3884
3885static reg_errcode_t
3886free_tree (UNUSED_PARAM void *extra, bin_tree_t *node)
3887{
3888 free_token (&node->token);
3889 return REG_NOERROR;
3890}
3891
3892
3893/* Duplicate the node SRC, and return new node. This is a preorder
3894 visit similar to the one implemented by the generic visitor, but
3895 we need more infrastructure to maintain two parallel trees --- so,
3896 it's easier to duplicate. */
3897
3898static bin_tree_t *
3899duplicate_tree (const bin_tree_t *root, re_dfa_t *dfa)
3900{
3901 const bin_tree_t *node;
3902 bin_tree_t *dup_root;
3903 bin_tree_t **p_new = &dup_root, *dup_node = root->parent;
3904
3905 for (node = root; ; )
3906 {
3907 /* Create a new tree and link it back to the current parent. */
3908 *p_new = create_token_tree (dfa, NULL, NULL, &node->token);
3909 if (*p_new == NULL)
3910 return NULL;
3911 (*p_new)->parent = dup_node;
3912 (*p_new)->token.duplicated = 1;
3913 dup_node = *p_new;
3914
3915 /* Go to the left node, or up and to the right. */
3916 if (node->left)
3917 {
3918 node = node->left;
3919 p_new = &dup_node->left;
3920 }
3921 else
3922 {
3923 const bin_tree_t *prev = NULL;
3924 while (node->right == prev || node->right == NULL)
3925 {
3926 prev = node;
3927 node = node->parent;
3928 dup_node = dup_node->parent;
3929 if (!node)
3930 return dup_root;
3931 }
3932 node = node->right;
3933 p_new = &dup_node->right;
3934 }
3935 }
3936}
diff --git a/win32/regex.c b/win32/regex.c
new file mode 100644
index 000000000..e40a2ea01
--- /dev/null
+++ b/win32/regex.c
@@ -0,0 +1,90 @@
1/* Extended regular expression matching and search library.
2 Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA. */
20
21#define HAVE_LIBINTL_H 0
22#define ENABLE_NLS 0
23#define HAVE_ALLOCA 0
24#define NO_MBSUPPORT 1
25#define GAWK 1
26
27/* Make sure no one compiles this code with a C++ compiler. */
28#ifdef __cplusplus
29# error "This is C code, use a C compiler"
30#endif
31
32#ifdef _LIBC
33/* We have to keep the namespace clean. */
34# define regfree(preg) __regfree (preg)
35# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
36# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
37# define regerror(errcode, preg, errbuf, errbuf_size) \
38 __regerror(errcode, preg, errbuf, errbuf_size)
39# define re_set_registers(bu, re, nu, st, en) \
40 __re_set_registers (bu, re, nu, st, en)
41# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
42 __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
43# define re_match(bufp, string, size, pos, regs) \
44 __re_match (bufp, string, size, pos, regs)
45# define re_search(bufp, string, size, startpos, range, regs) \
46 __re_search (bufp, string, size, startpos, range, regs)
47# define re_compile_pattern(pattern, length, bufp) \
48 __re_compile_pattern (pattern, length, bufp)
49# define re_set_syntax(syntax) __re_set_syntax (syntax)
50# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
51 __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
52# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
53
54# include "../locale/localeinfo.h"
55#endif
56
57#if defined (_MSC_VER)
58#include <stdio.h> /* for size_t */
59#endif
60
61/* On some systems, limits.h sets RE_DUP_MAX to a lower value than
62 GNU regex allows. Include it before <regex.h>, which correctly
63 #undefs RE_DUP_MAX and sets it to the right value. */
64#include <limits.h>
65#include <stdint.h>
66
67#ifdef GAWK
68#undef alloca
69#define alloca alloca_is_bad_you_should_never_use_it
70#endif
71#include <regex.h>
72#include "regex_internal.h"
73
74#include "regex_internal.c"
75#ifdef GAWK
76#define bool int
77#define true (1)
78#define false (0)
79#endif
80#include "regcomp.c"
81#include "regexec.c"
82
83/* Binary backward compatibility. */
84#ifdef _LIBC
85# include <shlib-compat.h>
86# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
87link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.")
88int re_max_failures = 2000;
89# endif
90#endif
diff --git a/win32/regex.h b/win32/regex.h
new file mode 100644
index 000000000..61c968387
--- /dev/null
+++ b/win32/regex.h
@@ -0,0 +1,582 @@
1#include <stdio.h>
2#include <stddef.h>
3
4/* Definitions for data structures and routines for the regular
5 expression library.
6 Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003,2005,2006,2008
7 Free Software Foundation, Inc.
8 This file is part of the GNU C Library.
9
10 The GNU C Library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2.1 of the License, or (at your option) any later version.
14
15 The GNU C Library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with the GNU C Library; if not, write to the Free
22 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 02110-1301 USA. */
24
25#ifndef _REGEX_H
26#define _REGEX_H 1
27
28#ifdef HAVE_STDDEF_H
29#include <stddef.h>
30#endif
31
32#ifdef HAVE_SYS_TYPES_H
33#include <sys/types.h>
34#endif
35
36#ifndef _LIBC
37#define __USE_GNU 1
38#endif
39
40/* Allow the use in C++ code. */
41#ifdef __cplusplus
42extern "C" {
43#endif
44
45/* The following two types have to be signed and unsigned integer type
46 wide enough to hold a value of a pointer. For most ANSI compilers
47 ptrdiff_t and size_t should be likely OK. Still size of these two
48 types is 2 for Microsoft C. Ugh... */
49typedef long int s_reg_t;
50typedef unsigned long int active_reg_t;
51
52/* The following bits are used to determine the regexp syntax we
53 recognize. The set/not-set meanings are chosen so that Emacs syntax
54 remains the value 0. The bits are given in alphabetical order, and
55 the definitions shifted by one from the previous bit; thus, when we
56 add or remove a bit, only one other definition need change. */
57typedef unsigned long int reg_syntax_t;
58
59#ifdef __USE_GNU
60/* If this bit is not set, then \ inside a bracket expression is literal.
61 If set, then such a \ quotes the following character. */
62# define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1)
63
64/* If this bit is not set, then + and ? are operators, and \+ and \? are
65 literals.
66 If set, then \+ and \? are operators and + and ? are literals. */
67# define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
68
69/* If this bit is set, then character classes are supported. They are:
70 [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
71 [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
72 If not set, then character classes are not supported. */
73# define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
74
75/* If this bit is set, then ^ and $ are always anchors (outside bracket
76 expressions, of course).
77 If this bit is not set, then it depends:
78 ^ is an anchor if it is at the beginning of a regular
79 expression or after an open-group or an alternation operator;
80 $ is an anchor if it is at the end of a regular expression, or
81 before a close-group or an alternation operator.
82
83 This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
84 POSIX draft 11.2 says that * etc. in leading positions is undefined.
85 We already implemented a previous draft which made those constructs
86 invalid, though, so we haven't changed the code back. */
87# define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
88
89/* If this bit is set, then special characters are always special
90 regardless of where they are in the pattern.
91 If this bit is not set, then special characters are special only in
92 some contexts; otherwise they are ordinary. Specifically,
93 * + ? and intervals are only special when not after the beginning,
94 open-group, or alternation operator. */
95# define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
96
97/* If this bit is set, then *, +, ?, and { cannot be first in an re or
98 immediately after an alternation or begin-group operator. */
99# define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
100
101/* If this bit is set, then . matches newline.
102 If not set, then it doesn't. */
103# define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
104
105/* If this bit is set, then . doesn't match NUL.
106 If not set, then it does. */
107# define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
108
109/* If this bit is set, nonmatching lists [^...] do not match newline.
110 If not set, they do. */
111# define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
112
113/* If this bit is set, either \{...\} or {...} defines an
114 interval, depending on RE_NO_BK_BRACES.
115 If not set, \{, \}, {, and } are literals. */
116# define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
117
118/* If this bit is set, +, ? and | aren't recognized as operators.
119 If not set, they are. */
120# define RE_LIMITED_OPS (RE_INTERVALS << 1)
121
122/* If this bit is set, newline is an alternation operator.
123 If not set, newline is literal. */
124# define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
125
126/* If this bit is set, then `{...}' defines an interval, and \{ and \}
127 are literals.
128 If not set, then `\{...\}' defines an interval. */
129# define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
130
131/* If this bit is set, (...) defines a group, and \( and \) are literals.
132 If not set, \(...\) defines a group, and ( and ) are literals. */
133# define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
134
135/* If this bit is set, then \<digit> matches <digit>.
136 If not set, then \<digit> is a back-reference. */
137# define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
138
139/* If this bit is set, then | is an alternation operator, and \| is literal.
140 If not set, then \| is an alternation operator, and | is literal. */
141# define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
142
143/* If this bit is set, then an ending range point collating higher
144 than the starting range point, as in [z-a], is invalid.
145 If not set, then when ending range point collates higher than the
146 starting range point, the range is ignored. */
147# define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
148
149/* If this bit is set, then an unmatched ) is ordinary.
150 If not set, then an unmatched ) is invalid. */
151# define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
152
153/* If this bit is set, succeed as soon as we match the whole pattern,
154 without further backtracking. */
155# define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
156
157/* If this bit is set, do not process the GNU regex operators.
158 If not set, then the GNU regex operators are recognized. */
159# define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
160
161/* If this bit is set, a syntactically invalid interval is treated as
162 a string of ordinary characters. For example, the ERE 'a{1' is
163 treated as 'a\{1'. */
164# define RE_INVALID_INTERVAL_ORD (RE_NO_GNU_OPS << 1)
165
166/* If this bit is set, then ignore case when matching.
167 If not set, then case is significant. */
168# define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1)
169
170/* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only
171 for ^, because it is difficult to scan the regex backwards to find
172 whether ^ should be special. */
173# define RE_CARET_ANCHORS_HERE (RE_ICASE << 1)
174
175/* If this bit is set, then \{ cannot be first in an bre or
176 immediately after an alternation or begin-group operator. */
177# define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1)
178
179/* If this bit is set, then no_sub will be set to 1 during
180 re_compile_pattern. */
181#define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1)
182#endif
183
184/* This global variable defines the particular regexp syntax to use (for
185 some interfaces). When a regexp is compiled, the syntax used is
186 stored in the pattern buffer, so changing this does not affect
187 already-compiled regexps. */
188extern reg_syntax_t re_syntax_options;
189
190#ifdef __USE_GNU
191/* Define combinations of the above bits for the standard possibilities.
192 (The [[[ comments delimit what gets put into the Texinfo file, so
193 don't delete them!) */
194/* [[[begin syntaxes]]] */
195#define RE_SYNTAX_EMACS 0
196
197#define RE_SYNTAX_AWK \
198 (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
199 | RE_NO_BK_PARENS | RE_NO_BK_REFS \
200 | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
201 | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \
202 | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
203
204#define RE_SYNTAX_GNU_AWK \
205 ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
206 | RE_INVALID_INTERVAL_ORD) \
207 & ~(RE_DOT_NOT_NULL | RE_CONTEXT_INDEP_OPS \
208 | RE_CONTEXT_INVALID_OPS ))
209
210#define RE_SYNTAX_POSIX_AWK \
211 (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
212 | RE_INTERVALS | RE_NO_GNU_OPS \
213 | RE_INVALID_INTERVAL_ORD)
214
215#define RE_SYNTAX_GREP \
216 (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
217 | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
218 | RE_NEWLINE_ALT)
219
220#define RE_SYNTAX_EGREP \
221 (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
222 | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
223 | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
224 | RE_NO_BK_VBAR)
225
226#define RE_SYNTAX_POSIX_EGREP \
227 (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \
228 | RE_INVALID_INTERVAL_ORD)
229
230/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
231#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
232
233#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
234
235/* Syntax bits common to both basic and extended POSIX regex syntax. */
236#define _RE_SYNTAX_POSIX_COMMON \
237 (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
238 | RE_INTERVALS | RE_NO_EMPTY_RANGES)
239
240#define RE_SYNTAX_POSIX_BASIC \
241 (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP)
242
243/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
244 RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
245 isn't minimal, since other operators, such as \`, aren't disabled. */
246#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
247 (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
248
249#define RE_SYNTAX_POSIX_EXTENDED \
250 (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
251 | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
252 | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
253 | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD)
254
255/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is
256 removed and RE_NO_BK_REFS is added. */
257#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
258 (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
259 | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
260 | RE_NO_BK_PARENS | RE_NO_BK_REFS \
261 | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
262/* [[[end syntaxes]]] */
263
264/* Maximum number of duplicates an interval can allow. Some systems
265 (erroneously) define this in other header files, but we want our
266 value, so remove any previous define. */
267# ifdef RE_DUP_MAX
268# undef RE_DUP_MAX
269# endif
270/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */
271# define RE_DUP_MAX (0x7fff)
272#endif
273
274
275/* POSIX `cflags' bits (i.e., information for `regcomp'). */
276
277/* If this bit is set, then use extended regular expression syntax.
278 If not set, then use basic regular expression syntax. */
279#define REG_EXTENDED 1
280
281/* If this bit is set, then ignore case when matching.
282 If not set, then case is significant. */
283#define REG_ICASE (REG_EXTENDED << 1)
284
285/* If this bit is set, then anchors do not match at newline
286 characters in the string.
287 If not set, then anchors do match at newlines. */
288#define REG_NEWLINE (REG_ICASE << 1)
289
290/* If this bit is set, then report only success or fail in regexec.
291 If not set, then returns differ between not matching and errors. */
292#define REG_NOSUB (REG_NEWLINE << 1)
293
294
295/* POSIX `eflags' bits (i.e., information for regexec). */
296
297/* If this bit is set, then the beginning-of-line operator doesn't match
298 the beginning of the string (presumably because it's not the
299 beginning of a line).
300 If not set, then the beginning-of-line operator does match the
301 beginning of the string. */
302#define REG_NOTBOL 1
303
304/* Like REG_NOTBOL, except for the end-of-line. */
305#define REG_NOTEOL (1 << 1)
306
307/* Use PMATCH[0] to delimit the start and end of the search in the
308 buffer. */
309#define REG_STARTEND (1 << 2)
310
311
312/* If any error codes are removed, changed, or added, update the
313 `re_error_msg' table in regex.c. */
314typedef enum
315{
316#if defined _XOPEN_SOURCE || defined __USE_XOPEN2K
317 REG_ENOSYS = -1, /* This will never happen for this implementation. */
318#endif
319
320 REG_NOERROR = 0, /* Success. */
321 REG_NOMATCH, /* Didn't find a match (for regexec). */
322
323 /* POSIX regcomp return error codes. (In the order listed in the
324 standard.) */
325 REG_BADPAT, /* Invalid pattern. */
326 REG_ECOLLATE, /* Inalid collating element. */
327 REG_ECTYPE, /* Invalid character class name. */
328 REG_EESCAPE, /* Trailing backslash. */
329 REG_ESUBREG, /* Invalid back reference. */
330 REG_EBRACK, /* Unmatched left bracket. */
331 REG_EPAREN, /* Parenthesis imbalance. */
332 REG_EBRACE, /* Unmatched \{. */
333 REG_BADBR, /* Invalid contents of \{\}. */
334 REG_ERANGE, /* Invalid range end. */
335 REG_ESPACE, /* Ran out of memory. */
336 REG_BADRPT, /* No preceding re for repetition op. */
337
338 /* Error codes we've added. */
339 REG_EEND, /* Premature end. */
340 REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
341 REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
342} reg_errcode_t;
343
344/* This data structure represents a compiled pattern. Before calling
345 the pattern compiler, the fields `buffer', `allocated', `fastmap',
346 `translate', and `no_sub' can be set. After the pattern has been
347 compiled, the `re_nsub' field is available. All other fields are
348 private to the regex routines. */
349
350#ifndef RE_TRANSLATE_TYPE
351# define __RE_TRANSLATE_TYPE unsigned char *
352# ifdef __USE_GNU
353# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE
354# endif
355#endif
356
357#ifdef __USE_GNU
358# define __REPB_PREFIX(name) name
359#else
360# define __REPB_PREFIX(name) __##name
361#endif
362
363struct re_pattern_buffer
364{
365 /* Space that holds the compiled pattern. It is declared as
366 `unsigned char *' because its elements are sometimes used as
367 array indexes. */
368 unsigned char *__REPB_PREFIX(buffer);
369
370 /* Number of bytes to which `buffer' points. */
371 unsigned long int __REPB_PREFIX(allocated);
372
373 /* Number of bytes actually used in `buffer'. */
374 unsigned long int __REPB_PREFIX(used);
375
376 /* Syntax setting with which the pattern was compiled. */
377 reg_syntax_t __REPB_PREFIX(syntax);
378
379 /* Pointer to a fastmap, if any, otherwise zero. re_search uses the
380 fastmap, if there is one, to skip over impossible starting points
381 for matches. */
382 char *__REPB_PREFIX(fastmap);
383
384 /* Either a translate table to apply to all characters before
385 comparing them, or zero for no translation. The translation is
386 applied to a pattern when it is compiled and to a string when it
387 is matched. */
388 __RE_TRANSLATE_TYPE __REPB_PREFIX(translate);
389
390 /* Number of subexpressions found by the compiler. */
391 size_t re_nsub;
392
393 /* Zero if this pattern cannot match the empty string, one else.
394 Well, in truth it's used only in `re_search_2', to see whether or
395 not we should use the fastmap, so we don't set this absolutely
396 perfectly; see `re_compile_fastmap' (the `duplicate' case). */
397 unsigned __REPB_PREFIX(can_be_null) : 1;
398
399 /* If REGS_UNALLOCATED, allocate space in the `regs' structure
400 for `max (RE_NREGS, re_nsub + 1)' groups.
401 If REGS_REALLOCATE, reallocate space if necessary.
402 If REGS_FIXED, use what's there. */
403#ifdef __USE_GNU
404# define REGS_UNALLOCATED 0
405# define REGS_REALLOCATE 1
406# define REGS_FIXED 2
407#endif
408 unsigned __REPB_PREFIX(regs_allocated) : 2;
409
410 /* Set to zero when `regex_compile' compiles a pattern; set to one
411 by `re_compile_fastmap' if it updates the fastmap. */
412 unsigned __REPB_PREFIX(fastmap_accurate) : 1;
413
414 /* If set, `re_match_2' does not return information about
415 subexpressions. */
416 unsigned __REPB_PREFIX(no_sub) : 1;
417
418 /* If set, a beginning-of-line anchor doesn't match at the beginning
419 of the string. */
420 unsigned __REPB_PREFIX(not_bol) : 1;
421
422 /* Similarly for an end-of-line anchor. */
423 unsigned __REPB_PREFIX(not_eol) : 1;
424
425 /* If true, an anchor at a newline matches. */
426 unsigned __REPB_PREFIX(newline_anchor) : 1;
427};
428
429typedef struct re_pattern_buffer regex_t;
430
431/* Type for byte offsets within the string. POSIX mandates this. */
432typedef int regoff_t;
433
434
435#ifdef __USE_GNU
436/* This is the structure we store register match data in. See
437 regex.texinfo for a full description of what registers match. */
438struct re_registers
439{
440 unsigned num_regs;
441 regoff_t *start;
442 regoff_t *end;
443};
444
445
446/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
447 `re_match_2' returns information about at least this many registers
448 the first time a `regs' structure is passed. */
449# ifndef RE_NREGS
450# define RE_NREGS 30
451# endif
452#endif
453
454
455/* POSIX specification for registers. Aside from the different names than
456 `re_registers', POSIX uses an array of structures, instead of a
457 structure of arrays. */
458typedef struct
459{
460 regoff_t rm_so; /* Byte offset from string's start to substring's start. */
461 regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
462} regmatch_t;
463
464/* Declarations for routines. */
465
466#ifdef __USE_GNU
467/* Sets the current default syntax to SYNTAX, and return the old syntax.
468 You can also simply assign to the `re_syntax_options' variable. */
469extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax);
470
471/* Compile the regular expression PATTERN, with length LENGTH
472 and syntax given by the global `re_syntax_options', into the buffer
473 BUFFER. Return NULL if successful, and an error string if not. */
474extern const char *re_compile_pattern (const char *__pattern, size_t __length,
475 struct re_pattern_buffer *__buffer);
476
477
478/* Compile a fastmap for the compiled pattern in BUFFER; used to
479 accelerate searches. Return 0 if successful and -2 if was an
480 internal error. */
481extern int re_compile_fastmap (struct re_pattern_buffer *__buffer);
482
483
484/* Search in the string STRING (with length LENGTH) for the pattern
485 compiled into BUFFER. Start searching at position START, for RANGE
486 characters. Return the starting position of the match, -1 for no
487 match, or -2 for an internal error. Also return register
488 information in REGS (if REGS and BUFFER->no_sub are nonzero). */
489extern int re_search (struct re_pattern_buffer *__buffer, const char *__cstring,
490 int __length, int __start, int __range,
491 struct re_registers *__regs);
492
493
494/* Like `re_search', but search in the concatenation of STRING1 and
495 STRING2. Also, stop searching at index START + STOP. */
496extern int re_search_2 (struct re_pattern_buffer *__buffer,
497 const char *__string1, int __length1,
498 const char *__string2, int __length2, int __start,
499 int __range, struct re_registers *__regs, int __stop);
500
501
502/* Like `re_search', but return how many characters in STRING the regexp
503 in BUFFER matched, starting at position START. */
504extern int re_match (struct re_pattern_buffer *__buffer, const char *__cstring,
505 int __length, int __start, struct re_registers *__regs);
506
507
508/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
509extern int re_match_2 (struct re_pattern_buffer *__buffer,
510 const char *__string1, int __length1,
511 const char *__string2, int __length2, int __start,
512 struct re_registers *__regs, int __stop);
513
514
515/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
516 ENDS. Subsequent matches using BUFFER and REGS will use this memory
517 for recording register information. STARTS and ENDS must be
518 allocated with malloc, and must each be at least `NUM_REGS * sizeof
519 (regoff_t)' bytes long.
520
521 If NUM_REGS == 0, then subsequent matches should allocate their own
522 register data.
523
524 Unless this function is called, the first search or match using
525 PATTERN_BUFFER will allocate its own register data, without
526 freeing the old data. */
527extern void re_set_registers (struct re_pattern_buffer *__buffer,
528 struct re_registers *__regs,
529 unsigned int __num_regs,
530 regoff_t *__starts, regoff_t *__ends);
531#endif /* Use GNU */
532
533#if defined _REGEX_RE_COMP || (defined _LIBC && defined __USE_BSD)
534# ifndef _CRAY
535/* 4.2 bsd compatibility. */
536extern char *re_comp (const char *);
537extern int re_exec (const char *);
538# endif
539#endif
540
541/* GCC 2.95 and later have "__restrict"; C99 compilers have
542 "restrict", and "configure" may have defined "restrict". */
543#ifndef __restrict
544# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__))
545# if defined restrict || 199901L <= __STDC_VERSION__
546# define __restrict restrict
547# else
548# define __restrict
549# endif
550# endif
551#endif
552/* gcc 3.1 and up support the [restrict] syntax. */
553#ifndef __restrict_arr
554# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) \
555 && !defined __GNUG__
556# define __restrict_arr __restrict
557# else
558# define __restrict_arr
559# endif
560#endif
561
562/* POSIX compatibility. */
563extern int regcomp (regex_t *__restrict __preg,
564 const char *__restrict __pattern,
565 int __cflags);
566
567extern int regexec (const regex_t *__restrict __preg,
568 const char *__restrict __cstring, size_t __nmatch,
569 regmatch_t __pmatch[__restrict_arr],
570 int __eflags);
571
572extern size_t regerror (int __errcode, const regex_t *__restrict __preg,
573 char *__restrict __errbuf, size_t __errbuf_size);
574
575extern void regfree (regex_t *__preg);
576
577
578#ifdef __cplusplus
579}
580#endif /* C++ */
581
582#endif /* regex.h */
diff --git a/win32/regex_internal.c b/win32/regex_internal.c
new file mode 100644
index 000000000..c33561743
--- /dev/null
+++ b/win32/regex_internal.c
@@ -0,0 +1,1744 @@
1/* Extended regular expression matching and search library.
2 Copyright (C) 2002-2006, 2010 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA. */
20
21static void re_string_construct_common (const char *str, int len,
22 re_string_t *pstr,
23 RE_TRANSLATE_TYPE trans, int icase,
24 const re_dfa_t *dfa) internal_function;
25static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa,
26 const re_node_set *nodes,
27 unsigned int hash) internal_function;
28static re_dfastate_t *create_cd_newstate (const re_dfa_t *dfa,
29 const re_node_set *nodes,
30 unsigned int context,
31 unsigned int hash) internal_function;
32
33#ifdef GAWK
34#undef MAX /* safety */
35static int
36MAX(size_t a, size_t b)
37{
38 return (a > b ? a : b);
39}
40#endif
41
42/* Functions for string operation. */
43
44/* This function allocate the buffers. It is necessary to call
45 re_string_reconstruct before using the object. */
46
47static reg_errcode_t
48internal_function
49re_string_allocate (re_string_t *pstr, const char *str, int len, int init_len,
50 RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa)
51{
52 reg_errcode_t ret;
53 int init_buf_len;
54
55 /* Ensure at least one character fits into the buffers. */
56 if (init_len < dfa->mb_cur_max)
57 init_len = dfa->mb_cur_max;
58 init_buf_len = (len + 1 < init_len) ? len + 1: init_len;
59 re_string_construct_common (str, len, pstr, trans, icase, dfa);
60
61 ret = re_string_realloc_buffers (pstr, init_buf_len);
62 if (BE (ret != REG_NOERROR, 0))
63 return ret;
64
65 pstr->word_char = dfa->word_char;
66 pstr->word_ops_used = dfa->word_ops_used;
67 pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
68 pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len;
69 pstr->valid_raw_len = pstr->valid_len;
70 return REG_NOERROR;
71}
72
73/* This function allocate the buffers, and initialize them. */
74
75static reg_errcode_t
76internal_function
77re_string_construct (re_string_t *pstr, const char *str, int len,
78 RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa)
79{
80 reg_errcode_t ret;
81 memset (pstr, '\0', sizeof (re_string_t));
82 re_string_construct_common (str, len, pstr, trans, icase, dfa);
83
84 if (len > 0)
85 {
86 ret = re_string_realloc_buffers (pstr, len + 1);
87 if (BE (ret != REG_NOERROR, 0))
88 return ret;
89 }
90 pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
91
92 if (icase)
93 {
94#ifdef RE_ENABLE_I18N
95 if (dfa->mb_cur_max > 1)
96 {
97 while (1)
98 {
99 ret = build_wcs_upper_buffer (pstr);
100 if (BE (ret != REG_NOERROR, 0))
101 return ret;
102 if (pstr->valid_raw_len >= len)
103 break;
104 if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max)
105 break;
106 ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
107 if (BE (ret != REG_NOERROR, 0))
108 return ret;
109 }
110 }
111 else
112#endif /* RE_ENABLE_I18N */
113 build_upper_buffer (pstr);
114 }
115 else
116 {
117#ifdef RE_ENABLE_I18N
118 if (dfa->mb_cur_max > 1)
119 build_wcs_buffer (pstr);
120 else
121#endif /* RE_ENABLE_I18N */
122 {
123 if (trans != NULL)
124 re_string_translate_buffer (pstr);
125 else
126 {
127 pstr->valid_len = pstr->bufs_len;
128 pstr->valid_raw_len = pstr->bufs_len;
129 }
130 }
131 }
132
133 return REG_NOERROR;
134}
135
136/* Helper functions for re_string_allocate, and re_string_construct. */
137
138static reg_errcode_t
139internal_function
140re_string_realloc_buffers (re_string_t *pstr, int new_buf_len)
141{
142#ifdef RE_ENABLE_I18N
143 if (pstr->mb_cur_max > 1)
144 {
145 wint_t *new_wcs;
146
147 /* Avoid overflow in realloc. */
148 const size_t max_object_size = MAX (sizeof (wint_t), sizeof (int));
149 if (BE (SIZE_MAX / max_object_size < new_buf_len, 0))
150 return REG_ESPACE;
151
152 new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len);
153 if (BE (new_wcs == NULL, 0))
154 return REG_ESPACE;
155 pstr->wcs = new_wcs;
156 if (pstr->offsets != NULL)
157 {
158 int *new_offsets = re_realloc (pstr->offsets, int, new_buf_len);
159 if (BE (new_offsets == NULL, 0))
160 return REG_ESPACE;
161 pstr->offsets = new_offsets;
162 }
163 }
164#endif /* RE_ENABLE_I18N */
165 if (pstr->mbs_allocated)
166 {
167 unsigned char *new_mbs = re_realloc (pstr->mbs, unsigned char,
168 new_buf_len);
169 if (BE (new_mbs == NULL, 0))
170 return REG_ESPACE;
171 pstr->mbs = new_mbs;
172 }
173 pstr->bufs_len = new_buf_len;
174 return REG_NOERROR;
175}
176
177
178static void
179internal_function
180re_string_construct_common (const char *str, int len, re_string_t *pstr,
181 RE_TRANSLATE_TYPE trans, int icase,
182 const re_dfa_t *dfa)
183{
184 pstr->raw_mbs = (const unsigned char *) str;
185 pstr->len = len;
186 pstr->raw_len = len;
187 pstr->trans = trans;
188 pstr->icase = icase ? 1 : 0;
189 pstr->mbs_allocated = (trans != NULL || icase);
190 pstr->mb_cur_max = dfa->mb_cur_max;
191 pstr->is_utf8 = dfa->is_utf8;
192 pstr->map_notascii = dfa->map_notascii;
193 pstr->stop = pstr->len;
194 pstr->raw_stop = pstr->stop;
195}
196
197#ifdef RE_ENABLE_I18N
198
199/* Build wide character buffer PSTR->WCS.
200 If the byte sequence of the string are:
201 <mb1>(0), <mb1>(1), <mb2>(0), <mb2>(1), <sb3>
202 Then wide character buffer will be:
203 <wc1> , WEOF , <wc2> , WEOF , <wc3>
204 We use WEOF for padding, they indicate that the position isn't
205 a first byte of a multibyte character.
206
207 Note that this function assumes PSTR->VALID_LEN elements are already
208 built and starts from PSTR->VALID_LEN. */
209
210static void
211internal_function
212build_wcs_buffer (re_string_t *pstr)
213{
214#ifdef _LIBC
215 unsigned char buf[MB_LEN_MAX];
216 assert (MB_LEN_MAX >= pstr->mb_cur_max);
217#else
218 unsigned char buf[64];
219#endif
220 mbstate_t prev_st;
221 int byte_idx, end_idx, remain_len;
222 size_t mbclen;
223
224 /* Build the buffers from pstr->valid_len to either pstr->len or
225 pstr->bufs_len. */
226 end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
227 for (byte_idx = pstr->valid_len; byte_idx < end_idx;)
228 {
229 wchar_t wc;
230 const char *p;
231
232 remain_len = end_idx - byte_idx;
233 prev_st = pstr->cur_state;
234 /* Apply the translation if we need. */
235 if (BE (pstr->trans != NULL, 0))
236 {
237 int i, ch;
238
239 for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
240 {
241 ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i];
242 buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch];
243 }
244 p = (const char *) buf;
245 }
246 else
247 p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx;
248 mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state);
249 if (BE (mbclen == (size_t) -2, 0))
250 {
251 /* The buffer doesn't have enough space, finish to build. */
252 pstr->cur_state = prev_st;
253 break;
254 }
255 else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0))
256 {
257 /* We treat these cases as a singlebyte character. */
258 mbclen = 1;
259 wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
260 if (BE (pstr->trans != NULL, 0))
261 wc = pstr->trans[wc];
262 pstr->cur_state = prev_st;
263 }
264
265 /* Write wide character and padding. */
266 pstr->wcs[byte_idx++] = wc;
267 /* Write paddings. */
268 for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
269 pstr->wcs[byte_idx++] = WEOF;
270 }
271 pstr->valid_len = byte_idx;
272 pstr->valid_raw_len = byte_idx;
273}
274
275/* Build wide character buffer PSTR->WCS like build_wcs_buffer,
276 but for REG_ICASE. */
277
278static reg_errcode_t
279internal_function
280build_wcs_upper_buffer (re_string_t *pstr)
281{
282 mbstate_t prev_st;
283 int src_idx, byte_idx, end_idx, remain_len;
284 size_t mbclen;
285#ifdef _LIBC
286 char buf[MB_LEN_MAX];
287 assert (MB_LEN_MAX >= pstr->mb_cur_max);
288#else
289 char buf[64];
290#endif
291
292 byte_idx = pstr->valid_len;
293 end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
294
295 /* The following optimization assumes that ASCII characters can be
296 mapped to wide characters with a simple cast. */
297 if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed)
298 {
299 while (byte_idx < end_idx)
300 {
301 wchar_t wc;
302
303 if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx])
304 && mbsinit (&pstr->cur_state))
305 {
306 /* In case of a singlebyte character. */
307 pstr->mbs[byte_idx]
308 = toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]);
309 /* The next step uses the assumption that wchar_t is encoded
310 ASCII-safe: all ASCII values can be converted like this. */
311 pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx];
312 ++byte_idx;
313 continue;
314 }
315
316 remain_len = end_idx - byte_idx;
317 prev_st = pstr->cur_state;
318 mbclen = __mbrtowc (&wc,
319 ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx
320 + byte_idx), remain_len, &pstr->cur_state);
321 if (BE (mbclen + 2 > 2, 1))
322 {
323 wchar_t wcu = wc;
324 if (iswlower (wc))
325 {
326 size_t mbcdlen;
327
328 wcu = towupper (wc);
329 mbcdlen = wcrtomb (buf, wcu, &prev_st);
330 if (BE (mbclen == mbcdlen, 1))
331 memcpy (pstr->mbs + byte_idx, buf, mbclen);
332 else
333 {
334 src_idx = byte_idx;
335 goto offsets_needed;
336 }
337 }
338 else
339 memcpy (pstr->mbs + byte_idx,
340 pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen);
341 pstr->wcs[byte_idx++] = wcu;
342 /* Write paddings. */
343 for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
344 pstr->wcs[byte_idx++] = WEOF;
345 }
346 else if (mbclen == (size_t) -1 || mbclen == 0)
347 {
348 /* It is an invalid character or '\0'. Just use the byte. */
349 int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
350 pstr->mbs[byte_idx] = ch;
351 /* And also cast it to wide char. */
352 pstr->wcs[byte_idx++] = (wchar_t) ch;
353 if (BE (mbclen == (size_t) -1, 0))
354 pstr->cur_state = prev_st;
355 }
356 else
357 {
358 /* The buffer doesn't have enough space, finish to build. */
359 pstr->cur_state = prev_st;
360 break;
361 }
362 }
363 pstr->valid_len = byte_idx;
364 pstr->valid_raw_len = byte_idx;
365 return REG_NOERROR;
366 }
367 else
368 for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;)
369 {
370 wchar_t wc;
371 const char *p;
372 offsets_needed:
373 remain_len = end_idx - byte_idx;
374 prev_st = pstr->cur_state;
375 if (BE (pstr->trans != NULL, 0))
376 {
377 int i, ch;
378
379 for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
380 {
381 ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i];
382 buf[i] = pstr->trans[ch];
383 }
384 p = (const char *) buf;
385 }
386 else
387 p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx;
388 mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state);
389 if (BE (mbclen + 2 > 2, 1))
390 {
391 wchar_t wcu = wc;
392 if (iswlower (wc))
393 {
394 size_t mbcdlen;
395
396 wcu = towupper (wc);
397 mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st);
398 if (BE (mbclen == mbcdlen, 1))
399 memcpy (pstr->mbs + byte_idx, buf, mbclen);
400 else if (mbcdlen != (size_t) -1)
401 {
402 size_t i;
403
404 if (byte_idx + mbcdlen > pstr->bufs_len)
405 {
406 pstr->cur_state = prev_st;
407 break;
408 }
409
410 if (pstr->offsets == NULL)
411 {
412 pstr->offsets = re_malloc (int, pstr->bufs_len);
413
414 if (pstr->offsets == NULL)
415 return REG_ESPACE;
416 }
417 if (!pstr->offsets_needed)
418 {
419 for (i = 0; i < (size_t) byte_idx; ++i)
420 pstr->offsets[i] = i;
421 pstr->offsets_needed = 1;
422 }
423
424 memcpy (pstr->mbs + byte_idx, buf, mbcdlen);
425 pstr->wcs[byte_idx] = wcu;
426 pstr->offsets[byte_idx] = src_idx;
427 for (i = 1; i < mbcdlen; ++i)
428 {
429 pstr->offsets[byte_idx + i]
430 = src_idx + (i < mbclen ? i : mbclen - 1);
431 pstr->wcs[byte_idx + i] = WEOF;
432 }
433 pstr->len += mbcdlen - mbclen;
434 if (pstr->raw_stop > src_idx)
435 pstr->stop += mbcdlen - mbclen;
436 end_idx = (pstr->bufs_len > pstr->len)
437 ? pstr->len : pstr->bufs_len;
438 byte_idx += mbcdlen;
439 src_idx += mbclen;
440 continue;
441 }
442 else
443 memcpy (pstr->mbs + byte_idx, p, mbclen);
444 }
445 else
446 memcpy (pstr->mbs + byte_idx, p, mbclen);
447
448 if (BE (pstr->offsets_needed != 0, 0))
449 {
450 size_t i;
451 for (i = 0; i < mbclen; ++i)
452 pstr->offsets[byte_idx + i] = src_idx + i;
453 }
454 src_idx += mbclen;
455
456 pstr->wcs[byte_idx++] = wcu;
457 /* Write paddings. */
458 for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
459 pstr->wcs[byte_idx++] = WEOF;
460 }
461 else if (mbclen == (size_t) -1 || mbclen == 0)
462 {
463 /* It is an invalid character or '\0'. Just use the byte. */
464 int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx];
465
466 if (BE (pstr->trans != NULL, 0))
467 ch = pstr->trans [ch];
468 pstr->mbs[byte_idx] = ch;
469
470 if (BE (pstr->offsets_needed != 0, 0))
471 pstr->offsets[byte_idx] = src_idx;
472 ++src_idx;
473
474 /* And also cast it to wide char. */
475 pstr->wcs[byte_idx++] = (wchar_t) ch;
476 if (BE (mbclen == (size_t) -1, 0))
477 pstr->cur_state = prev_st;
478 }
479 else
480 {
481 /* The buffer doesn't have enough space, finish to build. */
482 pstr->cur_state = prev_st;
483 break;
484 }
485 }
486 pstr->valid_len = byte_idx;
487 pstr->valid_raw_len = src_idx;
488 return REG_NOERROR;
489}
490
491/* Skip characters until the index becomes greater than NEW_RAW_IDX.
492 Return the index. */
493
494static int
495internal_function
496re_string_skip_chars (re_string_t *pstr, int new_raw_idx, wint_t *last_wc)
497{
498 mbstate_t prev_st;
499 int rawbuf_idx;
500 size_t mbclen;
501 wint_t wc = WEOF;
502
503 /* Skip the characters which are not necessary to check. */
504 for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len;
505 rawbuf_idx < new_raw_idx;)
506 {
507 wchar_t wc2;
508 int remain_len = pstr->len - rawbuf_idx;
509 prev_st = pstr->cur_state;
510 mbclen = __mbrtowc (&wc2, (const char *) pstr->raw_mbs + rawbuf_idx,
511 remain_len, &pstr->cur_state);
512 if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0))
513 {
514 /* We treat these cases as a single byte character. */
515 if (mbclen == 0 || remain_len == 0)
516 wc = L'\0';
517 else
518 wc = *(unsigned char *) (pstr->raw_mbs + rawbuf_idx);
519 mbclen = 1;
520 pstr->cur_state = prev_st;
521 }
522 else
523 wc = (wint_t) wc2;
524 /* Then proceed the next character. */
525 rawbuf_idx += mbclen;
526 }
527 *last_wc = (wint_t) wc;
528 return rawbuf_idx;
529}
530#endif /* RE_ENABLE_I18N */
531
532/* Build the buffer PSTR->MBS, and apply the translation if we need.
533 This function is used in case of REG_ICASE. */
534
535static void
536internal_function
537build_upper_buffer (re_string_t *pstr)
538{
539 int char_idx, end_idx;
540 end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
541
542 for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx)
543 {
544 int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx];
545 if (BE (pstr->trans != NULL, 0))
546 ch = pstr->trans[ch];
547 if (islower (ch))
548 pstr->mbs[char_idx] = toupper (ch);
549 else
550 pstr->mbs[char_idx] = ch;
551 }
552 pstr->valid_len = char_idx;
553 pstr->valid_raw_len = char_idx;
554}
555
556/* Apply TRANS to the buffer in PSTR. */
557
558static void
559internal_function
560re_string_translate_buffer (re_string_t *pstr)
561{
562 int buf_idx, end_idx;
563 end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
564
565 for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx)
566 {
567 int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx];
568 pstr->mbs[buf_idx] = pstr->trans[ch];
569 }
570
571 pstr->valid_len = buf_idx;
572 pstr->valid_raw_len = buf_idx;
573}
574
575/* This function re-construct the buffers.
576 Concretely, convert to wide character in case of pstr->mb_cur_max > 1,
577 convert to upper case in case of REG_ICASE, apply translation. */
578
579static reg_errcode_t
580internal_function
581re_string_reconstruct (re_string_t *pstr, int idx, int eflags)
582{
583 int offset = idx - pstr->raw_mbs_idx;
584 if (BE (offset < 0, 0))
585 {
586 /* Reset buffer. */
587#ifdef RE_ENABLE_I18N
588 if (pstr->mb_cur_max > 1)
589 memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
590#endif /* RE_ENABLE_I18N */
591 pstr->len = pstr->raw_len;
592 pstr->stop = pstr->raw_stop;
593 pstr->valid_len = 0;
594 pstr->raw_mbs_idx = 0;
595 pstr->valid_raw_len = 0;
596 pstr->offsets_needed = 0;
597 pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
598 : CONTEXT_NEWLINE | CONTEXT_BEGBUF);
599 if (!pstr->mbs_allocated)
600 pstr->mbs = (unsigned char *) pstr->raw_mbs;
601 offset = idx;
602 }
603
604 if (BE (offset != 0, 1))
605 {
606 /* Should the already checked characters be kept? */
607 if (BE (offset < pstr->valid_raw_len, 1))
608 {
609 /* Yes, move them to the front of the buffer. */
610#ifdef RE_ENABLE_I18N
611 if (BE (pstr->offsets_needed, 0))
612 {
613 int low = 0, high = pstr->valid_len, mid;
614 do
615 {
616 mid = (high + low) / 2;
617 if (pstr->offsets[mid] > offset)
618 high = mid;
619 else if (pstr->offsets[mid] < offset)
620 low = mid + 1;
621 else
622 break;
623 }
624 while (low < high);
625 if (pstr->offsets[mid] < offset)
626 ++mid;
627 pstr->tip_context = re_string_context_at (pstr, mid - 1,
628 eflags);
629 /* This can be quite complicated, so handle specially
630 only the common and easy case where the character with
631 different length representation of lower and upper
632 case is present at or after offset. */
633 if (pstr->valid_len > offset
634 && mid == offset && pstr->offsets[mid] == offset)
635 {
636 memmove (pstr->wcs, pstr->wcs + offset,
637 (pstr->valid_len - offset) * sizeof (wint_t));
638 memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset);
639 pstr->valid_len -= offset;
640 pstr->valid_raw_len -= offset;
641 for (low = 0; low < pstr->valid_len; low++)
642 pstr->offsets[low] = pstr->offsets[low + offset] - offset;
643 }
644 else
645 {
646 /* Otherwise, just find out how long the partial multibyte
647 character at offset is and fill it with WEOF/255. */
648 pstr->len = pstr->raw_len - idx + offset;
649 pstr->stop = pstr->raw_stop - idx + offset;
650 pstr->offsets_needed = 0;
651 while (mid > 0 && pstr->offsets[mid - 1] == offset)
652 --mid;
653 while (mid < pstr->valid_len)
654 if (pstr->wcs[mid] != WEOF)
655 break;
656 else
657 ++mid;
658 if (mid == pstr->valid_len)
659 pstr->valid_len = 0;
660 else
661 {
662 pstr->valid_len = pstr->offsets[mid] - offset;
663 if (pstr->valid_len)
664 {
665 for (low = 0; low < pstr->valid_len; ++low)
666 pstr->wcs[low] = WEOF;
667 memset (pstr->mbs, 255, pstr->valid_len);
668 }
669 }
670 pstr->valid_raw_len = pstr->valid_len;
671 }
672 }
673 else
674#endif
675 {
676 pstr->tip_context = re_string_context_at (pstr, offset - 1,
677 eflags);
678#ifdef RE_ENABLE_I18N
679 if (pstr->mb_cur_max > 1)
680 memmove (pstr->wcs, pstr->wcs + offset,
681 (pstr->valid_len - offset) * sizeof (wint_t));
682#endif /* RE_ENABLE_I18N */
683 if (BE (pstr->mbs_allocated, 0))
684 memmove (pstr->mbs, pstr->mbs + offset,
685 pstr->valid_len - offset);
686 pstr->valid_len -= offset;
687 pstr->valid_raw_len -= offset;
688#ifdef DEBUG
689 assert (pstr->valid_len > 0);
690#endif
691 }
692 }
693 else
694 {
695#ifdef RE_ENABLE_I18N
696 /* No, skip all characters until IDX. */
697 int prev_valid_len = pstr->valid_len;
698
699 if (BE (pstr->offsets_needed, 0))
700 {
701 pstr->len = pstr->raw_len - idx + offset;
702 pstr->stop = pstr->raw_stop - idx + offset;
703 pstr->offsets_needed = 0;
704 }
705#endif
706 pstr->valid_len = 0;
707#ifdef RE_ENABLE_I18N
708 if (pstr->mb_cur_max > 1)
709 {
710 int wcs_idx;
711 wint_t wc = WEOF;
712
713 if (pstr->is_utf8)
714 {
715 const unsigned char *raw, *p, *end;
716
717 /* Special case UTF-8. Multi-byte chars start with any
718 byte other than 0x80 - 0xbf. */
719 raw = pstr->raw_mbs + pstr->raw_mbs_idx;
720 end = raw + (offset - pstr->mb_cur_max);
721 if (end < pstr->raw_mbs)
722 end = pstr->raw_mbs;
723 p = raw + offset - 1;
724#ifdef _LIBC
725 /* We know the wchar_t encoding is UCS4, so for the simple
726 case, ASCII characters, skip the conversion step. */
727 if (isascii (*p) && BE (pstr->trans == NULL, 1))
728 {
729 memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
730 /* pstr->valid_len = 0; */
731 wc = (wchar_t) *p;
732 }
733 else
734#endif
735 for (; p >= end; --p)
736 if ((*p & 0xc0) != 0x80)
737 {
738 mbstate_t cur_state;
739 wchar_t wc2;
740 int mlen = raw + pstr->len - p;
741 unsigned char buf[6];
742 size_t mbclen;
743
744 if (BE (pstr->trans != NULL, 0))
745 {
746 int i = mlen < 6 ? mlen : 6;
747 while (--i >= 0)
748 buf[i] = pstr->trans[p[i]];
749 }
750 /* XXX Don't use mbrtowc, we know which conversion
751 to use (UTF-8 -> UCS4). */
752 memset (&cur_state, 0, sizeof (cur_state));
753 mbclen = __mbrtowc (&wc2, (const char *) p, mlen,
754 &cur_state);
755 if (raw + offset - p <= mbclen
756 && mbclen < (size_t) -2)
757 {
758 memset (&pstr->cur_state, '\0',
759 sizeof (mbstate_t));
760 pstr->valid_len = mbclen - (raw + offset - p);
761 wc = wc2;
762 }
763 break;
764 }
765 }
766
767 if (wc == WEOF)
768 pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx;
769 if (wc == WEOF)
770 pstr->tip_context
771 = re_string_context_at (pstr, prev_valid_len - 1, eflags);
772 else
773 pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0)
774 && IS_WIDE_WORD_CHAR (wc))
775 ? CONTEXT_WORD
776 : ((IS_WIDE_NEWLINE (wc)
777 && pstr->newline_anchor)
778 ? CONTEXT_NEWLINE : 0));
779 if (BE (pstr->valid_len, 0))
780 {
781 for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx)
782 pstr->wcs[wcs_idx] = WEOF;
783 if (pstr->mbs_allocated)
784 memset (pstr->mbs, 255, pstr->valid_len);
785 }
786 pstr->valid_raw_len = pstr->valid_len;
787 }
788 else
789#endif /* RE_ENABLE_I18N */
790 {
791 int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1];
792 pstr->valid_raw_len = 0;
793 if (pstr->trans)
794 c = pstr->trans[c];
795 pstr->tip_context = (bitset_contain (pstr->word_char, c)
796 ? CONTEXT_WORD
797 : ((IS_NEWLINE (c) && pstr->newline_anchor)
798 ? CONTEXT_NEWLINE : 0));
799 }
800 }
801 if (!BE (pstr->mbs_allocated, 0))
802 pstr->mbs += offset;
803 }
804 pstr->raw_mbs_idx = idx;
805 pstr->len -= offset;
806 pstr->stop -= offset;
807
808 /* Then build the buffers. */
809#ifdef RE_ENABLE_I18N
810 if (pstr->mb_cur_max > 1)
811 {
812 if (pstr->icase)
813 {
814 reg_errcode_t ret = build_wcs_upper_buffer (pstr);
815 if (BE (ret != REG_NOERROR, 0))
816 return ret;
817 }
818 else
819 build_wcs_buffer (pstr);
820 }
821 else
822#endif /* RE_ENABLE_I18N */
823 if (BE (pstr->mbs_allocated, 0))
824 {
825 if (pstr->icase)
826 build_upper_buffer (pstr);
827 else if (pstr->trans != NULL)
828 re_string_translate_buffer (pstr);
829 }
830 else
831 pstr->valid_len = pstr->len;
832
833 pstr->cur_idx = 0;
834 return REG_NOERROR;
835}
836
837static unsigned char
838internal_function __attribute ((pure))
839re_string_peek_byte_case (const re_string_t *pstr, int idx)
840{
841 int ch, off;
842
843 /* Handle the common (easiest) cases first. */
844 if (BE (!pstr->mbs_allocated, 1))
845 return re_string_peek_byte (pstr, idx);
846
847#ifdef RE_ENABLE_I18N
848 if (pstr->mb_cur_max > 1
849 && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx))
850 return re_string_peek_byte (pstr, idx);
851#endif
852
853 off = pstr->cur_idx + idx;
854#ifdef RE_ENABLE_I18N
855 if (pstr->offsets_needed)
856 off = pstr->offsets[off];
857#endif
858
859 ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
860
861#ifdef RE_ENABLE_I18N
862 /* Ensure that e.g. for tr_TR.UTF-8 BACKSLASH DOTLESS SMALL LETTER I
863 this function returns CAPITAL LETTER I instead of first byte of
864 DOTLESS SMALL LETTER I. The latter would confuse the parser,
865 since peek_byte_case doesn't advance cur_idx in any way. */
866 if (pstr->offsets_needed && !isascii (ch))
867 return re_string_peek_byte (pstr, idx);
868#endif
869
870 return ch;
871}
872
873static unsigned char
874internal_function __attribute ((pure))
875re_string_fetch_byte_case (re_string_t *pstr)
876{
877 if (BE (!pstr->mbs_allocated, 1))
878 return re_string_fetch_byte (pstr);
879
880#ifdef RE_ENABLE_I18N
881 if (pstr->offsets_needed)
882 {
883 int off, ch;
884
885 /* For tr_TR.UTF-8 [[:islower:]] there is
886 [[: CAPITAL LETTER I WITH DOT lower:]] in mbs. Skip
887 in that case the whole multi-byte character and return
888 the original letter. On the other side, with
889 [[: DOTLESS SMALL LETTER I return [[:I, as doing
890 anything else would complicate things too much. */
891
892 if (!re_string_first_byte (pstr, pstr->cur_idx))
893 return re_string_fetch_byte (pstr);
894
895 off = pstr->offsets[pstr->cur_idx];
896 ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
897
898 if (! isascii (ch))
899 return re_string_fetch_byte (pstr);
900
901 re_string_skip_bytes (pstr,
902 re_string_char_size_at (pstr, pstr->cur_idx));
903 return ch;
904 }
905#endif
906
907 return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++];
908}
909
910static void
911internal_function
912re_string_destruct (re_string_t *pstr)
913{
914#ifdef RE_ENABLE_I18N
915 re_free (pstr->wcs);
916 re_free (pstr->offsets);
917#endif /* RE_ENABLE_I18N */
918 if (pstr->mbs_allocated)
919 re_free (pstr->mbs);
920}
921
922/* Return the context at IDX in INPUT. */
923
924static unsigned int
925internal_function
926re_string_context_at (const re_string_t *input, int idx, int eflags)
927{
928 int c;
929 if (BE (idx < 0, 0))
930 /* In this case, we use the value stored in input->tip_context,
931 since we can't know the character in input->mbs[-1] here. */
932 return input->tip_context;
933 if (BE (idx == input->len, 0))
934 return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF
935 : CONTEXT_NEWLINE | CONTEXT_ENDBUF);
936#ifdef RE_ENABLE_I18N
937 if (input->mb_cur_max > 1)
938 {
939 wint_t wc;
940 int wc_idx = idx;
941 while(input->wcs[wc_idx] == WEOF)
942 {
943#ifdef DEBUG
944 /* It must not happen. */
945 assert (wc_idx >= 0);
946#endif
947 --wc_idx;
948 if (wc_idx < 0)
949 return input->tip_context;
950 }
951 wc = input->wcs[wc_idx];
952 if (BE (input->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc))
953 return CONTEXT_WORD;
954 return (IS_WIDE_NEWLINE (wc) && input->newline_anchor
955 ? CONTEXT_NEWLINE : 0);
956 }
957 else
958#endif
959 {
960 c = re_string_byte_at (input, idx);
961 if (bitset_contain (input->word_char, c))
962 return CONTEXT_WORD;
963 return IS_NEWLINE (c) && input->newline_anchor ? CONTEXT_NEWLINE : 0;
964 }
965}
966
967/* Functions for set operation. */
968
969static reg_errcode_t
970internal_function
971re_node_set_alloc (re_node_set *set, int size)
972{
973 /*
974 * ADR: valgrind says size can be 0, which then doesn't
975 * free the block of size 0. Harumph. This seems
976 * to work ok, though.
977 */
978 if (size == 0)
979 {
980 memset(set, 0, sizeof(*set));
981 return REG_NOERROR;
982 }
983 set->alloc = size;
984 set->nelem = 0;
985 set->elems = re_malloc (int, size);
986 if (BE (set->elems == NULL, 0))
987 return REG_ESPACE;
988 return REG_NOERROR;
989}
990
991static reg_errcode_t
992internal_function
993re_node_set_init_1 (re_node_set *set, int elem)
994{
995 set->alloc = 1;
996 set->nelem = 1;
997 set->elems = re_malloc (int, 1);
998 if (BE (set->elems == NULL, 0))
999 {
1000 set->alloc = set->nelem = 0;
1001 return REG_ESPACE;
1002 }
1003 set->elems[0] = elem;
1004 return REG_NOERROR;
1005}
1006
1007static reg_errcode_t
1008internal_function
1009re_node_set_init_2 (re_node_set *set, int elem1, int elem2)
1010{
1011 set->alloc = 2;
1012 set->elems = re_malloc (int, 2);
1013 if (BE (set->elems == NULL, 0))
1014 return REG_ESPACE;
1015 if (elem1 == elem2)
1016 {
1017 set->nelem = 1;
1018 set->elems[0] = elem1;
1019 }
1020 else
1021 {
1022 set->nelem = 2;
1023 if (elem1 < elem2)
1024 {
1025 set->elems[0] = elem1;
1026 set->elems[1] = elem2;
1027 }
1028 else
1029 {
1030 set->elems[0] = elem2;
1031 set->elems[1] = elem1;
1032 }
1033 }
1034 return REG_NOERROR;
1035}
1036
1037static reg_errcode_t
1038internal_function
1039re_node_set_init_copy (re_node_set *dest, const re_node_set *src)
1040{
1041 dest->nelem = src->nelem;
1042 if (src->nelem > 0)
1043 {
1044 dest->alloc = dest->nelem;
1045 dest->elems = re_malloc (int, dest->alloc);
1046 if (BE (dest->elems == NULL, 0))
1047 {
1048 dest->alloc = dest->nelem = 0;
1049 return REG_ESPACE;
1050 }
1051 memcpy (dest->elems, src->elems, src->nelem * sizeof (int));
1052 }
1053 else
1054 re_node_set_init_empty (dest);
1055 return REG_NOERROR;
1056}
1057
1058/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to
1059 DEST. Return value indicate the error code or REG_NOERROR if succeeded.
1060 Note: We assume dest->elems is NULL, when dest->alloc is 0. */
1061
1062static reg_errcode_t
1063internal_function
1064re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1,
1065 const re_node_set *src2)
1066{
1067 int i1, i2, is, id, delta, sbase;
1068 if (src1->nelem == 0 || src2->nelem == 0)
1069 return REG_NOERROR;
1070
1071 /* We need dest->nelem + 2 * elems_in_intersection; this is a
1072 conservative estimate. */
1073 if (src1->nelem + src2->nelem + dest->nelem > dest->alloc)
1074 {
1075 int new_alloc = src1->nelem + src2->nelem + dest->alloc;
1076 int *new_elems = re_realloc (dest->elems, int, new_alloc);
1077 if (BE (new_elems == NULL, 0))
1078 return REG_ESPACE;
1079 dest->elems = new_elems;
1080 dest->alloc = new_alloc;
1081 }
1082
1083 /* Find the items in the intersection of SRC1 and SRC2, and copy
1084 into the top of DEST those that are not already in DEST itself. */
1085 sbase = dest->nelem + src1->nelem + src2->nelem;
1086 i1 = src1->nelem - 1;
1087 i2 = src2->nelem - 1;
1088 id = dest->nelem - 1;
1089 for (;;)
1090 {
1091 if (src1->elems[i1] == src2->elems[i2])
1092 {
1093 /* Try to find the item in DEST. Maybe we could binary search? */
1094 while (id >= 0 && dest->elems[id] > src1->elems[i1])
1095 --id;
1096
1097 if (id < 0 || dest->elems[id] != src1->elems[i1])
1098 dest->elems[--sbase] = src1->elems[i1];
1099
1100 if (--i1 < 0 || --i2 < 0)
1101 break;
1102 }
1103
1104 /* Lower the highest of the two items. */
1105 else if (src1->elems[i1] < src2->elems[i2])
1106 {
1107 if (--i2 < 0)
1108 break;
1109 }
1110 else
1111 {
1112 if (--i1 < 0)
1113 break;
1114 }
1115 }
1116
1117 id = dest->nelem - 1;
1118 is = dest->nelem + src1->nelem + src2->nelem - 1;
1119 delta = is - sbase + 1;
1120
1121 /* Now copy. When DELTA becomes zero, the remaining
1122 DEST elements are already in place; this is more or
1123 less the same loop that is in re_node_set_merge. */
1124 dest->nelem += delta;
1125 if (delta > 0 && id >= 0)
1126 for (;;)
1127 {
1128 if (dest->elems[is] > dest->elems[id])
1129 {
1130 /* Copy from the top. */
1131 dest->elems[id + delta--] = dest->elems[is--];
1132 if (delta == 0)
1133 break;
1134 }
1135 else
1136 {
1137 /* Slide from the bottom. */
1138 dest->elems[id + delta] = dest->elems[id];
1139 if (--id < 0)
1140 break;
1141 }
1142 }
1143
1144 /* Copy remaining SRC elements. */
1145 memcpy (dest->elems, dest->elems + sbase, delta * sizeof (int));
1146
1147 return REG_NOERROR;
1148}
1149
1150/* Calculate the union set of the sets SRC1 and SRC2. And store it to
1151 DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
1152
1153static reg_errcode_t
1154internal_function
1155re_node_set_init_union (re_node_set *dest, const re_node_set *src1,
1156 const re_node_set *src2)
1157{
1158 int i1, i2, id;
1159 if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0)
1160 {
1161 dest->alloc = src1->nelem + src2->nelem;
1162 dest->elems = re_malloc (int, dest->alloc);
1163 if (BE (dest->elems == NULL, 0))
1164 return REG_ESPACE;
1165 }
1166 else
1167 {
1168 if (src1 != NULL && src1->nelem > 0)
1169 return re_node_set_init_copy (dest, src1);
1170 else if (src2 != NULL && src2->nelem > 0)
1171 return re_node_set_init_copy (dest, src2);
1172 else
1173 re_node_set_init_empty (dest);
1174 return REG_NOERROR;
1175 }
1176 for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;)
1177 {
1178 if (src1->elems[i1] > src2->elems[i2])
1179 {
1180 dest->elems[id++] = src2->elems[i2++];
1181 continue;
1182 }
1183 if (src1->elems[i1] == src2->elems[i2])
1184 ++i2;
1185 dest->elems[id++] = src1->elems[i1++];
1186 }
1187 if (i1 < src1->nelem)
1188 {
1189 memcpy (dest->elems + id, src1->elems + i1,
1190 (src1->nelem - i1) * sizeof (int));
1191 id += src1->nelem - i1;
1192 }
1193 else if (i2 < src2->nelem)
1194 {
1195 memcpy (dest->elems + id, src2->elems + i2,
1196 (src2->nelem - i2) * sizeof (int));
1197 id += src2->nelem - i2;
1198 }
1199 dest->nelem = id;
1200 return REG_NOERROR;
1201}
1202
1203/* Calculate the union set of the sets DEST and SRC. And store it to
1204 DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
1205
1206static reg_errcode_t
1207internal_function
1208re_node_set_merge (re_node_set *dest, const re_node_set *src)
1209{
1210 int is, id, sbase, delta;
1211 if (src == NULL || src->nelem == 0)
1212 return REG_NOERROR;
1213 if (dest->alloc < 2 * src->nelem + dest->nelem)
1214 {
1215 int new_alloc = 2 * (src->nelem + dest->alloc);
1216 int *new_buffer = re_realloc (dest->elems, int, new_alloc);
1217 if (BE (new_buffer == NULL, 0))
1218 return REG_ESPACE;
1219 dest->elems = new_buffer;
1220 dest->alloc = new_alloc;
1221 }
1222
1223 if (BE (dest->nelem == 0, 0))
1224 {
1225 dest->nelem = src->nelem;
1226 memcpy (dest->elems, src->elems, src->nelem * sizeof (int));
1227 return REG_NOERROR;
1228 }
1229
1230 /* Copy into the top of DEST the items of SRC that are not
1231 found in DEST. Maybe we could binary search in DEST? */
1232 for (sbase = dest->nelem + 2 * src->nelem,
1233 is = src->nelem - 1, id = dest->nelem - 1; is >= 0 && id >= 0; )
1234 {
1235 if (dest->elems[id] == src->elems[is])
1236 is--, id--;
1237 else if (dest->elems[id] < src->elems[is])
1238 dest->elems[--sbase] = src->elems[is--];
1239 else /* if (dest->elems[id] > src->elems[is]) */
1240 --id;
1241 }
1242
1243 if (is >= 0)
1244 {
1245 /* If DEST is exhausted, the remaining items of SRC must be unique. */
1246 sbase -= is + 1;
1247 memcpy (dest->elems + sbase, src->elems, (is + 1) * sizeof (int));
1248 }
1249
1250 id = dest->nelem - 1;
1251 is = dest->nelem + 2 * src->nelem - 1;
1252 delta = is - sbase + 1;
1253 if (delta == 0)
1254 return REG_NOERROR;
1255
1256 /* Now copy. When DELTA becomes zero, the remaining
1257 DEST elements are already in place. */
1258 dest->nelem += delta;
1259 for (;;)
1260 {
1261 if (dest->elems[is] > dest->elems[id])
1262 {
1263 /* Copy from the top. */
1264 dest->elems[id + delta--] = dest->elems[is--];
1265 if (delta == 0)
1266 break;
1267 }
1268 else
1269 {
1270 /* Slide from the bottom. */
1271 dest->elems[id + delta] = dest->elems[id];
1272 if (--id < 0)
1273 {
1274 /* Copy remaining SRC elements. */
1275 memcpy (dest->elems, dest->elems + sbase,
1276 delta * sizeof (int));
1277 break;
1278 }
1279 }
1280 }
1281
1282 return REG_NOERROR;
1283}
1284
1285/* Insert the new element ELEM to the re_node_set* SET.
1286 SET should not already have ELEM.
1287 return -1 if an error has occurred, return 1 otherwise. */
1288
1289static int
1290internal_function
1291re_node_set_insert (re_node_set *set, int elem)
1292{
1293 int idx;
1294 /* In case the set is empty. */
1295 if (set->alloc == 0)
1296 {
1297 if (BE (re_node_set_init_1 (set, elem) == REG_NOERROR, 1))
1298 return 1;
1299 else
1300 return -1;
1301 }
1302
1303 if (BE (set->nelem, 0) == 0)
1304 {
1305 /* We already guaranteed above that set->alloc != 0. */
1306 set->elems[0] = elem;
1307 ++set->nelem;
1308 return 1;
1309 }
1310
1311 /* Realloc if we need. */
1312 if (set->alloc == set->nelem)
1313 {
1314 int *new_elems;
1315 set->alloc = set->alloc * 2;
1316 new_elems = re_realloc (set->elems, int, set->alloc);
1317 if (BE (new_elems == NULL, 0))
1318 return -1;
1319 set->elems = new_elems;
1320 }
1321
1322 /* Move the elements which follows the new element. Test the
1323 first element separately to skip a check in the inner loop. */
1324 if (elem < set->elems[0])
1325 {
1326 idx = 0;
1327 for (idx = set->nelem; idx > 0; idx--)
1328 set->elems[idx] = set->elems[idx - 1];
1329 }
1330 else
1331 {
1332 for (idx = set->nelem; set->elems[idx - 1] > elem; idx--)
1333 set->elems[idx] = set->elems[idx - 1];
1334 }
1335
1336 /* Insert the new element. */
1337 set->elems[idx] = elem;
1338 ++set->nelem;
1339 return 1;
1340}
1341
1342/* Insert the new element ELEM to the re_node_set* SET.
1343 SET should not already have any element greater than or equal to ELEM.
1344 Return -1 if an error has occurred, return 1 otherwise. */
1345
1346static int
1347internal_function
1348re_node_set_insert_last (re_node_set *set, int elem)
1349{
1350 /* Realloc if we need. */
1351 if (set->alloc == set->nelem)
1352 {
1353 int *new_elems;
1354 set->alloc = (set->alloc + 1) * 2;
1355 new_elems = re_realloc (set->elems, int, set->alloc);
1356 if (BE (new_elems == NULL, 0))
1357 return -1;
1358 set->elems = new_elems;
1359 }
1360
1361 /* Insert the new element. */
1362 set->elems[set->nelem++] = elem;
1363 return 1;
1364}
1365
1366/* Compare two node sets SET1 and SET2.
1367 return 1 if SET1 and SET2 are equivalent, return 0 otherwise. */
1368
1369static int
1370internal_function __attribute ((pure))
1371re_node_set_compare (const re_node_set *set1, const re_node_set *set2)
1372{
1373 int i;
1374 if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem)
1375 return 0;
1376 for (i = set1->nelem ; --i >= 0 ; )
1377 if (set1->elems[i] != set2->elems[i])
1378 return 0;
1379 return 1;
1380}
1381
1382/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */
1383
1384static int
1385internal_function __attribute ((pure))
1386re_node_set_contains (const re_node_set *set, int elem)
1387{
1388 unsigned int idx, right, mid;
1389 if (set->nelem <= 0)
1390 return 0;
1391
1392 /* Binary search the element. */
1393 idx = 0;
1394 right = set->nelem - 1;
1395 while (idx < right)
1396 {
1397 mid = (idx + right) / 2;
1398 if (set->elems[mid] < elem)
1399 idx = mid + 1;
1400 else
1401 right = mid;
1402 }
1403 return set->elems[idx] == elem ? idx + 1 : 0;
1404}
1405
1406static void
1407internal_function
1408re_node_set_remove_at (re_node_set *set, int idx)
1409{
1410 if (idx < 0 || idx >= set->nelem)
1411 return;
1412 --set->nelem;
1413 for (; idx < set->nelem; idx++)
1414 set->elems[idx] = set->elems[idx + 1];
1415}
1416
1417
1418/* Add the token TOKEN to dfa->nodes, and return the index of the token.
1419 Or return -1, if an error has occurred. */
1420
1421static int
1422internal_function
1423re_dfa_add_node (re_dfa_t *dfa, re_token_t token)
1424{
1425 if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0))
1426 {
1427 size_t new_nodes_alloc = dfa->nodes_alloc * 2;
1428 int *new_nexts, *new_indices;
1429 re_node_set *new_edests, *new_eclosures;
1430 re_token_t *new_nodes;
1431
1432 /* Avoid overflows in realloc. */
1433 const size_t max_object_size = MAX (sizeof (re_token_t),
1434 MAX (sizeof (re_node_set),
1435 sizeof (int)));
1436 if (BE (SIZE_MAX / max_object_size < new_nodes_alloc, 0))
1437 return -1;
1438
1439 new_nodes = re_realloc (dfa->nodes, re_token_t, new_nodes_alloc);
1440 if (BE (new_nodes == NULL, 0))
1441 return -1;
1442 dfa->nodes = new_nodes;
1443 new_nexts = re_realloc (dfa->nexts, int, new_nodes_alloc);
1444 new_indices = re_realloc (dfa->org_indices, int, new_nodes_alloc);
1445 new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc);
1446 new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc);
1447 if (BE (new_nexts == NULL || new_indices == NULL
1448 || new_edests == NULL || new_eclosures == NULL, 0))
1449 return -1;
1450 dfa->nexts = new_nexts;
1451 dfa->org_indices = new_indices;
1452 dfa->edests = new_edests;
1453 dfa->eclosures = new_eclosures;
1454 dfa->nodes_alloc = new_nodes_alloc;
1455 }
1456 dfa->nodes[dfa->nodes_len] = token;
1457 dfa->nodes[dfa->nodes_len].constraint = 0;
1458#ifdef RE_ENABLE_I18N
1459 dfa->nodes[dfa->nodes_len].accept_mb =
1460 (token.type == OP_PERIOD && dfa->mb_cur_max > 1) || token.type == COMPLEX_BRACKET;
1461#endif
1462 dfa->nexts[dfa->nodes_len] = -1;
1463 re_node_set_init_empty (dfa->edests + dfa->nodes_len);
1464 re_node_set_init_empty (dfa->eclosures + dfa->nodes_len);
1465 return dfa->nodes_len++;
1466}
1467
1468static inline unsigned int
1469internal_function
1470calc_state_hash (const re_node_set *nodes, unsigned int context)
1471{
1472 unsigned int hash = nodes->nelem + context;
1473 int i;
1474 for (i = 0 ; i < nodes->nelem ; i++)
1475 hash += nodes->elems[i];
1476 return hash;
1477}
1478
1479/* Search for the state whose node_set is equivalent to NODES.
1480 Return the pointer to the state, if we found it in the DFA.
1481 Otherwise create the new one and return it. In case of an error
1482 return NULL and set the error code in ERR.
1483 Note: - We assume NULL as the invalid state, then it is possible that
1484 return value is NULL and ERR is REG_NOERROR.
1485 - We never return non-NULL value in case of any errors, it is for
1486 optimization. */
1487
1488static re_dfastate_t *
1489internal_function
1490re_acquire_state (reg_errcode_t *err, const re_dfa_t *dfa,
1491 const re_node_set *nodes)
1492{
1493 unsigned int hash;
1494 re_dfastate_t *new_state;
1495 struct re_state_table_entry *spot;
1496 int i;
1497 if (BE (nodes->nelem == 0, 0))
1498 {
1499 *err = REG_NOERROR;
1500 return NULL;
1501 }
1502 hash = calc_state_hash (nodes, 0);
1503 spot = dfa->state_table + (hash & dfa->state_hash_mask);
1504
1505 for (i = 0 ; i < spot->num ; i++)
1506 {
1507 re_dfastate_t *state = spot->array[i];
1508 if (hash != state->hash)
1509 continue;
1510 if (re_node_set_compare (&state->nodes, nodes))
1511 return state;
1512 }
1513
1514 /* There are no appropriate state in the dfa, create the new one. */
1515 new_state = create_ci_newstate (dfa, nodes, hash);
1516 if (BE (new_state == NULL, 0))
1517 *err = REG_ESPACE;
1518
1519 return new_state;
1520}
1521
1522/* Search for the state whose node_set is equivalent to NODES and
1523 whose context is equivalent to CONTEXT.
1524 Return the pointer to the state, if we found it in the DFA.
1525 Otherwise create the new one and return it. In case of an error
1526 return NULL and set the error code in ERR.
1527 Note: - We assume NULL as the invalid state, then it is possible that
1528 return value is NULL and ERR is REG_NOERROR.
1529 - We never return non-NULL value in case of any errors, it is for
1530 optimization. */
1531
1532static re_dfastate_t *
1533internal_function
1534re_acquire_state_context (reg_errcode_t *err, const re_dfa_t *dfa,
1535 const re_node_set *nodes, unsigned int context)
1536{
1537 unsigned int hash;
1538 re_dfastate_t *new_state;
1539 struct re_state_table_entry *spot;
1540 int i;
1541 if (nodes->nelem == 0)
1542 {
1543 *err = REG_NOERROR;
1544 return NULL;
1545 }
1546 hash = calc_state_hash (nodes, context);
1547 spot = dfa->state_table + (hash & dfa->state_hash_mask);
1548
1549 for (i = 0 ; i < spot->num ; i++)
1550 {
1551 re_dfastate_t *state = spot->array[i];
1552 if (state->hash == hash
1553 && state->context == context
1554 && re_node_set_compare (state->entrance_nodes, nodes))
1555 return state;
1556 }
1557 /* There are no appropriate state in `dfa', create the new one. */
1558 new_state = create_cd_newstate (dfa, nodes, context, hash);
1559 if (BE (new_state == NULL, 0))
1560 *err = REG_ESPACE;
1561
1562 return new_state;
1563}
1564
1565/* Finish initialization of the new state NEWSTATE, and using its hash value
1566 HASH put in the appropriate bucket of DFA's state table. Return value
1567 indicates the error code if failed. */
1568
1569static reg_errcode_t
1570register_state (const re_dfa_t *dfa, re_dfastate_t *newstate,
1571 unsigned int hash)
1572{
1573 struct re_state_table_entry *spot;
1574 reg_errcode_t err;
1575 int i;
1576
1577 newstate->hash = hash;
1578 err = re_node_set_alloc (&newstate->non_eps_nodes, newstate->nodes.nelem);
1579 if (BE (err != REG_NOERROR, 0))
1580 return REG_ESPACE;
1581 for (i = 0; i < newstate->nodes.nelem; i++)
1582 {
1583 int elem = newstate->nodes.elems[i];
1584 if (!IS_EPSILON_NODE (dfa->nodes[elem].type))
1585 if (re_node_set_insert_last (&newstate->non_eps_nodes, elem) < 0)
1586 return REG_ESPACE;
1587 }
1588
1589 spot = dfa->state_table + (hash & dfa->state_hash_mask);
1590 if (BE (spot->alloc <= spot->num, 0))
1591 {
1592 int new_alloc = 2 * spot->num + 2;
1593 re_dfastate_t **new_array = re_realloc (spot->array, re_dfastate_t *,
1594 new_alloc);
1595 if (BE (new_array == NULL, 0))
1596 return REG_ESPACE;
1597 spot->array = new_array;
1598 spot->alloc = new_alloc;
1599 }
1600 spot->array[spot->num++] = newstate;
1601 return REG_NOERROR;
1602}
1603
1604static void
1605free_state (re_dfastate_t *state)
1606{
1607 re_node_set_free (&state->non_eps_nodes);
1608 re_node_set_free (&state->inveclosure);
1609 if (state->entrance_nodes != &state->nodes)
1610 {
1611 re_node_set_free (state->entrance_nodes);
1612 re_free (state->entrance_nodes);
1613 }
1614 re_node_set_free (&state->nodes);
1615 re_free (state->word_trtable);
1616 re_free (state->trtable);
1617 re_free (state);
1618}
1619
1620/* Create the new state which is independ of contexts.
1621 Return the new state if succeeded, otherwise return NULL. */
1622
1623static re_dfastate_t *
1624internal_function
1625create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
1626 unsigned int hash)
1627{
1628 int i;
1629 reg_errcode_t err;
1630 re_dfastate_t *newstate;
1631
1632 newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
1633 if (BE (newstate == NULL, 0))
1634 return NULL;
1635 err = re_node_set_init_copy (&newstate->nodes, nodes);
1636 if (BE (err != REG_NOERROR, 0))
1637 {
1638 re_free (newstate);
1639 return NULL;
1640 }
1641
1642 newstate->entrance_nodes = &newstate->nodes;
1643 for (i = 0 ; i < nodes->nelem ; i++)
1644 {
1645 re_token_t *node = dfa->nodes + nodes->elems[i];
1646 re_token_type_t type = node->type;
1647 if (type == CHARACTER && !node->constraint)
1648 continue;
1649#ifdef RE_ENABLE_I18N
1650 newstate->accept_mb |= node->accept_mb;
1651#endif /* RE_ENABLE_I18N */
1652
1653 /* If the state has the halt node, the state is a halt state. */
1654 if (type == END_OF_RE)
1655 newstate->halt = 1;
1656 else if (type == OP_BACK_REF)
1657 newstate->has_backref = 1;
1658 else if (type == ANCHOR || node->constraint)
1659 newstate->has_constraint = 1;
1660 }
1661 err = register_state (dfa, newstate, hash);
1662 if (BE (err != REG_NOERROR, 0))
1663 {
1664 free_state (newstate);
1665 newstate = NULL;
1666 }
1667 return newstate;
1668}
1669
1670/* Create the new state which is depend on the context CONTEXT.
1671 Return the new state if succeeded, otherwise return NULL. */
1672
1673static re_dfastate_t *
1674internal_function
1675create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
1676 unsigned int context, unsigned int hash)
1677{
1678 int i, nctx_nodes = 0;
1679 reg_errcode_t err;
1680 re_dfastate_t *newstate;
1681
1682 newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
1683 if (BE (newstate == NULL, 0))
1684 return NULL;
1685 err = re_node_set_init_copy (&newstate->nodes, nodes);
1686 if (BE (err != REG_NOERROR, 0))
1687 {
1688 re_free (newstate);
1689 return NULL;
1690 }
1691
1692 newstate->context = context;
1693 newstate->entrance_nodes = &newstate->nodes;
1694
1695 for (i = 0 ; i < nodes->nelem ; i++)
1696 {
1697 re_token_t *node = dfa->nodes + nodes->elems[i];
1698 re_token_type_t type = node->type;
1699 unsigned int constraint = node->constraint;
1700
1701 if (type == CHARACTER && !constraint)
1702 continue;
1703#ifdef RE_ENABLE_I18N
1704 newstate->accept_mb |= node->accept_mb;
1705#endif /* RE_ENABLE_I18N */
1706
1707 /* If the state has the halt node, the state is a halt state. */
1708 if (type == END_OF_RE)
1709 newstate->halt = 1;
1710 else if (type == OP_BACK_REF)
1711 newstate->has_backref = 1;
1712
1713 if (constraint)
1714 {
1715 if (newstate->entrance_nodes == &newstate->nodes)
1716 {
1717 newstate->entrance_nodes = re_malloc (re_node_set, 1);
1718 if (BE (newstate->entrance_nodes == NULL, 0))
1719 {
1720 free_state (newstate);
1721 return NULL;
1722 }
1723 if (re_node_set_init_copy (newstate->entrance_nodes, nodes)
1724 != REG_NOERROR)
1725 return NULL;
1726 nctx_nodes = 0;
1727 newstate->has_constraint = 1;
1728 }
1729
1730 if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context))
1731 {
1732 re_node_set_remove_at (&newstate->nodes, i - nctx_nodes);
1733 ++nctx_nodes;
1734 }
1735 }
1736 }
1737 err = register_state (dfa, newstate, hash);
1738 if (BE (err != REG_NOERROR, 0))
1739 {
1740 free_state (newstate);
1741 newstate = NULL;
1742 }
1743 return newstate;
1744}
diff --git a/win32/regex_internal.h b/win32/regex_internal.h
new file mode 100644
index 000000000..1495059ab
--- /dev/null
+++ b/win32/regex_internal.h
@@ -0,0 +1,810 @@
1/* Extended regular expression matching and search library.
2 Copyright (C) 2002-2005, 2007, 2008, 2010 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
20
21#ifndef _REGEX_INTERNAL_H
22#define _REGEX_INTERNAL_H 1
23
24#include <assert.h>
25#include <ctype.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30#if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC
31# include <langinfo.h>
32#endif
33#if defined HAVE_LOCALE_H || defined _LIBC
34# include <locale.h>
35#endif
36#if defined HAVE_WCHAR_H || defined _LIBC
37# include <wchar.h>
38#endif /* HAVE_WCHAR_H || _LIBC */
39#if defined HAVE_WCTYPE_H || defined _LIBC
40# include <wctype.h>
41#endif /* HAVE_WCTYPE_H || _LIBC */
42#if defined HAVE_STDBOOL_H || defined _LIBC
43# include <stdbool.h>
44#endif /* HAVE_STDBOOL_H || _LIBC */
45#if !defined(ZOS_USS)
46#if defined HAVE_STDINT_H || defined _LIBC
47# include <stdint.h>
48#endif /* HAVE_STDINT_H || _LIBC */
49#endif /* !ZOS_USS */
50#if defined _LIBC
51# include <bits/libc-lock.h>
52#else
53# define __libc_lock_define(CLASS,NAME)
54# define __libc_lock_init(NAME) do { } while (0)
55# define __libc_lock_lock(NAME) do { } while (0)
56# define __libc_lock_unlock(NAME) do { } while (0)
57#endif
58
59#ifndef GAWK
60/* In case that the system doesn't have isblank(). */
61#if !defined _LIBC && !defined HAVE_ISBLANK && !defined isblank
62# define isblank(ch) ((ch) == ' ' || (ch) == '\t')
63#endif
64#else /* GAWK */
65/*
66 * This is a freaking mess. On glibc systems you have to define
67 * a magic constant to get isblank() out of <ctype.h>, since it's
68 * a C99 function. To heck with all that and borrow a page from
69 * dfa.c's book.
70 */
71
72static int
73is_blank (int c)
74{
75 return (c == ' ' || c == '\t');
76}
77#endif /* GAWK */
78
79#ifdef _LIBC
80# ifndef _RE_DEFINE_LOCALE_FUNCTIONS
81# define _RE_DEFINE_LOCALE_FUNCTIONS 1
82# include <locale/localeinfo.h>
83# include <locale/elem-hash.h>
84# include <locale/coll-lookup.h>
85# endif
86#endif
87
88/* This is for other GNU distributions with internationalized messages. */
89#if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
90# include <libintl.h>
91# ifdef _LIBC
92# undef gettext
93# define gettext(msgid) \
94 INTUSE(__dcgettext) (_libc_intl_domainname, msgid, LC_MESSAGES)
95# endif
96#else
97# define gettext(msgid) (msgid)
98#endif
99
100#ifndef gettext_noop
101/* This define is so xgettext can find the internationalizable
102 strings. */
103# define gettext_noop(String) String
104#endif
105
106/* For loser systems without the definition. */
107#ifndef SIZE_MAX
108# define SIZE_MAX ((size_t) -1)
109#endif
110
111#ifndef NO_MBSUPPORT
112#include "mbsupport.h" /* gawk */
113#endif
114#ifndef MB_CUR_MAX
115#define MB_CUR_MAX 1
116#endif
117
118#if (defined MBS_SUPPORT) || defined _LIBC
119# define RE_ENABLE_I18N
120#endif
121
122#if __GNUC__ >= 3
123# define BE(expr, val) __builtin_expect (expr, val)
124#else
125# define BE(expr, val) (expr)
126# ifdef inline
127# undef inline
128# endif
129# define inline
130#endif
131
132/* Number of single byte character. */
133#define SBC_MAX 256
134
135#define COLL_ELEM_LEN_MAX 8
136
137/* The character which represents newline. */
138#define NEWLINE_CHAR '\n'
139#define WIDE_NEWLINE_CHAR L'\n'
140
141/* Rename to standard API for using out of glibc. */
142#ifndef _LIBC
143# ifdef __wctype
144# undef __wctype
145# endif
146# define __wctype wctype
147# ifdef __iswctype
148# undef __iswctype
149# endif
150# define __iswctype iswctype
151# define __btowc btowc
152# define __mbrtowc mbrtowc
153#undef __mempcpy /* GAWK */
154# define __mempcpy mempcpy
155# define __wcrtomb wcrtomb
156# define __regfree regfree
157# define attribute_hidden
158#endif /* not _LIBC */
159
160#ifdef __GNUC__
161# define __attribute(arg) __attribute__ (arg)
162#else
163# define __attribute(arg)
164#endif
165
166extern const char __re_error_msgid[] attribute_hidden;
167extern const size_t __re_error_msgid_idx[] attribute_hidden;
168
169/* An integer used to represent a set of bits. It must be unsigned,
170 and must be at least as wide as unsigned int. */
171typedef unsigned long int bitset_word_t;
172/* All bits set in a bitset_word_t. */
173#define BITSET_WORD_MAX ULONG_MAX
174/* Number of bits in a bitset_word_t. */
175#define BITSET_WORD_BITS (sizeof (bitset_word_t) * CHAR_BIT)
176/* Number of bitset_word_t in a bit_set. */
177#define BITSET_WORDS (SBC_MAX / BITSET_WORD_BITS)
178typedef bitset_word_t bitset_t[BITSET_WORDS];
179typedef bitset_word_t *re_bitset_ptr_t;
180typedef const bitset_word_t *re_const_bitset_ptr_t;
181
182#define bitset_set(set,i) \
183 (set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS)
184#define bitset_clear(set,i) \
185 (set[i / BITSET_WORD_BITS] &= ~((bitset_word_t) 1 << i % BITSET_WORD_BITS))
186#define bitset_contain(set,i) \
187 (set[i / BITSET_WORD_BITS] & ((bitset_word_t) 1 << i % BITSET_WORD_BITS))
188#define bitset_empty(set) memset (set, '\0', sizeof (bitset_t))
189#define bitset_set_all(set) memset (set, '\xff', sizeof (bitset_t))
190#define bitset_copy(dest,src) memcpy (dest, src, sizeof (bitset_t))
191
192#define PREV_WORD_CONSTRAINT 0x0001
193#define PREV_NOTWORD_CONSTRAINT 0x0002
194#define NEXT_WORD_CONSTRAINT 0x0004
195#define NEXT_NOTWORD_CONSTRAINT 0x0008
196#define PREV_NEWLINE_CONSTRAINT 0x0010
197#define NEXT_NEWLINE_CONSTRAINT 0x0020
198#define PREV_BEGBUF_CONSTRAINT 0x0040
199#define NEXT_ENDBUF_CONSTRAINT 0x0080
200#define WORD_DELIM_CONSTRAINT 0x0100
201#define NOT_WORD_DELIM_CONSTRAINT 0x0200
202
203typedef enum
204{
205 INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
206 WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
207 WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
208 INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
209 LINE_FIRST = PREV_NEWLINE_CONSTRAINT,
210 LINE_LAST = NEXT_NEWLINE_CONSTRAINT,
211 BUF_FIRST = PREV_BEGBUF_CONSTRAINT,
212 BUF_LAST = NEXT_ENDBUF_CONSTRAINT,
213 WORD_DELIM = WORD_DELIM_CONSTRAINT,
214 NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT
215} re_context_type;
216
217typedef struct
218{
219 int alloc;
220 int nelem;
221 int *elems;
222} re_node_set;
223
224typedef enum
225{
226 NON_TYPE = 0,
227
228 /* Node type, These are used by token, node, tree. */
229 CHARACTER = 1,
230 END_OF_RE = 2,
231 SIMPLE_BRACKET = 3,
232 OP_BACK_REF = 4,
233 OP_PERIOD = 5,
234#ifdef RE_ENABLE_I18N
235 COMPLEX_BRACKET = 6,
236 OP_UTF8_PERIOD = 7,
237#endif /* RE_ENABLE_I18N */
238
239 /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used
240 when the debugger shows values of this enum type. */
241#define EPSILON_BIT 8
242 OP_OPEN_SUBEXP = EPSILON_BIT | 0,
243 OP_CLOSE_SUBEXP = EPSILON_BIT | 1,
244 OP_ALT = EPSILON_BIT | 2,
245 OP_DUP_ASTERISK = EPSILON_BIT | 3,
246 ANCHOR = EPSILON_BIT | 4,
247
248 /* Tree type, these are used only by tree. */
249 CONCAT = 16,
250 SUBEXP = 17,
251
252 /* Token type, these are used only by token. */
253 OP_DUP_PLUS = 18,
254 OP_DUP_QUESTION,
255 OP_OPEN_BRACKET,
256 OP_CLOSE_BRACKET,
257 OP_CHARSET_RANGE,
258 OP_OPEN_DUP_NUM,
259 OP_CLOSE_DUP_NUM,
260 OP_NON_MATCH_LIST,
261 OP_OPEN_COLL_ELEM,
262 OP_CLOSE_COLL_ELEM,
263 OP_OPEN_EQUIV_CLASS,
264 OP_CLOSE_EQUIV_CLASS,
265 OP_OPEN_CHAR_CLASS,
266 OP_CLOSE_CHAR_CLASS,
267 OP_WORD,
268 OP_NOTWORD,
269 OP_SPACE,
270 OP_NOTSPACE,
271 BACK_SLASH
272
273} re_token_type_t;
274
275#ifdef RE_ENABLE_I18N
276typedef struct
277{
278 /* Multibyte characters. */
279 wchar_t *mbchars;
280
281 /* Collating symbols. */
282# ifdef _LIBC
283 int32_t *coll_syms;
284# endif
285
286 /* Equivalence classes. */
287# ifdef _LIBC
288 int32_t *equiv_classes;
289# endif
290
291 /* Range expressions. */
292# ifdef _LIBC
293 uint32_t *range_starts;
294 uint32_t *range_ends;
295# else /* not _LIBC */
296 wchar_t *range_starts;
297 wchar_t *range_ends;
298# endif /* not _LIBC */
299
300 /* Character classes. */
301 wctype_t *char_classes;
302
303 /* If this character set is the non-matching list. */
304 unsigned int non_match : 1;
305
306 /* # of multibyte characters. */
307 int nmbchars;
308
309 /* # of collating symbols. */
310 int ncoll_syms;
311
312 /* # of equivalence classes. */
313 int nequiv_classes;
314
315 /* # of range expressions. */
316 int nranges;
317
318 /* # of character classes. */
319 int nchar_classes;
320} re_charset_t;
321#endif /* RE_ENABLE_I18N */
322
323typedef struct
324{
325 union
326 {
327 unsigned char c; /* for CHARACTER */
328 re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */
329#ifdef RE_ENABLE_I18N
330 re_charset_t *mbcset; /* for COMPLEX_BRACKET */
331#endif /* RE_ENABLE_I18N */
332 int idx; /* for BACK_REF */
333 re_context_type ctx_type; /* for ANCHOR */
334 } opr;
335#if __GNUC__ >= 2
336 re_token_type_t type : 8;
337#else
338 re_token_type_t type;
339#endif
340 unsigned int constraint : 10; /* context constraint */
341 unsigned int duplicated : 1;
342 unsigned int opt_subexp : 1;
343#ifdef RE_ENABLE_I18N
344 unsigned int accept_mb : 1;
345 /* These 2 bits can be moved into the union if needed (e.g. if running out
346 of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */
347 unsigned int mb_partial : 1;
348#endif
349 unsigned int word_char : 1;
350} re_token_t;
351
352#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT)
353
354struct re_string_t
355{
356 /* Indicate the raw buffer which is the original string passed as an
357 argument of regexec(), re_search(), etc.. */
358 const unsigned char *raw_mbs;
359 /* Store the multibyte string. In case of "case insensitive mode" like
360 REG_ICASE, upper cases of the string are stored, otherwise MBS points
361 the same address that RAW_MBS points. */
362 unsigned char *mbs;
363#ifdef RE_ENABLE_I18N
364 /* Store the wide character string which is corresponding to MBS. */
365 wint_t *wcs;
366 int *offsets;
367 mbstate_t cur_state;
368#endif
369 /* Index in RAW_MBS. Each character mbs[i] corresponds to
370 raw_mbs[raw_mbs_idx + i]. */
371 int raw_mbs_idx;
372 /* The length of the valid characters in the buffers. */
373 int valid_len;
374 /* The corresponding number of bytes in raw_mbs array. */
375 int valid_raw_len;
376 /* The length of the buffers MBS and WCS. */
377 int bufs_len;
378 /* The index in MBS, which is updated by re_string_fetch_byte. */
379 int cur_idx;
380 /* length of RAW_MBS array. */
381 int raw_len;
382 /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */
383 int len;
384 /* End of the buffer may be shorter than its length in the cases such
385 as re_match_2, re_search_2. Then, we use STOP for end of the buffer
386 instead of LEN. */
387 int raw_stop;
388 /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */
389 int stop;
390
391 /* The context of mbs[0]. We store the context independently, since
392 the context of mbs[0] may be different from raw_mbs[0], which is
393 the beginning of the input string. */
394 unsigned int tip_context;
395 /* The translation passed as a part of an argument of re_compile_pattern. */
396 RE_TRANSLATE_TYPE trans;
397 /* Copy of re_dfa_t's word_char. */
398 re_const_bitset_ptr_t word_char;
399 /* 1 if REG_ICASE. */
400 unsigned char icase;
401 unsigned char is_utf8;
402 unsigned char map_notascii;
403 unsigned char mbs_allocated;
404 unsigned char offsets_needed;
405 unsigned char newline_anchor;
406 unsigned char word_ops_used;
407 int mb_cur_max;
408};
409typedef struct re_string_t re_string_t;
410
411
412struct re_dfa_t;
413typedef struct re_dfa_t re_dfa_t;
414
415#ifndef _LIBC
416# ifdef __i386__
417# define internal_function __attribute ((regparm (3), stdcall))
418# else
419# define internal_function
420# endif
421#endif
422
423#ifndef NOT_IN_libc
424static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr,
425 int new_buf_len)
426 internal_function;
427# ifdef RE_ENABLE_I18N
428static void build_wcs_buffer (re_string_t *pstr) internal_function;
429static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr)
430 internal_function;
431# endif /* RE_ENABLE_I18N */
432static void build_upper_buffer (re_string_t *pstr) internal_function;
433static void re_string_translate_buffer (re_string_t *pstr) internal_function;
434static unsigned int re_string_context_at (const re_string_t *input, int idx,
435 int eflags)
436 internal_function __attribute ((pure));
437#endif
438#define re_string_peek_byte(pstr, offset) \
439 ((pstr)->mbs[(pstr)->cur_idx + offset])
440#define re_string_fetch_byte(pstr) \
441 ((pstr)->mbs[(pstr)->cur_idx++])
442#define re_string_first_byte(pstr, idx) \
443 ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF)
444#define re_string_is_single_byte_char(pstr, idx) \
445 ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \
446 || (pstr)->wcs[(idx) + 1] != WEOF))
447#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx)
448#define re_string_cur_idx(pstr) ((pstr)->cur_idx)
449#define re_string_get_buffer(pstr) ((pstr)->mbs)
450#define re_string_length(pstr) ((pstr)->len)
451#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx])
452#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx))
453#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx))
454
455#ifndef _LIBC
456# if HAVE_ALLOCA
457# ifdef (_MSC_VER)
458# include <malloc.h>
459# define __libc_use_alloca(n) 0
460# else
461# include <alloca.h>
462/* The OS usually guarantees only one guard page at the bottom of the stack,
463 and a page size can be as small as 4096 bytes. So we cannot safely
464 allocate anything larger than 4096 bytes. Also care for the possibility
465 of a few compiler-allocated temporary stack slots. */
466# define __libc_use_alloca(n) ((n) < 4032)
467# endif
468# else
469/* alloca is implemented with malloc, so just use malloc. */
470# define __libc_use_alloca(n) 0
471# endif
472#endif
473
474#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t)))
475/* SunOS 4.1.x realloc doesn't accept null pointers: pre-Standard C. Sigh. */
476#define re_realloc(p,t,n) ((p != NULL) ? (t *) realloc (p,(n)*sizeof(t)) : (t *) calloc(n,sizeof(t)))
477#define re_free(p) free (p)
478
479struct bin_tree_t
480{
481 struct bin_tree_t *parent;
482 struct bin_tree_t *left;
483 struct bin_tree_t *right;
484 struct bin_tree_t *first;
485 struct bin_tree_t *next;
486
487 re_token_t token;
488
489 /* `node_idx' is the index in dfa->nodes, if `type' == 0.
490 Otherwise `type' indicate the type of this node. */
491 int node_idx;
492};
493typedef struct bin_tree_t bin_tree_t;
494
495#define BIN_TREE_STORAGE_SIZE \
496 ((1024 - sizeof (void *)) / sizeof (bin_tree_t))
497
498struct bin_tree_storage_t
499{
500 struct bin_tree_storage_t *next;
501 bin_tree_t data[BIN_TREE_STORAGE_SIZE];
502};
503typedef struct bin_tree_storage_t bin_tree_storage_t;
504
505#define CONTEXT_WORD 1
506#define CONTEXT_NEWLINE (CONTEXT_WORD << 1)
507#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1)
508#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1)
509
510#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD)
511#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE)
512#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF)
513#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF)
514#define IS_ORDINARY_CONTEXT(c) ((c) == 0)
515
516#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_')
517#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR)
518#define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_')
519#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR)
520
521#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \
522 ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
523 || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
524 || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\
525 || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context)))
526
527#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \
528 ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
529 || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
530 || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \
531 || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context)))
532
533struct re_dfastate_t
534{
535 unsigned int hash;
536 re_node_set nodes;
537 re_node_set non_eps_nodes;
538 re_node_set inveclosure;
539 re_node_set *entrance_nodes;
540 struct re_dfastate_t **trtable, **word_trtable;
541 unsigned int context : 4;
542 unsigned int halt : 1;
543 /* If this state can accept `multi byte'.
544 Note that we refer to multibyte characters, and multi character
545 collating elements as `multi byte'. */
546 unsigned int accept_mb : 1;
547 /* If this state has backreference node(s). */
548 unsigned int has_backref : 1;
549 unsigned int has_constraint : 1;
550};
551typedef struct re_dfastate_t re_dfastate_t;
552
553struct re_state_table_entry
554{
555 int num;
556 int alloc;
557 re_dfastate_t **array;
558};
559
560/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */
561
562typedef struct
563{
564 int next_idx;
565 int alloc;
566 re_dfastate_t **array;
567} state_array_t;
568
569/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */
570
571typedef struct
572{
573 int node;
574 int str_idx; /* The position NODE match at. */
575 state_array_t path;
576} re_sub_match_last_t;
577
578/* Store information about the node NODE whose type is OP_OPEN_SUBEXP.
579 And information about the node, whose type is OP_CLOSE_SUBEXP,
580 corresponding to NODE is stored in LASTS. */
581
582typedef struct
583{
584 int str_idx;
585 int node;
586 state_array_t *path;
587 int alasts; /* Allocation size of LASTS. */
588 int nlasts; /* The number of LASTS. */
589 re_sub_match_last_t **lasts;
590} re_sub_match_top_t;
591
592struct re_backref_cache_entry
593{
594 int node;
595 int str_idx;
596 int subexp_from;
597 int subexp_to;
598 char more;
599 char unused;
600 unsigned short int eps_reachable_subexps_map;
601};
602
603typedef struct
604{
605 /* The string object corresponding to the input string. */
606 re_string_t input;
607#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
608 const re_dfa_t *const dfa;
609#else
610 const re_dfa_t *dfa;
611#endif
612 /* EFLAGS of the argument of regexec. */
613 int eflags;
614 /* Where the matching ends. */
615 int match_last;
616 int last_node;
617 /* The state log used by the matcher. */
618 re_dfastate_t **state_log;
619 int state_log_top;
620 /* Back reference cache. */
621 int nbkref_ents;
622 int abkref_ents;
623 struct re_backref_cache_entry *bkref_ents;
624 int max_mb_elem_len;
625 int nsub_tops;
626 int asub_tops;
627 re_sub_match_top_t **sub_tops;
628} re_match_context_t;
629
630typedef struct
631{
632 re_dfastate_t **sifted_states;
633 re_dfastate_t **limited_states;
634 int last_node;
635 int last_str_idx;
636 re_node_set limits;
637} re_sift_context_t;
638
639struct re_fail_stack_ent_t
640{
641 int idx;
642 int node;
643 regmatch_t *regs;
644 re_node_set eps_via_nodes;
645};
646
647struct re_fail_stack_t
648{
649 int num;
650 int alloc;
651 struct re_fail_stack_ent_t *stack;
652};
653
654struct re_dfa_t
655{
656 re_token_t *nodes;
657 size_t nodes_alloc;
658 size_t nodes_len;
659 int *nexts;
660 int *org_indices;
661 re_node_set *edests;
662 re_node_set *eclosures;
663 re_node_set *inveclosures;
664 struct re_state_table_entry *state_table;
665 re_dfastate_t *init_state;
666 re_dfastate_t *init_state_word;
667 re_dfastate_t *init_state_nl;
668 re_dfastate_t *init_state_begbuf;
669 bin_tree_t *str_tree;
670 bin_tree_storage_t *str_tree_storage;
671 re_bitset_ptr_t sb_char;
672 int str_tree_storage_idx;
673
674 /* number of subexpressions `re_nsub' is in regex_t. */
675 unsigned int state_hash_mask;
676 int init_node;
677 int nbackref; /* The number of backreference in this dfa. */
678
679 /* Bitmap expressing which backreference is used. */
680 bitset_word_t used_bkref_map;
681 bitset_word_t completed_bkref_map;
682
683 unsigned int has_plural_match : 1;
684 /* If this dfa has "multibyte node", which is a backreference or
685 a node which can accept multibyte character or multi character
686 collating element. */
687 unsigned int has_mb_node : 1;
688 unsigned int is_utf8 : 1;
689 unsigned int map_notascii : 1;
690 unsigned int word_ops_used : 1;
691 int mb_cur_max;
692 bitset_t word_char;
693 reg_syntax_t syntax;
694 int *subexp_map;
695#ifdef DEBUG
696 char* re_str;
697#endif
698#if defined _LIBC
699 __libc_lock_define (, lock)
700#endif
701};
702
703#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set))
704#define re_node_set_remove(set,id) \
705 (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1))
706#define re_node_set_empty(p) ((p)->nelem = 0)
707#define re_node_set_free(set) re_free ((set)->elems)
708
709
710typedef enum
711{
712 SB_CHAR,
713 MB_CHAR,
714 EQUIV_CLASS,
715 COLL_SYM,
716 CHAR_CLASS
717} bracket_elem_type;
718
719typedef struct
720{
721 bracket_elem_type type;
722 union
723 {
724 unsigned char ch;
725 unsigned char *name;
726 wchar_t wch;
727 } opr;
728} bracket_elem_t;
729
730
731/* Inline functions for bitset operation. */
732static inline void
733bitset_not (bitset_t set)
734{
735 int bitset_i;
736 for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
737 set[bitset_i] = ~set[bitset_i];
738}
739
740static inline void
741bitset_merge (bitset_t dest, const bitset_t src)
742{
743 int bitset_i;
744 for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
745 dest[bitset_i] |= src[bitset_i];
746}
747
748static inline void
749bitset_mask (bitset_t dest, const bitset_t src)
750{
751 int bitset_i;
752 for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
753 dest[bitset_i] &= src[bitset_i];
754}
755
756#ifdef RE_ENABLE_I18N
757/* Inline functions for re_string. */
758static inline int
759internal_function __attribute ((pure))
760re_string_char_size_at (const re_string_t *pstr, int idx)
761{
762 int byte_idx;
763 if (pstr->mb_cur_max == 1)
764 return 1;
765 for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx)
766 if (pstr->wcs[idx + byte_idx] != WEOF)
767 break;
768 return byte_idx;
769}
770
771static inline wint_t
772internal_function __attribute ((pure))
773re_string_wchar_at (const re_string_t *pstr, int idx)
774{
775 if (pstr->mb_cur_max == 1)
776 return (wint_t) pstr->mbs[idx];
777 return (wint_t) pstr->wcs[idx];
778}
779
780# ifndef NOT_IN_libc
781static int
782internal_function __attribute ((pure))
783re_string_elem_size_at (const re_string_t *pstr, int idx)
784{
785# ifdef _LIBC
786 const unsigned char *p, *extra;
787 const int32_t *table, *indirect;
788 int32_t tmp;
789# include <locale/weight.h>
790 uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
791
792 if (nrules != 0)
793 {
794 table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
795 extra = (const unsigned char *)
796 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
797 indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
798 _NL_COLLATE_INDIRECTMB);
799 p = pstr->mbs + idx;
800 tmp = findidx (&p);
801 return p - pstr->mbs - idx;
802 }
803 else
804# endif /* _LIBC */
805 return 1;
806}
807# endif
808#endif /* RE_ENABLE_I18N */
809
810#endif /* _REGEX_INTERNAL_H */
diff --git a/win32/regexec.c b/win32/regexec.c
new file mode 100644
index 000000000..eb5e1d443
--- /dev/null
+++ b/win32/regexec.c
@@ -0,0 +1,4369 @@
1/* Extended regular expression matching and search library.
2 Copyright (C) 2002-2005, 2007, 2009, 2010 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA. */
20
21static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags,
22 int n) internal_function;
23static void match_ctx_clean (re_match_context_t *mctx) internal_function;
24static void match_ctx_free (re_match_context_t *cache) internal_function;
25static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, int node,
26 int str_idx, int from, int to)
27 internal_function;
28static int search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx)
29 internal_function;
30static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, int node,
31 int str_idx) internal_function;
32static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop,
33 int node, int str_idx)
34 internal_function;
35static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
36 re_dfastate_t **limited_sts, int last_node,
37 int last_str_idx)
38 internal_function;
39static reg_errcode_t re_search_internal (const regex_t *preg,
40 const char *string, int length,
41 int start, int range, int stop,
42 size_t nmatch, regmatch_t pmatch[],
43 int eflags);
44static int re_search_2_stub (struct re_pattern_buffer *bufp,
45 const char *string1, int length1,
46 const char *string2, int length2,
47 int start, int range, struct re_registers *regs,
48 int stop, int ret_len);
49static int re_search_stub (struct re_pattern_buffer *bufp,
50 const char *string, int length, int start,
51 int range, int stop, struct re_registers *regs,
52 int ret_len);
53static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch,
54 int nregs, int regs_allocated);
55static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx);
56static int check_matching (re_match_context_t *mctx, int fl_longest_match,
57 int *p_match_first) internal_function;
58static int check_halt_state_context (const re_match_context_t *mctx,
59 const re_dfastate_t *state, int idx)
60 internal_function;
61static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
62 regmatch_t *prev_idx_match, int cur_node,
63 int cur_idx, int nmatch) internal_function;
64static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs,
65 int str_idx, int dest_node, int nregs,
66 regmatch_t *regs,
67 re_node_set *eps_via_nodes)
68 internal_function;
69static reg_errcode_t set_regs (const regex_t *preg,
70 const re_match_context_t *mctx,
71 size_t nmatch, regmatch_t *pmatch,
72 int fl_backtrack) internal_function;
73static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs)
74 internal_function;
75
76#ifdef RE_ENABLE_I18N
77static int sift_states_iter_mb (const re_match_context_t *mctx,
78 re_sift_context_t *sctx,
79 int node_idx, int str_idx, int max_str_idx)
80 internal_function;
81#endif /* RE_ENABLE_I18N */
82static reg_errcode_t sift_states_backward (const re_match_context_t *mctx,
83 re_sift_context_t *sctx)
84 internal_function;
85static reg_errcode_t build_sifted_states (const re_match_context_t *mctx,
86 re_sift_context_t *sctx, int str_idx,
87 re_node_set *cur_dest)
88 internal_function;
89static reg_errcode_t update_cur_sifted_state (const re_match_context_t *mctx,
90 re_sift_context_t *sctx,
91 int str_idx,
92 re_node_set *dest_nodes)
93 internal_function;
94static reg_errcode_t add_epsilon_src_nodes (const re_dfa_t *dfa,
95 re_node_set *dest_nodes,
96 const re_node_set *candidates)
97 internal_function;
98static int check_dst_limits (const re_match_context_t *mctx,
99 re_node_set *limits,
100 int dst_node, int dst_idx, int src_node,
101 int src_idx) internal_function;
102static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx,
103 int boundaries, int subexp_idx,
104 int from_node, int bkref_idx)
105 internal_function;
106static int check_dst_limits_calc_pos (const re_match_context_t *mctx,
107 int limit, int subexp_idx,
108 int node, int str_idx,
109 int bkref_idx) internal_function;
110static reg_errcode_t check_subexp_limits (const re_dfa_t *dfa,
111 re_node_set *dest_nodes,
112 const re_node_set *candidates,
113 re_node_set *limits,
114 struct re_backref_cache_entry *bkref_ents,
115 int str_idx) internal_function;
116static reg_errcode_t sift_states_bkref (const re_match_context_t *mctx,
117 re_sift_context_t *sctx,
118 int str_idx, const re_node_set *candidates)
119 internal_function;
120static reg_errcode_t merge_state_array (const re_dfa_t *dfa,
121 re_dfastate_t **dst,
122 re_dfastate_t **src, int num)
123 internal_function;
124static re_dfastate_t *find_recover_state (reg_errcode_t *err,
125 re_match_context_t *mctx) internal_function;
126static re_dfastate_t *transit_state (reg_errcode_t *err,
127 re_match_context_t *mctx,
128 re_dfastate_t *state) internal_function;
129static re_dfastate_t *merge_state_with_log (reg_errcode_t *err,
130 re_match_context_t *mctx,
131 re_dfastate_t *next_state)
132 internal_function;
133static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx,
134 re_node_set *cur_nodes,
135 int str_idx) internal_function;
136#if 0
137static re_dfastate_t *transit_state_sb (reg_errcode_t *err,
138 re_match_context_t *mctx,
139 re_dfastate_t *pstate)
140 internal_function;
141#endif
142#ifdef RE_ENABLE_I18N
143static reg_errcode_t transit_state_mb (re_match_context_t *mctx,
144 re_dfastate_t *pstate)
145 internal_function;
146#endif /* RE_ENABLE_I18N */
147static reg_errcode_t transit_state_bkref (re_match_context_t *mctx,
148 const re_node_set *nodes)
149 internal_function;
150static reg_errcode_t get_subexp (re_match_context_t *mctx,
151 int bkref_node, int bkref_str_idx)
152 internal_function;
153static reg_errcode_t get_subexp_sub (re_match_context_t *mctx,
154 const re_sub_match_top_t *sub_top,
155 re_sub_match_last_t *sub_last,
156 int bkref_node, int bkref_str)
157 internal_function;
158static int find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
159 int subexp_idx, int type) internal_function;
160static reg_errcode_t check_arrival (re_match_context_t *mctx,
161 state_array_t *path, int top_node,
162 int top_str, int last_node, int last_str,
163 int type) internal_function;
164static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx,
165 int str_idx,
166 re_node_set *cur_nodes,
167 re_node_set *next_nodes)
168 internal_function;
169static reg_errcode_t check_arrival_expand_ecl (const re_dfa_t *dfa,
170 re_node_set *cur_nodes,
171 int ex_subexp, int type)
172 internal_function;
173static reg_errcode_t check_arrival_expand_ecl_sub (const re_dfa_t *dfa,
174 re_node_set *dst_nodes,
175 int target, int ex_subexp,
176 int type) internal_function;
177static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx,
178 re_node_set *cur_nodes, int cur_str,
179 int subexp_num, int type)
180 internal_function;
181static int build_trtable (const re_dfa_t *dfa,
182 re_dfastate_t *state) internal_function;
183#ifdef RE_ENABLE_I18N
184static int check_node_accept_bytes (const re_dfa_t *dfa, int node_idx,
185 const re_string_t *input, int idx)
186 internal_function;
187# ifdef _LIBC
188static unsigned int find_collation_sequence_value (const unsigned char *mbs,
189 size_t name_len)
190 internal_function;
191# endif /* _LIBC */
192#endif /* RE_ENABLE_I18N */
193static int group_nodes_into_DFAstates (const re_dfa_t *dfa,
194 const re_dfastate_t *state,
195 re_node_set *states_node,
196 bitset_t *states_ch) internal_function;
197static int check_node_accept (const re_match_context_t *mctx,
198 const re_token_t *node, int idx)
199 internal_function;
200static reg_errcode_t extend_buffers (re_match_context_t *mctx)
201 internal_function;
202
203/* Entry point for POSIX code. */
204
205/* regexec searches for a given pattern, specified by PREG, in the
206 string STRING.
207
208 If NMATCH is zero or REG_NOSUB was set in the cflags argument to
209 `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
210 least NMATCH elements, and we set them to the offsets of the
211 corresponding matched substrings.
212
213 EFLAGS specifies `execution flags' which affect matching: if
214 REG_NOTBOL is set, then ^ does not match at the beginning of the
215 string; if REG_NOTEOL is set, then $ does not match at the end.
216
217 We return 0 if we find a match and REG_NOMATCH if not. */
218
219int
220regexec (
221 const regex_t *__restrict preg,
222 const char *__restrict string,
223 size_t nmatch,
224 regmatch_t pmatch[],
225 int eflags)
226{
227 reg_errcode_t err;
228 int start, length;
229
230 if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND))
231 return REG_BADPAT;
232
233 if (eflags & REG_STARTEND)
234 {
235 start = pmatch[0].rm_so;
236 length = pmatch[0].rm_eo;
237 }
238 else
239 {
240 start = 0;
241 length = strlen (string);
242 }
243
244 __libc_lock_lock (dfa->lock);
245 if (preg->no_sub)
246 err = re_search_internal (preg, string, length, start, length - start,
247 length, 0, NULL, eflags);
248 else
249 err = re_search_internal (preg, string, length, start, length - start,
250 length, nmatch, pmatch, eflags);
251 __libc_lock_unlock (dfa->lock);
252 return err != REG_NOERROR;
253}
254
255#ifdef _LIBC
256# include <shlib-compat.h>
257versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4);
258
259# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
260__typeof__ (__regexec) __compat_regexec;
261
262int
263attribute_compat_text_section
264__compat_regexec (const regex_t *__restrict preg,
265 const char *__restrict string, size_t nmatch,
266 regmatch_t pmatch[], int eflags)
267{
268 return regexec (preg, string, nmatch, pmatch,
269 eflags & (REG_NOTBOL | REG_NOTEOL));
270}
271compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
272# endif
273#endif
274
275/* Entry points for GNU code. */
276
277/* re_match, re_search, re_match_2, re_search_2
278
279 The former two functions operate on STRING with length LENGTH,
280 while the later two operate on concatenation of STRING1 and STRING2
281 with lengths LENGTH1 and LENGTH2, respectively.
282
283 re_match() matches the compiled pattern in BUFP against the string,
284 starting at index START.
285
286 re_search() first tries matching at index START, then it tries to match
287 starting from index START + 1, and so on. The last start position tried
288 is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same
289 way as re_match().)
290
291 The parameter STOP of re_{match,search}_2 specifies that no match exceeding
292 the first STOP characters of the concatenation of the strings should be
293 concerned.
294
295 If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match
296 and all groups is stroed in REGS. (For the "_2" variants, the offsets are
297 computed relative to the concatenation, not relative to the individual
298 strings.)
299
300 On success, re_match* functions return the length of the match, re_search*
301 return the position of the start of the match. Return value -1 means no
302 match was found and -2 indicates an internal error. */
303
304int
305re_match (struct re_pattern_buffer *bufp,
306 const char *string,
307 int length,
308 int start,
309 struct re_registers *regs)
310{
311 return re_search_stub (bufp, string, length, start, 0, length, regs, 1);
312}
313#ifdef _LIBC
314weak_alias (__re_match, re_match)
315#endif
316
317int
318re_search (struct re_pattern_buffer *bufp,
319 const char *string,
320 int length, int start, int range,
321 struct re_registers *regs)
322{
323 return re_search_stub (bufp, string, length, start, range, length, regs, 0);
324}
325#ifdef _LIBC
326weak_alias (__re_search, re_search)
327#endif
328
329int
330re_match_2 (struct re_pattern_buffer *bufp,
331 const char *string1, int length1,
332 const char *string2, int length2, int start,
333 struct re_registers *regs, int stop)
334{
335 return re_search_2_stub (bufp, string1, length1, string2, length2,
336 start, 0, regs, stop, 1);
337}
338#ifdef _LIBC
339weak_alias (__re_match_2, re_match_2)
340#endif
341
342int
343re_search_2 (struct re_pattern_buffer *bufp,
344 const char *string1, int length1,
345 const char *string2, int length2, int start,
346 int range, struct re_registers *regs, int stop)
347{
348 return re_search_2_stub (bufp, string1, length1, string2, length2,
349 start, range, regs, stop, 0);
350}
351#ifdef _LIBC
352weak_alias (__re_search_2, re_search_2)
353#endif
354
355static int
356re_search_2_stub (struct re_pattern_buffer *bufp,
357 const char *string1, int length1,
358 const char *string2, int length2, int start,
359 int range, struct re_registers *regs,
360 int stop, int ret_len)
361{
362 const char *str;
363 int rval;
364 int len = length1 + length2;
365 int free_str = 0;
366
367 if (BE (length1 < 0 || length2 < 0 || stop < 0, 0))
368 return -2;
369
370 /* Concatenate the strings. */
371 if (length2 > 0)
372 if (length1 > 0)
373 {
374 char *s = re_malloc (char, len);
375
376 if (BE (s == NULL, 0))
377 return -2;
378 memcpy (s, string1, length1);
379 memcpy (s + length1, string2, length2);
380 str = s;
381 free_str = 1;
382 }
383 else
384 str = string2;
385 else
386 str = string1;
387
388 rval = re_search_stub (bufp, str, len, start, range, stop, regs, ret_len);
389 if (free_str)
390 re_free ((char *) str);
391 return rval;
392}
393
394/* The parameters have the same meaning as those of re_search.
395 Additional parameters:
396 If RET_LEN is nonzero the length of the match is returned (re_match style);
397 otherwise the position of the match is returned. */
398
399static int
400re_search_stub (struct re_pattern_buffer *bufp,
401 const char *string, int length, int start,
402 int range, int stop,
403 struct re_registers *regs, int ret_len)
404{
405 reg_errcode_t result;
406 regmatch_t *pmatch;
407 int nregs, rval;
408 int eflags = 0;
409
410 /* Check for out-of-range. */
411 if (BE (start < 0 || start > length, 0))
412 return -1;
413 if (BE (start + range > length, 0))
414 range = length - start;
415 else if (BE (start + range < 0, 0))
416 range = -start;
417
418 __libc_lock_lock (dfa->lock);
419
420 eflags |= (bufp->not_bol) ? REG_NOTBOL : 0;
421 eflags |= (bufp->not_eol) ? REG_NOTEOL : 0;
422
423 /* Compile fastmap if we haven't yet. */
424 if (range > 0 && bufp->fastmap != NULL && !bufp->fastmap_accurate)
425 re_compile_fastmap (bufp);
426
427 if (BE (bufp->no_sub, 0))
428 regs = NULL;
429
430 /* We need at least 1 register. */
431 if (regs == NULL)
432 nregs = 1;
433 else if (BE (bufp->regs_allocated == REGS_FIXED &&
434 regs->num_regs < bufp->re_nsub + 1, 0))
435 {
436 nregs = regs->num_regs;
437 if (BE (nregs < 1, 0))
438 {
439 /* Nothing can be copied to regs. */
440 regs = NULL;
441 nregs = 1;
442 }
443 }
444 else
445 nregs = bufp->re_nsub + 1;
446 pmatch = re_malloc (regmatch_t, nregs);
447 if (BE (pmatch == NULL, 0))
448 {
449 rval = -2;
450 goto out;
451 }
452
453 result = re_search_internal (bufp, string, length, start, range, stop,
454 nregs, pmatch, eflags);
455
456 rval = 0;
457
458 /* I hope we needn't fill their regs with -1's when no match was found. */
459 if (result != REG_NOERROR)
460 rval = -1;
461 else if (regs != NULL)
462 {
463 /* If caller wants register contents data back, copy them. */
464 bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs,
465 bufp->regs_allocated);
466 if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0))
467 rval = -2;
468 }
469
470 if (BE (rval == 0, 1))
471 {
472 if (ret_len)
473 {
474 assert (pmatch[0].rm_so == start);
475 rval = pmatch[0].rm_eo - start;
476 }
477 else
478 rval = pmatch[0].rm_so;
479 }
480 re_free (pmatch);
481 out:
482 __libc_lock_unlock (dfa->lock);
483 return rval;
484}
485
486static unsigned
487re_copy_regs (struct re_registers *regs,
488 regmatch_t *pmatch,
489 int nregs, int regs_allocated)
490{
491 int rval = REGS_REALLOCATE;
492 int i;
493 int need_regs = nregs + 1;
494 /* We need one extra element beyond `num_regs' for the `-1' marker GNU code
495 uses. */
496
497 /* Have the register data arrays been allocated? */
498 if (regs_allocated == REGS_UNALLOCATED)
499 { /* No. So allocate them with malloc. */
500 regs->start = re_malloc (regoff_t, need_regs);
501 if (BE (regs->start == NULL, 0))
502 return REGS_UNALLOCATED;
503 regs->end = re_malloc (regoff_t, need_regs);
504 if (BE (regs->end == NULL, 0))
505 {
506 re_free (regs->start);
507 return REGS_UNALLOCATED;
508 }
509 regs->num_regs = need_regs;
510 }
511 else if (regs_allocated == REGS_REALLOCATE)
512 { /* Yes. If we need more elements than were already
513 allocated, reallocate them. If we need fewer, just
514 leave it alone. */
515 if (BE (need_regs > regs->num_regs, 0))
516 {
517 regoff_t *new_start = re_realloc (regs->start, regoff_t, need_regs);
518 regoff_t *new_end;
519 if (BE (new_start == NULL, 0))
520 return REGS_UNALLOCATED;
521 new_end = re_realloc (regs->end, regoff_t, need_regs);
522 if (BE (new_end == NULL, 0))
523 {
524 re_free (new_start);
525 return REGS_UNALLOCATED;
526 }
527 regs->start = new_start;
528 regs->end = new_end;
529 regs->num_regs = need_regs;
530 }
531 }
532 else
533 {
534 assert (regs_allocated == REGS_FIXED);
535 /* This function may not be called with REGS_FIXED and nregs too big. */
536 assert (regs->num_regs >= nregs);
537 rval = REGS_FIXED;
538 }
539
540 /* Copy the regs. */
541 for (i = 0; i < nregs; ++i)
542 {
543 regs->start[i] = pmatch[i].rm_so;
544 regs->end[i] = pmatch[i].rm_eo;
545 }
546 for ( ; i < regs->num_regs; ++i)
547 regs->start[i] = regs->end[i] = -1;
548
549 return rval;
550}
551
552/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
553 ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
554 this memory for recording register information. STARTS and ENDS
555 must be allocated using the malloc library routine, and must each
556 be at least NUM_REGS * sizeof (regoff_t) bytes long.
557
558 If NUM_REGS == 0, then subsequent matches should allocate their own
559 register data.
560
561 Unless this function is called, the first search or match using
562 PATTERN_BUFFER will allocate its own register data, without
563 freeing the old data. */
564
565void
566re_set_registers (struct re_pattern_buffer *bufp,
567 struct re_registers *regs,
568 unsigned num_regs,
569 regoff_t *starts,
570 regoff_t *ends)
571{
572 if (num_regs)
573 {
574 bufp->regs_allocated = REGS_REALLOCATE;
575 regs->num_regs = num_regs;
576 regs->start = starts;
577 regs->end = ends;
578 }
579 else
580 {
581 bufp->regs_allocated = REGS_UNALLOCATED;
582 regs->num_regs = 0;
583 regs->start = regs->end = (regoff_t *) 0;
584 }
585}
586#ifdef _LIBC
587weak_alias (__re_set_registers, re_set_registers)
588#endif
589
590/* Entry points compatible with 4.2 BSD regex library. We don't define
591 them unless specifically requested. */
592
593#if defined _REGEX_RE_COMP || defined _LIBC
594int
595# ifdef _LIBC
596weak_function
597# endif
598re_exec (s)
599 const char *s;
600{
601 return 0 == regexec (&re_comp_buf, s, 0, NULL, 0);
602}
603#endif /* _REGEX_RE_COMP */
604
605/* Internal entry point. */
606
607/* Searches for a compiled pattern PREG in the string STRING, whose
608 length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same
609 mingings with regexec. START, and RANGE have the same meanings
610 with re_search.
611 Return REG_NOERROR if we find a match, and REG_NOMATCH if not,
612 otherwise return the error code.
613 Note: We assume front end functions already check ranges.
614 (START + RANGE >= 0 && START + RANGE <= LENGTH) */
615
616static reg_errcode_t
617re_search_internal (const regex_t *preg,
618 const char *string,
619 int length, int start, int range, int stop,
620 size_t nmatch, regmatch_t pmatch[],
621 int eflags)
622{
623 reg_errcode_t err;
624 const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer;
625 int left_lim, right_lim, incr;
626 int fl_longest_match, match_first, match_kind, match_last = -1;
627 int extra_nmatch;
628 int sb, ch;
629#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
630 re_match_context_t mctx = { .dfa = dfa };
631#else
632 re_match_context_t mctx;
633#endif
634 char *fastmap = (preg->fastmap != NULL && preg->fastmap_accurate
635 && range && !preg->can_be_null) ? preg->fastmap : NULL;
636 RE_TRANSLATE_TYPE t = preg->translate;
637
638#if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L))
639 memset (&mctx, '\0', sizeof (re_match_context_t));
640 mctx.dfa = dfa;
641#endif
642
643 extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0;
644 nmatch -= extra_nmatch;
645
646 /* Check if the DFA haven't been compiled. */
647 if (BE (preg->used == 0 || dfa->init_state == NULL
648 || dfa->init_state_word == NULL || dfa->init_state_nl == NULL
649 || dfa->init_state_begbuf == NULL, 0))
650 return REG_NOMATCH;
651
652#ifdef DEBUG
653 /* We assume front-end functions already check them. */
654 assert (start + range >= 0 && start + range <= length);
655#endif
656
657 /* If initial states with non-begbuf contexts have no elements,
658 the regex must be anchored. If preg->newline_anchor is set,
659 we'll never use init_state_nl, so do not check it. */
660 if (dfa->init_state->nodes.nelem == 0
661 && dfa->init_state_word->nodes.nelem == 0
662 && (dfa->init_state_nl->nodes.nelem == 0
663 || !preg->newline_anchor))
664 {
665 if (start != 0 && start + range != 0)
666 return REG_NOMATCH;
667 start = range = 0;
668 }
669
670 /* We must check the longest matching, if nmatch > 0. */
671 fl_longest_match = (nmatch != 0 || dfa->nbackref);
672
673 err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1,
674 preg->translate, preg->syntax & RE_ICASE, dfa);
675 if (BE (err != REG_NOERROR, 0))
676 goto free_return;
677 mctx.input.stop = stop;
678 mctx.input.raw_stop = stop;
679 mctx.input.newline_anchor = preg->newline_anchor;
680
681 err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2);
682 if (BE (err != REG_NOERROR, 0))
683 goto free_return;
684
685 /* We will log all the DFA states through which the dfa pass,
686 if nmatch > 1, or this dfa has "multibyte node", which is a
687 back-reference or a node which can accept multibyte character or
688 multi character collating element. */
689 if (nmatch > 1 || dfa->has_mb_node)
690 {
691 /* Avoid overflow. */
692 if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= mctx.input.bufs_len, 0))
693 {
694 err = REG_ESPACE;
695 goto free_return;
696 }
697
698 mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1);
699 if (BE (mctx.state_log == NULL, 0))
700 {
701 err = REG_ESPACE;
702 goto free_return;
703 }
704 }
705 else
706 mctx.state_log = NULL;
707
708 match_first = start;
709 mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
710 : CONTEXT_NEWLINE | CONTEXT_BEGBUF;
711
712 /* Check incrementally whether of not the input string match. */
713 incr = (range < 0) ? -1 : 1;
714 left_lim = (range < 0) ? start + range : start;
715 right_lim = (range < 0) ? start : start + range;
716 sb = dfa->mb_cur_max == 1;
717 match_kind =
718 (fastmap
719 ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0)
720 | (range >= 0 ? 2 : 0)
721 | (t != NULL ? 1 : 0))
722 : 8);
723
724 for (;; match_first += incr)
725 {
726 err = REG_NOMATCH;
727 if (match_first < left_lim || right_lim < match_first)
728 goto free_return;
729
730 /* Advance as rapidly as possible through the string, until we
731 find a plausible place to start matching. This may be done
732 with varying efficiency, so there are various possibilities:
733 only the most common of them are specialized, in order to
734 save on code size. We use a switch statement for speed. */
735 switch (match_kind)
736 {
737 case 8:
738 /* No fastmap. */
739 break;
740
741 case 7:
742 /* Fastmap with single-byte translation, match forward. */
743 while (BE (match_first < right_lim, 1)
744 && !fastmap[t[(unsigned char) string[match_first]]])
745 ++match_first;
746 goto forward_match_found_start_or_reached_end;
747
748 case 6:
749 /* Fastmap without translation, match forward. */
750 while (BE (match_first < right_lim, 1)
751 && !fastmap[(unsigned char) string[match_first]])
752 ++match_first;
753
754 forward_match_found_start_or_reached_end:
755 if (BE (match_first == right_lim, 0))
756 {
757 ch = match_first >= length
758 ? 0 : (unsigned char) string[match_first];
759 if (!fastmap[t ? t[ch] : ch])
760 goto free_return;
761 }
762 break;
763
764 case 4:
765 case 5:
766 /* Fastmap without multi-byte translation, match backwards. */
767 while (match_first >= left_lim)
768 {
769 ch = match_first >= length
770 ? 0 : (unsigned char) string[match_first];
771 if (fastmap[t ? t[ch] : ch])
772 break;
773 --match_first;
774 }
775 if (match_first < left_lim)
776 goto free_return;
777 break;
778
779 default:
780 /* In this case, we can't determine easily the current byte,
781 since it might be a component byte of a multibyte
782 character. Then we use the constructed buffer instead. */
783 for (;;)
784 {
785 /* If MATCH_FIRST is out of the valid range, reconstruct the
786 buffers. */
787 unsigned int offset = match_first - mctx.input.raw_mbs_idx;
788 if (BE (offset >= (unsigned int) mctx.input.valid_raw_len, 0))
789 {
790 err = re_string_reconstruct (&mctx.input, match_first,
791 eflags);
792 if (BE (err != REG_NOERROR, 0))
793 goto free_return;
794
795 offset = match_first - mctx.input.raw_mbs_idx;
796 }
797 /* If MATCH_FIRST is out of the buffer, leave it as '\0'.
798 Note that MATCH_FIRST must not be smaller than 0. */
799 ch = (match_first >= length
800 ? 0 : re_string_byte_at (&mctx.input, offset));
801 if (fastmap[ch])
802 break;
803 match_first += incr;
804 if (match_first < left_lim || match_first > right_lim)
805 {
806 err = REG_NOMATCH;
807 goto free_return;
808 }
809 }
810 break;
811 }
812
813 /* Reconstruct the buffers so that the matcher can assume that
814 the matching starts from the beginning of the buffer. */
815 err = re_string_reconstruct (&mctx.input, match_first, eflags);
816 if (BE (err != REG_NOERROR, 0))
817 goto free_return;
818
819#ifdef RE_ENABLE_I18N
820 /* Don't consider this char as a possible match start if it part,
821 yet isn't the head, of a multibyte character. */
822 if (!sb && !re_string_first_byte (&mctx.input, 0))
823 continue;
824#endif
825
826 /* It seems to be appropriate one, then use the matcher. */
827 /* We assume that the matching starts from 0. */
828 mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0;
829 match_last = check_matching (&mctx, fl_longest_match,
830 range >= 0 ? &match_first : NULL);
831 if (match_last != -1)
832 {
833 if (BE (match_last == -2, 0))
834 {
835 err = REG_ESPACE;
836 goto free_return;
837 }
838 else
839 {
840 mctx.match_last = match_last;
841 if ((!preg->no_sub && nmatch > 1) || dfa->nbackref)
842 {
843 re_dfastate_t *pstate = mctx.state_log[match_last];
844 mctx.last_node = check_halt_state_context (&mctx, pstate,
845 match_last);
846 }
847 if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match)
848 || dfa->nbackref)
849 {
850 err = prune_impossible_nodes (&mctx);
851 if (err == REG_NOERROR)
852 break;
853 if (BE (err != REG_NOMATCH, 0))
854 goto free_return;
855 match_last = -1;
856 }
857 else
858 break; /* We found a match. */
859 }
860 }
861
862 match_ctx_clean (&mctx);
863 }
864
865#ifdef DEBUG
866 assert (match_last != -1);
867 assert (err == REG_NOERROR);
868#endif
869
870 /* Set pmatch[] if we need. */
871 if (nmatch > 0)
872 {
873 int reg_idx;
874
875 /* Initialize registers. */
876 for (reg_idx = 1; reg_idx < nmatch; ++reg_idx)
877 pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1;
878
879 /* Set the points where matching start/end. */
880 pmatch[0].rm_so = 0;
881 pmatch[0].rm_eo = mctx.match_last;
882
883 if (!preg->no_sub && nmatch > 1)
884 {
885 err = set_regs (preg, &mctx, nmatch, pmatch,
886 dfa->has_plural_match && dfa->nbackref > 0);
887 if (BE (err != REG_NOERROR, 0))
888 goto free_return;
889 }
890
891 /* At last, add the offset to the each registers, since we slided
892 the buffers so that we could assume that the matching starts
893 from 0. */
894 for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
895 if (pmatch[reg_idx].rm_so != -1)
896 {
897#ifdef RE_ENABLE_I18N
898 if (BE (mctx.input.offsets_needed != 0, 0))
899 {
900 pmatch[reg_idx].rm_so =
901 (pmatch[reg_idx].rm_so == mctx.input.valid_len
902 ? mctx.input.valid_raw_len
903 : mctx.input.offsets[pmatch[reg_idx].rm_so]);
904 pmatch[reg_idx].rm_eo =
905 (pmatch[reg_idx].rm_eo == mctx.input.valid_len
906 ? mctx.input.valid_raw_len
907 : mctx.input.offsets[pmatch[reg_idx].rm_eo]);
908 }
909#else
910 assert (mctx.input.offsets_needed == 0);
911#endif
912 pmatch[reg_idx].rm_so += match_first;
913 pmatch[reg_idx].rm_eo += match_first;
914 }
915 for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx)
916 {
917 pmatch[nmatch + reg_idx].rm_so = -1;
918 pmatch[nmatch + reg_idx].rm_eo = -1;
919 }
920
921 if (dfa->subexp_map)
922 for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++)
923 if (dfa->subexp_map[reg_idx] != reg_idx)
924 {
925 pmatch[reg_idx + 1].rm_so
926 = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so;
927 pmatch[reg_idx + 1].rm_eo
928 = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo;
929 }
930 }
931
932 free_return:
933 re_free (mctx.state_log);
934 if (dfa->nbackref)
935 match_ctx_free (&mctx);
936 re_string_destruct (&mctx.input);
937 return err;
938}
939
940static reg_errcode_t
941prune_impossible_nodes (re_match_context_t *mctx)
942{
943 const re_dfa_t *const dfa = mctx->dfa;
944 int halt_node, match_last;
945 reg_errcode_t ret;
946 re_dfastate_t **sifted_states;
947 re_dfastate_t **lim_states = NULL;
948 re_sift_context_t sctx;
949#ifdef DEBUG
950 assert (mctx->state_log != NULL);
951#endif
952 match_last = mctx->match_last;
953 halt_node = mctx->last_node;
954
955 /* Avoid overflow. */
956 if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= match_last, 0))
957 return REG_ESPACE;
958
959 sifted_states = re_malloc (re_dfastate_t *, match_last + 1);
960 if (BE (sifted_states == NULL, 0))
961 {
962 ret = REG_ESPACE;
963 goto free_return;
964 }
965 if (dfa->nbackref)
966 {
967 lim_states = re_malloc (re_dfastate_t *, match_last + 1);
968 if (BE (lim_states == NULL, 0))
969 {
970 ret = REG_ESPACE;
971 goto free_return;
972 }
973 while (1)
974 {
975 memset (lim_states, '\0',
976 sizeof (re_dfastate_t *) * (match_last + 1));
977 sift_ctx_init (&sctx, sifted_states, lim_states, halt_node,
978 match_last);
979 ret = sift_states_backward (mctx, &sctx);
980 re_node_set_free (&sctx.limits);
981 if (BE (ret != REG_NOERROR, 0))
982 goto free_return;
983 if (sifted_states[0] != NULL || lim_states[0] != NULL)
984 break;
985 do
986 {
987 --match_last;
988 if (match_last < 0)
989 {
990 ret = REG_NOMATCH;
991 goto free_return;
992 }
993 } while (mctx->state_log[match_last] == NULL
994 || !mctx->state_log[match_last]->halt);
995 halt_node = check_halt_state_context (mctx,
996 mctx->state_log[match_last],
997 match_last);
998 }
999 ret = merge_state_array (dfa, sifted_states, lim_states,
1000 match_last + 1);
1001 re_free (lim_states);
1002 lim_states = NULL;
1003 if (BE (ret != REG_NOERROR, 0))
1004 goto free_return;
1005 }
1006 else
1007 {
1008 sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last);
1009 ret = sift_states_backward (mctx, &sctx);
1010 re_node_set_free (&sctx.limits);
1011 if (BE (ret != REG_NOERROR, 0))
1012 goto free_return;
1013 if (sifted_states[0] == NULL)
1014 {
1015 ret = REG_NOMATCH;
1016 goto free_return;
1017 }
1018 }
1019 re_free (mctx->state_log);
1020 mctx->state_log = sifted_states;
1021 sifted_states = NULL;
1022 mctx->last_node = halt_node;
1023 mctx->match_last = match_last;
1024 ret = REG_NOERROR;
1025 free_return:
1026 re_free (sifted_states);
1027 re_free (lim_states);
1028 return ret;
1029}
1030
1031/* Acquire an initial state and return it.
1032 We must select appropriate initial state depending on the context,
1033 since initial states may have constraints like "\<", "^", etc.. */
1034
1035static inline re_dfastate_t *
1036__attribute ((always_inline)) internal_function
1037acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx,
1038 int idx)
1039{
1040 const re_dfa_t *const dfa = mctx->dfa;
1041 if (dfa->init_state->has_constraint)
1042 {
1043 unsigned int context;
1044 context = re_string_context_at (&mctx->input, idx - 1, mctx->eflags);
1045 if (IS_WORD_CONTEXT (context))
1046 return dfa->init_state_word;
1047 else if (IS_ORDINARY_CONTEXT (context))
1048 return dfa->init_state;
1049 else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context))
1050 return dfa->init_state_begbuf;
1051 else if (IS_NEWLINE_CONTEXT (context))
1052 return dfa->init_state_nl;
1053 else if (IS_BEGBUF_CONTEXT (context))
1054 {
1055 /* It is relatively rare case, then calculate on demand. */
1056 return re_acquire_state_context (err, dfa,
1057 dfa->init_state->entrance_nodes,
1058 context);
1059 }
1060 else
1061 /* Must not happen? */
1062 return dfa->init_state;
1063 }
1064 else
1065 return dfa->init_state;
1066}
1067
1068/* Check whether the regular expression match input string INPUT or not,
1069 and return the index where the matching end, return -1 if not match,
1070 or return -2 in case of an error.
1071 FL_LONGEST_MATCH means we want the POSIX longest matching.
1072 If P_MATCH_FIRST is not NULL, and the match fails, it is set to the
1073 next place where we may want to try matching.
1074 Note that the matcher assume that the matching starts from the current
1075 index of the buffer. */
1076
1077static int
1078internal_function
1079check_matching (re_match_context_t *mctx, int fl_longest_match,
1080 int *p_match_first)
1081{
1082 const re_dfa_t *const dfa = mctx->dfa;
1083 reg_errcode_t err;
1084 int match = 0;
1085 int match_last = -1;
1086 int cur_str_idx = re_string_cur_idx (&mctx->input);
1087 re_dfastate_t *cur_state;
1088 int at_init_state = p_match_first != NULL;
1089 int next_start_idx = cur_str_idx;
1090
1091 err = REG_NOERROR;
1092 cur_state = acquire_init_state_context (&err, mctx, cur_str_idx);
1093 /* An initial state must not be NULL (invalid). */
1094 if (BE (cur_state == NULL, 0))
1095 {
1096 assert (err == REG_ESPACE);
1097 return -2;
1098 }
1099
1100 if (mctx->state_log != NULL)
1101 {
1102 mctx->state_log[cur_str_idx] = cur_state;
1103
1104 /* Check OP_OPEN_SUBEXP in the initial state in case that we use them
1105 later. E.g. Processing back references. */
1106 if (BE (dfa->nbackref, 0))
1107 {
1108 at_init_state = 0;
1109 err = check_subexp_matching_top (mctx, &cur_state->nodes, 0);
1110 if (BE (err != REG_NOERROR, 0))
1111 return err;
1112
1113 if (cur_state->has_backref)
1114 {
1115 err = transit_state_bkref (mctx, &cur_state->nodes);
1116 if (BE (err != REG_NOERROR, 0))
1117 return err;
1118 }
1119 }
1120 }
1121
1122 /* If the RE accepts NULL string. */
1123 if (BE (cur_state->halt, 0))
1124 {
1125 if (!cur_state->has_constraint
1126 || check_halt_state_context (mctx, cur_state, cur_str_idx))
1127 {
1128 if (!fl_longest_match)
1129 return cur_str_idx;
1130 else
1131 {
1132 match_last = cur_str_idx;
1133 match = 1;
1134 }
1135 }
1136 }
1137
1138 while (!re_string_eoi (&mctx->input))
1139 {
1140 re_dfastate_t *old_state = cur_state;
1141 int next_char_idx = re_string_cur_idx (&mctx->input) + 1;
1142
1143 if (BE (next_char_idx >= mctx->input.bufs_len, 0)
1144 || (BE (next_char_idx >= mctx->input.valid_len, 0)
1145 && mctx->input.valid_len < mctx->input.len))
1146 {
1147 err = extend_buffers (mctx);
1148 if (BE (err != REG_NOERROR, 0))
1149 {
1150 assert (err == REG_ESPACE);
1151 return -2;
1152 }
1153 }
1154
1155 cur_state = transit_state (&err, mctx, cur_state);
1156 if (mctx->state_log != NULL)
1157 cur_state = merge_state_with_log (&err, mctx, cur_state);
1158
1159 if (cur_state == NULL)
1160 {
1161 /* Reached the invalid state or an error. Try to recover a valid
1162 state using the state log, if available and if we have not
1163 already found a valid (even if not the longest) match. */
1164 if (BE (err != REG_NOERROR, 0))
1165 return -2;
1166
1167 if (mctx->state_log == NULL
1168 || (match && !fl_longest_match)
1169 || (cur_state = find_recover_state (&err, mctx)) == NULL)
1170 break;
1171 }
1172
1173 if (BE (at_init_state, 0))
1174 {
1175 if (old_state == cur_state)
1176 next_start_idx = next_char_idx;
1177 else
1178 at_init_state = 0;
1179 }
1180
1181 if (cur_state->halt)
1182 {
1183 /* Reached a halt state.
1184 Check the halt state can satisfy the current context. */
1185 if (!cur_state->has_constraint
1186 || check_halt_state_context (mctx, cur_state,
1187 re_string_cur_idx (&mctx->input)))
1188 {
1189 /* We found an appropriate halt state. */
1190 match_last = re_string_cur_idx (&mctx->input);
1191 match = 1;
1192
1193 /* We found a match, do not modify match_first below. */
1194 p_match_first = NULL;
1195 if (!fl_longest_match)
1196 break;
1197 }
1198 }
1199 }
1200
1201 if (p_match_first)
1202 *p_match_first += next_start_idx;
1203
1204 return match_last;
1205}
1206
1207/* Check NODE match the current context. */
1208
1209static int
1210internal_function
1211check_halt_node_context (const re_dfa_t *dfa, int node, unsigned int context)
1212{
1213 re_token_type_t type = dfa->nodes[node].type;
1214 unsigned int constraint = dfa->nodes[node].constraint;
1215 if (type != END_OF_RE)
1216 return 0;
1217 if (!constraint)
1218 return 1;
1219 if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context))
1220 return 0;
1221 return 1;
1222}
1223
1224/* Check the halt state STATE match the current context.
1225 Return 0 if not match, if the node, STATE has, is a halt node and
1226 match the context, return the node. */
1227
1228static int
1229internal_function
1230check_halt_state_context (const re_match_context_t *mctx,
1231 const re_dfastate_t *state, int idx)
1232{
1233 int i;
1234 unsigned int context;
1235#ifdef DEBUG
1236 assert (state->halt);
1237#endif
1238 context = re_string_context_at (&mctx->input, idx, mctx->eflags);
1239 for (i = 0; i < state->nodes.nelem; ++i)
1240 if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], context))
1241 return state->nodes.elems[i];
1242 return 0;
1243}
1244
1245/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA
1246 corresponding to the DFA).
1247 Return the destination node, and update EPS_VIA_NODES, return -1 in case
1248 of errors. */
1249
1250static int
1251internal_function
1252proceed_next_node (const re_match_context_t *mctx, int nregs, regmatch_t *regs,
1253 int *pidx, int node, re_node_set *eps_via_nodes,
1254 struct re_fail_stack_t *fs)
1255{
1256 const re_dfa_t *const dfa = mctx->dfa;
1257 int i, err;
1258 if (IS_EPSILON_NODE (dfa->nodes[node].type))
1259 {
1260 re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes;
1261 re_node_set *edests = &dfa->edests[node];
1262 int dest_node;
1263 err = re_node_set_insert (eps_via_nodes, node);
1264 if (BE (err < 0, 0))
1265 return -2;
1266 /* Pick up a valid destination, or return -1 if none is found. */
1267 for (dest_node = -1, i = 0; i < edests->nelem; ++i)
1268 {
1269 int candidate = edests->elems[i];
1270 if (!re_node_set_contains (cur_nodes, candidate))
1271 continue;
1272 if (dest_node == -1)
1273 dest_node = candidate;
1274
1275 else
1276 {
1277 /* In order to avoid infinite loop like "(a*)*", return the second
1278 epsilon-transition if the first was already considered. */
1279 if (re_node_set_contains (eps_via_nodes, dest_node))
1280 return candidate;
1281
1282 /* Otherwise, push the second epsilon-transition on the fail stack. */
1283 else if (fs != NULL
1284 && push_fail_stack (fs, *pidx, candidate, nregs, regs,
1285 eps_via_nodes))
1286 return -2;
1287
1288 /* We know we are going to exit. */
1289 break;
1290 }
1291 }
1292 return dest_node;
1293 }
1294 else
1295 {
1296 int naccepted = 0;
1297 re_token_type_t type = dfa->nodes[node].type;
1298
1299#ifdef RE_ENABLE_I18N
1300 if (dfa->nodes[node].accept_mb)
1301 naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx);
1302 else
1303#endif /* RE_ENABLE_I18N */
1304 if (type == OP_BACK_REF)
1305 {
1306 int subexp_idx = dfa->nodes[node].opr.idx + 1;
1307 naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so;
1308 if (fs != NULL)
1309 {
1310 if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1)
1311 return -1;
1312 else if (naccepted)
1313 {
1314 char *buf = (char *) re_string_get_buffer (&mctx->input);
1315 if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
1316 naccepted) != 0)
1317 return -1;
1318 }
1319 }
1320
1321 if (naccepted == 0)
1322 {
1323 int dest_node;
1324 err = re_node_set_insert (eps_via_nodes, node);
1325 if (BE (err < 0, 0))
1326 return -2;
1327 dest_node = dfa->edests[node].elems[0];
1328 if (re_node_set_contains (&mctx->state_log[*pidx]->nodes,
1329 dest_node))
1330 return dest_node;
1331 }
1332 }
1333
1334 if (naccepted != 0
1335 || check_node_accept (mctx, dfa->nodes + node, *pidx))
1336 {
1337 int dest_node = dfa->nexts[node];
1338 *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted;
1339 if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL
1340 || !re_node_set_contains (&mctx->state_log[*pidx]->nodes,
1341 dest_node)))
1342 return -1;
1343 re_node_set_empty (eps_via_nodes);
1344 return dest_node;
1345 }
1346 }
1347 return -1;
1348}
1349
1350static reg_errcode_t
1351internal_function
1352push_fail_stack (struct re_fail_stack_t *fs, int str_idx, int dest_node,
1353 int nregs, regmatch_t *regs, re_node_set *eps_via_nodes)
1354{
1355 reg_errcode_t err;
1356 int num = fs->num++;
1357 if (fs->num == fs->alloc)
1358 {
1359 struct re_fail_stack_ent_t *new_array;
1360 new_array = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t)
1361 * fs->alloc * 2));
1362 if (new_array == NULL)
1363 return REG_ESPACE;
1364 fs->alloc *= 2;
1365 fs->stack = new_array;
1366 }
1367 fs->stack[num].idx = str_idx;
1368 fs->stack[num].node = dest_node;
1369 fs->stack[num].regs = re_malloc (regmatch_t, nregs);
1370 if (fs->stack[num].regs == NULL)
1371 return REG_ESPACE;
1372 memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs);
1373 err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes);
1374 return err;
1375}
1376
1377static int
1378internal_function
1379pop_fail_stack (struct re_fail_stack_t *fs, int *pidx, int nregs,
1380 regmatch_t *regs, re_node_set *eps_via_nodes)
1381{
1382 int num = --fs->num;
1383 assert (num >= 0);
1384 *pidx = fs->stack[num].idx;
1385 memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs);
1386 re_node_set_free (eps_via_nodes);
1387 re_free (fs->stack[num].regs);
1388 *eps_via_nodes = fs->stack[num].eps_via_nodes;
1389 return fs->stack[num].node;
1390}
1391
1392/* Set the positions where the subexpressions are starts/ends to registers
1393 PMATCH.
1394 Note: We assume that pmatch[0] is already set, and
1395 pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */
1396
1397static reg_errcode_t
1398internal_function
1399set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch,
1400 regmatch_t *pmatch, int fl_backtrack)
1401{
1402 const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer;
1403 int idx, cur_node;
1404 re_node_set eps_via_nodes;
1405 struct re_fail_stack_t *fs;
1406 struct re_fail_stack_t fs_body = { 0, 2, NULL };
1407 regmatch_t *prev_idx_match;
1408 int prev_idx_match_malloced = 0;
1409
1410#ifdef DEBUG
1411 assert (nmatch > 1);
1412 assert (mctx->state_log != NULL);
1413#endif
1414 if (fl_backtrack)
1415 {
1416 fs = &fs_body;
1417 fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc);
1418 if (fs->stack == NULL)
1419 return REG_ESPACE;
1420 }
1421 else
1422 fs = NULL;
1423
1424 cur_node = dfa->init_node;
1425 re_node_set_init_empty (&eps_via_nodes);
1426
1427#ifdef HAVE_ALLOCA
1428 if (__libc_use_alloca (nmatch * sizeof (regmatch_t)))
1429 prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t));
1430 else
1431#endif
1432 {
1433 prev_idx_match = re_malloc (regmatch_t, nmatch);
1434 if (prev_idx_match == NULL)
1435 {
1436 free_fail_stack_return (fs);
1437 return REG_ESPACE;
1438 }
1439 prev_idx_match_malloced = 1;
1440 }
1441 memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
1442
1443 for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;)
1444 {
1445 update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch);
1446
1447 if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node)
1448 {
1449 int reg_idx;
1450 if (fs)
1451 {
1452 for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
1453 if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1)
1454 break;
1455 if (reg_idx == nmatch)
1456 {
1457 re_node_set_free (&eps_via_nodes);
1458 if (prev_idx_match_malloced)
1459 re_free (prev_idx_match);
1460 return free_fail_stack_return (fs);
1461 }
1462 cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
1463 &eps_via_nodes);
1464 }
1465 else
1466 {
1467 re_node_set_free (&eps_via_nodes);
1468 if (prev_idx_match_malloced)
1469 re_free (prev_idx_match);
1470 return REG_NOERROR;
1471 }
1472 }
1473
1474 /* Proceed to next node. */
1475 cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node,
1476 &eps_via_nodes, fs);
1477
1478 if (BE (cur_node < 0, 0))
1479 {
1480 if (BE (cur_node == -2, 0))
1481 {
1482 re_node_set_free (&eps_via_nodes);
1483 if (prev_idx_match_malloced)
1484 re_free (prev_idx_match);
1485 free_fail_stack_return (fs);
1486 return REG_ESPACE;
1487 }
1488 if (fs)
1489 cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
1490 &eps_via_nodes);
1491 else
1492 {
1493 re_node_set_free (&eps_via_nodes);
1494 if (prev_idx_match_malloced)
1495 re_free (prev_idx_match);
1496 return REG_NOMATCH;
1497 }
1498 }
1499 }
1500 re_node_set_free (&eps_via_nodes);
1501 if (prev_idx_match_malloced)
1502 re_free (prev_idx_match);
1503 return free_fail_stack_return (fs);
1504}
1505
1506static reg_errcode_t
1507internal_function
1508free_fail_stack_return (struct re_fail_stack_t *fs)
1509{
1510 if (fs)
1511 {
1512 int fs_idx;
1513 for (fs_idx = 0; fs_idx < fs->num; ++fs_idx)
1514 {
1515 re_node_set_free (&fs->stack[fs_idx].eps_via_nodes);
1516 re_free (fs->stack[fs_idx].regs);
1517 }
1518 re_free (fs->stack);
1519 }
1520 return REG_NOERROR;
1521}
1522
1523static void
1524internal_function
1525update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
1526 regmatch_t *prev_idx_match, int cur_node, int cur_idx, int nmatch)
1527{
1528 int type = dfa->nodes[cur_node].type;
1529 if (type == OP_OPEN_SUBEXP)
1530 {
1531 int reg_num = dfa->nodes[cur_node].opr.idx + 1;
1532
1533 /* We are at the first node of this sub expression. */
1534 if (reg_num < nmatch)
1535 {
1536 pmatch[reg_num].rm_so = cur_idx;
1537 pmatch[reg_num].rm_eo = -1;
1538 }
1539 }
1540 else if (type == OP_CLOSE_SUBEXP)
1541 {
1542 int reg_num = dfa->nodes[cur_node].opr.idx + 1;
1543 if (reg_num < nmatch)
1544 {
1545 /* We are at the last node of this sub expression. */
1546 if (pmatch[reg_num].rm_so < cur_idx)
1547 {
1548 pmatch[reg_num].rm_eo = cur_idx;
1549 /* This is a non-empty match or we are not inside an optional
1550 subexpression. Accept this right away. */
1551 memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
1552 }
1553 else
1554 {
1555 if (dfa->nodes[cur_node].opt_subexp
1556 && prev_idx_match[reg_num].rm_so != -1)
1557 /* We transited through an empty match for an optional
1558 subexpression, like (a?)*, and this is not the subexp's
1559 first match. Copy back the old content of the registers
1560 so that matches of an inner subexpression are undone as
1561 well, like in ((a?))*. */
1562 memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch);
1563 else
1564 /* We completed a subexpression, but it may be part of
1565 an optional one, so do not update PREV_IDX_MATCH. */
1566 pmatch[reg_num].rm_eo = cur_idx;
1567 }
1568 }
1569 }
1570}
1571
1572/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0
1573 and sift the nodes in each states according to the following rules.
1574 Updated state_log will be wrote to STATE_LOG.
1575
1576 Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if...
1577 1. When STR_IDX == MATCH_LAST(the last index in the state_log):
1578 If `a' isn't the LAST_NODE and `a' can't epsilon transit to
1579 the LAST_NODE, we throw away the node `a'.
1580 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts
1581 string `s' and transit to `b':
1582 i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw
1583 away the node `a'.
1584 ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is
1585 thrown away, we throw away the node `a'.
1586 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b':
1587 i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the
1588 node `a'.
1589 ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away,
1590 we throw away the node `a'. */
1591
1592#define STATE_NODE_CONTAINS(state,node) \
1593 ((state) != NULL && re_node_set_contains (&(state)->nodes, node))
1594
1595static reg_errcode_t
1596internal_function
1597sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx)
1598{
1599 reg_errcode_t err;
1600 int null_cnt = 0;
1601 int str_idx = sctx->last_str_idx;
1602 re_node_set cur_dest;
1603
1604#ifdef DEBUG
1605 assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL);
1606#endif
1607
1608 /* Build sifted state_log[str_idx]. It has the nodes which can epsilon
1609 transit to the last_node and the last_node itself. */
1610 err = re_node_set_init_1 (&cur_dest, sctx->last_node);
1611 if (BE (err != REG_NOERROR, 0))
1612 return err;
1613 err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
1614 if (BE (err != REG_NOERROR, 0))
1615 goto free_return;
1616
1617 /* Then check each states in the state_log. */
1618 while (str_idx > 0)
1619 {
1620 /* Update counters. */
1621 null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0;
1622 if (null_cnt > mctx->max_mb_elem_len)
1623 {
1624 memset (sctx->sifted_states, '\0',
1625 sizeof (re_dfastate_t *) * str_idx);
1626 re_node_set_free (&cur_dest);
1627 return REG_NOERROR;
1628 }
1629 re_node_set_empty (&cur_dest);
1630 --str_idx;
1631
1632 if (mctx->state_log[str_idx])
1633 {
1634 err = build_sifted_states (mctx, sctx, str_idx, &cur_dest);
1635 if (BE (err != REG_NOERROR, 0))
1636 goto free_return;
1637 }
1638
1639 /* Add all the nodes which satisfy the following conditions:
1640 - It can epsilon transit to a node in CUR_DEST.
1641 - It is in CUR_SRC.
1642 And update state_log. */
1643 err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
1644 if (BE (err != REG_NOERROR, 0))
1645 goto free_return;
1646 }
1647 err = REG_NOERROR;
1648 free_return:
1649 re_node_set_free (&cur_dest);
1650 return err;
1651}
1652
1653static reg_errcode_t
1654internal_function
1655build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx,
1656 int str_idx, re_node_set *cur_dest)
1657{
1658 const re_dfa_t *const dfa = mctx->dfa;
1659 const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes;
1660 int i;
1661
1662 /* Then build the next sifted state.
1663 We build the next sifted state on `cur_dest', and update
1664 `sifted_states[str_idx]' with `cur_dest'.
1665 Note:
1666 `cur_dest' is the sifted state from `state_log[str_idx + 1]'.
1667 `cur_src' points the node_set of the old `state_log[str_idx]'
1668 (with the epsilon nodes pre-filtered out). */
1669 for (i = 0; i < cur_src->nelem; i++)
1670 {
1671 int prev_node = cur_src->elems[i];
1672 int naccepted = 0;
1673 int ret;
1674
1675#ifdef DEBUG
1676 re_token_type_t type = dfa->nodes[prev_node].type;
1677 assert (!IS_EPSILON_NODE (type));
1678#endif
1679#ifdef RE_ENABLE_I18N
1680 /* If the node may accept `multi byte'. */
1681 if (dfa->nodes[prev_node].accept_mb)
1682 naccepted = sift_states_iter_mb (mctx, sctx, prev_node,
1683 str_idx, sctx->last_str_idx);
1684#endif /* RE_ENABLE_I18N */
1685
1686 /* We don't check backreferences here.
1687 See update_cur_sifted_state(). */
1688 if (!naccepted
1689 && check_node_accept (mctx, dfa->nodes + prev_node, str_idx)
1690 && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1],
1691 dfa->nexts[prev_node]))
1692 naccepted = 1;
1693
1694 if (naccepted == 0)
1695 continue;
1696
1697 if (sctx->limits.nelem)
1698 {
1699 int to_idx = str_idx + naccepted;
1700 if (check_dst_limits (mctx, &sctx->limits,
1701 dfa->nexts[prev_node], to_idx,
1702 prev_node, str_idx))
1703 continue;
1704 }
1705 ret = re_node_set_insert (cur_dest, prev_node);
1706 if (BE (ret == -1, 0))
1707 return REG_ESPACE;
1708 }
1709
1710 return REG_NOERROR;
1711}
1712
1713/* Helper functions. */
1714
1715static reg_errcode_t
1716internal_function
1717clean_state_log_if_needed (re_match_context_t *mctx, int next_state_log_idx)
1718{
1719 int top = mctx->state_log_top;
1720
1721 if (next_state_log_idx >= mctx->input.bufs_len
1722 || (next_state_log_idx >= mctx->input.valid_len
1723 && mctx->input.valid_len < mctx->input.len))
1724 {
1725 reg_errcode_t err;
1726 err = extend_buffers (mctx);
1727 if (BE (err != REG_NOERROR, 0))
1728 return err;
1729 }
1730
1731 if (top < next_state_log_idx)
1732 {
1733 memset (mctx->state_log + top + 1, '\0',
1734 sizeof (re_dfastate_t *) * (next_state_log_idx - top));
1735 mctx->state_log_top = next_state_log_idx;
1736 }
1737 return REG_NOERROR;
1738}
1739
1740static reg_errcode_t
1741internal_function
1742merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst,
1743 re_dfastate_t **src, int num)
1744{
1745 int st_idx;
1746 reg_errcode_t err;
1747 for (st_idx = 0; st_idx < num; ++st_idx)
1748 {
1749 if (dst[st_idx] == NULL)
1750 dst[st_idx] = src[st_idx];
1751 else if (src[st_idx] != NULL)
1752 {
1753 re_node_set merged_set;
1754 err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes,
1755 &src[st_idx]->nodes);
1756 if (BE (err != REG_NOERROR, 0))
1757 return err;
1758 dst[st_idx] = re_acquire_state (&err, dfa, &merged_set);
1759 re_node_set_free (&merged_set);
1760 if (BE (err != REG_NOERROR, 0))
1761 return err;
1762 }
1763 }
1764 return REG_NOERROR;
1765}
1766
1767static reg_errcode_t
1768internal_function
1769update_cur_sifted_state (const re_match_context_t *mctx,
1770 re_sift_context_t *sctx, int str_idx,
1771 re_node_set *dest_nodes)
1772{
1773 const re_dfa_t *const dfa = mctx->dfa;
1774 reg_errcode_t err = REG_NOERROR;
1775 const re_node_set *candidates;
1776 candidates = ((mctx->state_log[str_idx] == NULL) ? NULL
1777 : &mctx->state_log[str_idx]->nodes);
1778
1779 if (dest_nodes->nelem == 0)
1780 sctx->sifted_states[str_idx] = NULL;
1781 else
1782 {
1783 if (candidates)
1784 {
1785 /* At first, add the nodes which can epsilon transit to a node in
1786 DEST_NODE. */
1787 err = add_epsilon_src_nodes (dfa, dest_nodes, candidates);
1788 if (BE (err != REG_NOERROR, 0))
1789 return err;
1790
1791 /* Then, check the limitations in the current sift_context. */
1792 if (sctx->limits.nelem)
1793 {
1794 err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits,
1795 mctx->bkref_ents, str_idx);
1796 if (BE (err != REG_NOERROR, 0))
1797 return err;
1798 }
1799 }
1800
1801 sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes);
1802 if (BE (err != REG_NOERROR, 0))
1803 return err;
1804 }
1805
1806 if (candidates && mctx->state_log[str_idx]->has_backref)
1807 {
1808 err = sift_states_bkref (mctx, sctx, str_idx, candidates);
1809 if (BE (err != REG_NOERROR, 0))
1810 return err;
1811 }
1812 return REG_NOERROR;
1813}
1814
1815static reg_errcode_t
1816internal_function
1817add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes,
1818 const re_node_set *candidates)
1819{
1820 reg_errcode_t err = REG_NOERROR;
1821 int i;
1822
1823 re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes);
1824 if (BE (err != REG_NOERROR, 0))
1825 return err;
1826
1827 if (!state->inveclosure.alloc)
1828 {
1829 err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem);
1830 if (BE (err != REG_NOERROR, 0))
1831 return REG_ESPACE;
1832 for (i = 0; i < dest_nodes->nelem; i++)
1833 {
1834 err = re_node_set_merge (&state->inveclosure,
1835 dfa->inveclosures + dest_nodes->elems[i]);
1836 if (BE (err != REG_NOERROR, 0))
1837 return REG_ESPACE;
1838 }
1839 }
1840 return re_node_set_add_intersect (dest_nodes, candidates,
1841 &state->inveclosure);
1842}
1843
1844static reg_errcode_t
1845internal_function
1846sub_epsilon_src_nodes (const re_dfa_t *dfa, int node, re_node_set *dest_nodes,
1847 const re_node_set *candidates)
1848{
1849 int ecl_idx;
1850 reg_errcode_t err;
1851 re_node_set *inv_eclosure = dfa->inveclosures + node;
1852 re_node_set except_nodes;
1853 re_node_set_init_empty (&except_nodes);
1854 for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
1855 {
1856 int cur_node = inv_eclosure->elems[ecl_idx];
1857 if (cur_node == node)
1858 continue;
1859 if (IS_EPSILON_NODE (dfa->nodes[cur_node].type))
1860 {
1861 int edst1 = dfa->edests[cur_node].elems[0];
1862 int edst2 = ((dfa->edests[cur_node].nelem > 1)
1863 ? dfa->edests[cur_node].elems[1] : -1);
1864 if ((!re_node_set_contains (inv_eclosure, edst1)
1865 && re_node_set_contains (dest_nodes, edst1))
1866 || (edst2 > 0
1867 && !re_node_set_contains (inv_eclosure, edst2)
1868 && re_node_set_contains (dest_nodes, edst2)))
1869 {
1870 err = re_node_set_add_intersect (&except_nodes, candidates,
1871 dfa->inveclosures + cur_node);
1872 if (BE (err != REG_NOERROR, 0))
1873 {
1874 re_node_set_free (&except_nodes);
1875 return err;
1876 }
1877 }
1878 }
1879 }
1880 for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
1881 {
1882 int cur_node = inv_eclosure->elems[ecl_idx];
1883 if (!re_node_set_contains (&except_nodes, cur_node))
1884 {
1885 int idx = re_node_set_contains (dest_nodes, cur_node) - 1;
1886 re_node_set_remove_at (dest_nodes, idx);
1887 }
1888 }
1889 re_node_set_free (&except_nodes);
1890 return REG_NOERROR;
1891}
1892
1893static int
1894internal_function
1895check_dst_limits (const re_match_context_t *mctx, re_node_set *limits,
1896 int dst_node, int dst_idx, int src_node, int src_idx)
1897{
1898 const re_dfa_t *const dfa = mctx->dfa;
1899 int lim_idx, src_pos, dst_pos;
1900
1901 int dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx);
1902 int src_bkref_idx = search_cur_bkref_entry (mctx, src_idx);
1903 for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
1904 {
1905 int subexp_idx;
1906 struct re_backref_cache_entry *ent;
1907 ent = mctx->bkref_ents + limits->elems[lim_idx];
1908 subexp_idx = dfa->nodes[ent->node].opr.idx;
1909
1910 dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
1911 subexp_idx, dst_node, dst_idx,
1912 dst_bkref_idx);
1913 src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
1914 subexp_idx, src_node, src_idx,
1915 src_bkref_idx);
1916
1917 /* In case of:
1918 <src> <dst> ( <subexp> )
1919 ( <subexp> ) <src> <dst>
1920 ( <subexp1> <src> <subexp2> <dst> <subexp3> ) */
1921 if (src_pos == dst_pos)
1922 continue; /* This is unrelated limitation. */
1923 else
1924 return 1;
1925 }
1926 return 0;
1927}
1928
1929static int
1930internal_function
1931check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries,
1932 int subexp_idx, int from_node, int bkref_idx)
1933{
1934 const re_dfa_t *const dfa = mctx->dfa;
1935 const re_node_set *eclosures = dfa->eclosures + from_node;
1936 int node_idx;
1937
1938 /* Else, we are on the boundary: examine the nodes on the epsilon
1939 closure. */
1940 for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx)
1941 {
1942 int node = eclosures->elems[node_idx];
1943 switch (dfa->nodes[node].type)
1944 {
1945 case OP_BACK_REF:
1946 if (bkref_idx != -1)
1947 {
1948 struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx;
1949 do
1950 {
1951 int dst, cpos;
1952
1953 if (ent->node != node)
1954 continue;
1955
1956 if (subexp_idx < BITSET_WORD_BITS
1957 && !(ent->eps_reachable_subexps_map
1958 & ((bitset_word_t) 1 << subexp_idx)))
1959 continue;
1960
1961 /* Recurse trying to reach the OP_OPEN_SUBEXP and
1962 OP_CLOSE_SUBEXP cases below. But, if the
1963 destination node is the same node as the source
1964 node, don't recurse because it would cause an
1965 infinite loop: a regex that exhibits this behavior
1966 is ()\1*\1* */
1967 dst = dfa->edests[node].elems[0];
1968 if (dst == from_node)
1969 {
1970 if (boundaries & 1)
1971 return -1;
1972 else /* if (boundaries & 2) */
1973 return 0;
1974 }
1975
1976 cpos =
1977 check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
1978 dst, bkref_idx);
1979 if (cpos == -1 /* && (boundaries & 1) */)
1980 return -1;
1981 if (cpos == 0 && (boundaries & 2))
1982 return 0;
1983
1984 if (subexp_idx < BITSET_WORD_BITS)
1985 ent->eps_reachable_subexps_map
1986 &= ~((bitset_word_t) 1 << subexp_idx);
1987 }
1988 while (ent++->more);
1989 }
1990 break;
1991
1992 case OP_OPEN_SUBEXP:
1993 if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx)
1994 return -1;
1995 break;
1996
1997 case OP_CLOSE_SUBEXP:
1998 if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx)
1999 return 0;
2000 break;
2001
2002 default:
2003 break;
2004 }
2005 }
2006
2007 return (boundaries & 2) ? 1 : 0;
2008}
2009
2010static int
2011internal_function
2012check_dst_limits_calc_pos (const re_match_context_t *mctx, int limit,
2013 int subexp_idx, int from_node, int str_idx,
2014 int bkref_idx)
2015{
2016 struct re_backref_cache_entry *lim = mctx->bkref_ents + limit;
2017 int boundaries;
2018
2019 /* If we are outside the range of the subexpression, return -1 or 1. */
2020 if (str_idx < lim->subexp_from)
2021 return -1;
2022
2023 if (lim->subexp_to < str_idx)
2024 return 1;
2025
2026 /* If we are within the subexpression, return 0. */
2027 boundaries = (str_idx == lim->subexp_from);
2028 boundaries |= (str_idx == lim->subexp_to) << 1;
2029 if (boundaries == 0)
2030 return 0;
2031
2032 /* Else, examine epsilon closure. */
2033 return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
2034 from_node, bkref_idx);
2035}
2036
2037/* Check the limitations of sub expressions LIMITS, and remove the nodes
2038 which are against limitations from DEST_NODES. */
2039
2040static reg_errcode_t
2041internal_function
2042check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes,
2043 const re_node_set *candidates, re_node_set *limits,
2044 struct re_backref_cache_entry *bkref_ents, int str_idx)
2045{
2046 reg_errcode_t err;
2047 int node_idx, lim_idx;
2048
2049 for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
2050 {
2051 int subexp_idx;
2052 struct re_backref_cache_entry *ent;
2053 ent = bkref_ents + limits->elems[lim_idx];
2054
2055 if (str_idx <= ent->subexp_from || ent->str_idx < str_idx)
2056 continue; /* This is unrelated limitation. */
2057
2058 subexp_idx = dfa->nodes[ent->node].opr.idx;
2059 if (ent->subexp_to == str_idx)
2060 {
2061 int ops_node = -1;
2062 int cls_node = -1;
2063 for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
2064 {
2065 int node = dest_nodes->elems[node_idx];
2066 re_token_type_t type = dfa->nodes[node].type;
2067 if (type == OP_OPEN_SUBEXP
2068 && subexp_idx == dfa->nodes[node].opr.idx)
2069 ops_node = node;
2070 else if (type == OP_CLOSE_SUBEXP
2071 && subexp_idx == dfa->nodes[node].opr.idx)
2072 cls_node = node;
2073 }
2074
2075 /* Check the limitation of the open subexpression. */
2076 /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */
2077 if (ops_node >= 0)
2078 {
2079 err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes,
2080 candidates);
2081 if (BE (err != REG_NOERROR, 0))
2082 return err;
2083 }
2084
2085 /* Check the limitation of the close subexpression. */
2086 if (cls_node >= 0)
2087 for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
2088 {
2089 int node = dest_nodes->elems[node_idx];
2090 if (!re_node_set_contains (dfa->inveclosures + node,
2091 cls_node)
2092 && !re_node_set_contains (dfa->eclosures + node,
2093 cls_node))
2094 {
2095 /* It is against this limitation.
2096 Remove it form the current sifted state. */
2097 err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
2098 candidates);
2099 if (BE (err != REG_NOERROR, 0))
2100 return err;
2101 --node_idx;
2102 }
2103 }
2104 }
2105 else /* (ent->subexp_to != str_idx) */
2106 {
2107 for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
2108 {
2109 int node = dest_nodes->elems[node_idx];
2110 re_token_type_t type = dfa->nodes[node].type;
2111 if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP)
2112 {
2113 if (subexp_idx != dfa->nodes[node].opr.idx)
2114 continue;
2115 /* It is against this limitation.
2116 Remove it form the current sifted state. */
2117 err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
2118 candidates);
2119 if (BE (err != REG_NOERROR, 0))
2120 return err;
2121 }
2122 }
2123 }
2124 }
2125 return REG_NOERROR;
2126}
2127
2128static reg_errcode_t
2129internal_function
2130sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx,
2131 int str_idx, const re_node_set *candidates)
2132{
2133 const re_dfa_t *const dfa = mctx->dfa;
2134 reg_errcode_t err;
2135 int node_idx, node;
2136 re_sift_context_t local_sctx;
2137 int first_idx = search_cur_bkref_entry (mctx, str_idx);
2138
2139 if (first_idx == -1)
2140 return REG_NOERROR;
2141
2142 local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */
2143
2144 for (node_idx = 0; node_idx < candidates->nelem; ++node_idx)
2145 {
2146 int enabled_idx;
2147 re_token_type_t type;
2148 struct re_backref_cache_entry *entry;
2149 node = candidates->elems[node_idx];
2150 type = dfa->nodes[node].type;
2151 /* Avoid infinite loop for the REs like "()\1+". */
2152 if (node == sctx->last_node && str_idx == sctx->last_str_idx)
2153 continue;
2154 if (type != OP_BACK_REF)
2155 continue;
2156
2157 entry = mctx->bkref_ents + first_idx;
2158 enabled_idx = first_idx;
2159 do
2160 {
2161 int subexp_len;
2162 int to_idx;
2163 int dst_node;
2164 int ret;
2165 re_dfastate_t *cur_state;
2166
2167 if (entry->node != node)
2168 continue;
2169 subexp_len = entry->subexp_to - entry->subexp_from;
2170 to_idx = str_idx + subexp_len;
2171 dst_node = (subexp_len ? dfa->nexts[node]
2172 : dfa->edests[node].elems[0]);
2173
2174 if (to_idx > sctx->last_str_idx
2175 || sctx->sifted_states[to_idx] == NULL
2176 || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node)
2177 || check_dst_limits (mctx, &sctx->limits, node,
2178 str_idx, dst_node, to_idx))
2179 continue;
2180
2181 if (local_sctx.sifted_states == NULL)
2182 {
2183 local_sctx = *sctx;
2184 err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits);
2185 if (BE (err != REG_NOERROR, 0))
2186 goto free_return;
2187 }
2188 local_sctx.last_node = node;
2189 local_sctx.last_str_idx = str_idx;
2190 ret = re_node_set_insert (&local_sctx.limits, enabled_idx);
2191 if (BE (ret < 0, 0))
2192 {
2193 err = REG_ESPACE;
2194 goto free_return;
2195 }
2196 cur_state = local_sctx.sifted_states[str_idx];
2197 err = sift_states_backward (mctx, &local_sctx);
2198 if (BE (err != REG_NOERROR, 0))
2199 goto free_return;
2200 if (sctx->limited_states != NULL)
2201 {
2202 err = merge_state_array (dfa, sctx->limited_states,
2203 local_sctx.sifted_states,
2204 str_idx + 1);
2205 if (BE (err != REG_NOERROR, 0))
2206 goto free_return;
2207 }
2208 local_sctx.sifted_states[str_idx] = cur_state;
2209 re_node_set_remove (&local_sctx.limits, enabled_idx);
2210
2211 /* mctx->bkref_ents may have changed, reload the pointer. */
2212 entry = mctx->bkref_ents + enabled_idx;
2213 }
2214 while (enabled_idx++, entry++->more);
2215 }
2216 err = REG_NOERROR;
2217 free_return:
2218 if (local_sctx.sifted_states != NULL)
2219 {
2220 re_node_set_free (&local_sctx.limits);
2221 }
2222
2223 return err;
2224}
2225
2226
2227#ifdef RE_ENABLE_I18N
2228static int
2229internal_function
2230sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx,
2231 int node_idx, int str_idx, int max_str_idx)
2232{
2233 const re_dfa_t *const dfa = mctx->dfa;
2234 int naccepted;
2235 /* Check the node can accept `multi byte'. */
2236 naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx);
2237 if (naccepted > 0 && str_idx + naccepted <= max_str_idx &&
2238 !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted],
2239 dfa->nexts[node_idx]))
2240 /* The node can't accept the `multi byte', or the
2241 destination was already thrown away, then the node
2242 couldn't accept the current input `multi byte'. */
2243 naccepted = 0;
2244 /* Otherwise, it is sure that the node could accept
2245 `naccepted' bytes input. */
2246 return naccepted;
2247}
2248#endif /* RE_ENABLE_I18N */
2249
2250
2251/* Functions for state transition. */
2252
2253/* Return the next state to which the current state STATE will transit by
2254 accepting the current input byte, and update STATE_LOG if necessary.
2255 If STATE can accept a multibyte char/collating element/back reference
2256 update the destination of STATE_LOG. */
2257
2258static re_dfastate_t *
2259internal_function
2260transit_state (reg_errcode_t *err, re_match_context_t *mctx,
2261 re_dfastate_t *state)
2262{
2263 re_dfastate_t **trtable;
2264 unsigned char ch;
2265
2266#ifdef RE_ENABLE_I18N
2267 /* If the current state can accept multibyte. */
2268 if (BE (state->accept_mb, 0))
2269 {
2270 *err = transit_state_mb (mctx, state);
2271 if (BE (*err != REG_NOERROR, 0))
2272 return NULL;
2273 }
2274#endif /* RE_ENABLE_I18N */
2275
2276 /* Then decide the next state with the single byte. */
2277#if 0
2278 if (0)
2279 /* don't use transition table */
2280 return transit_state_sb (err, mctx, state);
2281#endif
2282
2283 /* Use transition table */
2284 ch = re_string_fetch_byte (&mctx->input);
2285 for (;;)
2286 {
2287 trtable = state->trtable;
2288 if (BE (trtable != NULL, 1))
2289 return trtable[ch];
2290
2291 trtable = state->word_trtable;
2292 if (BE (trtable != NULL, 1))
2293 {
2294 unsigned int context;
2295 context
2296 = re_string_context_at (&mctx->input,
2297 re_string_cur_idx (&mctx->input) - 1,
2298 mctx->eflags);
2299 if (IS_WORD_CONTEXT (context))
2300 return trtable[ch + SBC_MAX];
2301 else
2302 return trtable[ch];
2303 }
2304
2305 if (!build_trtable (mctx->dfa, state))
2306 {
2307 *err = REG_ESPACE;
2308 return NULL;
2309 }
2310
2311 /* Retry, we now have a transition table. */
2312 }
2313}
2314
2315/* Update the state_log if we need */
2316static re_dfastate_t *
2317internal_function
2318merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx,
2319 re_dfastate_t *next_state)
2320{
2321 const re_dfa_t *const dfa = mctx->dfa;
2322 int cur_idx = re_string_cur_idx (&mctx->input);
2323
2324 if (cur_idx > mctx->state_log_top)
2325 {
2326 mctx->state_log[cur_idx] = next_state;
2327 mctx->state_log_top = cur_idx;
2328 }
2329 else if (mctx->state_log[cur_idx] == NULL)
2330 {
2331 mctx->state_log[cur_idx] = next_state;
2332 }
2333 else
2334 {
2335 re_dfastate_t *pstate;
2336 unsigned int context;
2337 re_node_set next_nodes, *log_nodes, *table_nodes = NULL;
2338 /* If (state_log[cur_idx] != 0), it implies that cur_idx is
2339 the destination of a multibyte char/collating element/
2340 back reference. Then the next state is the union set of
2341 these destinations and the results of the transition table. */
2342 pstate = mctx->state_log[cur_idx];
2343 log_nodes = pstate->entrance_nodes;
2344 if (next_state != NULL)
2345 {
2346 table_nodes = next_state->entrance_nodes;
2347 *err = re_node_set_init_union (&next_nodes, table_nodes,
2348 log_nodes);
2349 if (BE (*err != REG_NOERROR, 0))
2350 return NULL;
2351 }
2352 else
2353 next_nodes = *log_nodes;
2354 /* Note: We already add the nodes of the initial state,
2355 then we don't need to add them here. */
2356
2357 context = re_string_context_at (&mctx->input,
2358 re_string_cur_idx (&mctx->input) - 1,
2359 mctx->eflags);
2360 next_state = mctx->state_log[cur_idx]
2361 = re_acquire_state_context (err, dfa, &next_nodes, context);
2362 /* We don't need to check errors here, since the return value of
2363 this function is next_state and ERR is already set. */
2364
2365 if (table_nodes != NULL)
2366 re_node_set_free (&next_nodes);
2367 }
2368
2369 if (BE (dfa->nbackref, 0) && next_state != NULL)
2370 {
2371 /* Check OP_OPEN_SUBEXP in the current state in case that we use them
2372 later. We must check them here, since the back references in the
2373 next state might use them. */
2374 *err = check_subexp_matching_top (mctx, &next_state->nodes,
2375 cur_idx);
2376 if (BE (*err != REG_NOERROR, 0))
2377 return NULL;
2378
2379 /* If the next state has back references. */
2380 if (next_state->has_backref)
2381 {
2382 *err = transit_state_bkref (mctx, &next_state->nodes);
2383 if (BE (*err != REG_NOERROR, 0))
2384 return NULL;
2385 next_state = mctx->state_log[cur_idx];
2386 }
2387 }
2388
2389 return next_state;
2390}
2391
2392/* Skip bytes in the input that correspond to part of a
2393 multi-byte match, then look in the log for a state
2394 from which to restart matching. */
2395static re_dfastate_t *
2396internal_function
2397find_recover_state (reg_errcode_t *err, re_match_context_t *mctx)
2398{
2399 re_dfastate_t *cur_state;
2400 do
2401 {
2402 int max = mctx->state_log_top;
2403 int cur_str_idx = re_string_cur_idx (&mctx->input);
2404
2405 do
2406 {
2407 if (++cur_str_idx > max)
2408 return NULL;
2409 re_string_skip_bytes (&mctx->input, 1);
2410 }
2411 while (mctx->state_log[cur_str_idx] == NULL);
2412
2413 cur_state = merge_state_with_log (err, mctx, NULL);
2414 }
2415 while (*err == REG_NOERROR && cur_state == NULL);
2416 return cur_state;
2417}
2418
2419/* Helper functions for transit_state. */
2420
2421/* From the node set CUR_NODES, pick up the nodes whose types are
2422 OP_OPEN_SUBEXP and which have corresponding back references in the regular
2423 expression. And register them to use them later for evaluating the
2424 correspoding back references. */
2425
2426static reg_errcode_t
2427internal_function
2428check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes,
2429 int str_idx)
2430{
2431 const re_dfa_t *const dfa = mctx->dfa;
2432 int node_idx;
2433 reg_errcode_t err;
2434
2435 /* TODO: This isn't efficient.
2436 Because there might be more than one nodes whose types are
2437 OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
2438 nodes.
2439 E.g. RE: (a){2} */
2440 for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx)
2441 {
2442 int node = cur_nodes->elems[node_idx];
2443 if (dfa->nodes[node].type == OP_OPEN_SUBEXP
2444 && dfa->nodes[node].opr.idx < BITSET_WORD_BITS
2445 && (dfa->used_bkref_map
2446 & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx)))
2447 {
2448 err = match_ctx_add_subtop (mctx, node, str_idx);
2449 if (BE (err != REG_NOERROR, 0))
2450 return err;
2451 }
2452 }
2453 return REG_NOERROR;
2454}
2455
2456#if 0
2457/* Return the next state to which the current state STATE will transit by
2458 accepting the current input byte. */
2459
2460static re_dfastate_t *
2461transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx,
2462 re_dfastate_t *state)
2463{
2464 const re_dfa_t *const dfa = mctx->dfa;
2465 re_node_set next_nodes;
2466 re_dfastate_t *next_state;
2467 int node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input);
2468 unsigned int context;
2469
2470 *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1);
2471 if (BE (*err != REG_NOERROR, 0))
2472 return NULL;
2473 for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt)
2474 {
2475 int cur_node = state->nodes.elems[node_cnt];
2476 if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx))
2477 {
2478 *err = re_node_set_merge (&next_nodes,
2479 dfa->eclosures + dfa->nexts[cur_node]);
2480 if (BE (*err != REG_NOERROR, 0))
2481 {
2482 re_node_set_free (&next_nodes);
2483 return NULL;
2484 }
2485 }
2486 }
2487 context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags);
2488 next_state = re_acquire_state_context (err, dfa, &next_nodes, context);
2489 /* We don't need to check errors here, since the return value of
2490 this function is next_state and ERR is already set. */
2491
2492 re_node_set_free (&next_nodes);
2493 re_string_skip_bytes (&mctx->input, 1);
2494 return next_state;
2495}
2496#endif
2497
2498#ifdef RE_ENABLE_I18N
2499static reg_errcode_t
2500internal_function
2501transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate)
2502{
2503 const re_dfa_t *const dfa = mctx->dfa;
2504 reg_errcode_t err;
2505 int i;
2506
2507 for (i = 0; i < pstate->nodes.nelem; ++i)
2508 {
2509 re_node_set dest_nodes, *new_nodes;
2510 int cur_node_idx = pstate->nodes.elems[i];
2511 int naccepted, dest_idx;
2512 unsigned int context;
2513 re_dfastate_t *dest_state;
2514
2515 if (!dfa->nodes[cur_node_idx].accept_mb)
2516 continue;
2517
2518 if (dfa->nodes[cur_node_idx].constraint)
2519 {
2520 context = re_string_context_at (&mctx->input,
2521 re_string_cur_idx (&mctx->input),
2522 mctx->eflags);
2523 if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint,
2524 context))
2525 continue;
2526 }
2527
2528 /* How many bytes the node can accept? */
2529 naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input,
2530 re_string_cur_idx (&mctx->input));
2531 if (naccepted == 0)
2532 continue;
2533
2534 /* The node can accepts `naccepted' bytes. */
2535 dest_idx = re_string_cur_idx (&mctx->input) + naccepted;
2536 mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted
2537 : mctx->max_mb_elem_len);
2538 err = clean_state_log_if_needed (mctx, dest_idx);
2539 if (BE (err != REG_NOERROR, 0))
2540 return err;
2541#ifdef DEBUG
2542 assert (dfa->nexts[cur_node_idx] != -1);
2543#endif
2544 new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx];
2545
2546 dest_state = mctx->state_log[dest_idx];
2547 if (dest_state == NULL)
2548 dest_nodes = *new_nodes;
2549 else
2550 {
2551 err = re_node_set_init_union (&dest_nodes,
2552 dest_state->entrance_nodes, new_nodes);
2553 if (BE (err != REG_NOERROR, 0))
2554 return err;
2555 }
2556 context = re_string_context_at (&mctx->input, dest_idx - 1,
2557 mctx->eflags);
2558 mctx->state_log[dest_idx]
2559 = re_acquire_state_context (&err, dfa, &dest_nodes, context);
2560 if (dest_state != NULL)
2561 re_node_set_free (&dest_nodes);
2562 if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0))
2563 return err;
2564 }
2565 return REG_NOERROR;
2566}
2567#endif /* RE_ENABLE_I18N */
2568
2569static reg_errcode_t
2570internal_function
2571transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes)
2572{
2573 const re_dfa_t *const dfa = mctx->dfa;
2574 reg_errcode_t err;
2575 int i;
2576 int cur_str_idx = re_string_cur_idx (&mctx->input);
2577
2578 for (i = 0; i < nodes->nelem; ++i)
2579 {
2580 int dest_str_idx, prev_nelem, bkc_idx;
2581 int node_idx = nodes->elems[i];
2582 unsigned int context;
2583 const re_token_t *node = dfa->nodes + node_idx;
2584 re_node_set *new_dest_nodes;
2585
2586 /* Check whether `node' is a backreference or not. */
2587 if (node->type != OP_BACK_REF)
2588 continue;
2589
2590 if (node->constraint)
2591 {
2592 context = re_string_context_at (&mctx->input, cur_str_idx,
2593 mctx->eflags);
2594 if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
2595 continue;
2596 }
2597
2598 /* `node' is a backreference.
2599 Check the substring which the substring matched. */
2600 bkc_idx = mctx->nbkref_ents;
2601 err = get_subexp (mctx, node_idx, cur_str_idx);
2602 if (BE (err != REG_NOERROR, 0))
2603 goto free_return;
2604
2605 /* And add the epsilon closures (which is `new_dest_nodes') of
2606 the backreference to appropriate state_log. */
2607#ifdef DEBUG
2608 assert (dfa->nexts[node_idx] != -1);
2609#endif
2610 for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx)
2611 {
2612 int subexp_len;
2613 re_dfastate_t *dest_state;
2614 struct re_backref_cache_entry *bkref_ent;
2615 bkref_ent = mctx->bkref_ents + bkc_idx;
2616 if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx)
2617 continue;
2618 subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from;
2619 new_dest_nodes = (subexp_len == 0
2620 ? dfa->eclosures + dfa->edests[node_idx].elems[0]
2621 : dfa->eclosures + dfa->nexts[node_idx]);
2622 dest_str_idx = (cur_str_idx + bkref_ent->subexp_to
2623 - bkref_ent->subexp_from);
2624 context = re_string_context_at (&mctx->input, dest_str_idx - 1,
2625 mctx->eflags);
2626 dest_state = mctx->state_log[dest_str_idx];
2627 prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0
2628 : mctx->state_log[cur_str_idx]->nodes.nelem);
2629 /* Add `new_dest_node' to state_log. */
2630 if (dest_state == NULL)
2631 {
2632 mctx->state_log[dest_str_idx]
2633 = re_acquire_state_context (&err, dfa, new_dest_nodes,
2634 context);
2635 if (BE (mctx->state_log[dest_str_idx] == NULL
2636 && err != REG_NOERROR, 0))
2637 goto free_return;
2638 }
2639 else
2640 {
2641 re_node_set dest_nodes;
2642 err = re_node_set_init_union (&dest_nodes,
2643 dest_state->entrance_nodes,
2644 new_dest_nodes);
2645 if (BE (err != REG_NOERROR, 0))
2646 {
2647 re_node_set_free (&dest_nodes);
2648 goto free_return;
2649 }
2650 mctx->state_log[dest_str_idx]
2651 = re_acquire_state_context (&err, dfa, &dest_nodes, context);
2652 re_node_set_free (&dest_nodes);
2653 if (BE (mctx->state_log[dest_str_idx] == NULL
2654 && err != REG_NOERROR, 0))
2655 goto free_return;
2656 }
2657 /* We need to check recursively if the backreference can epsilon
2658 transit. */
2659 if (subexp_len == 0
2660 && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem)
2661 {
2662 err = check_subexp_matching_top (mctx, new_dest_nodes,
2663 cur_str_idx);
2664 if (BE (err != REG_NOERROR, 0))
2665 goto free_return;
2666 err = transit_state_bkref (mctx, new_dest_nodes);
2667 if (BE (err != REG_NOERROR, 0))
2668 goto free_return;
2669 }
2670 }
2671 }
2672 err = REG_NOERROR;
2673 free_return:
2674 return err;
2675}
2676
2677/* Enumerate all the candidates which the backreference BKREF_NODE can match
2678 at BKREF_STR_IDX, and register them by match_ctx_add_entry().
2679 Note that we might collect inappropriate candidates here.
2680 However, the cost of checking them strictly here is too high, then we
2681 delay these checking for prune_impossible_nodes(). */
2682
2683static reg_errcode_t
2684internal_function
2685get_subexp (re_match_context_t *mctx, int bkref_node, int bkref_str_idx)
2686{
2687 const re_dfa_t *const dfa = mctx->dfa;
2688 int subexp_num, sub_top_idx;
2689 const char *buf = (const char *) re_string_get_buffer (&mctx->input);
2690 /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */
2691 int cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx);
2692 if (cache_idx != -1)
2693 {
2694 const struct re_backref_cache_entry *entry
2695 = mctx->bkref_ents + cache_idx;
2696 do
2697 if (entry->node == bkref_node)
2698 return REG_NOERROR; /* We already checked it. */
2699 while (entry++->more);
2700 }
2701
2702 subexp_num = dfa->nodes[bkref_node].opr.idx;
2703
2704 /* For each sub expression */
2705 for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx)
2706 {
2707 reg_errcode_t err;
2708 re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx];
2709 re_sub_match_last_t *sub_last;
2710 int sub_last_idx, sl_str, bkref_str_off;
2711
2712 if (dfa->nodes[sub_top->node].opr.idx != subexp_num)
2713 continue; /* It isn't related. */
2714
2715 sl_str = sub_top->str_idx;
2716 bkref_str_off = bkref_str_idx;
2717 /* At first, check the last node of sub expressions we already
2718 evaluated. */
2719 for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx)
2720 {
2721 int sl_str_diff;
2722 sub_last = sub_top->lasts[sub_last_idx];
2723 sl_str_diff = sub_last->str_idx - sl_str;
2724 /* The matched string by the sub expression match with the substring
2725 at the back reference? */
2726 if (sl_str_diff > 0)
2727 {
2728 if (BE (bkref_str_off + sl_str_diff > mctx->input.valid_len, 0))
2729 {
2730 /* Not enough chars for a successful match. */
2731 if (bkref_str_off + sl_str_diff > mctx->input.len)
2732 break;
2733
2734 err = clean_state_log_if_needed (mctx,
2735 bkref_str_off
2736 + sl_str_diff);
2737 if (BE (err != REG_NOERROR, 0))
2738 return err;
2739 buf = (const char *) re_string_get_buffer (&mctx->input);
2740 }
2741 if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0)
2742 /* We don't need to search this sub expression any more. */
2743 break;
2744 }
2745 bkref_str_off += sl_str_diff;
2746 sl_str += sl_str_diff;
2747 err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
2748 bkref_str_idx);
2749
2750 /* Reload buf, since the preceding call might have reallocated
2751 the buffer. */
2752 buf = (const char *) re_string_get_buffer (&mctx->input);
2753
2754 if (err == REG_NOMATCH)
2755 continue;
2756 if (BE (err != REG_NOERROR, 0))
2757 return err;
2758 }
2759
2760 if (sub_last_idx < sub_top->nlasts)
2761 continue;
2762 if (sub_last_idx > 0)
2763 ++sl_str;
2764 /* Then, search for the other last nodes of the sub expression. */
2765 for (; sl_str <= bkref_str_idx; ++sl_str)
2766 {
2767 int cls_node, sl_str_off;
2768 const re_node_set *nodes;
2769 sl_str_off = sl_str - sub_top->str_idx;
2770 /* The matched string by the sub expression match with the substring
2771 at the back reference? */
2772 if (sl_str_off > 0)
2773 {
2774 if (BE (bkref_str_off >= mctx->input.valid_len, 0))
2775 {
2776 /* If we are at the end of the input, we cannot match. */
2777 if (bkref_str_off >= mctx->input.len)
2778 break;
2779
2780 err = extend_buffers (mctx);
2781 if (BE (err != REG_NOERROR, 0))
2782 return err;
2783
2784 buf = (const char *) re_string_get_buffer (&mctx->input);
2785 }
2786 if (buf [bkref_str_off++] != buf[sl_str - 1])
2787 break; /* We don't need to search this sub expression
2788 any more. */
2789 }
2790 if (mctx->state_log[sl_str] == NULL)
2791 continue;
2792 /* Does this state have a ')' of the sub expression? */
2793 nodes = &mctx->state_log[sl_str]->nodes;
2794 cls_node = find_subexp_node (dfa, nodes, subexp_num,
2795 OP_CLOSE_SUBEXP);
2796 if (cls_node == -1)
2797 continue; /* No. */
2798 if (sub_top->path == NULL)
2799 {
2800 sub_top->path = calloc (sizeof (state_array_t),
2801 sl_str - sub_top->str_idx + 1);
2802 if (sub_top->path == NULL)
2803 return REG_ESPACE;
2804 }
2805 /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node
2806 in the current context? */
2807 err = check_arrival (mctx, sub_top->path, sub_top->node,
2808 sub_top->str_idx, cls_node, sl_str,
2809 OP_CLOSE_SUBEXP);
2810 if (err == REG_NOMATCH)
2811 continue;
2812 if (BE (err != REG_NOERROR, 0))
2813 return err;
2814 sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str);
2815 if (BE (sub_last == NULL, 0))
2816 return REG_ESPACE;
2817 err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
2818 bkref_str_idx);
2819 if (err == REG_NOMATCH)
2820 continue;
2821 }
2822 }
2823 return REG_NOERROR;
2824}
2825
2826/* Helper functions for get_subexp(). */
2827
2828/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR.
2829 If it can arrive, register the sub expression expressed with SUB_TOP
2830 and SUB_LAST. */
2831
2832static reg_errcode_t
2833internal_function
2834get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top,
2835 re_sub_match_last_t *sub_last, int bkref_node, int bkref_str)
2836{
2837 reg_errcode_t err;
2838 int to_idx;
2839 /* Can the subexpression arrive the back reference? */
2840 err = check_arrival (mctx, &sub_last->path, sub_last->node,
2841 sub_last->str_idx, bkref_node, bkref_str,
2842 OP_OPEN_SUBEXP);
2843 if (err != REG_NOERROR)
2844 return err;
2845 err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx,
2846 sub_last->str_idx);
2847 if (BE (err != REG_NOERROR, 0))
2848 return err;
2849 to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx;
2850 return clean_state_log_if_needed (mctx, to_idx);
2851}
2852
2853/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX.
2854 Search '(' if FL_OPEN, or search ')' otherwise.
2855 TODO: This function isn't efficient...
2856 Because there might be more than one nodes whose types are
2857 OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
2858 nodes.
2859 E.g. RE: (a){2} */
2860
2861static int
2862internal_function
2863find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
2864 int subexp_idx, int type)
2865{
2866 int cls_idx;
2867 for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx)
2868 {
2869 int cls_node = nodes->elems[cls_idx];
2870 const re_token_t *node = dfa->nodes + cls_node;
2871 if (node->type == type
2872 && node->opr.idx == subexp_idx)
2873 return cls_node;
2874 }
2875 return -1;
2876}
2877
2878/* Check whether the node TOP_NODE at TOP_STR can arrive to the node
2879 LAST_NODE at LAST_STR. We record the path onto PATH since it will be
2880 heavily reused.
2881 Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */
2882
2883static reg_errcode_t
2884internal_function
2885check_arrival (re_match_context_t *mctx, state_array_t *path, int top_node,
2886 int top_str, int last_node, int last_str, int type)
2887{
2888 const re_dfa_t *const dfa = mctx->dfa;
2889 reg_errcode_t err = REG_NOERROR;
2890 int subexp_num, backup_cur_idx, str_idx, null_cnt;
2891 re_dfastate_t *cur_state = NULL;
2892 re_node_set *cur_nodes, next_nodes;
2893 re_dfastate_t **backup_state_log;
2894 unsigned int context;
2895
2896 subexp_num = dfa->nodes[top_node].opr.idx;
2897 /* Extend the buffer if we need. */
2898 if (BE (path->alloc < last_str + mctx->max_mb_elem_len + 1, 0))
2899 {
2900 re_dfastate_t **new_array;
2901 int old_alloc = path->alloc;
2902 path->alloc += last_str + mctx->max_mb_elem_len + 1;
2903 new_array = re_realloc (path->array, re_dfastate_t *, path->alloc);
2904 if (BE (new_array == NULL, 0))
2905 {
2906 path->alloc = old_alloc;
2907 return REG_ESPACE;
2908 }
2909 path->array = new_array;
2910 memset (new_array + old_alloc, '\0',
2911 sizeof (re_dfastate_t *) * (path->alloc - old_alloc));
2912 }
2913
2914 str_idx = path->next_idx ? path->next_idx : top_str;
2915
2916 /* Temporary modify MCTX. */
2917 backup_state_log = mctx->state_log;
2918 backup_cur_idx = mctx->input.cur_idx;
2919 mctx->state_log = path->array;
2920 mctx->input.cur_idx = str_idx;
2921
2922 /* Setup initial node set. */
2923 context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
2924 if (str_idx == top_str)
2925 {
2926 err = re_node_set_init_1 (&next_nodes, top_node);
2927 if (BE (err != REG_NOERROR, 0))
2928 return err;
2929 err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
2930 if (BE (err != REG_NOERROR, 0))
2931 {
2932 re_node_set_free (&next_nodes);
2933 return err;
2934 }
2935 }
2936 else
2937 {
2938 cur_state = mctx->state_log[str_idx];
2939 if (cur_state && cur_state->has_backref)
2940 {
2941 err = re_node_set_init_copy (&next_nodes, &cur_state->nodes);
2942 if (BE (err != REG_NOERROR, 0))
2943 return err;
2944 }
2945 else
2946 re_node_set_init_empty (&next_nodes);
2947 }
2948 if (str_idx == top_str || (cur_state && cur_state->has_backref))
2949 {
2950 if (next_nodes.nelem)
2951 {
2952 err = expand_bkref_cache (mctx, &next_nodes, str_idx,
2953 subexp_num, type);
2954 if (BE (err != REG_NOERROR, 0))
2955 {
2956 re_node_set_free (&next_nodes);
2957 return err;
2958 }
2959 }
2960 cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
2961 if (BE (cur_state == NULL && err != REG_NOERROR, 0))
2962 {
2963 re_node_set_free (&next_nodes);
2964 return err;
2965 }
2966 mctx->state_log[str_idx] = cur_state;
2967 }
2968
2969 for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;)
2970 {
2971 re_node_set_empty (&next_nodes);
2972 if (mctx->state_log[str_idx + 1])
2973 {
2974 err = re_node_set_merge (&next_nodes,
2975 &mctx->state_log[str_idx + 1]->nodes);
2976 if (BE (err != REG_NOERROR, 0))
2977 {
2978 re_node_set_free (&next_nodes);
2979 return err;
2980 }
2981 }
2982 if (cur_state)
2983 {
2984 err = check_arrival_add_next_nodes (mctx, str_idx,
2985 &cur_state->non_eps_nodes,
2986 &next_nodes);
2987 if (BE (err != REG_NOERROR, 0))
2988 {
2989 re_node_set_free (&next_nodes);
2990 return err;
2991 }
2992 }
2993 ++str_idx;
2994 if (next_nodes.nelem)
2995 {
2996 err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
2997 if (BE (err != REG_NOERROR, 0))
2998 {
2999 re_node_set_free (&next_nodes);
3000 return err;
3001 }
3002 err = expand_bkref_cache (mctx, &next_nodes, str_idx,
3003 subexp_num, type);
3004 if (BE (err != REG_NOERROR, 0))
3005 {
3006 re_node_set_free (&next_nodes);
3007 return err;
3008 }
3009 }
3010 context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
3011 cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
3012 if (BE (cur_state == NULL && err != REG_NOERROR, 0))
3013 {
3014 re_node_set_free (&next_nodes);
3015 return err;
3016 }
3017 mctx->state_log[str_idx] = cur_state;
3018 null_cnt = cur_state == NULL ? null_cnt + 1 : 0;
3019 }
3020 re_node_set_free (&next_nodes);
3021 cur_nodes = (mctx->state_log[last_str] == NULL ? NULL
3022 : &mctx->state_log[last_str]->nodes);
3023 path->next_idx = str_idx;
3024
3025 /* Fix MCTX. */
3026 mctx->state_log = backup_state_log;
3027 mctx->input.cur_idx = backup_cur_idx;
3028
3029 /* Then check the current node set has the node LAST_NODE. */
3030 if (cur_nodes != NULL && re_node_set_contains (cur_nodes, last_node))
3031 return REG_NOERROR;
3032
3033 return REG_NOMATCH;
3034}
3035
3036/* Helper functions for check_arrival. */
3037
3038/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them
3039 to NEXT_NODES.
3040 TODO: This function is similar to the functions transit_state*(),
3041 however this function has many additional works.
3042 Can't we unify them? */
3043
3044static reg_errcode_t
3045internal_function
3046check_arrival_add_next_nodes (re_match_context_t *mctx, int str_idx,
3047 re_node_set *cur_nodes, re_node_set *next_nodes)
3048{
3049 const re_dfa_t *const dfa = mctx->dfa;
3050 int result;
3051 int cur_idx;
3052#ifdef RE_ENABLE_I18N
3053 reg_errcode_t err = REG_NOERROR;
3054#endif
3055 re_node_set union_set;
3056 re_node_set_init_empty (&union_set);
3057 for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx)
3058 {
3059 int naccepted = 0;
3060 int cur_node = cur_nodes->elems[cur_idx];
3061#ifdef DEBUG
3062 re_token_type_t type = dfa->nodes[cur_node].type;
3063 assert (!IS_EPSILON_NODE (type));
3064#endif
3065#ifdef RE_ENABLE_I18N
3066 /* If the node may accept `multi byte'. */
3067 if (dfa->nodes[cur_node].accept_mb)
3068 {
3069 naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input,
3070 str_idx);
3071 if (naccepted > 1)
3072 {
3073 re_dfastate_t *dest_state;
3074 int next_node = dfa->nexts[cur_node];
3075 int next_idx = str_idx + naccepted;
3076 dest_state = mctx->state_log[next_idx];
3077 re_node_set_empty (&union_set);
3078 if (dest_state)
3079 {
3080 err = re_node_set_merge (&union_set, &dest_state->nodes);
3081 if (BE (err != REG_NOERROR, 0))
3082 {
3083 re_node_set_free (&union_set);
3084 return err;
3085 }
3086 }
3087 result = re_node_set_insert (&union_set, next_node);
3088 if (BE (result < 0, 0))
3089 {
3090 re_node_set_free (&union_set);
3091 return REG_ESPACE;
3092 }
3093 mctx->state_log[next_idx] = re_acquire_state (&err, dfa,
3094 &union_set);
3095 if (BE (mctx->state_log[next_idx] == NULL
3096 && err != REG_NOERROR, 0))
3097 {
3098 re_node_set_free (&union_set);
3099 return err;
3100 }
3101 }
3102 }
3103#endif /* RE_ENABLE_I18N */
3104 if (naccepted
3105 || check_node_accept (mctx, dfa->nodes + cur_node, str_idx))
3106 {
3107 result = re_node_set_insert (next_nodes, dfa->nexts[cur_node]);
3108 if (BE (result < 0, 0))
3109 {
3110 re_node_set_free (&union_set);
3111 return REG_ESPACE;
3112 }
3113 }
3114 }
3115 re_node_set_free (&union_set);
3116 return REG_NOERROR;
3117}
3118
3119/* For all the nodes in CUR_NODES, add the epsilon closures of them to
3120 CUR_NODES, however exclude the nodes which are:
3121 - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN.
3122 - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN.
3123*/
3124
3125static reg_errcode_t
3126internal_function
3127check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes,
3128 int ex_subexp, int type)
3129{
3130 reg_errcode_t err;
3131 int idx, outside_node;
3132 re_node_set new_nodes;
3133#ifdef DEBUG
3134 assert (cur_nodes->nelem);
3135#endif
3136 err = re_node_set_alloc (&new_nodes, cur_nodes->nelem);
3137 if (BE (err != REG_NOERROR, 0))
3138 return err;
3139 /* Create a new node set NEW_NODES with the nodes which are epsilon
3140 closures of the node in CUR_NODES. */
3141
3142 for (idx = 0; idx < cur_nodes->nelem; ++idx)
3143 {
3144 int cur_node = cur_nodes->elems[idx];
3145 const re_node_set *eclosure = dfa->eclosures + cur_node;
3146 outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type);
3147 if (outside_node == -1)
3148 {
3149 /* There are no problematic nodes, just merge them. */
3150 err = re_node_set_merge (&new_nodes, eclosure);
3151 if (BE (err != REG_NOERROR, 0))
3152 {
3153 re_node_set_free (&new_nodes);
3154 return err;
3155 }
3156 }
3157 else
3158 {
3159 /* There are problematic nodes, re-calculate incrementally. */
3160 err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node,
3161 ex_subexp, type);
3162 if (BE (err != REG_NOERROR, 0))
3163 {
3164 re_node_set_free (&new_nodes);
3165 return err;
3166 }
3167 }
3168 }
3169 re_node_set_free (cur_nodes);
3170 *cur_nodes = new_nodes;
3171 return REG_NOERROR;
3172}
3173
3174/* Helper function for check_arrival_expand_ecl.
3175 Check incrementally the epsilon closure of TARGET, and if it isn't
3176 problematic append it to DST_NODES. */
3177
3178static reg_errcode_t
3179internal_function
3180check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes,
3181 int target, int ex_subexp, int type)
3182{
3183 int cur_node;
3184 for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);)
3185 {
3186 int err;
3187
3188 if (dfa->nodes[cur_node].type == type
3189 && dfa->nodes[cur_node].opr.idx == ex_subexp)
3190 {
3191 if (type == OP_CLOSE_SUBEXP)
3192 {
3193 err = re_node_set_insert (dst_nodes, cur_node);
3194 if (BE (err == -1, 0))
3195 return REG_ESPACE;
3196 }
3197 break;
3198 }
3199 err = re_node_set_insert (dst_nodes, cur_node);
3200 if (BE (err == -1, 0))
3201 return REG_ESPACE;
3202 if (dfa->edests[cur_node].nelem == 0)
3203 break;
3204 if (dfa->edests[cur_node].nelem == 2)
3205 {
3206 err = check_arrival_expand_ecl_sub (dfa, dst_nodes,
3207 dfa->edests[cur_node].elems[1],
3208 ex_subexp, type);
3209 if (BE (err != REG_NOERROR, 0))
3210 return err;
3211 }
3212 cur_node = dfa->edests[cur_node].elems[0];
3213 }
3214 return REG_NOERROR;
3215}
3216
3217
3218/* For all the back references in the current state, calculate the
3219 destination of the back references by the appropriate entry
3220 in MCTX->BKREF_ENTS. */
3221
3222static reg_errcode_t
3223internal_function
3224expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes,
3225 int cur_str, int subexp_num, int type)
3226{
3227 const re_dfa_t *const dfa = mctx->dfa;
3228 reg_errcode_t err;
3229 int cache_idx_start = search_cur_bkref_entry (mctx, cur_str);
3230 struct re_backref_cache_entry *ent;
3231
3232 if (cache_idx_start == -1)
3233 return REG_NOERROR;
3234
3235 restart:
3236 ent = mctx->bkref_ents + cache_idx_start;
3237 do
3238 {
3239 int to_idx, next_node;
3240
3241 /* Is this entry ENT is appropriate? */
3242 if (!re_node_set_contains (cur_nodes, ent->node))
3243 continue; /* No. */
3244
3245 to_idx = cur_str + ent->subexp_to - ent->subexp_from;
3246 /* Calculate the destination of the back reference, and append it
3247 to MCTX->STATE_LOG. */
3248 if (to_idx == cur_str)
3249 {
3250 /* The backreference did epsilon transit, we must re-check all the
3251 node in the current state. */
3252 re_node_set new_dests;
3253 reg_errcode_t err2, err3;
3254 next_node = dfa->edests[ent->node].elems[0];
3255 if (re_node_set_contains (cur_nodes, next_node))
3256 continue;
3257 err = re_node_set_init_1 (&new_dests, next_node);
3258 err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type);
3259 err3 = re_node_set_merge (cur_nodes, &new_dests);
3260 re_node_set_free (&new_dests);
3261 if (BE (err != REG_NOERROR || err2 != REG_NOERROR
3262 || err3 != REG_NOERROR, 0))
3263 {
3264 err = (err != REG_NOERROR ? err
3265 : (err2 != REG_NOERROR ? err2 : err3));
3266 return err;
3267 }
3268 /* TODO: It is still inefficient... */
3269 goto restart;
3270 }
3271 else
3272 {
3273 re_node_set union_set;
3274 next_node = dfa->nexts[ent->node];
3275 if (mctx->state_log[to_idx])
3276 {
3277 int ret;
3278 if (re_node_set_contains (&mctx->state_log[to_idx]->nodes,
3279 next_node))
3280 continue;
3281 err = re_node_set_init_copy (&union_set,
3282 &mctx->state_log[to_idx]->nodes);
3283 ret = re_node_set_insert (&union_set, next_node);
3284 if (BE (err != REG_NOERROR || ret < 0, 0))
3285 {
3286 re_node_set_free (&union_set);
3287 err = err != REG_NOERROR ? err : REG_ESPACE;
3288 return err;
3289 }
3290 }
3291 else
3292 {
3293 err = re_node_set_init_1 (&union_set, next_node);
3294 if (BE (err != REG_NOERROR, 0))
3295 return err;
3296 }
3297 mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set);
3298 re_node_set_free (&union_set);
3299 if (BE (mctx->state_log[to_idx] == NULL
3300 && err != REG_NOERROR, 0))
3301 return err;
3302 }
3303 }
3304 while (ent++->more);
3305 return REG_NOERROR;
3306}
3307
3308/* Build transition table for the state.
3309 Return 1 if succeeded, otherwise return NULL. */
3310
3311static int
3312internal_function
3313build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
3314{
3315 reg_errcode_t err;
3316 int i, j, ch, need_word_trtable = 0;
3317 bitset_word_t elem, mask;
3318 bool dests_node_malloced = false;
3319 bool dest_states_malloced = false;
3320 int ndests; /* Number of the destination states from `state'. */
3321 re_dfastate_t **trtable;
3322 re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl;
3323 re_node_set follows, *dests_node;
3324 bitset_t *dests_ch;
3325 bitset_t acceptable;
3326
3327 struct dests_alloc
3328 {
3329 re_node_set dests_node[SBC_MAX];
3330 bitset_t dests_ch[SBC_MAX];
3331 } *dests_alloc;
3332
3333 /* We build DFA states which corresponds to the destination nodes
3334 from `state'. `dests_node[i]' represents the nodes which i-th
3335 destination state contains, and `dests_ch[i]' represents the
3336 characters which i-th destination state accepts. */
3337#ifdef HAVE_ALLOCA
3338 if (__libc_use_alloca (sizeof (struct dests_alloc)))
3339 dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc));
3340 else
3341#endif
3342 {
3343 dests_alloc = re_malloc (struct dests_alloc, 1);
3344 if (BE (dests_alloc == NULL, 0))
3345 return 0;
3346 dests_node_malloced = true;
3347 }
3348 dests_node = dests_alloc->dests_node;
3349 dests_ch = dests_alloc->dests_ch;
3350
3351 /* Initialize transiton table. */
3352 state->word_trtable = state->trtable = NULL;
3353
3354 /* At first, group all nodes belonging to `state' into several
3355 destinations. */
3356 ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch);
3357 if (BE (ndests <= 0, 0))
3358 {
3359 if (dests_node_malloced)
3360 free (dests_alloc);
3361 /* Return 0 in case of an error, 1 otherwise. */
3362 if (ndests == 0)
3363 {
3364 state->trtable = (re_dfastate_t **)
3365 calloc (sizeof (re_dfastate_t *), SBC_MAX);
3366 return 1;
3367 }
3368 return 0;
3369 }
3370
3371 err = re_node_set_alloc (&follows, ndests + 1);
3372 if (BE (err != REG_NOERROR, 0))
3373 goto out_free;
3374
3375 /* Avoid arithmetic overflow in size calculation. */
3376 if (BE ((((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX)
3377 / (3 * sizeof (re_dfastate_t *)))
3378 < ndests),
3379 0))
3380 goto out_free;
3381
3382#ifdef HAVE_ALLOCA
3383 if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX
3384 + ndests * 3 * sizeof (re_dfastate_t *)))
3385 dest_states = (re_dfastate_t **)
3386 alloca (ndests * 3 * sizeof (re_dfastate_t *));
3387 else
3388#endif
3389 {
3390 dest_states = (re_dfastate_t **)
3391 malloc (ndests * 3 * sizeof (re_dfastate_t *));
3392 if (BE (dest_states == NULL, 0))
3393 {
3394out_free:
3395 if (dest_states_malloced)
3396 free (dest_states);
3397 re_node_set_free (&follows);
3398 for (i = 0; i < ndests; ++i)
3399 re_node_set_free (dests_node + i);
3400 if (dests_node_malloced)
3401 free (dests_alloc);
3402 return 0;
3403 }
3404 dest_states_malloced = true;
3405 }
3406 dest_states_word = dest_states + ndests;
3407 dest_states_nl = dest_states_word + ndests;
3408 bitset_empty (acceptable);
3409
3410 /* Then build the states for all destinations. */
3411 for (i = 0; i < ndests; ++i)
3412 {
3413 int next_node;
3414 re_node_set_empty (&follows);
3415 /* Merge the follows of this destination states. */
3416 for (j = 0; j < dests_node[i].nelem; ++j)
3417 {
3418 next_node = dfa->nexts[dests_node[i].elems[j]];
3419 if (next_node != -1)
3420 {
3421 err = re_node_set_merge (&follows, dfa->eclosures + next_node);
3422 if (BE (err != REG_NOERROR, 0))
3423 goto out_free;
3424 }
3425 }
3426 dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0);
3427 if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0))
3428 goto out_free;
3429 /* If the new state has context constraint,
3430 build appropriate states for these contexts. */
3431 if (dest_states[i]->has_constraint)
3432 {
3433 dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows,
3434 CONTEXT_WORD);
3435 if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0))
3436 goto out_free;
3437
3438 if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1)
3439 need_word_trtable = 1;
3440
3441 dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows,
3442 CONTEXT_NEWLINE);
3443 if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0))
3444 goto out_free;
3445 }
3446 else
3447 {
3448 dest_states_word[i] = dest_states[i];
3449 dest_states_nl[i] = dest_states[i];
3450 }
3451 bitset_merge (acceptable, dests_ch[i]);
3452 }
3453
3454 if (!BE (need_word_trtable, 0))
3455 {
3456 /* We don't care about whether the following character is a word
3457 character, or we are in a single-byte character set so we can
3458 discern by looking at the character code: allocate a
3459 256-entry transition table. */
3460 trtable = state->trtable =
3461 (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX);
3462 if (BE (trtable == NULL, 0))
3463 goto out_free;
3464
3465 /* For all characters ch...: */
3466 for (i = 0; i < BITSET_WORDS; ++i)
3467 for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
3468 elem;
3469 mask <<= 1, elem >>= 1, ++ch)
3470 if (BE (elem & 1, 0))
3471 {
3472 /* There must be exactly one destination which accepts
3473 character ch. See group_nodes_into_DFAstates. */
3474 for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
3475 ;
3476
3477 /* j-th destination accepts the word character ch. */
3478 if (dfa->word_char[i] & mask)
3479 trtable[ch] = dest_states_word[j];
3480 else
3481 trtable[ch] = dest_states[j];
3482 }
3483 }
3484 else
3485 {
3486 /* We care about whether the following character is a word
3487 character, and we are in a multi-byte character set: discern
3488 by looking at the character code: build two 256-entry
3489 transition tables, one starting at trtable[0] and one
3490 starting at trtable[SBC_MAX]. */
3491 trtable = state->word_trtable =
3492 (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX);
3493 if (BE (trtable == NULL, 0))
3494 goto out_free;
3495
3496 /* For all characters ch...: */
3497 for (i = 0; i < BITSET_WORDS; ++i)
3498 for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
3499 elem;
3500 mask <<= 1, elem >>= 1, ++ch)
3501 if (BE (elem & 1, 0))
3502 {
3503 /* There must be exactly one destination which accepts
3504 character ch. See group_nodes_into_DFAstates. */
3505 for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
3506 ;
3507
3508 /* j-th destination accepts the word character ch. */
3509 trtable[ch] = dest_states[j];
3510 trtable[ch + SBC_MAX] = dest_states_word[j];
3511 }
3512 }
3513
3514 /* new line */
3515 if (bitset_contain (acceptable, NEWLINE_CHAR))
3516 {
3517 /* The current state accepts newline character. */
3518 for (j = 0; j < ndests; ++j)
3519 if (bitset_contain (dests_ch[j], NEWLINE_CHAR))
3520 {
3521 /* k-th destination accepts newline character. */
3522 trtable[NEWLINE_CHAR] = dest_states_nl[j];
3523 if (need_word_trtable)
3524 trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j];
3525 /* There must be only one destination which accepts
3526 newline. See group_nodes_into_DFAstates. */
3527 break;
3528 }
3529 }
3530
3531 if (dest_states_malloced)
3532 free (dest_states);
3533
3534 re_node_set_free (&follows);
3535 for (i = 0; i < ndests; ++i)
3536 re_node_set_free (dests_node + i);
3537
3538 if (dests_node_malloced)
3539 free (dests_alloc);
3540
3541 return 1;
3542}
3543
3544/* Group all nodes belonging to STATE into several destinations.
3545 Then for all destinations, set the nodes belonging to the destination
3546 to DESTS_NODE[i] and set the characters accepted by the destination
3547 to DEST_CH[i]. This function return the number of destinations. */
3548
3549static int
3550internal_function
3551group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state,
3552 re_node_set *dests_node, bitset_t *dests_ch)
3553{
3554 reg_errcode_t err;
3555 int result;
3556 int i, j, k;
3557 int ndests; /* Number of the destinations from `state'. */
3558 bitset_t accepts; /* Characters a node can accept. */
3559 const re_node_set *cur_nodes = &state->nodes;
3560 bitset_empty (accepts);
3561 ndests = 0;
3562
3563 /* For all the nodes belonging to `state', */
3564 for (i = 0; i < cur_nodes->nelem; ++i)
3565 {
3566 re_token_t *node = &dfa->nodes[cur_nodes->elems[i]];
3567 re_token_type_t type = node->type;
3568 unsigned int constraint = node->constraint;
3569
3570 /* Enumerate all single byte character this node can accept. */
3571 if (type == CHARACTER)
3572 bitset_set (accepts, node->opr.c);
3573 else if (type == SIMPLE_BRACKET)
3574 {
3575 bitset_merge (accepts, node->opr.sbcset);
3576 }
3577 else if (type == OP_PERIOD)
3578 {
3579#ifdef RE_ENABLE_I18N
3580 if (dfa->mb_cur_max > 1)
3581 bitset_merge (accepts, dfa->sb_char);
3582 else
3583#endif
3584 bitset_set_all (accepts);
3585 if (!(dfa->syntax & RE_DOT_NEWLINE))
3586 bitset_clear (accepts, '\n');
3587 if (dfa->syntax & RE_DOT_NOT_NULL)
3588 bitset_clear (accepts, '\0');
3589 }
3590#ifdef RE_ENABLE_I18N
3591 else if (type == OP_UTF8_PERIOD)
3592 {
3593 memset (accepts, '\xff', sizeof (bitset_t) / 2);
3594 if (!(dfa->syntax & RE_DOT_NEWLINE))
3595 bitset_clear (accepts, '\n');
3596 if (dfa->syntax & RE_DOT_NOT_NULL)
3597 bitset_clear (accepts, '\0');
3598 }
3599#endif
3600 else
3601 continue;
3602
3603 /* Check the `accepts' and sift the characters which are not
3604 match it the context. */
3605 if (constraint)
3606 {
3607 if (constraint & NEXT_NEWLINE_CONSTRAINT)
3608 {
3609 bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR);
3610 bitset_empty (accepts);
3611 if (accepts_newline)
3612 bitset_set (accepts, NEWLINE_CHAR);
3613 else
3614 continue;
3615 }
3616 if (constraint & NEXT_ENDBUF_CONSTRAINT)
3617 {
3618 bitset_empty (accepts);
3619 continue;
3620 }
3621
3622 if (constraint & NEXT_WORD_CONSTRAINT)
3623 {
3624 bitset_word_t any_set = 0;
3625 if (type == CHARACTER && !node->word_char)
3626 {
3627 bitset_empty (accepts);
3628 continue;
3629 }
3630#ifdef RE_ENABLE_I18N
3631 if (dfa->mb_cur_max > 1)
3632 for (j = 0; j < BITSET_WORDS; ++j)
3633 any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j]));
3634 else
3635#endif
3636 for (j = 0; j < BITSET_WORDS; ++j)
3637 any_set |= (accepts[j] &= dfa->word_char[j]);
3638 if (!any_set)
3639 continue;
3640 }
3641 if (constraint & NEXT_NOTWORD_CONSTRAINT)
3642 {
3643 bitset_word_t any_set = 0;
3644 if (type == CHARACTER && node->word_char)
3645 {
3646 bitset_empty (accepts);
3647 continue;
3648 }
3649#ifdef RE_ENABLE_I18N
3650 if (dfa->mb_cur_max > 1)
3651 for (j = 0; j < BITSET_WORDS; ++j)
3652 any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j]));
3653 else
3654#endif
3655 for (j = 0; j < BITSET_WORDS; ++j)
3656 any_set |= (accepts[j] &= ~dfa->word_char[j]);
3657 if (!any_set)
3658 continue;
3659 }
3660 }
3661
3662 /* Then divide `accepts' into DFA states, or create a new
3663 state. Above, we make sure that accepts is not empty. */
3664 for (j = 0; j < ndests; ++j)
3665 {
3666 bitset_t intersec; /* Intersection sets, see below. */
3667 bitset_t remains;
3668 /* Flags, see below. */
3669 bitset_word_t has_intersec, not_subset, not_consumed;
3670
3671 /* Optimization, skip if this state doesn't accept the character. */
3672 if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c))
3673 continue;
3674
3675 /* Enumerate the intersection set of this state and `accepts'. */
3676 has_intersec = 0;
3677 for (k = 0; k < BITSET_WORDS; ++k)
3678 has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k];
3679 /* And skip if the intersection set is empty. */
3680 if (!has_intersec)
3681 continue;
3682
3683 /* Then check if this state is a subset of `accepts'. */
3684 not_subset = not_consumed = 0;
3685 for (k = 0; k < BITSET_WORDS; ++k)
3686 {
3687 not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k];
3688 not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k];
3689 }
3690
3691 /* If this state isn't a subset of `accepts', create a
3692 new group state, which has the `remains'. */
3693 if (not_subset)
3694 {
3695 bitset_copy (dests_ch[ndests], remains);
3696 bitset_copy (dests_ch[j], intersec);
3697 err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]);
3698 if (BE (err != REG_NOERROR, 0))
3699 goto error_return;
3700 ++ndests;
3701 }
3702
3703 /* Put the position in the current group. */
3704 result = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]);
3705 if (BE (result < 0, 0))
3706 goto error_return;
3707
3708 /* If all characters are consumed, go to next node. */
3709 if (!not_consumed)
3710 break;
3711 }
3712 /* Some characters remain, create a new group. */
3713 if (j == ndests)
3714 {
3715 bitset_copy (dests_ch[ndests], accepts);
3716 err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]);
3717 if (BE (err != REG_NOERROR, 0))
3718 goto error_return;
3719 ++ndests;
3720 bitset_empty (accepts);
3721 }
3722 }
3723 return ndests;
3724 error_return:
3725 for (j = 0; j < ndests; ++j)
3726 re_node_set_free (dests_node + j);
3727 return -1;
3728}
3729
3730#ifdef RE_ENABLE_I18N
3731/* Check how many bytes the node `dfa->nodes[node_idx]' accepts.
3732 Return the number of the bytes the node accepts.
3733 STR_IDX is the current index of the input string.
3734
3735 This function handles the nodes which can accept one character, or
3736 one collating element like '.', '[a-z]', opposite to the other nodes
3737 can only accept one byte. */
3738
3739static int
3740internal_function
3741check_node_accept_bytes (const re_dfa_t *dfa, int node_idx,
3742 const re_string_t *input, int str_idx)
3743{
3744 const re_token_t *node = dfa->nodes + node_idx;
3745 int char_len, elem_len;
3746 int i;
3747 wint_t wc;
3748
3749 if (BE (node->type == OP_UTF8_PERIOD, 0))
3750 {
3751 unsigned char c = re_string_byte_at (input, str_idx), d;
3752 if (BE (c < 0xc2, 1))
3753 return 0;
3754
3755 if (str_idx + 2 > input->len)
3756 return 0;
3757
3758 d = re_string_byte_at (input, str_idx + 1);
3759 if (c < 0xe0)
3760 return (d < 0x80 || d > 0xbf) ? 0 : 2;
3761 else if (c < 0xf0)
3762 {
3763 char_len = 3;
3764 if (c == 0xe0 && d < 0xa0)
3765 return 0;
3766 }
3767 else if (c < 0xf8)
3768 {
3769 char_len = 4;
3770 if (c == 0xf0 && d < 0x90)
3771 return 0;
3772 }
3773 else if (c < 0xfc)
3774 {
3775 char_len = 5;
3776 if (c == 0xf8 && d < 0x88)
3777 return 0;
3778 }
3779 else if (c < 0xfe)
3780 {
3781 char_len = 6;
3782 if (c == 0xfc && d < 0x84)
3783 return 0;
3784 }
3785 else
3786 return 0;
3787
3788 if (str_idx + char_len > input->len)
3789 return 0;
3790
3791 for (i = 1; i < char_len; ++i)
3792 {
3793 d = re_string_byte_at (input, str_idx + i);
3794 if (d < 0x80 || d > 0xbf)
3795 return 0;
3796 }
3797 return char_len;
3798 }
3799
3800 char_len = re_string_char_size_at (input, str_idx);
3801 if (node->type == OP_PERIOD)
3802 {
3803 if (char_len <= 1)
3804 return 0;
3805 /* FIXME: I don't think this if is needed, as both '\n'
3806 and '\0' are char_len == 1. */
3807 /* '.' accepts any one character except the following two cases. */
3808 if ((!(dfa->syntax & RE_DOT_NEWLINE) &&
3809 re_string_byte_at (input, str_idx) == '\n') ||
3810 ((dfa->syntax & RE_DOT_NOT_NULL) &&
3811 re_string_byte_at (input, str_idx) == '\0'))
3812 return 0;
3813 return char_len;
3814 }
3815
3816 elem_len = re_string_elem_size_at (input, str_idx);
3817 wc = __btowc(*(input->mbs+str_idx));
3818 if (((elem_len <= 1 && char_len <= 1) || char_len == 0) && (wc != WEOF && wc < SBC_MAX))
3819 return 0;
3820
3821 if (node->type == COMPLEX_BRACKET)
3822 {
3823 const re_charset_t *cset = node->opr.mbcset;
3824# ifdef _LIBC
3825 const unsigned char *pin
3826 = ((const unsigned char *) re_string_get_buffer (input) + str_idx);
3827 int j;
3828 uint32_t nrules;
3829# endif /* _LIBC */
3830 int match_len = 0;
3831 wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars)
3832 ? re_string_wchar_at (input, str_idx) : 0);
3833
3834 /* match with multibyte character? */
3835 for (i = 0; i < cset->nmbchars; ++i)
3836 if (wc == cset->mbchars[i])
3837 {
3838 match_len = char_len;
3839 goto check_node_accept_bytes_match;
3840 }
3841 /* match with character_class? */
3842 for (i = 0; i < cset->nchar_classes; ++i)
3843 {
3844 wctype_t wt = cset->char_classes[i];
3845 if (__iswctype (wc, wt))
3846 {
3847 match_len = char_len;
3848 goto check_node_accept_bytes_match;
3849 }
3850 }
3851
3852# ifdef _LIBC
3853 nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
3854 if (nrules != 0)
3855 {
3856 unsigned int in_collseq = 0;
3857 const int32_t *table, *indirect;
3858 const unsigned char *weights, *extra;
3859 const char *collseqwc;
3860 /* This #include defines a local function! */
3861# include <locale/weight.h>
3862
3863 /* match with collating_symbol? */
3864 if (cset->ncoll_syms)
3865 extra = (const unsigned char *)
3866 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
3867 for (i = 0; i < cset->ncoll_syms; ++i)
3868 {
3869 const unsigned char *coll_sym = extra + cset->coll_syms[i];
3870 /* Compare the length of input collating element and
3871 the length of current collating element. */
3872 if (*coll_sym != elem_len)
3873 continue;
3874 /* Compare each bytes. */
3875 for (j = 0; j < *coll_sym; j++)
3876 if (pin[j] != coll_sym[1 + j])
3877 break;
3878 if (j == *coll_sym)
3879 {
3880 /* Match if every bytes is equal. */
3881 match_len = j;
3882 goto check_node_accept_bytes_match;
3883 }
3884 }
3885
3886 if (cset->nranges)
3887 {
3888 if (elem_len <= char_len)
3889 {
3890 collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
3891 in_collseq = __collseq_table_lookup (collseqwc, wc);
3892 }
3893 else
3894 in_collseq = find_collation_sequence_value (pin, elem_len);
3895 }
3896 /* match with range expression? */
3897 for (i = 0; i < cset->nranges; ++i)
3898 if (cset->range_starts[i] <= in_collseq
3899 && in_collseq <= cset->range_ends[i])
3900 {
3901 match_len = elem_len;
3902 goto check_node_accept_bytes_match;
3903 }
3904
3905 /* match with equivalence_class? */
3906 if (cset->nequiv_classes)
3907 {
3908 const unsigned char *cp = pin;
3909 table = (const int32_t *)
3910 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
3911 weights = (const unsigned char *)
3912 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
3913 extra = (const unsigned char *)
3914 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
3915 indirect = (const int32_t *)
3916 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
3917 int32_t idx = findidx (&cp);
3918 if (idx > 0)
3919 for (i = 0; i < cset->nequiv_classes; ++i)
3920 {
3921 int32_t equiv_class_idx = cset->equiv_classes[i];
3922 size_t weight_len = weights[idx & 0xffffff];
3923 if (weight_len == weights[equiv_class_idx & 0xffffff]
3924 && (idx >> 24) == (equiv_class_idx >> 24))
3925 {
3926 int cnt = 0;
3927
3928 idx &= 0xffffff;
3929 equiv_class_idx &= 0xffffff;
3930
3931 while (cnt <= weight_len
3932 && (weights[equiv_class_idx + 1 + cnt]
3933 == weights[idx + 1 + cnt]))
3934 ++cnt;
3935 if (cnt > weight_len)
3936 {
3937 match_len = elem_len;
3938 goto check_node_accept_bytes_match;
3939 }
3940 }
3941 }
3942 }
3943 }
3944 else
3945# endif /* _LIBC */
3946 {
3947 /* match with range expression? */
3948#if __GNUC__ >= 2
3949 wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'};
3950#else
3951 wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
3952 cmp_buf[2] = wc;
3953#endif
3954 for (i = 0; i < cset->nranges; ++i)
3955 {
3956 cmp_buf[0] = cset->range_starts[i];
3957 cmp_buf[4] = cset->range_ends[i];
3958 if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
3959 && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
3960 {
3961 match_len = char_len;
3962 goto check_node_accept_bytes_match;
3963 }
3964 }
3965 }
3966 check_node_accept_bytes_match:
3967 if (!cset->non_match)
3968 return match_len;
3969 else
3970 {
3971 if (match_len > 0)
3972 return 0;
3973 else
3974 return (elem_len > char_len) ? elem_len : char_len;
3975 }
3976 }
3977 return 0;
3978}
3979
3980# ifdef _LIBC
3981static unsigned int
3982internal_function
3983find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len)
3984{
3985 uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
3986 if (nrules == 0)
3987 {
3988 if (mbs_len == 1)
3989 {
3990 /* No valid character. Match it as a single byte character. */
3991 const unsigned char *collseq = (const unsigned char *)
3992 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
3993 return collseq[mbs[0]];
3994 }
3995 return UINT_MAX;
3996 }
3997 else
3998 {
3999 int32_t idx;
4000 const unsigned char *extra = (const unsigned char *)
4001 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
4002 int32_t extrasize = (const unsigned char *)
4003 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra;
4004
4005 for (idx = 0; idx < extrasize;)
4006 {
4007 int mbs_cnt, found = 0;
4008 int32_t elem_mbs_len;
4009 /* Skip the name of collating element name. */
4010 idx = idx + extra[idx] + 1;
4011 elem_mbs_len = extra[idx++];
4012 if (mbs_len == elem_mbs_len)
4013 {
4014 for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt)
4015 if (extra[idx + mbs_cnt] != mbs[mbs_cnt])
4016 break;
4017 if (mbs_cnt == elem_mbs_len)
4018 /* Found the entry. */
4019 found = 1;
4020 }
4021 /* Skip the byte sequence of the collating element. */
4022 idx += elem_mbs_len;
4023 /* Adjust for the alignment. */
4024 idx = (idx + 3) & ~3;
4025 /* Skip the collation sequence value. */
4026 idx += sizeof (uint32_t);
4027 /* Skip the wide char sequence of the collating element. */
4028 idx = idx + sizeof (uint32_t) * (extra[idx] + 1);
4029 /* If we found the entry, return the sequence value. */
4030 if (found)
4031 return *(uint32_t *) (extra + idx);
4032 /* Skip the collation sequence value. */
4033 idx += sizeof (uint32_t);
4034 }
4035 return UINT_MAX;
4036 }
4037}
4038# endif /* _LIBC */
4039#endif /* RE_ENABLE_I18N */
4040
4041/* Check whether the node accepts the byte which is IDX-th
4042 byte of the INPUT. */
4043
4044static int
4045internal_function
4046check_node_accept (const re_match_context_t *mctx, const re_token_t *node,
4047 int idx)
4048{
4049 unsigned char ch;
4050 ch = re_string_byte_at (&mctx->input, idx);
4051 switch (node->type)
4052 {
4053 case CHARACTER:
4054 if (node->opr.c != ch)
4055 return 0;
4056 break;
4057
4058 case SIMPLE_BRACKET:
4059 if (!bitset_contain (node->opr.sbcset, ch))
4060 return 0;
4061 break;
4062
4063#ifdef RE_ENABLE_I18N
4064 case OP_UTF8_PERIOD:
4065 if (ch >= 0x80)
4066 return 0;
4067 /* FALLTHROUGH */
4068#endif
4069 case OP_PERIOD:
4070 if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE))
4071 || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL)))
4072 return 0;
4073 break;
4074
4075 default:
4076 return 0;
4077 }
4078
4079 if (node->constraint)
4080 {
4081 /* The node has constraints. Check whether the current context
4082 satisfies the constraints. */
4083 unsigned int context = re_string_context_at (&mctx->input, idx,
4084 mctx->eflags);
4085 if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
4086 return 0;
4087 }
4088
4089 return 1;
4090}
4091
4092/* Extend the buffers, if the buffers have run out. */
4093
4094static reg_errcode_t
4095internal_function
4096extend_buffers (re_match_context_t *mctx)
4097{
4098 reg_errcode_t ret;
4099 re_string_t *pstr = &mctx->input;
4100
4101 /* Avoid overflow. */
4102 if (BE (INT_MAX / 2 / sizeof (re_dfastate_t *) <= pstr->bufs_len, 0))
4103 return REG_ESPACE;
4104
4105 /* Double the lengthes of the buffers. */
4106 ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
4107 if (BE (ret != REG_NOERROR, 0))
4108 return ret;
4109
4110 if (mctx->state_log != NULL)
4111 {
4112 /* And double the length of state_log. */
4113 /* XXX We have no indication of the size of this buffer. If this
4114 allocation fail we have no indication that the state_log array
4115 does not have the right size. */
4116 re_dfastate_t **new_array = re_realloc (mctx->state_log, re_dfastate_t *,
4117 pstr->bufs_len + 1);
4118 if (BE (new_array == NULL, 0))
4119 return REG_ESPACE;
4120 mctx->state_log = new_array;
4121 }
4122
4123 /* Then reconstruct the buffers. */
4124 if (pstr->icase)
4125 {
4126#ifdef RE_ENABLE_I18N
4127 if (pstr->mb_cur_max > 1)
4128 {
4129 ret = build_wcs_upper_buffer (pstr);
4130 if (BE (ret != REG_NOERROR, 0))
4131 return ret;
4132 }
4133 else
4134#endif /* RE_ENABLE_I18N */
4135 build_upper_buffer (pstr);
4136 }
4137 else
4138 {
4139#ifdef RE_ENABLE_I18N
4140 if (pstr->mb_cur_max > 1)
4141 build_wcs_buffer (pstr);
4142 else
4143#endif /* RE_ENABLE_I18N */
4144 {
4145 if (pstr->trans != NULL)
4146 re_string_translate_buffer (pstr);
4147 }
4148 }
4149 return REG_NOERROR;
4150}
4151
4152
4153/* Functions for matching context. */
4154
4155/* Initialize MCTX. */
4156
4157static reg_errcode_t
4158internal_function
4159match_ctx_init (re_match_context_t *mctx, int eflags, int n)
4160{
4161 mctx->eflags = eflags;
4162 mctx->match_last = -1;
4163 if (n > 0)
4164 {
4165 mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n);
4166 mctx->sub_tops = re_malloc (re_sub_match_top_t *, n);
4167 if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0))
4168 return REG_ESPACE;
4169 }
4170 /* Already zero-ed by the caller.
4171 else
4172 mctx->bkref_ents = NULL;
4173 mctx->nbkref_ents = 0;
4174 mctx->nsub_tops = 0; */
4175 mctx->abkref_ents = n;
4176 mctx->max_mb_elem_len = 1;
4177 mctx->asub_tops = n;
4178 return REG_NOERROR;
4179}
4180
4181/* Clean the entries which depend on the current input in MCTX.
4182 This function must be invoked when the matcher changes the start index
4183 of the input, or changes the input string. */
4184
4185static void
4186internal_function
4187match_ctx_clean (re_match_context_t *mctx)
4188{
4189 int st_idx;
4190 for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx)
4191 {
4192 int sl_idx;
4193 re_sub_match_top_t *top = mctx->sub_tops[st_idx];
4194 for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx)
4195 {
4196 re_sub_match_last_t *last = top->lasts[sl_idx];
4197 re_free (last->path.array);
4198 re_free (last);
4199 }
4200 re_free (top->lasts);
4201 if (top->path)
4202 {
4203 re_free (top->path->array);
4204 re_free (top->path);
4205 }
4206 free (top);
4207 }
4208
4209 mctx->nsub_tops = 0;
4210 mctx->nbkref_ents = 0;
4211}
4212
4213/* Free all the memory associated with MCTX. */
4214
4215static void
4216internal_function
4217match_ctx_free (re_match_context_t *mctx)
4218{
4219 /* First, free all the memory associated with MCTX->SUB_TOPS. */
4220 match_ctx_clean (mctx);
4221 re_free (mctx->sub_tops);
4222 re_free (mctx->bkref_ents);
4223}
4224
4225/* Add a new backreference entry to MCTX.
4226 Note that we assume that caller never call this function with duplicate
4227 entry, and call with STR_IDX which isn't smaller than any existing entry.
4228*/
4229
4230static reg_errcode_t
4231internal_function
4232match_ctx_add_entry (re_match_context_t *mctx, int node, int str_idx, int from,
4233 int to)
4234{
4235 if (mctx->nbkref_ents >= mctx->abkref_ents)
4236 {
4237 struct re_backref_cache_entry* new_entry;
4238 new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry,
4239 mctx->abkref_ents * 2);
4240 if (BE (new_entry == NULL, 0))
4241 {
4242 re_free (mctx->bkref_ents);
4243 return REG_ESPACE;
4244 }
4245 mctx->bkref_ents = new_entry;
4246 memset (mctx->bkref_ents + mctx->nbkref_ents, '\0',
4247 sizeof (struct re_backref_cache_entry) * mctx->abkref_ents);
4248 mctx->abkref_ents *= 2;
4249 }
4250 if (mctx->nbkref_ents > 0
4251 && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx)
4252 mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1;
4253
4254 mctx->bkref_ents[mctx->nbkref_ents].node = node;
4255 mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx;
4256 mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from;
4257 mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to;
4258
4259 /* This is a cache that saves negative results of check_dst_limits_calc_pos.
4260 If bit N is clear, means that this entry won't epsilon-transition to
4261 an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If
4262 it is set, check_dst_limits_calc_pos_1 will recurse and try to find one
4263 such node.
4264
4265 A backreference does not epsilon-transition unless it is empty, so set
4266 to all zeros if FROM != TO. */
4267 mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map
4268 = (from == to ? ~0 : 0);
4269
4270 mctx->bkref_ents[mctx->nbkref_ents++].more = 0;
4271 if (mctx->max_mb_elem_len < to - from)
4272 mctx->max_mb_elem_len = to - from;
4273 return REG_NOERROR;
4274}
4275
4276/* Search for the first entry which has the same str_idx, or -1 if none is
4277 found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */
4278
4279static int
4280internal_function
4281search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx)
4282{
4283 int left, right, mid, last;
4284 last = right = mctx->nbkref_ents;
4285 for (left = 0; left < right;)
4286 {
4287 mid = (left + right) / 2;
4288 if (mctx->bkref_ents[mid].str_idx < str_idx)
4289 left = mid + 1;
4290 else
4291 right = mid;
4292 }
4293 if (left < last && mctx->bkref_ents[left].str_idx == str_idx)
4294 return left;
4295 else
4296 return -1;
4297}
4298
4299/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches
4300 at STR_IDX. */
4301
4302static reg_errcode_t
4303internal_function
4304match_ctx_add_subtop (re_match_context_t *mctx, int node, int str_idx)
4305{
4306#ifdef DEBUG
4307 assert (mctx->sub_tops != NULL);
4308 assert (mctx->asub_tops > 0);
4309#endif
4310 if (BE (mctx->nsub_tops == mctx->asub_tops, 0))
4311 {
4312 int new_asub_tops = mctx->asub_tops * 2;
4313 re_sub_match_top_t **new_array = re_realloc (mctx->sub_tops,
4314 re_sub_match_top_t *,
4315 new_asub_tops);
4316 if (BE (new_array == NULL, 0))
4317 return REG_ESPACE;
4318 mctx->sub_tops = new_array;
4319 mctx->asub_tops = new_asub_tops;
4320 }
4321 mctx->sub_tops[mctx->nsub_tops] = calloc (1, sizeof (re_sub_match_top_t));
4322 if (BE (mctx->sub_tops[mctx->nsub_tops] == NULL, 0))
4323 return REG_ESPACE;
4324 mctx->sub_tops[mctx->nsub_tops]->node = node;
4325 mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx;
4326 return REG_NOERROR;
4327}
4328
4329/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches
4330 at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */
4331
4332static re_sub_match_last_t *
4333internal_function
4334match_ctx_add_sublast (re_sub_match_top_t *subtop, int node, int str_idx)
4335{
4336 re_sub_match_last_t *new_entry;
4337 if (BE (subtop->nlasts == subtop->alasts, 0))
4338 {
4339 int new_alasts = 2 * subtop->alasts + 1;
4340 re_sub_match_last_t **new_array = re_realloc (subtop->lasts,
4341 re_sub_match_last_t *,
4342 new_alasts);
4343 if (BE (new_array == NULL, 0))
4344 return NULL;
4345 subtop->lasts = new_array;
4346 subtop->alasts = new_alasts;
4347 }
4348 new_entry = calloc (1, sizeof (re_sub_match_last_t));
4349 if (BE (new_entry != NULL, 1))
4350 {
4351 subtop->lasts[subtop->nlasts] = new_entry;
4352 new_entry->node = node;
4353 new_entry->str_idx = str_idx;
4354 ++subtop->nlasts;
4355 }
4356 return new_entry;
4357}
4358
4359static void
4360internal_function
4361sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
4362 re_dfastate_t **limited_sts, int last_node, int last_str_idx)
4363{
4364 sctx->sifted_states = sifted_sts;
4365 sctx->limited_states = limited_sts;
4366 sctx->last_node = last_node;
4367 sctx->last_str_idx = last_str_idx;
4368 re_node_set_init_empty (&sctx->limits);
4369}
diff --git a/win32/resources/COPYING_CCBYSA3 b/win32/resources/COPYING_CCBYSA3
new file mode 100644
index 000000000..fc45d7818
--- /dev/null
+++ b/win32/resources/COPYING_CCBYSA3
@@ -0,0 +1,7 @@
1This work is licenced under the Creative Commons Attribution-Share Alike 3.0
2United States License. To view a copy of this licence, visit
3http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative
4Commons, 171 Second Street, Suite 300, San Francisco, California 94105, USA.
5
6When attributing the artwork, using "GNOME Project" is enough.
7Please link to http://www.gnome.org where available.
diff --git a/win32/resources/Kbuild.src b/win32/resources/Kbuild.src
new file mode 100644
index 000000000..d056a5964
--- /dev/null
+++ b/win32/resources/Kbuild.src
@@ -0,0 +1,29 @@
1# Makefile for busybox
2#
3# Copyright (C) 2018 by R M Yorston <rmy@pobox.com>
4#
5# Licensed under GPLv2, see file LICENSE in this source tree.
6
7obj-y :=
8
9obj-$(CONFIG_FEATURE_RESOURCES) += resources.o
10
11# return commit level if available or 0
12bb_level = $(or $(word 2,$(subst -, ,$1)),0)
13
14WRFLAGS := -D"BB_VER=$(BB_VER)" \
15 -D"BB_VERSION=$(VERSION)" -D"BB_PATCHLEVEL=$(PATCHLEVEL)" \
16 -D"BB_SUBLEVEL=$(SUBLEVEL)" \
17 -D"BB_EXTRAVERSION=$(call bb_level,$(EXTRAVERSION))" \
18 --include-dir=$(objtree)/include --include-dir=$(objtree)/win32/resources
19
20quiet_cmd_windres = WINDRES $@
21 cmd_windres = $(WINDRES) $(WRFLAGS) $< $@
22
23%.o: %.rc FORCE
24 $(call if_changed,windres)
25
26win32/resources/resources.o: win32/resources/resources.rc .config
27win32/resources/resources.o: win32/resources/aterm.ico win32/resources/sterm.ico
28win32/resources/resources.o: win32/resources/utf8.manifest
29win32/resources/resources.o: win32/resources/app.manifest
diff --git a/win32/resources/README b/win32/resources/README
new file mode 100644
index 000000000..33a245386
--- /dev/null
+++ b/win32/resources/README
@@ -0,0 +1,9 @@
1The icons are based on those for GNOME terminal in the Adwaita theme.
2
3They were generated by importing the 16x16, 32x32 and 48x48 PNG files
4into GIMP as separate layers then exporting as a single .ico file.
5
6The original files are dual-licensed under either the GNU LGPL v3 or
7Creative Commons Attribution-Share Alike 3.0 United States License.
8
9The .ico files are licensed under the latter.
diff --git a/win32/resources/app.manifest b/win32/resources/app.manifest
new file mode 100644
index 000000000..5e76b7b8e
--- /dev/null
+++ b/win32/resources/app.manifest
@@ -0,0 +1,24 @@
1<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
3 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
4 <security>
5 <requestedPrivileges>
6 <requestedExecutionLevel level="asInvoker"/>
7 </requestedPrivileges>
8 </security>
9 </trustInfo>
10 <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
11 <application>
12 <!--The ID below indicates application support for Windows Vista -->
13 <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
14 <!--The ID below indicates application support for Windows 7 -->
15 <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
16 <!--The ID below indicates application support for Windows 8 -->
17 <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
18 <!--The ID below indicates application support for Windows 8.1 -->
19 <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
20 <!--The ID below indicates application support for Windows 10 -->
21 <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
22 </application>
23 </compatibility>
24</assembly>
diff --git a/win32/resources/aterm.ico b/win32/resources/aterm.ico
new file mode 100644
index 000000000..e680216a2
--- /dev/null
+++ b/win32/resources/aterm.ico
Binary files differ
diff --git a/win32/resources/dummy.c b/win32/resources/dummy.c
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/resources/dummy.c
diff --git a/win32/resources/resources.rc b/win32/resources/resources.rc
new file mode 100644
index 000000000..5d06dda3c
--- /dev/null
+++ b/win32/resources/resources.rc
@@ -0,0 +1,45 @@
1#include <autoconf.h>
2#define xstr(s) str(s)
3#define str(s) #s
4
5#if ENABLE_FEATURE_ICON_ATERM || ENABLE_FEATURE_ICON_ALL
61 ICON "aterm.ico"
7#endif
8#if ENABLE_FEATURE_ICON_STERM || ENABLE_FEATURE_ICON_ALL
92 ICON "sterm.ico"
10#endif
11
12#if ENABLE_FEATURE_VERSIONINFO
131 VERSIONINFO
14FILEVERSION BB_VERSION,BB_PATCHLEVEL,BB_SUBLEVEL,BB_EXTRAVERSION
15PRODUCTVERSION BB_VERSION,BB_PATCHLEVEL,BB_SUBLEVEL,BB_EXTRAVERSION
16BEGIN
17 BLOCK "StringFileInfo"
18 BEGIN
19 BLOCK "080904E4"
20 BEGIN
21 VALUE "CompanyName", "frippery.org"
22 VALUE "FileDescription", "BusyBox multi-call binary"
23 VALUE "FileVersion", xstr(BB_VER)
24 VALUE "InternalName", "busybox"
25 VALUE "LegalCopyright", "(C) 1998-2022 Many authors"
26 VALUE "OriginalFilename", "busybox.exe"
27 VALUE "ProductName", "busybox-w32"
28 VALUE "ProductVersion", xstr(BB_VER)
29 END
30 END
31 BLOCK "VarFileInfo"
32 BEGIN
33 VALUE "Translation", 0x809, 1252
34 END
35END
36#endif
37
38/* Hardcode numeric value for MANIFEST for llvm windres */
39#if ENABLE_FEATURE_UTF8_MANIFEST
401 24 "utf8.manifest"
41#endif
42
43#if ENABLE_FEATURE_APP_MANIFEST
441 24 "app.manifest"
45#endif
diff --git a/win32/resources/sterm.ico b/win32/resources/sterm.ico
new file mode 100644
index 000000000..b9125b34d
--- /dev/null
+++ b/win32/resources/sterm.ico
Binary files differ
diff --git a/win32/resources/utf8.manifest b/win32/resources/utf8.manifest
new file mode 100644
index 000000000..efe6a3d2f
--- /dev/null
+++ b/win32/resources/utf8.manifest
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
3 <assemblyIdentity type="win32" name="busybox.exe" version="6.0.0.0"/>
4 <application>
5 <windowsSettings>
6 <activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
7 </windowsSettings>
8 </application>
9 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
10 <security>
11 <requestedPrivileges>
12 <requestedExecutionLevel level="asInvoker"/>
13 </requestedPrivileges>
14 </security>
15 </trustInfo>
16 <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
17 <application>
18 <!--The ID below indicates application support for Windows Vista -->
19 <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
20 <!--The ID below indicates application support for Windows 7 -->
21 <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
22 <!--The ID below indicates application support for Windows 8 -->
23 <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
24 <!--The ID below indicates application support for Windows 8.1 -->
25 <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
26 <!--The ID below indicates application support for Windows 10 -->
27 <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
28 </application>
29 </compatibility>
30</assembly>
diff --git a/win32/sched.h b/win32/sched.h
new file mode 100644
index 000000000..128bfe698
--- /dev/null
+++ b/win32/sched.h
@@ -0,0 +1 @@
static inline void sched_yield(void) {}
diff --git a/win32/select.c b/win32/select.c
new file mode 100644
index 000000000..2be221ac8
--- /dev/null
+++ b/win32/select.c
@@ -0,0 +1,592 @@
1/* Emulation for select(2)
2 Contributed by Paolo Bonzini.
3
4 Copyright 2008-2021 Free Software Foundation, Inc.
5
6 This file is part of gnulib.
7
8 This file is free software: you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as
10 published by the Free Software Foundation; either version 2.1 of the
11 License, or (at your option) any later version.
12
13 This file is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with this program. If not, see <https://www.gnu.org/licenses/>. */
20
21#include "libbb.h"
22
23/* Specification. */
24#include <sys/select.h>
25
26#if defined _WIN32 && ! defined __CYGWIN__
27/* Native Windows. */
28
29#include <malloc.h>
30#include <assert.h>
31#include <sys/types.h>
32#include <errno.h>
33#include <limits.h>
34
35#include <winsock2.h>
36#include <windows.h>
37#include <io.h>
38#include <stdio.h>
39#include <conio.h>
40#include <time.h>
41
42/* Get the overridden 'struct timeval'. */
43
44#undef select
45
46/* Don't assume that UNICODE is not defined. */
47#undef GetModuleHandle
48#define GetModuleHandle GetModuleHandleA
49#undef PeekConsoleInput
50#define PeekConsoleInput PeekConsoleInputA
51#undef CreateEvent
52#define CreateEvent CreateEventA
53#undef PeekMessage
54#define PeekMessage PeekMessageA
55#undef DispatchMessage
56#define DispatchMessage DispatchMessageA
57
58/* Avoid warnings from gcc -Wcast-function-type. */
59#define GetProcAddress \
60 (void *) GetProcAddress
61
62struct bitset {
63 unsigned char in[FD_SETSIZE / CHAR_BIT];
64 unsigned char out[FD_SETSIZE / CHAR_BIT];
65};
66
67/* Declare data structures for ntdll functions. */
68typedef struct _FILE_PIPE_LOCAL_INFORMATION {
69 ULONG NamedPipeType;
70 ULONG NamedPipeConfiguration;
71 ULONG MaximumInstances;
72 ULONG CurrentInstances;
73 ULONG InboundQuota;
74 ULONG ReadDataAvailable;
75 ULONG OutboundQuota;
76 ULONG WriteQuotaAvailable;
77 ULONG NamedPipeState;
78 ULONG NamedPipeEnd;
79} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
80
81typedef struct _IO_STATUS_BLOCK
82{
83 union {
84 DWORD Status;
85 PVOID Pointer;
86 } u;
87 ULONG_PTR Information;
88} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
89
90typedef enum _FILE_INFORMATION_CLASS {
91 FilePipeLocalInformation = 24
92} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
93
94typedef DWORD (WINAPI *PNtQueryInformationFile)
95 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
96
97#ifndef PIPE_BUF
98#define PIPE_BUF 512
99#endif
100
101static BOOL IsConsoleHandle (HANDLE h)
102{
103 DWORD mode;
104 return GetConsoleMode (h, &mode) != 0;
105}
106
107static BOOL
108IsSocketHandle (HANDLE h)
109{
110 WSANETWORKEVENTS ev;
111
112 if (IsConsoleHandle (h))
113 return FALSE;
114
115 /* Under Wine, it seems that getsockopt returns 0 for pipes too.
116 WSAEnumNetworkEvents instead distinguishes the two correctly. */
117 ev.lNetworkEvents = 0xDEADBEEF;
118 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
119 return ev.lNetworkEvents != 0xDEADBEEF;
120}
121
122/* Compute output fd_sets for libc descriptor FD (whose Windows handle is
123 H). */
124
125static int
126windows_poll_handle (HANDLE h, int fd,
127 struct bitset *rbits,
128 struct bitset *wbits,
129 struct bitset *xbits)
130{
131 BOOL read, write, except;
132 int i, ret;
133 INPUT_RECORD *irbuffer;
134 DWORD avail, nbuffer;
135 BOOL bRet;
136 IO_STATUS_BLOCK iosb;
137 FILE_PIPE_LOCAL_INFORMATION fpli;
138 static PNtQueryInformationFile NtQueryInformationFile;
139 static BOOL once_only;
140
141 read = write = except = FALSE;
142 switch (GetFileType (h))
143 {
144 case FILE_TYPE_DISK:
145 read = TRUE;
146 write = TRUE;
147 break;
148
149 case FILE_TYPE_PIPE:
150 if (!once_only)
151 {
152 NtQueryInformationFile = (PNtQueryInformationFile)
153 GetProcAddress (GetModuleHandle ("ntdll.dll"),
154 "NtQueryInformationFile");
155 once_only = TRUE;
156 }
157
158 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
159 {
160 if (avail)
161 read = TRUE;
162 }
163 else if (GetLastError () == ERROR_BROKEN_PIPE)
164 read = TRUE;
165
166 else
167 {
168 /* It was the write-end of the pipe. Check if it is writable.
169 If NtQueryInformationFile fails, optimistically assume the pipe is
170 writable. This could happen on Windows 9x, where
171 NtQueryInformationFile is not available, or if we inherit a pipe
172 that doesn't permit FILE_READ_ATTRIBUTES access on the write end
173 (I think this should not happen since Windows XP SP2; WINE seems
174 fine too). Otherwise, ensure that enough space is available for
175 atomic writes. */
176 memset (&iosb, 0, sizeof (iosb));
177 memset (&fpli, 0, sizeof (fpli));
178
179 if (!NtQueryInformationFile
180 || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
181 FilePipeLocalInformation)
182 || fpli.WriteQuotaAvailable >= PIPE_BUF
183 || (fpli.OutboundQuota < PIPE_BUF &&
184 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
185 write = TRUE;
186 }
187 break;
188
189 case FILE_TYPE_CHAR:
190 write = TRUE;
191 if (!(rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
192 break;
193
194 ret = WaitForSingleObject (h, 0);
195 if (ret == WAIT_OBJECT_0)
196 {
197 if (!IsConsoleHandle (h))
198 {
199 read = TRUE;
200 break;
201 }
202
203 nbuffer = avail = 0;
204 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
205
206 /* Screen buffers handles are filtered earlier. */
207 assert (bRet);
208 if (nbuffer == 0)
209 {
210 except = TRUE;
211 break;
212 }
213
214 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
215 bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
216 if (!bRet || avail == 0)
217 {
218 except = TRUE;
219 break;
220 }
221
222 for (i = 0; i < avail; i++)
223 if (irbuffer[i].EventType == KEY_EVENT &&
224 irbuffer[i].Event.KeyEvent.bKeyDown)
225 read = TRUE;
226 }
227 break;
228
229 default:
230 ret = WaitForSingleObject (h, 0);
231 write = TRUE;
232 if (ret == WAIT_OBJECT_0)
233 read = TRUE;
234
235 break;
236 }
237
238 ret = 0;
239 if (read && (rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
240 {
241 rbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
242 ret++;
243 }
244
245 if (write && (wbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
246 {
247 wbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
248 ret++;
249 }
250
251 if (except && (xbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
252 {
253 xbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
254 ret++;
255 }
256
257 return ret;
258}
259
260int
261mingw_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
262 struct timeval *timeout)
263#undef timeval
264{
265 static struct timeval tv0;
266 static HANDLE hEvent;
267 HANDLE h, handle_array[FD_SETSIZE + 2];
268 fd_set handle_rfds, handle_wfds, handle_xfds;
269 struct bitset rbits, wbits, xbits;
270 unsigned char anyfds_in[FD_SETSIZE / CHAR_BIT];
271 DWORD ret, wait_timeout, nhandles, nsock, nbuffer;
272 MSG msg;
273 int i, fd, rc;
274 clock_t tend = 0;
275
276 if (nfds > FD_SETSIZE)
277 nfds = FD_SETSIZE;
278
279 if (!timeout)
280 wait_timeout = INFINITE;
281 else
282 {
283 wait_timeout = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
284
285 /* select is also used as a portable usleep. */
286 if (!rfds && !wfds && !xfds)
287 {
288 Sleep (wait_timeout);
289 return 0;
290 }
291 }
292
293 if (!hEvent)
294 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
295
296 handle_array[0] = hEvent;
297 nhandles = 1;
298 nsock = 0;
299
300 /* Copy descriptors to bitsets. At the same time, eliminate
301 bits in the "wrong" direction for console input buffers
302 and screen buffers, because screen buffers are waitable
303 and they will block until a character is available. */
304 memset (&rbits, 0, sizeof (rbits));
305 memset (&wbits, 0, sizeof (wbits));
306 memset (&xbits, 0, sizeof (xbits));
307 memset (anyfds_in, 0, sizeof (anyfds_in));
308 if (rfds)
309 for (i = 0; i < rfds->fd_count; i++)
310 {
311 fd = rfds->fd_array[i];
312 h = (HANDLE) _get_osfhandle (fd);
313 if (IsConsoleHandle (h)
314 && !GetNumberOfConsoleInputEvents (h, &nbuffer))
315 continue;
316
317 rbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
318 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
319 }
320 else
321 rfds = (fd_set *) alloca (sizeof (fd_set));
322
323 if (wfds)
324 for (i = 0; i < wfds->fd_count; i++)
325 {
326 fd = wfds->fd_array[i];
327 h = (HANDLE) _get_osfhandle (fd);
328 if (IsConsoleHandle (h)
329 && GetNumberOfConsoleInputEvents (h, &nbuffer))
330 continue;
331
332 wbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
333 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
334 }
335 else
336 wfds = (fd_set *) alloca (sizeof (fd_set));
337
338 if (xfds)
339 for (i = 0; i < xfds->fd_count; i++)
340 {
341 fd = xfds->fd_array[i];
342 xbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
343 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
344 }
345 else
346 xfds = (fd_set *) alloca (sizeof (fd_set));
347
348 /* Zero all the fd_sets, including the application's. */
349 FD_ZERO (rfds);
350 FD_ZERO (wfds);
351 FD_ZERO (xfds);
352 FD_ZERO (&handle_rfds);
353 FD_ZERO (&handle_wfds);
354 FD_ZERO (&handle_xfds);
355
356 /* Classify handles. Create fd sets for sockets, poll the others. */
357 for (i = 0; i < nfds; i++)
358 {
359 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
360 continue;
361
362 h = (HANDLE) _get_osfhandle (i);
363 if (!h)
364 {
365 errno = EBADF;
366 return -1;
367 }
368
369 if (IsSocketHandle (h))
370 {
371 int requested = FD_CLOSE;
372
373 /* See above; socket handles are mapped onto select, but we
374 need to map descriptors to handles. */
375 if (rbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
376 {
377 requested |= FD_READ | FD_ACCEPT;
378 FD_SET ((SOCKET) h, rfds);
379 FD_SET ((SOCKET) h, &handle_rfds);
380 }
381 if (wbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
382 {
383 requested |= FD_WRITE | FD_CONNECT;
384 FD_SET ((SOCKET) h, wfds);
385 FD_SET ((SOCKET) h, &handle_wfds);
386 }
387 if (xbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
388 {
389 requested |= FD_OOB;
390 FD_SET ((SOCKET) h, xfds);
391 FD_SET ((SOCKET) h, &handle_xfds);
392 }
393
394 WSAEventSelect ((SOCKET) h, hEvent, requested);
395 nsock++;
396 }
397 else
398 {
399 handle_array[nhandles++] = h;
400
401 /* Poll now. If we get an event, do not wait below. */
402 if (wait_timeout != 0
403 && windows_poll_handle (h, i, &rbits, &wbits, &xbits))
404 wait_timeout = 0;
405 }
406 }
407
408 /* Place a sentinel at the end of the array. */
409 handle_array[nhandles] = NULL;
410
411 /* When will the waiting period expire? */
412 if (wait_timeout != INFINITE)
413 tend = clock () + wait_timeout;
414
415restart:
416 if (wait_timeout == 0 || nsock == 0)
417 rc = 0;
418 else
419 {
420 /* See if we need to wait in the loop below. If any select is ready,
421 do MsgWaitForMultipleObjects anyway to dispatch messages, but
422 no need to call select again. */
423 rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
424 if (rc == 0)
425 {
426 /* Restore the fd_sets for the other select we do below. */
427 memcpy (&handle_rfds, rfds, sizeof (fd_set));
428 memcpy (&handle_wfds, wfds, sizeof (fd_set));
429 memcpy (&handle_xfds, xfds, sizeof (fd_set));
430 }
431 else
432 wait_timeout = 0;
433 }
434
435 /* How much is left to wait? */
436 if (wait_timeout != INFINITE)
437 {
438 clock_t tnow = clock ();
439 if (tend >= tnow)
440 wait_timeout = tend - tnow;
441 else
442 wait_timeout = 0;
443 }
444
445 for (;;)
446 {
447 ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
448 wait_timeout, QS_ALLINPUT);
449
450 if (ret == WAIT_OBJECT_0 + nhandles)
451 {
452 /* new input of some other kind */
453 BOOL bRet;
454 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
455 {
456 TranslateMessage (&msg);
457 DispatchMessage (&msg);
458 }
459 }
460 else
461 break;
462 }
463
464 /* If we haven't done it yet, check the status of the sockets. */
465 if (rc == 0 && nsock > 0)
466 rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
467
468 if (nhandles > 1)
469 {
470 /* Count results that are not counted in the return value of select. */
471 nhandles = 1;
472 for (i = 0; i < nfds; i++)
473 {
474 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
475 continue;
476
477 h = (HANDLE) _get_osfhandle (i);
478 if (h == handle_array[nhandles])
479 {
480 /* Not a socket. */
481 nhandles++;
482 windows_poll_handle (h, i, &rbits, &wbits, &xbits);
483 if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
484 || wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
485 || xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
486 rc++;
487 }
488 }
489
490 if (rc == 0
491 && (wait_timeout == INFINITE
492 /* If NHANDLES > 1, but no bits are set, it means we've
493 been told incorrectly that some handle was signaled.
494 This happens with anonymous pipes, which always cause
495 MsgWaitForMultipleObjects to exit immediately, but no
496 data is found ready to be read by windows_poll_handle.
497 To avoid a total failure (whereby we return zero and
498 don't wait at all), let's poll in a more busy loop. */
499 || (wait_timeout != 0 && nhandles > 1)))
500 {
501 /* Sleep 1 millisecond to avoid busy wait and retry with the
502 original fd_sets. */
503 memcpy (&handle_rfds, rfds, sizeof (fd_set));
504 memcpy (&handle_wfds, wfds, sizeof (fd_set));
505 memcpy (&handle_xfds, xfds, sizeof (fd_set));
506 SleepEx (1, TRUE);
507 goto restart;
508 }
509 if (timeout && wait_timeout == 0 && rc == 0)
510 timeout->tv_sec = timeout->tv_usec = 0;
511 }
512
513 /* Now fill in the results. */
514 FD_ZERO (rfds);
515 FD_ZERO (wfds);
516 FD_ZERO (xfds);
517 nhandles = 1;
518 for (i = 0; i < nfds; i++)
519 {
520 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
521 continue;
522
523 h = (HANDLE) _get_osfhandle (i);
524 if (h != handle_array[nhandles])
525 {
526 /* Perform handle->descriptor mapping. */
527 SOCKET s = (SOCKET) h;
528 WSAEventSelect (s, NULL, 0);
529 if (FD_ISSET (s, &handle_rfds))
530 FD_SET (i, rfds);
531 if (FD_ISSET (s, &handle_wfds))
532 FD_SET (i, wfds);
533 if (FD_ISSET (s, &handle_xfds))
534 FD_SET (i, xfds);
535 }
536 else
537 {
538 /* Not a socket. */
539 nhandles++;
540 if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
541 FD_SET (i, rfds);
542 if (wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
543 FD_SET (i, wfds);
544 if (xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
545 FD_SET (i, xfds);
546 }
547 }
548
549 return rc;
550}
551
552#else /* ! Native Windows. */
553
554#include <stddef.h> /* NULL */
555#include <errno.h>
556#include <unistd.h>
557
558#undef select
559
560int
561rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
562 struct timeval *timeout)
563{
564 int i;
565
566 /* FreeBSD 8.2 has a bug: it does not always detect invalid fds. */
567 if (nfds < 0 || nfds > FD_SETSIZE)
568 {
569 errno = EINVAL;
570 return -1;
571 }
572 for (i = 0; i < nfds; i++)
573 {
574 if (((rfds && FD_ISSET (i, rfds))
575 || (wfds && FD_ISSET (i, wfds))
576 || (xfds && FD_ISSET (i, xfds)))
577 && dup2 (i, i) != i)
578 return -1;
579 }
580
581 /* Interix 3.5 has a bug: it does not support nfds == 0. */
582 if (nfds == 0)
583 {
584 nfds = 1;
585 rfds = NULL;
586 wfds = NULL;
587 xfds = NULL;
588 }
589 return select (nfds, rfds, wfds, xfds, timeout);
590}
591
592#endif
diff --git a/win32/sh_random.c b/win32/sh_random.c
new file mode 100644
index 000000000..10e942e80
--- /dev/null
+++ b/win32/sh_random.c
@@ -0,0 +1,59 @@
1#include "libbb.h"
2#include <ntsecapi.h>
3#include "../shell/random.h"
4
5/*
6 * Obtain a few bytes of random-ish data to initialise the generator.
7 * This is unlikely to be very robust: don't rely on it for
8 * anything that needs to be secure.
9 */
10static void get_entropy(uint32_t state[2])
11{
12#if defined(__MINGW64_VERSION_MAJOR) && \
13 (__MINGW64_VERSION_MAJOR >= 7 || defined(__MINGW64__))
14 if (!RtlGenRandom(state, sizeof(state[0])*2))
15#endif
16 GetSystemTimeAsFileTime((FILETIME *)state);
17
18#if 0
19 {
20 unsigned char *p = (unsigned char *)state;
21 int j;
22
23 for (j=0; j<8; ++j) {
24 fprintf(stderr, "%02x", *p++);
25 if ((j&3) == 3) {
26 fprintf(stderr, " ");
27 }
28 }
29 fprintf(stderr, "\n");
30 }
31#endif
32}
33
34ssize_t get_random_bytes(void *buf, ssize_t count)
35{
36 static random_t rnd;
37 ssize_t save_count = count;
38 uint32_t value;
39 unsigned char *ptr = (unsigned char *)&value;
40
41 if (buf == NULL || count < 0) {
42 errno = EINVAL;
43 return -1;
44 }
45
46 if (UNINITED_RANDOM_T(&rnd)) {
47 uint32_t state[2] = {0, 0};
48
49 get_entropy(state);
50 INIT_RANDOM_T(&rnd, state[0] ? state[0] : 1, state[1]);
51 }
52
53 for (;count > 0; buf+=4, count-=4) {
54 value = full_random(&rnd);
55 memcpy(buf, ptr, count >= 4 ? 4 : count);
56 }
57
58 return save_count;
59}
diff --git a/win32/statfs.c b/win32/statfs.c
new file mode 100644
index 000000000..97b3ce679
--- /dev/null
+++ b/win32/statfs.c
@@ -0,0 +1,70 @@
1#include <sys/statfs.h>
2#include "libbb.h"
3
4/*
5 * Code from libguestfs (with addition of GetVolumeInformation call)
6 */
7int statfs(const char *file, struct statfs *buf)
8{
9 ULONGLONG free_bytes_available; /* for user - similar to bavail */
10 ULONGLONG total_number_of_bytes;
11 ULONGLONG total_number_of_free_bytes; /* for everyone - bfree */
12 DWORD serial, namelen, flags;
13 char fsname[100];
14 struct mntent *mnt;
15 /* Valid filesystem names don't seem to be documented. The following
16 * are present in Wine (dlls/kernel32/volume.c). */
17#define FS_NAMES "NTFS\0FAT\0FAT32\0CDFS\0UDF\0"
18 int fstypes[] = {0, 0x5346544e, 0x4006, 0x4006, 0x9660, 0x15013346};
19
20 if ( (mnt=find_mount_point(file, 0)) == NULL ) {
21 return -1;
22 }
23
24 file = mnt->mnt_dir;
25 if ( !GetDiskFreeSpaceEx(file, (PULARGE_INTEGER) &free_bytes_available,
26 (PULARGE_INTEGER) &total_number_of_bytes,
27 (PULARGE_INTEGER) &total_number_of_free_bytes) ) {
28 errno = err_win_to_posix();
29 return -1;
30 }
31
32 if ( !GetVolumeInformation(file, NULL, 0, &serial, &namelen, &flags,
33 fsname, 100) ) {
34 errno = err_win_to_posix();
35 return -1;
36 }
37
38 memset(buf, 0, sizeof(*buf));
39
40 /* XXX I couldn't determine how to get block size. MSDN has a
41 * unhelpful hard-coded list here:
42 * http://support.microsoft.com/kb/140365
43 * but this depends on the filesystem type, the size of the disk and
44 * the version of Windows. So this code assumes the disk is NTFS
45 * and the version of Windows is >= Win2K.
46 */
47 if (total_number_of_bytes < UINT64_C(16) * 1024 * 1024 * 1024 * 1024)
48 buf->f_bsize = 4096;
49 else if (total_number_of_bytes < UINT64_C(32) * 1024 * 1024 * 1024 * 1024)
50 buf->f_bsize = 8192;
51 else if (total_number_of_bytes < UINT64_C(64) * 1024 * 1024 * 1024 * 1024)
52 buf->f_bsize = 16384;
53 else if (total_number_of_bytes < UINT64_C(128) * 1024 * 1024 * 1024 * 1024)
54 buf->f_bsize = 32768;
55 else
56 buf->f_bsize = 65536;
57
58 buf->f_type = fstypes[index_in_strings(FS_NAMES, fsname)+1];
59 buf->f_frsize = buf->f_bsize;
60 buf->f_blocks = total_number_of_bytes / buf->f_bsize;
61 buf->f_bfree = total_number_of_free_bytes / buf->f_bsize;
62 buf->f_bavail = free_bytes_available / buf->f_bsize;
63 //buf->f_files = 0;
64 //buf->f_ffree = 0;
65 buf->f_fsid = serial;
66 //buf->f_flag = 0;
67 buf->f_namelen = namelen;
68
69 return 0;
70}
diff --git a/win32/strndup.c b/win32/strndup.c
new file mode 100644
index 000000000..4d04609f6
--- /dev/null
+++ b/win32/strndup.c
@@ -0,0 +1,36 @@
1/* A replacement function, for systems that lack strndup.
2
3 Copyright (C) 1996-1998, 2001-2003, 2005-2007, 2009-2020 Free Software
4 Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <https://www.gnu.org/licenses/>. */
18
19#include "libbb.h"
20
21#include <string.h>
22
23#include <stdlib.h>
24
25char *
26strndup (char const *s, size_t n)
27{
28 size_t len = strnlen (s, n);
29 char *new = malloc (len + 1);
30
31 if (new == NULL)
32 return NULL;
33
34 new[len] = '\0';
35 return memcpy (new, s, len);
36}
diff --git a/win32/strptime.c b/win32/strptime.c
new file mode 100644
index 000000000..3205b95a2
--- /dev/null
+++ b/win32/strptime.c
@@ -0,0 +1,603 @@
1/* Copyright (C) 2002, 2004-2005, 2007, 2009-2020 Free Software Foundation,
2 Inc.
3 This file is part of the GNU C Library.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, see <https://www.gnu.org/licenses/>. */
17
18/*
19 * File from gnulib (https://www.gnu.org/software/gnulib/), processed with
20 * coan source -U_LIBC -U_NL_CURRENT -UHAVE_TM_GMTOFF strptime.c
21 * and lightly edited.
22 *
23 * A form of support for tm_gmtoff was later restored.
24 */
25
26#include "libbb.h"
27#include <time.h>
28
29#include <assert.h>
30#include <ctype.h>
31#include <limits.h>
32#include <string.h>
33#include <stdbool.h>
34
35
36enum ptime_locale_status { not, loc, raw };
37
38
39
40#define match_char(ch1, ch2) if (ch1 != ch2) return NULL
41/* Oh come on. Get a reasonable compiler. */
42# define match_string(cs1, s2) \
43 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
44/* We intentionally do not use isdigit() for testing because this will
45 lead to problems with the wide character version. */
46#define get_number(from, to, n) \
47 do { \
48 int __n = n; \
49 val = 0; \
50 while (*rp == ' ') \
51 ++rp; \
52 if (*rp < '0' || *rp > '9') \
53 return NULL; \
54 do { \
55 val *= 10; \
56 val += *rp++ - '0'; \
57 } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
58 if (val < from || val > to) \
59 return NULL; \
60 } while (0)
61# define get_alt_number(from, to, n) \
62 /* We don't have the alternate representation. */ \
63 get_number(from, to, n)
64#define recursive(new_fmt) \
65 (*(new_fmt) != '\0' \
66 && (rp = __strptime_internal (rp, (new_fmt), tm, \
67 decided, era_cnt, gmtoff)) != NULL)
68
69
70static char const weekday_name[][10] =
71 {
72 "Sunday", "Monday", "Tuesday", "Wednesday",
73 "Thursday", "Friday", "Saturday"
74 };
75static char const ab_weekday_name[][4] =
76 {
77 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
78 };
79static char const month_name[][10] =
80 {
81 "January", "February", "March", "April", "May", "June",
82 "July", "August", "September", "October", "November", "December"
83 };
84static char const ab_month_name[][4] =
85 {
86 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
87 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
88 };
89# define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
90# define HERE_D_FMT "%m/%d/%y"
91# define HERE_AM_STR "AM"
92# define HERE_PM_STR "PM"
93# define HERE_T_FMT_AMPM "%I:%M:%S %p"
94# define HERE_T_FMT "%H:%M:%S"
95
96static const unsigned short int __mon_yday[2][13] =
97 {
98 /* Normal years. */
99 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
100 /* Leap years. */
101 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
102 };
103
104# define ISSPACE(Ch) isspace (Ch)
105
106
107
108
109#ifndef __isleap
110/* Nonzero if YEAR is a leap year (every 4 years,
111 except every 100th isn't, and every 400th is). */
112# define __isleap(year) \
113 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
114#endif
115
116/* Compute the day of the week. */
117static void
118day_of_the_week (struct tm *tm)
119{
120 /* We know that January 1st 1970 was a Thursday (= 4). Compute the
121 difference between this data in the one on TM and so determine
122 the weekday. */
123 int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
124 int corr_quad = corr_year / 4;
125 int wday = (-473
126 + (365 * (tm->tm_year - 70))
127 + corr_quad
128 - ((corr_quad + (corr_quad < 0)) / 25 - (corr_quad < 0))
129 + ((corr_quad / 25) / 4)
130 + __mon_yday[0][tm->tm_mon]
131 + tm->tm_mday - 1);
132 tm->tm_wday = ((wday % 7) + 7) % 7;
133}
134
135/* Compute the day of the year. */
136static void
137day_of_the_year (struct tm *tm)
138{
139 tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
140 + (tm->tm_mday - 1));
141}
142
143
144static char *
145__strptime_internal (const char *rp, const char *fmt, struct tm *tm,
146 enum ptime_locale_status *decided, int era_cnt,
147 long *gmtoff)
148{
149
150 int cnt;
151 size_t val;
152 int have_I, is_pm;
153 int century, want_century;
154 int want_era;
155 int have_wday, want_xday;
156 int have_yday;
157 int have_mon, have_mday;
158 int have_uweek, have_wweek;
159 int week_no;
160
161 have_I = is_pm = 0;
162 century = -1;
163 want_century = 0;
164 want_era = 0;
165 week_no = 0;
166
167 have_wday = want_xday = have_yday = have_mon = have_mday = have_uweek = 0;
168 have_wweek = 0;
169
170 while (*fmt != '\0')
171 {
172 /* A white space in the format string matches 0 more or white
173 space in the input string. */
174 if (ISSPACE (*fmt))
175 {
176 while (ISSPACE (*rp))
177 ++rp;
178 ++fmt;
179 continue;
180 }
181
182 /* Any character but '%' must be matched by the same character
183 in the input string. */
184 if (*fmt != '%')
185 {
186 match_char (*fmt++, *rp++);
187 continue;
188 }
189
190 ++fmt;
191 /* We need this for handling the 'E' modifier. */
192 start_over:
193
194 switch (*fmt++)
195 {
196 case '%':
197 /* Match the '%' character itself. */
198 match_char ('%', *rp++);
199 break;
200 case 'a':
201 case 'A':
202 /* Match day of week. */
203 for (cnt = 0; cnt < 7; ++cnt)
204 {
205 if (*decided != loc
206 && (match_string (weekday_name[cnt], rp)
207 || match_string (ab_weekday_name[cnt], rp)))
208 {
209 *decided = raw;
210 break;
211 }
212 }
213 if (cnt == 7)
214 /* Does not match a weekday name. */
215 return NULL;
216 tm->tm_wday = cnt;
217 have_wday = 1;
218 break;
219 case 'b':
220 case 'B':
221 case 'h':
222 /* Match month name. */
223 for (cnt = 0; cnt < 12; ++cnt)
224 {
225 if (match_string (month_name[cnt], rp)
226 || match_string (ab_month_name[cnt], rp))
227 {
228 *decided = raw;
229 break;
230 }
231 }
232 if (cnt == 12)
233 /* Does not match a month name. */
234 return NULL;
235 tm->tm_mon = cnt;
236 want_xday = 1;
237 break;
238 case 'c':
239 /* Match locale's date and time format. */
240 if (!recursive (HERE_D_T_FMT))
241 return NULL;
242 want_xday = 1;
243 break;
244 case 'C':
245 /* Match century number. */
246 get_number (0, 99, 2);
247 century = val;
248 want_xday = 1;
249 break;
250 case 'd':
251 case 'e':
252 /* Match day of month. */
253 get_number (1, 31, 2);
254 tm->tm_mday = val;
255 have_mday = 1;
256 want_xday = 1;
257 break;
258 case 'F':
259 if (!recursive ("%Y-%m-%d"))
260 return NULL;
261 want_xday = 1;
262 break;
263 case 'x':
264 /* Fall through. */
265 case 'D':
266 /* Match standard day format. */
267 if (!recursive (HERE_D_FMT))
268 return NULL;
269 want_xday = 1;
270 break;
271 case 'k':
272 case 'H':
273 /* Match hour in 24-hour clock. */
274 get_number (0, 23, 2);
275 tm->tm_hour = val;
276 have_I = 0;
277 break;
278 case 'l':
279 /* Match hour in 12-hour clock. GNU extension. */
280 case 'I':
281 /* Match hour in 12-hour clock. */
282 get_number (1, 12, 2);
283 tm->tm_hour = val % 12;
284 have_I = 1;
285 break;
286 case 'j':
287 /* Match day number of year. */
288 get_number (1, 366, 3);
289 tm->tm_yday = val - 1;
290 have_yday = 1;
291 break;
292 case 'm':
293 /* Match number of month. */
294 get_number (1, 12, 2);
295 tm->tm_mon = val - 1;
296 have_mon = 1;
297 want_xday = 1;
298 break;
299 case 'M':
300 /* Match minute. */
301 get_number (0, 59, 2);
302 tm->tm_min = val;
303 break;
304 case 'n':
305 case 't':
306 /* Match any white space. */
307 while (ISSPACE (*rp))
308 ++rp;
309 break;
310 case 'p':
311 /* Match locale's equivalent of AM/PM. */
312 if (!match_string (HERE_AM_STR, rp))
313 {
314 if (match_string (HERE_PM_STR, rp))
315 is_pm = 1;
316 else
317 return NULL;
318 }
319 break;
320 case 'q':
321 /* Match quarter of year. GNU extension. */
322 get_number (1, 4, 1);
323 tm->tm_mon = (val - 1) * 3;
324 tm->tm_mday = 1;
325 have_mon = 1;
326 have_mday = 1;
327 want_xday = 1;
328 break;
329 case 'r':
330 if (!recursive (HERE_T_FMT_AMPM))
331 return NULL;
332 break;
333 case 'R':
334 if (!recursive ("%H:%M"))
335 return NULL;
336 break;
337 case 's':
338 {
339 /* The number of seconds may be very high so we cannot use
340 the 'get_number' macro. Instead read the number
341 character for character and construct the result while
342 doing this. */
343 time_t secs = 0;
344 if (*rp < '0' || *rp > '9')
345 /* We need at least one digit. */
346 return NULL;
347
348 do
349 {
350 secs *= 10;
351 secs += *rp++ - '0';
352 }
353 while (*rp >= '0' && *rp <= '9');
354
355 if (localtime_r (&secs, tm) == NULL)
356 /* Error in function. */
357 return NULL;
358 }
359 break;
360 case 'S':
361 get_number (0, 61, 2);
362 tm->tm_sec = val;
363 break;
364 case 'X':
365 /* Fall through. */
366 case 'T':
367 if (!recursive (HERE_T_FMT))
368 return NULL;
369 break;
370 case 'u':
371 get_number (1, 7, 1);
372 tm->tm_wday = val % 7;
373 have_wday = 1;
374 break;
375 case 'g':
376 get_number (0, 99, 2);
377 /* XXX This cannot determine any field in TM. */
378 break;
379 case 'G':
380 if (*rp < '0' || *rp > '9')
381 return NULL;
382 /* XXX Ignore the number since we would need some more
383 information to compute a real date. */
384 do
385 ++rp;
386 while (*rp >= '0' && *rp <= '9');
387 break;
388 case 'U':
389 get_number (0, 53, 2);
390 week_no = val;
391 have_uweek = 1;
392 break;
393 case 'W':
394 get_number (0, 53, 2);
395 week_no = val;
396 have_wweek = 1;
397 break;
398 case 'V':
399 get_number (0, 53, 2);
400 /* XXX This cannot determine any field in TM without some
401 information. */
402 break;
403 case 'w':
404 /* Match number of weekday. */
405 get_number (0, 6, 1);
406 tm->tm_wday = val;
407 have_wday = 1;
408 break;
409 case 'y':
410 /* Match year within century. */
411 get_number (0, 99, 2);
412 /* The "Year 2000: The Millennium Rollover" paper suggests that
413 values in the range 69-99 refer to the twentieth century. */
414 tm->tm_year = val >= 69 ? val : val + 100;
415 /* Indicate that we want to use the century, if specified. */
416 want_century = 1;
417 want_xday = 1;
418 break;
419 case 'Y':
420 /* Match year including century number. */
421 get_number (0, 9999, 4);
422 tm->tm_year = val - 1900;
423 want_century = 0;
424 want_xday = 1;
425 break;
426 case 'Z':
427 /* XXX How to handle this? */
428 break;
429 case 'z':
430 /* We recognize two formats: if two digits are given, these
431 specify hours. If fours digits are used, minutes are
432 also specified. And 'Z'.
433
434 Three formats! We recognize three formats... */
435 {
436 bool neg;
437 int n;
438
439 val = 0;
440 while (*rp == ' ')
441 ++rp;
442 if (*rp == 'Z') {
443 ++rp;
444 if (gmtoff)
445 *gmtoff = 0;
446 break;
447 }
448 if (*rp != '+' && *rp != '-')
449 return NULL;
450 neg = *rp++ == '-';
451 n = 0;
452 while (n < 4 && *rp >= '0' && *rp <= '9')
453 {
454 val = val * 10 + *rp++ - '0';
455 ++n;
456 }
457 if (n == 2)
458 val *= 100;
459 else if (n != 4)
460 /* Only two or four digits recognized. */
461 return NULL;
462 else
463 {
464 /* We have to convert the minutes into decimal. */
465 if (val % 100 >= 60)
466 return NULL;
467 val = (val / 100) * 100 + ((val % 100) * 50) / 30;
468 }
469 if (val > 1200)
470 return NULL;
471 if (gmtoff) {
472 *gmtoff = (val * 3600) / 100;
473 if (neg)
474 *gmtoff = -*gmtoff;
475 }
476 }
477 break;
478 case 'E':
479 /* We have no information about the era format. Just use
480 the normal format. */
481 if (strchr("cCyYxX", *fmt) == NULL)
482 /* This is an illegal format. */
483 return NULL;
484
485 goto start_over;
486 case 'O':
487 /* We don't have an alternative number format. Just use
488 the normal format. */
489 if (strchr("deHImMqSUWVwy", *fmt) == NULL)
490 /* This is an illegal format. */
491 return NULL;
492
493 goto start_over;
494 default:
495 return NULL;
496 }
497 }
498
499 if (have_I && is_pm)
500 tm->tm_hour += 12;
501
502 if (century != -1)
503 {
504 if (want_century)
505 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
506 else
507 /* Only the century, but not the year. Strange, but so be it. */
508 tm->tm_year = (century - 19) * 100;
509 }
510
511 if (era_cnt != -1)
512 {
513 }
514 else
515 if (want_era)
516 {
517 /* No era found but we have seen an E modifier. Rectify some
518 values. */
519 if (want_century && century == -1 && tm->tm_year < 69)
520 tm->tm_year += 100;
521 }
522
523 if (want_xday && !have_wday)
524 {
525 if ( !(have_mon && have_mday) && have_yday)
526 {
527 /* We don't have tm_mon and/or tm_mday, compute them. */
528 int t_mon = 0;
529 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
530 t_mon++;
531 if (!have_mon)
532 tm->tm_mon = t_mon - 1;
533 if (!have_mday)
534 tm->tm_mday =
535 (tm->tm_yday
536 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
537 }
538 day_of_the_week (tm);
539 }
540
541 if (want_xday && !have_yday)
542 day_of_the_year (tm);
543
544 if ((have_uweek || have_wweek) && have_wday)
545 {
546 int save_wday = tm->tm_wday;
547 int save_mday = tm->tm_mday;
548 int save_mon = tm->tm_mon;
549 int w_offset = have_uweek ? 0 : 1;
550
551 tm->tm_mday = 1;
552 tm->tm_mon = 0;
553 day_of_the_week (tm);
554 if (have_mday)
555 tm->tm_mday = save_mday;
556 if (have_mon)
557 tm->tm_mon = save_mon;
558
559 if (!have_yday)
560 tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
561 + (week_no - 1) *7
562 + save_wday - w_offset);
563
564 if (!have_mday || !have_mon)
565 {
566 int t_mon = 0;
567 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon]
568 <= tm->tm_yday)
569 t_mon++;
570 if (!have_mon)
571 tm->tm_mon = t_mon - 1;
572 if (!have_mday)
573 tm->tm_mday =
574 (tm->tm_yday
575 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
576 }
577
578 tm->tm_wday = save_wday;
579 }
580
581 return (char *) rp;
582}
583
584
585char *
586strptime (const char *buf, const char *format, struct tm *tm)
587{
588 enum ptime_locale_status decided;
589
590 decided = raw;
591 return __strptime_internal (buf, format, tm, &decided, -1, NULL);
592}
593
594char *
595mingw_strptime (const char *buf, const char *format, struct tm *tm,
596 long *gmtoff)
597{
598 enum ptime_locale_status decided;
599
600 decided = raw;
601 return __strptime_internal (buf, format, tm, &decided, -1, gmtoff);
602}
603
diff --git a/win32/strverscmp.c b/win32/strverscmp.c
new file mode 100644
index 000000000..05dc60c39
--- /dev/null
+++ b/win32/strverscmp.c
@@ -0,0 +1,62 @@
1/*
2 strverscmp from musl (https://www.musl-libc.org/).
3
4 MIT licensed:
5
6----------------------------------------------------------------------
7Copyright © 2005-2020 Rich Felker, et al.
8
9Permission is hereby granted, free of charge, to any person obtaining
10a copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice shall be
18included in all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27----------------------------------------------------------------------
28*/
29#include "libbb.h"
30#include <ctype.h>
31#include <string.h>
32
33int strverscmp(const char *l0, const char *r0)
34{
35 const unsigned char *l = (const void *)l0;
36 const unsigned char *r = (const void *)r0;
37 size_t i, dp, j;
38 int z = 1;
39
40 /* Find maximal matching prefix and track its maximal digit
41 * suffix and whether those digits are all zeros. */
42 for (dp=i=0; l[i]==r[i]; i++) {
43 int c = l[i];
44 if (!c) return 0;
45 if (!isdigit(c)) dp=i+1, z=1;
46 else if (c!='0') z=0;
47 }
48
49 if (l[dp]-'1'<9U && r[dp]-'1'<9U) {
50 /* If we're looking at non-degenerate digit sequences starting
51 * with nonzero digits, longest digit string is greater. */
52 for (j=i; isdigit(l[j]); j++)
53 if (!isdigit(r[j])) return 1;
54 if (isdigit(r[j])) return -1;
55 } else if (z && dp<i && (isdigit(l[i]) || isdigit(r[i]))) {
56 /* Otherwise, if common prefix of digit sequence is
57 * all zeros, digits order less than non-digits. */
58 return (unsigned char)(l[i]-'0') - (unsigned char)(r[i]-'0');
59 }
60
61 return l[i] - r[i];
62}
diff --git a/win32/sys/inotify.h b/win32/sys/inotify.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/inotify.h
diff --git a/win32/sys/ioctl.h b/win32/sys/ioctl.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/ioctl.h
diff --git a/win32/sys/mman.h b/win32/sys/mman.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/mman.h
diff --git a/win32/sys/resource.h b/win32/sys/resource.h
new file mode 100644
index 000000000..3220d8112
--- /dev/null
+++ b/win32/sys/resource.h
@@ -0,0 +1,11 @@
1#ifndef _SYS_RESOURCE_H
2#define _SYS_RESOURCE_H 1
3
4#include <time.h>
5
6struct rusage {
7 struct timeval ru_utime;
8 struct timeval ru_stime;
9};
10
11#endif
diff --git a/win32/sys/select.h b/win32/sys/select.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/select.h
diff --git a/win32/sys/socket.h b/win32/sys/socket.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/socket.h
diff --git a/win32/sys/statfs.h b/win32/sys/statfs.h
new file mode 100644
index 000000000..498f41e50
--- /dev/null
+++ b/win32/sys/statfs.h
@@ -0,0 +1,22 @@
1#ifndef _SYS_STATFS_H
2#define _SYS_STATFS_H 1
3
4#include <stdint.h>
5
6struct statfs {
7 int f_type;
8 uint64_t f_bsize;
9 uint64_t f_frsize;
10 uint64_t f_blocks;
11 uint64_t f_bfree;
12 uint64_t f_bavail;
13 uint64_t f_files;
14 uint64_t f_ffree;
15 uint64_t f_fsid;
16 uint64_t f_flag;
17 uint64_t f_namelen;
18};
19
20extern int statfs(const char *file, struct statfs *buf);
21
22#endif
diff --git a/win32/sys/statvfs.h b/win32/sys/statvfs.h
new file mode 100644
index 000000000..ceb9ee353
--- /dev/null
+++ b/win32/sys/statvfs.h
@@ -0,0 +1,3 @@
1#include <sys/statfs.h>
2
3#define statvfs statfs
diff --git a/win32/sys/syscall.h b/win32/sys/syscall.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/syscall.h
diff --git a/win32/sys/sysmacros.h b/win32/sys/sysmacros.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/sysmacros.h
diff --git a/win32/sys/times.h b/win32/sys/times.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/times.h
diff --git a/win32/sys/un.h b/win32/sys/un.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/un.h
diff --git a/win32/sys/utsname.h b/win32/sys/utsname.h
new file mode 100644
index 000000000..6f12efd58
--- /dev/null
+++ b/win32/sys/utsname.h
@@ -0,0 +1,66 @@
1/* Copyright (C) 1991,92,94,96,97,99,2002 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307 USA. */
18
19/*
20 * POSIX Standard: 4.4 System Identification <sys/utsname.h>
21 */
22
23#ifndef _SYS_UTSNAME_H
24#define _SYS_UTSNAME_H 1
25
26#define _UTSNAME_LENGTH 65
27
28#ifndef _UTSNAME_SYSNAME_LENGTH
29# define _UTSNAME_SYSNAME_LENGTH _UTSNAME_LENGTH
30#endif
31#ifndef _UTSNAME_NODENAME_LENGTH
32# define _UTSNAME_NODENAME_LENGTH _UTSNAME_LENGTH
33#endif
34#ifndef _UTSNAME_RELEASE_LENGTH
35# define _UTSNAME_RELEASE_LENGTH _UTSNAME_LENGTH
36#endif
37#ifndef _UTSNAME_VERSION_LENGTH
38# define _UTSNAME_VERSION_LENGTH _UTSNAME_LENGTH
39#endif
40#ifndef _UTSNAME_MACHINE_LENGTH
41# define _UTSNAME_MACHINE_LENGTH _UTSNAME_LENGTH
42#endif
43
44/* Structure describing the system and machine. */
45struct utsname
46 {
47 /* Name of the implementation of the operating system. */
48 char sysname[_UTSNAME_SYSNAME_LENGTH];
49
50 /* Name of this node on the network. */
51 char nodename[_UTSNAME_NODENAME_LENGTH];
52
53 /* Current release level of this implementation. */
54 char release[_UTSNAME_RELEASE_LENGTH];
55 /* Current version level of this release. */
56 char version[_UTSNAME_VERSION_LENGTH];
57
58 /* Name of the hardware type the system is running on. */
59 char machine[_UTSNAME_MACHINE_LENGTH];
60 };
61
62/* Put information about the system in NAME. */
63extern int uname (struct utsname *__name);
64
65
66#endif /* sys/utsname.h */
diff --git a/win32/sys/wait.h b/win32/sys/wait.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/wait.h
diff --git a/win32/system.c b/win32/system.c
new file mode 100644
index 000000000..c718d9948
--- /dev/null
+++ b/win32/system.c
@@ -0,0 +1,22 @@
1#include "libbb.h"
2
3int mingw_system(const char *cmd)
4{
5 const char *argv[4] = { "sh", "-c", cmd, NULL };
6 intptr_t proc;
7 HANDLE h;
8 DWORD ret = 0;
9
10 if (cmd == NULL)
11 return 1;
12
13 if ((proc=mingw_spawn_proc(argv)) == -1)
14 return -1;
15
16 h = (HANDLE)proc;
17 WaitForSingleObject(h, INFINITE);
18 GetExitCodeProcess(h, &ret);
19 CloseHandle(h);
20
21 return exit_code_to_wait_status(ret);
22}
diff --git a/win32/termios.c b/win32/termios.c
new file mode 100644
index 000000000..f18ff7c3b
--- /dev/null
+++ b/win32/termios.c
@@ -0,0 +1,128 @@
1#include "libbb.h"
2
3int tcsetattr(int fd, int mode UNUSED_PARAM, const struct termios *t)
4{
5 if (terminal_mode(FALSE) & VT_INPUT) {
6 HANDLE h = (HANDLE)_get_osfhandle(fd);
7 if (!SetConsoleMode(h, t->imode)) {
8 errno = err_win_to_posix();
9 return -1;
10 }
11 }
12
13 return 0;
14}
15
16int tcgetattr(int fd, struct termios *t)
17{
18 if (terminal_mode(FALSE) & VT_INPUT) {
19 HANDLE h = (HANDLE)_get_osfhandle(fd);
20 if (!GetConsoleMode(h, &t->imode)) {
21 errno = err_win_to_posix();
22 return -1;
23 }
24 }
25 t->c_cc[VINTR] = 3; // ctrl-c
26 t->c_cc[VEOF] = 4; // ctrl-d
27
28 return 0;
29}
30
31int64_t FAST_FUNC windows_read_key(int fd, char *buf UNUSED_PARAM, int timeout)
32{
33 HANDLE cin = GetStdHandle(STD_INPUT_HANDLE);
34 INPUT_RECORD record;
35 DWORD nevent_out, mode;
36 int ret = -1;
37 DWORD alt_pressed = FALSE;
38 DWORD state;
39
40 if (fd != 0)
41 bb_error_msg_and_die("read_key only works on stdin");
42 if (cin == INVALID_HANDLE_VALUE)
43 return -1;
44 GetConsoleMode(cin, &mode);
45 SetConsoleMode(cin, 0);
46
47 while (1) {
48 errno = 0;
49 if (timeout > 0) {
50 if (WaitForSingleObject(cin, timeout) != WAIT_OBJECT_0)
51 goto done;
52 }
53 if (!readConsoleInput_utf8(cin, &record, 1, &nevent_out))
54 goto done;
55
56 if (record.EventType != KEY_EVENT)
57 continue;
58
59 state = record.Event.KeyEvent.dwControlKeyState;
60 if (!record.Event.KeyEvent.bKeyDown) {
61 /* ignore all key up events except Alt */
62 if (!(alt_pressed && (state & LEFT_ALT_PRESSED) == 0 &&
63 record.Event.KeyEvent.wVirtualKeyCode == VK_MENU))
64 continue;
65 }
66 alt_pressed = state & LEFT_ALT_PRESSED;
67
68 if (!record.Event.KeyEvent.uChar.AsciiChar) {
69 if (alt_pressed && !(state & ENHANCED_KEY)) {
70 /* keys on numeric pad used to enter character codes */
71 switch (record.Event.KeyEvent.wVirtualKeyCode) {
72 case VK_NUMPAD0: case VK_INSERT:
73 case VK_NUMPAD1: case VK_END:
74 case VK_NUMPAD2: case VK_DOWN:
75 case VK_NUMPAD3: case VK_NEXT:
76 case VK_NUMPAD4: case VK_LEFT:
77 case VK_NUMPAD5: case VK_CLEAR:
78 case VK_NUMPAD6: case VK_RIGHT:
79 case VK_NUMPAD7: case VK_HOME:
80 case VK_NUMPAD8: case VK_UP:
81 case VK_NUMPAD9: case VK_PRIOR:
82 continue;
83 }
84 }
85
86 switch (record.Event.KeyEvent.wVirtualKeyCode) {
87 case VK_DELETE: ret = KEYCODE_DELETE; break;
88 case VK_INSERT: ret = KEYCODE_INSERT; break;
89 case VK_UP: ret = KEYCODE_UP; break;
90 case VK_DOWN: ret = KEYCODE_DOWN; break;
91 case VK_RIGHT: ret = KEYCODE_RIGHT; break;
92 case VK_LEFT: ret = KEYCODE_LEFT; break;
93 case VK_HOME: ret = KEYCODE_HOME; break;
94 case VK_END: ret = KEYCODE_END; break;
95 case VK_PRIOR: ret = KEYCODE_PAGEUP; break;
96 case VK_NEXT: ret = KEYCODE_PAGEDOWN; break;
97 default:
98 alt_pressed = FALSE;
99 continue;
100 }
101
102 if (state & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED))
103 ret &= ~0x20;
104 if (state & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED))
105 ret &= ~0x40;
106 if (state & SHIFT_PRESSED)
107 ret &= ~0x80;
108 goto done;
109 }
110 if ( (record.Event.KeyEvent.uChar.AsciiChar & 0x80) == 0x80 ) {
111 char *s = &record.Event.KeyEvent.uChar.AsciiChar;
112 conToCharBuffA(s, 1);
113 }
114 ret = record.Event.KeyEvent.uChar.AsciiChar;
115 if (state & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) {
116 switch (ret) {
117 case '\b': ret = KEYCODE_ALT_BACKSPACE; goto done;
118 case 'b': ret = KEYCODE_ALT_LEFT; goto done;
119 case 'd': ret = KEYCODE_ALT_D; goto done;
120 case 'f': ret = KEYCODE_ALT_RIGHT; goto done;
121 }
122 }
123 break;
124 }
125 done:
126 SetConsoleMode(cin, mode);
127 return ret;
128}
diff --git a/win32/termios.h b/win32/termios.h
new file mode 100644
index 000000000..8408aa3e3
--- /dev/null
+++ b/win32/termios.h
@@ -0,0 +1,31 @@
1#ifndef TERMIOS_H
2#define TERMIOS_H
3
4#define VINTR 0
5#define VEOF 1
6
7#define TCIFLUSH 0
8#define TCSAFLUSH 1
9#define TCSANOW 2
10#define TCSADRAIN 3
11#define TCSADFLUSH 4
12
13typedef unsigned char cc_t;
14typedef unsigned int speed_t;
15
16#define NCCS 2
17struct termios {
18 cc_t c_cc[NCCS];
19 unsigned long imode;
20 unsigned long omode;
21};
22
23struct winsize {
24 unsigned short ws_row, ws_col;
25 unsigned short ws_xpixel, ws_ypixel;
26};
27
28int tcgetattr(int fd, struct termios *t);
29int tcsetattr(int fd, int mode, const struct termios *t);
30
31#endif /* TERMIOS_H */
diff --git a/win32/timegm.c b/win32/timegm.c
new file mode 100644
index 000000000..ac39a26f5
--- /dev/null
+++ b/win32/timegm.c
@@ -0,0 +1,133 @@
1/*
2 timegm from musl (https://www.musl-libc.org/).
3
4 MIT licensed:
5
6----------------------------------------------------------------------
7Copyright © 2005-2020 Rich Felker, et al.
8
9Permission is hereby granted, free of charge, to any person obtaining
10a copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice shall be
18included in all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27----------------------------------------------------------------------
28*/
29#include "libbb.h"
30
31static long long __year_to_secs(long long year, int *is_leap)
32{
33 int cycles, centuries, leaps, rem;
34
35 if (year-2ULL <= 136) {
36 int y = year;
37 leaps = (y-68)>>2;
38 if (!((y-68)&3)) {
39 leaps--;
40 if (is_leap) *is_leap = 1;
41 } else if (is_leap) *is_leap = 0;
42 return 31536000*(y-70) + 86400*leaps;
43 }
44
45 cycles = (year-100) / 400;
46 rem = (year-100) % 400;
47 if (rem < 0) {
48 cycles--;
49 rem += 400;
50 }
51 if (!rem) {
52 *is_leap = 1;
53 centuries = 0;
54 leaps = 0;
55 } else {
56 if (rem >= 200) {
57 if (rem >= 300) centuries = 3, rem -= 300;
58 else centuries = 2, rem -= 200;
59 } else {
60 if (rem >= 100) centuries = 1, rem -= 100;
61 else centuries = 0;
62 }
63 if (!rem) {
64 *is_leap = 0;
65 leaps = 0;
66 } else {
67 leaps = rem / 4U;
68 rem %= 4U;
69 *is_leap = !rem;
70 }
71 }
72
73 leaps += 97*cycles + 24*centuries - *is_leap;
74
75 return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400;
76}
77
78static int __month_to_secs(int month, int is_leap)
79{
80 static const int secs_through_month[] = {
81 0, 31*86400, 59*86400, 90*86400,
82 120*86400, 151*86400, 181*86400, 212*86400,
83 243*86400, 273*86400, 304*86400, 334*86400 };
84 int t = secs_through_month[month];
85 if (is_leap && month >= 2) t+=86400;
86 return t;
87}
88
89static long long __tm_to_secs(const struct tm *tm)
90{
91 int is_leap;
92 long long t;
93 long long year = tm->tm_year;
94 int month = tm->tm_mon;
95 if (month >= 12 || month < 0) {
96 int adj = month / 12;
97 month %= 12;
98 if (month < 0) {
99 adj--;
100 month += 12;
101 }
102 year += adj;
103 }
104 t = __year_to_secs(year, &is_leap);
105 t += __month_to_secs(month, is_leap);
106 t += 86400LL * (tm->tm_mday-1);
107 t += 3600LL * tm->tm_hour;
108 t += 60LL * tm->tm_min;
109 t += tm->tm_sec;
110 return t;
111}
112
113/*
114 * Restricted version of timegm:
115 *
116 * it doesn't normalise its argument
117 * its return value is limited to the range Microsoft supports
118 */
119time_t timegm(struct tm *tm)
120{
121 long long t = __tm_to_secs(tm);
122 if (t < 0 ||
123#ifdef _USE_32BIT_TIME_T
124 t > INT_MAX /* 2038-01-19 03:14:07Z */
125#else
126 t > 32535215999 /* 3000-12-31 23:59:59Z */
127#endif
128 ) {
129 errno = EOVERFLOW;
130 return -1;
131 }
132 return t;
133}
diff --git a/win32/uname.c b/win32/uname.c
new file mode 100644
index 000000000..9474e5c04
--- /dev/null
+++ b/win32/uname.c
@@ -0,0 +1,47 @@
1#include "libbb.h"
2/* After libbb.h, since it needs sys/types.h on some systems */
3#include <sys/utsname.h>
4
5int uname(struct utsname *name)
6{
7 const char *unk = "unknown";
8 OSVERSIONINFO os_info;
9 SYSTEM_INFO sys_info;
10
11 strcpy(name->sysname, "Windows_NT");
12
13 if ( gethostname(name->nodename, sizeof(name->nodename)) != 0 ) {
14 strcpy(name->nodename, unk);
15 }
16
17 memset(&os_info, 0, sizeof(OSVERSIONINFO));
18 os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
19
20 GetVersionEx(&os_info);
21 sprintf(name->release, "%u.%u", (unsigned int)os_info.dwMajorVersion,
22 (unsigned int)os_info.dwMinorVersion);
23 sprintf(name->version, "%u", (unsigned int)os_info.dwBuildNumber);
24
25 GetSystemInfo(&sys_info);
26 switch (sys_info.wProcessorArchitecture) {
27 case PROCESSOR_ARCHITECTURE_AMD64:
28 strcpy(name->machine, "x86_64");
29 break;
30 case PROCESSOR_ARCHITECTURE_INTEL:
31 strcpy(name->machine, "i686");
32 if (sys_info.wProcessorLevel < 6) {
33 name->machine[1] = '3';
34 }
35 break;
36#if defined(PROCESSOR_ARCHITECTURE_ARM64)
37 case PROCESSOR_ARCHITECTURE_ARM64:
38 strcpy(name->machine, "aarch64");
39 break;
40#endif
41 default:
42 strcpy(name->machine, unk);
43 break;
44 }
45
46 return 0;
47}
diff --git a/win32/winansi.c b/win32/winansi.c
new file mode 100644
index 000000000..c7529c453
--- /dev/null
+++ b/win32/winansi.c
@@ -0,0 +1,1608 @@
1/*
2 * Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
3 */
4
5#include "libbb.h"
6#include <windows.h>
7#include "lazyload.h"
8#undef PACKED
9
10static BOOL charToConBuffA(LPSTR s, DWORD len);
11static BOOL charToConA(LPSTR s);
12
13static int conv_fwriteCon(FILE *stream, char *buf, size_t siz);
14static int conv_writeCon(int fd, char *buf, size_t siz);
15
16/*
17 Functions to be wrapped:
18*/
19#undef vfprintf
20#undef vprintf
21#undef printf
22#undef fprintf
23#undef fputs
24#undef fputc
25#undef putchar
26#undef fwrite
27#undef puts
28#undef write
29#undef read
30#undef fread
31#undef getc
32#undef fgets
33
34#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
35#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
36
37static WORD plain_attr = 0xffff;
38static WORD current_attr;
39
40static HANDLE get_console(void)
41{
42 return GetStdHandle(STD_OUTPUT_HANDLE);
43}
44
45static WORD get_console_attr(void)
46{
47 CONSOLE_SCREEN_BUFFER_INFO sbi;
48
49 if (GetConsoleScreenBufferInfo(get_console(), &sbi))
50 return sbi.wAttributes;
51
52 return FOREGROUND_ALL;
53}
54
55static int is_console(int fd)
56{
57 if (plain_attr == 0xffff)
58 current_attr = plain_attr = get_console_attr();
59 return isatty(fd) && get_console() != INVALID_HANDLE_VALUE;
60}
61
62static ALWAYS_INLINE int is_console_in(int fd)
63{
64 return isatty(fd) && GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE;
65}
66
67static int is_wine(void)
68{
69 DECLARE_PROC_ADDR(const char *, wine_get_version, void);
70
71 return INIT_PROC_ADDR(ntdll.dll, wine_get_version) != NULL;
72}
73
74#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
75#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
76#endif
77
78#ifndef DISABLE_NEWLINE_AUTO_RETURN
79#define DISABLE_NEWLINE_AUTO_RETURN 0x0008
80#endif
81
82#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
83#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
84#endif
85
86int FAST_FUNC terminal_mode(int reset)
87{
88 static int mode = -1;
89
90#if ENABLE_FEATURE_EURO
91 if (mode < 0) {
92 if (GetConsoleCP() == 850 && GetConsoleOutputCP() == 850) {
93 SetConsoleCP(858);
94 SetConsoleOutputCP(858);
95 }
96 }
97#endif
98
99 if (mode < 0 || reset) {
100 HANDLE h;
101 DWORD oldmode, newmode;
102 const char *term = getenv(BB_TERMINAL_MODE);
103 const char *skip = getenv(BB_SKIP_ANSI_EMULATION);
104
105 if (term) {
106 mode = atoi(term);
107 } else if (skip) {
108 mode = atoi(skip);
109 if (mode == 2)
110 mode = 5;
111 else if (mode != 1)
112 mode = 0;
113 } else {
114 mode = (getenv("CONEMUPID") != NULL || is_wine()) ? 0 :
115 CONFIG_TERMINAL_MODE;
116 }
117
118 if (mode < 0 || mode > 5)
119 mode = CONFIG_TERMINAL_MODE;
120
121 if (is_console(STDOUT_FILENO)) {
122 h = get_console();
123 if (GetConsoleMode(h, &oldmode)) {
124 // Try to recover from mode 0 induced by SSH.
125 newmode = oldmode == 0 ? 3 : oldmode;
126 // Turn off DISABLE_NEWLINE_AUTO_RETURN induced by Gradle?
127 newmode &= ~DISABLE_NEWLINE_AUTO_RETURN;
128
129 if ((mode & VT_OUTPUT)) {
130 newmode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
131 } else if (mode < 4) {
132 newmode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING;
133 } else if ((oldmode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
134 mode |= VT_OUTPUT;
135 }
136
137 if (newmode != oldmode) {
138 if (!SetConsoleMode(h, newmode)) {
139 if (mode >= 4)
140 mode &= ~VT_OUTPUT;
141 newmode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING;
142 SetConsoleMode(h, newmode);
143 }
144 }
145 }
146 }
147
148 if (is_console_in(STDIN_FILENO)) {
149 h = GetStdHandle(STD_INPUT_HANDLE);
150 if (GetConsoleMode(h, &oldmode)) {
151 // Try to recover from mode 0 induced by SSH.
152 newmode = oldmode == 0 ? 0x1f7 : oldmode;
153
154 if (mode < 4) {
155 if ((mode & VT_INPUT))
156 newmode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
157 else
158 newmode &= ~ENABLE_VIRTUAL_TERMINAL_INPUT;
159 } else if ((oldmode & ENABLE_VIRTUAL_TERMINAL_INPUT)) {
160 mode |= VT_INPUT;
161 }
162
163 if (newmode != oldmode) {
164 if (!SetConsoleMode(h, newmode)) {
165 if (mode >= 4)
166 mode &= ~VT_INPUT;
167 // Failure to set the new mode seems to leave
168 // the flag set. Forcibly unset it.
169 newmode &= ~ENABLE_VIRTUAL_TERMINAL_INPUT;
170 SetConsoleMode(h, newmode);
171 }
172 }
173 }
174 }
175 }
176
177 return mode;
178}
179
180void set_title(const char *str)
181{
182 SetConsoleTitle(str);
183}
184
185int get_title(char *buf, int len)
186{
187 return GetConsoleTitle(buf, len);
188}
189
190static HANDLE dup_handle(HANDLE h)
191{
192 HANDLE h2;
193
194 if (!DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(),
195 &h2, 0, TRUE, DUPLICATE_SAME_ACCESS))
196 return INVALID_HANDLE_VALUE;
197 return h2;
198}
199
200static void use_alt_buffer(int flag)
201{
202 static HANDLE console_orig = INVALID_HANDLE_VALUE;
203 HANDLE console, h;
204
205 if (flag) {
206 SECURITY_ATTRIBUTES sa;
207 CONSOLE_SCREEN_BUFFER_INFO sbi;
208
209 if (console_orig != INVALID_HANDLE_VALUE)
210 return;
211
212 console = get_console();
213 console_orig = dup_handle(console);
214
215 // handle should be inheritable
216 memset(&sa, 0, sizeof(sa));
217 sa.nLength = sizeof(sa);
218 /* sa.lpSecurityDescriptor = NULL; - memset did it */
219 sa.bInheritHandle = TRUE;
220
221 // create new alternate buffer
222 h = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE,
223 FILE_SHARE_READ|FILE_SHARE_WRITE, &sa,
224 CONSOLE_TEXTMODE_BUFFER, NULL);
225 if (h == INVALID_HANDLE_VALUE)
226 return;
227
228 if (GetConsoleScreenBufferInfo(console, &sbi))
229 SetConsoleScreenBufferSize(h, sbi.dwSize);
230 }
231 else {
232 if (console_orig == INVALID_HANDLE_VALUE)
233 return;
234
235 // revert to original buffer
236 h = dup_handle(console_orig);
237 console_orig = INVALID_HANDLE_VALUE;
238 if (h == INVALID_HANDLE_VALUE)
239 return;
240 }
241
242 console = h;
243 SetConsoleActiveScreenBuffer(console);
244 close(STDOUT_FILENO);
245 _open_osfhandle((intptr_t)console, O_RDWR|O_BINARY);
246}
247
248static void clear_buffer(DWORD len, COORD pos)
249{
250 HANDLE console = get_console();
251 DWORD dummy;
252
253 FillConsoleOutputCharacterA(console, ' ', len, pos, &dummy);
254 FillConsoleOutputAttribute(console, plain_attr, len, pos, &dummy);
255}
256
257static void erase_in_line(void)
258{
259 HANDLE console = get_console();
260 CONSOLE_SCREEN_BUFFER_INFO sbi;
261
262 if (!GetConsoleScreenBufferInfo(console, &sbi))
263 return;
264 clear_buffer(sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition);
265}
266
267static void erase_till_end_of_screen(void)
268{
269 HANDLE console = get_console();
270 CONSOLE_SCREEN_BUFFER_INFO sbi;
271 DWORD len;
272
273 if(!GetConsoleScreenBufferInfo(console, &sbi))
274 return;
275 len = sbi.dwSize.X - sbi.dwCursorPosition.X +
276 sbi.dwSize.X * (sbi.srWindow.Bottom - sbi.dwCursorPosition.Y);
277 clear_buffer(len, sbi.dwCursorPosition);
278}
279
280void reset_screen(void)
281{
282 HANDLE console = get_console();
283 CONSOLE_SCREEN_BUFFER_INFO sbi;
284 COORD pos = { 0, 0 };
285
286 /* move to start of screen buffer and clear it all */
287 if (!GetConsoleScreenBufferInfo(console, &sbi))
288 return;
289 SetConsoleCursorPosition(console, pos);
290 clear_buffer(sbi.dwSize.X * sbi.dwSize.Y, pos);
291}
292
293void move_cursor_row(int n)
294{
295 HANDLE console = get_console();
296 CONSOLE_SCREEN_BUFFER_INFO sbi;
297
298 if(!GetConsoleScreenBufferInfo(console, &sbi))
299 return;
300 sbi.dwCursorPosition.Y += n;
301 SetConsoleCursorPosition(console, sbi.dwCursorPosition);
302}
303
304static void move_cursor_column(int n)
305{
306 HANDLE console = get_console();
307 CONSOLE_SCREEN_BUFFER_INFO sbi;
308
309 if (!GetConsoleScreenBufferInfo(console, &sbi))
310 return;
311 sbi.dwCursorPosition.X += n;
312 SetConsoleCursorPosition(console, sbi.dwCursorPosition);
313}
314
315static void move_cursor(int x, int y)
316{
317 HANDLE console = get_console();
318 COORD pos;
319 CONSOLE_SCREEN_BUFFER_INFO sbi;
320
321 if (!GetConsoleScreenBufferInfo(console, &sbi))
322 return;
323 pos.X = sbi.srWindow.Left + x;
324 pos.Y = sbi.srWindow.Top + y;
325 SetConsoleCursorPosition(console, pos);
326}
327
328static const unsigned char colour_1bit[16] = {
329 /* Black */ 0,
330 /* Red */ FOREGROUND_RED,
331 /* Green */ FOREGROUND_GREEN,
332 /* Yellow */ FOREGROUND_RED | FOREGROUND_GREEN,
333 /* Blue */ FOREGROUND_BLUE,
334 /* Magenta */ FOREGROUND_RED | FOREGROUND_BLUE,
335 /* Cyan */ FOREGROUND_GREEN | FOREGROUND_BLUE,
336 /* White */ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
337 /* ... and again but brighter */
338 FOREGROUND_INTENSITY,
339 FOREGROUND_RED | FOREGROUND_INTENSITY,
340 FOREGROUND_GREEN | FOREGROUND_INTENSITY,
341 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
342 FOREGROUND_BLUE | FOREGROUND_INTENSITY,
343 FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
344 FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
345 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
346};
347
348#if !ENABLE_FEATURE_IMPROVED_COLOUR_MAPPING
349static WORD rgb_to_console(int *rgb)
350{
351 int dark = 0, bright;
352 WORD attr = 0;
353
354 if (rgb[0] > 85)
355 attr |= FOREGROUND_RED;
356 else
357 ++dark;
358
359 if (rgb[1] > 85)
360 attr |= FOREGROUND_GREEN;
361 else
362 ++dark;
363
364 if (rgb[2] > 85)
365 attr |= FOREGROUND_BLUE;
366 else
367 ++dark;
368
369 /* increase intensity if all components are either bright or
370 * dark and at least one is bright */
371 bright = (rgb[0] > 171) + (rgb[1] > 171) + (rgb[2] > 171);
372 if (bright + dark == 3 && dark != 3) {
373 attr |= FOREGROUND_INTENSITY;
374 }
375
376 return attr;
377}
378#else
379#include <math.h>
380
381/* Standard console colours in LAB colour space */
382static float colour_lab[16][3] = {
383 {-0.000000, 0.000000, 0.000000},
384 {25.530788, 48.055233, 38.059635},
385 {46.228817, -51.699638, 49.897949},
386 {51.868336, -12.930751, 56.677288},
387 {12.975313, 47.507763, -64.704285},
388 {29.782101, 58.939846, -36.497940},
389 {48.256081, -28.841570, -8.481050},
390 {77.704361, 0.004262, -0.008416},
391 {53.585018, 0.003129, -0.006235},
392 {53.232883, 80.109299, 67.220078},
393 {87.737038, -86.184654, 83.181168},
394 {97.138245, -21.555901, 94.482483},
395 {32.302586, 79.196678, -107.863686},
396 {60.319931, 98.254234, -60.842991},
397 {91.116524, -48.079609, -14.138126},
398 {100.000000, 0.005245, -0.010419},
399};
400
401/* Convert RGB to XYZ and XYZ to LAB. See:
402 * http://www.easyrgb.com/en/math.php#text1 */
403static void rgb2lab(const int *rgb, float *lab)
404{
405 float var_RGB[3], var_XYZ[3];
406 int i;
407
408 for (i = 0; i < 3; ++i) {
409 var_RGB[i] = rgb[i]/255.0f;
410 if (var_RGB[i] > 0.04045f)
411 var_RGB[i] = pow((var_RGB[i] + 0.055f) / 1.055f, 2.4f);
412 else
413 var_RGB[i] /= 12.92f;
414 }
415
416 /* use equal energy reference values */
417 var_XYZ[0] = var_RGB[0]*0.4124f + var_RGB[1]*0.3576f + var_RGB[2]*0.1805f;
418 var_XYZ[1] = var_RGB[0]*0.2126f + var_RGB[1]*0.7152f + var_RGB[2]*0.0722f;
419 var_XYZ[2] = var_RGB[0]*0.0193f + var_RGB[1]*0.1192f + var_RGB[2]*0.9505f;
420
421 for (i = 0; i < 3; ++i) {
422 if (var_XYZ[i] > 0.008856f)
423 var_XYZ[i] = pow(var_XYZ[i], 1.0f / 3.0f);
424 else
425 var_XYZ[i] = 7.787f * var_XYZ[i] + 16.0f / 116.0f;
426 }
427
428 lab[0] = 116.0f * var_XYZ[1] - 16.0f;
429 lab[1] = 500.0f * (var_XYZ[0] - var_XYZ[1]);
430 lab[2] = 200.0f * (var_XYZ[1] - var_XYZ[2]);
431}
432
433static WORD rgb_to_console(int *rgb)
434{
435 int i, imin = 0;
436 float deltamin = 1.0e20;
437
438 /* Use 1976 CIE deltaE to find closest console colour. See:
439 * https://zschuessler.github.io/DeltaE/learn */
440 for (i = 0; i < 16; ++i) {
441 float lab[3], dl, da, db, delta;
442
443 rgb2lab(rgb, lab);
444 dl = colour_lab[i][0] - lab[0];
445 da = colour_lab[i][1] - lab[1];
446 db = colour_lab[i][2] - lab[2];
447 delta = dl * dl + da * da + db *db;
448 if (delta < deltamin) {
449 imin = i;
450 deltamin = delta;
451 }
452 }
453 return colour_1bit[imin];
454}
455#endif
456
457/* 24-bit colour */
458static char *process_24bit(char *str, WORD *attr)
459{
460 int count;
461 int rgb[3];
462
463 for (count = 0; count < 3; ++count) {
464 rgb[count] = strtol(str, (char **)&str, 10);
465 if (*str == ';')
466 ++str;
467 }
468
469 *attr = rgb_to_console(rgb);
470
471 return *(str - 1) == ';' ? str - 1 : str;
472}
473
474/* 8-bit colour */
475static char *process_8bit(char *str, WORD *attr)
476{
477 int val = strtol(str, &str, 10);
478
479 if (val < 16) {
480 *attr = colour_1bit[val];
481 }
482 else if (val < 232) {
483 int i, rgb[3];
484
485 val -= 16;
486 for (i = 2; i >= 0; --i) {
487 rgb[i] = (val % 6) * 42 + 21;
488 val /= 6;
489 }
490
491 *attr = rgb_to_console(rgb);
492 }
493 else if (val < 238) {
494 /* black */
495 *attr = 0;
496 }
497 else if (val < 244) {
498 /* bright black */
499 *attr = FOREGROUND_INTENSITY;
500 }
501 else if (val < 250) {
502 /* white */
503 *attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
504 }
505 else if (val < 256) {
506 /* bright white */
507 *attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
508 FOREGROUND_INTENSITY;
509 }
510
511 return str;
512}
513
514static char *process_colour(char *str, WORD *attr)
515{
516 long val = strtol(str, (char **)&str, 10);
517
518 *attr = 0xffff; /* error return */
519 switch (val) {
520 case 2:
521 str = process_24bit(str + 1, attr);
522 break;
523 case 5:
524 str = process_8bit(str + 1, attr);
525 break;
526 default:
527 break;
528 }
529
530 return str;
531}
532
533/* On input pos points to the start of a suspected escape sequence.
534 * If a valid sequence is found return a pointer to the character
535 * following it, otherwise return the original pointer. */
536static char *process_escape(char *pos)
537{
538 char *str, *func;
539 char *bel;
540 size_t len;
541 WORD t, attr = current_attr;
542 static int reverse = 0;
543
544 switch (pos[1]) {
545 case '[':
546 /* go ahead and process "\033[" sequence */
547 break;
548 case ']':
549 if ((pos[2] == '0' || pos[2] == '2') && pos[3] == ';' &&
550 (bel=strchr(pos+4, '\007')) && bel - pos < 260) {
551 /* set console title */
552 *bel++ = '\0';
553 charToConA(pos+4);
554 SetConsoleTitle(pos+4);
555 return bel;
556 }
557 /* invalid "\033]" sequence, fall through */
558 default:
559 return pos;
560 }
561
562 str = pos + 2;
563 len = strspn(str, "0123456789;");
564 func = str + len;
565 switch (*func) {
566 case 'm':
567 do {
568 long val = strtol(str, (char **)&str, 10);
569 switch (val) {
570 case 0: /* reset */
571 attr = plain_attr;
572 reverse = 0;
573 break;
574 case 1: /* bold */
575 attr |= FOREGROUND_INTENSITY;
576 break;
577 case 2: /* faint */
578 case 22: /* normal */
579 attr &= ~FOREGROUND_INTENSITY;
580 break;
581 case 3: /* italic */
582 /* Unsupported */
583 break;
584 case 4: /* underline */
585 case 21: /* double underline */
586 /* Wikipedia says this flag does nothing */
587 /* Furthermore, mingw doesn't define this flag
588 attr |= COMMON_LVB_UNDERSCORE; */
589 break;
590 case 24: /* no underline */
591 /* attr &= ~COMMON_LVB_UNDERSCORE; */
592 break;
593 case 5: /* slow blink */
594 case 6: /* fast blink */
595 /* We don't have blink, but we do have
596 background intensity */
597 attr |= BACKGROUND_INTENSITY;
598 break;
599 case 25: /* no blink */
600 attr &= ~BACKGROUND_INTENSITY;
601 break;
602 case 7: /* reverse video on */
603 reverse = 1;
604 break;
605 case 27: /* reverse video off */
606 reverse = 0;
607 break;
608 case 8: /* conceal */
609 case 9: /* strike through */
610 case 28: /* reveal */
611 /* Unsupported */
612 break;
613
614 /* Foreground colours */
615 case 30: /* Black */
616 case 31: /* Red */
617 case 32: /* Green */
618 case 33: /* Yellow */
619 case 34: /* Blue */
620 case 35: /* Magenta */
621 case 36: /* Cyan */
622 case 37: /* White */
623 attr &= ~FOREGROUND_ALL;
624 attr |= colour_1bit[val - 30];
625 break;
626 case 38: /* 8/24 bit */
627 str = process_colour(str + 1, &t);
628 if (t != 0xffff) {
629 attr &= ~(FOREGROUND_ALL|FOREGROUND_INTENSITY);
630 attr |= t;
631 }
632 break;
633 case 39: /* reset */
634 attr &= ~FOREGROUND_ALL;
635 attr |= (plain_attr & FOREGROUND_ALL);
636 break;
637
638 /* Background colours */
639 case 40: /* Black */
640 case 41: /* Red */
641 case 42: /* Green */
642 case 43: /* Yellow */
643 case 44: /* Blue */
644 case 45: /* Magenta */
645 case 46: /* Cyan */
646 case 47: /* White */
647 attr &= ~BACKGROUND_ALL;
648 attr |= colour_1bit[val - 40] << 4;
649 break;
650 case 48: /* 8/24 bit */
651 str = process_colour(str + 1, &t);
652 if (t != 0xffff) {
653 attr &= ~(BACKGROUND_ALL|BACKGROUND_INTENSITY);
654 attr |= t << 4;
655 }
656 break;
657 case 49: /* reset */
658 attr &= ~BACKGROUND_ALL;
659 attr |= (plain_attr & BACKGROUND_ALL);
660 break;
661
662 default:
663 /* Unsupported code */
664 return pos;
665 }
666 str++;
667 } while (str < func);
668
669 current_attr = attr;
670 if (reverse)
671 attr = ((attr >> 4) & 0xf) | ((attr << 4) & 0xf0);
672 SetConsoleTextAttribute(get_console(), attr);
673 break;
674 case 'A': /* up */
675 move_cursor_row(-strtol(str, (char **)&str, 10));
676 break;
677 case 'B': /* down */
678 move_cursor_row(strtol(str, (char **)&str, 10));
679 break;
680 case 'C': /* forward */
681 move_cursor_column(strtol(str, (char **)&str, 10));
682 break;
683 case 'D': /* back */
684 move_cursor_column(-strtol(str, (char **)&str, 10));
685 break;
686 case 'H':
687 if (!len)
688 move_cursor(0, 0);
689 else {
690 int row, col = 1;
691
692 row = strtol(str, (char **)&str, 10);
693 if (*str == ';') {
694 col = strtol(str+1, (char **)&str, 10);
695 }
696 move_cursor(col > 0 ? col-1 : 0, row > 0 ? row-1 : 0);
697 }
698 break;
699 case 'J':
700 erase_till_end_of_screen();
701 break;
702 case 'K':
703 erase_in_line();
704 break;
705 case '?':
706 if (strncmp(str+1, "1049", 4) == 0 &&
707 (str[5] == 'h' || str[5] == 'l') ) {
708 use_alt_buffer(str[5] == 'h');
709 func = str + 5;
710 break;
711 }
712 /* fall through */
713 default:
714 /* Unsupported code */
715 return pos;
716 }
717
718 return (char *)func + 1;
719}
720
721static BOOL charToConBuffA(LPSTR s, DWORD len)
722{
723 UINT acp = GetACP(), conocp = GetConsoleOutputCP();
724 CPINFO acp_info, con_info;
725 WCHAR *buf;
726
727 if (acp == conocp)
728 return TRUE;
729
730 if (!s || !GetCPInfo(acp, &acp_info) || !GetCPInfo(conocp, &con_info) ||
731 con_info.MaxCharSize > acp_info.MaxCharSize ||
732 (len == 1 && acp_info.MaxCharSize != 1))
733 return FALSE;
734
735 terminal_mode(FALSE);
736 buf = xmalloc(len*sizeof(WCHAR));
737 MultiByteToWideChar(CP_ACP, 0, s, len, buf, len);
738 WideCharToMultiByte(conocp, 0, buf, len, s, len, NULL, NULL);
739 free(buf);
740 return TRUE;
741}
742
743static BOOL charToConA(LPSTR s)
744{
745 if (!s)
746 return FALSE;
747 return charToConBuffA(s, strlen(s)+1);
748}
749
750BOOL conToCharBuffA(LPSTR s, DWORD len)
751{
752 UINT acp = GetACP(), conicp = GetConsoleCP();
753 CPINFO acp_info, con_info;
754 WCHAR *buf;
755
756 if (acp == conicp
757#if ENABLE_FEATURE_UTF8_INPUT
758 // if acp is UTF8 then we got UTF8 via readConsoleInput_utf8
759 || acp == CP_UTF8
760#endif
761 )
762 return TRUE;
763
764 if (!s || !GetCPInfo(acp, &acp_info) || !GetCPInfo(conicp, &con_info) ||
765 acp_info.MaxCharSize > con_info.MaxCharSize ||
766 (len == 1 && con_info.MaxCharSize != 1))
767 return FALSE;
768
769 terminal_mode(FALSE);
770 buf = xmalloc(len*sizeof(WCHAR));
771 MultiByteToWideChar(conicp, 0, s, len, buf, len);
772 WideCharToMultiByte(CP_ACP, 0, buf, len, s, len, NULL, NULL);
773 free(buf);
774 return TRUE;
775}
776
777static int ansi_emulate(const char *s, FILE *stream)
778{
779 int rv = 0;
780 const unsigned char *t;
781 char *pos, *str;
782 size_t cur_len;
783 static size_t max_len = 0;
784 static char *mem = NULL;
785
786 /* if no special treatment is required output the string as-is */
787 for ( t=(unsigned char *)s; *t; ++t ) {
788 if ( *t == '\033' || *t > 0x7f ) {
789 break;
790 }
791 }
792
793 if ( *t == '\0' ) {
794 return fputs(s, stream) == EOF ? EOF : strlen(s);
795 }
796
797 /*
798 * Make a writable copy of the string and retain array for reuse.
799 * The test above guarantees that the string length won't be zero
800 * so the array will always be allocated.
801 */
802 cur_len = strlen(s);
803 if ( cur_len > max_len ) {
804 free(mem);
805 mem = xstrdup(s);
806 max_len = cur_len;
807 }
808 else {
809 strcpy(mem, s);
810 }
811 pos = str = mem;
812
813 while (*pos) {
814 pos = strchr(str, '\033');
815 if (pos && !(terminal_mode(FALSE) & VT_OUTPUT)) {
816 size_t len = pos - str;
817
818 if (len) {
819 if (conv_fwriteCon(stream, str, len) == EOF)
820 return EOF;
821 rv += len;
822 }
823
824 if (fflush(stream) == EOF)
825 return EOF;
826
827 str = process_escape(pos);
828 if (str == pos) {
829 if (fputc('\033', stream) == EOF)
830 return EOF;
831 ++str;
832 }
833 rv += str - pos;
834 pos = str;
835
836 if (fflush(stream) == EOF)
837 return EOF;
838
839 } else {
840 size_t len = strlen(str);
841 rv += len;
842 return conv_fwriteCon(stream, str, len) == EOF ? EOF : rv;
843 }
844 }
845 return rv;
846}
847
848int winansi_putchar(int c)
849{
850 return winansi_fputc(c, stdout);
851}
852
853int winansi_puts(const char *s)
854{
855 return (winansi_fputs(s, stdout) == EOF || putchar('\n') == EOF) ? EOF : 0;
856}
857
858static sighandler_t sigpipe_handler = SIG_DFL;
859
860#undef signal
861sighandler_t winansi_signal(int signum, sighandler_t handler)
862{
863 sighandler_t old;
864
865 if (signum == SIGPIPE) {
866 old = sigpipe_handler;
867 sigpipe_handler = handler;
868 return old;
869 }
870 return signal(signum, handler);
871}
872
873static void check_pipe_fd(int fd)
874{
875 int error = GetLastError();
876
877 if ((error == ERROR_NO_DATA &&
878 GetFileType((HANDLE)_get_osfhandle(fd)) == FILE_TYPE_PIPE) ||
879 error == ERROR_BROKEN_PIPE) {
880 if (sigpipe_handler == SIG_DFL)
881 exit(128+SIGPIPE);
882 else /* SIG_IGN */
883 errno = EPIPE;
884 }
885}
886
887static void check_pipe(FILE *stream)
888{
889 int fd = fileno(stream);
890
891 if (fd != -1 && ferror(stream)) {
892 check_pipe_fd(fd);
893 }
894}
895
896size_t winansi_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
897{
898 size_t lsize, lmemb, ret;
899 char *str;
900 int rv;
901
902 lsize = MIN(size, nmemb);
903 lmemb = MAX(size, nmemb);
904 if (lsize != 1 || !is_console(fileno(stream))) {
905 SetLastError(0);
906 if ((ret=fwrite(ptr, size, nmemb, stream)) < nmemb)
907 check_pipe(stream);
908 return ret;
909 }
910
911 str = xmalloc(lmemb+1);
912 memcpy(str, ptr, lmemb);
913 str[lmemb] = '\0';
914
915 rv = ansi_emulate(str, stream);
916 free(str);
917
918 return rv == EOF ? 0 : nmemb;
919}
920
921int winansi_fputs(const char *str, FILE *stream)
922{
923 int ret;
924
925 if (!is_console(fileno(stream))) {
926 SetLastError(0);
927 if ((ret=fputs(str, stream)) == EOF)
928 check_pipe(stream);
929 return ret;
930 }
931
932 return ansi_emulate(str, stream) == EOF ? EOF : 0;
933}
934
935int winansi_fputc(int c, FILE *stream)
936{
937 int ret;
938 char t = c;
939 char *s = &t;
940
941 if ((unsigned char)c <= 0x7f || !is_console(fileno(stream))) {
942 SetLastError(0);
943 if ((ret=fputc(c, stream)) == EOF)
944 check_pipe(stream);
945 return ret;
946 }
947
948 return conv_fwriteCon(stream, s, 1) == EOF ? EOF : (unsigned char )c;
949}
950
951#if !defined(__USE_MINGW_ANSI_STDIO) || !__USE_MINGW_ANSI_STDIO
952/*
953 * Prior to Windows 10 vsnprintf was incompatible with the C99 standard.
954 * Implement a replacement using _vsnprintf.
955 */
956int winansi_vsnprintf(char *buf, size_t size, const char *format, va_list list)
957{
958 size_t len;
959 va_list list2;
960
961 va_copy(list2, list);
962 len = _vsnprintf(NULL, 0, format, list2);
963 va_end(list2);
964 if (len < 0)
965 return -1;
966
967 _vsnprintf(buf, size, format, list);
968 buf[size-1] = '\0';
969 return len;
970}
971#endif
972
973int winansi_vfprintf(FILE *stream, const char *format, va_list list)
974{
975 int len, rv;
976 char small_buf[256];
977 char *buf = small_buf;
978 va_list cp;
979
980 if (!is_console(fileno(stream)))
981 goto abort;
982
983 va_copy(cp, list);
984 len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
985 va_end(cp);
986
987 if (len > sizeof(small_buf) - 1) {
988 buf = xmalloc(len + 1);
989 va_copy(cp, list);
990 len = vsnprintf(buf, len + 1, format, cp);
991 va_end(cp);
992 }
993
994 if (len == -1)
995 goto abort;
996
997 rv = ansi_emulate(buf, stream);
998
999 if (buf != small_buf)
1000 free(buf);
1001 return rv;
1002
1003abort:
1004 SetLastError(0);
1005 if ((rv=vfprintf(stream, format, list)) == EOF || ferror(stream) != 0)
1006 check_pipe(stream);
1007 return rv;
1008}
1009
1010int winansi_fprintf(FILE *stream, const char *format, ...)
1011{
1012 va_list list;
1013 int rv;
1014
1015 va_start(list, format);
1016 rv = winansi_vfprintf(stream, format, list);
1017 va_end(list);
1018
1019 return rv;
1020}
1021
1022int winansi_printf(const char *format, ...)
1023{
1024 va_list list;
1025 int rv;
1026
1027 va_start(list, format);
1028 rv = winansi_vfprintf(stdout, format, list);
1029 va_end(list);
1030
1031 return rv;
1032}
1033
1034static int ansi_emulate_write(int fd, const void *buf, size_t count)
1035{
1036 int rv = 0, i;
1037 int special = FALSE, has_null = FALSE;
1038 const unsigned char *s = (const unsigned char *)buf;
1039 char *pos, *str;
1040 size_t len, out_len;
1041 static size_t max_len = 0;
1042 static char *mem = NULL;
1043
1044 for ( i=0; i<count; ++i ) {
1045 if ( s[i] == '\033' || s[i] > 0x7f ) {
1046 special = TRUE;
1047 }
1048 else if ( !s[i] ) {
1049 has_null = TRUE;
1050 }
1051 }
1052
1053 /*
1054 * If no special treatment is required or the data contains NUL
1055 * characters output the string as-is.
1056 */
1057 if ( !special || has_null ) {
1058 return write(fd, buf, count);
1059 }
1060
1061 /* make a writable copy of the data and retain array for reuse */
1062 if ( count > max_len ) {
1063 free(mem);
1064 mem = malloc(count+1);
1065 max_len = count;
1066 }
1067 memcpy(mem, buf, count);
1068 mem[count] = '\0';
1069 pos = str = mem;
1070
1071 /* we've checked the data doesn't contain any NULs */
1072 while (*pos) {
1073 pos = strchr(str, '\033');
1074 if (pos && !(terminal_mode(FALSE) & VT_OUTPUT)) {
1075 len = pos - str;
1076
1077 if (len) {
1078 out_len = conv_writeCon(fd, str, len);
1079 if (out_len == -1)
1080 return -1;
1081 rv += out_len;
1082 }
1083
1084 str = process_escape(pos);
1085 if (str == pos) {
1086 if (write(fd, pos, 1) == -1)
1087 return -1;
1088 ++str;
1089 }
1090 rv += str - pos;
1091 pos = str;
1092 } else {
1093 len = strlen(str);
1094 out_len = conv_writeCon(fd, str, len);
1095 return (out_len == -1) ? -1 : rv+out_len;
1096 }
1097 }
1098 return rv;
1099}
1100
1101int winansi_write(int fd, const void *buf, size_t count)
1102{
1103 if (!is_console(fd)) {
1104 int ret;
1105
1106 SetLastError(0);
1107 if ((ret=write(fd, buf, count)) == -1) {
1108 check_pipe_fd(fd);
1109 }
1110 return ret;
1111 }
1112
1113 return ansi_emulate_write(fd, buf, count);
1114}
1115
1116int winansi_read(int fd, void *buf, size_t count)
1117{
1118 int rv;
1119
1120 rv = mingw_read(fd, buf, count);
1121 if (!is_console_in(fd))
1122 return rv;
1123
1124 if ( rv > 0 ) {
1125 conToCharBuffA(buf, rv);
1126 }
1127
1128 return rv;
1129}
1130
1131size_t winansi_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
1132{
1133 int rv;
1134
1135 rv = fread(ptr, size, nmemb, stream);
1136 if (!is_console_in(fileno(stream)))
1137 return rv;
1138
1139 if (rv > 0)
1140 conToCharBuffA(ptr, rv * size);
1141
1142 return rv;
1143}
1144
1145int winansi_getc(FILE *stream)
1146{
1147 int rv;
1148
1149 rv = _getc_nolock(stream);
1150 if (!is_console_in(fileno(stream)))
1151 return rv;
1152
1153 if ( rv != EOF ) {
1154 unsigned char c = (unsigned char)rv;
1155 char *s = (char *)&c;
1156 conToCharBuffA(s, 1);
1157 rv = (int)c;
1158 }
1159
1160 return rv;
1161}
1162
1163int winansi_getchar(void)
1164{
1165 return winansi_getc(stdin);
1166}
1167
1168char *winansi_fgets(char *s, int size, FILE *stream)
1169{
1170 char *rv;
1171
1172 rv = fgets(s, size, stream);
1173 if (!is_console_in(fileno(stream)))
1174 return rv;
1175
1176 if (rv)
1177 conToCharBuffA(s, strlen(s));
1178
1179 return rv;
1180}
1181
1182/* Ensure that isatty(fd) returns 0 for the NUL device */
1183int mingw_isatty(int fd)
1184{
1185 int result = _isatty(fd);
1186
1187 if (result) {
1188 HANDLE handle = (HANDLE) _get_osfhandle(fd);
1189 DWORD mode;
1190
1191 if (handle == INVALID_HANDLE_VALUE)
1192 return 0;
1193
1194 /* check if its a device (i.e. console, printer, serial port) */
1195 if (GetFileType(handle) != FILE_TYPE_CHAR)
1196 return 0;
1197
1198 if (!GetConsoleMode(handle, &mode))
1199 return 0;
1200 }
1201
1202 return result;
1203}
1204
1205#if ENABLE_FEATURE_UTF8_INPUT
1206// intentionally also converts invalid values (surrogate halfs, too big)
1207static int toutf8(DWORD cp, unsigned char *buf) {
1208 if (cp <= 0x7f) {
1209 *buf = cp;
1210 return 1;
1211 }
1212 if (cp <= 0x7ff) {
1213 *buf++ = 0xc0 | (cp >> 6);
1214 *buf = 0x80 | (cp & 0x3f);
1215 return 2;
1216 }
1217 if (cp <= 0xffff) {
1218 *buf++ = 0xe0 | (cp >> 12);
1219 *buf++ = 0x80 | ((cp >> 6) & 0x3f);
1220 *buf = 0x80 | (cp & 0x3f);
1221 return 3;
1222 }
1223 if (cp <= 0x10ffff) {
1224 *buf++ = 0xf0 | (cp >> 18);
1225 *buf++ = 0x80 | ((cp >> 12) & 0x3f);
1226 *buf++ = 0x80 | ((cp >> 6) & 0x3f);
1227 *buf = 0x80 | (cp & 0x3f);
1228 return 4;
1229 }
1230 // invalid. returning 0 works in our context because it's delivered
1231 // as a key event, where 0 values are typically ignored by the caller
1232 *buf = 0;
1233 return 1;
1234}
1235
1236// peek into the console input queue and try to find a key-up event of
1237// a surrugate-2nd-half, at which case eat the console events up to this
1238// one (excluding), and combine the pair values into *ph1
1239static void maybeEatUpto2ndHalfUp(HANDLE h, DWORD *ph1)
1240{
1241 // Peek into the queue arbitrary 16 records deep
1242 INPUT_RECORD r[16];
1243 DWORD got;
1244 int i;
1245
1246 if (!PeekConsoleInputW(h, r, 16, &got))
1247 return;
1248
1249 // we're conservative, and abort the search on anything which
1250 // seems out of place, like non-key event, non-2nd-half, etc.
1251 // search from 1 because i==0 is still the 1st half down record.
1252 for (i = 1; i < got; ++i) {
1253 DWORD h2;
1254 int is2nd, isdown;
1255
1256 if (r[i].EventType != KEY_EVENT)
1257 return;
1258
1259 isdown = r[i].Event.KeyEvent.bKeyDown;
1260 h2 = r[i].Event.KeyEvent.uChar.UnicodeChar;
1261 is2nd = h2 >= 0xDC00 && h2 <= 0xDFFF;
1262
1263 // skip 0 values, keyup of 1st half, and keydown of a 2nd half, if any
1264 if (!h2 || (h2 == *ph1 && !isdown) || (is2nd && isdown))
1265 continue;
1266
1267 if (!is2nd)
1268 return;
1269
1270 // got 2nd-half-up. eat the events up to this, combine the values
1271 ReadConsoleInputW(h, r, i, &got);
1272 *ph1 = 0x10000 + (((*ph1 & ~0xD800) << 10) | (h2 & ~0xDC00));
1273 return;
1274 }
1275}
1276
1277// if the codepoint is a key-down event, remember it, else if
1278// it's a key-up event with matching prior down - forget the down,
1279// else (up without matching prior key-down) - change it to down.
1280// We remember few prior key-down events so that a sequence
1281// like X-down Y-down X-up Y-up won't trigger this hack for Y-up.
1282// When up is changed into down there won't be further key-up event,
1283// but that's OK because the caller ignores key-up events anyway.
1284static void maybe_change_up_to_down(wchar_t key, BOOL *isdown)
1285{
1286 #define DOWN_BUF_SIZ 8
1287 static wchar_t downbuf[DOWN_BUF_SIZ] = {0};
1288 static int pos = 0;
1289
1290 if (*isdown) {
1291 downbuf[pos++] = key;
1292 pos = pos % DOWN_BUF_SIZ;
1293 return;
1294 }
1295
1296 // the missing-key-down issue was only observed with unicode values,
1297 // so limit this hack to non-ASCII-7 values.
1298 // also, launching a new shell/read process from CLI captures
1299 // an ENTER-up event without prior down at this new process, which
1300 // would otherwise change it to down - creating a wrong ENTER keypress.
1301 if (key <= 127)
1302 return;
1303
1304 // key up, try to match a prior down
1305 for (int i = 0; i < DOWN_BUF_SIZ; ++i) {
1306 if (downbuf[i] == key) {
1307 downbuf[i] = 0; // "forget" this down
1308 return;
1309 }
1310 }
1311
1312 // no prior key-down - replace the up with down
1313 *isdown = TRUE;
1314}
1315
1316/*
1317 * readConsoleInput_utf8 behaves similar enough to ReadConsoleInputA when
1318 * the console (input) CP is UTF8, but addressed two issues:
1319 * - It depend on the console CP, while we use ReadConsoleInputW internally.
1320 * - ReadConsoleInputA with Console CP of UTF8 (65001) is buggy:
1321 * - Doesn't work on Windows 7 (reads 0 or '?' for non-ASCII codepoints).
1322 * - When used at the cmd.exe console - but not Windows Terminal:
1323 * sometimes only key-up events arrive without the expected prior key-down.
1324 * Seems to depend both on the console CP and the entered/pasted codepoint.
1325 * - If reading one record at a time (which is how we use it), then input
1326 * codepoints of U+0800 or higher crash the console/terminal window.
1327 * (tested on Windows 10.0.19045.3086: console and Windows Terminal 1.17)
1328 * Example: U+0C80 (UTF8: 0xE0 0xB2 0x80): "ಀ"
1329 * Example: U+1F600 (UTF8: 0xF0 0x9F 0x98 0x80): "😀"
1330 * - If reading more than one record at a time:
1331 * - Unknown whether it can still crash in some cases (was not observed).
1332 * - Codepoints above U+FFFF are broken, and arrive as
1333 * U+FFFD REPLACEMENT CHARACTER "�"
1334 * - Few more codepoints to test the issues above (and below):
1335 * - U+0500 (UTF8: 0xD4, 0x80): "Ԁ" (OK in UTF8 CP, else maybe no key-down)
1336 * - U+07C0 (UTF8: 0xDF, 0x80): "߀" (might exhibit missing key-down)
1337 *
1338 * So this function uses ReadConsoleInputW and then delivers it as UTF8:
1339 * - Works with any console CP, in Windows terminal and Windows 7/10 console.
1340 * - Surrogate pairs are combined and delivered as a single UTF8 codepoint.
1341 * - Ignore occasional intermediate control events between the halfs.
1342 * - If we can't find the 2nd half, or if for some reason we get a 2nd half
1343 * wiithout the 1st, deliver the half we got as UTF8 (a-la WTF8).
1344 * - The "sometimes key-down is missing" issue at the cmd.exe console happens
1345 * also when using ReadConsoleInputW (for U+0080 or higher), so handle it.
1346 * This can also happen with surrogate pairs.
1347 * - Up to 4-bytes state is maintained for a single UTF8 codepoint buffer.
1348 *
1349 * Gotchas (could be solved, but currently there's no need):
1350 * - We support reading one record at a time, else fail - to make it obvious.
1351 * - We have a state which is hidden from PeekConsoleInput - so not in sync.
1352 * - We don't deliver key-up events in some cases: when working around
1353 * the "missing key-down" issue, and with combined surrogate halfs value.
1354 */
1355BOOL readConsoleInput_utf8(HANDLE h, INPUT_RECORD *r, DWORD len, DWORD *got)
1356{
1357 static unsigned char u8buf[4]; // any single codepoint in UTF8
1358 static int u8pos = 0, u8len = 0;
1359 static INPUT_RECORD srec;
1360
1361 if (len != 1)
1362 return FALSE;
1363
1364 // if ACP is UTF8 then we read UTF8 regardless of console (in) CP
1365 if (GetConsoleCP() != CP_UTF8 && GetACP() != CP_UTF8)
1366 return ReadConsoleInput(h, r, len, got);
1367
1368 if (u8pos == u8len) {
1369 DWORD codepoint;
1370
1371 // wait-and-peek rather than read to keep the last processed record
1372 // at the console queue until we deliver all of its products, so
1373 // that external WaitForSingleObject(h) shows there's data ready.
1374 if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0)
1375 return FALSE;
1376 if (!PeekConsoleInputW(h, r, 1, got))
1377 return FALSE;
1378 if (*got == 0)
1379 return TRUE;
1380 if (r->EventType != KEY_EVENT)
1381 return ReadConsoleInput(h, r, 1, got);
1382
1383 srec = *r;
1384 codepoint = srec.Event.KeyEvent.uChar.UnicodeChar;
1385
1386 // Observed when pasting unicode at cmd.exe console (but not
1387 // windows terminal), we sometimes get key-up event without
1388 // a prior matching key-down (or with key-down codepoint 0),
1389 // so this call would change the up into down in such case.
1390 // E.g. pastes fixed by this hack: U+1F600 "😀", or U+0C80 "ಀ"
1391 if (codepoint)
1392 maybe_change_up_to_down(codepoint, &srec.Event.KeyEvent.bKeyDown);
1393
1394 // if it's a 1st (high) surrogate pair half, try to eat upto and
1395 // excluding the 2nd (low) half, and combine them into codepoint.
1396 // this does not interfere with the missing-key-down workaround
1397 // (no issue if the down-buffer has 1st-half-down without up).
1398 if (codepoint >= 0xD800 && codepoint <= 0xDBFF)
1399 maybeEatUpto2ndHalfUp(h, &codepoint);
1400
1401 u8len = toutf8(codepoint, u8buf);
1402 u8pos = 0;
1403 }
1404
1405 *r = srec;
1406 r->Event.KeyEvent.uChar.AsciiChar = (char)u8buf[u8pos++];
1407 if (u8pos == u8len) // consume the record which generated this buffer
1408 ReadConsoleInputW(h, &srec, 1, got);
1409 *got = 1;
1410 return TRUE;
1411}
1412#else
1413/*
1414 * In Windows 10 and 11 using ReadConsoleInputA() with a console input
1415 * code page of CP_UTF8 can crash the console/terminal. Avoid this by
1416 * using ReadConsoleInputW() in that case.
1417 */
1418BOOL readConsoleInput_utf8(HANDLE h, INPUT_RECORD *r, DWORD len, DWORD *got)
1419{
1420 if (GetConsoleCP() != CP_UTF8)
1421 return ReadConsoleInput(h, r, len, got);
1422
1423 if (ReadConsoleInputW(h, r, len, got)) {
1424 wchar_t uchar = r->Event.KeyEvent.uChar.UnicodeChar;
1425 char achar = uchar & 0x7f;
1426 if (achar != uchar)
1427 achar = '?';
1428 r->Event.KeyEvent.uChar.AsciiChar = achar;
1429 return TRUE;
1430 }
1431 return FALSE;
1432}
1433#endif
1434
1435#if ENABLE_FEATURE_UTF8_OUTPUT
1436// Write u8buf as if the console output CP is UTF8 - regardless of the CP.
1437// fd should be associated with a console output.
1438// Return: 0 on successful write[s], else -1 (e.g. if fd is not a console).
1439//
1440// Up to 3 bytes of an incomplete codepoint may be buffered from prior call[s].
1441// All the completed codepoints in one call are written using WriteConsoleW.
1442// Bad sequence of any length (till ASCII7 or UTF8 lead) prints 1 subst wchar.
1443//
1444// note: one console is assumed, and the (3 bytes) buffer is shared regardless
1445// of the original output stream (stdout/err), or even if the handle is
1446// of a different console. This can result in invalid codepoints output
1447// if streams are multiplexed mid-codepoint (same as elsewhere?)
1448static int writeCon_utf8(int fd, const char *u8buf, size_t u8siz)
1449{
1450 static int state = 0; // -1: bad, 0-3: remaining cp bytes (0: done/new)
1451 static uint32_t codepoint = 0; // accumulated from up to 4 UTF8 bytes
1452
1453 // not a state, only avoids re-alloc on every call
1454 static const int wbufwsiz = 4096;
1455 static wchar_t *wbuf = 0;
1456
1457 HANDLE h = (HANDLE)_get_osfhandle(fd);
1458 int wlen = 0;
1459
1460 if (!wbuf)
1461 wbuf = xmalloc(wbufwsiz * sizeof(wchar_t));
1462
1463 // ASCII7 uses least logic, then UTF8 continuations, UTF8 lead, errors
1464 while (u8siz--) {
1465 unsigned char c = *u8buf++;
1466 int topbits = 0;
1467
1468 while (c & (0x80 >> topbits))
1469 ++topbits;
1470
1471 if (state == 0 && topbits == 0) {
1472 // valid ASCII7, state remains 0
1473 codepoint = c;
1474
1475 } else if (state > 0 && topbits == 1) {
1476 // valid continuation byte
1477 codepoint = (codepoint << 6) | (c & 0x3f);
1478 if (--state)
1479 continue;
1480
1481 } else if (state == 0 && topbits >= 2 && topbits <= 4) {
1482 // valid UTF8 lead of 2/3/4 bytes codepoint
1483 codepoint = c & (0x7f >> topbits);
1484 state = topbits - 1; // remaining bytes after lead
1485 continue;
1486
1487 } else {
1488 // already bad (state<0), or unexpected c at state 0-3.
1489 // placeholder is added only at the 1st (state>=0).
1490 // regardless, c may be valid to reprocess as state 0
1491 // (even when it's the 1st unexpected in state 1/2/3)
1492 int placeholder_done = state < 0;
1493
1494 if (topbits < 5 && topbits != 1) {
1495 --u8buf; // valid for state 0, reprocess
1496 ++u8siz;
1497 state = 0;
1498 } else {
1499 state = -1; // set/keep bad state
1500 }
1501
1502 if (placeholder_done)
1503 continue;
1504
1505 // 1st unexpected char, add placeholder
1506 codepoint = CONFIG_SUBST_WCHAR;
1507 }
1508
1509 // codepoint is complete
1510 // we don't reject surrogate halves, reserved, etc
1511 if (codepoint < 0x10000) {
1512 wbuf[wlen++] = codepoint;
1513 } else {
1514 // generate a surrogates pair (wbuf has room for 2+)
1515 codepoint -= 0x10000;
1516 wbuf[wlen++] = 0xd800 | (codepoint >> 10);
1517 wbuf[wlen++] = 0xdc00 | (codepoint & 0x3ff);
1518 }
1519
1520 // flush if we have less than two empty spaces
1521 if (wlen > wbufwsiz - 2) {
1522 if (!WriteConsoleW(h, wbuf, wlen, 0, 0))
1523 return -1;
1524 wlen = 0;
1525 }
1526 }
1527
1528 if (wlen && !WriteConsoleW(h, wbuf, wlen, 0, 0))
1529 return -1;
1530 return 0;
1531}
1532#endif
1533
1534void console_write(const char *str, int len)
1535{
1536 char *buf = xmemdup(str, len);
1537 int fd = _open("CONOUT$", _O_WRONLY);
1538 conv_writeCon(fd, buf, len);
1539 close(fd);
1540 free(buf);
1541}
1542
1543// LC_ALL=C disables console output conversion, so that the source
1544// data is interpreted only by the console according to its output CP.
1545static int conout_conv_enabled(void)
1546{
1547 static int enabled, tested; /* = 0 */
1548
1549 if (!tested) {
1550 // keep in sync with [re]init_unicode at libbb/unicode.c
1551 char *s = getenv("LC_ALL");
1552 if (!s) s = getenv("LC_CTYPE");
1553 if (!s) s = getenv("LANG");
1554
1555 enabled = !(s && s[0] == 'C' && s[1] == 0);
1556 tested = 1;
1557 }
1558
1559 return enabled;
1560}
1561
1562// TODO: improvements:
1563//
1564// 1. currently conv_[f]writeCon modify buf inplace, which means the caller
1565// typically has to make a writable copy first just for this.
1566// Sometimes it allocates a big copy once, and calls us with substrings.
1567// Instead, we could make a writable copy here - it's not used later anyway.
1568// To avoid the performance hit of many small allocations, we could use
1569// a local buffer for short strings, and allocate only if it doesn't fit
1570// (or maybe just reuse the local buffer with substring iterations).
1571//
1572// 2. Instead of converting from ACP to the console out CP - which guarantees
1573// potential data-loss if they differ, we could convert it to wchar_t and
1574// write it using WriteConsoleW. This should prevent all output data-loss.
1575// care should be taken with DBCS codepages (e.g. 936) or other multi-byte
1576// because then converting on arbitrary substring boundaries can fail.
1577
1578// convert buf inplace from ACP to console out CP and write it to stream
1579// returns EOF on error, 0 on success
1580static int conv_fwriteCon(FILE *stream, char *buf, size_t siz)
1581{
1582 if (conout_conv_enabled()) {
1583#if ENABLE_FEATURE_UTF8_OUTPUT
1584 if (GetConsoleOutputCP() != CP_UTF8) {
1585 fflush(stream); // writeCon_utf8 is unbuffered
1586 return writeCon_utf8(fileno(stream), buf, siz) ? EOF : 0;
1587 }
1588#else
1589 charToConBuffA(buf, siz);
1590#endif
1591 }
1592 return fwrite(buf, 1, siz, stream) < siz ? EOF : 0;
1593}
1594
1595// similar to above, but using lower level write
1596// returns -1 on error, actually-written bytes on suceess
1597static int conv_writeCon(int fd, char *buf, size_t siz)
1598{
1599 if (conout_conv_enabled()) {
1600#if ENABLE_FEATURE_UTF8_OUTPUT
1601 if (GetConsoleOutputCP() != CP_UTF8)
1602 return writeCon_utf8(fd, buf, siz) ? -1 : siz;
1603#else
1604 charToConBuffA(buf, siz);
1605#endif
1606 }
1607 return write(fd, buf, siz);
1608}