aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2022-11-07 11:15:43 +0000
committerRon Yorston <rmy@pobox.com>2022-11-07 13:49:46 +0000
commitf8aeca9d9e387be17c8ee96da47e2aea146dc8ee (patch)
tree756435ed2f6cd82a5c460b90ef2aea890f66f79e
parent9cd72d5b32e371b085afc740e8b4c4f2cac152fa (diff)
downloadbusybox-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.c229
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, ...);
302static void cprint_done(void); 304static void cprint_done(void);
303static int cprint(const char *fmt, ...); 305static int cprint(const char *fmt, ...);
304 306
307#ifdef __MINGW32__
308struct winsize {
309 unsigned short ws_row, ws_col;
310 unsigned short ws_xpixel, ws_ypixel;
311};
312
313static int mingw_get_terminal_width_height(struct winsize *win)
314{
315 int fd;
316 HANDLE handle;
317 CONSOLE_SCREEN_BUFFER_INFO sbi;
318
319 win->ws_row = 0;
320 win->ws_col = 0;
321
322 for (fd=STDOUT_FILENO; fd<=STDERR_FILENO; ++fd) {
323 handle = (HANDLE)_get_osfhandle(fd);
324 if (handle != INVALID_HANDLE_VALUE &&
325 GetConsoleScreenBufferInfo(handle, &sbi) != 0) {
326 win->ws_row = sbi.srWindow.Bottom - sbi.srWindow.Top + 1;
327 win->ws_col = sbi.srWindow.Right - sbi.srWindow.Left + 1;
328 return 0;
329 }
330 }
331
332 return -1;
333}
334#endif
335
305static void init_wsize(void) 336static 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
344static void cprint_init(void) 375static 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__
508static char *
509quote_arg(const char *arg)
510{
511 int len = 0, n = 0;
512 int force_quotes = 0;
513 char *q, *d;
514 const char *p = arg;
515
516 /* empty arguments must be quoted */
517 if (!*p) {
518 force_quotes = 1;
519 }
520
521 while (*p) {
522 if (isspace(*p)) {
523 /* arguments containing whitespace must be quoted */
524 force_quotes = 1;
525 }
526 else if (*p == '"') {
527 /* double quotes in arguments need to be escaped */
528 n++;
529 }
530 else if (*p == '\\') {
531 /* count contiguous backslashes */
532 int count = 0;
533 while (*p == '\\') {
534 count++;
535 p++;
536 len++;
537 }
538
539 /*
540 * Only escape backslashes before explicit double quotes or
541 * or where the backslashes are at the end of an argument
542 * that is scheduled to be quoted.
543 */
544 if (*p == '"' || (force_quotes && *p == '\0')) {
545 n += count*2 + 1;
546 }
547
548 if (*p == '\0') {
549 break;
550 }
551 continue;
552 }
553 len++;
554 p++;
555 }
556
557 if (!force_quotes && n == 0) {
558 return (char*)strdup(arg);
559 }
560
561 /* insert double quotes and backslashes where necessary */
562 d = q = malloc(len+n+3);
563 if (q == NULL)
564 return NULL;
565 if (force_quotes) {
566 *d++ = '"';
567 }
568
569 while (*arg) {
570 if (*arg == '"') {
571 *d++ = '\\';
572 }
573 else if (*arg == '\\') {
574 int count = 0;
575 while (*arg == '\\') {
576 count++;
577 *d++ = *arg++;
578 }
579
580 if (*arg == '"' || (force_quotes && *arg == '\0')) {
581 while (count-- > 0) {
582 *d++ = '\\';
583 }
584 if (*arg == '"') {
585 *d++ = '\\';
586 }
587 }
588 }
589 if (*arg != '\0') {
590 *d++ = *arg++;
591 }
592 }
593 if (force_quotes) {
594 *d++ = '"';
595 }
596 *d = '\0';
597
598 return q;
599}
600
601static int mingw_pipe(HANDLE *pipe)
602{
603 SECURITY_ATTRIBUTES sa;
604
605 sa.nLength = sizeof(sa); /* Length in bytes */
606 sa.bInheritHandle = 1; /* the child must inherit these handles */
607 sa.lpSecurityDescriptor = NULL;
608
609 /* pipe[0] is the read handle, pipe[i] the write handle */
610 if ( !CreatePipe (&pipe[0], &pipe[1], &sa, 1 << 13) ) {
611 return -1;
612 }
613
614 return (pipe[0] == INVALID_HANDLE_VALUE ||
615 pipe[1] == INVALID_HANDLE_VALUE) ? -1 : 0;
616}
617#endif
618
476static int exec_conf(void) 619static 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;