diff options
author | Ron Yorston <rmy@pobox.com> | 2022-11-07 11:15:43 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2022-11-07 13:49:46 +0000 |
commit | f8aeca9d9e387be17c8ee96da47e2aea146dc8ee (patch) | |
tree | 756435ed2f6cd82a5c460b90ef2aea890f66f79e | |
parent | 9cd72d5b32e371b085afc740e8b4c4f2cac152fa (diff) | |
download | busybox-w32-f8aeca9d9e387be17c8ee96da47e2aea146dc8ee.tar.gz busybox-w32-f8aeca9d9e387be17c8ee96da47e2aea146dc8ee.tar.bz2 busybox-w32-f8aeca9d9e387be17c8ee96da47e2aea146dc8ee.zip |
win32: allow 'make menuconfig' in native builds
'make menuconfig' is a build option to allow changes to be made
to the BusyBox configuration. It's a bit friendlier than using
a text editor on the .config file.
Previously 'menuconfig' was only available when cross-compiling
on a Linux/Unix platform. The 'mconf' build program has been
ported to WIN32 so it's now able to run the 'lxdialog' program
which displays the configuration dialogs.
Building 'lxdialog' is somewhat awkward in MSYS2. The MINGW32/64
build environments generate WIN32 executables for 'lxdialog'.
These doesn't work properly in the MSYS2 console.
For 'menuconfig' to work it's necessary to run it in an MSYS
build environment. This generates an MSYS binary which works
in the MSYS2 console. busybox-w32 should then be built in a
MINGW32/64 build environment. Doing so will generate additional
copies of the build programs without a '.exe' suffix: the MSYS
build environment adds '.exe' to binaries it builds. This breaks
'menuconfig'.
To configure an MSYS build environment use:
pacman -S gcc ncurses-devel
-rw-r--r-- | scripts/kconfig/mconf.c | 229 |
1 files changed, 223 insertions, 6 deletions
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 55afeb763..1112daa56 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c | |||
@@ -15,6 +15,8 @@ | |||
15 | #ifndef __MINGW32__ | 15 | #ifndef __MINGW32__ |
16 | #include <sys/ioctl.h> | 16 | #include <sys/ioctl.h> |
17 | #include <sys/wait.h> | 17 | #include <sys/wait.h> |
18 | #else | ||
19 | #include <windows.h> | ||
18 | #endif | 20 | #endif |
19 | #include <ctype.h> | 21 | #include <ctype.h> |
20 | #include <errno.h> | 22 | #include <errno.h> |
@@ -302,15 +304,45 @@ static int cprint1(const char *fmt, ...); | |||
302 | static void cprint_done(void); | 304 | static void cprint_done(void); |
303 | static int cprint(const char *fmt, ...); | 305 | static int cprint(const char *fmt, ...); |
304 | 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 | |||
305 | static void init_wsize(void) | 336 | static void init_wsize(void) |
306 | { | 337 | { |
307 | #ifdef __MINGW32__ | ||
308 | fprintf(stderr, "Skipping attempt to change window size\n"); | ||
309 | #else | ||
310 | struct winsize ws; | 338 | struct winsize ws; |
311 | char *env; | 339 | char *env; |
312 | 340 | ||
341 | #ifndef __MINGW32__ | ||
313 | 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 | ||
314 | rows = ws.ws_row; | 346 | rows = ws.ws_row; |
315 | cols = ws.ws_col; | 347 | cols = ws.ws_col; |
316 | } | 348 | } |
@@ -338,7 +370,6 @@ static void init_wsize(void) | |||
338 | 370 | ||
339 | rows -= 4; | 371 | rows -= 4; |
340 | cols -= 5; | 372 | cols -= 5; |
341 | #endif | ||
342 | } | 373 | } |
343 | 374 | ||
344 | static void cprint_init(void) | 375 | static void cprint_init(void) |
@@ -473,11 +504,197 @@ static void winch_handler(int sig) | |||
473 | } | 504 | } |
474 | #endif | 505 | #endif |
475 | 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 | |||
476 | static int exec_conf(void) | 619 | static int exec_conf(void) |
477 | { | 620 | { |
478 | #ifdef __MINGW32__ | 621 | #ifdef __MINGW32__ |
479 | fprintf(stderr, "exec_conf not implemented\n"); | 622 | char **a, *cmd; |
480 | exit(1); | 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; | ||
481 | #else | 698 | #else |
482 | int pipefd[2], stat, size; | 699 | int pipefd[2], stat, size; |
483 | sigset_t sset, osset; | 700 | sigset_t sset, osset; |