Ticket #4114: persistent_subshell_command_buffer4.patch
File persistent_subshell_command_buffer4.patch, 26.2 KB (added by congest, 4 years ago) |
---|
-
src/execute.c
diff --git a/src/execute.c b/src/execute.c index d9b306e67..f35c53d94 100644
a b toggle_subshell (void) 551 551 { 552 552 if (mc_global.mc_run_mode == MC_RUN_FULL) 553 553 { 554 do_load_prompt ();555 554 if (new_dir_vpath != NULL) 556 555 do_possible_cd (new_dir_vpath); 557 556 } -
src/filemanager/layout.c
diff --git a/src/filemanager/layout.c b/src/filemanager/layout.c index dfffa96f5..56318d99d 100644
a b load_prompt (int fd, void *unused) 1497 1497 { 1498 1498 (void) fd; 1499 1499 (void) unused; 1500 1501 do_load_prompt (); 1500 if (should_read_new_subshell_prompt) 1501 do_load_prompt (); 1502 else 1503 flush_subshell(0, QUIETLY); 1502 1504 return 0; 1503 1505 } 1504 1506 #endif /* ENABLE_SUBSHELL */ -
src/subshell/common.c
diff --git a/src/subshell/common.c b/src/subshell/common.c index 06699233c..256c3df85 100644
a b 15 15 Claes Nästén <me@pekdon.net> 16 16 Egmont Koblinger <egmont@gmail.com> 17 17 Enrico Weigelt, metux IT service <weigelt@metux.de> 18 Eric Roberts <ericmrobertsdeveloper@gmail.com> 18 19 Igor Urazov <z0rc3r@gmail.com> 19 20 Ilia Maslakov <il.smind@gmail.com> 20 21 Leonard den Ottolander <leonard@den.ottolander.nl> … … 105 106 #include "lib/util.h" 106 107 #include "lib/widget.h" 107 108 109 #include "src/filemanager/layout.h" /* setup_cmdline() */ 110 #include "src/filemanager/command.h" /* cmdline */ 111 108 112 #include "subshell.h" 109 113 #include "internal.h" 110 114 … … GString *subshell_prompt = NULL; 123 127 /* We need to paint it after CONSOLE_RESTORE, see: load_prompt */ 124 128 gboolean update_subshell_prompt = FALSE; 125 129 130 /* If set, then a command has just finished executing, and we need */ 131 /* to be on the lookout for a new prompt string from the subshell. */ 132 gboolean should_read_new_subshell_prompt; 133 126 134 /*** file scope macro definitions ****************************************************************/ 127 135 128 136 #ifndef WEXITSTATUS … … enum 151 159 WRITE = 1 152 160 }; 153 161 162 /* This is the keybinding that is sent to the shell, to make the shell send us the contents of 163 * the current command buffer. */ 164 #define SHELL_BUFFER_KEYBINDING "_" 165 166 /* This is the keybinding that is sent to the shell, to make the shell send us the location of 167 * the cursor. */ 168 #define SHELL_CURSOR_KEYBINDING "+" 169 154 170 /*** file scope variables ************************************************************************/ 155 171 156 172 /* tcsh closes all non-standard file descriptors, so we have to use a pipe */ … … static char pty_buffer[PTY_BUFFER_SIZE] = "\0"; 169 185 /* To pass CWD info from the subshell to MC */ 170 186 static int subshell_pipe[2]; 171 187 188 /* To pass command buffer info from the subshell to MC */ 189 static int command_buffer_pipe[2]; 190 172 191 /* The subshell's process ID */ 173 192 static pid_t subshell_pid = 1; 174 193 … … static char subshell_cwd[MC_MAXPATHLEN + 1]; 178 197 /* Flag to indicate whether the subshell is ready for next command */ 179 198 static int subshell_ready; 180 199 200 /* Flag to indicate if the subshell supports the persistent buffer feature. */ 201 static gboolean use_persistent_buffer = FALSE; 202 203 /* Flag to indicate if the contents of the subshell command line need to be cleared before */ 204 /* executing a command. This should only end up set to true if there is some sort of error.*/ 205 /* This allows us to recover gracefully from an error.*/ 206 static gboolean subshell_should_clear_command_line = FALSE; 207 208 /* This is the local variable where the subshell prompt is stored while we are working on it. */ 209 static GString *subshell_prompt_temp_buffer = NULL; 210 181 211 /* The following two flags can be changed by the SIGCHLD handler. This is */ 182 212 /* OK, because the 'int' type is updated atomically on all known machines */ 183 213 static volatile int subshell_alive, subshell_stopped; … … init_subshell_child (const char *pty_name) 362 392 dup2 (subshell_pty_slave, STDERR_FILENO); 363 393 364 394 close (subshell_pipe[READ]); 395 if (use_persistent_buffer == TRUE) 396 close (command_buffer_pipe[READ]); 365 397 close (subshell_pty_slave); /* These may be FD_CLOEXEC, but just in case... */ 366 398 /* Close master side of pty. This is important; apart from */ 367 399 /* freeing up the descriptor for use in the subshell, it also */ … … synchronize (void) 469 501 } 470 502 471 503 /* --------------------------------------------------------------------------------------------- */ 504 /* Get the contents of the current subshell command line buffer, and */ 505 /* transfer the contents to the panel command prompt. */ 506 507 static gboolean 508 read_command_line_buffer(gboolean test_mode) 509 { 510 fd_set read_set; 511 int i; 512 ssize_t bytes; 513 char subshell_command_buffer[BUF_LARGE]; 514 char subshell_cursor_buffer[BUF_SMALL]; 515 struct timeval subshell_prompt_timer = { 0, 0 }; 516 int command_buffer_length; 517 int command_buffer_char_length; 518 int cursor_position; 519 int maxfdp; 520 int rc; 521 char *end; 522 523 if (use_persistent_buffer == TRUE) 524 { 525 FD_ZERO (&read_set); 526 FD_SET (command_buffer_pipe[READ], &read_set); 527 maxfdp = command_buffer_pipe[READ]; 528 /* First, flush the command buffer pipe. This pipe shouldn't be written 529 * to under normal circumstances, but if it somehow does get written 530 * to, we need to make sure to discard whatever data is there before 531 * we try to use it. */ 532 while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 0) 533 { 534 if (rc == -1) 535 { 536 if (errno == EINTR) 537 continue; 538 else 539 return FALSE; 540 } 541 else if (rc == 1) 542 read (command_buffer_pipe[READ], subshell_command_buffer, sizeof(subshell_command_buffer)); 543 } 544 /* get contents of command line buffer */ 545 write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_BUFFER_KEYBINDING, 546 sizeof(ESC_STR SHELL_CURSOR_KEYBINDING) - 1); 547 subshell_prompt_timer.tv_sec = 1; 548 FD_ZERO (&read_set); 549 FD_SET (command_buffer_pipe[READ], &read_set); 550 while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 1) 551 { 552 if (rc == -1) 553 { 554 if (errno == EINTR) 555 continue; 556 else 557 return FALSE; 558 } 559 else if (rc == 0) 560 return FALSE; 561 } 562 563 bytes = read (command_buffer_pipe[READ], subshell_command_buffer, sizeof(subshell_command_buffer)); 564 if (bytes == sizeof(subshell_command_buffer)) 565 return FALSE; 566 if (bytes == 0) 567 return FALSE; 568 subshell_command_buffer[bytes - 1] = 0; 569 command_buffer_char_length = bytes - 1; 570 command_buffer_length = str_length(subshell_command_buffer); 571 572 /* get cursor position */ 573 write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_CURSOR_KEYBINDING, 574 sizeof(ESC_STR SHELL_CURSOR_KEYBINDING) - 1); 575 subshell_prompt_timer.tv_sec = 1; 576 subshell_prompt_timer.tv_usec = 0; 577 FD_ZERO (&read_set); 578 FD_SET (command_buffer_pipe[READ], &read_set); 579 while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 1) 580 { 581 if (rc == -1) 582 { 583 if (errno == EINTR) 584 continue; 585 else 586 return FALSE; 587 } 588 else if (rc == 0) 589 return FALSE; 590 } 591 bytes = read (command_buffer_pipe[READ], subshell_cursor_buffer, sizeof(subshell_cursor_buffer)); 592 if (bytes == 0) 593 return FALSE; 594 subshell_cursor_buffer[bytes - 1] = 0; 595 cursor_position = strtol(subshell_cursor_buffer, &end, 10); 596 if (end == subshell_cursor_buffer) 597 return FALSE; 598 599 if (test_mode == TRUE) 600 return TRUE; 601 /* Erase non-text characters in the command buffer, such as tab, or newline, as this 602 * could cause problems. */ 603 for(i = 0;i < command_buffer_char_length;i++) 604 { 605 if ((unsigned char) subshell_command_buffer[i] < 32 606 || (unsigned char)subshell_command_buffer[i] == 127) 607 subshell_command_buffer[i] = ' '; 608 } 609 input_assign_text (cmdline, ""); 610 input_insert (cmdline, subshell_command_buffer, 0); 611 612 if (mc_global.shell->type == SHELL_BASH) 613 { 614 /* We need to do this because bash gives the cursor position in a utf-8 string based 615 * on the location in bytes, not in unicode characters. */ 616 for (i = 0;i < command_buffer_length;i++) 617 if (str_offset_to_pos(subshell_command_buffer, i) == cursor_position) 618 break; 619 cursor_position = i; 620 } 621 if (cursor_position > command_buffer_length) 622 cursor_position = command_buffer_length; 623 cmdline->point = cursor_position; 624 /* We send any remaining data to STDOUT before we finish. */ 625 flush_subshell(0, VISIBLY); 626 627 /* Now we erase the current contents of the command line buffer */ 628 if (mc_global.shell->type != SHELL_ZSH) 629 /* In zsh, we can just press c-u to clear the line, without needing to go to the end of 630 * the line first first. In all other shells, we must go to the end of the line first. */ 631 { 632 /* If we are not at the end of the line, we go to the end. */ 633 if (cursor_position != command_buffer_length) 634 { 635 write_all (mc_global.tty.subshell_pty, "\005", 1); 636 if (flush_subshell(1, VISIBLY) != 1) 637 return FALSE; 638 } 639 } 640 if (command_buffer_length > 0) /* Now we clear the line. */ 641 { 642 write_all (mc_global.tty.subshell_pty, "\025", 1); 643 if (flush_subshell(1, VISIBLY) != 1) 644 return FALSE; 645 } 646 } 647 return TRUE; 648 } 649 650 /* --------------------------------------------------------------------------------------------- */ 651 652 static void 653 clear_subshell_prompt_string (void) 654 { 655 if(subshell_prompt_temp_buffer != NULL) 656 g_string_set_size (subshell_prompt_temp_buffer, 0); 657 } 658 659 /* --------------------------------------------------------------------------------------------- */ 660 661 static void 662 parse_subshell_prompt_string (const char *buffer, int bytes) 663 { 664 int i; 665 666 /* First time through */ 667 if (subshell_prompt == NULL) 668 { 669 subshell_prompt = g_string_sized_new (INITIAL_PROMPT_SIZE); 670 } 671 if (subshell_prompt_temp_buffer == NULL) 672 { 673 subshell_prompt_temp_buffer = g_string_sized_new (INITIAL_PROMPT_SIZE); 674 } 675 676 /* Extract the prompt from the shell output */ 677 for (i = 0; i < bytes; i++) 678 if (buffer[i] == '\n' || buffer[i] == '\r') 679 { 680 g_string_set_size (subshell_prompt_temp_buffer, 0); 681 } 682 else if (buffer[i] != '\0') 683 g_string_append_c (subshell_prompt_temp_buffer, buffer[i]); 684 } 685 686 /* --------------------------------------------------------------------------------------------- */ 687 688 static void 689 set_prompt_string (void) 690 { 691 if (subshell_prompt_temp_buffer->len != 0) 692 g_string_assign (subshell_prompt, subshell_prompt_temp_buffer->str); 693 694 setup_cmdline(); 695 } 696 697 /* --------------------------------------------------------------------------------------------- */ 472 698 /** Feed the subshell our keyboard input until it says it's finished */ 473 699 474 700 static gboolean … … feed_subshell (int how, gboolean fail_on_error) 481 707 struct timeval wtime; /* Maximum time we wait for the subshell */ 482 708 struct timeval *wptr; 483 709 710 should_read_new_subshell_prompt = FALSE; 711 subshell_should_clear_command_line = FALSE; 712 484 713 /* we wait up to 10 seconds if fail_on_error, forever otherwise */ 485 714 wtime.tv_sec = 10; 486 715 wtime.tv_usec = 0; … … feed_subshell (int how, gboolean fail_on_error) 549 778 550 779 if (how == VISIBLY) 551 780 write_all (STDOUT_FILENO, pty_buffer, bytes); 781 if (should_read_new_subshell_prompt == TRUE) 782 { 783 parse_subshell_prompt_string(pty_buffer, bytes); 784 } 785 552 786 } 553 787 554 788 else if (FD_ISSET (subshell_pipe[READ], &read_set)) … … feed_subshell (int how, gboolean fail_on_error) 567 801 568 802 synchronize (); 569 803 804 clear_subshell_prompt_string(); 805 should_read_new_subshell_prompt = TRUE; 570 806 subshell_ready = TRUE; 571 807 if (subshell_state == RUNNING_COMMAND) 572 808 { … … feed_subshell (int how, gboolean fail_on_error) 578 814 else if (FD_ISSET (STDIN_FILENO, &read_set)) 579 815 /* Read from stdin, write to the subshell */ 580 816 { 817 should_read_new_subshell_prompt = FALSE; 581 818 bytes = read (STDIN_FILENO, pty_buffer, sizeof (pty_buffer)); 582 819 if (bytes <= 0) 583 820 { … … feed_subshell (int how, gboolean fail_on_error) 592 829 { 593 830 write_all (mc_global.tty.subshell_pty, pty_buffer, i); 594 831 if (subshell_ready) 832 { 595 833 subshell_state = INACTIVE; 834 set_prompt_string (); 835 if (subshell_ready == TRUE) 836 { 837 if (!read_command_line_buffer(FALSE)) 838 { 839 /* If we got here, some unforseen error must have occurred. */ 840 flush_subshell(0, VISIBLY); 841 input_assign_text (cmdline, ""); 842 subshell_should_clear_command_line = TRUE; 843 return TRUE; 844 } 845 } 846 } 596 847 return TRUE; 597 848 } 598 849 599 850 write_all (mc_global.tty.subshell_pty, pty_buffer, bytes); 600 851 601 852 if (pty_buffer[bytes - 1] == '\n' || pty_buffer[bytes - 1] == '\r') 853 { 854 /* We should only clear the command line if we are using a shell that works 855 * with persistent command buffer, otherwise we get awkward results. */ 856 if (use_persistent_buffer == TRUE) 857 input_assign_text (cmdline, ""); 602 858 subshell_ready = FALSE; 859 } 603 860 } 604 861 else 605 862 return FALSE; … … init_subshell_precmd (char *precmd, size_t buff_size) 784 1041 { 785 1042 case SHELL_BASH: 786 1043 g_snprintf (precmd, buff_size, 1044 " bind -x '\"\\e" SHELL_BUFFER_KEYBINDING "\":\"echo $READLINE_LINE>&%d\"'\n" 1045 " bind -x '\"\\e" SHELL_CURSOR_KEYBINDING "\":\"echo $READLINE_POINT>&%d\"'\n" 787 1046 " PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND\n}'pwd>&%d;kill -STOP $$'\n" 788 "PS1='\\u@\\h:\\w\\$ '\n", subshell_pipe[WRITE]); 1047 "PS1='\\u@\\h:\\w\\$ '\n", 1048 command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]); 789 1049 break; 790 1050 791 1051 case SHELL_ASH_BUSYBOX: … … init_subshell_precmd (char *precmd, size_t buff_size) 844 1104 845 1105 case SHELL_ZSH: 846 1106 g_snprintf (precmd, buff_size, 1107 " mc_print_command_buffer () { echo $BUFFER >&%d}\n" 1108 " zle -N mc_print_command_buffer\n" 1109 " bindkey '^[" SHELL_BUFFER_KEYBINDING "' mc_print_command_buffer\n" 1110 " mc_print_cursor_position () { echo $CURSOR >&%d}\n" 1111 " zle -N mc_print_cursor_position\n" 1112 " bindkey '^[" SHELL_CURSOR_KEYBINDING "' mc_print_cursor_position\n" 847 1113 " _mc_precmd(){ pwd>&%d;kill -STOP $$ }; precmd_functions+=(_mc_precmd)\n" 848 "PS1='%%n@%%m:%%~%%# '\n", subshell_pipe[WRITE]); 1114 "PS1='%%n@%%m:%%~%%# '\n", 1115 command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]); 849 1116 break; 850 1117 851 1118 case SHELL_TCSH: … … init_subshell_precmd (char *precmd, size_t buff_size) 854 1121 "set prompt='%%n@%%m:%%~%%# '; " 855 1122 "alias precmd 'echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo); 856 1123 break; 857 858 1124 case SHELL_FISH: 859 1125 g_snprintf (precmd, buff_size, 860 1126 " if not functions -q fish_prompt_mc;" 861 1127 "functions -e fish_right_prompt;" 862 1128 "functions -c fish_prompt fish_prompt_mc; end;" 863 1129 "function fish_prompt;" 1130 "bind \\e\\" SHELL_BUFFER_KEYBINDING " 'echo (commandline)>&%d'\n" 1131 "bind \\e\\" SHELL_CURSOR_KEYBINDING " 'echo (commandline -C)>&%d'\n" 864 1132 "echo \"$PWD\">&%d; fish_prompt_mc; kill -STOP %%self; end\n", 865 subshell_pipe[WRITE]);1133 command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]); 866 1134 break; 867 1135 868 1136 default: … … init_subshell (void) 1040 1308 mc_global.tty.use_subshell = FALSE; 1041 1309 return; 1042 1310 } 1311 if (mc_global.shell->type == SHELL_BASH 1312 || mc_global.shell->type == SHELL_ZSH 1313 || mc_global.shell->type == SHELL_FISH) 1314 use_persistent_buffer = TRUE; 1315 if (use_persistent_buffer == TRUE) 1316 { 1317 if (pipe (command_buffer_pipe)) 1318 { 1319 perror (__FILE__ ": couldn't create pipe"); 1320 mc_global.tty.use_subshell = FALSE; 1321 return; 1322 } 1323 } 1043 1324 } 1044 1325 1045 1326 /* Fork the subshell */ … … init_subshell (void) 1061 1342 /* We are in the child process */ 1062 1343 init_subshell_child (pty_name); 1063 1344 } 1064 1065 1345 init_subshell_precmd (precmd, BUF_MEDIUM); 1066 1346 1067 1347 write_all (mc_global.tty.subshell_pty, precmd, strlen (precmd)); … … init_subshell (void) 1077 1357 tty_disable_interrupt_key (); 1078 1358 if (!subshell_alive) 1079 1359 mc_global.tty.use_subshell = FALSE; /* Subshell died instantly, so don't use it */ 1360 1361 /* Try out the persistent command buffer feature. If it doesn't work the first time, we 1362 * assume there must be something wrong with the shell, and we turn persistent buffer off 1363 * for good. This will save the user the trouble of having to wait for the persistent 1364 * buffer function to time out every time they try to close the subshell. */ 1365 if (use_persistent_buffer == TRUE) 1366 { 1367 if (read_command_line_buffer(TRUE) == FALSE) 1368 use_persistent_buffer = FALSE; 1369 } 1080 1370 } 1081 1371 1082 1372 /* --------------------------------------------------------------------------------------------- */ … … init_subshell (void) 1084 1374 int 1085 1375 invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath) 1086 1376 { 1377 size_t i; 1087 1378 /* Make the MC terminal transparent */ 1088 1379 tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode); 1089 1380 … … invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath) 1100 1391 /* FIXME: possibly take out this hack; the user can re-play it by hitting C-hyphen a few times! */ 1101 1392 if (subshell_ready && mc_global.mc_run_mode == MC_RUN_FULL) 1102 1393 write_all (mc_global.tty.subshell_pty, " \b", 2); /* Hack to make prompt reappear */ 1394 1395 if (use_persistent_buffer == TRUE) 1396 { 1397 /* Check to make sure there are no non text characters in the command buffer, 1398 * such as tab, or newline, as this could cause problems. */ 1399 for(i = 0;i < strlen(cmdline->buffer);i++) 1400 { 1401 if ((unsigned char) cmdline->buffer[i] < 32 1402 || (unsigned char)cmdline->buffer[i] == 127) 1403 cmdline->buffer[i] = ' '; 1404 } 1405 1406 /* Write the command buffer to the subshell. */ 1407 write_all (mc_global.tty.subshell_pty, cmdline->buffer, strlen (cmdline->buffer)); 1408 1409 /* Put the cursor in the correct place in the subshell. */ 1410 for (int j = 0;j < str_length (cmdline->buffer) - cmdline->point;j++) 1411 write_all (mc_global.tty.subshell_pty, ESC_STR "[D", 3); 1412 } 1103 1413 } 1104 1414 } 1105 1415 else /* MC has passed us a user command */ 1106 1416 { 1417 /* Before we write to the command prompt, we need to clear whatever */ 1418 /* data is there, but only if we are using one of the shells that */ 1419 /* doesn't support keeping command buffer contents, OR if there was */ 1420 /* some sort of error. */ 1421 if (use_persistent_buffer == FALSE || subshell_should_clear_command_line == TRUE) 1422 { 1423 write_all (mc_global.tty.subshell_pty, "\003", 1); 1424 subshell_state = RUNNING_COMMAND; 1425 /* We need to call feed_subshell here if we are using fish, because of a quirk 1426 * in the behavioral of that particular shell. */ 1427 if (mc_global.shell->type != SHELL_FISH) 1428 feed_subshell (QUIETLY, FALSE); 1429 } 1107 1430 if (how == QUIETLY) 1108 1431 write_all (mc_global.tty.subshell_pty, " ", 1); 1109 1432 /* FIXME: if command is long (>8KB ?) we go comma */ … … invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath) 1131 1454 return subshell_get_mainloop_quit (); 1132 1455 } 1133 1456 1134 1135 1457 /* --------------------------------------------------------------------------------------------- */ 1136 1458 1137 1459 gboolean 1138 read_subshell_prompt (void)1460 flush_subshell (int max_wait_length, int how) 1139 1461 { 1140 1462 int rc = 0; 1141 1463 ssize_t bytes = 0; 1142 1464 struct timeval timeleft = { 0, 0 }; 1143 GString *p; 1144 gboolean prompt_was_reset = FALSE; 1145 1465 int return_value = FALSE; 1146 1466 fd_set tmp; 1467 1468 timeleft.tv_sec = max_wait_length; 1147 1469 FD_ZERO (&tmp); 1148 1470 FD_SET (mc_global.tty.subshell_pty, &tmp); 1149 1471 1150 /* First time through */1151 if (subshell_prompt == NULL)1152 subshell_prompt = g_string_sized_new (INITIAL_PROMPT_SIZE);1153 1154 p = g_string_sized_new (INITIAL_PROMPT_SIZE);1155 1156 1472 while (subshell_alive 1157 1473 && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0) 1158 1474 { 1159 ssize_t i;1160 1161 1475 /* Check for 'select' errors */ 1162 1476 if (rc == -1) 1163 1477 { … … read_subshell_prompt (void) 1172 1486 fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno)); 1173 1487 exit (EXIT_FAILURE); 1174 1488 } 1489 return_value = TRUE; 1490 timeleft.tv_sec = 0; 1491 timeleft.tv_usec = 0; 1175 1492 1176 1493 bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer)); 1494 if (how == VISIBLY) 1495 write_all (STDOUT_FILENO, pty_buffer, bytes); 1496 } 1497 return return_value; 1498 } 1499 1500 /* --------------------------------------------------------------------------------------------- */ 1501 1502 gboolean 1503 read_subshell_prompt (void) 1504 { 1505 int rc = 0; 1506 ssize_t bytes = 0; 1507 struct timeval timeleft = { 0, 0 }; 1508 int should_reset_prompt = TRUE; 1509 int got_new_prompt = FALSE; 1510 1511 fd_set tmp; 1512 FD_ZERO (&tmp); 1513 FD_SET (mc_global.tty.subshell_pty, &tmp); 1177 1514 1178 /* Extract the prompt from the shell output */ 1179 for (i = 0; i < bytes; i++) 1180 if (pty_buffer[i] == '\n' || pty_buffer[i] == '\r') 1515 while (subshell_alive 1516 && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0) 1517 { 1518 /* Check for 'select' errors */ 1519 if (rc == -1) 1520 { 1521 if (errno == EINTR) 1181 1522 { 1182 g_string_set_size (p, 0); 1183 prompt_was_reset = TRUE; 1523 if (tty_got_winch ()) 1524 tty_change_screen_size (); 1525 1526 continue; 1184 1527 } 1185 else if (pty_buffer[i] != '\0')1186 g_string_append_c (p, pty_buffer[i]);1187 }1188 1528 1189 if (p->len != 0 || prompt_was_reset) 1190 g_string_assign (subshell_prompt, p->str); 1529 fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno)); 1530 exit (EXIT_FAILURE); 1531 } 1191 1532 1192 g_string_free (p, TRUE); 1533 bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer)); 1534 if (should_reset_prompt) 1535 { 1536 should_reset_prompt = FALSE; 1537 clear_subshell_prompt_string(); 1538 } 1539 parse_subshell_prompt_string (pty_buffer, bytes); 1540 got_new_prompt = TRUE; 1541 } 1542 if (got_new_prompt == TRUE) 1543 { 1544 set_prompt_string (); 1545 } 1193 1546 1194 1547 return (rc != 0 || bytes != 0); 1195 1548 } … … exit_subshell (void) 1231 1584 1232 1585 g_string_free (subshell_prompt, TRUE); 1233 1586 subshell_prompt = NULL; 1587 g_string_free (subshell_prompt_temp_buffer, TRUE); 1588 subshell_prompt_temp_buffer = NULL; 1234 1589 pty_buffer[0] = '\0'; 1235 1590 } 1236 1591 … … do_subshell_chdir (const vfs_path_t * vpath, gboolean update_prompt) 1259 1614 return; 1260 1615 } 1261 1616 1617 /* If we are using a shell that doesn't support persistent command buffer, we need to clear 1618 * the command prompt before we send the cd command. */ 1619 if (use_persistent_buffer == FALSE || subshell_should_clear_command_line == TRUE) 1620 { 1621 write_all (mc_global.tty.subshell_pty, "\003", 1); 1622 subshell_state = RUNNING_COMMAND; 1623 if (mc_global.shell->type != SHELL_FISH) 1624 feed_subshell (QUIETLY, FALSE); 1625 } 1262 1626 /* The initial space keeps this out of the command history (in bash 1263 1627 because we set "HISTCONTROL=ignorespace") */ 1264 1628 write_all (mc_global.tty.subshell_pty, " cd ", 4); -
src/subshell/subshell.h
diff --git a/src/subshell/subshell.h b/src/subshell/subshell.h index e0fdfb13e..bde19c469 100644
a b extern GString *subshell_prompt; 36 36 37 37 extern gboolean update_subshell_prompt; 38 38 39 extern gboolean should_read_new_subshell_prompt; 40 39 41 /*** declarations of public functions ************************************************************/ 40 42 41 43 void init_subshell (void); 42 44 int invoke_subshell (const char *command, int how, vfs_path_t ** new_dir); 45 gboolean flush_subshell (int max_wait_length, int how); 43 46 gboolean read_subshell_prompt (void); 44 47 void do_update_prompt (void); 45 48 gboolean exit_subshell (void);