diff options
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 | ||
@@ -9,6 +9,20 @@ config HAVE_DOT_CONFIG | |||
9 | bool | 9 | bool |
10 | default y | 10 | default y |
11 | 11 | ||
12 | choice | ||
13 | prompt "Target platform" | ||
14 | default PLATFORM_POSIX | ||
15 | help | ||
16 | Target platform you are building busybox for | ||
17 | |||
18 | config PLATFORM_POSIX | ||
19 | bool "POSIX" | ||
20 | |||
21 | config PLATFORM_MINGW32 | ||
22 | bool "MS Windows (MinGW port)" | ||
23 | |||
24 | endchoice | ||
25 | |||
12 | menu "Settings" | 26 | menu "Settings" |
13 | 27 | ||
14 | config DESKTOP | 28 | config 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 | ||
385 | comment 'Settings for MINGW32' | ||
386 | |||
387 | config 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 | |||
399 | choice | ||
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 | |||
412 | config FEATURE_PRNG_SHELL | ||
413 | bool "Use shell PRNG" | ||
414 | |||
415 | config FEATURE_PRNG_ISAAC | ||
416 | bool "Use ISAAC PRNG" | ||
417 | |||
418 | endchoice | ||
419 | |||
420 | config 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 | |||
428 | config 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 | |||
435 | choice | ||
436 | prompt "Manifest" | ||
437 | default FEATURE_APP_MANIFEST | ||
438 | depends on FEATURE_RESOURCES | ||
439 | help | ||
440 | Manifest to include in resources. | ||
441 | |||
442 | config 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 | |||
449 | config 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 | |||
455 | config 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 | |||
463 | endchoice | ||
464 | |||
465 | config 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 | |||
474 | choice | ||
475 | prompt "Application icon" | ||
476 | default FEATURE_ICON_ALL | ||
477 | depends on FEATURE_ICON | ||
478 | |||
479 | config FEATURE_ICON_ATERM | ||
480 | bool "Adwaita terminal" | ||
481 | |||
482 | config FEATURE_ICON_STERM | ||
483 | bool "Adwaita terminal (symbolic)" | ||
484 | |||
485 | config FEATURE_ICON_ALL | ||
486 | bool "All available icons" | ||
487 | |||
488 | endchoice | ||
489 | |||
490 | config 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 | |||
499 | config 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 | |||
508 | config 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 | |||
518 | config 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 | |||
539 | config 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 | |||
547 | config 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 | |||
559 | config 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 | |||
371 | comment 'Build Options' | 569 | comment 'Build Options' |
372 | 570 | ||
373 | config STATIC | 571 | config 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 | ||
692 | config HOST_COMPILER | ||
693 | string "Host compiler" | ||
694 | default "gcc" | ||
695 | help | ||
696 | Name of the compiler to use for host binaries. | ||
697 | |||
698 | config CROSS_COMPILER | ||
699 | string "Cross compiler" | ||
700 | default "gcc" | ||
701 | help | ||
702 | Name of the compiler to use for cross compilation. | ||
703 | |||
494 | config SYSROOT | 704 | config SYSROOT |
495 | string "Path to sysroot" | 705 | string "Path to sysroot" |
496 | default "" | 706 | default "" |
@@ -4,6 +4,10 @@ SUBLEVEL = 0 | |||
4 | EXTRAVERSION = .git | 4 | EXTRAVERSION = .git |
5 | NAME = Unnamed | 5 | NAME = Unnamed |
6 | 6 | ||
7 | # Colon is used as a separator in makefiles. Strip any drive prefix | ||
8 | # from the current directory to avoid confusion. | ||
9 | CURDIR := $(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 |
193 | UTS_MACHINE := $(ARCH) | 197 | UTS_MACHINE := $(ARCH) |
194 | 198 | ||
199 | HOST_COMPILER ?= | ||
200 | ifeq ($(HOST_COMPILER),) | ||
201 | HOST_COMPILER := $(shell grep ^CONFIG_HOST_COMPILER= .config 2>/dev/null) | ||
202 | HOST_COMPILER := $(subst CONFIG_HOST_COMPILER=,,$(HOST_COMPILER)) | ||
203 | HOST_COMPILER := $(subst ",,$(HOST_COMPILER)) | ||
204 | #") | ||
205 | endif | ||
206 | ifeq ($(HOST_COMPILER),) | ||
207 | HOST_COMPILER := gcc | ||
208 | endif | ||
209 | |||
210 | CROSS_COMPILER ?= | ||
211 | ifeq ($(CROSS_COMPILER),) | ||
212 | CROSS_COMPILER := $(shell grep ^CONFIG_CROSS_COMPILER= .config 2>/dev/null) | ||
213 | CROSS_COMPILER := $(subst CONFIG_CROSS_COMPILER=,,$(CROSS_COMPILER)) | ||
214 | CROSS_COMPILER := $(subst ",,$(CROSS_COMPILER)) | ||
215 | #") | ||
216 | endif | ||
217 | ifeq ($(CROSS_COMPILER),) | ||
218 | CROSS_COMPILER := gcc | ||
219 | endif | ||
220 | |||
195 | # SHELL used by kbuild | 221 | # SHELL used by kbuild |
196 | CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ | 222 | CONFIG_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 | |||
291 | ifeq ($(filter 3.%,$(MAKE_VERSION)),) | ||
292 | short-opts := $(firstword -$(MAKEFLAGS)) | ||
293 | else | ||
294 | short-opts := $(filter-out --%,$(MAKEFLAGS)) | ||
295 | endif | ||
263 | 296 | ||
264 | ifneq ($(findstring s,$(MAKEFLAGS)),) | 297 | ifneq ($(findstring s,$(short-opts)),) |
265 | quiet=silent_ | 298 | quiet=silent_ |
266 | endif | 299 | endif |
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 |
272 | MAKEFLAGS += --include-dir=$(srctree) | 305 | MAKEFLAGS += --include-dir=$(srctree) |
273 | 306 | ||
274 | HOSTCC = gcc | 307 | HOSTCC = $(HOST_COMPILER) |
275 | HOSTCXX = g++ | 308 | HOSTCXX = g++ |
276 | HOSTCFLAGS := | 309 | HOSTCFLAGS := |
277 | HOSTCXXFLAGS := | 310 | HOSTCXXFLAGS := |
@@ -289,7 +322,7 @@ MAKEFLAGS += -rR | |||
289 | # Make variables (CC, etc...) | 322 | # Make variables (CC, etc...) |
290 | 323 | ||
291 | AS = $(CROSS_COMPILE)as | 324 | AS = $(CROSS_COMPILE)as |
292 | CC = $(CROSS_COMPILE)gcc | 325 | CC = $(CROSS_COMPILE)$(CROSS_COMPILER) |
293 | LD = $(CC) -nostdlib | 326 | LD = $(CC) -nostdlib |
294 | CPP = $(CC) -E | 327 | CPP = $(CC) -E |
295 | AR = $(CROSS_COMPILE)ar | 328 | AR = $(CROSS_COMPILE)ar |
@@ -297,6 +330,7 @@ NM = $(CROSS_COMPILE)nm | |||
297 | STRIP = $(CROSS_COMPILE)strip | 330 | STRIP = $(CROSS_COMPILE)strip |
298 | OBJCOPY = $(CROSS_COMPILE)objcopy | 331 | OBJCOPY = $(CROSS_COMPILE)objcopy |
299 | OBJDUMP = $(CROSS_COMPILE)objdump | 332 | OBJDUMP = $(CROSS_COMPILE)objdump |
333 | WINDRES = $(CROSS_COMPILE)windres | ||
300 | PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config | 334 | PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config |
301 | AWK = awk | 335 | AWK = awk |
302 | GENKSYMS = scripts/genksyms/genksyms | 336 | GENKSYMS = scripts/genksyms/genksyms |
@@ -305,6 +339,15 @@ KALLSYMS = scripts/kallsyms | |||
305 | PERL = perl | 339 | PERL = perl |
306 | CHECK = sparse | 340 | CHECK = sparse |
307 | 341 | ||
342 | # Handle MSYS2 weirdness | ||
343 | ifneq ($(CROSS_COMPILE),) | ||
344 | ifeq ($(shell _= command -v $(AR)),) | ||
345 | AR := $(CROSS_COMPILE)gcc-ar | ||
346 | STRIP := strip | ||
347 | WINDRES := windres | ||
348 | endif | ||
349 | endif | ||
350 | |||
308 | CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise $(CF) | 351 | CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise $(CF) |
309 | MODFLAGS = -DMODULE | 352 | MODFLAGS = -DMODULE |
310 | CFLAGS_MODULE = $(MODFLAGS) | 353 | CFLAGS_MODULE = $(MODFLAGS) |
@@ -312,6 +355,7 @@ AFLAGS_MODULE = $(MODFLAGS) | |||
312 | LDFLAGS_MODULE = -r | 355 | LDFLAGS_MODULE = -r |
313 | CFLAGS_KERNEL = | 356 | CFLAGS_KERNEL = |
314 | AFLAGS_KERNEL = | 357 | AFLAGS_KERNEL = |
358 | EXEEXT = | ||
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) | |||
324 | LDFLAGS := $(LDFLAGS) | 368 | LDFLAGS := $(LDFLAGS) |
325 | LDLIBS := | 369 | LDLIBS := |
326 | 370 | ||
371 | CONFIG_PLATFORM_MINGW32 ?= | ||
372 | ifeq ($(CONFIG_PLATFORM_MINGW32),) | ||
373 | CONFIG_PLATFORM_MINGW32 := $(shell grep ^CONFIG_PLATFORM_MINGW32= .config 2>/dev/null) | ||
374 | CONFIG_PLATFORM_MINGW32 := $(subst CONFIG_PLATFORM_MINGW32=,,$(CONFIG_PLATFORM_MINGW32)) | ||
375 | CONFIG_PLATFORM_MINGW32 := $(subst ",,$(CONFIG_PLATFORM_MINGW32)) | ||
376 | #") | ||
377 | endif | ||
378 | |||
379 | # Try various methods to get a more specific EXTRAVERSION, but only | ||
380 | # for MINGW32 platform and if EXTRAVERSION is default '.git' | ||
381 | ifeq ($(CONFIG_PLATFORM_MINGW32)$(EXTRAVERSION),y.git) | ||
382 | # Ask git | ||
383 | extraversion := $(shell cd $(srctree) && git describe --match FRP 2>/dev/null) | ||
384 | ifeq ($(strip $(extraversion)),) | ||
385 | # That didn't work, look for a .frp_describe file | ||
386 | extraversion := $(shell grep '^FRP-' $(srctree)/.frp_describe 2>/dev/null) | ||
387 | ifeq ($(strip $(extraversion)),) | ||
388 | # That didn't work either, look at name of source directory | ||
389 | e1 := $(shell basename $(srctree) | grep '^busybox-w32-FRP-') | ||
390 | ifneq ($(strip $(e1)),) | ||
391 | extraversion := $(subst busybox-w32-,,$(e1)) | ||
392 | endif | ||
393 | endif | ||
394 | endif | ||
395 | |||
396 | ifneq ($(strip $(extraversion)),) | ||
397 | EXTRAVERSION := .$(subst FRP,git,$(extraversion)) | ||
398 | endif | ||
399 | endif | ||
400 | |||
327 | # Read KERNELRELEASE from .kernelrelease (if it exists) | 401 | # Read KERNELRELEASE from .kernelrelease (if it exists) |
328 | KERNELRELEASE = $(shell cat .kernelrelease 2> /dev/null) | 402 | KERNELRELEASE = $(shell cat .kernelrelease 2> /dev/null) |
329 | KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) | 403 | KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) |
330 | 404 | ||
331 | export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION \ | 405 | export 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 | ||
336 | export CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS | 410 | export 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 |
463 | core-y := \ | 537 | core-y := \ |
464 | applets/ \ | 538 | applets/ \ |
539 | win32/resources/ \ | ||
465 | 540 | ||
466 | libs-y := \ | 541 | libs-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 | ||
496 | endif # KBUILD_EXTMOD | 572 | endif # 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 |
535 | all: busybox doc | 611 | all: 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) | |||
715 | endif # ifdef CONFIG_KALLSYMS | 791 | endif # ifdef CONFIG_KALLSYMS |
716 | 792 | ||
717 | # busybox image - including updated kernel symbols | 793 | # busybox image - including updated kernel symbols |
718 | busybox_unstripped: $(busybox-all) FORCE | 794 | busybox_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 | ||
722 | busybox: busybox_unstripped | 798 | busybox$(EXEEXT): busybox_unstripped$(EXEEXT) |
723 | ifeq ($(SKIP_STRIP),y) | 799 | ifeq ($(SKIP_STRIP),y) |
724 | $(Q)cp $< $@ | 800 | $(Q)cp $< $@ |
725 | else | 801 | else |
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 $@ |
730 | endif | 806 | endif |
@@ -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 |
817 | prepare2: prepare3 outputmakefile | 893 | prepare2: prepare3 outputmakefile |
818 | 894 | ||
819 | prepare1: prepare2 include/config/MARKER | 895 | prepare1: prepare2 include/config/MARKER include/BB_VER.h |
820 | ifneq ($(KBUILD_MODULES),) | 896 | ifneq ($(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 | ) |
881 | endef | 957 | endef |
882 | 958 | ||
959 | define filechk_BB_VER.h | ||
960 | (echo \#define BB_VER \"$(KERNELRELEASE)\";) | ||
961 | endef | ||
962 | |||
963 | include/BB_VER.h: $(srctree)/Makefile .config .kernelrelease FORCE | ||
964 | $(call filechk,BB_VER.h) | ||
965 | |||
883 | # --------------------------------------------------------------------------- | 966 | # --------------------------------------------------------------------------- |
884 | 967 | ||
885 | PHONY += depend dep | 968 | PHONY += 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' |
968 | CLEAN_DIRS += $(MODVERDIR) _install 0_lib | 1051 | CLEAN_DIRS += $(MODVERDIR) _install 0_lib |
969 | CLEAN_FILES += busybox busybox_unstripped* busybox.links \ | 1052 | CLEAN_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 \ | |||
975 | MRPROPER_DIRS += include/config include2 | 1058 | MRPROPER_DIRS += include/config include2 |
976 | MRPROPER_FILES += .config .config.old include/asm .version .old_version \ | 1059 | MRPROPER_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 |
107 | sizes: busybox_unstripped | 107 | sizes: busybox_unstripped$(EXEEXT) |
108 | $(NM) --size-sort $(<) | 108 | $(NM) --size-sort $(<) |
109 | 109 | ||
110 | .PHONY: bloatcheck | 110 | .PHONY: bloatcheck |
111 | bloatcheck: busybox_old busybox_unstripped | 111 | bloatcheck: 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 |
116 | baseline: busybox_unstripped | 116 | baseline: 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 |
120 | objsizes: busybox_unstripped | 120 | objsizes: busybox_unstripped$(EXEEXT) |
121 | $(srctree)/scripts/objsizes | 121 | $(srctree)/scripts/objsizes |
122 | 122 | ||
123 | .PHONY: stksizes | 123 | .PHONY: stksizes |
124 | stksizes: busybox_unstripped | 124 | stksizes: 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 |
128 | bigdata: busybox_unstripped | 128 | bigdata: 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 | ||
21 | CFLAGS += $(call cc-option,-Wall,) | 22 | CFLAGS += $(call cc-option,-Wall,) |
22 | CFLAGS += $(call cc-option,-Wshadow,) | 23 | CFLAGS += $(call cc-option,-Wshadow,) |
@@ -146,6 +147,18 @@ CFLAGS += --sysroot=$(CONFIG_SYSROOT) | |||
146 | export SYSROOT=$(CONFIG_SYSROOT) | 147 | export SYSROOT=$(CONFIG_SYSROOT) |
147 | endif | 148 | endif |
148 | 149 | ||
150 | ifeq ($(CONFIG_PLATFORM_MINGW32),y) | ||
151 | CFLAGS += -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 | ||
153 | ifeq ($(lastword $(subst -, ,$(CC))),clang) | ||
154 | CFLAGS += $(call cc-option,-fsjlj-exceptions,) | ||
155 | endif | ||
156 | |||
157 | EXEEXT = .exe | ||
158 | LDLIBS += ws2_32 | ||
159 | endif | ||
160 | |||
161 | ifneq ($(CONFIG_PLATFORM_MINGW32),y) | ||
149 | # libm may be needed for dc, awk, ntpd | 162 | # libm may be needed for dc, awk, ntpd |
150 | LDLIBS += m | 163 | LDLIBS += m |
151 | # Android has no separate crypt library | 164 | # Android has no separate crypt library |
@@ -161,6 +174,7 @@ endif | |||
161 | ifeq ($(RT_AVAILABLE),y) | 174 | ifeq ($(RT_AVAILABLE),y) |
162 | LDLIBS += rt | 175 | LDLIBS += rt |
163 | endif | 176 | endif |
177 | endif | ||
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. |
@@ -1,3 +1,4 @@ | |||
1 | Please see README.md for Windows-specific info. | ||
1 | Please see the LICENSE file for details on copying and usage. | 2 | Please see the LICENSE file for details on copying and usage. |
2 | Please refer to the INSTALL file for instructions on how to build. | 3 | Please refer to the INSTALL file for instructions on how to build. |
3 | 4 | ||
diff --git a/README.md b/README.md new file mode 100644 index 000000000..2de1f89aa --- /dev/null +++ b/README.md | |||
@@ -0,0 +1,41 @@ | |||
1 | ### Status | ||
2 | |||
3 | Things may work for you, or may not. Things may never work because of huge differences between Linux and Windows. Or things may work in future, if you report the problem 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 | |||
5 | Additional 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 | |||
12 | You 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 | |||
20 | On 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 | |||
22 | On 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 | |||
24 | Then just `make`. | ||
25 | |||
26 | See 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 |
17 | fi | 17 | fi |
18 | 18 | ||
19 | ( | ||
19 | exec >"$target.$$" | 20 | exec >"$target.$$" |
20 | 21 | ||
21 | echo '#define UNPACKED_USAGE "" \' | 22 | echo '#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/$/ \\/' |
60 | echo '' | 61 | echo '' |
62 | ) | ||
61 | 63 | ||
62 | mv -- "$target.$$" "$target" | 64 | mv -- "$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 | ||
152 | enum operator_e { | 157 | enum 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 | ||
48 | lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o | 48 | lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o |
49 | lib-$(CONFIG_CPIO) += get_header_cpio.o | 49 | lib-$(CONFIG_CPIO) += get_header_cpio.o |
50 | lib-$(CONFIG_MAKE) += get_header_ar.o unpack_ar_archive.o | ||
51 | lib-$(CONFIG_PDPMAKE) += get_header_ar.o unpack_ar_archive.o | ||
50 | lib-$(CONFIG_TAR) += get_header_tar.o unsafe_prefix.o | 52 | lib-$(CONFIG_TAR) += get_header_tar.o unsafe_prefix.o |
51 | lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o | 53 | lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o |
52 | lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o | 54 | lib-$(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 | ||
1140 | static int check_header_gzip(STATE_PARAM transformer_state_t *xstate) | 1143 | static 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 | ||
1212 | IF_DESKTOP(long long) int FAST_FUNC | 1218 | IF_DESKTOP(long long) int FAST_FUNC |
1213 | unpack_gz_stream(transformer_state_t *xstate) | 1219 | unpack_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 | ||
67 | void check_errors_in_children(int signo) | 68 | void 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 */ | ||
155 | void 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 | ||
27 | void FAST_FUNC create_links_from_list(llist_t *list) | 35 | void 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 | ||
243 | static void fileaction_setowngrp(char *filename, int fileref) | 253 | static 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 | ||
253 | static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref)) | 264 | static 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 */ |
573 | static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) | 584 | static 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 | # | ||
6 | CONFIG_HAVE_DOT_CONFIG=y | ||
7 | # CONFIG_PLATFORM_POSIX is not set | ||
8 | CONFIG_PLATFORM_MINGW32=y | ||
9 | |||
10 | # | ||
11 | # Settings | ||
12 | # | ||
13 | CONFIG_DESKTOP=y | ||
14 | # CONFIG_EXTRA_COMPAT is not set | ||
15 | # CONFIG_FEDORA_COMPAT is not set | ||
16 | # CONFIG_INCLUDE_SUSv2 is not set | ||
17 | CONFIG_LONG_OPTS=y | ||
18 | CONFIG_SHOW_USAGE=y | ||
19 | CONFIG_FEATURE_VERBOSE_USAGE=y | ||
20 | CONFIG_FEATURE_COMPRESS_USAGE=y | ||
21 | CONFIG_LFS=y | ||
22 | CONFIG_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 | ||
28 | CONFIG_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 | ||
36 | CONFIG_FEATURE_PREFER_APPLETS=y | ||
37 | CONFIG_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 | # | ||
46 | CONFIG_GLOBBING=y | ||
47 | CONFIG_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 | ||
52 | CONFIG_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 | ||
61 | CONFIG_TERMINAL_MODE=5 | ||
62 | # CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING is not set | ||
63 | CONFIG_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 | ||
75 | CONFIG_CROSS_COMPILER_PREFIX="i686-w64-mingw32-" | ||
76 | CONFIG_SYSROOT="" | ||
77 | CONFIG_EXTRA_CFLAGS="" | ||
78 | CONFIG_EXTRA_LDFLAGS="" | ||
79 | CONFIG_EXTRA_LDLIBS="" | ||
80 | CONFIG_USE_PORTABLE_CODE=y | ||
81 | CONFIG_STACK_OPTIMIZATION_386=y | ||
82 | CONFIG_STATIC_LIBGCC=y | ||
83 | |||
84 | # | ||
85 | # Installation Options ("make install" behavior) | ||
86 | # | ||
87 | CONFIG_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 | ||
94 | CONFIG_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 | ||
105 | CONFIG_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 | ||
113 | CONFIG_FLOAT_DURATION=y | ||
114 | # CONFIG_FEATURE_RTMINMAX is not set | ||
115 | # CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS is not set | ||
116 | CONFIG_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 | ||
119 | CONFIG_PASSWORD_MINLEN=6 | ||
120 | CONFIG_MD5_SMALL=1 | ||
121 | CONFIG_SHA1_SMALL=3 | ||
122 | # CONFIG_SHA1_HWACCEL is not set | ||
123 | # CONFIG_SHA256_HWACCEL is not set | ||
124 | CONFIG_SHA3_SMALL=1 | ||
125 | CONFIG_FEATURE_NON_POSIX_CP=y | ||
126 | # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set | ||
127 | # CONFIG_FEATURE_USE_SENDFILE is not set | ||
128 | CONFIG_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 | ||
132 | CONFIG_FEATURE_EDITING_MAX_LEN=0 | ||
133 | # CONFIG_FEATURE_EDITING_VI is not set | ||
134 | CONFIG_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 | ||
147 | CONFIG_SUBST_WCHAR=0 | ||
148 | CONFIG_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 | ||
156 | CONFIG_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 | ||
171 | CONFIG_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 | ||
186 | CONFIG_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 | ||
197 | CONFIG_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 | # | ||
228 | CONFIG_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 | ||
271 | CONFIG_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 | ||
351 | CONFIG_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 | ||
363 | CONFIG_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 | ||
392 | CONFIG_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 | ||
440 | CONFIG_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 | ||
457 | CONFIG_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 | ||
521 | CONFIG_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 | ||
526 | CONFIG_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 | ||
531 | CONFIG_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 | ||
548 | CONFIG_LAST_ID=0 | ||
549 | CONFIG_FIRST_SYSTEM_ID=0 | ||
550 | CONFIG_LAST_SYSTEM_ID=0 | ||
551 | # CONFIG_CHPASSWD is not set | ||
552 | CONFIG_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 | ||
610 | CONFIG_DEFAULT_MODULES_DIR="" | ||
611 | CONFIG_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 | ||
774 | CONFIG_FEATURE_BEEP_FREQ=0 | ||
775 | CONFIG_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 | ||
789 | CONFIG_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 | ||
823 | CONFIG_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 | ||
836 | CONFIG_MAKE=y | ||
837 | CONFIG_PDPMAKE=y | ||
838 | CONFIG_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 | ||
901 | CONFIG_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 | ||
927 | CONFIG_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 | ||
950 | CONFIG_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 | ||
994 | CONFIG_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 | ||
1026 | CONFIG_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 | ||
1032 | CONFIG_UDHCPC_DEFAULT_SCRIPT="" | ||
1033 | CONFIG_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 | ||
1039 | CONFIG_UDHCPC_DEFAULT_INTERFACE="" | ||
1040 | # CONFIG_FEATURE_UDHCP_PORT is not set | ||
1041 | CONFIG_UDHCP_DEBUG=0 | ||
1042 | CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 | ||
1043 | # CONFIG_FEATURE_UDHCP_RFC3397 is not set | ||
1044 | # CONFIG_FEATURE_UDHCP_8021Q is not set | ||
1045 | CONFIG_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 | # | ||
1057 | CONFIG_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 | ||
1121 | CONFIG_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 | # | ||
1142 | CONFIG_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 | ||
1147 | CONFIG_BASH_IS_NONE=y | ||
1148 | CONFIG_SHELL_ASH=y | ||
1149 | CONFIG_ASH=y | ||
1150 | CONFIG_ASH_OPTIMIZE_FOR_SIZE=y | ||
1151 | CONFIG_ASH_INTERNAL_GLOB=y | ||
1152 | CONFIG_ASH_BASH_COMPAT=y | ||
1153 | # CONFIG_ASH_BASH_SOURCE_CURDIR is not set | ||
1154 | CONFIG_ASH_BASH_NOT_FOUND_HOOK=y | ||
1155 | CONFIG_ASH_JOB_CONTROL=y | ||
1156 | CONFIG_ASH_ALIAS=y | ||
1157 | CONFIG_ASH_RANDOM_SUPPORT=y | ||
1158 | CONFIG_ASH_EXPAND_PRMT=y | ||
1159 | CONFIG_ASH_IDLE_TIMEOUT=y | ||
1160 | CONFIG_ASH_MAIL=y | ||
1161 | CONFIG_ASH_ECHO=y | ||
1162 | CONFIG_ASH_PRINTF=y | ||
1163 | CONFIG_ASH_TEST=y | ||
1164 | CONFIG_ASH_HELP=y | ||
1165 | CONFIG_ASH_GETOPTS=y | ||
1166 | CONFIG_ASH_CMDCMD=y | ||
1167 | CONFIG_ASH_NOCONSOLE=y | ||
1168 | CONFIG_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 | # | ||
1211 | CONFIG_FEATURE_SH_MATH=y | ||
1212 | CONFIG_FEATURE_SH_MATH_64=y | ||
1213 | CONFIG_FEATURE_SH_MATH_BASE=y | ||
1214 | CONFIG_FEATURE_SH_EXTRA_QUIET=y | ||
1215 | # CONFIG_FEATURE_SH_STANDALONE is not set | ||
1216 | # CONFIG_FEATURE_SH_NOFORK is not set | ||
1217 | CONFIG_FEATURE_SH_READ_FRAC=y | ||
1218 | CONFIG_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 | ||
1235 | CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 | ||
1236 | # CONFIG_FEATURE_IPC_SYSLOG is not set | ||
1237 | CONFIG_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 | # | ||
6 | CONFIG_HAVE_DOT_CONFIG=y | ||
7 | # CONFIG_PLATFORM_POSIX is not set | ||
8 | CONFIG_PLATFORM_MINGW32=y | ||
9 | |||
10 | # | ||
11 | # Settings | ||
12 | # | ||
13 | CONFIG_DESKTOP=y | ||
14 | # CONFIG_EXTRA_COMPAT is not set | ||
15 | # CONFIG_FEDORA_COMPAT is not set | ||
16 | # CONFIG_INCLUDE_SUSv2 is not set | ||
17 | CONFIG_LONG_OPTS=y | ||
18 | CONFIG_SHOW_USAGE=y | ||
19 | CONFIG_FEATURE_VERBOSE_USAGE=y | ||
20 | CONFIG_FEATURE_COMPRESS_USAGE=y | ||
21 | CONFIG_LFS=y | ||
22 | CONFIG_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 | ||
28 | CONFIG_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 | ||
36 | CONFIG_FEATURE_PREFER_APPLETS=y | ||
37 | CONFIG_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 | # | ||
46 | CONFIG_GLOBBING=y | ||
47 | CONFIG_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 | ||
52 | CONFIG_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 | ||
61 | CONFIG_TERMINAL_MODE=5 | ||
62 | # CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING is not set | ||
63 | CONFIG_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 | ||
75 | CONFIG_CROSS_COMPILER_PREFIX="x86_64-w64-mingw32-" | ||
76 | CONFIG_SYSROOT="" | ||
77 | CONFIG_EXTRA_CFLAGS="" | ||
78 | CONFIG_EXTRA_LDFLAGS="" | ||
79 | CONFIG_EXTRA_LDLIBS="" | ||
80 | CONFIG_USE_PORTABLE_CODE=y | ||
81 | CONFIG_STACK_OPTIMIZATION_386=y | ||
82 | CONFIG_STATIC_LIBGCC=y | ||
83 | |||
84 | # | ||
85 | # Installation Options ("make install" behavior) | ||
86 | # | ||
87 | CONFIG_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 | ||
94 | CONFIG_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 | ||
105 | CONFIG_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 | ||
113 | CONFIG_FLOAT_DURATION=y | ||
114 | # CONFIG_FEATURE_RTMINMAX is not set | ||
115 | # CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS is not set | ||
116 | CONFIG_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 | ||
119 | CONFIG_PASSWORD_MINLEN=6 | ||
120 | CONFIG_MD5_SMALL=1 | ||
121 | CONFIG_SHA1_SMALL=3 | ||
122 | # CONFIG_SHA1_HWACCEL is not set | ||
123 | # CONFIG_SHA256_HWACCEL is not set | ||
124 | CONFIG_SHA3_SMALL=1 | ||
125 | CONFIG_FEATURE_NON_POSIX_CP=y | ||
126 | # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set | ||
127 | # CONFIG_FEATURE_USE_SENDFILE is not set | ||
128 | CONFIG_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 | ||
132 | CONFIG_FEATURE_EDITING_MAX_LEN=0 | ||
133 | # CONFIG_FEATURE_EDITING_VI is not set | ||
134 | CONFIG_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 | ||
147 | CONFIG_SUBST_WCHAR=0 | ||
148 | CONFIG_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 | ||
156 | CONFIG_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 | ||
171 | CONFIG_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 | ||
186 | CONFIG_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 | ||
197 | CONFIG_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 | # | ||
228 | CONFIG_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 | ||
271 | CONFIG_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 | ||
351 | CONFIG_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 | ||
363 | CONFIG_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 | ||
392 | CONFIG_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 | ||
440 | CONFIG_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 | ||
457 | CONFIG_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 | ||
521 | CONFIG_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 | ||
526 | CONFIG_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 | ||
531 | CONFIG_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 | ||
548 | CONFIG_LAST_ID=0 | ||
549 | CONFIG_FIRST_SYSTEM_ID=0 | ||
550 | CONFIG_LAST_SYSTEM_ID=0 | ||
551 | # CONFIG_CHPASSWD is not set | ||
552 | CONFIG_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 | ||
610 | CONFIG_DEFAULT_MODULES_DIR="" | ||
611 | CONFIG_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 | ||
774 | CONFIG_FEATURE_BEEP_FREQ=0 | ||
775 | CONFIG_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 | ||
789 | CONFIG_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 | ||
823 | CONFIG_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 | ||
836 | CONFIG_MAKE=y | ||
837 | CONFIG_PDPMAKE=y | ||
838 | CONFIG_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 | ||
901 | CONFIG_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 | ||
927 | CONFIG_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 | ||
950 | CONFIG_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 | ||
994 | CONFIG_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 | ||
1026 | CONFIG_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 | ||
1032 | CONFIG_UDHCPC_DEFAULT_SCRIPT="" | ||
1033 | CONFIG_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 | ||
1039 | CONFIG_UDHCPC_DEFAULT_INTERFACE="" | ||
1040 | # CONFIG_FEATURE_UDHCP_PORT is not set | ||
1041 | CONFIG_UDHCP_DEBUG=0 | ||
1042 | CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 | ||
1043 | # CONFIG_FEATURE_UDHCP_RFC3397 is not set | ||
1044 | # CONFIG_FEATURE_UDHCP_8021Q is not set | ||
1045 | CONFIG_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 | # | ||
1057 | CONFIG_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 | ||
1121 | CONFIG_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 | # | ||
1142 | CONFIG_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 | ||
1147 | CONFIG_BASH_IS_NONE=y | ||
1148 | CONFIG_SHELL_ASH=y | ||
1149 | CONFIG_ASH=y | ||
1150 | CONFIG_ASH_OPTIMIZE_FOR_SIZE=y | ||
1151 | CONFIG_ASH_INTERNAL_GLOB=y | ||
1152 | CONFIG_ASH_BASH_COMPAT=y | ||
1153 | # CONFIG_ASH_BASH_SOURCE_CURDIR is not set | ||
1154 | CONFIG_ASH_BASH_NOT_FOUND_HOOK=y | ||
1155 | CONFIG_ASH_JOB_CONTROL=y | ||
1156 | CONFIG_ASH_ALIAS=y | ||
1157 | CONFIG_ASH_RANDOM_SUPPORT=y | ||
1158 | CONFIG_ASH_EXPAND_PRMT=y | ||
1159 | CONFIG_ASH_IDLE_TIMEOUT=y | ||
1160 | CONFIG_ASH_MAIL=y | ||
1161 | CONFIG_ASH_ECHO=y | ||
1162 | CONFIG_ASH_PRINTF=y | ||
1163 | CONFIG_ASH_TEST=y | ||
1164 | CONFIG_ASH_HELP=y | ||
1165 | CONFIG_ASH_GETOPTS=y | ||
1166 | CONFIG_ASH_CMDCMD=y | ||
1167 | CONFIG_ASH_NOCONSOLE=y | ||
1168 | CONFIG_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 | # | ||
1211 | CONFIG_FEATURE_SH_MATH=y | ||
1212 | CONFIG_FEATURE_SH_MATH_64=y | ||
1213 | CONFIG_FEATURE_SH_MATH_BASE=y | ||
1214 | CONFIG_FEATURE_SH_EXTRA_QUIET=y | ||
1215 | # CONFIG_FEATURE_SH_STANDALONE is not set | ||
1216 | # CONFIG_FEATURE_SH_NOFORK is not set | ||
1217 | CONFIG_FEATURE_SH_READ_FRAC=y | ||
1218 | CONFIG_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 | ||
1235 | CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 | ||
1236 | # CONFIG_FEATURE_IPC_SYSLOG is not set | ||
1237 | CONFIG_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 | # | ||
6 | CONFIG_HAVE_DOT_CONFIG=y | ||
7 | # CONFIG_PLATFORM_POSIX is not set | ||
8 | CONFIG_PLATFORM_MINGW32=y | ||
9 | |||
10 | # | ||
11 | # Settings | ||
12 | # | ||
13 | CONFIG_DESKTOP=y | ||
14 | # CONFIG_EXTRA_COMPAT is not set | ||
15 | # CONFIG_FEDORA_COMPAT is not set | ||
16 | # CONFIG_INCLUDE_SUSv2 is not set | ||
17 | CONFIG_LONG_OPTS=y | ||
18 | CONFIG_SHOW_USAGE=y | ||
19 | CONFIG_FEATURE_VERBOSE_USAGE=y | ||
20 | CONFIG_FEATURE_COMPRESS_USAGE=y | ||
21 | CONFIG_LFS=y | ||
22 | CONFIG_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 | ||
28 | CONFIG_PID_FILE_PATH="" | ||
29 | CONFIG_BUSYBOX=y | ||
30 | CONFIG_FEATURE_SHOW_SCRIPT=y | ||
31 | CONFIG_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 | ||
36 | CONFIG_FEATURE_PREFER_APPLETS=y | ||
37 | CONFIG_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 | # | ||
46 | CONFIG_GLOBBING=y | ||
47 | CONFIG_FEATURE_PRNG_SHELL=y | ||
48 | # CONFIG_FEATURE_PRNG_ISAAC is not set | ||
49 | CONFIG_FEATURE_RESOURCES=y | ||
50 | CONFIG_FEATURE_VERSIONINFO=y | ||
51 | # CONFIG_FEATURE_TOOLCHAIN_MANIFEST is not set | ||
52 | CONFIG_FEATURE_APP_MANIFEST=y | ||
53 | # CONFIG_FEATURE_UTF8_MANIFEST is not set | ||
54 | CONFIG_FEATURE_ICON=y | ||
55 | # CONFIG_FEATURE_ICON_ATERM is not set | ||
56 | # CONFIG_FEATURE_ICON_STERM is not set | ||
57 | CONFIG_FEATURE_ICON_ALL=y | ||
58 | CONFIG_FEATURE_EURO=y | ||
59 | # CONFIG_FEATURE_UTF8_INPUT is not set | ||
60 | # CONFIG_FEATURE_UTF8_OUTPUT is not set | ||
61 | CONFIG_TERMINAL_MODE=5 | ||
62 | CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y | ||
63 | CONFIG_FEATURE_EXTRA_FILE_DATA=y | ||
64 | CONFIG_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 | ||
76 | CONFIG_CROSS_COMPILER_PREFIX="i686-w64-mingw32-" | ||
77 | CONFIG_HOST_COMPILER="gcc" | ||
78 | CONFIG_CROSS_COMPILER="gcc" | ||
79 | CONFIG_SYSROOT="" | ||
80 | CONFIG_EXTRA_CFLAGS="" | ||
81 | CONFIG_EXTRA_LDFLAGS="" | ||
82 | CONFIG_EXTRA_LDLIBS="" | ||
83 | CONFIG_USE_PORTABLE_CODE=y | ||
84 | CONFIG_STACK_OPTIMIZATION_386=y | ||
85 | CONFIG_STATIC_LIBGCC=y | ||
86 | |||
87 | # | ||
88 | # Installation Options ("make install" behavior) | ||
89 | # | ||
90 | CONFIG_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 | ||
97 | CONFIG_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 | ||
108 | CONFIG_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 | ||
116 | CONFIG_FLOAT_DURATION=y | ||
117 | # CONFIG_FEATURE_RTMINMAX is not set | ||
118 | # CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS is not set | ||
119 | CONFIG_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 | ||
122 | CONFIG_PASSWORD_MINLEN=6 | ||
123 | CONFIG_MD5_SMALL=1 | ||
124 | CONFIG_SHA1_SMALL=3 | ||
125 | # CONFIG_SHA1_HWACCEL is not set | ||
126 | # CONFIG_SHA256_HWACCEL is not set | ||
127 | CONFIG_SHA3_SMALL=1 | ||
128 | CONFIG_FEATURE_NON_POSIX_CP=y | ||
129 | # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set | ||
130 | # CONFIG_FEATURE_USE_SENDFILE is not set | ||
131 | CONFIG_FEATURE_COPYBUF_KB=4 | ||
132 | # CONFIG_MONOTONIC_SYSCALL is not set | ||
133 | # CONFIG_IOCTL_HEX2STR_ERROR is not set | ||
134 | CONFIG_FEATURE_EDITING=y | ||
135 | CONFIG_FEATURE_EDITING_MAX_LEN=8192 | ||
136 | CONFIG_FEATURE_EDITING_VI=y | ||
137 | CONFIG_FEATURE_EDITING_HISTORY=1023 | ||
138 | CONFIG_FEATURE_EDITING_HISTORY_DEFAULT=384 | ||
139 | CONFIG_FEATURE_EDITING_SAVEHISTORY=y | ||
140 | # CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set | ||
141 | CONFIG_FEATURE_REVERSE_SEARCH=y | ||
142 | CONFIG_FEATURE_TAB_COMPLETION=y | ||
143 | CONFIG_FEATURE_USERNAME_COMPLETION=y | ||
144 | CONFIG_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 | ||
151 | CONFIG_SUBST_WCHAR=0 | ||
152 | CONFIG_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 | ||
160 | CONFIG_TRY_LOOP_CONFIGURE=y | ||
161 | |||
162 | # | ||
163 | # Applets | ||
164 | # | ||
165 | |||
166 | # | ||
167 | # Archival Utilities | ||
168 | # | ||
169 | CONFIG_FEATURE_SEAMLESS_XZ=y | ||
170 | CONFIG_FEATURE_SEAMLESS_LZMA=y | ||
171 | CONFIG_FEATURE_SEAMLESS_BZ2=y | ||
172 | CONFIG_FEATURE_SEAMLESS_GZ=y | ||
173 | CONFIG_FEATURE_SEAMLESS_Z=y | ||
174 | CONFIG_AR=y | ||
175 | CONFIG_FEATURE_AR_LONG_FILENAMES=y | ||
176 | CONFIG_FEATURE_AR_CREATE=y | ||
177 | CONFIG_UNCOMPRESS=y | ||
178 | CONFIG_GUNZIP=y | ||
179 | CONFIG_ZCAT=y | ||
180 | CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y | ||
181 | CONFIG_BUNZIP2=y | ||
182 | CONFIG_BZCAT=y | ||
183 | CONFIG_UNLZMA=y | ||
184 | CONFIG_LZCAT=y | ||
185 | CONFIG_LZMA=y | ||
186 | CONFIG_UNXZ=y | ||
187 | CONFIG_XZCAT=y | ||
188 | CONFIG_XZ=y | ||
189 | CONFIG_BZIP2=y | ||
190 | CONFIG_BZIP2_SMALL=8 | ||
191 | CONFIG_FEATURE_BZIP2_DECOMPRESS=y | ||
192 | CONFIG_CPIO=y | ||
193 | CONFIG_FEATURE_CPIO_O=y | ||
194 | # CONFIG_FEATURE_CPIO_P is not set | ||
195 | CONFIG_FEATURE_CPIO_IGNORE_DEVNO=y | ||
196 | CONFIG_FEATURE_CPIO_RENUMBER_INODES=y | ||
197 | CONFIG_DPKG=y | ||
198 | CONFIG_DPKG_DEB=y | ||
199 | CONFIG_GZIP=y | ||
200 | CONFIG_FEATURE_GZIP_LONG_OPTIONS=y | ||
201 | CONFIG_GZIP_FAST=2 | ||
202 | CONFIG_FEATURE_GZIP_LEVELS=y | ||
203 | CONFIG_FEATURE_GZIP_DECOMPRESS=y | ||
204 | CONFIG_LZOP=y | ||
205 | CONFIG_UNLZOP=y | ||
206 | CONFIG_LZOPCAT=y | ||
207 | # CONFIG_LZOP_COMPR_HIGH is not set | ||
208 | CONFIG_RPM=y | ||
209 | CONFIG_RPM2CPIO=y | ||
210 | CONFIG_TAR=y | ||
211 | CONFIG_FEATURE_TAR_LONG_OPTIONS=y | ||
212 | CONFIG_FEATURE_TAR_CREATE=y | ||
213 | CONFIG_FEATURE_TAR_AUTODETECT=y | ||
214 | CONFIG_FEATURE_TAR_FROM=y | ||
215 | CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y | ||
216 | # CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set | ||
217 | CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y | ||
218 | # CONFIG_FEATURE_TAR_TO_COMMAND is not set | ||
219 | # CONFIG_FEATURE_TAR_UNAME_GNAME is not set | ||
220 | CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y | ||
221 | # CONFIG_FEATURE_TAR_SELINUX is not set | ||
222 | CONFIG_UNZIP=y | ||
223 | CONFIG_FEATURE_UNZIP_CDF=y | ||
224 | CONFIG_FEATURE_UNZIP_BZIP2=y | ||
225 | CONFIG_FEATURE_UNZIP_LZMA=y | ||
226 | CONFIG_FEATURE_UNZIP_XZ=y | ||
227 | CONFIG_FEATURE_LZMA_FAST=y | ||
228 | |||
229 | # | ||
230 | # Coreutils | ||
231 | # | ||
232 | CONFIG_FEATURE_VERBOSE=y | ||
233 | |||
234 | # | ||
235 | # Common options for date and touch | ||
236 | # | ||
237 | CONFIG_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 | # | ||
247 | CONFIG_FEATURE_HUMAN_READABLE=y | ||
248 | CONFIG_BASENAME=y | ||
249 | CONFIG_CAT=y | ||
250 | CONFIG_FEATURE_CATN=y | ||
251 | CONFIG_FEATURE_CATV=y | ||
252 | # CONFIG_CHGRP is not set | ||
253 | CONFIG_CHMOD=y | ||
254 | # CONFIG_CHOWN is not set | ||
255 | # CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set | ||
256 | # CONFIG_CHROOT is not set | ||
257 | CONFIG_CKSUM=y | ||
258 | CONFIG_CRC32=y | ||
259 | CONFIG_COMM=y | ||
260 | CONFIG_CP=y | ||
261 | CONFIG_FEATURE_CP_LONG_OPTIONS=y | ||
262 | # CONFIG_FEATURE_CP_REFLINK is not set | ||
263 | CONFIG_CUT=y | ||
264 | CONFIG_FEATURE_CUT_REGEX=y | ||
265 | CONFIG_DATE=y | ||
266 | CONFIG_FEATURE_DATE_ISOFMT=y | ||
267 | CONFIG_FEATURE_DATE_NANO=y | ||
268 | CONFIG_FEATURE_DATE_COMPAT=y | ||
269 | CONFIG_DD=y | ||
270 | # CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set | ||
271 | # CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set | ||
272 | CONFIG_FEATURE_DD_IBS_OBS=y | ||
273 | CONFIG_FEATURE_DD_STATUS=y | ||
274 | CONFIG_DF=y | ||
275 | # CONFIG_FEATURE_DF_FANCY is not set | ||
276 | # CONFIG_FEATURE_SKIP_ROOTFS is not set | ||
277 | CONFIG_DIRNAME=y | ||
278 | CONFIG_DOS2UNIX=y | ||
279 | CONFIG_UNIX2DOS=y | ||
280 | CONFIG_DU=y | ||
281 | CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y | ||
282 | CONFIG_ECHO=y | ||
283 | CONFIG_FEATURE_FANCY_ECHO=y | ||
284 | CONFIG_ENV=y | ||
285 | CONFIG_EXPAND=y | ||
286 | CONFIG_UNEXPAND=y | ||
287 | CONFIG_EXPR=y | ||
288 | CONFIG_EXPR_MATH_SUPPORT_64=y | ||
289 | CONFIG_FACTOR=y | ||
290 | CONFIG_FALSE=y | ||
291 | CONFIG_FOLD=y | ||
292 | CONFIG_HEAD=y | ||
293 | CONFIG_FEATURE_FANCY_HEAD=y | ||
294 | # CONFIG_HOSTID is not set | ||
295 | CONFIG_ID=y | ||
296 | CONFIG_GROUPS=y | ||
297 | CONFIG_INSTALL=y | ||
298 | CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y | ||
299 | CONFIG_LINK=y | ||
300 | CONFIG_LN=y | ||
301 | CONFIG_LOGNAME=y | ||
302 | CONFIG_LS=y | ||
303 | CONFIG_FEATURE_LS_FILETYPES=y | ||
304 | CONFIG_FEATURE_LS_FOLLOWLINKS=y | ||
305 | CONFIG_FEATURE_LS_RECURSIVE=y | ||
306 | CONFIG_FEATURE_LS_WIDTH=y | ||
307 | CONFIG_FEATURE_LS_SORTFILES=y | ||
308 | CONFIG_FEATURE_LS_TIMESTAMPS=y | ||
309 | CONFIG_FEATURE_LS_USERNAME=y | ||
310 | CONFIG_FEATURE_LS_COLOR=y | ||
311 | CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y | ||
312 | CONFIG_MD5SUM=y | ||
313 | CONFIG_SHA1SUM=y | ||
314 | CONFIG_SHA256SUM=y | ||
315 | CONFIG_SHA512SUM=y | ||
316 | CONFIG_SHA3SUM=y | ||
317 | |||
318 | # | ||
319 | # Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum | ||
320 | # | ||
321 | CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y | ||
322 | CONFIG_MKDIR=y | ||
323 | # CONFIG_MKFIFO is not set | ||
324 | # CONFIG_MKNOD is not set | ||
325 | CONFIG_MKTEMP=y | ||
326 | CONFIG_MV=y | ||
327 | # CONFIG_NICE is not set | ||
328 | CONFIG_NL=y | ||
329 | # CONFIG_NOHUP is not set | ||
330 | CONFIG_NPROC=y | ||
331 | CONFIG_OD=y | ||
332 | CONFIG_PASTE=y | ||
333 | CONFIG_PRINTENV=y | ||
334 | CONFIG_PRINTF=y | ||
335 | CONFIG_PWD=y | ||
336 | CONFIG_READLINK=y | ||
337 | CONFIG_FEATURE_READLINK_FOLLOW=y | ||
338 | CONFIG_REALPATH=y | ||
339 | CONFIG_RM=y | ||
340 | CONFIG_RMDIR=y | ||
341 | CONFIG_SEQ=y | ||
342 | CONFIG_SHRED=y | ||
343 | CONFIG_SHUF=y | ||
344 | CONFIG_SLEEP=y | ||
345 | CONFIG_FEATURE_FANCY_SLEEP=y | ||
346 | CONFIG_SORT=y | ||
347 | CONFIG_FEATURE_SORT_BIG=y | ||
348 | # CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set | ||
349 | CONFIG_SPLIT=y | ||
350 | CONFIG_FEATURE_SPLIT_FANCY=y | ||
351 | CONFIG_STAT=y | ||
352 | CONFIG_FEATURE_STAT_FORMAT=y | ||
353 | CONFIG_FEATURE_STAT_FILESYSTEM=y | ||
354 | # CONFIG_STTY is not set | ||
355 | CONFIG_SUM=y | ||
356 | CONFIG_SYNC=y | ||
357 | # CONFIG_FEATURE_SYNC_FANCY is not set | ||
358 | CONFIG_FSYNC=y | ||
359 | CONFIG_TAC=y | ||
360 | CONFIG_TAIL=y | ||
361 | CONFIG_FEATURE_FANCY_TAIL=y | ||
362 | CONFIG_TEE=y | ||
363 | CONFIG_FEATURE_TEE_USE_BLOCK_IO=y | ||
364 | CONFIG_TEST=y | ||
365 | CONFIG_TEST1=y | ||
366 | CONFIG_TEST2=y | ||
367 | CONFIG_FEATURE_TEST_64=y | ||
368 | CONFIG_TIMEOUT=y | ||
369 | CONFIG_TOUCH=y | ||
370 | CONFIG_FEATURE_TOUCH_SUSV3=y | ||
371 | CONFIG_TR=y | ||
372 | CONFIG_FEATURE_TR_CLASSES=y | ||
373 | CONFIG_FEATURE_TR_EQUIV=y | ||
374 | CONFIG_TRUE=y | ||
375 | CONFIG_TRUNCATE=y | ||
376 | CONFIG_TSORT=y | ||
377 | # CONFIG_TTY is not set | ||
378 | CONFIG_UNAME=y | ||
379 | CONFIG_UNAME_OSNAME="MS/Windows" | ||
380 | CONFIG_BB_ARCH=y | ||
381 | CONFIG_UNIQ=y | ||
382 | CONFIG_UNLINK=y | ||
383 | CONFIG_USLEEP=y | ||
384 | CONFIG_UUDECODE=y | ||
385 | CONFIG_BASE32=y | ||
386 | CONFIG_BASE64=y | ||
387 | CONFIG_UUENCODE=y | ||
388 | CONFIG_WC=y | ||
389 | CONFIG_FEATURE_WC_LARGE=y | ||
390 | # CONFIG_WHO is not set | ||
391 | # CONFIG_W is not set | ||
392 | # CONFIG_USERS is not set | ||
393 | CONFIG_WHOAMI=y | ||
394 | CONFIG_YES=y | ||
395 | |||
396 | # | ||
397 | # Console Utilities | ||
398 | # | ||
399 | # CONFIG_CHVT is not set | ||
400 | CONFIG_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 | ||
408 | CONFIG_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 | ||
413 | CONFIG_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 | # | ||
425 | CONFIG_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 | ||
432 | CONFIG_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 | # | ||
445 | CONFIG_AWK=y | ||
446 | CONFIG_FEATURE_AWK_LIBM=y | ||
447 | CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y | ||
448 | CONFIG_CMP=y | ||
449 | CONFIG_DIFF=y | ||
450 | CONFIG_FEATURE_DIFF_LONG_OPTIONS=y | ||
451 | CONFIG_FEATURE_DIFF_DIR=y | ||
452 | CONFIG_ED=y | ||
453 | CONFIG_PATCH=y | ||
454 | CONFIG_SED=y | ||
455 | CONFIG_VI=y | ||
456 | CONFIG_FEATURE_VI_MAX_LEN=4096 | ||
457 | CONFIG_FEATURE_VI_8BIT=y | ||
458 | CONFIG_FEATURE_VI_COLON=y | ||
459 | CONFIG_FEATURE_VI_COLON_EXPAND=y | ||
460 | CONFIG_FEATURE_VI_YANKMARK=y | ||
461 | CONFIG_FEATURE_VI_SEARCH=y | ||
462 | CONFIG_FEATURE_VI_REGEX_SEARCH=y | ||
463 | # CONFIG_FEATURE_VI_USE_SIGNALS is not set | ||
464 | CONFIG_FEATURE_VI_DOT_CMD=y | ||
465 | CONFIG_FEATURE_VI_READONLY=y | ||
466 | CONFIG_FEATURE_VI_SETOPTS=y | ||
467 | CONFIG_FEATURE_VI_FILE_FORMAT=y | ||
468 | CONFIG_FEATURE_VI_SET=y | ||
469 | CONFIG_FEATURE_VI_WIN_RESIZE=y | ||
470 | # CONFIG_FEATURE_VI_ASK_TERMINAL is not set | ||
471 | CONFIG_FEATURE_VI_UNDO=y | ||
472 | CONFIG_FEATURE_VI_UNDO_QUEUE=y | ||
473 | CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256 | ||
474 | CONFIG_FEATURE_VI_VERBOSE_STATUS=y | ||
475 | CONFIG_FEATURE_ALLOW_EXEC=y | ||
476 | |||
477 | # | ||
478 | # Finding Utilities | ||
479 | # | ||
480 | CONFIG_FIND=y | ||
481 | CONFIG_FEATURE_FIND_PRINT0=y | ||
482 | CONFIG_FEATURE_FIND_MTIME=y | ||
483 | CONFIG_FEATURE_FIND_ATIME=y | ||
484 | CONFIG_FEATURE_FIND_CTIME=y | ||
485 | CONFIG_FEATURE_FIND_MMIN=y | ||
486 | CONFIG_FEATURE_FIND_AMIN=y | ||
487 | CONFIG_FEATURE_FIND_CMIN=y | ||
488 | CONFIG_FEATURE_FIND_PERM=y | ||
489 | CONFIG_FEATURE_FIND_TYPE=y | ||
490 | CONFIG_FEATURE_FIND_EXECUTABLE=y | ||
491 | CONFIG_FEATURE_FIND_XDEV=y | ||
492 | CONFIG_FEATURE_FIND_MAXDEPTH=y | ||
493 | CONFIG_FEATURE_FIND_NEWER=y | ||
494 | CONFIG_FEATURE_FIND_INUM=y | ||
495 | CONFIG_FEATURE_FIND_SAMEFILE=y | ||
496 | CONFIG_FEATURE_FIND_EXEC=y | ||
497 | CONFIG_FEATURE_FIND_EXEC_PLUS=y | ||
498 | CONFIG_FEATURE_FIND_EXEC_OK=y | ||
499 | # CONFIG_FEATURE_FIND_USER is not set | ||
500 | # CONFIG_FEATURE_FIND_GROUP is not set | ||
501 | CONFIG_FEATURE_FIND_NOT=y | ||
502 | CONFIG_FEATURE_FIND_DEPTH=y | ||
503 | CONFIG_FEATURE_FIND_PAREN=y | ||
504 | CONFIG_FEATURE_FIND_SIZE=y | ||
505 | CONFIG_FEATURE_FIND_PRUNE=y | ||
506 | CONFIG_FEATURE_FIND_QUIT=y | ||
507 | CONFIG_FEATURE_FIND_DELETE=y | ||
508 | CONFIG_FEATURE_FIND_EMPTY=y | ||
509 | CONFIG_FEATURE_FIND_PATH=y | ||
510 | CONFIG_FEATURE_FIND_REGEX=y | ||
511 | # CONFIG_FEATURE_FIND_CONTEXT is not set | ||
512 | CONFIG_FEATURE_FIND_LINKS=y | ||
513 | CONFIG_GREP=y | ||
514 | CONFIG_EGREP=y | ||
515 | CONFIG_FGREP=y | ||
516 | CONFIG_FEATURE_GREP_CONTEXT=y | ||
517 | CONFIG_XARGS=y | ||
518 | CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y | ||
519 | CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y | ||
520 | CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y | ||
521 | CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y | ||
522 | CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y | ||
523 | CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y | ||
524 | CONFIG_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 | ||
537 | CONFIG_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 | ||
542 | CONFIG_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 | ||
547 | CONFIG_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 | ||
564 | CONFIG_LAST_ID=0 | ||
565 | CONFIG_FIRST_SYSTEM_ID=0 | ||
566 | CONFIG_LAST_SYSTEM_ID=0 | ||
567 | # CONFIG_CHPASSWD is not set | ||
568 | CONFIG_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 | ||
587 | CONFIG_SUW32=y | ||
588 | # CONFIG_VLOCK is not set | ||
589 | |||
590 | # | ||
591 | # Linux Ext2 FS Progs | ||
592 | # | ||
593 | CONFIG_CHATTR=y | ||
594 | # CONFIG_FSCK is not set | ||
595 | CONFIG_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 | ||
626 | CONFIG_DEFAULT_MODULES_DIR="" | ||
627 | CONFIG_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 | ||
638 | CONFIG_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 | ||
666 | CONFIG_GETOPT=y | ||
667 | CONFIG_FEATURE_GETOPT_LONG=y | ||
668 | CONFIG_HEXDUMP=y | ||
669 | CONFIG_HD=y | ||
670 | CONFIG_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 | ||
719 | CONFIG_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 | ||
780 | CONFIG_ASCII=y | ||
781 | # CONFIG_BBCONFIG is not set | ||
782 | # CONFIG_FEATURE_COMPRESS_BBCONFIG is not set | ||
783 | CONFIG_BC=y | ||
784 | CONFIG_DC=y | ||
785 | CONFIG_FEATURE_DC_BIG=y | ||
786 | # CONFIG_FEATURE_DC_LIBM is not set | ||
787 | CONFIG_FEATURE_BC_INTERACTIVE=y | ||
788 | CONFIG_FEATURE_BC_LONG_OPTIONS=y | ||
789 | # CONFIG_BEEP is not set | ||
790 | CONFIG_FEATURE_BEEP_FREQ=0 | ||
791 | CONFIG_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 | ||
805 | CONFIG_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 | ||
813 | CONFIG_DROP=y | ||
814 | CONFIG_CDROP=y | ||
815 | CONFIG_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 | ||
835 | CONFIG_ICONV=y | ||
836 | CONFIG_INOTIFYD=y | ||
837 | CONFIG_JN=y | ||
838 | CONFIG_LESS=y | ||
839 | CONFIG_FEATURE_LESS_MAXLINES=9999999 | ||
840 | CONFIG_FEATURE_LESS_BRACKETS=y | ||
841 | CONFIG_FEATURE_LESS_FLAGS=y | ||
842 | CONFIG_FEATURE_LESS_TRUNCATE=y | ||
843 | CONFIG_FEATURE_LESS_MARKS=y | ||
844 | CONFIG_FEATURE_LESS_REGEXP=y | ||
845 | # CONFIG_FEATURE_LESS_WINCH is not set | ||
846 | # CONFIG_FEATURE_LESS_ASK_TERMINAL is not set | ||
847 | CONFIG_FEATURE_LESS_DASHCMD=y | ||
848 | CONFIG_FEATURE_LESS_LINENUMS=y | ||
849 | CONFIG_FEATURE_LESS_RAW=y | ||
850 | CONFIG_FEATURE_LESS_ENV=y | ||
851 | # CONFIG_LSSCSI is not set | ||
852 | CONFIG_MAKE=y | ||
853 | CONFIG_PDPMAKE=y | ||
854 | CONFIG_FEATURE_MAKE_POSIX=y | ||
855 | # CONFIG_FEATURE_MAKE_POSIX_2017 is not set | ||
856 | CONFIG_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 | ||
860 | CONFIG_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 | ||
875 | CONFIG_STRINGS=y | ||
876 | CONFIG_TIME=y | ||
877 | # CONFIG_TREE is not set | ||
878 | CONFIG_TS=y | ||
879 | CONFIG_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 | # | ||
894 | CONFIG_FEATURE_IPV6=y | ||
895 | # CONFIG_FEATURE_UNIX_LOCAL is not set | ||
896 | CONFIG_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 | ||
913 | CONFIG_FTPGET=y | ||
914 | CONFIG_FTPPUT=y | ||
915 | CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y | ||
916 | # CONFIG_HOSTNAME is not set | ||
917 | # CONFIG_DNSDOMAINNAME is not set | ||
918 | CONFIG_HTTPD=y | ||
919 | CONFIG_FEATURE_HTTPD_PORT_DEFAULT=80 | ||
920 | CONFIG_FEATURE_HTTPD_RANGES=y | ||
921 | # CONFIG_FEATURE_HTTPD_SETUID is not set | ||
922 | CONFIG_FEATURE_HTTPD_BASIC_AUTH=y | ||
923 | # CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set | ||
924 | CONFIG_FEATURE_HTTPD_CGI=y | ||
925 | CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y | ||
926 | # CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set | ||
927 | CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y | ||
928 | CONFIG_FEATURE_HTTPD_ERROR_PAGES=y | ||
929 | # CONFIG_FEATURE_HTTPD_PROXY is not set | ||
930 | CONFIG_FEATURE_HTTPD_GZIP=y | ||
931 | CONFIG_FEATURE_HTTPD_ETAG=y | ||
932 | CONFIG_FEATURE_HTTPD_LAST_MODIFIED=y | ||
933 | CONFIG_FEATURE_HTTPD_DATE=y | ||
934 | CONFIG_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 | ||
945 | CONFIG_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 | ||
968 | CONFIG_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 | ||
973 | CONFIG_IPCALC=y | ||
974 | CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y | ||
975 | CONFIG_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 | ||
980 | CONFIG_NC=y | ||
981 | # CONFIG_NETCAT is not set | ||
982 | CONFIG_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 | ||
1001 | CONFIG_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 | ||
1012 | CONFIG_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 | ||
1022 | CONFIG_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 | ||
1030 | CONFIG_WGET=y | ||
1031 | CONFIG_FEATURE_WGET_LONG_OPTIONS=y | ||
1032 | CONFIG_FEATURE_WGET_STATUSBAR=y | ||
1033 | CONFIG_FEATURE_WGET_FTP=y | ||
1034 | CONFIG_FEATURE_WGET_AUTHENTICATION=y | ||
1035 | # CONFIG_FEATURE_WGET_TIMEOUT is not set | ||
1036 | CONFIG_FEATURE_WGET_HTTPS=y | ||
1037 | # CONFIG_FEATURE_WGET_OPENSSL is not set | ||
1038 | CONFIG_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 | ||
1044 | CONFIG_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 | ||
1050 | CONFIG_UDHCPC_DEFAULT_SCRIPT="" | ||
1051 | CONFIG_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 | ||
1057 | CONFIG_UDHCPC_DEFAULT_INTERFACE="" | ||
1058 | # CONFIG_FEATURE_UDHCP_PORT is not set | ||
1059 | CONFIG_UDHCP_DEBUG=0 | ||
1060 | CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 | ||
1061 | # CONFIG_FEATURE_UDHCP_RFC3397 is not set | ||
1062 | # CONFIG_FEATURE_UDHCP_8021Q is not set | ||
1063 | CONFIG_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 | # | ||
1075 | CONFIG_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 | ||
1088 | CONFIG_FREE=y | ||
1089 | # CONFIG_FUSER is not set | ||
1090 | # CONFIG_IOSTAT is not set | ||
1091 | CONFIG_KILL=y | ||
1092 | CONFIG_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 | ||
1097 | CONFIG_PGREP=y | ||
1098 | CONFIG_PKILL=y | ||
1099 | CONFIG_PIDOF=y | ||
1100 | CONFIG_FEATURE_PIDOF_SINGLE=y | ||
1101 | CONFIG_FEATURE_PIDOF_OMIT=y | ||
1102 | # CONFIG_PMAP is not set | ||
1103 | # CONFIG_POWERTOP is not set | ||
1104 | # CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set | ||
1105 | CONFIG_PS=y | ||
1106 | # CONFIG_FEATURE_PS_WIDE is not set | ||
1107 | # CONFIG_FEATURE_PS_LONG is not set | ||
1108 | CONFIG_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 | ||
1123 | CONFIG_UPTIME=y | ||
1124 | # CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set | ||
1125 | CONFIG_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 | ||
1139 | CONFIG_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 | # | ||
1160 | CONFIG_SH_IS_ASH=y | ||
1161 | # CONFIG_SH_IS_HUSH is not set | ||
1162 | # CONFIG_SH_IS_NONE is not set | ||
1163 | CONFIG_BASH_IS_ASH=y | ||
1164 | # CONFIG_BASH_IS_HUSH is not set | ||
1165 | # CONFIG_BASH_IS_NONE is not set | ||
1166 | CONFIG_SHELL_ASH=y | ||
1167 | CONFIG_ASH=y | ||
1168 | # CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set | ||
1169 | CONFIG_ASH_INTERNAL_GLOB=y | ||
1170 | CONFIG_ASH_BASH_COMPAT=y | ||
1171 | # CONFIG_ASH_BASH_SOURCE_CURDIR is not set | ||
1172 | CONFIG_ASH_BASH_NOT_FOUND_HOOK=y | ||
1173 | CONFIG_ASH_JOB_CONTROL=y | ||
1174 | CONFIG_ASH_ALIAS=y | ||
1175 | CONFIG_ASH_RANDOM_SUPPORT=y | ||
1176 | CONFIG_ASH_EXPAND_PRMT=y | ||
1177 | # CONFIG_ASH_IDLE_TIMEOUT is not set | ||
1178 | # CONFIG_ASH_MAIL is not set | ||
1179 | CONFIG_ASH_ECHO=y | ||
1180 | CONFIG_ASH_PRINTF=y | ||
1181 | CONFIG_ASH_TEST=y | ||
1182 | CONFIG_ASH_HELP=y | ||
1183 | CONFIG_ASH_GETOPTS=y | ||
1184 | CONFIG_ASH_CMDCMD=y | ||
1185 | CONFIG_ASH_NOCONSOLE=y | ||
1186 | CONFIG_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 | # | ||
1229 | CONFIG_FEATURE_SH_MATH=y | ||
1230 | CONFIG_FEATURE_SH_MATH_64=y | ||
1231 | CONFIG_FEATURE_SH_MATH_BASE=y | ||
1232 | CONFIG_FEATURE_SH_EXTRA_QUIET=y | ||
1233 | CONFIG_FEATURE_SH_STANDALONE=y | ||
1234 | CONFIG_FEATURE_SH_NOFORK=y | ||
1235 | CONFIG_FEATURE_SH_READ_FRAC=y | ||
1236 | CONFIG_FEATURE_SH_HISTFILESIZE=y | ||
1237 | CONFIG_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 | ||
1253 | CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 | ||
1254 | # CONFIG_FEATURE_IPC_SYSLOG is not set | ||
1255 | CONFIG_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 | # | ||
6 | CONFIG_HAVE_DOT_CONFIG=y | ||
7 | # CONFIG_PLATFORM_POSIX is not set | ||
8 | CONFIG_PLATFORM_MINGW32=y | ||
9 | |||
10 | # | ||
11 | # Settings | ||
12 | # | ||
13 | CONFIG_DESKTOP=y | ||
14 | # CONFIG_EXTRA_COMPAT is not set | ||
15 | # CONFIG_FEDORA_COMPAT is not set | ||
16 | # CONFIG_INCLUDE_SUSv2 is not set | ||
17 | CONFIG_LONG_OPTS=y | ||
18 | CONFIG_SHOW_USAGE=y | ||
19 | CONFIG_FEATURE_VERBOSE_USAGE=y | ||
20 | CONFIG_FEATURE_COMPRESS_USAGE=y | ||
21 | CONFIG_LFS=y | ||
22 | CONFIG_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 | ||
28 | CONFIG_PID_FILE_PATH="" | ||
29 | CONFIG_BUSYBOX=y | ||
30 | CONFIG_FEATURE_SHOW_SCRIPT=y | ||
31 | CONFIG_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 | ||
36 | CONFIG_FEATURE_PREFER_APPLETS=y | ||
37 | CONFIG_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 | # | ||
46 | CONFIG_GLOBBING=y | ||
47 | CONFIG_FEATURE_PRNG_SHELL=y | ||
48 | # CONFIG_FEATURE_PRNG_ISAAC is not set | ||
49 | CONFIG_FEATURE_RESOURCES=y | ||
50 | CONFIG_FEATURE_VERSIONINFO=y | ||
51 | # CONFIG_FEATURE_TOOLCHAIN_MANIFEST is not set | ||
52 | CONFIG_FEATURE_APP_MANIFEST=y | ||
53 | # CONFIG_FEATURE_UTF8_MANIFEST is not set | ||
54 | CONFIG_FEATURE_ICON=y | ||
55 | # CONFIG_FEATURE_ICON_ATERM is not set | ||
56 | # CONFIG_FEATURE_ICON_STERM is not set | ||
57 | CONFIG_FEATURE_ICON_ALL=y | ||
58 | CONFIG_FEATURE_EURO=y | ||
59 | # CONFIG_FEATURE_UTF8_INPUT is not set | ||
60 | # CONFIG_FEATURE_UTF8_OUTPUT is not set | ||
61 | CONFIG_TERMINAL_MODE=5 | ||
62 | CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y | ||
63 | CONFIG_FEATURE_EXTRA_FILE_DATA=y | ||
64 | CONFIG_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 | ||
76 | CONFIG_CROSS_COMPILER_PREFIX="x86_64-w64-mingw32-" | ||
77 | CONFIG_HOST_COMPILER="gcc" | ||
78 | CONFIG_CROSS_COMPILER="gcc" | ||
79 | CONFIG_SYSROOT="" | ||
80 | CONFIG_EXTRA_CFLAGS="" | ||
81 | CONFIG_EXTRA_LDFLAGS="" | ||
82 | CONFIG_EXTRA_LDLIBS="" | ||
83 | CONFIG_USE_PORTABLE_CODE=y | ||
84 | CONFIG_STACK_OPTIMIZATION_386=y | ||
85 | CONFIG_STATIC_LIBGCC=y | ||
86 | |||
87 | # | ||
88 | # Installation Options ("make install" behavior) | ||
89 | # | ||
90 | CONFIG_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 | ||
97 | CONFIG_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 | ||
108 | CONFIG_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 | ||
116 | CONFIG_FLOAT_DURATION=y | ||
117 | # CONFIG_FEATURE_RTMINMAX is not set | ||
118 | # CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS is not set | ||
119 | CONFIG_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 | ||
122 | CONFIG_PASSWORD_MINLEN=6 | ||
123 | CONFIG_MD5_SMALL=1 | ||
124 | CONFIG_SHA1_SMALL=3 | ||
125 | # CONFIG_SHA1_HWACCEL is not set | ||
126 | # CONFIG_SHA256_HWACCEL is not set | ||
127 | CONFIG_SHA3_SMALL=1 | ||
128 | CONFIG_FEATURE_NON_POSIX_CP=y | ||
129 | # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set | ||
130 | # CONFIG_FEATURE_USE_SENDFILE is not set | ||
131 | CONFIG_FEATURE_COPYBUF_KB=4 | ||
132 | # CONFIG_MONOTONIC_SYSCALL is not set | ||
133 | # CONFIG_IOCTL_HEX2STR_ERROR is not set | ||
134 | CONFIG_FEATURE_EDITING=y | ||
135 | CONFIG_FEATURE_EDITING_MAX_LEN=8192 | ||
136 | CONFIG_FEATURE_EDITING_VI=y | ||
137 | CONFIG_FEATURE_EDITING_HISTORY=1023 | ||
138 | CONFIG_FEATURE_EDITING_HISTORY_DEFAULT=384 | ||
139 | CONFIG_FEATURE_EDITING_SAVEHISTORY=y | ||
140 | # CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set | ||
141 | CONFIG_FEATURE_REVERSE_SEARCH=y | ||
142 | CONFIG_FEATURE_TAB_COMPLETION=y | ||
143 | CONFIG_FEATURE_USERNAME_COMPLETION=y | ||
144 | CONFIG_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 | ||
151 | CONFIG_SUBST_WCHAR=0 | ||
152 | CONFIG_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 | ||
160 | CONFIG_TRY_LOOP_CONFIGURE=y | ||
161 | |||
162 | # | ||
163 | # Applets | ||
164 | # | ||
165 | |||
166 | # | ||
167 | # Archival Utilities | ||
168 | # | ||
169 | CONFIG_FEATURE_SEAMLESS_XZ=y | ||
170 | CONFIG_FEATURE_SEAMLESS_LZMA=y | ||
171 | CONFIG_FEATURE_SEAMLESS_BZ2=y | ||
172 | CONFIG_FEATURE_SEAMLESS_GZ=y | ||
173 | CONFIG_FEATURE_SEAMLESS_Z=y | ||
174 | CONFIG_AR=y | ||
175 | CONFIG_FEATURE_AR_LONG_FILENAMES=y | ||
176 | CONFIG_FEATURE_AR_CREATE=y | ||
177 | CONFIG_UNCOMPRESS=y | ||
178 | CONFIG_GUNZIP=y | ||
179 | CONFIG_ZCAT=y | ||
180 | CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y | ||
181 | CONFIG_BUNZIP2=y | ||
182 | CONFIG_BZCAT=y | ||
183 | CONFIG_UNLZMA=y | ||
184 | CONFIG_LZCAT=y | ||
185 | CONFIG_LZMA=y | ||
186 | CONFIG_UNXZ=y | ||
187 | CONFIG_XZCAT=y | ||
188 | CONFIG_XZ=y | ||
189 | CONFIG_BZIP2=y | ||
190 | CONFIG_BZIP2_SMALL=8 | ||
191 | CONFIG_FEATURE_BZIP2_DECOMPRESS=y | ||
192 | CONFIG_CPIO=y | ||
193 | CONFIG_FEATURE_CPIO_O=y | ||
194 | # CONFIG_FEATURE_CPIO_P is not set | ||
195 | CONFIG_FEATURE_CPIO_IGNORE_DEVNO=y | ||
196 | CONFIG_FEATURE_CPIO_RENUMBER_INODES=y | ||
197 | CONFIG_DPKG=y | ||
198 | CONFIG_DPKG_DEB=y | ||
199 | CONFIG_GZIP=y | ||
200 | CONFIG_FEATURE_GZIP_LONG_OPTIONS=y | ||
201 | CONFIG_GZIP_FAST=2 | ||
202 | CONFIG_FEATURE_GZIP_LEVELS=y | ||
203 | CONFIG_FEATURE_GZIP_DECOMPRESS=y | ||
204 | CONFIG_LZOP=y | ||
205 | CONFIG_UNLZOP=y | ||
206 | CONFIG_LZOPCAT=y | ||
207 | # CONFIG_LZOP_COMPR_HIGH is not set | ||
208 | CONFIG_RPM=y | ||
209 | CONFIG_RPM2CPIO=y | ||
210 | CONFIG_TAR=y | ||
211 | CONFIG_FEATURE_TAR_LONG_OPTIONS=y | ||
212 | CONFIG_FEATURE_TAR_CREATE=y | ||
213 | CONFIG_FEATURE_TAR_AUTODETECT=y | ||
214 | CONFIG_FEATURE_TAR_FROM=y | ||
215 | CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y | ||
216 | # CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set | ||
217 | CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y | ||
218 | # CONFIG_FEATURE_TAR_TO_COMMAND is not set | ||
219 | # CONFIG_FEATURE_TAR_UNAME_GNAME is not set | ||
220 | CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y | ||
221 | # CONFIG_FEATURE_TAR_SELINUX is not set | ||
222 | CONFIG_UNZIP=y | ||
223 | CONFIG_FEATURE_UNZIP_CDF=y | ||
224 | CONFIG_FEATURE_UNZIP_BZIP2=y | ||
225 | CONFIG_FEATURE_UNZIP_LZMA=y | ||
226 | CONFIG_FEATURE_UNZIP_XZ=y | ||
227 | CONFIG_FEATURE_LZMA_FAST=y | ||
228 | |||
229 | # | ||
230 | # Coreutils | ||
231 | # | ||
232 | CONFIG_FEATURE_VERBOSE=y | ||
233 | |||
234 | # | ||
235 | # Common options for date and touch | ||
236 | # | ||
237 | CONFIG_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 | # | ||
247 | CONFIG_FEATURE_HUMAN_READABLE=y | ||
248 | CONFIG_BASENAME=y | ||
249 | CONFIG_CAT=y | ||
250 | CONFIG_FEATURE_CATN=y | ||
251 | CONFIG_FEATURE_CATV=y | ||
252 | # CONFIG_CHGRP is not set | ||
253 | CONFIG_CHMOD=y | ||
254 | # CONFIG_CHOWN is not set | ||
255 | # CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set | ||
256 | # CONFIG_CHROOT is not set | ||
257 | CONFIG_CKSUM=y | ||
258 | CONFIG_CRC32=y | ||
259 | CONFIG_COMM=y | ||
260 | CONFIG_CP=y | ||
261 | CONFIG_FEATURE_CP_LONG_OPTIONS=y | ||
262 | # CONFIG_FEATURE_CP_REFLINK is not set | ||
263 | CONFIG_CUT=y | ||
264 | CONFIG_FEATURE_CUT_REGEX=y | ||
265 | CONFIG_DATE=y | ||
266 | CONFIG_FEATURE_DATE_ISOFMT=y | ||
267 | CONFIG_FEATURE_DATE_NANO=y | ||
268 | CONFIG_FEATURE_DATE_COMPAT=y | ||
269 | CONFIG_DD=y | ||
270 | # CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set | ||
271 | # CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set | ||
272 | CONFIG_FEATURE_DD_IBS_OBS=y | ||
273 | CONFIG_FEATURE_DD_STATUS=y | ||
274 | CONFIG_DF=y | ||
275 | # CONFIG_FEATURE_DF_FANCY is not set | ||
276 | # CONFIG_FEATURE_SKIP_ROOTFS is not set | ||
277 | CONFIG_DIRNAME=y | ||
278 | CONFIG_DOS2UNIX=y | ||
279 | CONFIG_UNIX2DOS=y | ||
280 | CONFIG_DU=y | ||
281 | CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y | ||
282 | CONFIG_ECHO=y | ||
283 | CONFIG_FEATURE_FANCY_ECHO=y | ||
284 | CONFIG_ENV=y | ||
285 | CONFIG_EXPAND=y | ||
286 | CONFIG_UNEXPAND=y | ||
287 | CONFIG_EXPR=y | ||
288 | CONFIG_EXPR_MATH_SUPPORT_64=y | ||
289 | CONFIG_FACTOR=y | ||
290 | CONFIG_FALSE=y | ||
291 | CONFIG_FOLD=y | ||
292 | CONFIG_HEAD=y | ||
293 | CONFIG_FEATURE_FANCY_HEAD=y | ||
294 | # CONFIG_HOSTID is not set | ||
295 | CONFIG_ID=y | ||
296 | CONFIG_GROUPS=y | ||
297 | CONFIG_INSTALL=y | ||
298 | CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y | ||
299 | CONFIG_LINK=y | ||
300 | CONFIG_LN=y | ||
301 | CONFIG_LOGNAME=y | ||
302 | CONFIG_LS=y | ||
303 | CONFIG_FEATURE_LS_FILETYPES=y | ||
304 | CONFIG_FEATURE_LS_FOLLOWLINKS=y | ||
305 | CONFIG_FEATURE_LS_RECURSIVE=y | ||
306 | CONFIG_FEATURE_LS_WIDTH=y | ||
307 | CONFIG_FEATURE_LS_SORTFILES=y | ||
308 | CONFIG_FEATURE_LS_TIMESTAMPS=y | ||
309 | CONFIG_FEATURE_LS_USERNAME=y | ||
310 | CONFIG_FEATURE_LS_COLOR=y | ||
311 | CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y | ||
312 | CONFIG_MD5SUM=y | ||
313 | CONFIG_SHA1SUM=y | ||
314 | CONFIG_SHA256SUM=y | ||
315 | CONFIG_SHA512SUM=y | ||
316 | CONFIG_SHA3SUM=y | ||
317 | |||
318 | # | ||
319 | # Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum | ||
320 | # | ||
321 | CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y | ||
322 | CONFIG_MKDIR=y | ||
323 | # CONFIG_MKFIFO is not set | ||
324 | # CONFIG_MKNOD is not set | ||
325 | CONFIG_MKTEMP=y | ||
326 | CONFIG_MV=y | ||
327 | # CONFIG_NICE is not set | ||
328 | CONFIG_NL=y | ||
329 | # CONFIG_NOHUP is not set | ||
330 | CONFIG_NPROC=y | ||
331 | CONFIG_OD=y | ||
332 | CONFIG_PASTE=y | ||
333 | CONFIG_PRINTENV=y | ||
334 | CONFIG_PRINTF=y | ||
335 | CONFIG_PWD=y | ||
336 | CONFIG_READLINK=y | ||
337 | CONFIG_FEATURE_READLINK_FOLLOW=y | ||
338 | CONFIG_REALPATH=y | ||
339 | CONFIG_RM=y | ||
340 | CONFIG_RMDIR=y | ||
341 | CONFIG_SEQ=y | ||
342 | CONFIG_SHRED=y | ||
343 | CONFIG_SHUF=y | ||
344 | CONFIG_SLEEP=y | ||
345 | CONFIG_FEATURE_FANCY_SLEEP=y | ||
346 | CONFIG_SORT=y | ||
347 | CONFIG_FEATURE_SORT_BIG=y | ||
348 | # CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set | ||
349 | CONFIG_SPLIT=y | ||
350 | CONFIG_FEATURE_SPLIT_FANCY=y | ||
351 | CONFIG_STAT=y | ||
352 | CONFIG_FEATURE_STAT_FORMAT=y | ||
353 | CONFIG_FEATURE_STAT_FILESYSTEM=y | ||
354 | # CONFIG_STTY is not set | ||
355 | CONFIG_SUM=y | ||
356 | CONFIG_SYNC=y | ||
357 | # CONFIG_FEATURE_SYNC_FANCY is not set | ||
358 | CONFIG_FSYNC=y | ||
359 | CONFIG_TAC=y | ||
360 | CONFIG_TAIL=y | ||
361 | CONFIG_FEATURE_FANCY_TAIL=y | ||
362 | CONFIG_TEE=y | ||
363 | CONFIG_FEATURE_TEE_USE_BLOCK_IO=y | ||
364 | CONFIG_TEST=y | ||
365 | CONFIG_TEST1=y | ||
366 | CONFIG_TEST2=y | ||
367 | CONFIG_FEATURE_TEST_64=y | ||
368 | CONFIG_TIMEOUT=y | ||
369 | CONFIG_TOUCH=y | ||
370 | CONFIG_FEATURE_TOUCH_SUSV3=y | ||
371 | CONFIG_TR=y | ||
372 | CONFIG_FEATURE_TR_CLASSES=y | ||
373 | CONFIG_FEATURE_TR_EQUIV=y | ||
374 | CONFIG_TRUE=y | ||
375 | CONFIG_TRUNCATE=y | ||
376 | CONFIG_TSORT=y | ||
377 | # CONFIG_TTY is not set | ||
378 | CONFIG_UNAME=y | ||
379 | CONFIG_UNAME_OSNAME="MS/Windows" | ||
380 | CONFIG_BB_ARCH=y | ||
381 | CONFIG_UNIQ=y | ||
382 | CONFIG_UNLINK=y | ||
383 | CONFIG_USLEEP=y | ||
384 | CONFIG_UUDECODE=y | ||
385 | CONFIG_BASE32=y | ||
386 | CONFIG_BASE64=y | ||
387 | CONFIG_UUENCODE=y | ||
388 | CONFIG_WC=y | ||
389 | CONFIG_FEATURE_WC_LARGE=y | ||
390 | # CONFIG_WHO is not set | ||
391 | # CONFIG_W is not set | ||
392 | # CONFIG_USERS is not set | ||
393 | CONFIG_WHOAMI=y | ||
394 | CONFIG_YES=y | ||
395 | |||
396 | # | ||
397 | # Console Utilities | ||
398 | # | ||
399 | # CONFIG_CHVT is not set | ||
400 | CONFIG_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 | ||
408 | CONFIG_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 | ||
413 | CONFIG_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 | # | ||
425 | CONFIG_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 | ||
432 | CONFIG_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 | # | ||
445 | CONFIG_AWK=y | ||
446 | CONFIG_FEATURE_AWK_LIBM=y | ||
447 | CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y | ||
448 | CONFIG_CMP=y | ||
449 | CONFIG_DIFF=y | ||
450 | CONFIG_FEATURE_DIFF_LONG_OPTIONS=y | ||
451 | CONFIG_FEATURE_DIFF_DIR=y | ||
452 | CONFIG_ED=y | ||
453 | CONFIG_PATCH=y | ||
454 | CONFIG_SED=y | ||
455 | CONFIG_VI=y | ||
456 | CONFIG_FEATURE_VI_MAX_LEN=4096 | ||
457 | CONFIG_FEATURE_VI_8BIT=y | ||
458 | CONFIG_FEATURE_VI_COLON=y | ||
459 | CONFIG_FEATURE_VI_COLON_EXPAND=y | ||
460 | CONFIG_FEATURE_VI_YANKMARK=y | ||
461 | CONFIG_FEATURE_VI_SEARCH=y | ||
462 | CONFIG_FEATURE_VI_REGEX_SEARCH=y | ||
463 | # CONFIG_FEATURE_VI_USE_SIGNALS is not set | ||
464 | CONFIG_FEATURE_VI_DOT_CMD=y | ||
465 | CONFIG_FEATURE_VI_READONLY=y | ||
466 | CONFIG_FEATURE_VI_SETOPTS=y | ||
467 | CONFIG_FEATURE_VI_FILE_FORMAT=y | ||
468 | CONFIG_FEATURE_VI_SET=y | ||
469 | CONFIG_FEATURE_VI_WIN_RESIZE=y | ||
470 | # CONFIG_FEATURE_VI_ASK_TERMINAL is not set | ||
471 | CONFIG_FEATURE_VI_UNDO=y | ||
472 | CONFIG_FEATURE_VI_UNDO_QUEUE=y | ||
473 | CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256 | ||
474 | CONFIG_FEATURE_VI_VERBOSE_STATUS=y | ||
475 | CONFIG_FEATURE_ALLOW_EXEC=y | ||
476 | |||
477 | # | ||
478 | # Finding Utilities | ||
479 | # | ||
480 | CONFIG_FIND=y | ||
481 | CONFIG_FEATURE_FIND_PRINT0=y | ||
482 | CONFIG_FEATURE_FIND_MTIME=y | ||
483 | CONFIG_FEATURE_FIND_ATIME=y | ||
484 | CONFIG_FEATURE_FIND_CTIME=y | ||
485 | CONFIG_FEATURE_FIND_MMIN=y | ||
486 | CONFIG_FEATURE_FIND_AMIN=y | ||
487 | CONFIG_FEATURE_FIND_CMIN=y | ||
488 | CONFIG_FEATURE_FIND_PERM=y | ||
489 | CONFIG_FEATURE_FIND_TYPE=y | ||
490 | CONFIG_FEATURE_FIND_EXECUTABLE=y | ||
491 | CONFIG_FEATURE_FIND_XDEV=y | ||
492 | CONFIG_FEATURE_FIND_MAXDEPTH=y | ||
493 | CONFIG_FEATURE_FIND_NEWER=y | ||
494 | CONFIG_FEATURE_FIND_INUM=y | ||
495 | CONFIG_FEATURE_FIND_SAMEFILE=y | ||
496 | CONFIG_FEATURE_FIND_EXEC=y | ||
497 | CONFIG_FEATURE_FIND_EXEC_PLUS=y | ||
498 | CONFIG_FEATURE_FIND_EXEC_OK=y | ||
499 | # CONFIG_FEATURE_FIND_USER is not set | ||
500 | # CONFIG_FEATURE_FIND_GROUP is not set | ||
501 | CONFIG_FEATURE_FIND_NOT=y | ||
502 | CONFIG_FEATURE_FIND_DEPTH=y | ||
503 | CONFIG_FEATURE_FIND_PAREN=y | ||
504 | CONFIG_FEATURE_FIND_SIZE=y | ||
505 | CONFIG_FEATURE_FIND_PRUNE=y | ||
506 | CONFIG_FEATURE_FIND_QUIT=y | ||
507 | CONFIG_FEATURE_FIND_DELETE=y | ||
508 | CONFIG_FEATURE_FIND_EMPTY=y | ||
509 | CONFIG_FEATURE_FIND_PATH=y | ||
510 | CONFIG_FEATURE_FIND_REGEX=y | ||
511 | # CONFIG_FEATURE_FIND_CONTEXT is not set | ||
512 | CONFIG_FEATURE_FIND_LINKS=y | ||
513 | CONFIG_GREP=y | ||
514 | CONFIG_EGREP=y | ||
515 | CONFIG_FGREP=y | ||
516 | CONFIG_FEATURE_GREP_CONTEXT=y | ||
517 | CONFIG_XARGS=y | ||
518 | CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y | ||
519 | CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y | ||
520 | CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y | ||
521 | CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y | ||
522 | CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y | ||
523 | CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y | ||
524 | CONFIG_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 | ||
537 | CONFIG_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 | ||
542 | CONFIG_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 | ||
547 | CONFIG_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 | ||
564 | CONFIG_LAST_ID=0 | ||
565 | CONFIG_FIRST_SYSTEM_ID=0 | ||
566 | CONFIG_LAST_SYSTEM_ID=0 | ||
567 | # CONFIG_CHPASSWD is not set | ||
568 | CONFIG_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 | ||
587 | CONFIG_SUW32=y | ||
588 | # CONFIG_VLOCK is not set | ||
589 | |||
590 | # | ||
591 | # Linux Ext2 FS Progs | ||
592 | # | ||
593 | CONFIG_CHATTR=y | ||
594 | # CONFIG_FSCK is not set | ||
595 | CONFIG_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 | ||
626 | CONFIG_DEFAULT_MODULES_DIR="" | ||
627 | CONFIG_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 | ||
638 | CONFIG_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 | ||
666 | CONFIG_GETOPT=y | ||
667 | CONFIG_FEATURE_GETOPT_LONG=y | ||
668 | CONFIG_HEXDUMP=y | ||
669 | CONFIG_HD=y | ||
670 | CONFIG_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 | ||
719 | CONFIG_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 | ||
780 | CONFIG_ASCII=y | ||
781 | # CONFIG_BBCONFIG is not set | ||
782 | # CONFIG_FEATURE_COMPRESS_BBCONFIG is not set | ||
783 | CONFIG_BC=y | ||
784 | CONFIG_DC=y | ||
785 | CONFIG_FEATURE_DC_BIG=y | ||
786 | # CONFIG_FEATURE_DC_LIBM is not set | ||
787 | CONFIG_FEATURE_BC_INTERACTIVE=y | ||
788 | CONFIG_FEATURE_BC_LONG_OPTIONS=y | ||
789 | # CONFIG_BEEP is not set | ||
790 | CONFIG_FEATURE_BEEP_FREQ=0 | ||
791 | CONFIG_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 | ||
805 | CONFIG_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 | ||
813 | CONFIG_DROP=y | ||
814 | CONFIG_CDROP=y | ||
815 | CONFIG_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 | ||
835 | CONFIG_ICONV=y | ||
836 | CONFIG_INOTIFYD=y | ||
837 | CONFIG_JN=y | ||
838 | CONFIG_LESS=y | ||
839 | CONFIG_FEATURE_LESS_MAXLINES=9999999 | ||
840 | CONFIG_FEATURE_LESS_BRACKETS=y | ||
841 | CONFIG_FEATURE_LESS_FLAGS=y | ||
842 | CONFIG_FEATURE_LESS_TRUNCATE=y | ||
843 | CONFIG_FEATURE_LESS_MARKS=y | ||
844 | CONFIG_FEATURE_LESS_REGEXP=y | ||
845 | # CONFIG_FEATURE_LESS_WINCH is not set | ||
846 | # CONFIG_FEATURE_LESS_ASK_TERMINAL is not set | ||
847 | CONFIG_FEATURE_LESS_DASHCMD=y | ||
848 | CONFIG_FEATURE_LESS_LINENUMS=y | ||
849 | CONFIG_FEATURE_LESS_RAW=y | ||
850 | CONFIG_FEATURE_LESS_ENV=y | ||
851 | # CONFIG_LSSCSI is not set | ||
852 | CONFIG_MAKE=y | ||
853 | CONFIG_PDPMAKE=y | ||
854 | CONFIG_FEATURE_MAKE_POSIX=y | ||
855 | # CONFIG_FEATURE_MAKE_POSIX_2017 is not set | ||
856 | CONFIG_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 | ||
860 | CONFIG_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 | ||
875 | CONFIG_STRINGS=y | ||
876 | CONFIG_TIME=y | ||
877 | # CONFIG_TREE is not set | ||
878 | CONFIG_TS=y | ||
879 | CONFIG_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 | # | ||
894 | CONFIG_FEATURE_IPV6=y | ||
895 | # CONFIG_FEATURE_UNIX_LOCAL is not set | ||
896 | CONFIG_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 | ||
913 | CONFIG_FTPGET=y | ||
914 | CONFIG_FTPPUT=y | ||
915 | CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y | ||
916 | # CONFIG_HOSTNAME is not set | ||
917 | # CONFIG_DNSDOMAINNAME is not set | ||
918 | CONFIG_HTTPD=y | ||
919 | CONFIG_FEATURE_HTTPD_PORT_DEFAULT=80 | ||
920 | CONFIG_FEATURE_HTTPD_RANGES=y | ||
921 | # CONFIG_FEATURE_HTTPD_SETUID is not set | ||
922 | CONFIG_FEATURE_HTTPD_BASIC_AUTH=y | ||
923 | # CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set | ||
924 | CONFIG_FEATURE_HTTPD_CGI=y | ||
925 | CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y | ||
926 | # CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set | ||
927 | CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y | ||
928 | CONFIG_FEATURE_HTTPD_ERROR_PAGES=y | ||
929 | # CONFIG_FEATURE_HTTPD_PROXY is not set | ||
930 | CONFIG_FEATURE_HTTPD_GZIP=y | ||
931 | CONFIG_FEATURE_HTTPD_ETAG=y | ||
932 | CONFIG_FEATURE_HTTPD_LAST_MODIFIED=y | ||
933 | CONFIG_FEATURE_HTTPD_DATE=y | ||
934 | CONFIG_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 | ||
945 | CONFIG_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 | ||
968 | CONFIG_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 | ||
973 | CONFIG_IPCALC=y | ||
974 | CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y | ||
975 | CONFIG_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 | ||
980 | CONFIG_NC=y | ||
981 | # CONFIG_NETCAT is not set | ||
982 | CONFIG_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 | ||
1001 | CONFIG_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 | ||
1012 | CONFIG_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 | ||
1022 | CONFIG_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 | ||
1030 | CONFIG_WGET=y | ||
1031 | CONFIG_FEATURE_WGET_LONG_OPTIONS=y | ||
1032 | CONFIG_FEATURE_WGET_STATUSBAR=y | ||
1033 | CONFIG_FEATURE_WGET_FTP=y | ||
1034 | CONFIG_FEATURE_WGET_AUTHENTICATION=y | ||
1035 | # CONFIG_FEATURE_WGET_TIMEOUT is not set | ||
1036 | CONFIG_FEATURE_WGET_HTTPS=y | ||
1037 | # CONFIG_FEATURE_WGET_OPENSSL is not set | ||
1038 | CONFIG_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 | ||
1044 | CONFIG_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 | ||
1050 | CONFIG_UDHCPC_DEFAULT_SCRIPT="" | ||
1051 | CONFIG_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 | ||
1057 | CONFIG_UDHCPC_DEFAULT_INTERFACE="" | ||
1058 | # CONFIG_FEATURE_UDHCP_PORT is not set | ||
1059 | CONFIG_UDHCP_DEBUG=0 | ||
1060 | CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 | ||
1061 | # CONFIG_FEATURE_UDHCP_RFC3397 is not set | ||
1062 | # CONFIG_FEATURE_UDHCP_8021Q is not set | ||
1063 | CONFIG_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 | # | ||
1075 | CONFIG_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 | ||
1088 | CONFIG_FREE=y | ||
1089 | # CONFIG_FUSER is not set | ||
1090 | # CONFIG_IOSTAT is not set | ||
1091 | CONFIG_KILL=y | ||
1092 | CONFIG_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 | ||
1097 | CONFIG_PGREP=y | ||
1098 | CONFIG_PKILL=y | ||
1099 | CONFIG_PIDOF=y | ||
1100 | CONFIG_FEATURE_PIDOF_SINGLE=y | ||
1101 | CONFIG_FEATURE_PIDOF_OMIT=y | ||
1102 | # CONFIG_PMAP is not set | ||
1103 | # CONFIG_POWERTOP is not set | ||
1104 | # CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set | ||
1105 | CONFIG_PS=y | ||
1106 | # CONFIG_FEATURE_PS_WIDE is not set | ||
1107 | # CONFIG_FEATURE_PS_LONG is not set | ||
1108 | CONFIG_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 | ||
1123 | CONFIG_UPTIME=y | ||
1124 | # CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set | ||
1125 | CONFIG_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 | ||
1139 | CONFIG_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 | # | ||
1160 | CONFIG_SH_IS_ASH=y | ||
1161 | # CONFIG_SH_IS_HUSH is not set | ||
1162 | # CONFIG_SH_IS_NONE is not set | ||
1163 | CONFIG_BASH_IS_ASH=y | ||
1164 | # CONFIG_BASH_IS_HUSH is not set | ||
1165 | # CONFIG_BASH_IS_NONE is not set | ||
1166 | CONFIG_SHELL_ASH=y | ||
1167 | CONFIG_ASH=y | ||
1168 | # CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set | ||
1169 | CONFIG_ASH_INTERNAL_GLOB=y | ||
1170 | CONFIG_ASH_BASH_COMPAT=y | ||
1171 | # CONFIG_ASH_BASH_SOURCE_CURDIR is not set | ||
1172 | CONFIG_ASH_BASH_NOT_FOUND_HOOK=y | ||
1173 | CONFIG_ASH_JOB_CONTROL=y | ||
1174 | CONFIG_ASH_ALIAS=y | ||
1175 | CONFIG_ASH_RANDOM_SUPPORT=y | ||
1176 | CONFIG_ASH_EXPAND_PRMT=y | ||
1177 | # CONFIG_ASH_IDLE_TIMEOUT is not set | ||
1178 | # CONFIG_ASH_MAIL is not set | ||
1179 | CONFIG_ASH_ECHO=y | ||
1180 | CONFIG_ASH_PRINTF=y | ||
1181 | CONFIG_ASH_TEST=y | ||
1182 | CONFIG_ASH_HELP=y | ||
1183 | CONFIG_ASH_GETOPTS=y | ||
1184 | CONFIG_ASH_CMDCMD=y | ||
1185 | CONFIG_ASH_NOCONSOLE=y | ||
1186 | CONFIG_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 | # | ||
1229 | CONFIG_FEATURE_SH_MATH=y | ||
1230 | CONFIG_FEATURE_SH_MATH_64=y | ||
1231 | CONFIG_FEATURE_SH_MATH_BASE=y | ||
1232 | CONFIG_FEATURE_SH_EXTRA_QUIET=y | ||
1233 | CONFIG_FEATURE_SH_STANDALONE=y | ||
1234 | CONFIG_FEATURE_SH_NOFORK=y | ||
1235 | CONFIG_FEATURE_SH_READ_FRAC=y | ||
1236 | CONFIG_FEATURE_SH_HISTFILESIZE=y | ||
1237 | CONFIG_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 | ||
1253 | CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 | ||
1254 | # CONFIG_FEATURE_IPC_SYSLOG is not set | ||
1255 | CONFIG_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 | # | ||
6 | CONFIG_HAVE_DOT_CONFIG=y | ||
7 | # CONFIG_PLATFORM_POSIX is not set | ||
8 | CONFIG_PLATFORM_MINGW32=y | ||
9 | |||
10 | # | ||
11 | # Settings | ||
12 | # | ||
13 | CONFIG_DESKTOP=y | ||
14 | # CONFIG_EXTRA_COMPAT is not set | ||
15 | # CONFIG_FEDORA_COMPAT is not set | ||
16 | # CONFIG_INCLUDE_SUSv2 is not set | ||
17 | CONFIG_LONG_OPTS=y | ||
18 | CONFIG_SHOW_USAGE=y | ||
19 | CONFIG_FEATURE_VERBOSE_USAGE=y | ||
20 | CONFIG_FEATURE_COMPRESS_USAGE=y | ||
21 | CONFIG_LFS=y | ||
22 | CONFIG_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 | ||
28 | CONFIG_PID_FILE_PATH="" | ||
29 | CONFIG_BUSYBOX=y | ||
30 | CONFIG_FEATURE_SHOW_SCRIPT=y | ||
31 | CONFIG_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 | ||
36 | CONFIG_FEATURE_PREFER_APPLETS=y | ||
37 | CONFIG_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 | # | ||
46 | CONFIG_GLOBBING=y | ||
47 | CONFIG_FEATURE_PRNG_SHELL=y | ||
48 | # CONFIG_FEATURE_PRNG_ISAAC is not set | ||
49 | CONFIG_FEATURE_RESOURCES=y | ||
50 | CONFIG_FEATURE_VERSIONINFO=y | ||
51 | # CONFIG_FEATURE_TOOLCHAIN_MANIFEST is not set | ||
52 | CONFIG_FEATURE_APP_MANIFEST=y | ||
53 | # CONFIG_FEATURE_UTF8_MANIFEST is not set | ||
54 | CONFIG_FEATURE_ICON=y | ||
55 | # CONFIG_FEATURE_ICON_ATERM is not set | ||
56 | # CONFIG_FEATURE_ICON_STERM is not set | ||
57 | CONFIG_FEATURE_ICON_ALL=y | ||
58 | CONFIG_FEATURE_EURO=y | ||
59 | # CONFIG_FEATURE_UTF8_INPUT is not set | ||
60 | # CONFIG_FEATURE_UTF8_OUTPUT is not set | ||
61 | CONFIG_TERMINAL_MODE=5 | ||
62 | CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y | ||
63 | CONFIG_FEATURE_EXTRA_FILE_DATA=y | ||
64 | CONFIG_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 | ||
76 | CONFIG_CROSS_COMPILER_PREFIX="aarch64-w64-mingw32-" | ||
77 | CONFIG_HOST_COMPILER="clang" | ||
78 | CONFIG_CROSS_COMPILER="clang" | ||
79 | CONFIG_SYSROOT="" | ||
80 | CONFIG_EXTRA_CFLAGS="" | ||
81 | CONFIG_EXTRA_LDFLAGS="" | ||
82 | CONFIG_EXTRA_LDLIBS="" | ||
83 | CONFIG_USE_PORTABLE_CODE=y | ||
84 | CONFIG_STACK_OPTIMIZATION_386=y | ||
85 | # CONFIG_STATIC_LIBGCC is not set | ||
86 | |||
87 | # | ||
88 | # Installation Options ("make install" behavior) | ||
89 | # | ||
90 | CONFIG_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 | ||
97 | CONFIG_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 | ||
108 | CONFIG_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 | ||
116 | CONFIG_FLOAT_DURATION=y | ||
117 | # CONFIG_FEATURE_RTMINMAX is not set | ||
118 | # CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS is not set | ||
119 | CONFIG_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 | ||
122 | CONFIG_PASSWORD_MINLEN=6 | ||
123 | CONFIG_MD5_SMALL=1 | ||
124 | CONFIG_SHA1_SMALL=3 | ||
125 | # CONFIG_SHA1_HWACCEL is not set | ||
126 | # CONFIG_SHA256_HWACCEL is not set | ||
127 | CONFIG_SHA3_SMALL=1 | ||
128 | CONFIG_FEATURE_NON_POSIX_CP=y | ||
129 | # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set | ||
130 | # CONFIG_FEATURE_USE_SENDFILE is not set | ||
131 | CONFIG_FEATURE_COPYBUF_KB=4 | ||
132 | # CONFIG_MONOTONIC_SYSCALL is not set | ||
133 | # CONFIG_IOCTL_HEX2STR_ERROR is not set | ||
134 | CONFIG_FEATURE_EDITING=y | ||
135 | CONFIG_FEATURE_EDITING_MAX_LEN=8192 | ||
136 | CONFIG_FEATURE_EDITING_VI=y | ||
137 | CONFIG_FEATURE_EDITING_HISTORY=1023 | ||
138 | CONFIG_FEATURE_EDITING_HISTORY_DEFAULT=384 | ||
139 | CONFIG_FEATURE_EDITING_SAVEHISTORY=y | ||
140 | # CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set | ||
141 | CONFIG_FEATURE_REVERSE_SEARCH=y | ||
142 | CONFIG_FEATURE_TAB_COMPLETION=y | ||
143 | CONFIG_FEATURE_USERNAME_COMPLETION=y | ||
144 | CONFIG_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 | ||
151 | CONFIG_SUBST_WCHAR=0 | ||
152 | CONFIG_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 | ||
160 | CONFIG_TRY_LOOP_CONFIGURE=y | ||
161 | |||
162 | # | ||
163 | # Applets | ||
164 | # | ||
165 | |||
166 | # | ||
167 | # Archival Utilities | ||
168 | # | ||
169 | CONFIG_FEATURE_SEAMLESS_XZ=y | ||
170 | CONFIG_FEATURE_SEAMLESS_LZMA=y | ||
171 | CONFIG_FEATURE_SEAMLESS_BZ2=y | ||
172 | CONFIG_FEATURE_SEAMLESS_GZ=y | ||
173 | CONFIG_FEATURE_SEAMLESS_Z=y | ||
174 | CONFIG_AR=y | ||
175 | CONFIG_FEATURE_AR_LONG_FILENAMES=y | ||
176 | CONFIG_FEATURE_AR_CREATE=y | ||
177 | CONFIG_UNCOMPRESS=y | ||
178 | CONFIG_GUNZIP=y | ||
179 | CONFIG_ZCAT=y | ||
180 | CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y | ||
181 | CONFIG_BUNZIP2=y | ||
182 | CONFIG_BZCAT=y | ||
183 | CONFIG_UNLZMA=y | ||
184 | CONFIG_LZCAT=y | ||
185 | CONFIG_LZMA=y | ||
186 | CONFIG_UNXZ=y | ||
187 | CONFIG_XZCAT=y | ||
188 | CONFIG_XZ=y | ||
189 | CONFIG_BZIP2=y | ||
190 | CONFIG_BZIP2_SMALL=8 | ||
191 | CONFIG_FEATURE_BZIP2_DECOMPRESS=y | ||
192 | CONFIG_CPIO=y | ||
193 | CONFIG_FEATURE_CPIO_O=y | ||
194 | # CONFIG_FEATURE_CPIO_P is not set | ||
195 | CONFIG_FEATURE_CPIO_IGNORE_DEVNO=y | ||
196 | CONFIG_FEATURE_CPIO_RENUMBER_INODES=y | ||
197 | CONFIG_DPKG=y | ||
198 | CONFIG_DPKG_DEB=y | ||
199 | CONFIG_GZIP=y | ||
200 | CONFIG_FEATURE_GZIP_LONG_OPTIONS=y | ||
201 | CONFIG_GZIP_FAST=2 | ||
202 | CONFIG_FEATURE_GZIP_LEVELS=y | ||
203 | CONFIG_FEATURE_GZIP_DECOMPRESS=y | ||
204 | CONFIG_LZOP=y | ||
205 | CONFIG_UNLZOP=y | ||
206 | CONFIG_LZOPCAT=y | ||
207 | # CONFIG_LZOP_COMPR_HIGH is not set | ||
208 | CONFIG_RPM=y | ||
209 | CONFIG_RPM2CPIO=y | ||
210 | CONFIG_TAR=y | ||
211 | CONFIG_FEATURE_TAR_LONG_OPTIONS=y | ||
212 | CONFIG_FEATURE_TAR_CREATE=y | ||
213 | CONFIG_FEATURE_TAR_AUTODETECT=y | ||
214 | CONFIG_FEATURE_TAR_FROM=y | ||
215 | CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y | ||
216 | # CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set | ||
217 | CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y | ||
218 | # CONFIG_FEATURE_TAR_TO_COMMAND is not set | ||
219 | # CONFIG_FEATURE_TAR_UNAME_GNAME is not set | ||
220 | CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y | ||
221 | # CONFIG_FEATURE_TAR_SELINUX is not set | ||
222 | CONFIG_UNZIP=y | ||
223 | CONFIG_FEATURE_UNZIP_CDF=y | ||
224 | CONFIG_FEATURE_UNZIP_BZIP2=y | ||
225 | CONFIG_FEATURE_UNZIP_LZMA=y | ||
226 | CONFIG_FEATURE_UNZIP_XZ=y | ||
227 | CONFIG_FEATURE_LZMA_FAST=y | ||
228 | |||
229 | # | ||
230 | # Coreutils | ||
231 | # | ||
232 | CONFIG_FEATURE_VERBOSE=y | ||
233 | |||
234 | # | ||
235 | # Common options for date and touch | ||
236 | # | ||
237 | CONFIG_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 | # | ||
247 | CONFIG_FEATURE_HUMAN_READABLE=y | ||
248 | CONFIG_BASENAME=y | ||
249 | CONFIG_CAT=y | ||
250 | CONFIG_FEATURE_CATN=y | ||
251 | CONFIG_FEATURE_CATV=y | ||
252 | # CONFIG_CHGRP is not set | ||
253 | CONFIG_CHMOD=y | ||
254 | # CONFIG_CHOWN is not set | ||
255 | # CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set | ||
256 | # CONFIG_CHROOT is not set | ||
257 | CONFIG_CKSUM=y | ||
258 | CONFIG_CRC32=y | ||
259 | CONFIG_COMM=y | ||
260 | CONFIG_CP=y | ||
261 | CONFIG_FEATURE_CP_LONG_OPTIONS=y | ||
262 | # CONFIG_FEATURE_CP_REFLINK is not set | ||
263 | CONFIG_CUT=y | ||
264 | CONFIG_FEATURE_CUT_REGEX=y | ||
265 | CONFIG_DATE=y | ||
266 | CONFIG_FEATURE_DATE_ISOFMT=y | ||
267 | CONFIG_FEATURE_DATE_NANO=y | ||
268 | CONFIG_FEATURE_DATE_COMPAT=y | ||
269 | CONFIG_DD=y | ||
270 | # CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set | ||
271 | # CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set | ||
272 | CONFIG_FEATURE_DD_IBS_OBS=y | ||
273 | CONFIG_FEATURE_DD_STATUS=y | ||
274 | CONFIG_DF=y | ||
275 | # CONFIG_FEATURE_DF_FANCY is not set | ||
276 | # CONFIG_FEATURE_SKIP_ROOTFS is not set | ||
277 | CONFIG_DIRNAME=y | ||
278 | CONFIG_DOS2UNIX=y | ||
279 | CONFIG_UNIX2DOS=y | ||
280 | CONFIG_DU=y | ||
281 | CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y | ||
282 | CONFIG_ECHO=y | ||
283 | CONFIG_FEATURE_FANCY_ECHO=y | ||
284 | CONFIG_ENV=y | ||
285 | CONFIG_EXPAND=y | ||
286 | CONFIG_UNEXPAND=y | ||
287 | CONFIG_EXPR=y | ||
288 | CONFIG_EXPR_MATH_SUPPORT_64=y | ||
289 | CONFIG_FACTOR=y | ||
290 | CONFIG_FALSE=y | ||
291 | CONFIG_FOLD=y | ||
292 | CONFIG_HEAD=y | ||
293 | CONFIG_FEATURE_FANCY_HEAD=y | ||
294 | # CONFIG_HOSTID is not set | ||
295 | CONFIG_ID=y | ||
296 | CONFIG_GROUPS=y | ||
297 | CONFIG_INSTALL=y | ||
298 | CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y | ||
299 | CONFIG_LINK=y | ||
300 | CONFIG_LN=y | ||
301 | CONFIG_LOGNAME=y | ||
302 | CONFIG_LS=y | ||
303 | CONFIG_FEATURE_LS_FILETYPES=y | ||
304 | CONFIG_FEATURE_LS_FOLLOWLINKS=y | ||
305 | CONFIG_FEATURE_LS_RECURSIVE=y | ||
306 | CONFIG_FEATURE_LS_WIDTH=y | ||
307 | CONFIG_FEATURE_LS_SORTFILES=y | ||
308 | CONFIG_FEATURE_LS_TIMESTAMPS=y | ||
309 | CONFIG_FEATURE_LS_USERNAME=y | ||
310 | CONFIG_FEATURE_LS_COLOR=y | ||
311 | CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y | ||
312 | CONFIG_MD5SUM=y | ||
313 | CONFIG_SHA1SUM=y | ||
314 | CONFIG_SHA256SUM=y | ||
315 | CONFIG_SHA512SUM=y | ||
316 | CONFIG_SHA3SUM=y | ||
317 | |||
318 | # | ||
319 | # Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum | ||
320 | # | ||
321 | CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y | ||
322 | CONFIG_MKDIR=y | ||
323 | # CONFIG_MKFIFO is not set | ||
324 | # CONFIG_MKNOD is not set | ||
325 | CONFIG_MKTEMP=y | ||
326 | CONFIG_MV=y | ||
327 | # CONFIG_NICE is not set | ||
328 | CONFIG_NL=y | ||
329 | # CONFIG_NOHUP is not set | ||
330 | CONFIG_NPROC=y | ||
331 | CONFIG_OD=y | ||
332 | CONFIG_PASTE=y | ||
333 | CONFIG_PRINTENV=y | ||
334 | CONFIG_PRINTF=y | ||
335 | CONFIG_PWD=y | ||
336 | CONFIG_READLINK=y | ||
337 | CONFIG_FEATURE_READLINK_FOLLOW=y | ||
338 | CONFIG_REALPATH=y | ||
339 | CONFIG_RM=y | ||
340 | CONFIG_RMDIR=y | ||
341 | CONFIG_SEQ=y | ||
342 | CONFIG_SHRED=y | ||
343 | CONFIG_SHUF=y | ||
344 | CONFIG_SLEEP=y | ||
345 | CONFIG_FEATURE_FANCY_SLEEP=y | ||
346 | CONFIG_SORT=y | ||
347 | CONFIG_FEATURE_SORT_BIG=y | ||
348 | # CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set | ||
349 | CONFIG_SPLIT=y | ||
350 | CONFIG_FEATURE_SPLIT_FANCY=y | ||
351 | CONFIG_STAT=y | ||
352 | CONFIG_FEATURE_STAT_FORMAT=y | ||
353 | CONFIG_FEATURE_STAT_FILESYSTEM=y | ||
354 | # CONFIG_STTY is not set | ||
355 | CONFIG_SUM=y | ||
356 | CONFIG_SYNC=y | ||
357 | # CONFIG_FEATURE_SYNC_FANCY is not set | ||
358 | CONFIG_FSYNC=y | ||
359 | CONFIG_TAC=y | ||
360 | CONFIG_TAIL=y | ||
361 | CONFIG_FEATURE_FANCY_TAIL=y | ||
362 | CONFIG_TEE=y | ||
363 | CONFIG_FEATURE_TEE_USE_BLOCK_IO=y | ||
364 | CONFIG_TEST=y | ||
365 | CONFIG_TEST1=y | ||
366 | CONFIG_TEST2=y | ||
367 | CONFIG_FEATURE_TEST_64=y | ||
368 | CONFIG_TIMEOUT=y | ||
369 | CONFIG_TOUCH=y | ||
370 | CONFIG_FEATURE_TOUCH_SUSV3=y | ||
371 | CONFIG_TR=y | ||
372 | CONFIG_FEATURE_TR_CLASSES=y | ||
373 | CONFIG_FEATURE_TR_EQUIV=y | ||
374 | CONFIG_TRUE=y | ||
375 | CONFIG_TRUNCATE=y | ||
376 | CONFIG_TSORT=y | ||
377 | # CONFIG_TTY is not set | ||
378 | CONFIG_UNAME=y | ||
379 | CONFIG_UNAME_OSNAME="MS/Windows" | ||
380 | CONFIG_BB_ARCH=y | ||
381 | CONFIG_UNIQ=y | ||
382 | CONFIG_UNLINK=y | ||
383 | CONFIG_USLEEP=y | ||
384 | CONFIG_UUDECODE=y | ||
385 | CONFIG_BASE32=y | ||
386 | CONFIG_BASE64=y | ||
387 | CONFIG_UUENCODE=y | ||
388 | CONFIG_WC=y | ||
389 | CONFIG_FEATURE_WC_LARGE=y | ||
390 | # CONFIG_WHO is not set | ||
391 | # CONFIG_W is not set | ||
392 | # CONFIG_USERS is not set | ||
393 | CONFIG_WHOAMI=y | ||
394 | CONFIG_YES=y | ||
395 | |||
396 | # | ||
397 | # Console Utilities | ||
398 | # | ||
399 | # CONFIG_CHVT is not set | ||
400 | CONFIG_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 | ||
408 | CONFIG_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 | ||
413 | CONFIG_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 | # | ||
425 | CONFIG_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 | ||
432 | CONFIG_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 | # | ||
445 | CONFIG_AWK=y | ||
446 | CONFIG_FEATURE_AWK_LIBM=y | ||
447 | CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y | ||
448 | CONFIG_CMP=y | ||
449 | CONFIG_DIFF=y | ||
450 | CONFIG_FEATURE_DIFF_LONG_OPTIONS=y | ||
451 | CONFIG_FEATURE_DIFF_DIR=y | ||
452 | CONFIG_ED=y | ||
453 | CONFIG_PATCH=y | ||
454 | CONFIG_SED=y | ||
455 | CONFIG_VI=y | ||
456 | CONFIG_FEATURE_VI_MAX_LEN=4096 | ||
457 | CONFIG_FEATURE_VI_8BIT=y | ||
458 | CONFIG_FEATURE_VI_COLON=y | ||
459 | CONFIG_FEATURE_VI_COLON_EXPAND=y | ||
460 | CONFIG_FEATURE_VI_YANKMARK=y | ||
461 | CONFIG_FEATURE_VI_SEARCH=y | ||
462 | CONFIG_FEATURE_VI_REGEX_SEARCH=y | ||
463 | # CONFIG_FEATURE_VI_USE_SIGNALS is not set | ||
464 | CONFIG_FEATURE_VI_DOT_CMD=y | ||
465 | CONFIG_FEATURE_VI_READONLY=y | ||
466 | CONFIG_FEATURE_VI_SETOPTS=y | ||
467 | CONFIG_FEATURE_VI_FILE_FORMAT=y | ||
468 | CONFIG_FEATURE_VI_SET=y | ||
469 | CONFIG_FEATURE_VI_WIN_RESIZE=y | ||
470 | # CONFIG_FEATURE_VI_ASK_TERMINAL is not set | ||
471 | CONFIG_FEATURE_VI_UNDO=y | ||
472 | CONFIG_FEATURE_VI_UNDO_QUEUE=y | ||
473 | CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256 | ||
474 | CONFIG_FEATURE_VI_VERBOSE_STATUS=y | ||
475 | CONFIG_FEATURE_ALLOW_EXEC=y | ||
476 | |||
477 | # | ||
478 | # Finding Utilities | ||
479 | # | ||
480 | CONFIG_FIND=y | ||
481 | CONFIG_FEATURE_FIND_PRINT0=y | ||
482 | CONFIG_FEATURE_FIND_MTIME=y | ||
483 | CONFIG_FEATURE_FIND_ATIME=y | ||
484 | CONFIG_FEATURE_FIND_CTIME=y | ||
485 | CONFIG_FEATURE_FIND_MMIN=y | ||
486 | CONFIG_FEATURE_FIND_AMIN=y | ||
487 | CONFIG_FEATURE_FIND_CMIN=y | ||
488 | CONFIG_FEATURE_FIND_PERM=y | ||
489 | CONFIG_FEATURE_FIND_TYPE=y | ||
490 | CONFIG_FEATURE_FIND_EXECUTABLE=y | ||
491 | CONFIG_FEATURE_FIND_XDEV=y | ||
492 | CONFIG_FEATURE_FIND_MAXDEPTH=y | ||
493 | CONFIG_FEATURE_FIND_NEWER=y | ||
494 | CONFIG_FEATURE_FIND_INUM=y | ||
495 | CONFIG_FEATURE_FIND_SAMEFILE=y | ||
496 | CONFIG_FEATURE_FIND_EXEC=y | ||
497 | CONFIG_FEATURE_FIND_EXEC_PLUS=y | ||
498 | CONFIG_FEATURE_FIND_EXEC_OK=y | ||
499 | # CONFIG_FEATURE_FIND_USER is not set | ||
500 | # CONFIG_FEATURE_FIND_GROUP is not set | ||
501 | CONFIG_FEATURE_FIND_NOT=y | ||
502 | CONFIG_FEATURE_FIND_DEPTH=y | ||
503 | CONFIG_FEATURE_FIND_PAREN=y | ||
504 | CONFIG_FEATURE_FIND_SIZE=y | ||
505 | CONFIG_FEATURE_FIND_PRUNE=y | ||
506 | CONFIG_FEATURE_FIND_QUIT=y | ||
507 | CONFIG_FEATURE_FIND_DELETE=y | ||
508 | CONFIG_FEATURE_FIND_EMPTY=y | ||
509 | CONFIG_FEATURE_FIND_PATH=y | ||
510 | CONFIG_FEATURE_FIND_REGEX=y | ||
511 | # CONFIG_FEATURE_FIND_CONTEXT is not set | ||
512 | CONFIG_FEATURE_FIND_LINKS=y | ||
513 | CONFIG_GREP=y | ||
514 | CONFIG_EGREP=y | ||
515 | CONFIG_FGREP=y | ||
516 | CONFIG_FEATURE_GREP_CONTEXT=y | ||
517 | CONFIG_XARGS=y | ||
518 | CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y | ||
519 | CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y | ||
520 | CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y | ||
521 | CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y | ||
522 | CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y | ||
523 | CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y | ||
524 | CONFIG_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 | ||
537 | CONFIG_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 | ||
542 | CONFIG_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 | ||
547 | CONFIG_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 | ||
564 | CONFIG_LAST_ID=0 | ||
565 | CONFIG_FIRST_SYSTEM_ID=0 | ||
566 | CONFIG_LAST_SYSTEM_ID=0 | ||
567 | # CONFIG_CHPASSWD is not set | ||
568 | CONFIG_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 | ||
587 | CONFIG_SUW32=y | ||
588 | # CONFIG_VLOCK is not set | ||
589 | |||
590 | # | ||
591 | # Linux Ext2 FS Progs | ||
592 | # | ||
593 | CONFIG_CHATTR=y | ||
594 | # CONFIG_FSCK is not set | ||
595 | CONFIG_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 | ||
626 | CONFIG_DEFAULT_MODULES_DIR="" | ||
627 | CONFIG_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 | ||
638 | CONFIG_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 | ||
666 | CONFIG_GETOPT=y | ||
667 | CONFIG_FEATURE_GETOPT_LONG=y | ||
668 | CONFIG_HEXDUMP=y | ||
669 | CONFIG_HD=y | ||
670 | CONFIG_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 | ||
719 | CONFIG_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 | ||
780 | CONFIG_ASCII=y | ||
781 | # CONFIG_BBCONFIG is not set | ||
782 | # CONFIG_FEATURE_COMPRESS_BBCONFIG is not set | ||
783 | CONFIG_BC=y | ||
784 | CONFIG_DC=y | ||
785 | CONFIG_FEATURE_DC_BIG=y | ||
786 | # CONFIG_FEATURE_DC_LIBM is not set | ||
787 | CONFIG_FEATURE_BC_INTERACTIVE=y | ||
788 | CONFIG_FEATURE_BC_LONG_OPTIONS=y | ||
789 | # CONFIG_BEEP is not set | ||
790 | CONFIG_FEATURE_BEEP_FREQ=0 | ||
791 | CONFIG_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 | ||
805 | CONFIG_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 | ||
813 | CONFIG_DROP=y | ||
814 | CONFIG_CDROP=y | ||
815 | CONFIG_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 | ||
835 | CONFIG_ICONV=y | ||
836 | CONFIG_INOTIFYD=y | ||
837 | CONFIG_JN=y | ||
838 | CONFIG_LESS=y | ||
839 | CONFIG_FEATURE_LESS_MAXLINES=9999999 | ||
840 | CONFIG_FEATURE_LESS_BRACKETS=y | ||
841 | CONFIG_FEATURE_LESS_FLAGS=y | ||
842 | CONFIG_FEATURE_LESS_TRUNCATE=y | ||
843 | CONFIG_FEATURE_LESS_MARKS=y | ||
844 | CONFIG_FEATURE_LESS_REGEXP=y | ||
845 | # CONFIG_FEATURE_LESS_WINCH is not set | ||
846 | # CONFIG_FEATURE_LESS_ASK_TERMINAL is not set | ||
847 | CONFIG_FEATURE_LESS_DASHCMD=y | ||
848 | CONFIG_FEATURE_LESS_LINENUMS=y | ||
849 | CONFIG_FEATURE_LESS_RAW=y | ||
850 | CONFIG_FEATURE_LESS_ENV=y | ||
851 | # CONFIG_LSSCSI is not set | ||
852 | CONFIG_MAKE=y | ||
853 | CONFIG_PDPMAKE=y | ||
854 | CONFIG_FEATURE_MAKE_POSIX=y | ||
855 | # CONFIG_FEATURE_MAKE_POSIX_2017 is not set | ||
856 | CONFIG_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 | ||
860 | CONFIG_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 | ||
875 | CONFIG_STRINGS=y | ||
876 | CONFIG_TIME=y | ||
877 | # CONFIG_TREE is not set | ||
878 | CONFIG_TS=y | ||
879 | CONFIG_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 | # | ||
894 | CONFIG_FEATURE_IPV6=y | ||
895 | # CONFIG_FEATURE_UNIX_LOCAL is not set | ||
896 | CONFIG_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 | ||
913 | CONFIG_FTPGET=y | ||
914 | CONFIG_FTPPUT=y | ||
915 | CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y | ||
916 | # CONFIG_HOSTNAME is not set | ||
917 | # CONFIG_DNSDOMAINNAME is not set | ||
918 | CONFIG_HTTPD=y | ||
919 | CONFIG_FEATURE_HTTPD_PORT_DEFAULT=80 | ||
920 | CONFIG_FEATURE_HTTPD_RANGES=y | ||
921 | # CONFIG_FEATURE_HTTPD_SETUID is not set | ||
922 | CONFIG_FEATURE_HTTPD_BASIC_AUTH=y | ||
923 | # CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set | ||
924 | CONFIG_FEATURE_HTTPD_CGI=y | ||
925 | CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y | ||
926 | # CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set | ||
927 | CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y | ||
928 | CONFIG_FEATURE_HTTPD_ERROR_PAGES=y | ||
929 | # CONFIG_FEATURE_HTTPD_PROXY is not set | ||
930 | CONFIG_FEATURE_HTTPD_GZIP=y | ||
931 | CONFIG_FEATURE_HTTPD_ETAG=y | ||
932 | CONFIG_FEATURE_HTTPD_LAST_MODIFIED=y | ||
933 | CONFIG_FEATURE_HTTPD_DATE=y | ||
934 | CONFIG_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 | ||
945 | CONFIG_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 | ||
968 | CONFIG_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 | ||
973 | CONFIG_IPCALC=y | ||
974 | CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y | ||
975 | CONFIG_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 | ||
980 | CONFIG_NC=y | ||
981 | # CONFIG_NETCAT is not set | ||
982 | CONFIG_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 | ||
1001 | CONFIG_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 | ||
1012 | CONFIG_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 | ||
1022 | CONFIG_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 | ||
1030 | CONFIG_WGET=y | ||
1031 | CONFIG_FEATURE_WGET_LONG_OPTIONS=y | ||
1032 | CONFIG_FEATURE_WGET_STATUSBAR=y | ||
1033 | CONFIG_FEATURE_WGET_FTP=y | ||
1034 | CONFIG_FEATURE_WGET_AUTHENTICATION=y | ||
1035 | # CONFIG_FEATURE_WGET_TIMEOUT is not set | ||
1036 | CONFIG_FEATURE_WGET_HTTPS=y | ||
1037 | # CONFIG_FEATURE_WGET_OPENSSL is not set | ||
1038 | CONFIG_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 | ||
1044 | CONFIG_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 | ||
1050 | CONFIG_UDHCPC_DEFAULT_SCRIPT="" | ||
1051 | CONFIG_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 | ||
1057 | CONFIG_UDHCPC_DEFAULT_INTERFACE="" | ||
1058 | # CONFIG_FEATURE_UDHCP_PORT is not set | ||
1059 | CONFIG_UDHCP_DEBUG=0 | ||
1060 | CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 | ||
1061 | # CONFIG_FEATURE_UDHCP_RFC3397 is not set | ||
1062 | # CONFIG_FEATURE_UDHCP_8021Q is not set | ||
1063 | CONFIG_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 | # | ||
1075 | CONFIG_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 | ||
1088 | CONFIG_FREE=y | ||
1089 | # CONFIG_FUSER is not set | ||
1090 | # CONFIG_IOSTAT is not set | ||
1091 | CONFIG_KILL=y | ||
1092 | CONFIG_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 | ||
1097 | CONFIG_PGREP=y | ||
1098 | CONFIG_PKILL=y | ||
1099 | CONFIG_PIDOF=y | ||
1100 | CONFIG_FEATURE_PIDOF_SINGLE=y | ||
1101 | CONFIG_FEATURE_PIDOF_OMIT=y | ||
1102 | # CONFIG_PMAP is not set | ||
1103 | # CONFIG_POWERTOP is not set | ||
1104 | # CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set | ||
1105 | CONFIG_PS=y | ||
1106 | # CONFIG_FEATURE_PS_WIDE is not set | ||
1107 | # CONFIG_FEATURE_PS_LONG is not set | ||
1108 | CONFIG_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 | ||
1123 | CONFIG_UPTIME=y | ||
1124 | # CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set | ||
1125 | CONFIG_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 | ||
1139 | CONFIG_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 | # | ||
1160 | CONFIG_SH_IS_ASH=y | ||
1161 | # CONFIG_SH_IS_HUSH is not set | ||
1162 | # CONFIG_SH_IS_NONE is not set | ||
1163 | CONFIG_BASH_IS_ASH=y | ||
1164 | # CONFIG_BASH_IS_HUSH is not set | ||
1165 | # CONFIG_BASH_IS_NONE is not set | ||
1166 | CONFIG_SHELL_ASH=y | ||
1167 | CONFIG_ASH=y | ||
1168 | # CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set | ||
1169 | CONFIG_ASH_INTERNAL_GLOB=y | ||
1170 | CONFIG_ASH_BASH_COMPAT=y | ||
1171 | # CONFIG_ASH_BASH_SOURCE_CURDIR is not set | ||
1172 | CONFIG_ASH_BASH_NOT_FOUND_HOOK=y | ||
1173 | CONFIG_ASH_JOB_CONTROL=y | ||
1174 | CONFIG_ASH_ALIAS=y | ||
1175 | CONFIG_ASH_RANDOM_SUPPORT=y | ||
1176 | CONFIG_ASH_EXPAND_PRMT=y | ||
1177 | # CONFIG_ASH_IDLE_TIMEOUT is not set | ||
1178 | # CONFIG_ASH_MAIL is not set | ||
1179 | CONFIG_ASH_ECHO=y | ||
1180 | CONFIG_ASH_PRINTF=y | ||
1181 | CONFIG_ASH_TEST=y | ||
1182 | CONFIG_ASH_HELP=y | ||
1183 | CONFIG_ASH_GETOPTS=y | ||
1184 | CONFIG_ASH_CMDCMD=y | ||
1185 | CONFIG_ASH_NOCONSOLE=y | ||
1186 | CONFIG_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 | # | ||
1229 | CONFIG_FEATURE_SH_MATH=y | ||
1230 | CONFIG_FEATURE_SH_MATH_64=y | ||
1231 | CONFIG_FEATURE_SH_MATH_BASE=y | ||
1232 | CONFIG_FEATURE_SH_EXTRA_QUIET=y | ||
1233 | CONFIG_FEATURE_SH_STANDALONE=y | ||
1234 | CONFIG_FEATURE_SH_NOFORK=y | ||
1235 | CONFIG_FEATURE_SH_READ_FRAC=y | ||
1236 | CONFIG_FEATURE_SH_HISTFILESIZE=y | ||
1237 | CONFIG_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 | ||
1253 | CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 | ||
1254 | # CONFIG_FEATURE_IPC_SYSLOG is not set | ||
1255 | CONFIG_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 | # | ||
6 | CONFIG_HAVE_DOT_CONFIG=y | ||
7 | # CONFIG_PLATFORM_POSIX is not set | ||
8 | CONFIG_PLATFORM_MINGW32=y | ||
9 | |||
10 | # | ||
11 | # Settings | ||
12 | # | ||
13 | CONFIG_DESKTOP=y | ||
14 | # CONFIG_EXTRA_COMPAT is not set | ||
15 | # CONFIG_FEDORA_COMPAT is not set | ||
16 | # CONFIG_INCLUDE_SUSv2 is not set | ||
17 | CONFIG_LONG_OPTS=y | ||
18 | CONFIG_SHOW_USAGE=y | ||
19 | CONFIG_FEATURE_VERBOSE_USAGE=y | ||
20 | CONFIG_FEATURE_COMPRESS_USAGE=y | ||
21 | CONFIG_LFS=y | ||
22 | CONFIG_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 | ||
28 | CONFIG_PID_FILE_PATH="" | ||
29 | CONFIG_BUSYBOX=y | ||
30 | CONFIG_FEATURE_SHOW_SCRIPT=y | ||
31 | CONFIG_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 | ||
36 | CONFIG_FEATURE_PREFER_APPLETS=y | ||
37 | CONFIG_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 | # | ||
46 | CONFIG_GLOBBING=y | ||
47 | CONFIG_FEATURE_PRNG_SHELL=y | ||
48 | # CONFIG_FEATURE_PRNG_ISAAC is not set | ||
49 | CONFIG_FEATURE_RESOURCES=y | ||
50 | CONFIG_FEATURE_VERSIONINFO=y | ||
51 | # CONFIG_FEATURE_TOOLCHAIN_MANIFEST is not set | ||
52 | # CONFIG_FEATURE_APP_MANIFEST is not set | ||
53 | CONFIG_FEATURE_UTF8_MANIFEST=y | ||
54 | CONFIG_FEATURE_ICON=y | ||
55 | # CONFIG_FEATURE_ICON_ATERM is not set | ||
56 | # CONFIG_FEATURE_ICON_STERM is not set | ||
57 | CONFIG_FEATURE_ICON_ALL=y | ||
58 | CONFIG_FEATURE_EURO=y | ||
59 | CONFIG_FEATURE_UTF8_INPUT=y | ||
60 | CONFIG_FEATURE_UTF8_OUTPUT=y | ||
61 | CONFIG_TERMINAL_MODE=5 | ||
62 | CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y | ||
63 | CONFIG_FEATURE_EXTRA_FILE_DATA=y | ||
64 | CONFIG_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 | ||
76 | CONFIG_CROSS_COMPILER_PREFIX="x86_64-w64-mingw32-" | ||
77 | CONFIG_HOST_COMPILER="gcc" | ||
78 | CONFIG_CROSS_COMPILER="gcc" | ||
79 | CONFIG_SYSROOT="" | ||
80 | CONFIG_EXTRA_CFLAGS="" | ||
81 | CONFIG_EXTRA_LDFLAGS="" | ||
82 | CONFIG_EXTRA_LDLIBS="" | ||
83 | CONFIG_USE_PORTABLE_CODE=y | ||
84 | CONFIG_STACK_OPTIMIZATION_386=y | ||
85 | CONFIG_STATIC_LIBGCC=y | ||
86 | |||
87 | # | ||
88 | # Installation Options ("make install" behavior) | ||
89 | # | ||
90 | CONFIG_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 | ||
97 | CONFIG_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 | ||
108 | CONFIG_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 | ||
116 | CONFIG_FLOAT_DURATION=y | ||
117 | # CONFIG_FEATURE_RTMINMAX is not set | ||
118 | # CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS is not set | ||
119 | CONFIG_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 | ||
122 | CONFIG_PASSWORD_MINLEN=6 | ||
123 | CONFIG_MD5_SMALL=1 | ||
124 | CONFIG_SHA1_SMALL=3 | ||
125 | # CONFIG_SHA1_HWACCEL is not set | ||
126 | # CONFIG_SHA256_HWACCEL is not set | ||
127 | CONFIG_SHA3_SMALL=1 | ||
128 | CONFIG_FEATURE_NON_POSIX_CP=y | ||
129 | # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set | ||
130 | # CONFIG_FEATURE_USE_SENDFILE is not set | ||
131 | CONFIG_FEATURE_COPYBUF_KB=4 | ||
132 | # CONFIG_MONOTONIC_SYSCALL is not set | ||
133 | # CONFIG_IOCTL_HEX2STR_ERROR is not set | ||
134 | CONFIG_FEATURE_EDITING=y | ||
135 | CONFIG_FEATURE_EDITING_MAX_LEN=8192 | ||
136 | CONFIG_FEATURE_EDITING_VI=y | ||
137 | CONFIG_FEATURE_EDITING_HISTORY=1023 | ||
138 | CONFIG_FEATURE_EDITING_HISTORY_DEFAULT=384 | ||
139 | CONFIG_FEATURE_EDITING_SAVEHISTORY=y | ||
140 | # CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set | ||
141 | CONFIG_FEATURE_REVERSE_SEARCH=y | ||
142 | CONFIG_FEATURE_TAB_COMPLETION=y | ||
143 | CONFIG_FEATURE_USERNAME_COMPLETION=y | ||
144 | CONFIG_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=y | ||
149 | # CONFIG_UNICODE_USING_LOCALE is not set | ||
150 | CONFIG_FEATURE_CHECK_UNICODE_IN_ENV=y | ||
151 | CONFIG_SUBST_WCHAR=63 | ||
152 | CONFIG_LAST_SUPPORTED_WCHAR=1114111 | ||
153 | CONFIG_UNICODE_COMBINING_WCHARS=y | ||
154 | CONFIG_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 | ||
160 | CONFIG_TRY_LOOP_CONFIGURE=y | ||
161 | |||
162 | # | ||
163 | # Applets | ||
164 | # | ||
165 | |||
166 | # | ||
167 | # Archival Utilities | ||
168 | # | ||
169 | CONFIG_FEATURE_SEAMLESS_XZ=y | ||
170 | CONFIG_FEATURE_SEAMLESS_LZMA=y | ||
171 | CONFIG_FEATURE_SEAMLESS_BZ2=y | ||
172 | CONFIG_FEATURE_SEAMLESS_GZ=y | ||
173 | CONFIG_FEATURE_SEAMLESS_Z=y | ||
174 | CONFIG_AR=y | ||
175 | CONFIG_FEATURE_AR_LONG_FILENAMES=y | ||
176 | CONFIG_FEATURE_AR_CREATE=y | ||
177 | CONFIG_UNCOMPRESS=y | ||
178 | CONFIG_GUNZIP=y | ||
179 | CONFIG_ZCAT=y | ||
180 | CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y | ||
181 | CONFIG_BUNZIP2=y | ||
182 | CONFIG_BZCAT=y | ||
183 | CONFIG_UNLZMA=y | ||
184 | CONFIG_LZCAT=y | ||
185 | CONFIG_LZMA=y | ||
186 | CONFIG_UNXZ=y | ||
187 | CONFIG_XZCAT=y | ||
188 | CONFIG_XZ=y | ||
189 | CONFIG_BZIP2=y | ||
190 | CONFIG_BZIP2_SMALL=8 | ||
191 | CONFIG_FEATURE_BZIP2_DECOMPRESS=y | ||
192 | CONFIG_CPIO=y | ||
193 | CONFIG_FEATURE_CPIO_O=y | ||
194 | # CONFIG_FEATURE_CPIO_P is not set | ||
195 | CONFIG_FEATURE_CPIO_IGNORE_DEVNO=y | ||
196 | CONFIG_FEATURE_CPIO_RENUMBER_INODES=y | ||
197 | CONFIG_DPKG=y | ||
198 | CONFIG_DPKG_DEB=y | ||
199 | CONFIG_GZIP=y | ||
200 | CONFIG_FEATURE_GZIP_LONG_OPTIONS=y | ||
201 | CONFIG_GZIP_FAST=2 | ||
202 | CONFIG_FEATURE_GZIP_LEVELS=y | ||
203 | CONFIG_FEATURE_GZIP_DECOMPRESS=y | ||
204 | CONFIG_LZOP=y | ||
205 | CONFIG_UNLZOP=y | ||
206 | CONFIG_LZOPCAT=y | ||
207 | # CONFIG_LZOP_COMPR_HIGH is not set | ||
208 | CONFIG_RPM=y | ||
209 | CONFIG_RPM2CPIO=y | ||
210 | CONFIG_TAR=y | ||
211 | CONFIG_FEATURE_TAR_LONG_OPTIONS=y | ||
212 | CONFIG_FEATURE_TAR_CREATE=y | ||
213 | CONFIG_FEATURE_TAR_AUTODETECT=y | ||
214 | CONFIG_FEATURE_TAR_FROM=y | ||
215 | CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y | ||
216 | # CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set | ||
217 | CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y | ||
218 | # CONFIG_FEATURE_TAR_TO_COMMAND is not set | ||
219 | # CONFIG_FEATURE_TAR_UNAME_GNAME is not set | ||
220 | CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y | ||
221 | # CONFIG_FEATURE_TAR_SELINUX is not set | ||
222 | CONFIG_UNZIP=y | ||
223 | CONFIG_FEATURE_UNZIP_CDF=y | ||
224 | CONFIG_FEATURE_UNZIP_BZIP2=y | ||
225 | CONFIG_FEATURE_UNZIP_LZMA=y | ||
226 | CONFIG_FEATURE_UNZIP_XZ=y | ||
227 | CONFIG_FEATURE_LZMA_FAST=y | ||
228 | |||
229 | # | ||
230 | # Coreutils | ||
231 | # | ||
232 | CONFIG_FEATURE_VERBOSE=y | ||
233 | |||
234 | # | ||
235 | # Common options for date and touch | ||
236 | # | ||
237 | CONFIG_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 | # | ||
247 | CONFIG_FEATURE_HUMAN_READABLE=y | ||
248 | CONFIG_BASENAME=y | ||
249 | CONFIG_CAT=y | ||
250 | CONFIG_FEATURE_CATN=y | ||
251 | CONFIG_FEATURE_CATV=y | ||
252 | # CONFIG_CHGRP is not set | ||
253 | CONFIG_CHMOD=y | ||
254 | # CONFIG_CHOWN is not set | ||
255 | # CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set | ||
256 | # CONFIG_CHROOT is not set | ||
257 | CONFIG_CKSUM=y | ||
258 | CONFIG_CRC32=y | ||
259 | CONFIG_COMM=y | ||
260 | CONFIG_CP=y | ||
261 | CONFIG_FEATURE_CP_LONG_OPTIONS=y | ||
262 | # CONFIG_FEATURE_CP_REFLINK is not set | ||
263 | CONFIG_CUT=y | ||
264 | CONFIG_FEATURE_CUT_REGEX=y | ||
265 | CONFIG_DATE=y | ||
266 | CONFIG_FEATURE_DATE_ISOFMT=y | ||
267 | CONFIG_FEATURE_DATE_NANO=y | ||
268 | CONFIG_FEATURE_DATE_COMPAT=y | ||
269 | CONFIG_DD=y | ||
270 | # CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set | ||
271 | # CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set | ||
272 | CONFIG_FEATURE_DD_IBS_OBS=y | ||
273 | CONFIG_FEATURE_DD_STATUS=y | ||
274 | CONFIG_DF=y | ||
275 | # CONFIG_FEATURE_DF_FANCY is not set | ||
276 | # CONFIG_FEATURE_SKIP_ROOTFS is not set | ||
277 | CONFIG_DIRNAME=y | ||
278 | CONFIG_DOS2UNIX=y | ||
279 | CONFIG_UNIX2DOS=y | ||
280 | CONFIG_DU=y | ||
281 | CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y | ||
282 | CONFIG_ECHO=y | ||
283 | CONFIG_FEATURE_FANCY_ECHO=y | ||
284 | CONFIG_ENV=y | ||
285 | CONFIG_EXPAND=y | ||
286 | CONFIG_UNEXPAND=y | ||
287 | CONFIG_EXPR=y | ||
288 | CONFIG_EXPR_MATH_SUPPORT_64=y | ||
289 | CONFIG_FACTOR=y | ||
290 | CONFIG_FALSE=y | ||
291 | CONFIG_FOLD=y | ||
292 | CONFIG_HEAD=y | ||
293 | CONFIG_FEATURE_FANCY_HEAD=y | ||
294 | # CONFIG_HOSTID is not set | ||
295 | CONFIG_ID=y | ||
296 | CONFIG_GROUPS=y | ||
297 | CONFIG_INSTALL=y | ||
298 | CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y | ||
299 | CONFIG_LINK=y | ||
300 | CONFIG_LN=y | ||
301 | CONFIG_LOGNAME=y | ||
302 | CONFIG_LS=y | ||
303 | CONFIG_FEATURE_LS_FILETYPES=y | ||
304 | CONFIG_FEATURE_LS_FOLLOWLINKS=y | ||
305 | CONFIG_FEATURE_LS_RECURSIVE=y | ||
306 | CONFIG_FEATURE_LS_WIDTH=y | ||
307 | CONFIG_FEATURE_LS_SORTFILES=y | ||
308 | CONFIG_FEATURE_LS_TIMESTAMPS=y | ||
309 | CONFIG_FEATURE_LS_USERNAME=y | ||
310 | CONFIG_FEATURE_LS_COLOR=y | ||
311 | CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y | ||
312 | CONFIG_MD5SUM=y | ||
313 | CONFIG_SHA1SUM=y | ||
314 | CONFIG_SHA256SUM=y | ||
315 | CONFIG_SHA512SUM=y | ||
316 | CONFIG_SHA3SUM=y | ||
317 | |||
318 | # | ||
319 | # Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum | ||
320 | # | ||
321 | CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y | ||
322 | CONFIG_MKDIR=y | ||
323 | # CONFIG_MKFIFO is not set | ||
324 | # CONFIG_MKNOD is not set | ||
325 | CONFIG_MKTEMP=y | ||
326 | CONFIG_MV=y | ||
327 | # CONFIG_NICE is not set | ||
328 | CONFIG_NL=y | ||
329 | # CONFIG_NOHUP is not set | ||
330 | CONFIG_NPROC=y | ||
331 | CONFIG_OD=y | ||
332 | CONFIG_PASTE=y | ||
333 | CONFIG_PRINTENV=y | ||
334 | CONFIG_PRINTF=y | ||
335 | CONFIG_PWD=y | ||
336 | CONFIG_READLINK=y | ||
337 | CONFIG_FEATURE_READLINK_FOLLOW=y | ||
338 | CONFIG_REALPATH=y | ||
339 | CONFIG_RM=y | ||
340 | CONFIG_RMDIR=y | ||
341 | CONFIG_SEQ=y | ||
342 | CONFIG_SHRED=y | ||
343 | CONFIG_SHUF=y | ||
344 | CONFIG_SLEEP=y | ||
345 | CONFIG_FEATURE_FANCY_SLEEP=y | ||
346 | CONFIG_SORT=y | ||
347 | CONFIG_FEATURE_SORT_BIG=y | ||
348 | # CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set | ||
349 | CONFIG_SPLIT=y | ||
350 | CONFIG_FEATURE_SPLIT_FANCY=y | ||
351 | CONFIG_STAT=y | ||
352 | CONFIG_FEATURE_STAT_FORMAT=y | ||
353 | CONFIG_FEATURE_STAT_FILESYSTEM=y | ||
354 | # CONFIG_STTY is not set | ||
355 | CONFIG_SUM=y | ||
356 | CONFIG_SYNC=y | ||
357 | # CONFIG_FEATURE_SYNC_FANCY is not set | ||
358 | CONFIG_FSYNC=y | ||
359 | CONFIG_TAC=y | ||
360 | CONFIG_TAIL=y | ||
361 | CONFIG_FEATURE_FANCY_TAIL=y | ||
362 | CONFIG_TEE=y | ||
363 | CONFIG_FEATURE_TEE_USE_BLOCK_IO=y | ||
364 | CONFIG_TEST=y | ||
365 | CONFIG_TEST1=y | ||
366 | CONFIG_TEST2=y | ||
367 | CONFIG_FEATURE_TEST_64=y | ||
368 | CONFIG_TIMEOUT=y | ||
369 | CONFIG_TOUCH=y | ||
370 | CONFIG_FEATURE_TOUCH_SUSV3=y | ||
371 | CONFIG_TR=y | ||
372 | CONFIG_FEATURE_TR_CLASSES=y | ||
373 | CONFIG_FEATURE_TR_EQUIV=y | ||
374 | CONFIG_TRUE=y | ||
375 | CONFIG_TRUNCATE=y | ||
376 | CONFIG_TSORT=y | ||
377 | # CONFIG_TTY is not set | ||
378 | CONFIG_UNAME=y | ||
379 | CONFIG_UNAME_OSNAME="MS/Windows" | ||
380 | CONFIG_BB_ARCH=y | ||
381 | CONFIG_UNIQ=y | ||
382 | CONFIG_UNLINK=y | ||
383 | CONFIG_USLEEP=y | ||
384 | CONFIG_UUDECODE=y | ||
385 | CONFIG_BASE32=y | ||
386 | CONFIG_BASE64=y | ||
387 | CONFIG_UUENCODE=y | ||
388 | CONFIG_WC=y | ||
389 | CONFIG_FEATURE_WC_LARGE=y | ||
390 | # CONFIG_WHO is not set | ||
391 | # CONFIG_W is not set | ||
392 | # CONFIG_USERS is not set | ||
393 | CONFIG_WHOAMI=y | ||
394 | CONFIG_YES=y | ||
395 | |||
396 | # | ||
397 | # Console Utilities | ||
398 | # | ||
399 | # CONFIG_CHVT is not set | ||
400 | CONFIG_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 | ||
408 | CONFIG_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 | ||
413 | CONFIG_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 | # | ||
425 | CONFIG_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 | ||
432 | CONFIG_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 | # | ||
445 | CONFIG_AWK=y | ||
446 | CONFIG_FEATURE_AWK_LIBM=y | ||
447 | CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y | ||
448 | CONFIG_CMP=y | ||
449 | CONFIG_DIFF=y | ||
450 | CONFIG_FEATURE_DIFF_LONG_OPTIONS=y | ||
451 | CONFIG_FEATURE_DIFF_DIR=y | ||
452 | CONFIG_ED=y | ||
453 | CONFIG_PATCH=y | ||
454 | CONFIG_SED=y | ||
455 | CONFIG_VI=y | ||
456 | CONFIG_FEATURE_VI_MAX_LEN=4096 | ||
457 | CONFIG_FEATURE_VI_8BIT=y | ||
458 | CONFIG_FEATURE_VI_COLON=y | ||
459 | CONFIG_FEATURE_VI_COLON_EXPAND=y | ||
460 | CONFIG_FEATURE_VI_YANKMARK=y | ||
461 | CONFIG_FEATURE_VI_SEARCH=y | ||
462 | CONFIG_FEATURE_VI_REGEX_SEARCH=y | ||
463 | # CONFIG_FEATURE_VI_USE_SIGNALS is not set | ||
464 | CONFIG_FEATURE_VI_DOT_CMD=y | ||
465 | CONFIG_FEATURE_VI_READONLY=y | ||
466 | CONFIG_FEATURE_VI_SETOPTS=y | ||
467 | CONFIG_FEATURE_VI_FILE_FORMAT=y | ||
468 | CONFIG_FEATURE_VI_SET=y | ||
469 | CONFIG_FEATURE_VI_WIN_RESIZE=y | ||
470 | # CONFIG_FEATURE_VI_ASK_TERMINAL is not set | ||
471 | CONFIG_FEATURE_VI_UNDO=y | ||
472 | CONFIG_FEATURE_VI_UNDO_QUEUE=y | ||
473 | CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256 | ||
474 | CONFIG_FEATURE_VI_VERBOSE_STATUS=y | ||
475 | CONFIG_FEATURE_ALLOW_EXEC=y | ||
476 | |||
477 | # | ||
478 | # Finding Utilities | ||
479 | # | ||
480 | CONFIG_FIND=y | ||
481 | CONFIG_FEATURE_FIND_PRINT0=y | ||
482 | CONFIG_FEATURE_FIND_MTIME=y | ||
483 | CONFIG_FEATURE_FIND_ATIME=y | ||
484 | CONFIG_FEATURE_FIND_CTIME=y | ||
485 | CONFIG_FEATURE_FIND_MMIN=y | ||
486 | CONFIG_FEATURE_FIND_AMIN=y | ||
487 | CONFIG_FEATURE_FIND_CMIN=y | ||
488 | CONFIG_FEATURE_FIND_PERM=y | ||
489 | CONFIG_FEATURE_FIND_TYPE=y | ||
490 | CONFIG_FEATURE_FIND_EXECUTABLE=y | ||
491 | CONFIG_FEATURE_FIND_XDEV=y | ||
492 | CONFIG_FEATURE_FIND_MAXDEPTH=y | ||
493 | CONFIG_FEATURE_FIND_NEWER=y | ||
494 | CONFIG_FEATURE_FIND_INUM=y | ||
495 | CONFIG_FEATURE_FIND_SAMEFILE=y | ||
496 | CONFIG_FEATURE_FIND_EXEC=y | ||
497 | CONFIG_FEATURE_FIND_EXEC_PLUS=y | ||
498 | CONFIG_FEATURE_FIND_EXEC_OK=y | ||
499 | # CONFIG_FEATURE_FIND_USER is not set | ||
500 | # CONFIG_FEATURE_FIND_GROUP is not set | ||
501 | CONFIG_FEATURE_FIND_NOT=y | ||
502 | CONFIG_FEATURE_FIND_DEPTH=y | ||
503 | CONFIG_FEATURE_FIND_PAREN=y | ||
504 | CONFIG_FEATURE_FIND_SIZE=y | ||
505 | CONFIG_FEATURE_FIND_PRUNE=y | ||
506 | CONFIG_FEATURE_FIND_QUIT=y | ||
507 | CONFIG_FEATURE_FIND_DELETE=y | ||
508 | CONFIG_FEATURE_FIND_EMPTY=y | ||
509 | CONFIG_FEATURE_FIND_PATH=y | ||
510 | CONFIG_FEATURE_FIND_REGEX=y | ||
511 | # CONFIG_FEATURE_FIND_CONTEXT is not set | ||
512 | CONFIG_FEATURE_FIND_LINKS=y | ||
513 | CONFIG_GREP=y | ||
514 | CONFIG_EGREP=y | ||
515 | CONFIG_FGREP=y | ||
516 | CONFIG_FEATURE_GREP_CONTEXT=y | ||
517 | CONFIG_XARGS=y | ||
518 | CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y | ||
519 | CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y | ||
520 | CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y | ||
521 | CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y | ||
522 | CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y | ||
523 | CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y | ||
524 | CONFIG_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 | ||
537 | CONFIG_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 | ||
542 | CONFIG_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 | ||
547 | CONFIG_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 | ||
564 | CONFIG_LAST_ID=0 | ||
565 | CONFIG_FIRST_SYSTEM_ID=0 | ||
566 | CONFIG_LAST_SYSTEM_ID=0 | ||
567 | # CONFIG_CHPASSWD is not set | ||
568 | CONFIG_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 | ||
587 | CONFIG_SUW32=y | ||
588 | # CONFIG_VLOCK is not set | ||
589 | |||
590 | # | ||
591 | # Linux Ext2 FS Progs | ||
592 | # | ||
593 | CONFIG_CHATTR=y | ||
594 | # CONFIG_FSCK is not set | ||
595 | CONFIG_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 | ||
626 | CONFIG_DEFAULT_MODULES_DIR="" | ||
627 | CONFIG_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 | ||
638 | CONFIG_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 | ||
666 | CONFIG_GETOPT=y | ||
667 | CONFIG_FEATURE_GETOPT_LONG=y | ||
668 | CONFIG_HEXDUMP=y | ||
669 | CONFIG_HD=y | ||
670 | CONFIG_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 | ||
719 | CONFIG_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 | ||
780 | CONFIG_ASCII=y | ||
781 | # CONFIG_BBCONFIG is not set | ||
782 | # CONFIG_FEATURE_COMPRESS_BBCONFIG is not set | ||
783 | CONFIG_BC=y | ||
784 | CONFIG_DC=y | ||
785 | CONFIG_FEATURE_DC_BIG=y | ||
786 | # CONFIG_FEATURE_DC_LIBM is not set | ||
787 | CONFIG_FEATURE_BC_INTERACTIVE=y | ||
788 | CONFIG_FEATURE_BC_LONG_OPTIONS=y | ||
789 | # CONFIG_BEEP is not set | ||
790 | CONFIG_FEATURE_BEEP_FREQ=0 | ||
791 | CONFIG_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 | ||
805 | CONFIG_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 | ||
813 | CONFIG_DROP=y | ||
814 | CONFIG_CDROP=y | ||
815 | CONFIG_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 | ||
835 | CONFIG_ICONV=y | ||
836 | CONFIG_INOTIFYD=y | ||
837 | CONFIG_JN=y | ||
838 | CONFIG_LESS=y | ||
839 | CONFIG_FEATURE_LESS_MAXLINES=9999999 | ||
840 | CONFIG_FEATURE_LESS_BRACKETS=y | ||
841 | CONFIG_FEATURE_LESS_FLAGS=y | ||
842 | CONFIG_FEATURE_LESS_TRUNCATE=y | ||
843 | CONFIG_FEATURE_LESS_MARKS=y | ||
844 | CONFIG_FEATURE_LESS_REGEXP=y | ||
845 | # CONFIG_FEATURE_LESS_WINCH is not set | ||
846 | # CONFIG_FEATURE_LESS_ASK_TERMINAL is not set | ||
847 | CONFIG_FEATURE_LESS_DASHCMD=y | ||
848 | CONFIG_FEATURE_LESS_LINENUMS=y | ||
849 | CONFIG_FEATURE_LESS_RAW=y | ||
850 | CONFIG_FEATURE_LESS_ENV=y | ||
851 | # CONFIG_LSSCSI is not set | ||
852 | CONFIG_MAKE=y | ||
853 | CONFIG_PDPMAKE=y | ||
854 | CONFIG_FEATURE_MAKE_POSIX=y | ||
855 | # CONFIG_FEATURE_MAKE_POSIX_2017 is not set | ||
856 | CONFIG_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 | ||
860 | CONFIG_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 | ||
875 | CONFIG_STRINGS=y | ||
876 | CONFIG_TIME=y | ||
877 | # CONFIG_TREE is not set | ||
878 | CONFIG_TS=y | ||
879 | CONFIG_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 | # | ||
894 | CONFIG_FEATURE_IPV6=y | ||
895 | # CONFIG_FEATURE_UNIX_LOCAL is not set | ||
896 | CONFIG_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 | ||
913 | CONFIG_FTPGET=y | ||
914 | CONFIG_FTPPUT=y | ||
915 | CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y | ||
916 | # CONFIG_HOSTNAME is not set | ||
917 | # CONFIG_DNSDOMAINNAME is not set | ||
918 | CONFIG_HTTPD=y | ||
919 | CONFIG_FEATURE_HTTPD_PORT_DEFAULT=80 | ||
920 | CONFIG_FEATURE_HTTPD_RANGES=y | ||
921 | # CONFIG_FEATURE_HTTPD_SETUID is not set | ||
922 | CONFIG_FEATURE_HTTPD_BASIC_AUTH=y | ||
923 | # CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set | ||
924 | CONFIG_FEATURE_HTTPD_CGI=y | ||
925 | CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y | ||
926 | # CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set | ||
927 | CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y | ||
928 | CONFIG_FEATURE_HTTPD_ERROR_PAGES=y | ||
929 | # CONFIG_FEATURE_HTTPD_PROXY is not set | ||
930 | CONFIG_FEATURE_HTTPD_GZIP=y | ||
931 | CONFIG_FEATURE_HTTPD_ETAG=y | ||
932 | CONFIG_FEATURE_HTTPD_LAST_MODIFIED=y | ||
933 | CONFIG_FEATURE_HTTPD_DATE=y | ||
934 | CONFIG_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 | ||
945 | CONFIG_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 | ||
968 | CONFIG_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 | ||
973 | CONFIG_IPCALC=y | ||
974 | CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y | ||
975 | CONFIG_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 | ||
980 | CONFIG_NC=y | ||
981 | # CONFIG_NETCAT is not set | ||
982 | CONFIG_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 | ||
1001 | CONFIG_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 | ||
1012 | CONFIG_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 | ||
1022 | CONFIG_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 | ||
1030 | CONFIG_WGET=y | ||
1031 | CONFIG_FEATURE_WGET_LONG_OPTIONS=y | ||
1032 | CONFIG_FEATURE_WGET_STATUSBAR=y | ||
1033 | CONFIG_FEATURE_WGET_FTP=y | ||
1034 | CONFIG_FEATURE_WGET_AUTHENTICATION=y | ||
1035 | # CONFIG_FEATURE_WGET_TIMEOUT is not set | ||
1036 | CONFIG_FEATURE_WGET_HTTPS=y | ||
1037 | # CONFIG_FEATURE_WGET_OPENSSL is not set | ||
1038 | CONFIG_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 | ||
1044 | CONFIG_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 | ||
1050 | CONFIG_UDHCPC_DEFAULT_SCRIPT="" | ||
1051 | CONFIG_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 | ||
1057 | CONFIG_UDHCPC_DEFAULT_INTERFACE="" | ||
1058 | # CONFIG_FEATURE_UDHCP_PORT is not set | ||
1059 | CONFIG_UDHCP_DEBUG=0 | ||
1060 | CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 | ||
1061 | # CONFIG_FEATURE_UDHCP_RFC3397 is not set | ||
1062 | # CONFIG_FEATURE_UDHCP_8021Q is not set | ||
1063 | CONFIG_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 | # | ||
1075 | CONFIG_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 | ||
1088 | CONFIG_FREE=y | ||
1089 | # CONFIG_FUSER is not set | ||
1090 | # CONFIG_IOSTAT is not set | ||
1091 | CONFIG_KILL=y | ||
1092 | CONFIG_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 | ||
1097 | CONFIG_PGREP=y | ||
1098 | CONFIG_PKILL=y | ||
1099 | CONFIG_PIDOF=y | ||
1100 | CONFIG_FEATURE_PIDOF_SINGLE=y | ||
1101 | CONFIG_FEATURE_PIDOF_OMIT=y | ||
1102 | # CONFIG_PMAP is not set | ||
1103 | # CONFIG_POWERTOP is not set | ||
1104 | # CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set | ||
1105 | CONFIG_PS=y | ||
1106 | # CONFIG_FEATURE_PS_WIDE is not set | ||
1107 | # CONFIG_FEATURE_PS_LONG is not set | ||
1108 | CONFIG_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 | ||
1123 | CONFIG_UPTIME=y | ||
1124 | # CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set | ||
1125 | CONFIG_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 | ||
1139 | CONFIG_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 | # | ||
1160 | CONFIG_SH_IS_ASH=y | ||
1161 | # CONFIG_SH_IS_HUSH is not set | ||
1162 | # CONFIG_SH_IS_NONE is not set | ||
1163 | CONFIG_BASH_IS_ASH=y | ||
1164 | # CONFIG_BASH_IS_HUSH is not set | ||
1165 | # CONFIG_BASH_IS_NONE is not set | ||
1166 | CONFIG_SHELL_ASH=y | ||
1167 | CONFIG_ASH=y | ||
1168 | # CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set | ||
1169 | CONFIG_ASH_INTERNAL_GLOB=y | ||
1170 | CONFIG_ASH_BASH_COMPAT=y | ||
1171 | # CONFIG_ASH_BASH_SOURCE_CURDIR is not set | ||
1172 | CONFIG_ASH_BASH_NOT_FOUND_HOOK=y | ||
1173 | CONFIG_ASH_JOB_CONTROL=y | ||
1174 | CONFIG_ASH_ALIAS=y | ||
1175 | CONFIG_ASH_RANDOM_SUPPORT=y | ||
1176 | CONFIG_ASH_EXPAND_PRMT=y | ||
1177 | # CONFIG_ASH_IDLE_TIMEOUT is not set | ||
1178 | # CONFIG_ASH_MAIL is not set | ||
1179 | CONFIG_ASH_ECHO=y | ||
1180 | CONFIG_ASH_PRINTF=y | ||
1181 | CONFIG_ASH_TEST=y | ||
1182 | CONFIG_ASH_HELP=y | ||
1183 | CONFIG_ASH_GETOPTS=y | ||
1184 | CONFIG_ASH_CMDCMD=y | ||
1185 | CONFIG_ASH_NOCONSOLE=y | ||
1186 | CONFIG_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 | # | ||
1229 | CONFIG_FEATURE_SH_MATH=y | ||
1230 | CONFIG_FEATURE_SH_MATH_64=y | ||
1231 | CONFIG_FEATURE_SH_MATH_BASE=y | ||
1232 | CONFIG_FEATURE_SH_EXTRA_QUIET=y | ||
1233 | CONFIG_FEATURE_SH_STANDALONE=y | ||
1234 | CONFIG_FEATURE_SH_NOFORK=y | ||
1235 | CONFIG_FEATURE_SH_READ_FRAC=y | ||
1236 | CONFIG_FEATURE_SH_HISTFILESIZE=y | ||
1237 | CONFIG_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 | ||
1253 | CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 | ||
1254 | # CONFIG_FEATURE_IPC_SYSLOG is not set | ||
1255 | CONFIG_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; | |||
36 | int reset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 40 | int reset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
37 | int reset_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 41 | int 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 | ||
308 | static void *alloc_buf(size_t size) | 326 | static 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? | ||
338 | static 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 | |||
316 | int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 347 | int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
317 | int dd_main(int argc UNUSED_PARAM, char **argv) | 348 | int 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 |
85 | typedef int64_t arith_t; | 85 | typedef 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 | } |
130 | static NOINLINE void print_h(half_t n) | 130 | static 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 | ||
146 | int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 148 | int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
147 | int id_main(int argc UNUSED_PARAM, char **argv) | 149 | int 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 | ||
321 | struct globals { | 327 | struct 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 | ||
945 | static 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) */ |
924 | static struct dnode **scan_one_dir(const char *path, unsigned *nfiles_p) | 954 | static 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 | ||
1117 | static 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 | ||
1064 | int ls_main(int argc UNUSED_PARAM, char **argv) | 1129 | int 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 @@ | |||
28 | int nproc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 28 | int nproc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
29 | int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 29 | int 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 | ||
113 | enum size_spec { | 120 | enum 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 | ||
156 | static int buflen = 0; | ||
157 | static int bufmax = 0; | ||
158 | static char *buffer = NULL; | ||
159 | |||
160 | static 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 | |||
169 | static 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 | |||
188 | static int my_putchar(int ch) | ||
189 | { | ||
190 | char str[1] = { (char)ch }; | ||
191 | copy_to_buffer(str, 1); | ||
192 | return ch; | ||
193 | } | ||
194 | |||
195 | static 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 */ |
156 | static int print_esc_string(const char *str) | 221 | static 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 |
82 | enum { READ_BUFFER_SIZE = COMMON_BUFSIZE - 1 }; | 83 | enum { 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") \ | |||
190 | FS_TYPE(0x012FF7B5, "sysv4") \ | 190 | FS_TYPE(0x012FF7B5, "sysv4") \ |
191 | FS_TYPE(0x012FF7B6, "sysv2") \ | 191 | FS_TYPE(0x012FF7B6, "sysv2") \ |
192 | FS_TYPE(0x012FF7B7, "coh") \ | 192 | FS_TYPE(0x012FF7B7, "coh") \ |
193 | IF_PLATFORM_MINGW32(FS_TYPE(0x15013346, "udf")) \ | ||
193 | FS_TYPE(0x00011954, "ufs") \ | 194 | FS_TYPE(0x00011954, "ufs") \ |
194 | FS_TYPE(0x012FD16D, "xia") \ | 195 | FS_TYPE(0x012FD16D, "xia") \ |
195 | FS_TYPE(0x5346544e, "ntfs") \ | 196 | FS_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 | ||
52 | static HANDLE child = INVALID_HANDLE_VALUE; | ||
53 | |||
54 | static 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 */ | ||
64 | static 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 | ||
50 | static NOINLINE int timeout_wait(duration_t timeout, pid_t pid) | 75 | static 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 | ||
70 | int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 96 | int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
71 | int timeout_main(int argc UNUSED_PARAM, char **argv) | 97 | int 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 | ||
63 | struct globals { | 86 | struct 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 | ||
155 | static void change_attributes(const char *name, struct globals *gp) | 190 | static 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 */ |
12 | const uint32_t e2attr_flags_value[] ALIGN4 = { | 13 | const 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 */ | ||
76 | const 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 | |||
90 | const char e2attr_flags_sname[] ALIGN1 = | ||
91 | "RoecSrhsatn"; | ||
92 | |||
93 | static 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 | ||
74 | void print_e2flags_long(unsigned flags) | 109 | void print_e2flags_long(unsigned flags) |
110 | #else | ||
111 | #define flags sb->st_attr | ||
112 | void 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 | ||
96 | void print_e2flags(unsigned flags) | 157 | void print_e2flags(unsigned flags) |
158 | #else | ||
159 | void 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 | ||
12 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | 12 | PUSH_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 */ | ||
21 | void print_e2flags_long(struct stat *sb); | ||
22 | void 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 */ |
15 | void print_e2flags_long(unsigned flags); | 26 | void print_e2flags_long(unsigned flags); |
16 | void print_e2flags(unsigned flags); | 27 | void print_e2flags(unsigned flags); |
28 | #endif | ||
17 | 29 | ||
18 | extern const uint32_t e2attr_flags_value[]; | 30 | extern const uint32_t e2attr_flags_value[]; |
19 | extern const char e2attr_flags_sname[]; | 31 | extern 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 | ||
31 | POP_SAVED_FUNCTION_VISIBILITY | 48 | POP_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 | ||
47 | static void list_attributes(const char *name) | 76 | static 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 | ||
99 | static int FAST_FUNC lsattr_dir_proc(const char *dir_name, | 140 | static int FAST_FUNC lsattr_dir_proc(const char *dir_name, |
@@ -142,7 +183,11 @@ static void lsattr_args(const char *name) | |||
142 | int lsattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 183 | int lsattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
143 | int lsattr_main(int argc UNUSED_PARAM, char **argv) | 184 | int 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) | |||
970 | static const char *fmt_num(const char *format, double n) | 970 | static 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 | ||
2934 | static 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 */ |
2933 | static int next_input_file(void) | 2942 | static 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 | ||
2996 | static 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]) | |||
776 | out: | 808 | out: |
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"; | |||
138 | struct globals { | 141 | struct 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 | ||
229 | enum { | 252 | enum { |
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) |
616 | static int mysleep(int hund) | 673 | static 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 | ||
2057 | static 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[]! |
1982 | static int file_insert(const char *fn, char *p, int initial) | 2069 | static 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 | |||
2358 | static int file_write(char *fn, char *first, char *last) | 2465 | static 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 | ||
4942 | enum { | 5123 | enum { |
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 @@ | |||
1 | These scripts can be used to cross-compile busybox-w32 on a | ||
2 | Fedora Linux system with mingw-w64 and llvm-mingw toolchains. | ||
3 | The former are available from the Fedora repositories; the | ||
4 | latter needs to be downloaded and installed from: | ||
5 | |||
6 | https://github.com/mstorsjo/llvm-mingw | ||
7 | |||
8 | The script should be run from the directory above a git repository | ||
9 | named busybox-w32. The builds are performed in the directories | ||
10 | named in the TARGETS variable in the scripts. Previous copies of | ||
11 | these directories are deleted. | ||
12 | |||
13 | The scripts check out the master branch of the git repository. You | ||
14 | should edit the script if you wish to build from a different commit. | ||
15 | |||
16 | The build time recorded in the executables is the time of the checked | ||
17 | out commit. This may not result in a perfectly reproducible build | ||
18 | but it's a step in that direction. | ||
19 | |||
20 | The release build performs some additional optimisation and takes | ||
21 | slightly longer as a result. | ||
22 | |||
23 | The busybox-w32 help message includes information about the build | ||
24 | platform. Obtaining this information is very specific to the | ||
25 | platform used: you may need to adjust this if building on something | ||
26 | other 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 | # | ||
5 | TARGETS="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. | ||
8 | SRC=busybox-w32 | ||
9 | if [ $# -eq 1 ] | ||
10 | then | ||
11 | SRC=$1 | ||
12 | fi | ||
13 | |||
14 | if [ ! -d $SRC ] | ||
15 | then | ||
16 | echo "$SRC doesn't exist" | ||
17 | exit 0 | ||
18 | fi | ||
19 | |||
20 | # remove old and make new build directories | ||
21 | for i in $TARGETS | ||
22 | do | ||
23 | rm -rf $i | ||
24 | cp -rp $SRC $i | ||
25 | done | ||
26 | |||
27 | # apply default configuration | ||
28 | for i in $TARGETS | ||
29 | do | ||
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 | ) | ||
51 | done | ||
52 | |||
53 | # perform build | ||
54 | for i in $TARGETS | ||
55 | do | ||
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 | ) | ||
77 | done | ||
78 | |||
79 | # Check the expected binaries exist | ||
80 | echo | ||
81 | for i in $TARGETS | ||
82 | do | ||
83 | ls -l $i/busybox.exe | ||
84 | done | ||
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 | # | ||
5 | TARGETS="build_32 build_64 build_64a build_64u" | ||
6 | |||
7 | if [ ! -d busybox-w32 ] | ||
8 | then | ||
9 | echo "busybox-w32 doesn't exist" | ||
10 | exit 0 | ||
11 | fi | ||
12 | |||
13 | # remove old and make new build directories | ||
14 | for i in $TARGETS | ||
15 | do | ||
16 | rm -rf $i | ||
17 | cp -rp busybox-w32 $i | ||
18 | done | ||
19 | |||
20 | # apply default configuration | ||
21 | for i in $TARGETS | ||
22 | do | ||
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 | ) | ||
71 | done | ||
72 | |||
73 | # perform build | ||
74 | for i in $TARGETS | ||
75 | do | ||
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 | ) | ||
97 | done | ||
98 | |||
99 | # Check the expected binaries exist | ||
100 | echo | ||
101 | for i in $TARGETS | ||
102 | do | ||
103 | ls -l $i/busybox.exe | ||
104 | done | ||
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 | ||
198 | static 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 | ||
227 | static 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 | |||
237 | check_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 | */ |
560 | static int xargs_ask_confirmation(void) | 694 | static 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 | |||
729 | static 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 | |||
5 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | 15 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN |
6 | 16 | ||
7 | enum { | 17 | enum { |
@@ -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 | ||
280 | void check_errors_in_children(int signo); | 291 | void 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 |
282 | void fork_transformer(int fd, | 296 | void 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 | ||
185 | extern char **environ; | 195 | extern 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 */ |
187 | int klogctl(int type, char *b, int len); | 198 | int 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; | |||
570 | const char *bb_basename(const char *name) FAST_FUNC; | 602 | const 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) */ |
572 | char *last_char_is(const char *s, int c) FAST_FUNC; | 604 | char *last_char_is(const char *s, int c) FAST_FUNC; |
605 | char *last_char_is_dir_sep(const char *s) FAST_FUNC; | ||
573 | const char* endofname(const char *name) FAST_FUNC; | 606 | const char* endofname(const char *name) FAST_FUNC; |
574 | char *is_prefixed_with(const char *string, const char *key) FAST_FUNC; | 607 | char *is_prefixed_with(const char *string, const char *key) FAST_FUNC; |
575 | char *is_suffixed_with(const char *string, const char *key) FAST_FUNC; | 608 | char *is_suffixed_with(const char *string, const char *key) FAST_FUNC; |
576 | 609 | ||
610 | #if !ENABLE_PLATFORM_MINGW32 | ||
577 | int ndelay_on(int fd) FAST_FUNC; | 611 | int ndelay_on(int fd) FAST_FUNC; |
578 | int ndelay_off(int fd) FAST_FUNC; | 612 | int ndelay_off(int fd) FAST_FUNC; |
579 | void close_on_exec_on(int fd) FAST_FUNC; | 613 | void close_on_exec_on(int fd) FAST_FUNC; |
614 | #else | ||
615 | static inline int ndelay_on(int fd UNUSED_PARAM) { return 0; } | ||
616 | static inline int ndelay_off(int fd UNUSED_PARAM) { return 0; } | ||
617 | static inline void close_on_exec_on(int fd UNUSED_PARAM) { return; } | ||
618 | #endif | ||
580 | void xdup2(int, int) FAST_FUNC; | 619 | void xdup2(int, int) FAST_FUNC; |
581 | void xmove_fd(int, int) FAST_FUNC; | 620 | void 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 | ||
627 | void bb_signals(int sigs, void (*f)(int)) FAST_FUNC; | 683 | void 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; | |||
643 | int sigprocmask_allsigs(int how) FAST_FUNC; | 699 | int sigprocmask_allsigs(int how) FAST_FUNC; |
644 | /* Return old set in the same set: */ | 700 | /* Return old set in the same set: */ |
645 | int sigprocmask2(int how, sigset_t *set) FAST_FUNC; | 701 | int 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 */ |
647 | extern smallint bb_got_signal; | 707 | extern smallint bb_got_signal; |
648 | void record_signo(int signo); /* not FAST_FUNC! */ | 708 | void record_signo(int signo); /* not FAST_FUNC! */ |
@@ -726,7 +786,7 @@ void xsettimeofday(const struct timeval *tv) FAST_FUNC; | |||
726 | int xsocket(int domain, int type, int protocol) FAST_FUNC; | 786 | int xsocket(int domain, int type, int protocol) FAST_FUNC; |
727 | void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC; | 787 | void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC; |
728 | void xlisten(int s, int backlog) FAST_FUNC; | 788 | void xlisten(int s, int backlog) FAST_FUNC; |
729 | void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) FAST_FUNC; | 789 | void xconnect(int s, const struct sockaddr *saddr, socklen_t addrlen) FAST_FUNC; |
730 | ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, | 790 | ssize_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 */ |
934 | int bb_putchar_stderr(char ch) FAST_FUNC; | 994 | int bb_putchar_stderr(char ch) FAST_FUNC; |
935 | int fputs_stdout(const char *s) FAST_FUNC; | 995 | int fputs_stdout(const char *s) FAST_FUNC; |
936 | char *xasprintf(const char *format, ...) __attribute__ ((format(printf, 1, 2))) FAST_FUNC RETURNS_MALLOC; | 996 | char *xasprintf(const char *format, ...) __attribute__ ((format(printf, 1, 2))) RETURNS_MALLOC; |
937 | char *auto_string(char *str) FAST_FUNC; | 997 | char *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; | |||
1208 | struct cached_groupinfo { | 1268 | struct 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 | }; |
1214 | uid_t FAST_FUNC get_cached_euid(uid_t *euid); | 1278 | uid_t FAST_FUNC get_cached_euid(uid_t *euid); |
1215 | gid_t FAST_FUNC get_cached_egid(gid_t *egid); | 1279 | gid_t FAST_FUNC get_cached_egid(gid_t *egid); |
1280 | #if !ENABLE_PLATFORM_MINGW32 | ||
1216 | int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid); | 1281 | int 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 |
1219 | void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); | 1287 | void 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 |
1260 | pid_t xfork(void) FAST_FUNC; | 1332 | pid_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 |
1291 | int find_applet_by_name(const char *name) FAST_FUNC; | 1363 | int find_applet_by_name(const char *name) FAST_FUNC; |
1292 | void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; | 1364 | void 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 | ||
1367 | int prefer_applet(const char *name, const char *path) FAST_FUNC; | ||
1368 | int 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 |
1294 | void show_usage_if_dash_dash_help(int applet_no, char **argv) FAST_FUNC; | 1375 | void 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; | |||
1370 | char **skip_dash_dash(char **argv) FAST_FUNC; | 1451 | char **skip_dash_dash(char **argv) FAST_FUNC; |
1371 | extern const char *const bb_argv_dash[]; /* { "-", NULL } */ | 1452 | extern const char *const bb_argv_dash[]; /* { "-", NULL } */ |
1372 | extern uint32_t option_mask32; | 1453 | extern uint32_t option_mask32; |
1373 | uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; | 1454 | uint32_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 |
1378 | uint32_t getopt32long(char **argv, const char *optstring, const char *longopts, ...) FAST_FUNC; | 1459 | uint32_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; | |||
1450 | extern void (*die_func)(void); | 1531 | extern void (*die_func)(void); |
1451 | void xfunc_die(void) NORETURN FAST_FUNC; | 1532 | void xfunc_die(void) NORETURN FAST_FUNC; |
1452 | void bb_show_usage(void) NORETURN FAST_FUNC; | 1533 | void bb_show_usage(void) NORETURN FAST_FUNC; |
1453 | void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; | 1534 | void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))); |
1454 | void bb_simple_error_msg(const char *s) FAST_FUNC; | 1535 | void bb_simple_error_msg(const char *s) FAST_FUNC; |
1455 | void bb_error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; | 1536 | void bb_error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))); |
1456 | void bb_simple_error_msg_and_die(const char *s) NORETURN FAST_FUNC; | 1537 | void bb_simple_error_msg_and_die(const char *s) NORETURN FAST_FUNC; |
1457 | void bb_perror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; | 1538 | void bb_perror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))); |
1458 | void bb_simple_perror_msg(const char *s) FAST_FUNC; | 1539 | void bb_simple_perror_msg(const char *s) FAST_FUNC; |
1459 | void bb_perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; | 1540 | void bb_perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))); |
1460 | void bb_simple_perror_msg_and_die(const char *s) NORETURN FAST_FUNC; | 1541 | void bb_simple_perror_msg_and_die(const char *s) NORETURN FAST_FUNC; |
1461 | void bb_herror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; | 1542 | void bb_herror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))); |
1462 | void bb_simple_herror_msg(const char *s) FAST_FUNC; | 1543 | void bb_simple_herror_msg(const char *s) FAST_FUNC; |
1463 | void bb_herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; | 1544 | void bb_herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))); |
1464 | void bb_simple_herror_msg_and_die(const char *s) NORETURN FAST_FUNC; | 1545 | void bb_simple_herror_msg_and_die(const char *s) NORETURN FAST_FUNC; |
1465 | void bb_perror_nomsg_and_die(void) NORETURN FAST_FUNC; | 1546 | void bb_perror_nomsg_and_die(void) NORETURN FAST_FUNC; |
1466 | void bb_perror_nomsg(void) FAST_FUNC; | 1547 | void bb_perror_nomsg(void) FAST_FUNC; |
@@ -1476,7 +1557,7 @@ void bb_logenv_override(void) FAST_FUNC; | |||
1476 | typedef smalluint exitcode_t; | 1557 | typedef smalluint exitcode_t; |
1477 | 1558 | ||
1478 | #if ENABLE_FEATURE_SYSLOG_INFO | 1559 | #if ENABLE_FEATURE_SYSLOG_INFO |
1479 | void bb_info_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; | 1560 | void bb_info_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))); |
1480 | void bb_simple_info_msg(const char *s) FAST_FUNC; | 1561 | void bb_simple_info_msg(const char *s) FAST_FUNC; |
1481 | void bb_vinfo_msg(const char *s, va_list p) FAST_FUNC; | 1562 | void 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 | |||
1853 | int set_termios_to_raw(int fd, struct termios *oldterm, int flags) FAST_FUNC; | 1934 | int 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! */ |
1856 | int ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) __attribute__ ((format (printf, 4, 5))) FAST_FUNC; | 1937 | int ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) __attribute__ ((format (printf, 4, 5))); |
1857 | int ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...) __attribute__ ((format (printf, 4, 5))) FAST_FUNC; | 1938 | int 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 |
1859 | int bb_ioctl_or_warn(int fd, unsigned request, void *argp, const char *ioctl_name) FAST_FUNC; | 1940 | int bb_ioctl_or_warn(int fd, unsigned request, void *argp, const char *ioctl_name) FAST_FUNC; |
1860 | int bb_xioctl(int fd, unsigned request, void *argp, const char *ioctl_name) FAST_FUNC; | 1941 | int 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 | ||
1870 | char *is_in_ino_dev_hashtable(const struct stat *statbuf) FAST_FUNC; | 1952 | char *is_in_ino_dev_hashtable(const struct stat *statbuf) FAST_FUNC; |
1871 | void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) FAST_FUNC; | 1953 | void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) FAST_FUNC; |
1872 | void reset_ino_dev_hashtable(void) FAST_FUNC; | 1954 | void 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 */ |
1875 | unsigned long long bb_makedev(unsigned major, unsigned minor) FAST_FUNC; | 1962 | unsigned 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 | */ |
1949 | int64_t read_key(int fd, char *buffer, int timeout) FAST_FUNC; | 2036 | int64_t read_key(int fd, char *buffer, int timeout) FAST_FUNC; |
2037 | #if ENABLE_PLATFORM_MINGW32 | ||
2038 | int64_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: */ |
1951 | int64_t safe_read_key(int fd, char *buffer, int timeout) FAST_FUNC; | 2041 | int64_t safe_read_key(int fd, char *buffer, int timeout) FAST_FUNC; |
1952 | void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; | 2042 | void 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 | ||
1963 | typedef const char *get_exe_name_t(int i) FAST_FUNC; | 2058 | typedef const char *get_exe_name_t(int i) FAST_FUNC; |
1964 | typedef const char *sh_get_var_t(const char *name) FAST_FUNC; | 2059 | typedef const char *sh_get_var_t(const char *name) FAST_FUNC; |
2060 | typedef int sh_accept_glob_t(const char *name) FAST_FUNC; | ||
1965 | typedef struct line_input_t { | 2061 | typedef 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 | }; |
2014 | line_input_t *new_line_input_t(int flags) FAST_FUNC; | 2116 | line_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 | ||
2039 | unsigned long* FAST_FUNC get_malloc_cpu_affinity(int pid, unsigned *sz); | 2141 | unsigned 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 |
2043 | enum { COMM_LEN = TASK_COMM_LEN }; | 2149 | enum { 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 | ||
2077 | typedef struct procps_status_t { | 2183 | typedef 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() | ||
2426 | extern char bb_comm[]; | ||
2427 | extern char bb_command_line[]; | ||
2428 | #else | ||
2312 | extern const char bb_busybox_exec_path[] ALIGN1; | 2429 | extern 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 |
2318 | extern const char bb_PATH_root_path[] ALIGN1; /* BB_PATH_ROOT_PATH */ | 2437 | extern 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 | ||
2447 | extern 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 ";" | ||
2452 | extern 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 | ||
2325 | extern const int const_int_0; | 2461 | extern 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. */ | ||
2496 | void 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 | */ | ||
19 | typedef int gid_t; | ||
20 | typedef int uid_t; | ||
21 | |||
22 | #define DEFAULT_UID 4095 | ||
23 | #define DEFAULT_GID DEFAULT_UID | ||
24 | |||
25 | /* | ||
26 | * arpa/inet.h | ||
27 | */ | ||
28 | static inline unsigned int git_ntohl(unsigned int x) { return (unsigned int)ntohl(x); } | ||
29 | #define ntohl git_ntohl | ||
30 | int inet_aton(const char *cp, struct in_addr *inp); | ||
31 | int 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 | |||
55 | struct group { | ||
56 | char *gr_name; | ||
57 | char *gr_passwd; | ||
58 | gid_t gr_gid; | ||
59 | char **gr_mem; | ||
60 | }; | ||
61 | IMPL(getgrnam,struct group *,NULL,const char *name UNUSED_PARAM); | ||
62 | struct group *getgrgid(gid_t gid); | ||
63 | NOIMPL(initgroups,const char *group UNUSED_PARAM,gid_t gid UNUSED_PARAM); | ||
64 | static inline void endgrent(void) {} | ||
65 | int 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 | |||
93 | typedef int sa_family_t; | ||
94 | |||
95 | /* | ||
96 | * linux/un.h | ||
97 | */ | ||
98 | struct 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 | */ | ||
106 | struct 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 | |||
116 | struct passwd *getpwnam(const char *name); | ||
117 | struct passwd *getpwuid(uid_t uid); | ||
118 | static inline void setpwent(void) {} | ||
119 | static inline void endpwent(void) {} | ||
120 | IMPL(getpwent_r,int,ENOENT,struct passwd *pwbuf UNUSED_PARAM,char *buf UNUSED_PARAM,size_t buflen UNUSED_PARAM,struct passwd **pwbufp UNUSED_PARAM); | ||
121 | IMPL(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 | |||
133 | typedef void (*sighandler_t)(int); | ||
134 | sighandler_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 | |||
143 | int fdprintf(int fd, const char *format, ...); | ||
144 | FILE* mingw_fopen(const char *filename, const char *mode); | ||
145 | int mingw_rename(const char*, const char*); | ||
146 | #define fopen mingw_fopen | ||
147 | #define rename mingw_rename | ||
148 | |||
149 | FILE *mingw_popen(const char *cmd, const char *mode); | ||
150 | int mingw_popen_fd(const char *exe, const char *cmd, const char *mode, | ||
151 | int fd0, pid_t *pid); | ||
152 | int mingw_pclose(FILE *fd); | ||
153 | pid_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 | |||
159 | IMPL(setlinebuf, void, ,FILE *fd UNUSED_PARAM) | ||
160 | |||
161 | /* | ||
162 | * ANSI emulation wrappers | ||
163 | */ | ||
164 | |||
165 | BOOL conToCharBuffA(LPSTR d, DWORD len); | ||
166 | BOOL conToCharA(LPSTR d); | ||
167 | |||
168 | // same as ReadConsoleInputA, but delivers UTF8 regardless of console CP | ||
169 | BOOL readConsoleInput_utf8(HANDLE h, INPUT_RECORD *r, DWORD len, DWORD *got); | ||
170 | |||
171 | void set_title(const char *str); | ||
172 | int get_title(char *buf, int len); | ||
173 | void move_cursor_row(int n); | ||
174 | void reset_screen(void); | ||
175 | int winansi_putchar(int c); | ||
176 | int winansi_puts(const char *s); | ||
177 | size_t winansi_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); | ||
178 | int winansi_fputs(const char *str, FILE *stream); | ||
179 | int winansi_fputc(int c, FILE *stream); | ||
180 | int winansi_vsnprintf(char *buf, size_t size, const char *format, va_list list); | ||
181 | int winansi_vfprintf(FILE *stream, const char *format, va_list list); | ||
182 | int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); | ||
183 | int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); | ||
184 | int winansi_write(int fd, const void *buf, size_t count); | ||
185 | int winansi_read(int fd, void *buf, size_t count); | ||
186 | size_t winansi_fread(void *ptr, size_t size, size_t nmemb, FILE *stream); | ||
187 | int winansi_getc(FILE *stream); | ||
188 | int winansi_getchar(void); | ||
189 | char *winansi_fgets(char *s, int size, FILE *stream); | ||
190 | void 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 | |||
222 | int mingw_system(const char *cmd); | ||
223 | #define system mingw_system | ||
224 | |||
225 | int clearenv(void); | ||
226 | char *mingw_getenv(const char *name); | ||
227 | int mingw_putenv(const char *env); | ||
228 | char *mingw_mktemp(char *template); | ||
229 | int mkstemp(char *template); | ||
230 | char *realpath(const char *path, char *resolved_path); | ||
231 | int setenv(const char *name, const char *value, int replace); | ||
232 | int 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 | */ | ||
241 | char *strndup(char const *s, size_t n); | ||
242 | char *mingw_strerror(int errnum); | ||
243 | char *strsignal(int sig); | ||
244 | int strverscmp(const char *s1, const char *s2); | ||
245 | |||
246 | #define strerror mingw_strerror | ||
247 | |||
248 | /* | ||
249 | * strings.h | ||
250 | */ | ||
251 | #if !defined(__GNUC__) | ||
252 | int 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 | |||
263 | int ioctl(int fd, int code, ...); | ||
264 | |||
265 | /* | ||
266 | * sys/socket.h | ||
267 | */ | ||
268 | #define hstrerror strerror | ||
269 | |||
270 | #define SHUT_WR SD_SEND | ||
271 | |||
272 | int mingw_socket(int domain, int type, int protocol); | ||
273 | int mingw_connect(int sockfd, const struct sockaddr *sa, size_t sz); | ||
274 | int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz); | ||
275 | int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen); | ||
276 | int mingw_shutdown(int sockfd, int how); | ||
277 | int mingw_listen(int sockfd, int backlog); | ||
278 | int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz); | ||
279 | int mingw_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds, | ||
280 | struct timeval *timeout); | ||
281 | int mingw_getpeername(int fd, struct sockaddr *sa, socklen_t *sz); | ||
282 | int mingw_gethostname(char *host, int namelen); | ||
283 | int mingw_getaddrinfo(const char *node, const char *service, | ||
284 | const struct addrinfo *hints, struct addrinfo **res); | ||
285 | struct 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 | ||
305 | struct timespec { | ||
306 | time_t tv_sec; | ||
307 | long int tv_nsec; | ||
308 | }; | ||
309 | #endif | ||
310 | |||
311 | typedef int clockid_t; | ||
312 | #define CLOCK_REALTIME 0 | ||
313 | |||
314 | time_t timegm(struct tm *tm); | ||
315 | |||
316 | int nanosleep(const struct timespec *req, struct timespec *rem); | ||
317 | int clock_gettime(clockid_t clockid, struct timespec *tp); | ||
318 | int 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 | |||
344 | mode_t mingw_umask(mode_t mode); | ||
345 | #define umask mingw_umask | ||
346 | |||
347 | #define DEFAULT_UMASK 0002 | ||
348 | |||
349 | IMPL(fchmod,int,0,int fildes UNUSED_PARAM, mode_t mode UNUSED_PARAM); | ||
350 | NOIMPL(fchown,int fd UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM); | ||
351 | int mingw_mkdir(const char *path, int mode); | ||
352 | int mingw_chdir(const char *path); | ||
353 | int 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 | |||
363 | typedef int nlink_t; | ||
364 | typedef int blksize_t; | ||
365 | typedef off_t blkcnt_t; | ||
366 | #if ENABLE_FEATURE_EXTRA_FILE_DATA | ||
367 | #define ino_t uint64_t | ||
368 | #endif | ||
369 | |||
370 | struct 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 | |||
391 | int count_subdirs(const char *pathname); | ||
392 | int mingw_lstat(const char *file_name, struct mingw_stat *buf); | ||
393 | int mingw_stat(const char *file_name, struct mingw_stat *buf); | ||
394 | int 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 | |||
405 | int utimensat(int fd, const char *path, const struct timespec times[2], | ||
406 | int flags); | ||
407 | int futimens(int fd, const struct timespec times[2]); | ||
408 | |||
409 | /* | ||
410 | * sys/sysinfo.h | ||
411 | */ | ||
412 | struct 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 | |||
427 | int 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 | ||
441 | pid_t waitpid(pid_t pid, int *status, int options); | ||
442 | pid_t mingw_wait3(pid_t pid, int *status, int options, struct rusage *rusage); | ||
443 | |||
444 | /* | ||
445 | * time.h | ||
446 | */ | ||
447 | struct tm *gmtime_r(const time_t *timep, struct tm *result); | ||
448 | struct tm *localtime_r(const time_t *timep, struct tm *result); | ||
449 | char *strptime(const char *s, const char *format, struct tm *tm); | ||
450 | char *mingw_strptime(const char *s, const char *format, struct tm *tm, long *gmt); | ||
451 | size_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 | |||
460 | struct 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 | |||
467 | clock_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 | |||
480 | IMPL(alarm,unsigned int,0,unsigned int seconds UNUSED_PARAM); | ||
481 | IMPL(chown,int,0,const char *path UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM); | ||
482 | NOIMPL(chroot,const char *root UNUSED_PARAM); | ||
483 | NOIMPL(fchdir,int fd UNUSED_PARAM); | ||
484 | int mingw_dup2 (int fd, int fdto); | ||
485 | char *mingw_getcwd(char *pointer, int len); | ||
486 | off_t mingw_lseek(int fd, off_t offset, int whence); | ||
487 | |||
488 | |||
489 | int getuid(void); | ||
490 | #define getgid getuid | ||
491 | #define geteuid getuid | ||
492 | #define getegid getuid | ||
493 | int getgroups(int n, gid_t *groups); | ||
494 | pid_t getppid(void); | ||
495 | NOIMPL(getsid,pid_t pid UNUSED_PARAM); | ||
496 | int getlogin_r(char *buf, size_t len); | ||
497 | int fcntl(int fd, int cmd, ...); | ||
498 | int fsync(int fd); | ||
499 | int kill(pid_t pid, int sig); | ||
500 | int link(const char *oldpath, const char *newpath); | ||
501 | NOIMPL(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 */ | ||
503 | enum {DEV_NULL, DEV_ZERO, DEV_URANDOM, NOT_DEVICE = -1}; | ||
504 | int get_dev_type(const char *filename); | ||
505 | void update_special_fd(int dev, int fd); | ||
506 | int mingw_open (const char *filename, int oflags, ...); | ||
507 | |||
508 | /* functions which add O_SPECIAL to open(2) to allow access to devices */ | ||
509 | int mingw_xopen(const char *filename, int oflags); | ||
510 | ssize_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 | |||
516 | ssize_t mingw_read(int fd, void *buf, size_t count); | ||
517 | int mingw_close(int fd); | ||
518 | int pipe(int filedes[2]); | ||
519 | NOIMPL(setgid,gid_t gid UNUSED_PARAM); | ||
520 | NOIMPL(setegid,gid_t gid UNUSED_PARAM); | ||
521 | NOIMPL(setsid,void); | ||
522 | NOIMPL(setuid,uid_t gid UNUSED_PARAM); | ||
523 | NOIMPL(seteuid,uid_t gid UNUSED_PARAM); | ||
524 | unsigned int sleep(unsigned int seconds); | ||
525 | int symlink(const char *target, const char *linkpath); | ||
526 | int create_junction(const char *oldpath, const char *newpath); | ||
527 | long sysconf(int name); | ||
528 | IMPL(getpagesize,int,4096,void); | ||
529 | NOIMPL(ttyname_r,int fd UNUSED_PARAM, char *buf UNUSED_PARAM, int sz UNUSED_PARAM); | ||
530 | int mingw_unlink(const char *pathname); | ||
531 | int mingw_access(const char *name, int mode); | ||
532 | int mingw_rmdir(const char *name); | ||
533 | void mingw_sync(void); | ||
534 | int 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 | */ | ||
554 | int 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 | |||
569 | typedef struct { | ||
570 | char *path; | ||
571 | char *name; | ||
572 | char *opts; | ||
573 | char buf[100]; | ||
574 | } interp_t; | ||
575 | |||
576 | int FAST_FUNC parse_interpreter(const char *cmd, interp_t *interp); | ||
577 | char ** FAST_FUNC grow_argv(char **argv, int n); | ||
578 | pid_t FAST_FUNC mingw_spawn(char **argv); | ||
579 | intptr_t FAST_FUNC mingw_spawn_detach(char **argv); | ||
580 | intptr_t FAST_FUNC mingw_spawn_proc(const char **argv); | ||
581 | int mingw_execv(const char *cmd, char *const *argv); | ||
582 | int httpd_execv_detach(const char *cmd, char *const *argv); | ||
583 | int mingw_execvp(const char *cmd, char *const *argv); | ||
584 | int 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 | |||
593 | BOOL WINAPI kill_child_ctrl_handler(DWORD dwCtrlType); | ||
594 | int FAST_FUNC is_valid_signal(int number); | ||
595 | int exit_code_to_wait_status(DWORD win_exit_code); | ||
596 | int exit_code_to_posix(DWORD win_exit_code); | ||
597 | |||
598 | #define find_mount_point(n, s) find_mount_point(n) | ||
599 | |||
600 | char *is_prefixed_with_case(const char *string, const char *key) FAST_FUNC; | ||
601 | char *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 | |||
610 | const char *get_busybox_exec_path(void); | ||
611 | void init_winsock(void); | ||
612 | |||
613 | int has_bat_suffix(const char *p); | ||
614 | int has_exe_suffix(const char *p); | ||
615 | int has_exe_suffix_or_dot(const char *name); | ||
616 | char *alloc_ext_space(const char *path); | ||
617 | int add_win32_extension(char *p); | ||
618 | char *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 | |||
629 | MINGW_BB_WCHAR_T *bs_to_slash_u(MINGW_BB_WCHAR_T *p) FAST_FUNC; | ||
630 | #endif | ||
631 | |||
632 | char *bs_to_slash(char *p) FAST_FUNC; | ||
633 | void slash_to_bs(char *p) FAST_FUNC; | ||
634 | void strip_dot_space(char *p) FAST_FUNC; | ||
635 | size_t remove_cr(char *p, size_t len) FAST_FUNC; | ||
636 | |||
637 | int err_win_to_posix(void); | ||
638 | |||
639 | ULONGLONG CompatGetTickCount64(void); | ||
640 | #define GetTickCount64 CompatGetTickCount64 | ||
641 | |||
642 | ssize_t get_random_bytes(void *buf, ssize_t count); | ||
643 | int enumerate_links(const char *file, char *name); | ||
644 | |||
645 | int unc_root_len(const char *dir) FAST_FUNC; | ||
646 | int root_len(const char *path) FAST_FUNC; | ||
647 | const char *get_system_drive(void) FAST_FUNC; | ||
648 | int chdir_system_drive(void); | ||
649 | char *xabsolute_path(char *path) FAST_FUNC; | ||
650 | char *get_drive_cwd(const char *path, char *buffer, int size) FAST_FUNC; | ||
651 | void fix_path_case(char *path) FAST_FUNC; | ||
652 | void make_sparse(int fd, off_t start, off_t end) FAST_FUNC; | ||
653 | int terminal_mode(int reset) FAST_FUNC; | ||
654 | int unix_path(const char *path) FAST_FUNC; | ||
655 | int has_path(const char *file) FAST_FUNC; | ||
656 | int is_relative_path(const char *path) FAST_FUNC; | ||
657 | char *get_last_slash(const char *path) FAST_FUNC; | ||
658 | const char *applet_to_exe(const char *name) FAST_FUNC; | ||
659 | char *get_user_name(void); | ||
660 | char *quote_arg(const char *arg) FAST_FUNC; | ||
661 | char *find_first_executable(const char *name) FAST_FUNC; | ||
662 | char *xappendword(const char *str, const char *word) FAST_FUNC; | ||
663 | int windows_env(void); | ||
664 | void change_critical_error_dialogs(const char *newval) FAST_FUNC; | ||
665 | char *exe_relative_path(const char *tail) FAST_FUNC; | ||
666 | enum { | ||
667 | ELEVATED_PRIVILEGE = 1, | ||
668 | ADMIN_ENABLED = 2 | ||
669 | }; | ||
670 | int elevation_state(void); | ||
671 | void 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> | ||
566 | extern void *memrchr(const void *s, int c, size_t n) FAST_FUNC; | 608 | extern 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> | ||
629 | extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC; | 672 | extern 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 | ||
191 | config 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 | |||
191 | config FEATURE_EDITING_SAVEHISTORY | 201 | config 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 | ||
11 | INSERT | 11 | INSERT |
12 | 12 | ||
13 | lib-y += alloc_affinity.o | ||
14 | lib-y += appletlib.o | 13 | lib-y += appletlib.o |
15 | lib-y += ask_confirmation.o | 14 | lib-y += ask_confirmation.o |
16 | lib-y += bb_askpass.o | ||
17 | lib-y += bb_bswap_64.o | 15 | lib-y += bb_bswap_64.o |
18 | lib-y += bb_do_delay.o | 16 | lib-y += bb_do_delay.o |
19 | lib-y += bb_pwd.o | 17 | lib-y += bb_pwd.o |
20 | lib-y += bb_qsort.o | 18 | lib-y += bb_qsort.o |
21 | #lib-y += bb_strtod.o | 19 | #lib-y += bb_strtod.o |
22 | lib-y += bb_strtonum.o | 20 | lib-y += bb_strtonum.o |
23 | lib-y += change_identity.o | ||
24 | lib-y += chomp.o | 21 | lib-y += chomp.o |
25 | lib-y += compare_string_array.o | 22 | lib-y += compare_string_array.o |
26 | lib-y += concat_path_file.o | 23 | lib-y += concat_path_file.o |
@@ -30,32 +27,23 @@ lib-y += copy_file.o | |||
30 | lib-y += copyfd.o | 27 | lib-y += copyfd.o |
31 | lib-y += crc32.o | 28 | lib-y += crc32.o |
32 | lib-y += default_error_retval.o | 29 | lib-y += default_error_retval.o |
33 | lib-y += device_open.o | ||
34 | lib-y += dump.o | 30 | lib-y += dump.o |
35 | lib-y += executable.o | 31 | lib-y += executable.o |
36 | lib-y += fclose_nonstdin.o | 32 | lib-y += fclose_nonstdin.o |
37 | lib-y += fflush_stdout_and_exit.o | 33 | lib-y += fflush_stdout_and_exit.o |
38 | lib-y += fgets_str.o | 34 | lib-y += fgets_str.o |
39 | lib-y += find_pid_by_name.o | 35 | lib-y += find_pid_by_name.o |
40 | lib-y += find_root_device.o | ||
41 | lib-y += full_write.o | 36 | lib-y += full_write.o |
42 | lib-y += get_console.o | ||
43 | lib-y += get_last_path_component.o | 37 | lib-y += get_last_path_component.o |
44 | lib-y += get_line_from_file.o | 38 | lib-y += get_line_from_file.o |
45 | lib-y += getpty.o | 39 | lib-y += getopt32.o |
46 | lib-y += get_volsize.o | ||
47 | lib-y += herror_msg.o | 40 | lib-y += herror_msg.o |
48 | lib-y += human_readable.o | 41 | lib-y += human_readable.o |
49 | lib-y += inet_common.o | ||
50 | lib-y += inode_hash.o | ||
51 | lib-y += isdirectory.o | 42 | lib-y += isdirectory.o |
52 | lib-y += kernel_version.o | ||
53 | lib-y += last_char_is.o | 43 | lib-y += last_char_is.o |
54 | lib-y += lineedit.o lineedit_ptr_hack.o | 44 | lib-y += lineedit.o lineedit_ptr_hack.o |
55 | lib-y += llist.o | 45 | lib-y += llist.o |
56 | lib-y += login.o | ||
57 | lib-y += make_directory.o | 46 | lib-y += make_directory.o |
58 | lib-y += makedev.o | ||
59 | lib-y += hash_md5_sha.o | 47 | lib-y += hash_md5_sha.o |
60 | lib-y += hash_sha1_x86-64.o | 48 | lib-y += hash_sha1_x86-64.o |
61 | lib-y += hash_sha1_hwaccel_x86-64.o | 49 | lib-y += hash_sha1_hwaccel_x86-64.o |
@@ -68,21 +56,18 @@ lib-y += messages.o | |||
68 | lib-y += mode_string.o | 56 | lib-y += mode_string.o |
69 | lib-y += parse_mode.o | 57 | lib-y += parse_mode.o |
70 | lib-y += perror_msg.o | 58 | lib-y += perror_msg.o |
71 | lib-y += perror_nomsg.o | ||
72 | lib-y += perror_nomsg_and_die.o | 59 | lib-y += perror_nomsg_and_die.o |
73 | lib-y += pidfile.o | ||
74 | lib-y += platform.o | 60 | lib-y += platform.o |
75 | lib-y += popcnt.o | 61 | lib-y += popcnt.o |
76 | lib-y += printable.o | 62 | lib-y += printable.o |
77 | lib-y += printable_string.o | 63 | lib-y += printable_string.o |
78 | lib-y += print_flags.o | ||
79 | lib-y += process_escape_sequence.o | 64 | lib-y += process_escape_sequence.o |
80 | lib-y += procps.o | 65 | lib-y += procps.o |
81 | lib-y += progress.o | 66 | lib-y += progress.o |
82 | lib-y += ptr_to_globals.o | 67 | lib-y += ptr_to_globals.o |
83 | lib-y += read.o | 68 | lib-y += read.o |
84 | lib-y += read_printf.o | ||
85 | lib-y += read_key.o | 69 | lib-y += read_key.o |
70 | lib-y += read_printf.o | ||
86 | lib-y += recursive_action.o | 71 | lib-y += recursive_action.o |
87 | lib-y += remove_file.o | 72 | lib-y += remove_file.o |
88 | lib-y += run_shell.o | 73 | lib-y += run_shell.o |
@@ -91,12 +76,9 @@ lib-y += safe_poll.o | |||
91 | lib-y += safe_strncpy.o | 76 | lib-y += safe_strncpy.o |
92 | lib-y += safe_write.o | 77 | lib-y += safe_write.o |
93 | lib-y += securetty.o | 78 | lib-y += securetty.o |
94 | lib-y += setup_environment.o | ||
95 | lib-y += signals.o | ||
96 | lib-y += simplify_path.o | 79 | lib-y += simplify_path.o |
97 | lib-y += single_argv.o | 80 | lib-y += single_argv.o |
98 | lib-y += skip_whitespace.o | 81 | lib-y += skip_whitespace.o |
99 | lib-y += speed_table.o | ||
100 | lib-y += str_tolower.o | 82 | lib-y += str_tolower.o |
101 | lib-y += strrstr.o | 83 | lib-y += strrstr.o |
102 | lib-y += sysconf.o | 84 | lib-y += sysconf.o |
@@ -109,17 +91,39 @@ lib-y += vfork_daemon_rexec.o | |||
109 | lib-y += warn_ignoring_args.o | 91 | lib-y += warn_ignoring_args.o |
110 | lib-y += wfopen.o | 92 | lib-y += wfopen.o |
111 | lib-y += wfopen_input.o | 93 | lib-y += wfopen_input.o |
112 | lib-y += write.o | ||
113 | lib-y += xatonum.o | 94 | lib-y += xatonum.o |
114 | lib-y += xconnect.o | 95 | lib-y += xconnect.o |
115 | lib-y += xfuncs.o | 96 | lib-y += xfuncs.o |
116 | lib-y += xfuncs_printf.o | 97 | lib-y += xfuncs_printf.o |
117 | lib-y += xfunc_die.o | 98 | lib-y += xfunc_die.o |
118 | lib-y += xgetcwd.o | 99 | lib-y += xgetcwd.o |
119 | lib-y += xgethostbyname.o | ||
120 | lib-y += xreadlink.o | 100 | lib-y += xreadlink.o |
121 | lib-y += xrealloc_vector.o | 101 | lib-y += xrealloc_vector.o |
122 | 102 | ||
103 | lib-$(CONFIG_PLATFORM_POSIX) += alloc_affinity.o | ||
104 | lib-$(CONFIG_PLATFORM_POSIX) += bb_askpass.o | ||
105 | lib-$(CONFIG_PLATFORM_POSIX) += change_identity.o | ||
106 | lib-$(CONFIG_PLATFORM_POSIX) += device_open.o | ||
107 | lib-$(CONFIG_PLATFORM_POSIX) += find_root_device.o | ||
108 | lib-$(CONFIG_PLATFORM_POSIX) += get_console.o | ||
109 | lib-$(CONFIG_PLATFORM_POSIX) += getpty.o | ||
110 | lib-$(CONFIG_PLATFORM_POSIX) += get_volsize.o | ||
111 | lib-$(CONFIG_PLATFORM_POSIX) += inet_common.o | ||
112 | lib-$(CONFIG_PLATFORM_POSIX) += inode_hash.o | ||
113 | lib-$(CONFIG_FEATURE_EXTRA_FILE_DATA) += inode_hash.o | ||
114 | lib-$(CONFIG_PLATFORM_POSIX) += kernel_version.o | ||
115 | lib-$(CONFIG_PLATFORM_POSIX) += login.o | ||
116 | lib-$(CONFIG_PLATFORM_POSIX) += makedev.o | ||
117 | lib-$(CONFIG_PLATFORM_POSIX) += perror_nomsg.o | ||
118 | lib-$(CONFIG_PLATFORM_POSIX) += pidfile.o | ||
119 | lib-$(CONFIG_PLATFORM_POSIX) += print_flags.o | ||
120 | lib-$(CONFIG_PLATFORM_POSIX) += setup_environment.o | ||
121 | lib-$(CONFIG_PLATFORM_POSIX) += signals.o | ||
122 | lib-$(CONFIG_PLATFORM_POSIX) += speed_table.o | ||
123 | lib-$(CONFIG_PLATFORM_POSIX) += udp_io.o | ||
124 | lib-$(CONFIG_PLATFORM_POSIX) += write.o | ||
125 | lib-$(CONFIG_PLATFORM_POSIX) += xgethostbyname.o | ||
126 | |||
123 | lib-$(CONFIG_MOUNT) += match_fstype.o | 127 | lib-$(CONFIG_MOUNT) += match_fstype.o |
124 | lib-$(CONFIG_UMOUNT) += match_fstype.o | 128 | lib-$(CONFIG_UMOUNT) += match_fstype.o |
125 | 129 | ||
@@ -132,7 +136,7 @@ lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o | |||
132 | lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o | 136 | lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o |
133 | lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o | 137 | lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o |
134 | 138 | ||
135 | lib-$(CONFIG_NC) += udp_io.o | 139 | lib-$(CONFIG_NC_110_COMPAT) += udp_io.o |
136 | lib-$(CONFIG_NETCAT) += udp_io.o | 140 | lib-$(CONFIG_NETCAT) += udp_io.o |
137 | lib-$(CONFIG_DNSD) += udp_io.o | 141 | lib-$(CONFIG_DNSD) += udp_io.o |
138 | lib-$(CONFIG_NTPD) += udp_io.o | 142 | lib-$(CONFIG_NTPD) += udp_io.o |
@@ -171,6 +175,7 @@ lib-$(CONFIG_MKE2FS) += find_mount_point.o | |||
171 | lib-$(CONFIG_MKFS_REISER) += find_mount_point.o | 175 | lib-$(CONFIG_MKFS_REISER) += find_mount_point.o |
172 | lib-$(CONFIG_FSCK_MINIX) += find_mount_point.o | 176 | lib-$(CONFIG_FSCK_MINIX) += find_mount_point.o |
173 | lib-$(CONFIG_MOUNT) += find_mount_point.o | 177 | lib-$(CONFIG_MOUNT) += find_mount_point.o |
178 | lib-$(CONFIG_STAT) += find_mount_point.o | ||
174 | 179 | ||
175 | lib-$(CONFIG_HWCLOCK) += rtc.o | 180 | lib-$(CONFIG_HWCLOCK) += rtc.o |
176 | lib-$(CONFIG_RTCWAKE) += rtc.o | 181 | lib-$(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" |
66 | static const char packed_scripts[] ALIGN1 = { PACKED_SCRIPTS }; | 76 | static 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 | ||
105 | static 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 | ||
94 | unsigned FAST_FUNC string_array_len(char **argv) | 110 | unsigned 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 | ||
113 | static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; | 129 | static 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 | ||
202 | static int find_applet_by_name_internal(const char *name) | ||
203 | #else | ||
179 | int FAST_FUNC find_applet_by_name(const char *name) | 204 | int 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 | ||
272 | int 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 | |||
278 | int 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 | ||
285 | static 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 | |||
296 | static 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 | |||
335 | int 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 | ||
245 | void lbb_prepare(const char *applet | 348 | void 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 |
292 | bool re_execed; | 395 | bool re_execed; |
293 | #endif | 396 | #endif |
397 | #if ENABLE_PLATFORM_MINGW32 | ||
398 | static int interp = 0; | ||
399 | char bb_comm[COMM_LEN]; | ||
400 | char bb_command_line[128]; | ||
401 | |||
402 | # if ENABLE_FEATURE_SH_STANDALONE | ||
403 | void 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 | ||
955 | void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv) | 1192 | void 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 | ||
13 | gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array) | 14 | gid_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 | ||
49 | uid_t FAST_FUNC get_cached_euid(uid_t *euid) | 51 | uid_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. */ |
64 | int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid) | 71 | int 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 | ||
31 | char* 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 | ||
35 | char* FAST_FUNC is_suffixed_with(const char *string, const char *key) | 49 | char* 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 | ||
64 | static 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 | |||
80 | char* FAST_FUNC is_suffixed_with(const char *string, const char *key) | ||
81 | { | ||
82 | return is_suffixed(string, key, strcmp); | ||
83 | } | ||
84 | |||
85 | char* 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 | ||
18 | void 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 @@ | |||
15 | int FAST_FUNC file_is_executable(const char *name) | 15 | int 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 @@ | |||
19 | struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too) | 22 | struct 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 | ||
40 | static int comm_match(procps_status_t *p, const char *procName) | 40 | static 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 | ||
11 | const char* FAST_FUNC bb_basename(const char *name) | 11 | const 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 | ||
27 | char * 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 | */ |
25 | char* FAST_FUNC bb_get_last_path_component_nostrip(const char *path) | 47 | char* 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 | */ |
41 | char* FAST_FUNC bb_get_last_path_component_strip(char *path) | 73 | char* 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 | ||
595 | uint32_t FAST_FUNC | 595 | uint32_t |
596 | getopt32(char **argv, const char *applet_opts, ...) | 596 | getopt32(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 |
608 | uint32_t FAST_FUNC | 608 | uint32_t |
609 | getopt32long(char **argv, const char *applet_opts, const char *longopts, ...) | 609 | getopt32long(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 | ||
11 | void FAST_FUNC bb_herror_msg(const char *s, ...) | 11 | void 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 | ||
20 | void FAST_FUNC bb_herror_msg_and_die(const char *s, ...) | 20 | void 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 | ||
22 | char* 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 |
417 | static void put_cur_glyph_and_inc_cursor(void) | 423 | static 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 | ||
486 | static 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) */ |
480 | static void put_till_end_and_adv_cursor(void) | 522 | static 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) | |||
688 | static void input_forward(void) | 732 | static 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 | ||
712 | static void add_match(char *matched) | 772 | #if !ENABLE_PLATFORM_MINGW32 |
773 | # define add_match(m, s) add_match(m) | ||
774 | #endif | ||
775 | |||
776 | static 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 | ||
814 | static 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 | */ |
736 | static char *username_path_completion(char *ud) | 827 | static 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 | ||
786 | enum { | 883 | enum { |
@@ -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 | ||
1403 | unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp) | 1589 | unsigned 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 | ||
28 | const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF"; | 31 | const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF"; |
29 | 32 | ||
33 | #if !ENABLE_PLATFORM_MINGW32 | ||
30 | const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; | 34 | const 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 | */ | ||
46 | const 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 | ||
31 | const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; | 53 | const 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 | ||
11 | void FAST_FUNC bb_perror_msg(const char *s, ...) | 11 | void 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 | ||
21 | void FAST_FUNC bb_perror_msg_and_die(const char *s, ...) | 21 | void 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... */ |
22 | int FAST_FUNC sigaction_set(int signum, const struct sigaction *act) | 23 | int 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 | ||
44 | void FAST_FUNC bb_signals(int sigs, void (*f)(int)) | 46 | void 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 | ||
33 | static const char signals[][7] ALIGN1 = { | 46 | static 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) | |||
69 | void FAST_FUNC reinit_unicode(const char *LANG) | 69 | void 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 |
275 | struct interval { | 283 | struct 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 |
702 | int FAST_FUNC unicode_bidi_isrtl(wint_t wc) | 715 | int 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 | ||
159 | void FAST_FUNC bb_error_msg_and_die(const char *s, ...) | 159 | void 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 | ||
169 | void FAST_FUNC bb_error_msg(const char *s, ...) | 169 | void 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 | ||
186 | void FAST_FUNC bb_info_msg(const char *s, ...) | 186 | void 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. */ |
176 | pid_t FAST_FUNC spawn(char **argv) | 177 | pid_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. */ |
217 | pid_t FAST_FUNC xspawn(char **argv) | 219 | pid_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 |
252 | void FAST_FUNC re_exec(char **argv) | 257 | void 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 | */ | ||
8 | int 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 | ||
74 | static len_and_sockaddr* get_lsa(int fd, int (*get_name)(int fd, struct sockaddr *addr, socklen_t *addrlen)) | 75 | static 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 | ||
103 | void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) | 105 | void 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 | ||
26 | int FAST_FUNC ndelay_on(int fd) | 27 | int 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 | ||
49 | char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src) | 51 | char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src) |
50 | { | 52 | { |
@@ -219,7 +221,12 @@ off_t FAST_FUNC fdlength(int fd) | |||
219 | 221 | ||
220 | int FAST_FUNC bb_putchar_stderr(char ch) | 222 | int 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 | ||
225 | ssize_t FAST_FUNC full_write1_str(const char *str) | 232 | ssize_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 | ||
317 | int FAST_FUNC get_termios_and_make_raw(int fd, struct termios *newterm, struct termios *oldterm, int flags) | 326 | int 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 | ||
111 | void* FAST_FUNC mmap_read(int fd, size_t size) | 112 | void* 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. |
337 | char* FAST_FUNC xasprintf(const char *format, ...) | 339 | char* 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 */ |
506 | ssize_t FAST_FUNC xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, | 509 | ssize_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 |
519 | void FAST_FUNC xstat(const char *name, struct stat *stat_buf) | 523 | void 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 | ||
550 | int FAST_FUNC ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...) | 554 | #if !ENABLE_PLATFORM_MINGW32 |
555 | int 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 | ||
566 | int FAST_FUNC ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) | 571 | int 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 | ||
727 | void FAST_FUNC xsettimeofday(const struct timeval *tv) | 734 | void 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 | ||
733 | void FAST_FUNC xgettimeofday(struct timeval *tv) | 741 | void 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 | ||
20 | char* FAST_FUNC xmalloc_readlink(const char *path) | 21 | char* 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 | |||
33 | enum { | ||
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 | |||
43 | int suw32_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
44 | int 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 | ||
7473 | static 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 | |||
7469 | static int xc_vm_init(const char *env_len) | 7483 | static 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 |
19 | typedef unsigned long long data_t; | 19 | typedef unsigned long long data_t; |
20 | #define DATA_FMT "ll" | 20 | #define DATA_FMT LL_FMT |
21 | #endif | 21 | #endif |
22 | 22 | ||
23 | struct globals { | 23 | struct 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". | ||
63 | static 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 | |||
73 | int drop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
74 | int 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 | |||
51 | typedef unsigned char uchar; | ||
52 | typedef unsigned short ushort; | ||
53 | typedef unsigned int uint; | ||
54 | |||
55 | typedef void* iconv_t; | ||
56 | |||
57 | static iconv_t iconv_open(const char *tocode, const char *fromcode); | ||
58 | static int iconv_close(iconv_t cd); | ||
59 | static size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); | ||
60 | |||
61 | typedef struct compat_t compat_t; | ||
62 | typedef struct csconv_t csconv_t; | ||
63 | typedef struct rec_iconv_t rec_iconv_t; | ||
64 | |||
65 | typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); | ||
66 | typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); | ||
67 | typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize); | ||
68 | typedef 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. */ | ||
74 | struct compat_t { | ||
75 | uint in; | ||
76 | uint out; | ||
77 | uint flag; | ||
78 | }; | ||
79 | |||
80 | struct 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 | |||
91 | struct rec_iconv_t { | ||
92 | iconv_t cd; | ||
93 | csconv_t from; | ||
94 | csconv_t to; | ||
95 | }; | ||
96 | |||
97 | static int load_mlang(void); | ||
98 | static int make_csconv(const char *name, csconv_t *cv); | ||
99 | static int name_to_codepage(const char *name); | ||
100 | static uint utf16_to_ucs4(const ushort *wbuf); | ||
101 | static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize); | ||
102 | static int mbtowc_flags(int codepage); | ||
103 | static int must_use_null_useddefaultchar(int codepage); | ||
104 | static int seterror(int err); | ||
105 | |||
106 | static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize); | ||
107 | static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize); | ||
108 | static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize); | ||
109 | static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize); | ||
110 | static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize); | ||
111 | |||
112 | static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); | ||
113 | static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); | ||
114 | static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); | ||
115 | static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); | ||
116 | static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); | ||
117 | static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); | ||
118 | static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); | ||
119 | static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); | ||
120 | static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); | ||
121 | static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); | ||
122 | static 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, | ||
557 | static const int cp_codepage[] = { | ||
558 | CP_ALIAS_LIST | ||
559 | }; | ||
560 | #undef CP_ALIAS | ||
561 | |||
562 | #define CP_ALIAS(codepage, alias) alias"\0" | ||
563 | static 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 | */ | ||
586 | static 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 | |||
599 | static 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 | |||
612 | static compat_t *cp51932_compat = cp932_compat; | ||
613 | |||
614 | /* cp20932_compat for kernel. cp932_compat for mlang. */ | ||
615 | static compat_t *cp5022x_compat = cp932_compat; | ||
616 | |||
617 | typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)( | ||
618 | LPDWORD lpdwMode, | ||
619 | DWORD dwSrcEncoding, | ||
620 | LPCSTR lpSrcStr, | ||
621 | LPINT lpnMultiCharCount, | ||
622 | LPWSTR lpDstStr, | ||
623 | LPINT lpnWideCharCount | ||
624 | ); | ||
625 | |||
626 | typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)( | ||
627 | LPDWORD lpdwMode, | ||
628 | DWORD dwEncoding, | ||
629 | LPCWSTR lpSrcStr, | ||
630 | LPINT lpnWideCharCount, | ||
631 | LPSTR lpDstStr, | ||
632 | LPINT lpnMultiCharCount | ||
633 | ); | ||
634 | |||
635 | static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode; | ||
636 | static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte; | ||
637 | |||
638 | static int | ||
639 | load_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 | |||
652 | static iconv_t | ||
653 | iconv_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 | |||
671 | static int | ||
672 | iconv_close(iconv_t _cd) | ||
673 | { | ||
674 | free(_cd); | ||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static size_t | ||
679 | iconv(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 | |||
800 | static int | ||
801 | make_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 | |||
907 | static int | ||
908 | name_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 | */ | ||
939 | static uint | ||
940 | utf16_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 | |||
948 | static void | ||
949 | ucs4_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 | */ | ||
975 | static int | ||
976 | mbtowc_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 | */ | ||
994 | static int | ||
995 | must_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 | |||
1006 | static int | ||
1007 | seterror(int err) | ||
1008 | { | ||
1009 | errno = err; | ||
1010 | return -1; | ||
1011 | } | ||
1012 | |||
1013 | static int | ||
1014 | sbcs_mblen(csconv_t *cv UNUSED_PARAM, const uchar *buf UNUSED_PARAM, | ||
1015 | int bufsize UNUSED_PARAM) | ||
1016 | { | ||
1017 | return 1; | ||
1018 | } | ||
1019 | |||
1020 | static int | ||
1021 | dbcs_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 | |||
1029 | static int | ||
1030 | mbcs_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 | |||
1054 | static int | ||
1055 | utf8_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 | |||
1073 | static int | ||
1074 | eucjp_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 | |||
1106 | static int | ||
1107 | kernel_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 | |||
1127 | static int | ||
1128 | kernel_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 | */ | ||
1168 | static int | ||
1169 | mlang_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 | |||
1186 | static int | ||
1187 | mlang_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 | |||
1206 | static int | ||
1207 | utf16_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 | |||
1257 | static int | ||
1258 | utf16_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 | |||
1309 | static int | ||
1310 | utf32_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 | |||
1348 | static int | ||
1349 | utf32_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 */ | ||
1412 | static const char iso2022_SI_seq[] = "\x0F"; | ||
1413 | /* shift out */ | ||
1414 | static const char iso2022_SO_seq[] = "\x0E"; | ||
1415 | |||
1416 | typedef struct iso2022_esc_t iso2022_esc_t; | ||
1417 | struct 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 | |||
1431 | static 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 | |||
1441 | static int | ||
1442 | iso2022jp_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 | |||
1545 | static int | ||
1546 | iso2022jp_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 | |||
1641 | static int | ||
1642 | iso2022jp_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 | |||
1674 | static 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 | |||
1709 | enum { | ||
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 | |||
1717 | int iconv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
1718 | int 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 | ||
72 | static const char mask_names[] ALIGN1 = | 79 | static 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 | */ | ||
238 | static 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 | |||
247 | enum { | ||
248 | MASK_BITS = sizeof(mask_names) - 1 | ||
249 | }; | ||
250 | |||
251 | static 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 | |||
260 | struct 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 | |||
270 | static 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 | |||
305 | static 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 | |||
318 | int inotifyd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
319 | int 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 | |||
27 | int jn_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
28 | int 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 | ||
336 | static NOINLINE void less_exit(void) | 344 | static 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 | ||
1132 | static int64_t unix_getch_nowait(void) | ||
1133 | #else | ||
1096 | static int64_t getch_nowait(void) | 1134 | static 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 | ||
1198 | static int64_t getch_nowait(void) | ||
1199 | { | ||
1200 | int64_t c; | ||
1201 | |||
1202 | if (terminal_mode(FALSE) & VT_INPUT) | ||
1203 | return unix_getch_nowait(); | ||
1204 | |||
1205 | retry: | ||
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 | ||
1797 | static void sig_catcher(int sig) | 1881 | static 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 |
1804 | static void sigwinch_handler(int sig UNUSED_PARAM) | 1889 | static void sigwinch_handler(int sig UNUSED_PARAM) |
@@ -1810,7 +1895,11 @@ static void sigwinch_handler(int sig UNUSED_PARAM) | |||
1810 | int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1895 | int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1811 | int less_main(int argc, char **argv) | 1896 | int 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 | |||
114 | enum { | ||
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. | ||
173 | struct 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 | ||
194 | struct 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 | ||
204 | struct 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 | ||
211 | struct 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 | ||
220 | struct 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(). | ||
235 | enum { | ||
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 | |||
262 | struct 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 | |||
322 | static 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 | */ | ||
336 | static void | ||
337 | vwarning(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 | */ | ||
349 | static void | ||
350 | diagnostic(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 | */ | ||
362 | static void error(const char *msg, ...) NORETURN; | ||
363 | static void | ||
364 | error(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 | |||
374 | static void error_unexpected(const char *s) NORETURN; | ||
375 | static void | ||
376 | error_unexpected(const char *s) | ||
377 | { | ||
378 | error("unexpected %s", s); | ||
379 | } | ||
380 | |||
381 | static void error_in_inference_rule(const char *s) NORETURN; | ||
382 | static void | ||
383 | error_in_inference_rule(const char *s) | ||
384 | { | ||
385 | error("%s in inference rule", s); | ||
386 | } | ||
387 | |||
388 | static void | ||
389 | error_not_allowed(const char *s, const char *t) | ||
390 | { | ||
391 | error("%s not allowed for %s", s, t); | ||
392 | } | ||
393 | |||
394 | static void | ||
395 | warning(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 | |||
404 | static char * | ||
405 | auto_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 | */ | ||
416 | static char * | ||
417 | xappendword(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 | |||
425 | static unsigned int | ||
426 | getbucket(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 | */ | ||
439 | static void | ||
440 | newdep(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 | |||
450 | static void | ||
451 | freedeps(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 | */ | ||
460 | static void | ||
461 | newcmd(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 | |||
477 | static void | ||
478 | freecmds(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 | |||
492 | static struct name * | ||
493 | findname(const char *name) | ||
494 | { | ||
495 | struct name *np = namehead[getbucket(name)]; | ||
496 | return (struct name *)llist_find_str((llist_t *)np, name); | ||
497 | } | ||
498 | |||
499 | static int | ||
500 | check_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 | |||
527 | static char *splitlib(const char *name, char **member); | ||
528 | |||
529 | static int | ||
530 | is_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 | ||
546 | static int | ||
547 | potentially_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 | */ | ||
563 | static struct name * | ||
564 | newname(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 | */ | ||
595 | static struct cmd * | ||
596 | getcmd(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 | ||
610 | static void | ||
611 | freenames(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 | |||
627 | static void | ||
628 | freerules(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 | |||
640 | static void * | ||
641 | inc_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 | ||
655 | static 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 | |||
667 | static void | ||
668 | set_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 | |||
690 | static void | ||
691 | pragmas_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 | */ | ||
723 | static void | ||
724 | addrule(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 | */ | ||
782 | static struct macro * | ||
783 | getmp(const char *name) | ||
784 | { | ||
785 | struct macro *mp = macrohead[getbucket(name)]; | ||
786 | return (struct macro *)llist_find_str((llist_t *)mp, name); | ||
787 | } | ||
788 | |||
789 | static int | ||
790 | is_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 | ||
811 | static int | ||
812 | potentially_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 | |||
825 | static void | ||
826 | setmacro(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 | ||
872 | static void | ||
873 | freemacros(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 | */ | ||
892 | static void FAST_FUNC | ||
893 | record_mtime(const file_header_t *file_header) | ||
894 | { | ||
895 | ar_mtime = file_header->mtime; | ||
896 | } | ||
897 | |||
898 | static time_t | ||
899 | artime(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 | */ | ||
933 | static char * | ||
934 | splitlib(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 | */ | ||
957 | static void | ||
958 | modtime(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 | */ | ||
988 | static char * | ||
989 | suffix(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 | */ | ||
1002 | static struct name * | ||
1003 | dyndep(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 | */ | ||
1145 | static char * | ||
1146 | getrules(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 | */ | ||
1192 | static char * | ||
1193 | gettok(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 | */ | ||
1218 | static char * | ||
1219 | skip_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 | */ | ||
1245 | static char * | ||
1246 | modify_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 | */ | ||
1327 | static char * | ||
1328 | find_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 | */ | ||
1344 | static char * | ||
1345 | find_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 | */ | ||
1364 | static char * | ||
1365 | expand_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 | */ | ||
1507 | static void | ||
1508 | process_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 | |||
1545 | enum { | ||
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 | */ | ||
1563 | static int | ||
1564 | compare_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 | */ | ||
1618 | static int | ||
1619 | skip_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 | */ | ||
1721 | static char * | ||
1722 | make_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 | */ | ||
1732 | static char * | ||
1733 | readline(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 | */ | ||
1794 | static int | ||
1795 | is_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 | |||
1812 | enum { | ||
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 | */ | ||
1824 | static int | ||
1825 | target_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 | |||
1882 | static int | ||
1883 | ends_with_bracket(const char *s) | ||
1884 | { | ||
1885 | return last_char_is(s, ')') != NULL; | ||
1886 | } | ||
1887 | |||
1888 | /* | ||
1889 | * Process a command line | ||
1890 | */ | ||
1891 | static char * | ||
1892 | process_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 | |||
1938 | static char * | ||
1939 | run_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 | */ | ||
2001 | static 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 | */ | ||
2024 | static int | ||
2025 | wildcard(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 | ||
2055 | static void | ||
2056 | pragmas_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 | */ | ||
2074 | static void | ||
2075 | input(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 | |||
2441 | static void | ||
2442 | remove_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 | */ | ||
2454 | static void | ||
2455 | touch(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 | */ | ||
2479 | static int | ||
2480 | docmds(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 | |||
2588 | static int | ||
2589 | make1(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 | */ | ||
2640 | static int | ||
2641 | timespec_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 | */ | ||
2655 | static const struct timespec * | ||
2656 | timespec_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 | */ | ||
2664 | static int | ||
2665 | make(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 | |||
2829 | static void | ||
2830 | print_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 | |||
2839 | static void | ||
2840 | print_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 | |||
2848 | static void | ||
2849 | print_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 | |||
2857 | static void | ||
2858 | print_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 | */ | ||
2901 | static uint32_t | ||
2902 | process_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 | */ | ||
2922 | static char ** | ||
2923 | expand_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 | */ | ||
2996 | static char ** | ||
2997 | process_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 | */ | ||
3071 | static void | ||
3072 | update_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 | ||
3130 | static void | ||
3131 | make_handler(int sig) | ||
3132 | { | ||
3133 | signal(sig, SIG_DFL); | ||
3134 | remove_target(); | ||
3135 | kill(getpid(), sig); | ||
3136 | } | ||
3137 | |||
3138 | static void | ||
3139 | init_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 | */ | ||
3158 | static void | ||
3159 | mark_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 | |||
3179 | int make_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
3180 | int 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 .*/ |
58 | static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S"; | 65 | static 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.*/ |
62 | static const char long_format[] ALIGN1 = | 70 | static 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 | ||
190 | static void summarize(const char *fmt, char **command, resource_t *resp) | 203 | static 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) | |||
409 | static void run_command(char *const *cmd, resource_t *resp) | 434 | static 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 | ||
434 | int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 467 | int 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; | |||
25 | int ts_main(int argc UNUSED_PARAM, char **argv) | 25 | int 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 | ||
335 | static 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 | ||
453 | struct globals { | 465 | struct 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 */ |
563 | enum { | 592 | enum { |
@@ -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 | ||
1583 | static 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 | ||
1527 | static void setenv1(const char *name, const char *value) | 1624 | static 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 | */ |
2170 | static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN; | ||
2171 | static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM) | 2339 | static 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 |
2636 | static void mini_httpd(int server_socket) NORETURN; | 2822 | static void mini_httpd(int server_socket) NORETURN; |
2637 | static void mini_httpd(int server_socket) | 2823 | static 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 */ | ||
2910 | static void mini_httpd_win32(int sock, int argc, char **argv) NORETURN; | ||
2911 | static 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 | ||
2961 | static 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 | ||
2740 | static void sighup_handler(int sig UNUSED_PARAM) | 2983 | static 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 | ||
2747 | enum { | 2991 | enum { |
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 | ||
113 | static void timeout(int signum UNUSED_PARAM) | 114 | static 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 | ||
118 | int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 120 | int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
119 | int nc_main(int argc, char **argv) | 121 | int 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 | ||
332 | void FAST_FUNC tls_get_random(void *buf, unsigned len) | 332 | void 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 | }; |
218 | static const char wget_user_headers[] ALIGN1 = | 221 | static 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 | ||
769 | static void spawn_ssl_client(const char *host, int network_fd, int flags) | 784 | static 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 | ||
839 | static 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) */ |
81 | static NOINLINE unsigned int parse_meminfo(struct globals *g) | 82 | static 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 | ||
108 | static 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 | ||
107 | int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 116 | int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
108 | int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM)) | 117 | int 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 |
29 | typedef unsigned long long cputime_t; | 29 | typedef unsigned long long cputime_t; |
30 | typedef long long icputime_t; | 30 | typedef 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 |
34 | typedef unsigned long cputime_t; | 34 | typedef 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 |
50 | typedef unsigned long long data_t; | 50 | typedef unsigned long long data_t; |
51 | typedef long long idata_t; | 51 | typedef 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 |
55 | typedef unsigned long data_t; | 55 | typedef 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 | ||
92 | static void act(unsigned pid, char *cmd, int signo) | 132 | static 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 |
121 | static unsigned long get_uptime(void) | 121 | static 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 | ||
240 | static void func_state(char *buf, int size, const procps_status_t *ps) | 241 | static 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 | ||
245 | static void func_args(char *buf, int size, const procps_status_t *ps) | 247 | static 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 | ||
260 | static void func_pgid(char *buf, int size, const procps_status_t *ps) | 263 | static 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 |
298 | static void func_rgroup(char *buf, int size, const procps_status_t *ps) | 302 | static 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 | ||
24 | struct fileblock { | 25 | struct 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 | ||
55 | as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \ | 55 | as-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 | ||
62 | cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \ | 62 | cc-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 | ||
68 | hostcc-option = $(shell if $(HOSTCC) $(HOSTCFLAGS) $(1) -S -o /dev/null -xc /dev/null \ | 68 | hostcc-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) |
73 | cc-option-yn = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \ | 73 | cc-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 | # |
255 | ifdef builtin-target | 255 | ifdef builtin-target |
256 | quiet_cmd_link_o_target = LD $@ | 256 | quiet_cmd_link_o_target = LD $@ |
257 | ifeq ($(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) |
259 | cmd_link_o_target = $(if $(strip $(obj-y)),\ | 260 | cmd_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 $@) |
263 | else | ||
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. | ||
268 | ifeq ($(words $(obj-y)),0) | ||
269 | cmd_link_o_target = rm -f $@; $(AR) rcs $@ | ||
270 | else | ||
271 | ifeq ($(words $(obj-y)),1) | ||
272 | cmd_link_o_target = cp $(obj-y) $@ | ||
273 | else | ||
274 | cmd_link_o_target = \ | ||
275 | $(LD) -nostdlib $(ld_flags) -r -o $@ $(filter $(obj-y), $^)) | ||
276 | endif | ||
277 | endif | ||
278 | endif | ||
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 | |||
92 | hostc_flags = -Wp,-MD,$(depfile) $(__hostc_flags) | 92 | hostc_flags = -Wp,-MD,$(depfile) $(__hostc_flags) |
93 | hostcxx_flags = -Wp,-MD,$(depfile) $(__hostcxx_flags) | 93 | hostcxx_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 | # | ||
104 | host_target := $(shell $(HOSTCC) -v 2>&1 | grep ^Target:) | ||
105 | host_platform := $(word 4,$(subst -, ,$(host_target))) | ||
106 | dot := | ||
107 | ifeq ($(host_platform),mingw32) | ||
108 | dot := . | ||
109 | endif | ||
110 | ifeq ($(host_platform),windows) | ||
111 | dot := . | ||
112 | endif | ||
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 |
100 | quiet_cmd_host-csingle = HOSTCC $@ | 119 | quiet_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 |
108 | quiet_cmd_host-cmulti = HOSTLD $@ | 127 | quiet_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 | |||
2 | fixdep | 2 | fixdep |
3 | docproc | 3 | docproc |
4 | split-include | 4 | split-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 | */ |
79 | void exec_kernel_doc(char **svec) | 81 | void 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 | ||
140 | void *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 | } | ||
175 | void munmap(void *p, size_t size UNUSED) | ||
176 | { | ||
177 | free(p); | ||
178 | } | ||
179 | #endif | ||
180 | |||
126 | char *target; | 181 | char *target; |
127 | char *depfile; | 182 | char *depfile; |
128 | char *cmdline; | 183 | char *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 | |||
44 | int main(int argc, const char * argv []) | 42 | int 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 | ||
44 | sym_args = " ".join(sys.argv[3 + flag_timing + dashes:]) | 44 | sym_args = " ".join(sys.argv[3 + flag_timing + dashes:]) |
45 | def getsizes(file): | 45 | def 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 | ||
85 | def 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 | |||
83 | if flag_timing: | 108 | if flag_timing: |
84 | start_t1 = int(time.time() * 1e9) | 109 | start_t1 = int(time.time() * 1e9) |
85 | old = getsizes(f1) | 110 | old = 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 |
24 | fi | 24 | fi |
25 | 25 | ||
26 | bzip2 </dev/null >/dev/null | 26 | bzip2 </dev/null >/dev/null 2>&1 |
27 | if test $? != 0; then | 27 | if test $? = 127; then |
28 | echo 'bzip2 is not installed' | 28 | echo 'bzip2 is not installed' |
29 | exit 1 | 29 | exit 1 |
30 | fi | 30 | fi |
@@ -90,6 +90,7 @@ concatenate_scripts() { | |||
90 | done | 90 | done |
91 | } | 91 | } |
92 | 92 | ||
93 | ( | ||
93 | exec >"$target.$$" | 94 | exec >"$target.$$" |
94 | 95 | ||
95 | if [ $n -ne 0 ] | 96 | if [ $n -ne 0 ] |
@@ -127,5 +128,6 @@ then | |||
127 | -e 's/$/ \\/' | 128 | -e 's/$/ \\/' |
128 | printf '\n' | 129 | printf '\n' |
129 | fi | 130 | fi |
131 | ) | ||
130 | 132 | ||
131 | mv -- "$target.$$" "$target" | 133 | mv -- "$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 | |||
17 | qconf | 17 | qconf |
18 | gconf | 18 | gconf |
19 | kxgettext | 19 | kxgettext |
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. | ||
7 | ifndef 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 | ||
14 | endif | ||
15 | |||
5 | PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config | 16 | PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config |
6 | 17 | ||
7 | xconfig: $(obj)/qconf | 18 | xconfig: $(obj)/qconf |
@@ -11,6 +22,9 @@ gconfig: $(obj)/gconf | |||
11 | $< Config.in | 22 | $< Config.in |
12 | 23 | ||
13 | menuconfig: $(obj)/mconf | 24 | menuconfig: $(obj)/mconf |
25 | ifdef W64DEVKIT | ||
26 | $(Q)$(MAKE) $(build)=scripts/kconfig/libcurses | ||
27 | endif | ||
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 @@ | |||
1 | lib-y := | ||
2 | |||
3 | INSERT | ||
4 | |||
5 | lib-y +=addch.o | ||
6 | lib-n +=addchstr.o | ||
7 | lib-y +=addstr.o | ||
8 | lib-y +=attr.o | ||
9 | lib-y +=beep.o | ||
10 | lib-y +=bkgd.o | ||
11 | lib-y +=border.o | ||
12 | lib-y +=clear.o | ||
13 | lib-y +=color.o | ||
14 | lib-n +=debug.o | ||
15 | lib-n +=delch.o | ||
16 | lib-n +=deleteln.o | ||
17 | lib-y +=getch.o | ||
18 | lib-n +=getstr.o | ||
19 | lib-y +=getyx.o | ||
20 | lib-y +=inch.o | ||
21 | lib-n +=inchstr.o | ||
22 | lib-y +=initscr.o | ||
23 | lib-y +=inopts.o | ||
24 | lib-n +=insch.o | ||
25 | lib-n +=insstr.o | ||
26 | lib-n +=instr.o | ||
27 | lib-y +=kernel.o | ||
28 | lib-n +=keyname.o | ||
29 | lib-n +=mouse.o | ||
30 | lib-y +=move.o | ||
31 | lib-y +=outopts.o | ||
32 | lib-y +=overlay.o | ||
33 | lib-y +=pad.o | ||
34 | lib-n +=panel.o | ||
35 | lib-y +=pdcclip.o | ||
36 | lib-y +=pdcdisp.o | ||
37 | lib-y +=pdcgetsc.o | ||
38 | lib-y +=pdckbd.o | ||
39 | lib-y +=pdcscrn.o | ||
40 | lib-y +=pdcsetsc.o | ||
41 | lib-y +=pdcutil.o | ||
42 | lib-y +=printw.o | ||
43 | lib-y +=refresh.o | ||
44 | lib-n +=scanw.o | ||
45 | lib-n +=scr_dump.o | ||
46 | lib-y +=scroll.o | ||
47 | lib-y +=slk.o | ||
48 | lib-n +=termattr.o | ||
49 | lib-y +=touch.o | ||
50 | lib-n +=util.o | ||
51 | lib-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 @@ | |||
1 | PDCurses for Windows console | ||
2 | ============================ | ||
3 | |||
4 | This directory contains PDCurses source code files specific to the | ||
5 | Microsoft Windows console. Although historically called "Win32", this | ||
6 | port can just as easily be built for 64-bit systems. Windows 95 through | ||
7 | Windows 10 are covered. (Some features require later versions.) | ||
8 | |||
9 | |||
10 | Acknowledgements | ||
11 | ---------------- | ||
12 | |||
13 | Windows console port was originally provided by Chris Szurgot | ||
14 | <szurgot@itribe.net> | ||
15 | |||
16 | |||
17 | Distribution Status | ||
18 | ------------------- | ||
19 | |||
20 | The 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 | |||
4 | chtype 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 | |||
3 | chtype 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 | |||
7 | addch | ||
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 | |||
113 | int 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 | |||
273 | int addch(const chtype ch) | ||
274 | { | ||
275 | PDC_LOG(("addch() - called: ch=%x\n", ch)); | ||
276 | |||
277 | return waddch(stdscr, ch); | ||
278 | } | ||
279 | |||
280 | int 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 | |||
290 | int 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 | |||
300 | int echochar(const chtype ch) | ||
301 | { | ||
302 | PDC_LOG(("echochar() - called: ch=%x\n", ch)); | ||
303 | |||
304 | return wechochar(stdscr, ch); | ||
305 | } | ||
306 | |||
307 | int 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 | |||
317 | int 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 | |||
328 | int addrawch(chtype ch) | ||
329 | { | ||
330 | PDC_LOG(("addrawch() - called: ch=%x\n", ch)); | ||
331 | |||
332 | return waddrawch(stdscr, ch); | ||
333 | } | ||
334 | |||
335 | int 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 | |||
345 | int 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 | ||
357 | int 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 | |||
364 | int 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 | |||
371 | int 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 | |||
381 | int 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 | |||
392 | int 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 | |||
399 | int 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 | |||
7 | addstr | ||
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 | |||
66 | int 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 | |||
95 | int addstr(const char *str) | ||
96 | { | ||
97 | PDC_LOG(("addstr() - called: string=\"%s\"\n", str)); | ||
98 | |||
99 | return waddnstr(stdscr, str, -1); | ||
100 | } | ||
101 | |||
102 | int 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 | |||
109 | int 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 | |||
116 | int 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 | |||
126 | int 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 | |||
137 | int 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 | |||
147 | int 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 | ||
159 | int 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 | |||
179 | int addwstr(const wchar_t *wstr) | ||
180 | { | ||
181 | PDC_LOG(("addwstr() - called\n")); | ||
182 | |||
183 | return waddnwstr(stdscr, wstr, -1); | ||
184 | } | ||
185 | |||
186 | int addnwstr(const wchar_t *wstr, int n) | ||
187 | { | ||
188 | PDC_LOG(("addnwstr() - called\n")); | ||
189 | |||
190 | return waddnwstr(stdscr, wstr, n); | ||
191 | } | ||
192 | |||
193 | int waddwstr(WINDOW *win, const wchar_t *wstr) | ||
194 | { | ||
195 | PDC_LOG(("waddwstr() - called\n")); | ||
196 | |||
197 | return waddnwstr(win, wstr, -1); | ||
198 | } | ||
199 | |||
200 | int 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 | |||
210 | int 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 | |||
220 | int 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 | |||
230 | int 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 | |||
7 | attr | ||
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 | |||
132 | int 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 | |||
144 | int attroff(chtype attrs) | ||
145 | { | ||
146 | PDC_LOG(("attroff() - called\n")); | ||
147 | |||
148 | return wattroff(stdscr, attrs); | ||
149 | } | ||
150 | |||
151 | int 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 | |||
175 | int attron(chtype attrs) | ||
176 | { | ||
177 | PDC_LOG(("attron() - called\n")); | ||
178 | |||
179 | return wattron(stdscr, attrs); | ||
180 | } | ||
181 | |||
182 | int 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 | |||
194 | int attrset(chtype attrs) | ||
195 | { | ||
196 | PDC_LOG(("attrset() - called\n")); | ||
197 | |||
198 | return wattrset(stdscr, attrs); | ||
199 | } | ||
200 | |||
201 | int standend(void) | ||
202 | { | ||
203 | PDC_LOG(("standend() - called\n")); | ||
204 | |||
205 | return wattrset(stdscr, A_NORMAL); | ||
206 | } | ||
207 | |||
208 | int standout(void) | ||
209 | { | ||
210 | PDC_LOG(("standout() - called\n")); | ||
211 | |||
212 | return wattrset(stdscr, A_STANDOUT); | ||
213 | } | ||
214 | |||
215 | int wstandend(WINDOW *win) | ||
216 | { | ||
217 | PDC_LOG(("wstandend() - called\n")); | ||
218 | |||
219 | return wattrset(win, A_NORMAL); | ||
220 | } | ||
221 | |||
222 | int wstandout(WINDOW *win) | ||
223 | { | ||
224 | PDC_LOG(("wstandout() - called\n")); | ||
225 | |||
226 | return wattrset(win, A_STANDOUT); | ||
227 | } | ||
228 | |||
229 | chtype getattrs(WINDOW *win) | ||
230 | { | ||
231 | return win ? win->_attrs : 0; | ||
232 | } | ||
233 | |||
234 | int 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 | |||
246 | int 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 | |||
253 | int 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 | |||
269 | int 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 | |||
276 | int 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 | |||
283 | int attr_off(attr_t attrs, void *opts) | ||
284 | { | ||
285 | PDC_LOG(("attr_off() - called\n")); | ||
286 | |||
287 | return wattroff(stdscr, attrs); | ||
288 | } | ||
289 | |||
290 | int 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 | |||
297 | int attr_on(attr_t attrs, void *opts) | ||
298 | { | ||
299 | PDC_LOG(("attr_on() - called\n")); | ||
300 | |||
301 | return wattron(stdscr, attrs); | ||
302 | } | ||
303 | |||
304 | int 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 | |||
316 | int 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 | |||
323 | int 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 | |||
355 | int 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 | |||
362 | int 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 | |||
372 | int 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 | |||
383 | int underend(void) | ||
384 | { | ||
385 | PDC_LOG(("underend() - called\n")); | ||
386 | |||
387 | return wattroff(stdscr, A_UNDERLINE); | ||
388 | } | ||
389 | |||
390 | int wunderend(WINDOW *win) | ||
391 | { | ||
392 | PDC_LOG(("wunderend() - called\n")); | ||
393 | |||
394 | return wattroff(win, A_UNDERLINE); | ||
395 | } | ||
396 | |||
397 | int underscore(void) | ||
398 | { | ||
399 | PDC_LOG(("underscore() - called\n")); | ||
400 | |||
401 | return wattron(stdscr, A_UNDERLINE); | ||
402 | } | ||
403 | |||
404 | int 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 | |||
7 | beep | ||
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 | |||
35 | int 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 | |||
50 | int 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 | |||
7 | bkgd | ||
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 | |||
66 | int 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 | |||
144 | int bkgd(chtype ch) | ||
145 | { | ||
146 | PDC_LOG(("bkgd() - called\n")); | ||
147 | |||
148 | return wbkgd(stdscr, ch); | ||
149 | } | ||
150 | |||
151 | void 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 | |||
164 | void bkgdset(chtype ch) | ||
165 | { | ||
166 | PDC_LOG(("bkgdset() - called\n")); | ||
167 | |||
168 | wbkgdset(stdscr, ch); | ||
169 | } | ||
170 | |||
171 | chtype getbkgd(WINDOW *win) | ||
172 | { | ||
173 | PDC_LOG(("getbkgd() - called\n")); | ||
174 | |||
175 | return win ? win->_bkgd : (chtype)ERR; | ||
176 | } | ||
177 | |||
178 | #ifdef PDC_WIDE | ||
179 | int wbkgrnd(WINDOW *win, const cchar_t *wch) | ||
180 | { | ||
181 | PDC_LOG(("wbkgrnd() - called\n")); | ||
182 | |||
183 | return wch ? wbkgd(win, *wch) : ERR; | ||
184 | } | ||
185 | |||
186 | int bkgrnd(const cchar_t *wch) | ||
187 | { | ||
188 | PDC_LOG(("bkgrnd() - called\n")); | ||
189 | |||
190 | return wbkgrnd(stdscr, wch); | ||
191 | } | ||
192 | |||
193 | void wbkgrndset(WINDOW *win, const cchar_t *wch) | ||
194 | { | ||
195 | PDC_LOG(("wbkgdset() - called\n")); | ||
196 | |||
197 | if (wch) | ||
198 | wbkgdset(win, *wch); | ||
199 | } | ||
200 | |||
201 | void bkgrndset(const cchar_t *wch) | ||
202 | { | ||
203 | PDC_LOG(("bkgrndset() - called\n")); | ||
204 | |||
205 | wbkgrndset(stdscr, wch); | ||
206 | } | ||
207 | |||
208 | int 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 | |||
220 | int 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 | |||
7 | border | ||
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 | |||
108 | static 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 | |||
137 | int 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 | |||
187 | int 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 | |||
195 | int 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 | |||
202 | int 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 | |||
233 | int hline(chtype ch, int n) | ||
234 | { | ||
235 | PDC_LOG(("hline() - called\n")); | ||
236 | |||
237 | return whline(stdscr, ch, n); | ||
238 | } | ||
239 | |||
240 | int 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 | |||
250 | int 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 | |||
260 | int 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 | |||
290 | int vline(chtype ch, int n) | ||
291 | { | ||
292 | PDC_LOG(("vline() - called\n")); | ||
293 | |||
294 | return wvline(stdscr, ch, n); | ||
295 | } | ||
296 | |||
297 | int 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 | |||
307 | int 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 | ||
318 | int 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 | |||
329 | int 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 | |||
338 | int 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 | |||
347 | int 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 | |||
354 | int 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 | |||
361 | int 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 | |||
371 | int 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 | |||
381 | int 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 | |||
388 | int 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 | |||
395 | int 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 | |||
405 | int 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 | |||
7 | clear | ||
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 | |||
53 | int 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 | |||
83 | int clrtoeol(void) | ||
84 | { | ||
85 | PDC_LOG(("clrtoeol() - called\n")); | ||
86 | |||
87 | return wclrtoeol(stdscr); | ||
88 | } | ||
89 | |||
90 | int 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 | |||
119 | int clrtobot(void) | ||
120 | { | ||
121 | PDC_LOG(("clrtobot() - called\n")); | ||
122 | |||
123 | return wclrtobot(stdscr); | ||
124 | } | ||
125 | |||
126 | int 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 | |||
136 | int erase(void) | ||
137 | { | ||
138 | PDC_LOG(("erase() - called\n")); | ||
139 | |||
140 | return werase(stdscr); | ||
141 | } | ||
142 | |||
143 | int 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 | |||
154 | int 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 | |||
7 | color | ||
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 | |||
115 | int COLORS = 0; | ||
116 | int COLOR_PAIRS = PDC_COLOR_PAIRS; | ||
117 | |||
118 | static bool default_colors = FALSE; | ||
119 | static short first_col = 0; | ||
120 | static int allocnum = 0; | ||
121 | |||
122 | int 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 | |||
141 | static 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 | |||
150 | static 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 | |||
172 | int 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 | |||
185 | bool has_colors(void) | ||
186 | { | ||
187 | PDC_LOG(("has_colors() - called\n")); | ||
188 | |||
189 | return SP ? !(SP->mono) : FALSE; | ||
190 | } | ||
191 | |||
192 | int 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 | |||
206 | int 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 | |||
230 | bool can_change_color(void) | ||
231 | { | ||
232 | PDC_LOG(("can_change_color() - called\n")); | ||
233 | |||
234 | return PDC_can_change_color(); | ||
235 | } | ||
236 | |||
237 | int 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 | |||
250 | int 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 | |||
263 | int 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 | |||
273 | int 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 | |||
285 | void 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 | |||
308 | int 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 | |||
317 | int 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 | |||
329 | static 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 | |||
349 | int 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 | |||
10 | Define 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 | |||
20 | Defined 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 | ||
61 | extern "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) | ||
87 | typedef unsigned char bool; | ||
88 | #endif | ||
89 | |||
90 | #if _LP64 | ||
91 | typedef unsigned int chtype; | ||
92 | #else | ||
93 | typedef unsigned long chtype; /* 16-bit attr + 16-bit char */ | ||
94 | #endif | ||
95 | |||
96 | #ifdef PDC_WIDE | ||
97 | typedef chtype cchar_t; | ||
98 | #endif | ||
99 | |||
100 | typedef 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 | |||
111 | typedef 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 | |||
121 | enum | ||
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 | ||
137 | typedef unsigned int mmask_t; | ||
138 | #else | ||
139 | typedef unsigned long mmask_t; | ||
140 | #endif | ||
141 | |||
142 | typedef 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 | |||
248 | typedef 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 | |||
277 | typedef 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 | |||
318 | typedef 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 | |||
329 | typedef 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 | |||
404 | PDCEX int LINES; /* terminal height */ | ||
405 | PDCEX int COLS; /* terminal width */ | ||
406 | PDCEX WINDOW *stdscr; /* the default screen window */ | ||
407 | PDCEX WINDOW *curscr; /* the current screen image */ | ||
408 | PDCEX SCREEN *SP; /* curses variables */ | ||
409 | PDCEX MOUSE_STATUS Mouse_status; | ||
410 | PDCEX int COLORS; | ||
411 | PDCEX int COLOR_PAIRS; | ||
412 | PDCEX int TABSIZE; | ||
413 | PDCEX chtype acs_map[]; /* alternate character set map */ | ||
414 | PDCEX char ttytype[]; /* terminal name/description */ | ||
415 | |||
416 | /*man-start************************************************************** | ||
417 | |||
418 | Text Attributes | ||
419 | =============== | ||
420 | |||
421 | PDCurses 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 | |||
428 | There are 256 color pairs (8 bits), 8 bits for modifiers, and 16 bits | ||
429 | for character data. The modifiers are bold, underline, right-line, | ||
430 | left-line, italic, reverse and blink, plus the alternate character set | ||
431 | indicator. | ||
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 | |||
897 | PDCEX int addch(const chtype); | ||
898 | PDCEX int addchnstr(const chtype *, int); | ||
899 | PDCEX int addchstr(const chtype *); | ||
900 | PDCEX int addnstr(const char *, int); | ||
901 | PDCEX int addstr(const char *); | ||
902 | PDCEX int attroff(chtype); | ||
903 | PDCEX int attron(chtype); | ||
904 | PDCEX int attrset(chtype); | ||
905 | PDCEX int attr_get(attr_t *, short *, void *); | ||
906 | PDCEX int attr_off(attr_t, void *); | ||
907 | PDCEX int attr_on(attr_t, void *); | ||
908 | PDCEX int attr_set(attr_t, short, void *); | ||
909 | PDCEX int baudrate(void); | ||
910 | PDCEX int beep(void); | ||
911 | PDCEX int bkgd(chtype); | ||
912 | PDCEX void bkgdset(chtype); | ||
913 | PDCEX int border(chtype, chtype, chtype, chtype, | ||
914 | chtype, chtype, chtype, chtype); | ||
915 | PDCEX int box(WINDOW *, chtype, chtype); | ||
916 | PDCEX bool can_change_color(void); | ||
917 | PDCEX int cbreak(void); | ||
918 | PDCEX int chgat(int, attr_t, short, const void *); | ||
919 | PDCEX int clearok(WINDOW *, bool); | ||
920 | PDCEX int clear(void); | ||
921 | PDCEX int clrtobot(void); | ||
922 | PDCEX int clrtoeol(void); | ||
923 | PDCEX int color_content(short, short *, short *, short *); | ||
924 | PDCEX int color_set(short, void *); | ||
925 | PDCEX int copywin(const WINDOW *, WINDOW *, int, int, int, | ||
926 | int, int, int, int); | ||
927 | PDCEX int curs_set(int); | ||
928 | PDCEX int def_prog_mode(void); | ||
929 | PDCEX int def_shell_mode(void); | ||
930 | PDCEX int delay_output(int); | ||
931 | PDCEX int delch(void); | ||
932 | PDCEX int deleteln(void); | ||
933 | PDCEX void delscreen(SCREEN *); | ||
934 | PDCEX int delwin(WINDOW *); | ||
935 | PDCEX WINDOW *derwin(WINDOW *, int, int, int, int); | ||
936 | PDCEX int doupdate(void); | ||
937 | PDCEX WINDOW *dupwin(WINDOW *); | ||
938 | PDCEX int echochar(const chtype); | ||
939 | PDCEX int echo(void); | ||
940 | PDCEX int endwin(void); | ||
941 | PDCEX char erasechar(void); | ||
942 | PDCEX int erase(void); | ||
943 | PDCEX void filter(void); | ||
944 | PDCEX int flash(void); | ||
945 | PDCEX int flushinp(void); | ||
946 | PDCEX chtype getbkgd(WINDOW *); | ||
947 | PDCEX int getnstr(char *, int); | ||
948 | PDCEX int getstr(char *); | ||
949 | PDCEX WINDOW *getwin(FILE *); | ||
950 | PDCEX int halfdelay(int); | ||
951 | PDCEX bool has_colors(void); | ||
952 | PDCEX bool has_ic(void); | ||
953 | PDCEX bool has_il(void); | ||
954 | PDCEX int hline(chtype, int); | ||
955 | PDCEX void idcok(WINDOW *, bool); | ||
956 | PDCEX int idlok(WINDOW *, bool); | ||
957 | PDCEX void immedok(WINDOW *, bool); | ||
958 | PDCEX int inchnstr(chtype *, int); | ||
959 | PDCEX int inchstr(chtype *); | ||
960 | PDCEX chtype inch(void); | ||
961 | PDCEX int init_color(short, short, short, short); | ||
962 | PDCEX int init_pair(short, short, short); | ||
963 | PDCEX WINDOW *initscr(void); | ||
964 | PDCEX int innstr(char *, int); | ||
965 | PDCEX int insch(chtype); | ||
966 | PDCEX int insdelln(int); | ||
967 | PDCEX int insertln(void); | ||
968 | PDCEX int insnstr(const char *, int); | ||
969 | PDCEX int insstr(const char *); | ||
970 | PDCEX int instr(char *); | ||
971 | PDCEX int intrflush(WINDOW *, bool); | ||
972 | PDCEX bool isendwin(void); | ||
973 | PDCEX bool is_linetouched(WINDOW *, int); | ||
974 | PDCEX bool is_wintouched(WINDOW *); | ||
975 | PDCEX char *keyname(int); | ||
976 | PDCEX int keypad(WINDOW *, bool); | ||
977 | PDCEX char killchar(void); | ||
978 | PDCEX int leaveok(WINDOW *, bool); | ||
979 | PDCEX char *longname(void); | ||
980 | PDCEX int meta(WINDOW *, bool); | ||
981 | PDCEX int move(int, int); | ||
982 | PDCEX int mvaddch(int, int, const chtype); | ||
983 | PDCEX int mvaddchnstr(int, int, const chtype *, int); | ||
984 | PDCEX int mvaddchstr(int, int, const chtype *); | ||
985 | PDCEX int mvaddnstr(int, int, const char *, int); | ||
986 | PDCEX int mvaddstr(int, int, const char *); | ||
987 | PDCEX int mvchgat(int, int, int, attr_t, short, const void *); | ||
988 | PDCEX int mvcur(int, int, int, int); | ||
989 | PDCEX int mvdelch(int, int); | ||
990 | PDCEX int mvderwin(WINDOW *, int, int); | ||
991 | PDCEX int mvgetch(int, int); | ||
992 | PDCEX int mvgetnstr(int, int, char *, int); | ||
993 | PDCEX int mvgetstr(int, int, char *); | ||
994 | PDCEX int mvhline(int, int, chtype, int); | ||
995 | PDCEX chtype mvinch(int, int); | ||
996 | PDCEX int mvinchnstr(int, int, chtype *, int); | ||
997 | PDCEX int mvinchstr(int, int, chtype *); | ||
998 | PDCEX int mvinnstr(int, int, char *, int); | ||
999 | PDCEX int mvinsch(int, int, chtype); | ||
1000 | PDCEX int mvinsnstr(int, int, const char *, int); | ||
1001 | PDCEX int mvinsstr(int, int, const char *); | ||
1002 | PDCEX int mvinstr(int, int, char *); | ||
1003 | PDCEX int mvprintw(int, int, const char *, ...); | ||
1004 | PDCEX int mvscanw(int, int, const char *, ...); | ||
1005 | PDCEX int mvvline(int, int, chtype, int); | ||
1006 | PDCEX int mvwaddchnstr(WINDOW *, int, int, const chtype *, int); | ||
1007 | PDCEX int mvwaddchstr(WINDOW *, int, int, const chtype *); | ||
1008 | PDCEX int mvwaddch(WINDOW *, int, int, const chtype); | ||
1009 | PDCEX int mvwaddnstr(WINDOW *, int, int, const char *, int); | ||
1010 | PDCEX int mvwaddstr(WINDOW *, int, int, const char *); | ||
1011 | PDCEX int mvwchgat(WINDOW *, int, int, int, attr_t, short, const void *); | ||
1012 | PDCEX int mvwdelch(WINDOW *, int, int); | ||
1013 | PDCEX int mvwgetch(WINDOW *, int, int); | ||
1014 | PDCEX int mvwgetnstr(WINDOW *, int, int, char *, int); | ||
1015 | PDCEX int mvwgetstr(WINDOW *, int, int, char *); | ||
1016 | PDCEX int mvwhline(WINDOW *, int, int, chtype, int); | ||
1017 | PDCEX int mvwinchnstr(WINDOW *, int, int, chtype *, int); | ||
1018 | PDCEX int mvwinchstr(WINDOW *, int, int, chtype *); | ||
1019 | PDCEX chtype mvwinch(WINDOW *, int, int); | ||
1020 | PDCEX int mvwinnstr(WINDOW *, int, int, char *, int); | ||
1021 | PDCEX int mvwinsch(WINDOW *, int, int, chtype); | ||
1022 | PDCEX int mvwinsnstr(WINDOW *, int, int, const char *, int); | ||
1023 | PDCEX int mvwinsstr(WINDOW *, int, int, const char *); | ||
1024 | PDCEX int mvwinstr(WINDOW *, int, int, char *); | ||
1025 | PDCEX int mvwin(WINDOW *, int, int); | ||
1026 | PDCEX int mvwprintw(WINDOW *, int, int, const char *, ...); | ||
1027 | PDCEX int mvwscanw(WINDOW *, int, int, const char *, ...); | ||
1028 | PDCEX int mvwvline(WINDOW *, int, int, chtype, int); | ||
1029 | PDCEX int napms(int); | ||
1030 | PDCEX WINDOW *newpad(int, int); | ||
1031 | PDCEX SCREEN *newterm(const char *, FILE *, FILE *); | ||
1032 | PDCEX WINDOW *newwin(int, int, int, int); | ||
1033 | PDCEX int nl(void); | ||
1034 | PDCEX int nocbreak(void); | ||
1035 | PDCEX int nodelay(WINDOW *, bool); | ||
1036 | PDCEX int noecho(void); | ||
1037 | PDCEX int nonl(void); | ||
1038 | PDCEX void noqiflush(void); | ||
1039 | PDCEX int noraw(void); | ||
1040 | PDCEX int notimeout(WINDOW *, bool); | ||
1041 | PDCEX int overlay(const WINDOW *, WINDOW *); | ||
1042 | PDCEX int overwrite(const WINDOW *, WINDOW *); | ||
1043 | PDCEX int pair_content(short, short *, short *); | ||
1044 | PDCEX int pechochar(WINDOW *, chtype); | ||
1045 | PDCEX int pnoutrefresh(WINDOW *, int, int, int, int, int, int); | ||
1046 | PDCEX int prefresh(WINDOW *, int, int, int, int, int, int); | ||
1047 | PDCEX int printw(const char *, ...); | ||
1048 | PDCEX int putwin(WINDOW *, FILE *); | ||
1049 | PDCEX void qiflush(void); | ||
1050 | PDCEX int raw(void); | ||
1051 | PDCEX int redrawwin(WINDOW *); | ||
1052 | PDCEX int refresh(void); | ||
1053 | PDCEX int reset_prog_mode(void); | ||
1054 | PDCEX int reset_shell_mode(void); | ||
1055 | PDCEX int resetty(void); | ||
1056 | PDCEX int ripoffline(int, int (*)(WINDOW *, int)); | ||
1057 | PDCEX int savetty(void); | ||
1058 | PDCEX int scanw(const char *, ...); | ||
1059 | PDCEX int scr_dump(const char *); | ||
1060 | PDCEX int scr_init(const char *); | ||
1061 | PDCEX int scr_restore(const char *); | ||
1062 | PDCEX int scr_set(const char *); | ||
1063 | PDCEX int scrl(int); | ||
1064 | PDCEX int scroll(WINDOW *); | ||
1065 | PDCEX int scrollok(WINDOW *, bool); | ||
1066 | PDCEX SCREEN *set_term(SCREEN *); | ||
1067 | PDCEX int setscrreg(int, int); | ||
1068 | PDCEX int slk_attroff(const chtype); | ||
1069 | PDCEX int slk_attr_off(const attr_t, void *); | ||
1070 | PDCEX int slk_attron(const chtype); | ||
1071 | PDCEX int slk_attr_on(const attr_t, void *); | ||
1072 | PDCEX int slk_attrset(const chtype); | ||
1073 | PDCEX int slk_attr_set(const attr_t, short, void *); | ||
1074 | PDCEX int slk_clear(void); | ||
1075 | PDCEX int slk_color(short); | ||
1076 | PDCEX int slk_init(int); | ||
1077 | PDCEX char *slk_label(int); | ||
1078 | PDCEX int slk_noutrefresh(void); | ||
1079 | PDCEX int slk_refresh(void); | ||
1080 | PDCEX int slk_restore(void); | ||
1081 | PDCEX int slk_set(int, const char *, int); | ||
1082 | PDCEX int slk_touch(void); | ||
1083 | PDCEX int standend(void); | ||
1084 | PDCEX int standout(void); | ||
1085 | PDCEX int start_color(void); | ||
1086 | PDCEX WINDOW *subpad(WINDOW *, int, int, int, int); | ||
1087 | PDCEX WINDOW *subwin(WINDOW *, int, int, int, int); | ||
1088 | PDCEX int syncok(WINDOW *, bool); | ||
1089 | PDCEX chtype termattrs(void); | ||
1090 | PDCEX attr_t term_attrs(void); | ||
1091 | PDCEX char *termname(void); | ||
1092 | PDCEX void timeout(int); | ||
1093 | PDCEX int touchline(WINDOW *, int, int); | ||
1094 | PDCEX int touchwin(WINDOW *); | ||
1095 | PDCEX int typeahead(int); | ||
1096 | PDCEX int untouchwin(WINDOW *); | ||
1097 | PDCEX void use_env(bool); | ||
1098 | PDCEX int vidattr(chtype); | ||
1099 | PDCEX int vid_attr(attr_t, short, void *); | ||
1100 | PDCEX int vidputs(chtype, int (*)(int)); | ||
1101 | PDCEX int vid_puts(attr_t, short, void *, int (*)(int)); | ||
1102 | PDCEX int vline(chtype, int); | ||
1103 | PDCEX int vw_printw(WINDOW *, const char *, va_list); | ||
1104 | PDCEX int vwprintw(WINDOW *, const char *, va_list); | ||
1105 | PDCEX int vw_scanw(WINDOW *, const char *, va_list); | ||
1106 | PDCEX int vwscanw(WINDOW *, const char *, va_list); | ||
1107 | PDCEX int waddchnstr(WINDOW *, const chtype *, int); | ||
1108 | PDCEX int waddchstr(WINDOW *, const chtype *); | ||
1109 | PDCEX int waddch(WINDOW *, const chtype); | ||
1110 | PDCEX int waddnstr(WINDOW *, const char *, int); | ||
1111 | PDCEX int waddstr(WINDOW *, const char *); | ||
1112 | PDCEX int wattroff(WINDOW *, chtype); | ||
1113 | PDCEX int wattron(WINDOW *, chtype); | ||
1114 | PDCEX int wattrset(WINDOW *, chtype); | ||
1115 | PDCEX int wattr_get(WINDOW *, attr_t *, short *, void *); | ||
1116 | PDCEX int wattr_off(WINDOW *, attr_t, void *); | ||
1117 | PDCEX int wattr_on(WINDOW *, attr_t, void *); | ||
1118 | PDCEX int wattr_set(WINDOW *, attr_t, short, void *); | ||
1119 | PDCEX void wbkgdset(WINDOW *, chtype); | ||
1120 | PDCEX int wbkgd(WINDOW *, chtype); | ||
1121 | PDCEX int wborder(WINDOW *, chtype, chtype, chtype, chtype, | ||
1122 | chtype, chtype, chtype, chtype); | ||
1123 | PDCEX int wchgat(WINDOW *, int, attr_t, short, const void *); | ||
1124 | PDCEX int wclear(WINDOW *); | ||
1125 | PDCEX int wclrtobot(WINDOW *); | ||
1126 | PDCEX int wclrtoeol(WINDOW *); | ||
1127 | PDCEX int wcolor_set(WINDOW *, short, void *); | ||
1128 | PDCEX void wcursyncup(WINDOW *); | ||
1129 | PDCEX int wdelch(WINDOW *); | ||
1130 | PDCEX int wdeleteln(WINDOW *); | ||
1131 | PDCEX int wechochar(WINDOW *, const chtype); | ||
1132 | PDCEX int werase(WINDOW *); | ||
1133 | PDCEX int wgetch(WINDOW *); | ||
1134 | PDCEX int wgetnstr(WINDOW *, char *, int); | ||
1135 | PDCEX int wgetstr(WINDOW *, char *); | ||
1136 | PDCEX int whline(WINDOW *, chtype, int); | ||
1137 | PDCEX int winchnstr(WINDOW *, chtype *, int); | ||
1138 | PDCEX int winchstr(WINDOW *, chtype *); | ||
1139 | PDCEX chtype winch(WINDOW *); | ||
1140 | PDCEX int winnstr(WINDOW *, char *, int); | ||
1141 | PDCEX int winsch(WINDOW *, chtype); | ||
1142 | PDCEX int winsdelln(WINDOW *, int); | ||
1143 | PDCEX int winsertln(WINDOW *); | ||
1144 | PDCEX int winsnstr(WINDOW *, const char *, int); | ||
1145 | PDCEX int winsstr(WINDOW *, const char *); | ||
1146 | PDCEX int winstr(WINDOW *, char *); | ||
1147 | PDCEX int wmove(WINDOW *, int, int); | ||
1148 | PDCEX int wnoutrefresh(WINDOW *); | ||
1149 | PDCEX int wprintw(WINDOW *, const char *, ...); | ||
1150 | PDCEX int wredrawln(WINDOW *, int, int); | ||
1151 | PDCEX int wrefresh(WINDOW *); | ||
1152 | PDCEX int wscanw(WINDOW *, const char *, ...); | ||
1153 | PDCEX int wscrl(WINDOW *, int); | ||
1154 | PDCEX int wsetscrreg(WINDOW *, int, int); | ||
1155 | PDCEX int wstandend(WINDOW *); | ||
1156 | PDCEX int wstandout(WINDOW *); | ||
1157 | PDCEX void wsyncdown(WINDOW *); | ||
1158 | PDCEX void wsyncup(WINDOW *); | ||
1159 | PDCEX void wtimeout(WINDOW *, int); | ||
1160 | PDCEX int wtouchln(WINDOW *, int, int, int); | ||
1161 | PDCEX int wvline(WINDOW *, chtype, int); | ||
1162 | |||
1163 | /* Wide-character functions */ | ||
1164 | |||
1165 | #ifdef PDC_WIDE | ||
1166 | PDCEX int addnwstr(const wchar_t *, int); | ||
1167 | PDCEX int addwstr(const wchar_t *); | ||
1168 | PDCEX int add_wch(const cchar_t *); | ||
1169 | PDCEX int add_wchnstr(const cchar_t *, int); | ||
1170 | PDCEX int add_wchstr(const cchar_t *); | ||
1171 | PDCEX int bkgrnd(const cchar_t *); | ||
1172 | PDCEX void bkgrndset(const cchar_t *); | ||
1173 | PDCEX 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 *); | ||
1176 | PDCEX int box_set(WINDOW *, const cchar_t *, const cchar_t *); | ||
1177 | PDCEX int echo_wchar(const cchar_t *); | ||
1178 | PDCEX int erasewchar(wchar_t *); | ||
1179 | PDCEX int getbkgrnd(cchar_t *); | ||
1180 | PDCEX int getcchar(const cchar_t *, wchar_t *, attr_t *, short *, void *); | ||
1181 | PDCEX int getn_wstr(wint_t *, int); | ||
1182 | PDCEX int get_wch(wint_t *); | ||
1183 | PDCEX int get_wstr(wint_t *); | ||
1184 | PDCEX int hline_set(const cchar_t *, int); | ||
1185 | PDCEX int innwstr(wchar_t *, int); | ||
1186 | PDCEX int ins_nwstr(const wchar_t *, int); | ||
1187 | PDCEX int ins_wch(const cchar_t *); | ||
1188 | PDCEX int ins_wstr(const wchar_t *); | ||
1189 | PDCEX int inwstr(wchar_t *); | ||
1190 | PDCEX int in_wch(cchar_t *); | ||
1191 | PDCEX int in_wchnstr(cchar_t *, int); | ||
1192 | PDCEX int in_wchstr(cchar_t *); | ||
1193 | PDCEX char *key_name(wchar_t); | ||
1194 | PDCEX int killwchar(wchar_t *); | ||
1195 | PDCEX int mvaddnwstr(int, int, const wchar_t *, int); | ||
1196 | PDCEX int mvaddwstr(int, int, const wchar_t *); | ||
1197 | PDCEX int mvadd_wch(int, int, const cchar_t *); | ||
1198 | PDCEX int mvadd_wchnstr(int, int, const cchar_t *, int); | ||
1199 | PDCEX int mvadd_wchstr(int, int, const cchar_t *); | ||
1200 | PDCEX int mvgetn_wstr(int, int, wint_t *, int); | ||
1201 | PDCEX int mvget_wch(int, int, wint_t *); | ||
1202 | PDCEX int mvget_wstr(int, int, wint_t *); | ||
1203 | PDCEX int mvhline_set(int, int, const cchar_t *, int); | ||
1204 | PDCEX int mvinnwstr(int, int, wchar_t *, int); | ||
1205 | PDCEX int mvins_nwstr(int, int, const wchar_t *, int); | ||
1206 | PDCEX int mvins_wch(int, int, const cchar_t *); | ||
1207 | PDCEX int mvins_wstr(int, int, const wchar_t *); | ||
1208 | PDCEX int mvinwstr(int, int, wchar_t *); | ||
1209 | PDCEX int mvin_wch(int, int, cchar_t *); | ||
1210 | PDCEX int mvin_wchnstr(int, int, cchar_t *, int); | ||
1211 | PDCEX int mvin_wchstr(int, int, cchar_t *); | ||
1212 | PDCEX int mvvline_set(int, int, const cchar_t *, int); | ||
1213 | PDCEX int mvwaddnwstr(WINDOW *, int, int, const wchar_t *, int); | ||
1214 | PDCEX int mvwaddwstr(WINDOW *, int, int, const wchar_t *); | ||
1215 | PDCEX int mvwadd_wch(WINDOW *, int, int, const cchar_t *); | ||
1216 | PDCEX int mvwadd_wchnstr(WINDOW *, int, int, const cchar_t *, int); | ||
1217 | PDCEX int mvwadd_wchstr(WINDOW *, int, int, const cchar_t *); | ||
1218 | PDCEX int mvwgetn_wstr(WINDOW *, int, int, wint_t *, int); | ||
1219 | PDCEX int mvwget_wch(WINDOW *, int, int, wint_t *); | ||
1220 | PDCEX int mvwget_wstr(WINDOW *, int, int, wint_t *); | ||
1221 | PDCEX int mvwhline_set(WINDOW *, int, int, const cchar_t *, int); | ||
1222 | PDCEX int mvwinnwstr(WINDOW *, int, int, wchar_t *, int); | ||
1223 | PDCEX int mvwins_nwstr(WINDOW *, int, int, const wchar_t *, int); | ||
1224 | PDCEX int mvwins_wch(WINDOW *, int, int, const cchar_t *); | ||
1225 | PDCEX int mvwins_wstr(WINDOW *, int, int, const wchar_t *); | ||
1226 | PDCEX int mvwin_wch(WINDOW *, int, int, cchar_t *); | ||
1227 | PDCEX int mvwin_wchnstr(WINDOW *, int, int, cchar_t *, int); | ||
1228 | PDCEX int mvwin_wchstr(WINDOW *, int, int, cchar_t *); | ||
1229 | PDCEX int mvwinwstr(WINDOW *, int, int, wchar_t *); | ||
1230 | PDCEX int mvwvline_set(WINDOW *, int, int, const cchar_t *, int); | ||
1231 | PDCEX int pecho_wchar(WINDOW *, const cchar_t*); | ||
1232 | PDCEX int setcchar(cchar_t*, const wchar_t*, const attr_t, | ||
1233 | short, const void*); | ||
1234 | PDCEX int slk_wset(int, const wchar_t *, int); | ||
1235 | PDCEX int unget_wch(const wchar_t); | ||
1236 | PDCEX int vline_set(const cchar_t *, int); | ||
1237 | PDCEX int waddnwstr(WINDOW *, const wchar_t *, int); | ||
1238 | PDCEX int waddwstr(WINDOW *, const wchar_t *); | ||
1239 | PDCEX int wadd_wch(WINDOW *, const cchar_t *); | ||
1240 | PDCEX int wadd_wchnstr(WINDOW *, const cchar_t *, int); | ||
1241 | PDCEX int wadd_wchstr(WINDOW *, const cchar_t *); | ||
1242 | PDCEX int wbkgrnd(WINDOW *, const cchar_t *); | ||
1243 | PDCEX void wbkgrndset(WINDOW *, const cchar_t *); | ||
1244 | PDCEX 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 *); | ||
1247 | PDCEX int wecho_wchar(WINDOW *, const cchar_t *); | ||
1248 | PDCEX int wgetbkgrnd(WINDOW *, cchar_t *); | ||
1249 | PDCEX int wgetn_wstr(WINDOW *, wint_t *, int); | ||
1250 | PDCEX int wget_wch(WINDOW *, wint_t *); | ||
1251 | PDCEX int wget_wstr(WINDOW *, wint_t *); | ||
1252 | PDCEX int whline_set(WINDOW *, const cchar_t *, int); | ||
1253 | PDCEX int winnwstr(WINDOW *, wchar_t *, int); | ||
1254 | PDCEX int wins_nwstr(WINDOW *, const wchar_t *, int); | ||
1255 | PDCEX int wins_wch(WINDOW *, const cchar_t *); | ||
1256 | PDCEX int wins_wstr(WINDOW *, const wchar_t *); | ||
1257 | PDCEX int winwstr(WINDOW *, wchar_t *); | ||
1258 | PDCEX int win_wch(WINDOW *, cchar_t *); | ||
1259 | PDCEX int win_wchnstr(WINDOW *, cchar_t *, int); | ||
1260 | PDCEX int win_wchstr(WINDOW *, cchar_t *); | ||
1261 | PDCEX wchar_t *wunctrl(cchar_t *); | ||
1262 | PDCEX int wvline_set(WINDOW *, const cchar_t *, int); | ||
1263 | #endif | ||
1264 | |||
1265 | /* Quasi-standard */ | ||
1266 | |||
1267 | PDCEX chtype getattrs(WINDOW *); | ||
1268 | PDCEX int getbegx(WINDOW *); | ||
1269 | PDCEX int getbegy(WINDOW *); | ||
1270 | PDCEX int getmaxx(WINDOW *); | ||
1271 | PDCEX int getmaxy(WINDOW *); | ||
1272 | PDCEX int getparx(WINDOW *); | ||
1273 | PDCEX int getpary(WINDOW *); | ||
1274 | PDCEX int getcurx(WINDOW *); | ||
1275 | PDCEX int getcury(WINDOW *); | ||
1276 | PDCEX void traceoff(void); | ||
1277 | PDCEX void traceon(void); | ||
1278 | PDCEX char *unctrl(chtype); | ||
1279 | |||
1280 | PDCEX int crmode(void); | ||
1281 | PDCEX int nocrmode(void); | ||
1282 | PDCEX int draino(int); | ||
1283 | PDCEX int resetterm(void); | ||
1284 | PDCEX int fixterm(void); | ||
1285 | PDCEX int saveterm(void); | ||
1286 | PDCEX void setsyx(int, int); | ||
1287 | |||
1288 | PDCEX int mouse_set(mmask_t); | ||
1289 | PDCEX int mouse_on(mmask_t); | ||
1290 | PDCEX int mouse_off(mmask_t); | ||
1291 | PDCEX int request_mouse_pos(void); | ||
1292 | PDCEX void wmouse_position(WINDOW *, int *, int *); | ||
1293 | PDCEX mmask_t getmouse(void); | ||
1294 | |||
1295 | /* ncurses */ | ||
1296 | |||
1297 | PDCEX int alloc_pair(int, int); | ||
1298 | PDCEX int assume_default_colors(int, int); | ||
1299 | PDCEX const char *curses_version(void); | ||
1300 | PDCEX int find_pair(int, int); | ||
1301 | PDCEX int free_pair(int); | ||
1302 | PDCEX bool has_key(int); | ||
1303 | PDCEX bool is_cleared(const WINDOW *); | ||
1304 | PDCEX bool is_idcok(const WINDOW *); | ||
1305 | PDCEX bool is_idlok(const WINDOW *); | ||
1306 | PDCEX bool is_immedok(const WINDOW *); | ||
1307 | PDCEX bool is_keypad(const WINDOW *); | ||
1308 | PDCEX bool is_leaveok(const WINDOW *); | ||
1309 | PDCEX bool is_nodelay(const WINDOW *); | ||
1310 | PDCEX bool is_notimeout(const WINDOW *); | ||
1311 | PDCEX bool is_pad(const WINDOW *); | ||
1312 | PDCEX bool is_scrollok(const WINDOW *); | ||
1313 | PDCEX bool is_subwin(const WINDOW *); | ||
1314 | PDCEX bool is_syncok(const WINDOW *); | ||
1315 | PDCEX int set_tabsize(int); | ||
1316 | PDCEX int use_default_colors(void); | ||
1317 | PDCEX int wgetdelay(const WINDOW *); | ||
1318 | PDCEX WINDOW *wgetparent(const WINDOW *); | ||
1319 | PDCEX int wgetscrreg(const WINDOW *, int *, int *); | ||
1320 | PDCEX int wresize(WINDOW *, int, int); | ||
1321 | |||
1322 | PDCEX bool has_mouse(void); | ||
1323 | PDCEX int mouseinterval(int); | ||
1324 | PDCEX mmask_t mousemask(mmask_t, mmask_t *); | ||
1325 | PDCEX bool mouse_trafo(int *, int *, bool); | ||
1326 | PDCEX int nc_getmouse(MEVENT *); | ||
1327 | PDCEX int ungetmouse(MEVENT *); | ||
1328 | PDCEX bool wenclose(const WINDOW *, int, int); | ||
1329 | PDCEX bool wmouse_trafo(const WINDOW *, int *, int *, bool); | ||
1330 | |||
1331 | /* PDCurses */ | ||
1332 | |||
1333 | PDCEX int addrawch(chtype); | ||
1334 | PDCEX int insrawch(chtype); | ||
1335 | PDCEX bool is_termresized(void); | ||
1336 | PDCEX int mvaddrawch(int, int, chtype); | ||
1337 | PDCEX int mvdeleteln(int, int); | ||
1338 | PDCEX int mvinsertln(int, int); | ||
1339 | PDCEX int mvinsrawch(int, int, chtype); | ||
1340 | PDCEX int mvwaddrawch(WINDOW *, int, int, chtype); | ||
1341 | PDCEX int mvwdeleteln(WINDOW *, int, int); | ||
1342 | PDCEX int mvwinsertln(WINDOW *, int, int); | ||
1343 | PDCEX int mvwinsrawch(WINDOW *, int, int, chtype); | ||
1344 | PDCEX int raw_output(bool); | ||
1345 | PDCEX int resize_term(int, int); | ||
1346 | PDCEX WINDOW *resize_window(WINDOW *, int, int); | ||
1347 | PDCEX int waddrawch(WINDOW *, chtype); | ||
1348 | PDCEX int winsrawch(WINDOW *, chtype); | ||
1349 | PDCEX char wordchar(void); | ||
1350 | |||
1351 | #ifdef PDC_WIDE | ||
1352 | PDCEX wchar_t *slk_wlabel(int); | ||
1353 | #endif | ||
1354 | |||
1355 | PDCEX void PDC_debug(const char *, ...); | ||
1356 | PDCEX void PDC_get_version(PDC_VERSION *); | ||
1357 | PDCEX int PDC_ungetch(int); | ||
1358 | PDCEX int PDC_set_blink(bool); | ||
1359 | PDCEX int PDC_set_bold(bool); | ||
1360 | PDCEX int PDC_set_line_color(short); | ||
1361 | PDCEX void PDC_set_title(const char *); | ||
1362 | |||
1363 | PDCEX int PDC_clearclipboard(void); | ||
1364 | PDCEX int PDC_freeclipboard(char *); | ||
1365 | PDCEX int PDC_getclipboard(char **, long *); | ||
1366 | PDCEX int PDC_setclipboard(const char *, long); | ||
1367 | |||
1368 | PDCEX unsigned long PDC_get_key_modifiers(void); | ||
1369 | PDCEX int PDC_return_key_modifiers(bool); | ||
1370 | |||
1371 | #ifdef XCURSES | ||
1372 | PDCEX WINDOW *Xinitscr(int, char **); | ||
1373 | PDCEX void XCursesExit(void); | ||
1374 | PDCEX int sb_init(void); | ||
1375 | PDCEX int sb_set_horz(int, int, int); | ||
1376 | PDCEX int sb_set_vert(int, int, int); | ||
1377 | PDCEX int sb_get_horz(int *, int *, int *); | ||
1378 | PDCEX int sb_get_vert(int *, int *, int *); | ||
1379 | PDCEX int sb_refresh(void); | ||
1380 | #endif | ||
1381 | |||
1382 | /* NetBSD */ | ||
1383 | |||
1384 | PDCEX int touchoverlap(const WINDOW *, WINDOW *); | ||
1385 | PDCEX int underend(void); | ||
1386 | PDCEX int underscore(void); | ||
1387 | PDCEX int wunderend(WINDOW *); | ||
1388 | PDCEX 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 | ||
11 | extern "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 | |||
32 | typedef 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 | |||
56 | void PDC_beep(void); | ||
57 | bool PDC_can_change_color(void); | ||
58 | int PDC_color_content(short, short *, short *, short *); | ||
59 | bool PDC_check_key(void); | ||
60 | int PDC_curs_set(int); | ||
61 | void PDC_doupdate(void); | ||
62 | void PDC_flushinp(void); | ||
63 | int PDC_get_columns(void); | ||
64 | int PDC_get_cursor_mode(void); | ||
65 | int PDC_get_key(void); | ||
66 | int PDC_get_rows(void); | ||
67 | void PDC_gotoyx(int, int); | ||
68 | bool PDC_has_mouse(void); | ||
69 | int PDC_init_color(short, short, short, short); | ||
70 | int PDC_modifiers_set(void); | ||
71 | int PDC_mouse_set(void); | ||
72 | void PDC_napms(int); | ||
73 | void PDC_reset_prog_mode(void); | ||
74 | void PDC_reset_shell_mode(void); | ||
75 | int PDC_resize_screen(int, int); | ||
76 | void PDC_restore_screen_mode(int); | ||
77 | void PDC_save_screen_mode(int); | ||
78 | #ifdef XCURSES | ||
79 | void PDC_set_args(int, char **); | ||
80 | #endif | ||
81 | void PDC_scr_close(void); | ||
82 | void PDC_scr_free(void); | ||
83 | int PDC_scr_open(void); | ||
84 | void PDC_set_keyboard_binary(bool); | ||
85 | void PDC_transform_line(int, int, int, const chtype *); | ||
86 | const char *PDC_sysname(void); | ||
87 | |||
88 | /* Internal cross-module functions */ | ||
89 | |||
90 | void PDC_init_atrtab(void); | ||
91 | WINDOW *PDC_makelines(WINDOW *); | ||
92 | WINDOW *PDC_makenew(int, int, int, int); | ||
93 | int PDC_mouse_in_slk(int, int); | ||
94 | void PDC_slk_free(void); | ||
95 | void PDC_slk_initialize(void); | ||
96 | void PDC_sync(WINDOW *); | ||
97 | |||
98 | #ifdef PDC_WIDE | ||
99 | int PDC_mbtowc(wchar_t *, const char *, size_t); | ||
100 | size_t PDC_mbstowcs(wchar_t *, const char *, size_t); | ||
101 | size_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 | |||
7 | getch | ||
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 | |||
96 | static 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 | |||
120 | static 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 | |||
137 | static 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 | |||
190 | static 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 | |||
230 | static 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 | |||
323 | int 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 | |||
469 | int 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 | |||
479 | int 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 | |||
489 | int 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 | |||
501 | int 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 | |||
517 | unsigned 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 | |||
527 | int 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 | ||
539 | int 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 | |||
558 | int get_wch(wint_t *wch) | ||
559 | { | ||
560 | PDC_LOG(("get_wch() - called\n")); | ||
561 | |||
562 | return wget_wch(stdscr, wch); | ||
563 | } | ||
564 | |||
565 | int 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 | |||
575 | int 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 | |||
585 | int 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 | |||
7 | getyx | ||
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 | |||
75 | int getbegy(WINDOW *win) | ||
76 | { | ||
77 | PDC_LOG(("getbegy() - called\n")); | ||
78 | |||
79 | return win ? win->_begy : ERR; | ||
80 | } | ||
81 | |||
82 | int getbegx(WINDOW *win) | ||
83 | { | ||
84 | PDC_LOG(("getbegx() - called\n")); | ||
85 | |||
86 | return win ? win->_begx : ERR; | ||
87 | } | ||
88 | |||
89 | int getcury(WINDOW *win) | ||
90 | { | ||
91 | PDC_LOG(("getcury() - called\n")); | ||
92 | |||
93 | return win ? win->_cury : ERR; | ||
94 | } | ||
95 | |||
96 | int getcurx(WINDOW *win) | ||
97 | { | ||
98 | PDC_LOG(("getcurx() - called\n")); | ||
99 | |||
100 | return win ? win->_curx : ERR; | ||
101 | } | ||
102 | |||
103 | int getpary(WINDOW *win) | ||
104 | { | ||
105 | PDC_LOG(("getpary() - called\n")); | ||
106 | |||
107 | return win ? win->_pary : ERR; | ||
108 | } | ||
109 | |||
110 | int getparx(WINDOW *win) | ||
111 | { | ||
112 | PDC_LOG(("getparx() - called\n")); | ||
113 | |||
114 | return win ? win->_parx : ERR; | ||
115 | } | ||
116 | |||
117 | int getmaxy(WINDOW *win) | ||
118 | { | ||
119 | PDC_LOG(("getmaxy() - called\n")); | ||
120 | |||
121 | return win ? win->_maxy : ERR; | ||
122 | } | ||
123 | |||
124 | int getmaxx(WINDOW *win) | ||
125 | { | ||
126 | PDC_LOG(("getmaxx() - called\n")); | ||
127 | |||
128 | return win ? win->_maxx : ERR; | ||
129 | } | ||
130 | |||
131 | void 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 | |||
7 | inch | ||
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 | |||
46 | chtype 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 | |||
56 | chtype inch(void) | ||
57 | { | ||
58 | PDC_LOG(("inch() - called\n")); | ||
59 | |||
60 | return winch(stdscr); | ||
61 | } | ||
62 | |||
63 | chtype 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 | |||
73 | chtype 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 | ||
84 | int 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 | |||
96 | int in_wch(cchar_t *wcval) | ||
97 | { | ||
98 | PDC_LOG(("in_wch() - called\n")); | ||
99 | |||
100 | return win_wch(stdscr, wcval); | ||
101 | } | ||
102 | |||
103 | int 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 | |||
115 | int 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 | |||
7 | initscr | ||
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 | |||
102 | char ttytype[128]; | ||
103 | |||
104 | const char *_curses_notice = "PDCurses " PDC_VERDOT " - " __DATE__; | ||
105 | |||
106 | SCREEN *SP = (SCREEN*)NULL; /* curses variables */ | ||
107 | WINDOW *curscr = (WINDOW *)NULL; /* the current screen image */ | ||
108 | WINDOW *stdscr = (WINDOW *)NULL; /* the default screen window */ | ||
109 | |||
110 | int LINES = 0; /* current terminal height */ | ||
111 | int COLS = 0; /* current terminal width */ | ||
112 | int TABSIZE = 8; | ||
113 | |||
114 | MOUSE_STATUS Mouse_status; | ||
115 | |||
116 | extern RIPPEDOFFLINE linesripped[5]; | ||
117 | extern char linesrippedoff; | ||
118 | |||
119 | WINDOW *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 | ||
262 | WINDOW *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 | |||
271 | int 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 | |||
285 | bool isendwin(void) | ||
286 | { | ||
287 | PDC_LOG(("isendwin() - called\n")); | ||
288 | |||
289 | return SP ? !(SP->alive) : FALSE; | ||
290 | } | ||
291 | |||
292 | SCREEN *newterm(const char *type, FILE *outfd, FILE *infd) | ||
293 | { | ||
294 | PDC_LOG(("newterm() - called\n")); | ||
295 | |||
296 | return initscr() ? SP : NULL; | ||
297 | } | ||
298 | |||
299 | SCREEN *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 | |||
308 | void 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 | |||
336 | int 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 | |||
379 | bool is_termresized(void) | ||
380 | { | ||
381 | PDC_LOG(("is_termresized() - called\n")); | ||
382 | |||
383 | return SP->resized; | ||
384 | } | ||
385 | |||
386 | const char *curses_version(void) | ||
387 | { | ||
388 | return _curses_notice; | ||
389 | } | ||
390 | |||
391 | void 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 | |||
421 | int 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 | |||
7 | inopts | ||
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 | |||
138 | int 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 | |||
150 | int 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 | |||
163 | int 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 | |||
175 | int 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 | |||
187 | int 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 | |||
199 | int intrflush(WINDOW *win, bool bf) | ||
200 | { | ||
201 | PDC_LOG(("intrflush() - called\n")); | ||
202 | |||
203 | return OK; | ||
204 | } | ||
205 | |||
206 | int 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 | |||
218 | int 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 | |||
230 | int 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 | |||
242 | int 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 | |||
254 | int 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 | |||
266 | int notimeout(WINDOW *win, bool flag) | ||
267 | { | ||
268 | PDC_LOG(("notimeout() - called\n")); | ||
269 | |||
270 | return OK; | ||
271 | } | ||
272 | |||
273 | int 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 | |||
286 | int 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 | |||
299 | void noqiflush(void) | ||
300 | { | ||
301 | PDC_LOG(("noqiflush() - called\n")); | ||
302 | } | ||
303 | |||
304 | void qiflush(void) | ||
305 | { | ||
306 | PDC_LOG(("qiflush() - called\n")); | ||
307 | } | ||
308 | |||
309 | void timeout(int delay) | ||
310 | { | ||
311 | PDC_LOG(("timeout() - called\n")); | ||
312 | |||
313 | wtimeout(stdscr, delay); | ||
314 | } | ||
315 | |||
316 | void 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 | |||
350 | int 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 | |||
360 | int typeahead(int fildes) | ||
361 | { | ||
362 | PDC_LOG(("typeahead() - called\n")); | ||
363 | |||
364 | return OK; | ||
365 | } | ||
366 | |||
367 | int crmode(void) | ||
368 | { | ||
369 | PDC_LOG(("crmode() - called\n")); | ||
370 | |||
371 | return cbreak(); | ||
372 | } | ||
373 | |||
374 | int nocrmode(void) | ||
375 | { | ||
376 | PDC_LOG(("nocrmode() - called\n")); | ||
377 | |||
378 | return nocbreak(); | ||
379 | } | ||
380 | |||
381 | bool 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 | |||
391 | bool 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 | |||
401 | bool 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 | |||
7 | kernel | ||
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 | |||
93 | RIPPEDOFFLINE linesripped[5]; | ||
94 | char linesrippedoff = 0; | ||
95 | |||
96 | static struct cttyset | ||
97 | { | ||
98 | bool been_set; | ||
99 | SCREEN saved; | ||
100 | } ctty[3]; | ||
101 | |||
102 | enum { PDC_SH_TTY, PDC_PR_TTY, PDC_SAVE_TTY }; | ||
103 | |||
104 | static 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 | |||
113 | static 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 | |||
136 | int 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 | |||
148 | int 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 | |||
160 | int 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 | |||
173 | int 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 | |||
186 | int 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 | |||
196 | int 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 | |||
208 | int 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 | |||
228 | int 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 | |||
256 | int 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 | |||
271 | int draino(int ms) | ||
272 | { | ||
273 | PDC_LOG(("draino() - called\n")); | ||
274 | |||
275 | return napms(ms); | ||
276 | } | ||
277 | |||
278 | int resetterm(void) | ||
279 | { | ||
280 | PDC_LOG(("resetterm() - called\n")); | ||
281 | |||
282 | return reset_shell_mode(); | ||
283 | } | ||
284 | |||
285 | int fixterm(void) | ||
286 | { | ||
287 | PDC_LOG(("fixterm() - called\n")); | ||
288 | |||
289 | return reset_prog_mode(); | ||
290 | } | ||
291 | |||
292 | int 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 | |||
7 | move | ||
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 | |||
38 | int 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 | |||
51 | int 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 | |||
66 | int 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 | |||
7 | outopts | ||
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 | |||
98 | int 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 | |||
110 | int idlok(WINDOW *win, bool bf) | ||
111 | { | ||
112 | PDC_LOG(("idlok() - called\n")); | ||
113 | |||
114 | return OK; | ||
115 | } | ||
116 | |||
117 | void idcok(WINDOW *win, bool bf) | ||
118 | { | ||
119 | PDC_LOG(("idcok() - called\n")); | ||
120 | } | ||
121 | |||
122 | void immedok(WINDOW *win, bool bf) | ||
123 | { | ||
124 | PDC_LOG(("immedok() - called\n")); | ||
125 | |||
126 | if (win) | ||
127 | win->_immed = bf; | ||
128 | } | ||
129 | |||
130 | int 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 | |||
144 | int 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 | |||
151 | int 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 | |||
167 | int 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 | |||
180 | int 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 | |||
192 | int 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 | |||
204 | bool 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 | |||
214 | bool is_idlok(const WINDOW *win) | ||
215 | { | ||
216 | (void) win; | ||
217 | |||
218 | PDC_LOG(("is_idlok() - called\n")); | ||
219 | |||
220 | return FALSE; | ||
221 | } | ||
222 | |||
223 | bool is_idcok(const WINDOW *win) | ||
224 | { | ||
225 | (void) win; | ||
226 | |||
227 | PDC_LOG(("is_idcok() - called\n")); | ||
228 | |||
229 | return FALSE; | ||
230 | } | ||
231 | |||
232 | bool 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 | |||
242 | bool 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 | |||
252 | bool 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 | |||
7 | overlay | ||
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 | |||
52 | static 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 | |||
119 | int _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 | |||
174 | int 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 | |||
181 | int 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 | |||
188 | int 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 | |||
7 | pad | ||
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 | |||
78 | WINDOW *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 | |||
104 | WINDOW *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 | |||
155 | int 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 | |||
166 | int 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 | |||
242 | int 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 | ||
254 | int 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 | |||
266 | bool 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 | |||
9 | clipboard | ||
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 | |||
56 | int 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 | |||
96 | int 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 | |||
134 | int PDC_freeclipboard(char *contents) | ||
135 | { | ||
136 | PDC_LOG(("PDC_freeclipboard() - called\n")); | ||
137 | |||
138 | GlobalFree(contents); | ||
139 | return PDC_CLIP_SUCCESS; | ||
140 | } | ||
141 | |||
142 | int 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 | |||
14 | DWORD pdc_last_blink; | ||
15 | static bool blinked_off = FALSE; | ||
16 | static bool in_italic = FALSE; | ||
17 | |||
18 | /* position hardware cursor at (y, x) */ | ||
19 | |||
20 | void 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 | |||
33 | void _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 | |||
139 | void _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 | ||
206 | NONANSI: | ||
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 | |||
257 | void 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 | |||
283 | void 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 | |||
327 | void 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 | |||
7 | int 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 | |||
20 | int 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 | |||
33 | int 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 | |||
8 | static INPUT_RECORD save_ip; | ||
9 | static MOUSE_STATUS old_mouse_status; | ||
10 | static DWORD event_count = 0; | ||
11 | static SHORT left_key; | ||
12 | static int key_count = 0; | ||
13 | static 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 | |||
24 | typedef 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 | |||
33 | static 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 | |||
226 | static 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 | |||
246 | void 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 | |||
259 | bool 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 | |||
287 | static 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 | |||
362 | static 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 | |||
472 | static 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 | |||
610 | int 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 | |||
659 | void PDC_flushinp(void) | ||
660 | { | ||
661 | PDC_LOG(("PDC_flushinp() - called\n")); | ||
662 | |||
663 | FlushConsoleInputBuffer(pdc_con_in); | ||
664 | } | ||
665 | |||
666 | bool PDC_has_mouse(void) | ||
667 | { | ||
668 | return TRUE; | ||
669 | } | ||
670 | |||
671 | int 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 | |||
690 | int 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 | |||
9 | PDCCOLOR pdc_color[PDC_MAXCOL]; | ||
10 | |||
11 | HANDLE std_con_out = INVALID_HANDLE_VALUE; | ||
12 | HANDLE pdc_con_out = INVALID_HANDLE_VALUE; | ||
13 | HANDLE pdc_con_in = INVALID_HANDLE_VALUE; | ||
14 | |||
15 | DWORD pdc_quick_edit; | ||
16 | |||
17 | static 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 | |||
25 | static 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 | |||
33 | short pdc_curstoreal[16], pdc_curstoansi[16]; | ||
34 | short pdc_oldf, pdc_oldb, pdc_oldu; | ||
35 | bool pdc_conemu, pdc_wt, pdc_ansi; | ||
36 | |||
37 | enum { 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 | |||
43 | static 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) */ | ||
78 | typedef 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; | ||
89 | typedef CONSOLE_SCREEN_BUFFER_INFOEX *PCONSOLE_SCREEN_BUFFER_INFOEX; | ||
90 | #endif | ||
91 | |||
92 | typedef BOOL (WINAPI *SetConsoleScreenBufferInfoExFn)(HANDLE hConsoleOutput, | ||
93 | PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx); | ||
94 | typedef BOOL (WINAPI *GetConsoleScreenBufferInfoExFn)(HANDLE hConsoleOutput, | ||
95 | PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx); | ||
96 | |||
97 | static SetConsoleScreenBufferInfoExFn pSetConsoleScreenBufferInfoEx = NULL; | ||
98 | static GetConsoleScreenBufferInfoExFn pGetConsoleScreenBufferInfoEx = NULL; | ||
99 | |||
100 | static CONSOLE_SCREEN_BUFFER_INFO orig_scr; | ||
101 | static CONSOLE_SCREEN_BUFFER_INFOEX console_infoex; | ||
102 | |||
103 | static LPTOP_LEVEL_EXCEPTION_FILTER xcpt_filter; | ||
104 | |||
105 | static DWORD old_console_mode = 0; | ||
106 | |||
107 | static bool is_nt; | ||
108 | |||
109 | static void _reset_old_colors(void) | ||
110 | { | ||
111 | pdc_oldf = -1; | ||
112 | pdc_oldb = -1; | ||
113 | pdc_oldu = 0; | ||
114 | } | ||
115 | |||
116 | static 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 | |||
143 | static 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 | |||
201 | static int _set_console_infoex(void) | ||
202 | { | ||
203 | if (!pSetConsoleScreenBufferInfoEx(pdc_con_out, &console_infoex)) | ||
204 | return ERR; | ||
205 | |||
206 | return OK; | ||
207 | } | ||
208 | |||
209 | static 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 | |||
226 | static 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, ®hnd); | ||
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 | |||
282 | static 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 | |||
295 | static 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 | |||
315 | static 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 | |||
325 | static 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 | |||
336 | void 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 | |||
360 | void 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 | |||
375 | int 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 | |||
481 | static 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 | |||
515 | int 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 | |||
562 | void 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 | |||
589 | void 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 | |||
607 | void PDC_restore_screen_mode(int i) | ||
608 | { | ||
609 | } | ||
610 | |||
611 | void PDC_save_screen_mode(int i) | ||
612 | { | ||
613 | } | ||
614 | |||
615 | bool PDC_can_change_color(void) | ||
616 | { | ||
617 | return is_nt; | ||
618 | } | ||
619 | |||
620 | int 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 | |||
653 | int 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 | |||
7 | pdcsetsc | ||
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 | |||
40 | int 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 | |||
74 | void 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 | |||
89 | int 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 | |||
127 | int 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 | |||
5 | void PDC_beep(void) | ||
6 | { | ||
7 | PDC_LOG(("PDC_beep() - called\n")); | ||
8 | |||
9 | /* MessageBeep(MB_OK); */ | ||
10 | MessageBeep(0XFFFFFFFF); | ||
11 | } | ||
12 | |||
13 | void 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 | |||
23 | const 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 | |||
16 | typedef struct {short r, g, b; bool mapped;} PDCCOLOR; | ||
17 | |||
18 | extern PDCCOLOR pdc_color[PDC_MAXCOL]; | ||
19 | |||
20 | extern HANDLE pdc_con_out, pdc_con_in; | ||
21 | extern DWORD pdc_quick_edit; | ||
22 | extern DWORD pdc_last_blink; | ||
23 | extern short pdc_curstoreal[16], pdc_curstoansi[16]; | ||
24 | extern short pdc_oldf, pdc_oldb, pdc_oldu; | ||
25 | extern bool pdc_conemu, pdc_wt, pdc_ansi; | ||
26 | |||
27 | extern 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 | |||
7 | printw | ||
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 | |||
47 | int 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 | |||
62 | int 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 | |||
76 | int 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 | |||
90 | int 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 | |||
107 | int 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 | |||
124 | int 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 | |||
7 | refresh | ||
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 | |||
60 | int 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 | |||
136 | int 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 | |||
231 | int 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 | |||
253 | int refresh(void) | ||
254 | { | ||
255 | PDC_LOG(("refresh() - called\n")); | ||
256 | |||
257 | return wrefresh(stdscr); | ||
258 | } | ||
259 | |||
260 | int 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 | |||
279 | int 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 | |||
7 | scroll | ||
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 | |||
41 | int 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 | |||
89 | int scrl(int n) | ||
90 | { | ||
91 | PDC_LOG(("scrl() - called\n")); | ||
92 | |||
93 | return wscrl(stdscr, n); | ||
94 | } | ||
95 | |||
96 | int 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 | |||
7 | slk | ||
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 | |||
89 | enum { LABEL_NORMAL = 8, LABEL_EXTENDED = 10, LABEL_NCURSES_EXTENDED = 12 }; | ||
90 | |||
91 | static int label_length = 0; | ||
92 | static int labels = 0; | ||
93 | static int label_fmt = 0; | ||
94 | static int label_line = 0; | ||
95 | static bool hidden = FALSE; | ||
96 | |||
97 | static 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 | |||
115 | int 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 | |||
160 | static 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 | |||
195 | static 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 | |||
209 | int 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 | |||
269 | int slk_refresh(void) | ||
270 | { | ||
271 | PDC_LOG(("slk_refresh() - called\n")); | ||
272 | |||
273 | return (slk_noutrefresh() == ERR) ? ERR : doupdate(); | ||
274 | } | ||
275 | |||
276 | int 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 | |||
286 | char *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 | |||
310 | int 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 | |||
322 | int 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 | |||
334 | int 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 | |||
344 | int 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 | |||
359 | int 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 | |||
366 | int 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 | |||
381 | int 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 | |||
388 | int 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 | |||
403 | int 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 | |||
418 | int 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 | |||
425 | static 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 | |||
513 | void 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 | |||
559 | void 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 | |||
580 | int 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 | ||
600 | int 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 | |||
653 | wchar_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 | |||
7 | touch | ||
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 | |||
63 | int 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 | |||
81 | int 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 | |||
100 | int 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 | |||
118 | int 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 | |||
145 | bool 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 | |||
155 | bool 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 | |||
169 | int 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 | |||
7 | window | ||
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 | |||
152 | WINDOW *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 | |||
220 | WINDOW *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 | |||
254 | void 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 | |||
264 | WINDOW *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 | |||
289 | int 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 | |||
313 | int 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 | |||
328 | WINDOW *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 | |||
378 | WINDOW *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 | |||
383 | int 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 | |||
408 | WINDOW *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 | |||
466 | WINDOW *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 | |||
476 | WINDOW *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 | |||
566 | int wresize(WINDOW *win, int nlines, int ncols) | ||
567 | { | ||
568 | return (resize_window(win, nlines, ncols) ? OK : ERR); | ||
569 | } | ||
570 | |||
571 | void 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 | |||
581 | int 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 | |||
593 | bool 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 | |||
603 | bool 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 | |||
613 | void 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 | |||
623 | void 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)) | 14 | static inline const char *gettext(const char *txt) { return txt; } |
15 | # define textdomain(Domainname) ((const char *) (Domainname)) | 15 | static inline void textdomain(const char *domainname) {} |
16 | # define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) | 16 | static 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 | |||
47 | check() { | 53 | check() { |
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 |
50 | main() {} | 56 | int main() {} |
51 | EOF | 57 | EOF |
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 | */ |
139 | void init_dialog(void) | 139 | void 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]; | |||
270 | static const char filename[] = ".config"; | 278 | static const char filename[] = ".config"; |
271 | static char *args[1024], **argptr = args; | 279 | static char *args[1024], **argptr = args; |
272 | static int indent; | 280 | static int indent; |
281 | #ifndef __MINGW32__ | ||
273 | static struct termios ios_org; | 282 | static struct termios ios_org; |
283 | #endif | ||
274 | static int rows = 0, cols = 0; | 284 | static int rows = 0, cols = 0; |
275 | static struct menu *current_menu; | 285 | static struct menu *current_menu; |
276 | static int child_count; | 286 | static int child_count; |
287 | #ifndef __MINGW32__ | ||
277 | static int do_resize; | 288 | static int do_resize; |
289 | #endif | ||
278 | static int single_menu_mode; | 290 | static int single_menu_mode; |
279 | 291 | ||
280 | static void conf(struct menu *menu); | 292 | static void conf(struct menu *menu); |
@@ -292,12 +304,45 @@ static int cprint1(const char *fmt, ...); | |||
292 | static void cprint_done(void); | 304 | static void cprint_done(void); |
293 | static int cprint(const char *fmt, ...); | 305 | static int cprint(const char *fmt, ...); |
294 | 306 | ||
307 | #ifdef __MINGW32__ | ||
308 | struct winsize { | ||
309 | unsigned short ws_row, ws_col; | ||
310 | unsigned short ws_xpixel, ws_ypixel; | ||
311 | }; | ||
312 | |||
313 | static 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 | |||
295 | static void init_wsize(void) | 336 | static 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__ | ||
508 | static char * | ||
509 | quote_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 | |||
601 | static 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 | |||
462 | static int exec_conf(void) | 619 | static 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 | ||
540 | static void search_conf(void) | 776 | static 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 | ||
1052 | static void conf_cleanup(void) | 1288 | static 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) | |||
44 | void sym_init(void) | 46 | void 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 | ||
77 | enum symbol_type sym_get_type(struct symbol *sym) | 87 | enum 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 | |||
721 | struct symbol **sym_re_search(const char *pattern) | 735 | struct 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 | |||
3 | configs=$(dirname -- "$0")/../configs | ||
4 | |||
5 | # replace each FOO=bar argument with -e 's/.*FOO.*/FOO=bar/', then sed "$@" | ||
6 | set_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 | |||
25 | set_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 | |||
38 | sed -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 |
35 | fi | 35 | fi |
36 | bzip2 </dev/null >/dev/null | 36 | bzip2 </dev/null >/dev/null 2>&1 |
37 | if test $? != 0; then | 37 | if test $? = 127; then |
38 | echo 'bzip2 is not installed' | 38 | echo 'bzip2 is not installed' |
39 | exit 1 | 39 | exit 1 |
40 | fi | 40 | fi |
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 | |||
28 | export LC_ALL=C | ||
29 | self=${0##*/} | ||
30 | |||
31 | # c-types (bigger types work but waste memory. uintN_t need <stdint.h>) | ||
32 | u32=uint32_t # "unsigned" is also typically 32 bit | ||
33 | u16=uint16_t # "unsigned short" is also typically 16 bits | ||
34 | FUNC_ATTR=FAST_FUNC # delete this line if not generating a busybox function | ||
35 | |||
36 | |||
37 | err() { >&2 printf %s\\n "$self: $*"; exit 1; } | ||
38 | |||
39 | case ${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)." | ||
47 | esac | ||
48 | |||
49 | [ "${1-}" != -- ] || shift | ||
50 | |||
51 | pwc_root=${1:-.} | ||
52 | pwc_git() { git -C "$pwc_root" "$@"; } | ||
53 | |||
54 | zerowidth_py=$pwc_root/wcwidth/table_zero.py | ||
55 | widewidth_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': (") | ||
61 | ver=$(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) | ||
65 | last_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. | ||
75 | py_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 | |||
90 | data=$(last_table < "$zerowidth_py" | py_data_to_c 0 && | ||
91 | last_table < "$widewidth_py" | py_data_to_c 2) || err abort | ||
92 | data=$(printf %s\\n "$data" | sort) # lexicographic here is also numeric | ||
93 | |||
94 | # sorted hex ranges and their (wc)width: R(first, last, {0|2}),[ /* ... */] | ||
95 | data() { printf %s\\n "$data"; } | ||
96 | |||
97 | repeat() { 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 | ||
100 | mkplanes() { | ||
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 | |||
110 | indent() { sed -e 's/^/\t\t/' -e 's/\s*$//'; } # also trim trailing spaces | ||
111 | |||
112 | cat << 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 | */ | ||
120 | int ${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 */ | ||
169 | CFUNCTION | ||
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="" |
94 | fi | 94 | fi |
95 | 95 | ||
96 | WARN_COMMON="-Wl,--warn-common" | ||
97 | if ! check_cc "-Wl,--warn-common"; then | ||
98 | echo "Your linker does not support --warn-common" | ||
99 | WARN_COMMON="" | ||
100 | fi | ||
101 | |||
96 | START_GROUP="-Wl,--start-group" | 102 | START_GROUP="-Wl,--start-group" |
97 | END_GROUP="-Wl,--end-group" | 103 | END_GROUP="-Wl,--end-group" |
98 | INFO_OPTS() { | 104 | INFO_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:= | |||
9 | INSERT | 9 | INSERT |
10 | 10 | ||
11 | lib-$(CONFIG_FEATURE_SH_MATH) += math.o | 11 | lib-$(CONFIG_FEATURE_SH_MATH) += math.o |
12 | lib-$(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 | |||
383 | union node; | ||
384 | struct strlist; | ||
385 | struct job; | ||
386 | |||
387 | struct 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 | |||
432 | enum { | ||
433 | FS_OPENHERE, | ||
434 | FS_EVALBACKCMD, | ||
435 | FS_EVALSUBSHELL, | ||
436 | FS_EVALPIPE, | ||
437 | FS_SHELLEXEC | ||
438 | }; | ||
439 | |||
440 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
441 | static void forkshell_init(const char *idstr); | ||
442 | static void *sticky_mem_start, *sticky_mem_end; | ||
443 | static 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 | ||
448 | static void spawn_forkshell(struct forkshell *fs, struct job *jp, | ||
449 | union node *n, int mode); | ||
450 | # if FORKSHELL_DEBUG | ||
451 | static 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 { | |||
406 | struct globals_misc { | 554 | struct 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, ...); | |||
547 | static void trace_vprintf(const char *fmt, va_list va); | 744 | static 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 | ||
640 | static struct parsefile basepf; /* top level input file */ | 845 | static struct parsefile basepf; /* top level input file */ |
641 | static struct parsefile *g_parsefile = &basepf; /* current input file */ | 846 | static struct parsefile *g_parsefile = &basepf; /* current input file */ |
847 | #if ENABLE_PLATFORM_POSIX | ||
642 | static char *commandname; /* currently executing command */ | 848 | static 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 | */ |
699 | static void raise_interrupt(void) NORETURN; | 906 | static void raise_interrupt(void) IF_NOT_PLATFORM_MINGW32(NORETURN); |
700 | static void | 907 | static void |
701 | raise_interrupt(void) | 908 | raise_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. */ | ||
2229 | static char * | ||
2230 | stack_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; | |||
2149 | static void change_realtime(const char *) FAST_FUNC; | 2389 | static void change_realtime(const char *) FAST_FUNC; |
2150 | #endif | 2390 | #endif |
2151 | 2391 | ||
2392 | #if ENABLE_PLATFORM_MINGW32 | ||
2393 | static void FAST_FUNC | ||
2394 | change_terminal_mode(const char *newval UNUSED_PARAM) | ||
2395 | { | ||
2396 | terminal_mode(TRUE); | ||
2397 | } | ||
2398 | |||
2399 | static void clearcmdentry(void); | ||
2400 | static void FAST_FUNC | ||
2401 | change_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 | |||
2152 | static const struct { | 2410 | static 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 | ||
2191 | struct redirtab; | 2455 | struct 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 | ||
2677 | static char * | ||
2678 | fix_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 */ | ||
2716 | static int | ||
2717 | is_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 * | |||
2420 | setvareq(char *s, int flags) | 2743 | setvareq(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 */ | ||
2951 | static void | ||
2952 | setwinxp(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 | */ | ||
2985 | static 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 | |||
2998 | static 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 */ |
2599 | static const char * | 3010 | static const char * |
@@ -2637,7 +3048,7 @@ static const char *pathopt; /* set by padvance */ | |||
2637 | static int | 3048 | static int |
2638 | padvance_magic(const char **path, const char *name, int magic) | 3049 | padvance_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 | ||
2774 | static int | 3190 | static int |
2775 | cdopt(void) | 3191 | cdopt(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) | |||
2795 | static const char * | 3218 | static const char * |
2796 | updatepwd(const char *dir) | 3219 | updatepwd(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 | ||
3540 | static void | ||
3541 | print_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 | |||
2991 | static int FAST_FUNC | 3559 | static int FAST_FUNC |
2992 | pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 3560 | pwdcmd(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) | |||
3623 | struct procstat { | 4197 | struct 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 | ||
3629 | struct job { | 4208 | struct 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 | ||
3652 | static struct job *makejob(/*union node *,*/ int); | 4233 | static struct job *makejob(/*union node *,*/ int); |
4234 | #if !ENABLE_PLATFORM_MINGW32 | ||
3653 | static int forkshell(struct job *, union node *, int); | 4235 | static int forkshell(struct job *, union node *, int); |
4236 | #endif | ||
3654 | static int waitforjob(struct job *); | 4237 | static int waitforjob(struct job *); |
3655 | 4238 | ||
3656 | #if !JOBS | 4239 | #if !JOBS && !JOBS_WIN32 |
3657 | enum { doing_jobctl = 0 }; | 4240 | enum { doing_jobctl = 0 }; |
3658 | #define setjobctl(on) do {} while (0) | 4241 | #define setjobctl(on) do {} while (0) |
3659 | #else | 4242 | #elif JOBS_WIN32 |
4243 | static smallint doing_jobctl; //references:8 | ||
4244 | #define setjobctl(on) do { if (rootshell) doing_jobctl = on; } while (0) | ||
4245 | #else /* JOBS */ | ||
3660 | static smallint doing_jobctl; //references:8 | 4246 | static smallint doing_jobctl; //references:8 |
3661 | static void setjobctl(int); | 4247 | static 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 |
3946 | static int | 4537 | static int |
3947 | jobno(const struct job *jp) | 4538 | jobno(const struct job *jp) |
3948 | { | 4539 | { |
@@ -3960,7 +4551,9 @@ static struct job * | |||
3960 | getjob(const char *name, int getctl) | 4551 | getjob(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) | |||
4039 | static void | 4636 | static void |
4040 | freejob(struct job *jp) | 4637 | freejob(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 | ||
4143 | static int FAST_FUNC | 4746 | static int FAST_FUNC |
4144 | killcmd(int argc, char **argv) | 4747 | killcmd(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 | ||
4197 | static void | 4808 | static void |
4198 | showpipe(struct job *jp /*, FILE *out*/) | 4809 | showpipe(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 | ||
4913 | static 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 | */ | ||
4931 | static pid_t | ||
4932 | waitpid_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) | |||
4308 | static int | 4978 | static int |
4309 | waitproc(int block, int *status) | 4979 | waitproc(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 | ||
4343 | static int | 5019 | static 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) | |||
4456 | static int | 5136 | static int |
4457 | dowait(int block, struct job *jp) | 5137 | dowait(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 |
4483 | static void | 5172 | static void |
4484 | showjob(struct job *jp, int mode) | 5173 | showjob(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 */ |
5172 | static void closescript(void); | 5868 | static 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 |
5302 | static void | 5999 | static void |
6000 | #if !ENABLE_PLATFORM_MINGW32 | ||
5303 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 6001 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
6002 | #else | ||
6003 | forkparent(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 */ |
5337 | static int | 6051 | static int |
5338 | forkshell(struct job *jp, union node *n, int mode) | 6052 | forkshell(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 | ||
5446 | static int | 6166 | static int |
5447 | stoppedjobs(void) | 6167 | stoppedjobs(void) |
5448 | { | 6168 | { |
@@ -5461,6 +6181,17 @@ stoppedjobs(void) | |||
5461 | out: | 6181 | out: |
5462 | return retval; | 6182 | return retval; |
5463 | } | 6183 | } |
6184 | #else | ||
6185 | static int | ||
6186 | stoppedjobs(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 | ||
8669 | static int FAST_FUNC | ||
8670 | ash_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 | ||
8004 | static struct strlist * | 8836 | static struct strlist * |
@@ -8271,14 +9103,40 @@ static int builtinloc = -1; /* index in path of %builtin, or -1 */ | |||
8271 | 9103 | ||
8272 | 9104 | ||
8273 | static void | 9105 | static void |
9106 | #if ENABLE_PLATFORM_MINGW32 | ||
9107 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no, const char *path, int noexec,) | ||
9108 | const char *cmd, char **argv, char **envp) | ||
9109 | #else | ||
8274 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp) | 9110 | tryexec(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 | */ |
8334 | static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN; | 9235 | static struct builtincmd *find_builtin(const char *name); |
8335 | static void shellexec(char *prog, char **argv, const char *path, int idx) | 9236 | static void shellexec(char *prog, char **argv, const char *path, int idx, |
9237 | int noexec) NORETURN; | ||
9238 | static 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 */ |
8941 | static void *funcblock; /* block to allocate function from */ | 9909 | static void *funcblock; /* block to allocate function from */ |
8942 | static char *funcstring_end; /* end of block to allocate strings from */ | 9910 | static char *funcstring_end; /* end of block to allocate strings from */ |
9911 | #if ENABLE_PLATFORM_MINGW32 | ||
9912 | static int fs_size; | ||
9913 | static void *fs_start; | ||
9914 | # if FORKSHELL_DEBUG | ||
9915 | static void *fs_funcstring; | ||
9916 | static const char **annot; | ||
9917 | static char *annot_free; | ||
9918 | # endif | ||
9919 | #endif | ||
8943 | 9920 | ||
8944 | static const uint8_t nodesize[N_NUMBER] ALIGN1 = { | 9921 | static 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 | ||
9074 | static char * | 10051 | static char * |
9075 | nodeckstrdup(char *s) | 10052 | nodeckstrdup(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 | ||
9081 | static union node *copynode(union node *); | 10062 | static 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 | ||
10075 | static void forkshell_mark_ptr(void *dst, const char *note, int flag) | ||
10076 | #else | ||
10077 | static 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 | |||
9083 | static struct nodelist * | 10125 | static struct nodelist * |
9084 | copynodelist(struct nodelist *lp) | 10126 | copynodelist(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) |
9240 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ | 10319 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ |
9241 | static int skipcount; /* number of levels to skip */ | 10320 | static int skipcount; /* number of levels to skip */ |
10321 | #if ENABLE_PLATFORM_POSIX | ||
9242 | static int loopnest; /* current loop nesting level */ | 10322 | static int loopnest; /* current loop nesting level */ |
10323 | #endif | ||
9243 | static int funcline; /* starting line number of current function, or 0 if not in a function */ | 10324 | static 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 */ |
9246 | static int evalstring(char *s, int flags); | 10327 | static 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 | ||
10389 | static void | ||
10390 | dotrap(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... */ |
9308 | static int evalloop(union node *, int); | 10429 | static int evalloop(union node *, int); |
@@ -9588,19 +10709,36 @@ evalcase(union node *n, int flags) | |||
9588 | static int | 10709 | static int |
9589 | evalsubshell(union node *n, int flags) | 10710 | evalsubshell(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) | |||
9692 | static int | 10831 | static int |
9693 | evalpipe(union node *n, int flags) | 10832 | evalpipe(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 | ||
9824 | struct localvar_list { | 10984 | struct 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; | |||
10155 | static int setcmd(int, char **) FAST_FUNC; | 11329 | static int setcmd(int, char **) FAST_FUNC; |
10156 | static int shiftcmd(int, char **) FAST_FUNC; | 11330 | static int shiftcmd(int, char **) FAST_FUNC; |
10157 | static int timescmd(int, char **) FAST_FUNC; | 11331 | static int timescmd(int, char **) FAST_FUNC; |
11332 | #if ENABLE_PLATFORM_MINGW32 | ||
11333 | static int titlecmd(int, char **) FAST_FUNC; | ||
11334 | #endif | ||
10158 | static int trapcmd(int, char **) FAST_FUNC; | 11335 | static int trapcmd(int, char **) FAST_FUNC; |
10159 | static int umaskcmd(int, char **) FAST_FUNC; | 11336 | static int umaskcmd(int, char **) FAST_FUNC; |
10160 | static int unsetcmd(int, char **) FAST_FUNC; | 11337 | static 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 | |||
10356 | static int | 11537 | static int |
10357 | evalcommand(union node *cmd, int flags) | 11538 | evalcommand(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 | */ | ||
12060 | static inline ssize_t | ||
12061 | nonblock_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 | |||
10834 | static int | 12103 | static int |
10835 | preadfd(void) | 12104 | preadfd(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 | ||
15709 | static int FAST_FUNC | ||
15710 | titlecmd(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 | ||
16010 | static 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 */ |
14552 | static NOINLINE void | 16018 | static NOINLINE void |
14553 | init(void) | 16019 | init(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 | ||
16500 | static void | ||
16501 | forkshell_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 | |||
16522 | static void | ||
16523 | forkshell_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 | |||
16553 | static void | ||
16554 | forkshell_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 | |||
16570 | static void | ||
16571 | forkshell_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 | |||
16594 | static void | ||
16595 | forkshell_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 | |||
16605 | static void | ||
16606 | forkshell_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 | */ | ||
16636 | static void | ||
16637 | reinitvar(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 | |||
16660 | static void | ||
16661 | spawn_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 | |||
16711 | static int align_len(const char *s) | ||
16712 | { | ||
16713 | return s ? SHELL_ALIGN(strlen(s)+1) : 0; | ||
16714 | } | ||
16715 | |||
16716 | struct datasize { | ||
16717 | int funcblocksize; | ||
16718 | int funcstringsize; | ||
16719 | }; | ||
16720 | |||
16721 | #define SLIST_SIZE_BEGIN(name,type) \ | ||
16722 | static struct datasize \ | ||
16723 | name(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) \ | ||
16735 | static type * \ | ||
16736 | name(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 | */ | ||
16757 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
16758 | ds.funcstringsize += align_len(p->var_text); | ||
16759 | SLIST_SIZE_END() | ||
16760 | |||
16761 | SLIST_COPY_BEGIN(var_copy,struct var) | ||
16762 | (*vpp)->var_text = nodeckstrdup(vp->var_text); | ||
16763 | (*vpp)->flags = vp->flags; | ||
16764 | (*vpp)->var_func = NULL; | ||
16765 | SAVE_PTR((*vpp)->var_text, xasprintf("(*vpp)->var_text '%s'", vp->var_text ?: "NULL"), FREE); | ||
16766 | SLIST_COPY_END() | ||
16767 | |||
16768 | /* | ||
16769 | * struct tblentry | ||
16770 | */ | ||
16771 | static struct datasize | ||
16772 | tblentry_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 | |||
16786 | static struct tblentry * | ||
16787 | tblentry_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 | |||
16822 | static struct datasize | ||
16823 | cmdtable_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 | |||
16832 | static struct tblentry ** | ||
16833 | cmdtable_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 | */ | ||
16850 | SLIST_SIZE_BEGIN(alias_size,struct alias) | ||
16851 | ds.funcstringsize += align_len(p->name); | ||
16852 | ds.funcstringsize += align_len(p->val); | ||
16853 | SLIST_SIZE_END() | ||
16854 | |||
16855 | SLIST_COPY_BEGIN(alias_copy,struct alias) | ||
16856 | (*vpp)->name = nodeckstrdup(vp->name); | ||
16857 | (*vpp)->val = nodeckstrdup(vp->val); | ||
16858 | (*vpp)->flag = vp->flag; | ||
16859 | SAVE_PTR((*vpp)->name, xasprintf("(*vpp)->name '%s'", vp->name ?: "NULL"), FREE); | ||
16860 | SAVE_PTR((*vpp)->val, xasprintf("(*vpp)->val '%s'", vp->val ?: "NULL"), FREE); | ||
16861 | SLIST_COPY_END() | ||
16862 | |||
16863 | static struct datasize | ||
16864 | atab_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 | |||
16873 | static struct alias ** | ||
16874 | atab_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 | */ | ||
16891 | static struct datasize | ||
16892 | argv_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 | |||
16906 | static char ** | ||
16907 | argv_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 | ||
16933 | static struct datasize | ||
16934 | history_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 | |||
16946 | static char ** | ||
16947 | history_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 | */ | ||
16967 | static struct datasize | ||
16968 | procstat_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 | |||
16981 | static struct procstat * | ||
16982 | procstat_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 | */ | ||
17002 | static struct datasize | ||
17003 | jobtab_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 | |||
17013 | static struct job * | ||
17014 | jobtab_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 | */ | ||
17052 | static int | ||
17053 | redirtab_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 | |||
17062 | static struct redirtab * | ||
17063 | redirtab_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 | |||
17082 | static struct datasize | ||
17083 | globals_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 | ||
17100 | static struct globals_var * | ||
17101 | globals_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 | |||
17130 | static struct datasize | ||
17131 | globals_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 | ||
17153 | static struct globals_misc * | ||
17154 | globals_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 | |||
17182 | static struct datasize | ||
17183 | forkshell_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 | |||
17214 | static void | ||
17215 | forkshell_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 | ||
17265 | enum {GVP, GMP, CMDTABLE, NODE, ARGV, ATAB, HISTORY, JOBTAB, FUNCSTRING}; | ||
17266 | |||
17267 | /* fp0 and notes can each be NULL */ | ||
17268 | static void | ||
17269 | forkshell_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 | |||
17378 | static struct forkshell * | ||
17379 | forkshell_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 | ||
17464 | static void | ||
17465 | forkshell_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 | ||
17586 | static void | ||
17587 | sticky_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 |
49 | typedef long long arith_t; | 49 | typedef long long arith_t; |
50 | # define ARITH_FMT "%lld" | 50 | #define ARITH_FMT "%"LL_FMT"d" |
51 | #else | 51 | #else |
52 | typedef long arith_t; | 52 | typedef 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 | ||
23 | uint32_t FAST_FUNC | ||
24 | next_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 | ||
37 | uint32_t next_random(random_t *rnd) FAST_FUNC; | 37 | uint32_t next_random(random_t *rnd) FAST_FUNC; |
38 | #if ENABLE_FEATURE_PRNG_SHELL | ||
39 | uint32_t full_random(random_t *rnd) FAST_FUNC; | ||
40 | #endif | ||
38 | 41 | ||
39 | POP_SAVED_FUNCTION_VISIBILITY | 42 | POP_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 | ||
342 | struct limits { | 409 | struct 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 | ||
778 | int 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 | ||
483 | optional PLATFORM_MINGW32 | ||
484 | testing 'awk match line ending' \ | ||
485 | "awk '/world$/'" \ | ||
486 | "world\n" \ | ||
487 | "" \ | ||
488 | "hello\r\nworld\r\n" | ||
489 | |||
490 | testing 'awk backslash+CRLF eaten with no trace' \ | ||
491 | "awk -f -" \ | ||
492 | "Hello world\n" \ | ||
493 | '' \ | ||
494 | 'BEGIN { printf "Hello\\\r\n world\\n" }\n' | ||
495 | SKIP= | ||
496 | |||
483 | # User-supplied bug (SEGV) example, was causing use-after-realloc | 497 | # User-supplied bug (SEGV) example, was causing use-after-realloc |
484 | testing 'awk assign while assign' \ | 498 | testing '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 |
8 | test -f "$bindir/.config" && . "$bindir/.config" | 8 | test -f "$bindir/.config" && . "$bindir/.config" |
9 | 9 | ||
10 | ln -s `which busybox` unknown | 10 | if [ -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" | ||
16 | else | ||
17 | suffix="" | ||
18 | lncmd="ln -s" | ||
19 | fi | ||
20 | |||
21 | $lncmd "$(which busybox)" unknown$suffix | ||
11 | 22 | ||
12 | testing "busybox as unknown name" "./unknown 2>&1" \ | 23 | testing "busybox as unknown name" "./unknown 2>&1" \ |
13 | "unknown: applet not found\n" "" "" | 24 | "unknown: applet not found\n" "" "" |
14 | rm unknown | 25 | rm 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 |
17 | test x"$CONFIG_BUSYBOX" = x"y" \ | 28 | test x"$CONFIG_BUSYBOX" = x"y" \ |
@@ -23,7 +34,7 @@ optional FEATURE_VERBOSE_USAGE | |||
23 | testing "busybox --help busybox" "true | busybox --help busybox 2>&1 | cat" "$HELPDUMP\n" "" "" | 34 | testing "busybox --help busybox" "true | busybox --help busybox 2>&1 | cat" "$HELPDUMP\n" "" "" |
24 | SKIP= | 35 | SKIP= |
25 | 36 | ||
26 | ln -s `which busybox` busybox-suffix | 37 | $lncmd "$(which busybox)" busybox-suffix$suffix |
27 | for i in busybox ./busybox-suffix | 38 | for i in busybox ./busybox-suffix |
28 | do | 39 | do |
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" "" "" |
44 | done | 55 | done |
45 | rm busybox-suffix | 56 | rm busybox-suffix$suffix |
46 | 57 | ||
47 | exit $FAILCOUNT | 58 | exit $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 | ||
126 | optional PLATFORM_MINGW32 LONG_OPTS | ||
127 | testing "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 | |||
142 | testing "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 | |||
157 | testing "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 | |||
172 | testing "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 | |||
187 | SKIP= | ||
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 | |||
9 | optional 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. | ||
12 | testing "environment variables 1a" \ | ||
13 | "V=set env sh -c 'env | grep ^V='" \ | ||
14 | "V=set | ||
15 | " "" "" | ||
16 | |||
17 | testing "environment variables 1b" \ | ||
18 | "V= env sh -c 'env | grep ^V='" \ | ||
19 | "V= | ||
20 | " "" "" | ||
21 | |||
22 | testing "environment variables 1c" \ | ||
23 | "env sh -c 'env | grep ^V='" \ | ||
24 | "" "" "" | ||
25 | |||
26 | testing "environment variables 2a" \ | ||
27 | "V=set sh -c 'env | grep ^V='" \ | ||
28 | "V=set | ||
29 | " "" "" | ||
30 | |||
31 | testing "environment variables 2b" \ | ||
32 | "V= sh -c 'env | grep ^V='" \ | ||
33 | "V= | ||
34 | " "" "" | ||
35 | |||
36 | testing "environment variables 2c" \ | ||
37 | "sh -c 'env | grep ^V='" \ | ||
38 | "" "" "" | ||
39 | |||
40 | testing "environment variables 3a" \ | ||
41 | "V=set env sh -c 'echo \${V-unset}'" \ | ||
42 | "set | ||
43 | " "" "" | ||
44 | |||
45 | testing "environment variables 3b" \ | ||
46 | "V= env sh -c 'echo \${V-unset}'" \ | ||
47 | " | ||
48 | " "" "" | ||
49 | |||
50 | testing "environment variables 3c" \ | ||
51 | "env sh -c 'echo \${V-unset}'" \ | ||
52 | "unset | ||
53 | " "" "" | ||
54 | |||
55 | testing "environment variables 4a" \ | ||
56 | "V=set sh -c 'echo \${V-unset}'" \ | ||
57 | "set | ||
58 | " "" "" | ||
59 | |||
60 | testing "environment variables 4b" \ | ||
61 | "V= sh -c 'echo \${V-unset}'" \ | ||
62 | " | ||
63 | " "" "" | ||
64 | |||
65 | testing "environment variables 4c" \ | ||
66 | "sh -c 'echo \${V-unset}'" \ | ||
67 | "unset | ||
68 | " "" "" | ||
69 | SKIP= | ||
70 | |||
71 | exit $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 | ||
4 | unset MAKEFLAGS | ||
5 | rm -rf make.tempdir | ||
6 | |||
7 | # testing "test name" "command" "expected result" "file input" "stdin" | ||
8 | |||
9 | testing "make basic makefile" \ | ||
10 | "make -f -" "target\n" "" ' | ||
11 | target: | ||
12 | @echo target | ||
13 | ' | ||
14 | |||
15 | testing "make .DEFAULT rule for prerequisite" \ | ||
16 | "make -f - 2>/dev/null" "source\n" "" ' | ||
17 | .DEFAULT: | ||
18 | @echo $@ | ||
19 | target: source | ||
20 | ' | ||
21 | |||
22 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
23 | touch target.xyz | ||
24 | testing "make empty command overrides inference rule" \ | ||
25 | "make -f - target 2>/dev/null" "" "" ' | ||
26 | .SUFFIXES: .xyz | ||
27 | .xyz: | ||
28 | @echo xyz | ||
29 | target: ; | ||
30 | ' | ||
31 | cd .. || 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. | ||
35 | testing "make macro expansion and suffix substitution" \ | ||
36 | "make -f -" "src1.o src2.o\n" "" ' | ||
37 | DOTC = .c | ||
38 | DOTO = .o | ||
39 | SRC1 = src1.c | ||
40 | SRCS = $(SRC1) src2.c | ||
41 | target: | ||
42 | @echo $(SRCS:$(DOTC)=$(DOTO)) | ||
43 | ' | ||
44 | |||
45 | # Indeed, everything after the <colon> can be obtained by macro | ||
46 | # macro expansion. | ||
47 | testing "make macro expansion and suffix substitution 2" \ | ||
48 | "make -f -" "src1.o src2.o\n" "" ' | ||
49 | DOTS = .c=.o | ||
50 | SRC1 = src1.c | ||
51 | SRCS = $(SRC1) src2.c | ||
52 | target: | ||
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. | ||
58 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
59 | testing "make inference rule with explicit rule for prerequisite" \ | ||
60 | "make -f -" "touch x.p\ncat x.p >x.q\n" "" ' | ||
61 | .SUFFIXES: .p .q | ||
62 | x.q: | ||
63 | x.p: | ||
64 | touch $@ | ||
65 | .p.q: | ||
66 | cat $< >$@ | ||
67 | ' | ||
68 | cd .. || 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. | ||
73 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
74 | touch test.j test.k | ||
75 | testing "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 | ||
83 | test.l: test.k | ||
84 | test.j: | ||
85 | test.k: | ||
86 | ' | ||
87 | cd .. || 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. | ||
91 | testing "make return error if command fails" \ | ||
92 | "make -f - >/dev/null 2>&1; test \$? -gt 0 && echo OK" "OK\n" "" ' | ||
93 | target: | ||
94 | @exit 42 | ||
95 | ' | ||
96 | |||
97 | # An equal sign in a command on a target rule was detected as a | ||
98 | # macro assignment. | ||
99 | testing "make equal sign in inline command" \ | ||
100 | "make -f -" "a = a\n" "" ' | ||
101 | a = a | ||
102 | target:;@echo a = $(a) | ||
103 | ' | ||
104 | |||
105 | # Ensure an inline command on a target rule can be detected even if | ||
106 | # the semicolon is obfuscated. | ||
107 | testing "make equal sign in obfuscated inline command" \ | ||
108 | "make -f -" "a = a\n" "" ' | ||
109 | a = a | ||
110 | semi = ; | ||
111 | target:$(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. | ||
117 | testing "make failure of build command with -k" \ | ||
118 | "make -k -f - 2>/dev/null" "OK\n" "" ' | ||
119 | all: bar baz | ||
120 | bar: | ||
121 | @echo OK | ||
122 | @false | ||
123 | @echo Not reached | ||
124 | baz: | ||
125 | @: | ||
126 | ' | ||
127 | # Build commands with a '+' prefix are executed even with the -q option. | ||
128 | testing "make execute build command with + prefix and -q" \ | ||
129 | "make -q -f - 2>/dev/null" "OK\n" "" ' | ||
130 | all: bar | ||
131 | bar: | ||
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. | ||
137 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
138 | touch baz | ||
139 | testing "make check -t option" \ | ||
140 | "make -t -f - 2>/dev/null" "touch bar\n" "" ' | ||
141 | all: foo bar baz | ||
142 | foo: | ||
143 | bar: | ||
144 | @echo bar | ||
145 | baz: | ||
146 | @echo baz | ||
147 | ' | ||
148 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
149 | |||
150 | # Build commands with a '+' prefix are executed even with the -t option. | ||
151 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
152 | testing "make execute build command with + prefix and -t" \ | ||
153 | "make -t -f - 2>/dev/null" "OK\n" "" ' | ||
154 | all: bar | ||
155 | bar: | ||
156 | @+echo OK | ||
157 | ' | ||
158 | cd .. || 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. | ||
162 | testing "make appending to immediate-expansion macro" \ | ||
163 | "make -f -" \ | ||
164 | "hello 1 2 3\nhello 4 4\n" "" ' | ||
165 | world = 1 | ||
166 | hello ::= hello $(world) | ||
167 | world = 2 | ||
168 | hello += $(world) | ||
169 | world = 3 | ||
170 | hello += $(world) | ||
171 | world = 4 | ||
172 | |||
173 | world = 1 | ||
174 | reset ::= hello $(world) | ||
175 | world = 2 | ||
176 | # No longer immediate-expansion | ||
177 | reset = hello $(world) | ||
178 | world = 3 | ||
179 | reset += $(world) | ||
180 | world = 4 | ||
181 | |||
182 | target: | ||
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. | ||
189 | testing "make different styles of := macro assignment" \ | ||
190 | "make -f -" \ | ||
191 | '65 a a $A\n' "" ' | ||
192 | A = a | ||
193 | GNU ::= $A | ||
194 | BSD1 :::= $A | ||
195 | BSD2 :::= $$A | ||
196 | A = 65 | ||
197 | |||
198 | target: | ||
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. | ||
204 | testing "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' "" ' | ||
207 | target: | ||
208 | @echo '\''$(A) $(GNU) $(BSD1) $(BSD2)'\'' | ||
209 | ' | ||
210 | |||
211 | # basic pattern macro expansion | ||
212 | testing "make basic pattern macro expansion" \ | ||
213 | "make -f -" \ | ||
214 | "obj/util.o obj/main.o\n" "" ' | ||
215 | SRC = src/util.c src/main.c | ||
216 | OBJ = $(SRC:src/%.c=obj/%.o) | ||
217 | |||
218 | target: | ||
219 | @echo $(OBJ) | ||
220 | ' | ||
221 | |||
222 | # pattern macro expansion; match any value | ||
223 | testing "make pattern macro expansion; match any value" \ | ||
224 | "make -f -" \ | ||
225 | "any_value.o\n" "" ' | ||
226 | SRC = any_value | ||
227 | OBJ = $(SRC:%=%.o) | ||
228 | |||
229 | target: | ||
230 | @echo $(OBJ) | ||
231 | ' | ||
232 | |||
233 | # pattern macro expansion with empty rvalue | ||
234 | testing "make pattern macro expansion with empty rvalue" \ | ||
235 | "make -f -" \ | ||
236 | "\n" "" ' | ||
237 | SRC = util.c main.c | ||
238 | OBJ = $(SRC:%.c=) | ||
239 | |||
240 | target: | ||
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. | ||
247 | testing "make pattern macro expansion with multiple <percent> in rvalue" \ | ||
248 | "make -f - | sed 's/mainmainmain/main%%/'" \ | ||
249 | "main%%\n" "" ' | ||
250 | SRC = main.c | ||
251 | OBJ = $(SRC:%.c=%%%) | ||
252 | |||
253 | target: | ||
254 | @echo $(OBJ) | ||
255 | ' | ||
256 | |||
257 | # pattern macro expansion; zero match | ||
258 | testing "make pattern macro expansion; zero match" \ | ||
259 | "make -f -" \ | ||
260 | "nsnp\n" "" ' | ||
261 | WORD = osop | ||
262 | REPL = $(WORD:os%op=ns%np) | ||
263 | |||
264 | target: | ||
265 | @echo $(REPL) | ||
266 | ' | ||
267 | |||
268 | # Check that MAKE will contain argv[0], e.g make in this case | ||
269 | testing "make basic MAKE macro expansion" \ | ||
270 | "make -f -" \ | ||
271 | "make\n" "" ' | ||
272 | target: | ||
273 | @echo $(MAKE) | ||
274 | ' | ||
275 | |||
276 | # Check that MAKE defined as environment variable will overwrite default MAKE | ||
277 | testing "make MAKE macro expansion; overwrite with env macro" \ | ||
278 | "MAKE=hello make -f -" \ | ||
279 | "hello\n" "" ' | ||
280 | target: | ||
281 | @echo $(MAKE) | ||
282 | ' | ||
283 | |||
284 | # Check that MAKE defined on the command-line will overwrite MAKE defined in | ||
285 | # Makefile | ||
286 | testing "make MAKE macro expansion; overwrite with command-line macro" \ | ||
287 | "make -f - MAKE=hello" \ | ||
288 | "hello\n" "" ' | ||
289 | MAKE = test | ||
290 | |||
291 | target: | ||
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] | ||
297 | testing "make MAKE macro expansion; turn relative path into absolute" \ | ||
298 | "../runtest-tempdir-links/make -f -" \ | ||
299 | "ok\n" "" ' | ||
300 | target: | ||
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 | ||
306 | touch -t 202206171200 file1 | ||
307 | touch -t 202206171201 target | ||
308 | touch -t 202206171202 file2 | ||
309 | testing "make compare \$? and \$^ internal macros" \ | ||
310 | "make -f -" \ | ||
311 | "file2\nfile1 file2\n" "" ' | ||
312 | target: file1 file2 | ||
313 | @echo $? | ||
314 | @echo $^ | ||
315 | ' | ||
316 | rm -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. | ||
320 | touch -t 202206171201 target | ||
321 | testing "make phony target" \ | ||
322 | "make -f -" \ | ||
323 | "phony\n" "" ' | ||
324 | .PHONY: target | ||
325 | .PHONY: | ||
326 | target: | ||
327 | @echo phony | ||
328 | ' | ||
329 | rm -f target | ||
330 | |||
331 | # Phony targets aren't touched with -t | ||
332 | testing "make phony target not touched" \ | ||
333 | "make -t -f - >/dev/null && test -f target && echo target" \ | ||
334 | "" "" ' | ||
335 | .PHONY: target | ||
336 | target: | ||
337 | @: | ||
338 | ' | ||
339 | rm -f target | ||
340 | |||
341 | # Include files are created or brought up-to-date | ||
342 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
343 | testing "make create include file" \ | ||
344 | "make -f -" \ | ||
345 | "made\n" "" ' | ||
346 | target: | ||
347 | @echo $(VAR) | ||
348 | mk: | ||
349 | @echo "VAR = made" >mk | ||
350 | include mk | ||
351 | ' | ||
352 | cd .. || 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. | ||
356 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
357 | testing "make create include file even with -n" \ | ||
358 | "make -n -f -" \ | ||
359 | "echo made\n" "" ' | ||
360 | target: | ||
361 | @echo $(VAR) | ||
362 | mk: | ||
363 | @echo "VAR = made" >mk | ||
364 | include mk | ||
365 | ' | ||
366 | cd .. || 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.) | ||
370 | testing "make failure to create include file is OK" \ | ||
371 | "make -f -" \ | ||
372 | "OK\n" "" ' | ||
373 | target: | ||
374 | @echo OK | ||
375 | mk: | ||
376 | @: | ||
377 | -include mk | ||
378 | ' | ||
379 | |||
380 | # $^ skips duplicate prerequisites, $+ doesn't | ||
381 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
382 | touch file1 file2 file3 | ||
383 | testing "make skip duplicate entries in \$^ but not \$+" \ | ||
384 | "make -f -" \ | ||
385 | "file1 file2 file3\nfile1 file2 file2 file3 file3\n" "" ' | ||
386 | target: file1 file2 file2 file3 file3 | ||
387 | @echo $^ | ||
388 | @echo $+ | ||
389 | ' | ||
390 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
391 | |||
392 | # Assign the output of a shell command to a macro. | ||
393 | testing "make shell assignment" \ | ||
394 | "make -f -" \ | ||
395 | "1 2 3 4\n" "" ' | ||
396 | hello != echo 1; echo 2; echo 3; echo; echo | ||
397 | |||
398 | target: | ||
399 | @echo "$(hello) 4" | ||
400 | ' | ||
401 | |||
402 | # Nested macro expansion is allowed. This should be compatible | ||
403 | # with other implementations. | ||
404 | testing "make nested macro expansion" \ | ||
405 | "make -f -" "0 bc\n1 d\n2\n3\n4 bcd\n5 bcd\n" "" ' | ||
406 | a = b | ||
407 | b = c | ||
408 | c = d | ||
409 | $(a:.q=.v)$(b:.z=.v) = bc | ||
410 | bcd = bcd | ||
411 | target: | ||
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. | ||
422 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
423 | touch file1 file2 | ||
424 | testing "make .WAIT is allowed as a prerequisite" \ | ||
425 | "make -f -" \ | ||
426 | "file1 file2\n" "" ' | ||
427 | target: file1 .WAIT file2 | ||
428 | @echo $? | ||
429 | ' | ||
430 | cd .. || 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'. | ||
434 | testing "make replace escaped NL in macro in command with space" \ | ||
435 | "make -f -" \ | ||
436 | "a b a b\n" "" ' | ||
437 | M=word | ||
438 | N=${M:word=a\\ | ||
439 | b} | ||
440 | target: | ||
441 | @echo ${N} ${M:word=a\\ | ||
442 | b} | ||
443 | ' | ||
444 | |||
445 | # The CURDIR macro is supported in POSIX 2024. | ||
446 | testing "make CURDIR macro" \ | ||
447 | "make -f -" \ | ||
448 | "OK\n" "" ' | ||
449 | target: | ||
450 | @test "$(CURDIR)" = "$$(pwd -P)" && echo OK | ||
451 | ' | ||
452 | # The CURDIR environment variable doesn't affect the macro | ||
453 | export CURDIR=/you/are/here | ||
454 | testing "make CURDIR macro not affected by environment" \ | ||
455 | "make -f -" \ | ||
456 | "OK\n" "" ' | ||
457 | target: | ||
458 | @test "$(CURDIR)" != "/you/are/here" && echo OK | ||
459 | ' | ||
460 | |||
461 | # The -e option makes the CURDIR macro match the environment | ||
462 | testing "make with -e CURDIR macro is affected by the environment" \ | ||
463 | "make -e -f -" \ | ||
464 | "/you/are/here\n" "" ' | ||
465 | target: | ||
466 | @echo $(CURDIR) | ||
467 | ' | ||
468 | unset 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. | ||
472 | testing "make complex chain of macro assignments" \ | ||
473 | "make -f -" "flag 1\n" "" ' | ||
474 | FLAG_ = $(FLAG_$(VALUE)) | ||
475 | FLAG_0 = flag 0 | ||
476 | FLAG_1 = flag 1 | ||
477 | MYFLAG = $(FLAG_$(VALUE)) | ||
478 | VALUE = 1 | ||
479 | |||
480 | target: | ||
481 | @echo $(MYFLAG) | ||
482 | ' | ||
483 | |||
484 | # POSIX 2024 permits additional characters in macro and target names | ||
485 | testing "make allow - and / in target names, - in macro names" \ | ||
486 | "make -f -" \ | ||
487 | "/hello\nhel-lo\nmac-ro\n" "" ' | ||
488 | target: ./hello hel-lo | ||
489 | @echo $(mac-ro) | ||
490 | ./hello: | ||
491 | @echo /hello | ||
492 | hel-lo: | ||
493 | @echo hel-lo | ||
494 | mac-ro = mac-ro | ||
495 | ' | ||
496 | |||
497 | testing "make double-colon rule" \ | ||
498 | "make -f -" "target1\ntarget2\n" "" ' | ||
499 | target:: | ||
500 | @echo target1 | ||
501 | target:: | ||
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. | ||
508 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
509 | touch -t 202206171200 file1 | ||
510 | touch -t 202206171201 intermediate | ||
511 | touch -t 202206171202 target | ||
512 | touch -t 202206171203 file2 | ||
513 | testing "make target depends on prerequisite updated by double-colon rule" \ | ||
514 | "make -f -" \ | ||
515 | "file2\n" "" ' | ||
516 | target: intermediate | ||
517 | @cat intermediate | ||
518 | intermediate:: file1 | ||
519 | @echo file1 >>intermediate | ||
520 | intermediate:: file2 | ||
521 | @echo file2 >>intermediate | ||
522 | ' | ||
523 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
524 | |||
525 | # Use chained inference rules to determine prerequisites. | ||
526 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
527 | touch target.p | ||
528 | testing "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 | ' | ||
542 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
543 | |||
544 | # make supports *, ? and [] wildcards in targets and prerequisites | ||
545 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
546 | touch -t 202206171201 t1a t2aa t3b | ||
547 | touch s1a s2aa s3b | ||
548 | testing "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" "" ' | ||
551 | t1? t2* t3[abc]: s1? s2* s3[abc] | ||
552 | @echo $@ $? | ||
553 | ' | ||
554 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
555 | |||
556 | # A '#' character in a macro expansion doesn't start a comment | ||
557 | testing "make hash in macro expansion isn't a comment" \ | ||
558 | "make -f -" \ | ||
559 | ": hash # hash\n" "" ' | ||
560 | HASH = hash | ||
561 | hash = $(HASH:hash=#) | ||
562 | target: | ||
563 | : hash $(hash) hash | ||
564 | ' | ||
565 | |||
566 | # A '#' character can be escaped with a backslash | ||
567 | testing "make backslash-escaped hash isn't a comment" \ | ||
568 | "make -f -" \ | ||
569 | ": hash # hash\n" "" ' | ||
570 | hash = \\# | ||
571 | target: | ||
572 | : hash $(hash) hash | ||
573 | ' | ||
574 | |||
575 | # A '#' character in a command line doesn't start a comment | ||
576 | testing "make hash in command line isn't a comment" \ | ||
577 | "make -f -" \ | ||
578 | ": hash # hash\n" "" ' | ||
579 | target: | ||
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. | ||
588 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
589 | touch test.a test.b | ||
590 | testing "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 | ||
598 | test.c: test.b | ||
599 | test.a: | ||
600 | test.b: | ||
601 | ' | ||
602 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
603 | |||
604 | # Don't use the shell -e option when running commands. | ||
605 | testing "make no shell -e option when running commands" \ | ||
606 | "make -f -" "OK\n" "" ' | ||
607 | target: | ||
608 | @false; echo OK | ||
609 | ' | ||
610 | |||
611 | # Macros and targets may be mixed on the command line | ||
612 | testing "make allow mixed macros and targets" \ | ||
613 | "make -f - FOO=foo foo BAR=bar bar" "foo\nbar\nfoo\nbar\n" "" ' | ||
614 | foo: | ||
615 | @echo $(FOO) | ||
616 | @echo $(BAR) | ||
617 | bar: | ||
618 | @echo $(FOO) | ||
619 | @echo $(BAR) | ||
620 | ' | ||
621 | |||
622 | # $* and $< are supported for target rules | ||
623 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
624 | touch src.c src.h | ||
625 | testing 'make support $* and $< for target rules' \ | ||
626 | "make -f -" "src.c src.h\nsrc.o\nsrc\nsrc.c\n" "" ' | ||
627 | src.o: src.c src.h | ||
628 | @echo "$?" | ||
629 | @echo "$@" | ||
630 | @echo "$*" | ||
631 | @echo "$<" | ||
632 | ' | ||
633 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
634 | |||
635 | # ifeq/ifneq conditionals are supported | ||
636 | testing 'make support ifeq and ifneq conditionals' \ | ||
637 | "make -f -" "A OK\nB OK\n" "" ' | ||
638 | A = a | ||
639 | B = b | ||
640 | target: | ||
641 | ifeq ($(A),a) | ||
642 | @echo A OK | ||
643 | else | ||
644 | @echo A not OK | ||
645 | endif | ||
646 | ifneq "a" "$B" | ||
647 | @echo B OK | ||
648 | endif | ||
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. | ||
654 | testing "make macro expansion and suffix substitution 3" \ | ||
655 | "make -f -" "src1.c src2.c\nsrc1 src2\n" "" ' | ||
656 | SRCS = src1 src2 | ||
657 | target: | ||
658 | @echo $(SRCS:=.c) | ||
659 | @echo $(SRCS:=) | ||
660 | ' | ||
661 | |||
662 | # Skip duplicate entries in $? and $^ | ||
663 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
664 | touch -t 202206171200 file1 file3 | ||
665 | touch -t 202206171201 target | ||
666 | touch -t 202206171202 file2 | ||
667 | testing "make skip duplicate entries in \$? and \$^" \ | ||
668 | "make -f -" \ | ||
669 | "file2\nfile1 file2 file3\n" "" ' | ||
670 | target: file1 file2 file2 file3 file3 | ||
671 | @echo $? | ||
672 | @echo $^ | ||
673 | ' | ||
674 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
675 | |||
676 | # Skip duplicate entries in $? and $^, with each double-colon rule | ||
677 | # handled separately | ||
678 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
679 | touch -t 202206171200 file1 file3 | ||
680 | touch -t 202206171201 target | ||
681 | touch -t 202206171202 file2 | ||
682 | testing "make skip duplicate entries: double-colon rules" \ | ||
683 | "make -f -" \ | ||
684 | "file2\nfile1 file3 file2\nfile2\nfile2 file3\n" "" ' | ||
685 | target:: file1 file3 file1 file2 file3 | ||
686 | @echo $? | ||
687 | @echo $^ | ||
688 | target:: file2 file3 file3 | ||
689 | @echo $? | ||
690 | @echo $^ | ||
691 | ' | ||
692 | cd .. || 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. | ||
696 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
697 | touch -t 202206171200 file1 file3 | ||
698 | touch -t 202206171201 target | ||
699 | touch -t 202206171202 file2 | ||
700 | testing "make skip duplicate entries: double-colon rules, only second invoked" \ | ||
701 | "make -f -" \ | ||
702 | "file2\nfile2 file3\n" "" ' | ||
703 | target:: file1 file3 file1 file3 | ||
704 | @echo $? | ||
705 | @echo $^ | ||
706 | target:: file2 file3 file3 | ||
707 | @echo $? | ||
708 | @echo $^ | ||
709 | ' | ||
710 | cd .. || 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. | ||
714 | testing "make: .DEFAULT rule" \ | ||
715 | "make -f - default" "default2\n" "" ' | ||
716 | .DEFAULT: ignored | ||
717 | .DEFAULT: | ||
718 | @echo default1 | ||
719 | .DEFAULT: | ||
720 | @echo default2 | ||
721 | target: | ||
722 | ' | ||
723 | |||
724 | testing "make: double-colon rule" \ | ||
725 | "make -f -" "target1\ntarget2\n" "" ' | ||
726 | target:: | ||
727 | @echo target1 | ||
728 | target:: | ||
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. | ||
735 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
736 | touch -t 202206171200 file1 | ||
737 | touch -t 202206171201 target | ||
738 | testing "make phony target of double-colon rule" \ | ||
739 | "make -f - 2>&1" \ | ||
740 | "unconditional\nconditional\n" "" ' | ||
741 | .PHONY: target | ||
742 | target:: | ||
743 | @echo unconditional | ||
744 | target:: file1 | ||
745 | @echo conditional | ||
746 | file1: | ||
747 | @touch file1 | ||
748 | ' | ||
749 | cd .. || 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". | ||
753 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
754 | touch phony.xyz | ||
755 | testing "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 $< | ||
761 | phony: | ||
762 | ' | ||
763 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
764 | |||
765 | exit $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 |
100 | fi | 100 | fi |
101 | 101 | ||
102 | if [ -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 | ||
111 | else | ||
112 | suffix="" | ||
113 | lnflag="-s" | ||
114 | fi | ||
115 | |||
102 | implemented=$( | 116 | implemented=$( |
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 |
132 | done | 146 | done |
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 | |||
10 | test -f "$bindir/.config" && . "$bindir/.config" | ||
11 | |||
12 | # testing "test name" "options" "expected result" "file input" "stdin" | ||
13 | |||
14 | optional PLATFORM_MINGW32 | ||
15 | # Test case | ||
16 | testing "shebang" \ | ||
17 | "uudecode; sh -c './shebang.sh'; echo \$?" \ | ||
18 | "Hello world | ||
19 | 0 | ||
20 | " \ | ||
21 | "" "\ | ||
22 | begin-base64 755 shebang.sh | ||
23 | IyEvYmluL3NoCmVjaG8gIkhlbGxvIHdvcmxkIgo= | ||
24 | ==== | ||
25 | " | ||
26 | rm -f shebang.sh | ||
27 | |||
28 | # Test case | ||
29 | testing "shebang with whitespace" \ | ||
30 | "uudecode; sh -c './shebang_trailing_space.sh'; echo \$?" \ | ||
31 | "Hello world | ||
32 | 0 | ||
33 | " \ | ||
34 | "" "\ | ||
35 | begin-base64 755 shebang_trailing_space.sh | ||
36 | IyEvYmluL3NoIAplY2hvICJIZWxsbyB3b3JsZCIK | ||
37 | ==== | ||
38 | " | ||
39 | rm -f shebang_trailing_space.sh | ||
40 | |||
41 | # Test case | ||
42 | testing "shebang with argument" \ | ||
43 | "uudecode; sh -c './shebang_argument.sh'; echo \$?" \ | ||
44 | "Hello world | ||
45 | 0 | ||
46 | " \ | ||
47 | "" "\ | ||
48 | begin-base64 755 shebang_argument.sh | ||
49 | IyEvYmluL3NoIC0KZWNobyAiSGVsbG8gd29ybGQiCg== | ||
50 | ==== | ||
51 | " | ||
52 | rm -f shebang_argument.sh | ||
53 | |||
54 | # Test case | ||
55 | testing "shebang with leading whitespace and argument" \ | ||
56 | "uudecode; sh -c './shebang_leading_space_argument.sh'; echo \$?" \ | ||
57 | "Hello world | ||
58 | 0 | ||
59 | " \ | ||
60 | "" "\ | ||
61 | begin-base64 755 shebang_leading_space_argument.sh | ||
62 | IyEvYmluL3NoICAtCmVjaG8gIkhlbGxvIHdvcmxkIgo= | ||
63 | ==== | ||
64 | " | ||
65 | rm -f shebang_leading_space_argument.sh | ||
66 | |||
67 | # Test case | ||
68 | testing "shebang with argument and trailing whitespace" \ | ||
69 | "uudecode; sh -c './shebang_argument_trailing_space.sh'; echo \$?" \ | ||
70 | "Hello world | ||
71 | 0 | ||
72 | " \ | ||
73 | "" "\ | ||
74 | begin-base64 755 shebang_argument_trailing_space.sh | ||
75 | IyEvYmluL3NoIC0gCmVjaG8gIkhlbGxvIHdvcmxkIgo= | ||
76 | ==== | ||
77 | " | ||
78 | rm -f shebang_argument_trailing_space.sh | ||
79 | |||
80 | # Test case | ||
81 | testing "shebang with leading whitespace, argument and trailing whitespace" \ | ||
82 | "uudecode; sh -c './shebang_leading_argument_trailing_space.sh'; echo \$?" \ | ||
83 | "Hello world | ||
84 | 0 | ||
85 | " \ | ||
86 | "" "\ | ||
87 | begin-base64 755 shebang_leading_argument_trailing_space.sh | ||
88 | IyEvYmluL3NoICAtIAplY2hvICJIZWxsbyB3b3JsZCIK | ||
89 | ==== | ||
90 | " | ||
91 | rm -f shebang_leading_argument_trailing_space.sh | ||
92 | |||
93 | testing "sh remove CRs from string being evaluated" \ | ||
94 | "sh -c \"$(printf 'set -e\r\necho Hello world\r\n')\"" \ | ||
95 | "Hello world\n" "" "" | ||
96 | |||
97 | testing "sh preserve lone CRs during field splitting" \ | ||
98 | "sh input" \ | ||
99 | "Hello\r world\n" "echo \$(printf \"Hello\\\\r\\\\r\\\\nworld\\\\r\\\\n\")" "" | ||
100 | |||
101 | testing "sh read with CRLF" \ | ||
102 | "printf '1 2\\r\\n' | { read var; printf \"\${var}\\\\n\"; }" \ | ||
103 | "1 2\n" "" "" | ||
104 | |||
105 | testing "sh read with CR" \ | ||
106 | "printf '1\\r2\\r\\n' | { read var; printf \"\${var}\\\\n\"; }" \ | ||
107 | "1\r2\n" "" "" | ||
108 | |||
109 | testing "sh read with \\CRLF" \ | ||
110 | "printf '1\\\\\r\\n2\\r\\n' | { read var; printf \"\${var}\\\\n\"; }" \ | ||
111 | "12\n" "" "" | ||
112 | |||
113 | testing "sh read with \\CR" \ | ||
114 | "printf '1\\\\\r2\\r\\n' | { read var; printf \"\${var}\\\\n\"; }" \ | ||
115 | "1\r2\n" "" "" | ||
116 | SKIP= | ||
117 | |||
118 | exit $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 | ||
62 | static void gotsig(int sig UNUSED_PARAM) | 66 | static 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 | |||
5 | lib-y:= | ||
6 | |||
7 | lib-$(CONFIG_PLATFORM_MINGW32) += dirent.o | ||
8 | lib-$(CONFIG_PLATFORM_MINGW32) += dirname.o | ||
9 | lib-$(CONFIG_PLATFORM_MINGW32) += env.o | ||
10 | lib-$(CONFIG_PLATFORM_MINGW32) += fnmatch.o | ||
11 | lib-$(CONFIG_PLATFORM_MINGW32) += fsync.o | ||
12 | lib-$(CONFIG_PLATFORM_MINGW32) += glob.o | ||
13 | lib-$(CONFIG_PLATFORM_MINGW32) += inet_pton.o | ||
14 | lib-$(CONFIG_PLATFORM_MINGW32) += ioctl.o | ||
15 | lib-$(CONFIG_FEATURE_PRNG_ISAAC) += isaac.o | ||
16 | lib-$(CONFIG_PLATFORM_MINGW32) += mingw.o | ||
17 | lib-$(CONFIG_PLATFORM_MINGW32) += process.o | ||
18 | lib-$(CONFIG_PLATFORM_MINGW32) += match_class.o | ||
19 | lib-$(CONFIG_PLATFORM_MINGW32) += mntent.o | ||
20 | lib-$(CONFIG_PLATFORM_MINGW32) += net.o | ||
21 | lib-$(CONFIG_PLATFORM_MINGW32) += poll.o | ||
22 | lib-$(CONFIG_PLATFORM_MINGW32) += popen.o | ||
23 | lib-$(CONFIG_PLATFORM_MINGW32) += regex.o | ||
24 | lib-$(CONFIG_PLATFORM_MINGW32) += select.o | ||
25 | lib-$(CONFIG_FEATURE_PRNG_SHELL) += sh_random.o | ||
26 | lib-$(CONFIG_PLATFORM_MINGW32) += statfs.o | ||
27 | lib-$(CONFIG_PLATFORM_MINGW32) += strndup.o | ||
28 | lib-$(CONFIG_PLATFORM_MINGW32) += strptime.o | ||
29 | lib-$(CONFIG_PLATFORM_MINGW32) += strverscmp.o | ||
30 | lib-$(CONFIG_PLATFORM_MINGW32) += system.o | ||
31 | lib-$(CONFIG_PLATFORM_MINGW32) += termios.o | ||
32 | lib-$(CONFIG_PLATFORM_MINGW32) += timegm.o | ||
33 | lib-$(CONFIG_PLATFORM_MINGW32) += uname.o | ||
34 | lib-$(CONFIG_PLATFORM_MINGW32) += winansi.o | ||
diff --git a/win32/arpa/inet.h b/win32/arpa/inet.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/win32/arpa/inet.h | |||
diff --git a/win32/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 | |||
3 | struct DIR { | ||
4 | struct dirent dd_dir; | ||
5 | HANDLE dd_handle; /* FindFirstFile handle */ | ||
6 | int dd_stat; /* 0-based index */ | ||
7 | }; | ||
8 | |||
9 | static 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 | |||
25 | DIR *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 | |||
69 | struct 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 | |||
96 | int 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 | |||
4 | typedef 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 | |||
11 | struct dirent { | ||
12 | unsigned char d_type; | ||
13 | char d_name[PATH_MAX]; // file name | ||
14 | }; | ||
15 | |||
16 | DIR *opendir(const char *dirname); | ||
17 | struct dirent *readdir(DIR *dir); | ||
18 | int 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 | |||
66 | struct 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 | |||
86 | static | ||
87 | void | ||
88 | do_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 | |||
188 | char* | ||
189 | dirname(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 | |||
249 | char* | ||
250 | basename(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 | |||
6 | char *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 | |||
24 | int 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 | */ | ||
49 | int 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 | |||
65 | int 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 | |||
85 | int 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 | ||
126 | extern char *getenv (const char *); | ||
127 | # endif | ||
128 | |||
129 | # ifndef errno | ||
130 | extern int errno; | ||
131 | # endif | ||
132 | |||
133 | /* This function doesn't exist on most systems. */ | ||
134 | |||
135 | # if !defined HAVE___STRCHRNUL && !defined _LIBC && 0 | ||
136 | static 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. */ | ||
156 | static int internal_fnmatch __P ((const char *pattern, const char *string, | ||
157 | int no_leading_period, int flags)) | ||
158 | internal_function; | ||
159 | static int | ||
160 | internal_function | ||
161 | internal_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 | |||
519 | int | ||
520 | fnmatch (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 | ||
23 | extern "C" { | ||
24 | #endif | ||
25 | |||
26 | #if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 | ||
27 | # if !defined __GLIBC__ || !defined __P | ||
28 | # undef __P | ||
29 | # define __P(protos) protos | ||
30 | # endif | ||
31 | #else /* Not C++ or ANSI C. */ | ||
32 | # undef __P | ||
33 | # define __P(protos) () | ||
34 | /* We can get away without defining `const' here only because in this file | ||
35 | it is used only inside the prototype for `fnmatch', which is elided in | ||
36 | non-ANSI C where `const' is problematical. */ | ||
37 | #endif /* C++ or ANSI C. */ | ||
38 | |||
39 | #ifndef const | ||
40 | # if (defined __STDC__ && __STDC__) || defined __cplusplus | ||
41 | # define __const const | ||
42 | # else | ||
43 | # define __const | ||
44 | # endif | ||
45 | #endif | ||
46 | |||
47 | /* We #undef these before defining them because some losing systems | ||
48 | (HP-UX A.08.07 for example) define these in <unistd.h>. */ | ||
49 | #undef FNM_PATHNAME | ||
50 | #undef FNM_NOESCAPE | ||
51 | #undef FNM_PERIOD | ||
52 | |||
53 | /* Bits set in the FLAGS argument to `fnmatch'. */ | ||
54 | #define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ | ||
55 | #define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ | ||
56 | #define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ | ||
57 | |||
58 | #if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE | ||
59 | # define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ | ||
60 | # define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ | ||
61 | # define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ | ||
62 | #endif | ||
63 | |||
64 | /* Value returned by `fnmatch' if STRING does not match PATTERN. */ | ||
65 | #define FNM_NOMATCH 1 | ||
66 | |||
67 | /* This value is returned if the implementation does not support | ||
68 | `fnmatch'. Since this is not the case here it will never be | ||
69 | returned but the conformance test suites still require the symbol | ||
70 | to be defined. */ | ||
71 | #ifdef _XOPEN_SOURCE | ||
72 | # define FNM_NOSYS (-1) | ||
73 | #endif | ||
74 | |||
75 | /* Match NAME against the filename pattern PATTERN, | ||
76 | returning zero if it matches, FNM_NOMATCH if not. */ | ||
77 | extern int fnmatch __P ((__const char *__pattern, __const char *__name, | ||
78 | int __flags)); | ||
79 | |||
80 | #ifdef __cplusplus | ||
81 | } | ||
82 | #endif | ||
83 | |||
84 | #endif /* fnmatch.h */ | ||
diff --git a/win32/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 | |||
37 | int | ||
38 | fsync (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 | ---------------------------------------------------------------------- | ||
7 | Copyright © 2005-2020 Rich Felker, et al. | ||
8 | |||
9 | Permission is hereby granted, free of charge, to any person obtaining | ||
10 | a copy of this software and associated documentation files (the | ||
11 | "Software"), to deal in the Software without restriction, including | ||
12 | without limitation the rights to use, copy, modify, merge, publish, | ||
13 | distribute, sublicense, and/or sell copies of the Software, and to | ||
14 | permit persons to whom the Software is furnished to do so, subject to | ||
15 | the following conditions: | ||
16 | |||
17 | The above copyright notice and this permission notice shall be | ||
18 | included in all copies or substantial portions of the Software. | ||
19 | |||
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
23 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
25 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
26 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
27 | ---------------------------------------------------------------------- | ||
28 | */ | ||
29 | #include "libbb.h" | ||
30 | #include <glob.h> | ||
31 | #include <fnmatch.h> | ||
32 | |||
33 | struct match | ||
34 | { | ||
35 | struct match *next; | ||
36 | char name[]; | ||
37 | }; | ||
38 | |||
39 | static 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 | |||
54 | static 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 | |||
204 | static int ignore_err(const char *path UNUSED_PARAM, int err UNUSED_PARAM) | ||
205 | { | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static 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 | ||
219 | static int sort(const void *a, const void *b) | ||
220 | { | ||
221 | return strcmp(*(const char **)a, *(const char **)b); | ||
222 | } | ||
223 | |||
224 | static 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 | |||
258 | int 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 | |||
335 | void 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 | ---------------------------------------------------------------------- | ||
7 | Copyright © 2005-2020 Rich Felker, et al. | ||
8 | |||
9 | Permission is hereby granted, free of charge, to any person obtaining | ||
10 | a copy of this software and associated documentation files (the | ||
11 | "Software"), to deal in the Software without restriction, including | ||
12 | without limitation the rights to use, copy, modify, merge, publish, | ||
13 | distribute, sublicense, and/or sell copies of the Software, and to | ||
14 | permit persons to whom the Software is furnished to do so, subject to | ||
15 | the following conditions: | ||
16 | |||
17 | The above copyright notice and this permission notice shall be | ||
18 | included in all copies or substantial portions of the Software. | ||
19 | |||
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
23 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
25 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
26 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
27 | ---------------------------------------------------------------------- | ||
28 | */ | ||
29 | #ifndef _GLOB_H | ||
30 | #define _GLOB_H | ||
31 | |||
32 | #ifdef __cplusplus | ||
33 | extern "C" { | ||
34 | #endif | ||
35 | |||
36 | typedef 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 | |||
44 | int glob(const char *__restrict, int, int (*)(const char *, int), glob_t *__restrict); | ||
45 | void 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 | ---------------------------------------------------------------------- | ||
7 | Copyright © 2005-2020 Rich Felker, et al. | ||
8 | |||
9 | Permission is hereby granted, free of charge, to any person obtaining | ||
10 | a copy of this software and associated documentation files (the | ||
11 | "Software"), to deal in the Software without restriction, including | ||
12 | without limitation the rights to use, copy, modify, merge, publish, | ||
13 | distribute, sublicense, and/or sell copies of the Software, and to | ||
14 | permit persons to whom the Software is furnished to do so, subject to | ||
15 | the following conditions: | ||
16 | |||
17 | The above copyright notice and this permission notice shall be | ||
18 | included in all copies or substantial portions of the Software. | ||
19 | |||
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
23 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
25 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
26 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
27 | ---------------------------------------------------------------------- | ||
28 | */ | ||
29 | #include "libbb.h" | ||
30 | |||
31 | static 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 | |||
39 | int 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 | |||
3 | static 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 | |||
25 | int 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 | ------------------------------------------------------------------------------ | ||
3 | readable.c: My random number generator, ISAAC. | ||
4 | (c) Bob Jenkins, March 1996, Public Domain | ||
5 | You 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 | |||
23 | typedef 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 | |||
33 | static 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 | |||
77 | static 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 | */ | ||
122 | static 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 | */ | ||
153 | ssize_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 | |||
6 | struct 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 | |||
24 | void *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 | |||
4 | int 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 | |||
5 | enum { | ||
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 | |||
11 | extern 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 | ||
12 | extern int _setargv(void); | ||
13 | int _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 | ||
30 | int _dowildcard = 0; | ||
31 | #endif | ||
32 | |||
33 | #undef _fmode | ||
34 | int _fmode = _O_BINARY; | ||
35 | #endif | ||
36 | |||
37 | #if !defined(__MINGW64_VERSION_MAJOR) | ||
38 | #if ENABLE_GLOBBING | ||
39 | int _CRT_glob = 1; | ||
40 | #else | ||
41 | int _CRT_glob = 0; | ||
42 | #endif | ||
43 | |||
44 | unsigned int _CRT_fmode = _O_BINARY; | ||
45 | #endif | ||
46 | |||
47 | smallint bb_got_signal; | ||
48 | static mode_t current_umask = DEFAULT_UMASK; | ||
49 | |||
50 | #pragma GCC optimize ("no-if-conversion") | ||
51 | int 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 | ||
170 | char *mingw_strerror(int errnum) | ||
171 | { | ||
172 | if (errnum == ELOOP) | ||
173 | return (char *)"Too many levels of symbolic links"; | ||
174 | return strerror(errnum); | ||
175 | } | ||
176 | |||
177 | char *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 | |||
186 | static int zero_fd = -1; | ||
187 | static 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 | */ | ||
194 | int 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 | |||
202 | void 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) | ||
211 | static 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 | |||
223 | static int mingw_is_directory(const char *path); | ||
224 | #undef open | ||
225 | int 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 | |||
262 | int 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 | |||
274 | ssize_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 | ||
284 | FILE *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 | ||
296 | ssize_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 | ||
309 | int 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 | ||
321 | int 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 | */ | ||
331 | static 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 | |||
338 | static 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 | |||
349 | static 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 | |||
363 | static 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 | ||
422 | mode_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 | */ | ||
441 | static 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 | ||
519 | static 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 | |||
606 | static 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 | |||
626 | static 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 | |||
636 | static 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 | */ | ||
651 | int 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 | */ | ||
683 | static 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 | |||
790 | int mingw_lstat(const char *file_name, struct mingw_stat *buf) | ||
791 | { | ||
792 | return do_lstat(0, file_name, buf); | ||
793 | } | ||
794 | |||
795 | int 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 | ||
803 | int 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 | |||
870 | static 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 | |||
878 | static 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 | |||
910 | int 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 | |||
923 | int 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 | |||
950 | int 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 | |||
968 | unsigned int sleep (unsigned int seconds) | ||
969 | { | ||
970 | Sleep(seconds*1000); | ||
971 | return 0; | ||
972 | } | ||
973 | |||
974 | int 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 | ||
997 | char *mingw_mktemp(char *template) | ||
998 | { | ||
999 | if ( mktemp(template) == NULL ) { | ||
1000 | template[0] = '\0'; | ||
1001 | } | ||
1002 | |||
1003 | return template; | ||
1004 | } | ||
1005 | |||
1006 | int 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 | |||
1014 | int 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 | |||
1026 | int 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 | |||
1039 | int 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 | |||
1062 | int pipe(int filedes[2]) | ||
1063 | { | ||
1064 | if (_pipe(filedes, PIPE_BUF, 0) < 0) | ||
1065 | return -1; | ||
1066 | return 0; | ||
1067 | } | ||
1068 | |||
1069 | struct 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 | |||
1076 | struct 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 | ||
1084 | char *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 | ||
1093 | int 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 | |||
1129 | static 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 | ||
1151 | char *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 | */ | ||
1183 | int | ||
1184 | elevation_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 | |||
1217 | int getuid(void) | ||
1218 | { | ||
1219 | return elevation_state() == (ELEVATED_PRIVILEGE | ADMIN_ENABLED) ? | ||
1220 | 0 : DEFAULT_UID; | ||
1221 | } | ||
1222 | |||
1223 | struct 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 | |||
1238 | struct 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 | |||
1257 | struct 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 | ||
1277 | int 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 | |||
1290 | int 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 | |||
1301 | int 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 | |||
1318 | long sysconf(int name) | ||
1319 | { | ||
1320 | if ( name == _SC_CLK_TCK ) { | ||
1321 | return TICKS_PER_SECOND; | ||
1322 | } | ||
1323 | errno = EINVAL; | ||
1324 | return -1; | ||
1325 | } | ||
1326 | |||
1327 | clock_t times(struct tms *buf) | ||
1328 | { | ||
1329 | memset(buf, 0, sizeof(*buf)); | ||
1330 | return 0; | ||
1331 | } | ||
1332 | |||
1333 | int 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 | |||
1356 | int 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 | ||
1399 | static 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 | |||
1438 | static 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 | |||
1478 | int 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 | |||
1532 | static 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 | |||
1551 | static 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 | */ | ||
1607 | char *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 | |||
1629 | static 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 | */ | ||
1662 | typedef 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 | ||
1671 | char * 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 | |||
1732 | const 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 | ||
1748 | int 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 | ||
1767 | int 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 | ||
1787 | int 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 | |||
1795 | int 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 | ||
1840 | int 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 | |||
1858 | struct pagefile_info { | ||
1859 | SIZE_T total; | ||
1860 | SIZE_T in_use; | ||
1861 | }; | ||
1862 | |||
1863 | static BOOL CALLBACK | ||
1864 | pagefile_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 | |||
1874 | int 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 | ||
1911 | size_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 | ||
2002 | int 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 | |||
2025 | int 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 | |||
2038 | void 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 | ||
2062 | static const char win_suffix[NUMEXT][4] = { "com", "exe", "sh", "bat", "cmd" }; | ||
2063 | |||
2064 | static 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 | |||
2079 | int has_bat_suffix(const char *name) | ||
2080 | { | ||
2081 | return has_win_suffix(name, 3); | ||
2082 | } | ||
2083 | |||
2084 | int has_exe_suffix(const char *name) | ||
2085 | { | ||
2086 | return has_win_suffix(name, 0); | ||
2087 | } | ||
2088 | |||
2089 | int 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. */ | ||
2096 | char *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 | */ | ||
2110 | int | ||
2111 | add_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 | */ | ||
2134 | char * | ||
2135 | file_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 | |||
2146 | char * 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 | ||
2159 | MINGW_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 | |||
2172 | void 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. */ | ||
2184 | void 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 | |||
2199 | size_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 | |||
2211 | off_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 | ||
2228 | ULONGLONG 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 | */ | ||
2246 | int 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. */ | ||
2280 | int 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. */ | ||
2301 | int 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 | |||
2310 | const 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 | |||
2327 | int 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 | */ | ||
2345 | char * 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 | |||
2357 | char * 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 | |||
2368 | void 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 | |||
2390 | void 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 | |||
2407 | void *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 | |||
2435 | int 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. */ | ||
2448 | int 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 | */ | ||
2463 | int 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 | */ | ||
2476 | const 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 | */ | ||
2494 | char * 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 | */ | ||
2508 | int | ||
2509 | windows_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 | |||
2527 | void FAST_FUNC | ||
2528 | change_critical_error_dialogs(const char *newval) | ||
2529 | { | ||
2530 | SetErrorMode(newval && newval[0] == '1' && newval[1] == '\0' ? | ||
2531 | 0 : SEM_FAILCRITICALERRORS); | ||
2532 | } | ||
2533 | |||
2534 | char * 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 | |||
8 | struct mntstate { | ||
9 | DWORD drives; | ||
10 | int index; | ||
11 | }; | ||
12 | |||
13 | int 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 | |||
55 | FILE *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 | |||
69 | struct 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 | |||
90 | int 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 | |||
6 | struct mntent { | ||
7 | char *mnt_fsname; /* Device or server for filesystem. */ | ||
8 | char *mnt_dir; /* Directory mounted on. */ | ||
9 | char *mnt_type; /* Type of filesystem: ufs, nfs, etc. */ | ||
10 | char *mnt_opts; /* Comma-separated options for fs. */ | ||
11 | int mnt_freq; /* Dump frequency (in days). */ | ||
12 | int mnt_passno; /* Pass number for `fsck'. */ | ||
13 | }; | ||
14 | |||
15 | extern FILE *mingw_setmntent(void); | ||
16 | extern struct mntent *getmntent(FILE *stream); | ||
17 | extern int endmntent(FILE *stream); | ||
18 | |||
19 | # if defined(MNTENT_PRIVATE) | ||
20 | struct 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 | |||
28 | extern 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 | |||
3 | int inet_aton(const char *cp, struct in_addr *inp) | ||
4 | { | ||
5 | unsigned long val = inet_addr(cp); | ||
6 | |||
7 | if (val == INADDR_NONE) | ||
8 | return 0; | ||
9 | inp->S_un.S_addr = val; | ||
10 | return 1; | ||
11 | } | ||
12 | |||
13 | void init_winsock(void) | ||
14 | { | ||
15 | WSADATA wsa; | ||
16 | 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 | ||
29 | int mingw_gethostname(char *name, int namelen) | ||
30 | { | ||
31 | init_winsock(); | ||
32 | return gethostname(name, namelen); | ||
33 | } | ||
34 | |||
35 | #undef gethostbyaddr | ||
36 | struct 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 | ||
43 | int 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 | |||
50 | int 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 | ||
81 | int 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 | ||
88 | int 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 | ||
95 | int 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 | ||
102 | int mingw_shutdown(int sockfd, int how) | ||
103 | { | ||
104 | SOCKET s = (SOCKET)_get_osfhandle(sockfd); | ||
105 | return shutdown(s, how); | ||
106 | } | ||
107 | |||
108 | #undef listen | ||
109 | int mingw_listen(int sockfd, int backlog) | ||
110 | { | ||
111 | SOCKET s = (SOCKET)_get_osfhandle(sockfd); | ||
112 | return listen(s, backlog); | ||
113 | } | ||
114 | |||
115 | #undef accept | ||
116 | int 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 | ||
135 | int 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 | |||
108 | static BOOL IsConsoleHandle (HANDLE h) | ||
109 | { | ||
110 | DWORD mode; | ||
111 | return GetConsoleMode (h, &mode) != 0; | ||
112 | } | ||
113 | |||
114 | static BOOL | ||
115 | IsSocketHandle (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. */ | ||
130 | typedef 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 | |||
143 | typedef 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 | |||
152 | typedef enum _FILE_INFORMATION_CLASS { | ||
153 | FilePipeLocalInformation = 24 | ||
154 | } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; | ||
155 | |||
156 | typedef 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 | |||
166 | static int | ||
167 | windows_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 | |||
282 | static int | ||
283 | windows_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. */ | ||
324 | static int | ||
325 | compute_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 | |||
378 | int | ||
379 | poll (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 | |||
499 | restart: | ||
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 | |||
37 | struct pollfd | ||
38 | { | ||
39 | int fd; /* which file descriptor to poll */ | ||
40 | short events; /* events we are interested in */ | ||
41 | short revents; /* events found on return */ | ||
42 | }; | ||
43 | |||
44 | typedef unsigned long nfds_t; | ||
45 | |||
46 | extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout); | ||
47 | |||
48 | /* Define INFTIM only if doing so conforms to POSIX. */ | ||
49 | #if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE) | ||
50 | #define INFTIM (-1) | ||
51 | #endif | ||
52 | |||
53 | #endif /* _GL_POLL_H */ | ||
diff --git a/win32/popen.c b/win32/popen.c new file mode 100644 index 000000000..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 | |||
5 | typedef struct { | ||
6 | PROCESS_INFORMATION piProcInfo; | ||
7 | HANDLE pipe[2]; | ||
8 | int fd; | ||
9 | } pipe_data; | ||
10 | |||
11 | static pipe_data *pipes = NULL; | ||
12 | static int num_pipes = 0; | ||
13 | |||
14 | static int mingw_popen_internal(pipe_data *p, const char *exe, | ||
15 | const char *cmd, const char *mode, int fd0, pid_t *pid); | ||
16 | |||
17 | static 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 | |||
55 | static 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 | |||
63 | static 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 | */ | ||
78 | static 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 | |||
113 | FILE *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 | */ | ||
157 | static 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 | |||
252 | finito: | ||
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 | |||
267 | int 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 | |||
273 | int 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. */ | ||
296 | pid_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 | |||
7 | pid_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 | ||
15 | pid_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 | |||
56 | int FAST_FUNC | ||
57 | parse_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 | */ | ||
109 | char * FAST_FUNC | ||
110 | quote_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 | |||
142 | char * FAST_FUNC | ||
143 | find_first_executable(const char *name) | ||
144 | { | ||
145 | const char *path = getenv("PATH"); | ||
146 | return find_executable(name, &path); | ||
147 | } | ||
148 | |||
149 | static intptr_t | ||
150 | spawnveq(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 | ||
218 | static intptr_t | ||
219 | mingw_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 */ | ||
228 | char ** FAST_FUNC | ||
229 | grow_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 | ||
241 | static int | ||
242 | create_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 | |||
290 | static intptr_t | ||
291 | mingw_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 | |||
340 | static intptr_t | ||
341 | mingw_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 | |||
372 | pid_t FAST_FUNC | ||
373 | mingw_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 | |||
382 | intptr_t FAST_FUNC | ||
383 | mingw_spawn_detach(char **argv) | ||
384 | { | ||
385 | return mingw_spawnvp(P_DETACH, argv[0], argv); | ||
386 | } | ||
387 | |||
388 | intptr_t FAST_FUNC | ||
389 | mingw_spawn_proc(const char **argv) | ||
390 | { | ||
391 | return mingw_spawnvp(P_NOWAIT, argv[0], (char *const *)argv); | ||
392 | } | ||
393 | |||
394 | BOOL 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 | |||
432 | static 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 | |||
481 | static 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 | |||
502 | int | ||
503 | mingw_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 | |||
511 | int | ||
512 | mingw_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 | |||
520 | int | ||
521 | mingw_execv(const char *cmd, char *const *argv) | ||
522 | { | ||
523 | return mingw_execve(cmd, argv, NULL); | ||
524 | } | ||
525 | |||
526 | #if ENABLE_FEATURE_HTTPD_CGI | ||
527 | int 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 | |||
537 | static 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 | */ | ||
548 | static 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 | |||
631 | pid_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 */ | ||
647 | procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags | ||
648 | #if !ENABLE_FEATURE_PS_TIME && !ENABLE_FEATURE_PS_LONG | ||
649 | UNUSED_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 | |||
754 | void 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 | */ | ||
773 | static 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(), ¤t_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 | */ | ||
800 | static 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 | |||
820 | static 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 | */ | ||
861 | int 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 | |||
938 | int FAST_FUNC is_valid_signal(int number) | ||
939 | { | ||
940 | return isalpha(*get_signame(number)); | ||
941 | } | ||
942 | |||
943 | int exit_code_to_wait_status(DWORD exit_code) | ||
944 | { | ||
945 | return exit_code_to_wait_status_cmd(exit_code, NULL); | ||
946 | } | ||
947 | |||
948 | int 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 | |||
25 | static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern, | ||
26 | size_t length, reg_syntax_t syntax); | ||
27 | static void re_compile_fastmap_iter (regex_t *bufp, | ||
28 | const re_dfastate_t *init_state, | ||
29 | char *fastmap); | ||
30 | static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len); | ||
31 | #ifdef RE_ENABLE_I18N | ||
32 | static void free_charset (re_charset_t *cset); | ||
33 | #endif /* RE_ENABLE_I18N */ | ||
34 | static void free_workarea_compile (regex_t *preg); | ||
35 | static reg_errcode_t create_initial_state (re_dfa_t *dfa); | ||
36 | #ifdef RE_ENABLE_I18N | ||
37 | static void optimize_utf8 (re_dfa_t *dfa); | ||
38 | #endif | ||
39 | static reg_errcode_t analyze (regex_t *preg); | ||
40 | static reg_errcode_t preorder (bin_tree_t *root, | ||
41 | reg_errcode_t (fn (void *, bin_tree_t *)), | ||
42 | void *extra); | ||
43 | static reg_errcode_t postorder (bin_tree_t *root, | ||
44 | reg_errcode_t (fn (void *, bin_tree_t *)), | ||
45 | void *extra); | ||
46 | static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node); | ||
47 | static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node); | ||
48 | static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg, | ||
49 | bin_tree_t *node); | ||
50 | static reg_errcode_t calc_first (void *extra, bin_tree_t *node); | ||
51 | static reg_errcode_t calc_next (void *extra, bin_tree_t *node); | ||
52 | static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node); | ||
53 | static int duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint); | ||
54 | static int search_duplicated_node (const re_dfa_t *dfa, int org_node, | ||
55 | unsigned int constraint); | ||
56 | static reg_errcode_t calc_eclosure (re_dfa_t *dfa); | ||
57 | static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, | ||
58 | int node, int root); | ||
59 | static reg_errcode_t calc_inveclosure (re_dfa_t *dfa); | ||
60 | static int fetch_number (re_string_t *input, re_token_t *token, | ||
61 | reg_syntax_t syntax); | ||
62 | static int peek_token (re_token_t *token, re_string_t *input, | ||
63 | reg_syntax_t syntax) internal_function; | ||
64 | static bin_tree_t *parse (re_string_t *regexp, regex_t *preg, | ||
65 | reg_syntax_t syntax, reg_errcode_t *err); | ||
66 | static 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); | ||
69 | static 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); | ||
72 | static 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); | ||
75 | static 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); | ||
78 | static 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); | ||
81 | static 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); | ||
84 | static 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); | ||
90 | static 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 | ||
94 | static reg_errcode_t build_equiv_class (bitset_t sbcset, | ||
95 | re_charset_t *mbcset, | ||
96 | int *equiv_class_alloc, | ||
97 | const unsigned char *name); | ||
98 | static 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 */ | ||
105 | static reg_errcode_t build_equiv_class (bitset_t sbcset, | ||
106 | const unsigned char *name); | ||
107 | static 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 */ | ||
112 | static 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); | ||
117 | static bin_tree_t *create_tree (re_dfa_t *dfa, | ||
118 | bin_tree_t *left, bin_tree_t *right, | ||
119 | re_token_type_t type); | ||
120 | static 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); | ||
123 | static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa); | ||
124 | static void free_token (re_token_t *node); | ||
125 | static reg_errcode_t free_tree (void *extra, bin_tree_t *node); | ||
126 | static 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 | |||
133 | const 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 | |||
187 | const 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 | |||
215 | wchar_t | ||
216 | btowc (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 | |||
236 | const char * | ||
237 | re_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 | ||
258 | weak_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. */ | ||
266 | reg_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 | |||
276 | reg_syntax_t | ||
277 | re_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 | ||
285 | weak_alias (__re_set_syntax, re_set_syntax) | ||
286 | #endif | ||
287 | |||
288 | int | ||
289 | re_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 | ||
306 | weak_alias (__re_compile_fastmap, re_compile_fastmap) | ||
307 | #endif | ||
308 | |||
309 | static inline void | ||
310 | __attribute ((always_inline)) | ||
311 | re_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 | |||
321 | static void | ||
322 | re_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 | |||
487 | int | ||
488 | regcomp (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 | ||
542 | weak_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 | |||
548 | size_t | ||
549 | regerror(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 | ||
582 | weak_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 | ||
592 | static 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) */ | ||
597 | static bitset_t utf8_sb_map; | ||
598 | #endif /* __GNUC__ >= 3 */ | ||
599 | #endif /* RE_ENABLE_I18N */ | ||
600 | |||
601 | |||
602 | static void | ||
603 | free_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 | |||
652 | void | ||
653 | regfree (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 | ||
668 | weak_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. */ | ||
677 | static struct re_pattern_buffer re_comp_buf; | ||
678 | |||
679 | char * | ||
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. */ | ||
684 | weak_function | ||
685 | # endif | ||
686 | re_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 | ||
732 | libc_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 | |||
744 | static reg_errcode_t | ||
745 | re_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 (®exp, 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 (®exp); | ||
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 (®exp, 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 (®exp); | ||
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 | |||
843 | static reg_errcode_t | ||
844 | init_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 | |||
965 | static void | ||
966 | internal_function | ||
967 | init_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 | |||
979 | static void | ||
980 | free_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 | |||
998 | static reg_errcode_t | ||
999 | create_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 | |||
1083 | static void | ||
1084 | optimize_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 | |||
1153 | static reg_errcode_t | ||
1154 | analyze (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. */ | ||
1216 | static reg_errcode_t | ||
1217 | postorder (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 | |||
1248 | static reg_errcode_t | ||
1249 | preorder (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. */ | ||
1281 | static reg_errcode_t | ||
1282 | optimize_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. */ | ||
1312 | static reg_errcode_t | ||
1313 | lower_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 | |||
1334 | static bin_tree_t * | ||
1335 | lower_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. */ | ||
1371 | static reg_errcode_t | ||
1372 | calc_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. */ | ||
1393 | static reg_errcode_t | ||
1394 | calc_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). */ | ||
1416 | static reg_errcode_t | ||
1417 | link_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 | |||
1476 | static reg_errcode_t | ||
1477 | internal_function | ||
1478 | duplicate_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 | |||
1583 | static int | ||
1584 | search_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 | |||
1601 | static int | ||
1602 | duplicate_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 | |||
1617 | static reg_errcode_t | ||
1618 | calc_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 | |||
1640 | static reg_errcode_t | ||
1641 | calc_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 | |||
1684 | static reg_errcode_t | ||
1685 | calc_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 | |||
1765 | static void | ||
1766 | internal_function | ||
1767 | fetch_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 | |||
1775 | static int | ||
1776 | internal_function | ||
1777 | peek_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 | |||
2014 | static int | ||
2015 | internal_function | ||
2016 | peek_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 | |||
2111 | static bin_tree_t * | ||
2112 | parse (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 (¤t_token, regexp, syntax | RE_CARET_ANCHORS_HERE); | ||
2120 | tree = parse_reg_exp (regexp, preg, ¤t_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 | |||
2145 | static bin_tree_t * | ||
2146 | parse_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 | |||
2186 | static bin_tree_t * | ||
2187 | parse_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 | |||
2226 | static bin_tree_t * | ||
2227 | parse_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 | |||
2442 | static bin_tree_t * | ||
2443 | parse_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 | |||
2480 | static bin_tree_t * | ||
2481 | parse_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 | |||
2626 | static reg_errcode_t | ||
2627 | internal_function | ||
2628 | # ifdef RE_ENABLE_I18N | ||
2629 | build_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 */ | ||
2632 | build_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 | |||
2759 | static reg_errcode_t | ||
2760 | internal_function | ||
2761 | # ifdef RE_ENABLE_I18N | ||
2762 | build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset, | ||
2763 | int *coll_sym_alloc, const unsigned char *name) | ||
2764 | # else /* not RE_ENABLE_I18N */ | ||
2765 | build_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 | |||
2782 | static bin_tree_t * | ||
2783 | parse_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 | |||
3340 | static reg_errcode_t | ||
3341 | parse_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 | |||
3381 | static reg_errcode_t | ||
3382 | parse_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 | |||
3428 | static reg_errcode_t | ||
3429 | #ifdef RE_ENABLE_I18N | ||
3430 | build_equiv_class (bitset_t sbcset, re_charset_t *mbcset, | ||
3431 | int *equiv_class_alloc, const unsigned char *name) | ||
3432 | #else /* not RE_ENABLE_I18N */ | ||
3433 | build_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 | |||
3524 | static reg_errcode_t | ||
3525 | #ifdef RE_ENABLE_I18N | ||
3526 | build_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 */ | ||
3530 | build_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 | |||
3659 | static bin_tree_t * | ||
3660 | build_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 | |||
3772 | static int | ||
3773 | fetch_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 | ||
3793 | static void | ||
3794 | free_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 | |||
3812 | static bin_tree_t * | ||
3813 | create_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 | |||
3821 | static bin_tree_t * | ||
3822 | create_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 | |||
3858 | static reg_errcode_t | ||
3859 | mark_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 | |||
3870 | static void | ||
3871 | free_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 | |||
3885 | static reg_errcode_t | ||
3886 | free_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 | |||
3898 | static bin_tree_t * | ||
3899 | duplicate_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) | ||
87 | link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.") | ||
88 | int 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 | ||
42 | extern "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... */ | ||
49 | typedef long int s_reg_t; | ||
50 | typedef 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. */ | ||
57 | typedef 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. */ | ||
188 | extern 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. */ | ||
314 | typedef 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 | |||
363 | struct 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 | |||
429 | typedef struct re_pattern_buffer regex_t; | ||
430 | |||
431 | /* Type for byte offsets within the string. POSIX mandates this. */ | ||
432 | typedef 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. */ | ||
438 | struct 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. */ | ||
458 | typedef 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. */ | ||
469 | extern 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. */ | ||
474 | extern 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. */ | ||
481 | extern 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). */ | ||
489 | extern 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. */ | ||
496 | extern 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. */ | ||
504 | extern 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'. */ | ||
509 | extern 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. */ | ||
527 | extern 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. */ | ||
536 | extern char *re_comp (const char *); | ||
537 | extern 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. */ | ||
563 | extern int regcomp (regex_t *__restrict __preg, | ||
564 | const char *__restrict __pattern, | ||
565 | int __cflags); | ||
566 | |||
567 | extern 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 | |||
572 | extern size_t regerror (int __errcode, const regex_t *__restrict __preg, | ||
573 | char *__restrict __errbuf, size_t __errbuf_size); | ||
574 | |||
575 | extern 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 | |||
21 | static 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; | ||
25 | static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa, | ||
26 | const re_node_set *nodes, | ||
27 | unsigned int hash) internal_function; | ||
28 | static 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 */ | ||
35 | static int | ||
36 | MAX(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 | |||
47 | static reg_errcode_t | ||
48 | internal_function | ||
49 | re_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 | |||
75 | static reg_errcode_t | ||
76 | internal_function | ||
77 | re_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 | |||
138 | static reg_errcode_t | ||
139 | internal_function | ||
140 | re_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 | |||
178 | static void | ||
179 | internal_function | ||
180 | re_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 | |||
210 | static void | ||
211 | internal_function | ||
212 | build_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 | |||
278 | static reg_errcode_t | ||
279 | internal_function | ||
280 | build_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 | |||
494 | static int | ||
495 | internal_function | ||
496 | re_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 | |||
535 | static void | ||
536 | internal_function | ||
537 | build_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 | |||
558 | static void | ||
559 | internal_function | ||
560 | re_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 | |||
579 | static reg_errcode_t | ||
580 | internal_function | ||
581 | re_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 | |||
837 | static unsigned char | ||
838 | internal_function __attribute ((pure)) | ||
839 | re_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 | |||
873 | static unsigned char | ||
874 | internal_function __attribute ((pure)) | ||
875 | re_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 | |||
910 | static void | ||
911 | internal_function | ||
912 | re_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 | |||
924 | static unsigned int | ||
925 | internal_function | ||
926 | re_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 | |||
969 | static reg_errcode_t | ||
970 | internal_function | ||
971 | re_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 | |||
991 | static reg_errcode_t | ||
992 | internal_function | ||
993 | re_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 | |||
1007 | static reg_errcode_t | ||
1008 | internal_function | ||
1009 | re_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 | |||
1037 | static reg_errcode_t | ||
1038 | internal_function | ||
1039 | re_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 | |||
1062 | static reg_errcode_t | ||
1063 | internal_function | ||
1064 | re_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 | |||
1153 | static reg_errcode_t | ||
1154 | internal_function | ||
1155 | re_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 | |||
1206 | static reg_errcode_t | ||
1207 | internal_function | ||
1208 | re_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 | |||
1289 | static int | ||
1290 | internal_function | ||
1291 | re_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 | |||
1346 | static int | ||
1347 | internal_function | ||
1348 | re_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 | |||
1369 | static int | ||
1370 | internal_function __attribute ((pure)) | ||
1371 | re_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 | |||
1384 | static int | ||
1385 | internal_function __attribute ((pure)) | ||
1386 | re_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 | |||
1406 | static void | ||
1407 | internal_function | ||
1408 | re_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 | |||
1421 | static int | ||
1422 | internal_function | ||
1423 | re_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 | |||
1468 | static inline unsigned int | ||
1469 | internal_function | ||
1470 | calc_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 | |||
1488 | static re_dfastate_t * | ||
1489 | internal_function | ||
1490 | re_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 | |||
1532 | static re_dfastate_t * | ||
1533 | internal_function | ||
1534 | re_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 | |||
1569 | static reg_errcode_t | ||
1570 | register_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 | |||
1604 | static void | ||
1605 | free_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 | |||
1623 | static re_dfastate_t * | ||
1624 | internal_function | ||
1625 | create_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 | |||
1673 | static re_dfastate_t * | ||
1674 | internal_function | ||
1675 | create_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 | |||
72 | static int | ||
73 | is_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 | |||
166 | extern const char __re_error_msgid[] attribute_hidden; | ||
167 | extern 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. */ | ||
171 | typedef 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) | ||
178 | typedef bitset_word_t bitset_t[BITSET_WORDS]; | ||
179 | typedef bitset_word_t *re_bitset_ptr_t; | ||
180 | typedef 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 | |||
203 | typedef 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 | |||
217 | typedef struct | ||
218 | { | ||
219 | int alloc; | ||
220 | int nelem; | ||
221 | int *elems; | ||
222 | } re_node_set; | ||
223 | |||
224 | typedef 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 | ||
276 | typedef 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 | |||
323 | typedef 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 | |||
354 | struct 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 | }; | ||
409 | typedef struct re_string_t re_string_t; | ||
410 | |||
411 | |||
412 | struct re_dfa_t; | ||
413 | typedef 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 | ||
424 | static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr, | ||
425 | int new_buf_len) | ||
426 | internal_function; | ||
427 | # ifdef RE_ENABLE_I18N | ||
428 | static void build_wcs_buffer (re_string_t *pstr) internal_function; | ||
429 | static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr) | ||
430 | internal_function; | ||
431 | # endif /* RE_ENABLE_I18N */ | ||
432 | static void build_upper_buffer (re_string_t *pstr) internal_function; | ||
433 | static void re_string_translate_buffer (re_string_t *pstr) internal_function; | ||
434 | static 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 | |||
479 | struct 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 | }; | ||
493 | typedef struct bin_tree_t bin_tree_t; | ||
494 | |||
495 | #define BIN_TREE_STORAGE_SIZE \ | ||
496 | ((1024 - sizeof (void *)) / sizeof (bin_tree_t)) | ||
497 | |||
498 | struct bin_tree_storage_t | ||
499 | { | ||
500 | struct bin_tree_storage_t *next; | ||
501 | bin_tree_t data[BIN_TREE_STORAGE_SIZE]; | ||
502 | }; | ||
503 | typedef 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 | |||
533 | struct 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 | }; | ||
551 | typedef struct re_dfastate_t re_dfastate_t; | ||
552 | |||
553 | struct 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 | |||
562 | typedef 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 | |||
571 | typedef 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 | |||
582 | typedef 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 | |||
592 | struct 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 | |||
603 | typedef 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 | |||
630 | typedef 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 | |||
639 | struct 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 | |||
647 | struct re_fail_stack_t | ||
648 | { | ||
649 | int num; | ||
650 | int alloc; | ||
651 | struct re_fail_stack_ent_t *stack; | ||
652 | }; | ||
653 | |||
654 | struct 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 | |||
710 | typedef enum | ||
711 | { | ||
712 | SB_CHAR, | ||
713 | MB_CHAR, | ||
714 | EQUIV_CLASS, | ||
715 | COLL_SYM, | ||
716 | CHAR_CLASS | ||
717 | } bracket_elem_type; | ||
718 | |||
719 | typedef 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. */ | ||
732 | static inline void | ||
733 | bitset_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 | |||
740 | static inline void | ||
741 | bitset_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 | |||
748 | static inline void | ||
749 | bitset_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. */ | ||
758 | static inline int | ||
759 | internal_function __attribute ((pure)) | ||
760 | re_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 | |||
771 | static inline wint_t | ||
772 | internal_function __attribute ((pure)) | ||
773 | re_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 | ||
781 | static int | ||
782 | internal_function __attribute ((pure)) | ||
783 | re_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 | |||
21 | static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags, | ||
22 | int n) internal_function; | ||
23 | static void match_ctx_clean (re_match_context_t *mctx) internal_function; | ||
24 | static void match_ctx_free (re_match_context_t *cache) internal_function; | ||
25 | static 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; | ||
28 | static int search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx) | ||
29 | internal_function; | ||
30 | static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, int node, | ||
31 | int str_idx) internal_function; | ||
32 | static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop, | ||
33 | int node, int str_idx) | ||
34 | internal_function; | ||
35 | static 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; | ||
39 | static 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); | ||
44 | static 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); | ||
49 | static 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); | ||
53 | static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, | ||
54 | int nregs, int regs_allocated); | ||
55 | static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx); | ||
56 | static int check_matching (re_match_context_t *mctx, int fl_longest_match, | ||
57 | int *p_match_first) internal_function; | ||
58 | static int check_halt_state_context (const re_match_context_t *mctx, | ||
59 | const re_dfastate_t *state, int idx) | ||
60 | internal_function; | ||
61 | static 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; | ||
64 | static 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; | ||
69 | static 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; | ||
73 | static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs) | ||
74 | internal_function; | ||
75 | |||
76 | #ifdef RE_ENABLE_I18N | ||
77 | static 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 */ | ||
82 | static reg_errcode_t sift_states_backward (const re_match_context_t *mctx, | ||
83 | re_sift_context_t *sctx) | ||
84 | internal_function; | ||
85 | static 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; | ||
89 | static 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; | ||
94 | static 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; | ||
98 | static 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; | ||
102 | static 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; | ||
106 | static 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; | ||
110 | static 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; | ||
116 | static 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; | ||
120 | static 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; | ||
124 | static re_dfastate_t *find_recover_state (reg_errcode_t *err, | ||
125 | re_match_context_t *mctx) internal_function; | ||
126 | static re_dfastate_t *transit_state (reg_errcode_t *err, | ||
127 | re_match_context_t *mctx, | ||
128 | re_dfastate_t *state) internal_function; | ||
129 | static 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; | ||
133 | static 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 | ||
137 | static 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 | ||
143 | static reg_errcode_t transit_state_mb (re_match_context_t *mctx, | ||
144 | re_dfastate_t *pstate) | ||
145 | internal_function; | ||
146 | #endif /* RE_ENABLE_I18N */ | ||
147 | static reg_errcode_t transit_state_bkref (re_match_context_t *mctx, | ||
148 | const re_node_set *nodes) | ||
149 | internal_function; | ||
150 | static reg_errcode_t get_subexp (re_match_context_t *mctx, | ||
151 | int bkref_node, int bkref_str_idx) | ||
152 | internal_function; | ||
153 | static 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; | ||
158 | static int find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, | ||
159 | int subexp_idx, int type) internal_function; | ||
160 | static 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; | ||
164 | static 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; | ||
169 | static 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; | ||
173 | static 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; | ||
177 | static 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; | ||
181 | static int build_trtable (const re_dfa_t *dfa, | ||
182 | re_dfastate_t *state) internal_function; | ||
183 | #ifdef RE_ENABLE_I18N | ||
184 | static 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 | ||
188 | static 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 */ | ||
193 | static 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; | ||
197 | static int check_node_accept (const re_match_context_t *mctx, | ||
198 | const re_token_t *node, int idx) | ||
199 | internal_function; | ||
200 | static 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 | |||
219 | int | ||
220 | regexec ( | ||
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> | ||
257 | versioned_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 | |||
262 | int | ||
263 | attribute_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 | } | ||
271 | compat_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 | |||
304 | int | ||
305 | re_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 | ||
314 | weak_alias (__re_match, re_match) | ||
315 | #endif | ||
316 | |||
317 | int | ||
318 | re_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 | ||
326 | weak_alias (__re_search, re_search) | ||
327 | #endif | ||
328 | |||
329 | int | ||
330 | re_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 | ||
339 | weak_alias (__re_match_2, re_match_2) | ||
340 | #endif | ||
341 | |||
342 | int | ||
343 | re_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 | ||
352 | weak_alias (__re_search_2, re_search_2) | ||
353 | #endif | ||
354 | |||
355 | static int | ||
356 | re_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 | |||
399 | static int | ||
400 | re_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 | |||
486 | static unsigned | ||
487 | re_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 | |||
565 | void | ||
566 | re_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 | ||
587 | weak_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 | ||
594 | int | ||
595 | # ifdef _LIBC | ||
596 | weak_function | ||
597 | # endif | ||
598 | re_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 | |||
616 | static reg_errcode_t | ||
617 | re_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 | |||
940 | static reg_errcode_t | ||
941 | prune_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 | |||
1035 | static inline re_dfastate_t * | ||
1036 | __attribute ((always_inline)) internal_function | ||
1037 | acquire_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 | |||
1077 | static int | ||
1078 | internal_function | ||
1079 | check_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 | |||
1209 | static int | ||
1210 | internal_function | ||
1211 | check_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 | |||
1228 | static int | ||
1229 | internal_function | ||
1230 | check_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 | |||
1250 | static int | ||
1251 | internal_function | ||
1252 | proceed_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 | |||
1350 | static reg_errcode_t | ||
1351 | internal_function | ||
1352 | push_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 | |||
1377 | static int | ||
1378 | internal_function | ||
1379 | pop_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 | |||
1397 | static reg_errcode_t | ||
1398 | internal_function | ||
1399 | set_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 | |||
1506 | static reg_errcode_t | ||
1507 | internal_function | ||
1508 | free_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 | |||
1523 | static void | ||
1524 | internal_function | ||
1525 | update_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 | |||
1595 | static reg_errcode_t | ||
1596 | internal_function | ||
1597 | sift_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 | |||
1653 | static reg_errcode_t | ||
1654 | internal_function | ||
1655 | build_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 | |||
1715 | static reg_errcode_t | ||
1716 | internal_function | ||
1717 | clean_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 | |||
1740 | static reg_errcode_t | ||
1741 | internal_function | ||
1742 | merge_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 | |||
1767 | static reg_errcode_t | ||
1768 | internal_function | ||
1769 | update_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 | |||
1815 | static reg_errcode_t | ||
1816 | internal_function | ||
1817 | add_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 | |||
1844 | static reg_errcode_t | ||
1845 | internal_function | ||
1846 | sub_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 | |||
1893 | static int | ||
1894 | internal_function | ||
1895 | check_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 | |||
1929 | static int | ||
1930 | internal_function | ||
1931 | check_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 | |||
2010 | static int | ||
2011 | internal_function | ||
2012 | check_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 | |||
2040 | static reg_errcode_t | ||
2041 | internal_function | ||
2042 | check_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 | |||
2128 | static reg_errcode_t | ||
2129 | internal_function | ||
2130 | sift_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 | ||
2228 | static int | ||
2229 | internal_function | ||
2230 | sift_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 | |||
2258 | static re_dfastate_t * | ||
2259 | internal_function | ||
2260 | transit_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 */ | ||
2316 | static re_dfastate_t * | ||
2317 | internal_function | ||
2318 | merge_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. */ | ||
2395 | static re_dfastate_t * | ||
2396 | internal_function | ||
2397 | find_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 | |||
2426 | static reg_errcode_t | ||
2427 | internal_function | ||
2428 | check_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 | |||
2460 | static re_dfastate_t * | ||
2461 | transit_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 | ||
2499 | static reg_errcode_t | ||
2500 | internal_function | ||
2501 | transit_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 | |||
2569 | static reg_errcode_t | ||
2570 | internal_function | ||
2571 | transit_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 | |||
2683 | static reg_errcode_t | ||
2684 | internal_function | ||
2685 | get_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 | |||
2832 | static reg_errcode_t | ||
2833 | internal_function | ||
2834 | get_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 | |||
2861 | static int | ||
2862 | internal_function | ||
2863 | find_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 | |||
2883 | static reg_errcode_t | ||
2884 | internal_function | ||
2885 | check_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 | |||
3044 | static reg_errcode_t | ||
3045 | internal_function | ||
3046 | check_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 | |||
3125 | static reg_errcode_t | ||
3126 | internal_function | ||
3127 | check_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 | |||
3178 | static reg_errcode_t | ||
3179 | internal_function | ||
3180 | check_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 | |||
3222 | static reg_errcode_t | ||
3223 | internal_function | ||
3224 | expand_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 | |||
3311 | static int | ||
3312 | internal_function | ||
3313 | build_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 | { | ||
3394 | out_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 | |||
3549 | static int | ||
3550 | internal_function | ||
3551 | group_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 | |||
3739 | static int | ||
3740 | internal_function | ||
3741 | check_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 | ||
3981 | static unsigned int | ||
3982 | internal_function | ||
3983 | find_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 | |||
4044 | static int | ||
4045 | internal_function | ||
4046 | check_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 | |||
4094 | static reg_errcode_t | ||
4095 | internal_function | ||
4096 | extend_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 | |||
4157 | static reg_errcode_t | ||
4158 | internal_function | ||
4159 | match_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 | |||
4185 | static void | ||
4186 | internal_function | ||
4187 | match_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 | |||
4215 | static void | ||
4216 | internal_function | ||
4217 | match_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 | |||
4230 | static reg_errcode_t | ||
4231 | internal_function | ||
4232 | match_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 | |||
4279 | static int | ||
4280 | internal_function | ||
4281 | search_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 | |||
4302 | static reg_errcode_t | ||
4303 | internal_function | ||
4304 | match_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 | |||
4332 | static re_sub_match_last_t * | ||
4333 | internal_function | ||
4334 | match_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 | |||
4359 | static void | ||
4360 | internal_function | ||
4361 | sift_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 @@ | |||
1 | This work is licenced under the Creative Commons Attribution-Share Alike 3.0 | ||
2 | United States License. To view a copy of this licence, visit | ||
3 | http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative | ||
4 | Commons, 171 Second Street, Suite 300, San Francisco, California 94105, USA. | ||
5 | |||
6 | When attributing the artwork, using "GNOME Project" is enough. | ||
7 | Please 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 | |||
7 | obj-y := | ||
8 | |||
9 | obj-$(CONFIG_FEATURE_RESOURCES) += resources.o | ||
10 | |||
11 | # return commit level if available or 0 | ||
12 | bb_level = $(or $(word 2,$(subst -, ,$1)),0) | ||
13 | |||
14 | WRFLAGS := -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 | |||
20 | quiet_cmd_windres = WINDRES $@ | ||
21 | cmd_windres = $(WINDRES) $(WRFLAGS) $< $@ | ||
22 | |||
23 | %.o: %.rc FORCE | ||
24 | $(call if_changed,windres) | ||
25 | |||
26 | win32/resources/resources.o: win32/resources/resources.rc .config | ||
27 | win32/resources/resources.o: win32/resources/aterm.ico win32/resources/sterm.ico | ||
28 | win32/resources/resources.o: win32/resources/utf8.manifest | ||
29 | win32/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 @@ | |||
1 | The icons are based on those for GNOME terminal in the Adwaita theme. | ||
2 | |||
3 | They were generated by importing the 16x16, 32x32 and 48x48 PNG files | ||
4 | into GIMP as separate layers then exporting as a single .ico file. | ||
5 | |||
6 | The original files are dual-licensed under either the GNU LGPL v3 or | ||
7 | Creative Commons Attribution-Share Alike 3.0 United States License. | ||
8 | |||
9 | The .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 | ||
6 | 1 ICON "aterm.ico" | ||
7 | #endif | ||
8 | #if ENABLE_FEATURE_ICON_STERM || ENABLE_FEATURE_ICON_ALL | ||
9 | 2 ICON "sterm.ico" | ||
10 | #endif | ||
11 | |||
12 | #if ENABLE_FEATURE_VERSIONINFO | ||
13 | 1 VERSIONINFO | ||
14 | FILEVERSION BB_VERSION,BB_PATCHLEVEL,BB_SUBLEVEL,BB_EXTRAVERSION | ||
15 | PRODUCTVERSION BB_VERSION,BB_PATCHLEVEL,BB_SUBLEVEL,BB_EXTRAVERSION | ||
16 | BEGIN | ||
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 | ||
35 | END | ||
36 | #endif | ||
37 | |||
38 | /* Hardcode numeric value for MANIFEST for llvm windres */ | ||
39 | #if ENABLE_FEATURE_UTF8_MANIFEST | ||
40 | 1 24 "utf8.manifest" | ||
41 | #endif | ||
42 | |||
43 | #if ENABLE_FEATURE_APP_MANIFEST | ||
44 | 1 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 | |||
62 | struct 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. */ | ||
68 | typedef 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 | |||
81 | typedef 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 | |||
90 | typedef enum _FILE_INFORMATION_CLASS { | ||
91 | FilePipeLocalInformation = 24 | ||
92 | } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; | ||
93 | |||
94 | typedef 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 | |||
101 | static BOOL IsConsoleHandle (HANDLE h) | ||
102 | { | ||
103 | DWORD mode; | ||
104 | return GetConsoleMode (h, &mode) != 0; | ||
105 | } | ||
106 | |||
107 | static BOOL | ||
108 | IsSocketHandle (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 | |||
125 | static int | ||
126 | windows_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 | |||
260 | int | ||
261 | mingw_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 | |||
415 | restart: | ||
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 | |||
560 | int | ||
561 | rpl_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 | */ | ||
10 | static 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 | |||
34 | ssize_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 | */ | ||
7 | int statfs(const char *file, struct statfs *buf) | ||
8 | { | ||
9 | ULONGLONG free_bytes_available; /* for user - similar to bavail */ | ||
10 | ULONGLONG total_number_of_bytes; | ||
11 | ULONGLONG total_number_of_free_bytes; /* for everyone - bfree */ | ||
12 | DWORD serial, namelen, flags; | ||
13 | char fsname[100]; | ||
14 | struct mntent *mnt; | ||
15 | /* 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 | |||
25 | char * | ||
26 | strndup (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 | |||
36 | enum 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 | |||
70 | static char const weekday_name[][10] = | ||
71 | { | ||
72 | "Sunday", "Monday", "Tuesday", "Wednesday", | ||
73 | "Thursday", "Friday", "Saturday" | ||
74 | }; | ||
75 | static char const ab_weekday_name[][4] = | ||
76 | { | ||
77 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" | ||
78 | }; | ||
79 | static char const month_name[][10] = | ||
80 | { | ||
81 | "January", "February", "March", "April", "May", "June", | ||
82 | "July", "August", "September", "October", "November", "December" | ||
83 | }; | ||
84 | static 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 | |||
96 | static 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. */ | ||
117 | static void | ||
118 | day_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. */ | ||
136 | static void | ||
137 | day_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 | |||
144 | static 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 | |||
585 | char * | ||
586 | strptime (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 | |||
594 | char * | ||
595 | mingw_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 | ---------------------------------------------------------------------- | ||
7 | Copyright © 2005-2020 Rich Felker, et al. | ||
8 | |||
9 | Permission is hereby granted, free of charge, to any person obtaining | ||
10 | a copy of this software and associated documentation files (the | ||
11 | "Software"), to deal in the Software without restriction, including | ||
12 | without limitation the rights to use, copy, modify, merge, publish, | ||
13 | distribute, sublicense, and/or sell copies of the Software, and to | ||
14 | permit persons to whom the Software is furnished to do so, subject to | ||
15 | the following conditions: | ||
16 | |||
17 | The above copyright notice and this permission notice shall be | ||
18 | included in all copies or substantial portions of the Software. | ||
19 | |||
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
23 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
25 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
26 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
27 | ---------------------------------------------------------------------- | ||
28 | */ | ||
29 | #include "libbb.h" | ||
30 | #include <ctype.h> | ||
31 | #include <string.h> | ||
32 | |||
33 | int 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 | |||
6 | struct 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 | |||
6 | struct statfs { | ||
7 | int f_type; | ||
8 | uint64_t f_bsize; | ||
9 | uint64_t f_frsize; | ||
10 | uint64_t f_blocks; | ||
11 | uint64_t f_bfree; | ||
12 | uint64_t f_bavail; | ||
13 | uint64_t f_files; | ||
14 | uint64_t f_ffree; | ||
15 | uint64_t f_fsid; | ||
16 | uint64_t f_flag; | ||
17 | uint64_t f_namelen; | ||
18 | }; | ||
19 | |||
20 | extern int statfs(const char *file, struct statfs *buf); | ||
21 | |||
22 | #endif | ||
diff --git a/win32/sys/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. */ | ||
45 | struct utsname | ||
46 | { | ||
47 | /* Name of the implementation of the operating system. */ | ||
48 | char sysname[_UTSNAME_SYSNAME_LENGTH]; | ||
49 | |||
50 | /* Name of this node on the network. */ | ||
51 | char nodename[_UTSNAME_NODENAME_LENGTH]; | ||
52 | |||
53 | /* Current release level of this implementation. */ | ||
54 | char release[_UTSNAME_RELEASE_LENGTH]; | ||
55 | /* Current version level of this release. */ | ||
56 | char version[_UTSNAME_VERSION_LENGTH]; | ||
57 | |||
58 | /* Name of the hardware type the system is running on. */ | ||
59 | char machine[_UTSNAME_MACHINE_LENGTH]; | ||
60 | }; | ||
61 | |||
62 | /* Put information about the system in NAME. */ | ||
63 | extern int uname (struct utsname *__name); | ||
64 | |||
65 | |||
66 | #endif /* sys/utsname.h */ | ||
diff --git a/win32/sys/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 | |||
3 | int 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 | |||
3 | int 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 | |||
16 | int 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 | |||
31 | int64_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 | |||
13 | typedef unsigned char cc_t; | ||
14 | typedef unsigned int speed_t; | ||
15 | |||
16 | #define NCCS 2 | ||
17 | struct termios { | ||
18 | cc_t c_cc[NCCS]; | ||
19 | unsigned long imode; | ||
20 | unsigned long omode; | ||
21 | }; | ||
22 | |||
23 | struct winsize { | ||
24 | unsigned short ws_row, ws_col; | ||
25 | unsigned short ws_xpixel, ws_ypixel; | ||
26 | }; | ||
27 | |||
28 | int tcgetattr(int fd, struct termios *t); | ||
29 | int 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 | ---------------------------------------------------------------------- | ||
7 | Copyright © 2005-2020 Rich Felker, et al. | ||
8 | |||
9 | Permission is hereby granted, free of charge, to any person obtaining | ||
10 | a copy of this software and associated documentation files (the | ||
11 | "Software"), to deal in the Software without restriction, including | ||
12 | without limitation the rights to use, copy, modify, merge, publish, | ||
13 | distribute, sublicense, and/or sell copies of the Software, and to | ||
14 | permit persons to whom the Software is furnished to do so, subject to | ||
15 | the following conditions: | ||
16 | |||
17 | The above copyright notice and this permission notice shall be | ||
18 | included in all copies or substantial portions of the Software. | ||
19 | |||
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
23 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
25 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
26 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
27 | ---------------------------------------------------------------------- | ||
28 | */ | ||
29 | #include "libbb.h" | ||
30 | |||
31 | static 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 | |||
78 | static 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 | |||
89 | static 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 | */ | ||
119 | time_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 | |||
5 | int uname(struct utsname *name) | ||
6 | { | ||
7 | const char *unk = "unknown"; | ||
8 | OSVERSIONINFO os_info; | ||
9 | SYSTEM_INFO sys_info; | ||
10 | |||
11 | strcpy(name->sysname, "Windows_NT"); | ||
12 | |||
13 | if ( gethostname(name->nodename, sizeof(name->nodename)) != 0 ) { | ||
14 | strcpy(name->nodename, unk); | ||
15 | } | ||
16 | |||
17 | memset(&os_info, 0, sizeof(OSVERSIONINFO)); | ||
18 | os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | ||
19 | |||
20 | 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 | |||
10 | static BOOL charToConBuffA(LPSTR s, DWORD len); | ||
11 | static BOOL charToConA(LPSTR s); | ||
12 | |||
13 | static int conv_fwriteCon(FILE *stream, char *buf, size_t siz); | ||
14 | static 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 | |||
37 | static WORD plain_attr = 0xffff; | ||
38 | static WORD current_attr; | ||
39 | |||
40 | static HANDLE get_console(void) | ||
41 | { | ||
42 | return GetStdHandle(STD_OUTPUT_HANDLE); | ||
43 | } | ||
44 | |||
45 | static 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 | |||
55 | static 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 | |||
62 | static ALWAYS_INLINE int is_console_in(int fd) | ||
63 | { | ||
64 | return isatty(fd) && GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE; | ||
65 | } | ||
66 | |||
67 | static 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 | |||
86 | int 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 | |||
180 | void set_title(const char *str) | ||
181 | { | ||
182 | SetConsoleTitle(str); | ||
183 | } | ||
184 | |||
185 | int get_title(char *buf, int len) | ||
186 | { | ||
187 | return GetConsoleTitle(buf, len); | ||
188 | } | ||
189 | |||
190 | static 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 | |||
200 | static 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 | |||
248 | static 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 | |||
257 | static 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 | |||
267 | static 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 | |||
280 | void 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 | |||
293 | void 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 | |||
304 | static 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 | |||
315 | static 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 | |||
328 | static 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 | ||
349 | static 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 */ | ||
382 | static 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 */ | ||
403 | static 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 | |||
433 | static 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 */ | ||
458 | static 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 */ | ||
475 | static 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 | |||
514 | static 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. */ | ||
536 | static 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 | |||
721 | static 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 | |||
743 | static BOOL charToConA(LPSTR s) | ||
744 | { | ||
745 | if (!s) | ||
746 | return FALSE; | ||
747 | return charToConBuffA(s, strlen(s)+1); | ||
748 | } | ||
749 | |||
750 | BOOL 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 | |||
777 | static 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 | |||
848 | int winansi_putchar(int c) | ||
849 | { | ||
850 | return winansi_fputc(c, stdout); | ||
851 | } | ||
852 | |||
853 | int winansi_puts(const char *s) | ||
854 | { | ||
855 | return (winansi_fputs(s, stdout) == EOF || putchar('\n') == EOF) ? EOF : 0; | ||
856 | } | ||
857 | |||
858 | static sighandler_t sigpipe_handler = SIG_DFL; | ||
859 | |||
860 | #undef signal | ||
861 | sighandler_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 | |||
873 | static 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 | |||
887 | static 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 | |||
896 | size_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 | |||
921 | int 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 | |||
935 | int 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 | */ | ||
956 | int 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 | |||
973 | int 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 | |||
1003 | abort: | ||
1004 | SetLastError(0); | ||
1005 | if ((rv=vfprintf(stream, format, list)) == EOF || ferror(stream) != 0) | ||
1006 | check_pipe(stream); | ||
1007 | return rv; | ||
1008 | } | ||
1009 | |||
1010 | int 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 | |||
1022 | int 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 | |||
1034 | static 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 | |||
1101 | int 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 | |||
1116 | int 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 | |||
1131 | size_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 | |||
1145 | int 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 | |||
1163 | int winansi_getchar(void) | ||
1164 | { | ||
1165 | return winansi_getc(stdin); | ||
1166 | } | ||
1167 | |||
1168 | char *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 */ | ||
1183 | int 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) | ||
1207 | static 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 | ||
1239 | static 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. | ||
1284 | static 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 | */ | ||
1355 | BOOL 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 | */ | ||
1418 | BOOL 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?) | ||
1448 | static 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 | |||
1534 | void 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. | ||
1545 | static 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 | ||
1580 | static 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 | ||
1597 | static 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 | } | ||