@@ -4411,7 +4411,49 @@ restore_environment()
44114411# endif
44124412 environmentRestored = true;
44134413}
4414- #endif
4414+
4415+ typedef struct _keyboardParameters {
4416+ FILE * stdin ;
4417+ FILE * stdout ;
4418+ FILE * stderr ;
4419+ int toshell_fd ;
4420+ } keyboardParameters ;
4421+
4422+ static void * forwardKeyboard (void * parameters ) {
4423+ // What do I need: curbuf, toshell_fd.
4424+ keyboardParameters * kp = (keyboardParameters * )parameters ;
4425+ int toshell_fd = kp -> toshell_fd ;
4426+ thread_stdin = kp -> stdin ;
4427+ thread_stdout = kp -> stdout ;
4428+ thread_stderr = kp -> stderr ;
4429+
4430+ // Can't use getchar, because it blocks all file reading functions, including fileno!
4431+ // Must wait for something to happen on thread_stdin, but passively.
4432+ #define BUFSIZE 1024
4433+ char buffer [BUFSIZE ];
4434+ int in = fileno (thread_stdin );
4435+ int out = fileno (thread_stdout );
4436+ int num = read (in , buffer , BUFSIZE );
4437+ int written = 0 ;
4438+
4439+ for (;;)
4440+ {
4441+ while (written < num ) {
4442+ written += write (out , buffer + written , num - written );
4443+ }
4444+ if (buffer [num - 1 ] == '\r' ) {
4445+ buffer [num - 1 ] = '\n' ;
4446+ write (toshell_fd , buffer , num );
4447+ num = 0 ;
4448+ written = 0 ;
4449+ buffer [0 ] = '\n' ;
4450+ write (out , buffer , 1 );
4451+ }
4452+ num += read (in , buffer + num , BUFSIZE - num );
4453+ }
4454+ }
4455+
4456+ #endif // TARGET_OS_IPHONE
44154457
44164458#endif
44174459
@@ -4491,6 +4533,14 @@ build_argv(
44914533 char * * argv = NULL ;
44924534 int argc ;
44934535
4536+ #if TARGET_OS_IPHONE
4537+ // Prevent the user from running ":term" or ":!sh"
4538+ if ((cmd == NULL ) || (strcmp (cmd , "/bin/sh" ) == 0 ) || (strcmp (cmd , "sh" ) == 0 )) {
4539+ mch_msg ("We cannot run sh from Vim. Try :VimShell for a terminal." );
4540+ return FAIL ;
4541+ }
4542+ #endif
4543+
44944544 * sh_tofree = vim_strsave (p_sh );
44954545 if (* sh_tofree == NULL ) /* out of memory */
44964546 return FAIL ;
@@ -4525,6 +4575,12 @@ build_argv(
45254575
45264576 argv [argc ++ ] = (char * )cmd ;
45274577 }
4578+ #if TARGET_OS_IPHONE
4579+ else {
4580+ mch_msg ("We cannot start an empty shell command in Vim. Try :VimShell to open a terminal.\r\n" );
4581+ return FAIL ;
4582+ }
4583+ #endif
45284584 argv [argc ] = NULL ;
45294585 return OK ;
45304586}
@@ -4938,7 +4994,6 @@ mch_call_shell_fork(
49384994 vim_ignored = dup (fd_toshell [0 ]);
49394995 close (fd_toshell [0 ]);
49404996# else
4941- // iOS:
49424997 ios_dup2 (fd_toshell [0 ], 0 );
49434998# endif
49444999# if !TARGET_OS_IPHONE
@@ -4973,6 +5028,9 @@ mch_call_shell_fork(
49735028 * to the X server (esp. with GTK, which uses atexit()).
49745029 */
49755030#if TARGET_OS_IPHONE
5031+ // For taking keyboard input (if it works)
5032+ pipe (fd_toshell );
5033+ ios_dup2 (fd_toshell [0 ], 0 );
49765034 ios_system (cmd ); // We do not need argv and sh, but we still built them to minimize code changes.
49775035#else
49785036 execvp (argv [0 ], argv );
@@ -4984,6 +5042,7 @@ mch_call_shell_fork(
49845042 else /* parent */
49855043#endif
49865044 {
5045+ // options == 4 (SHELL_COOKED). No SHELL_READ or SHELL_WRITE. Until I forced it in ex_cmds.
49875046 /*
49885047 * While child is running, ignore terminating signals.
49895048 * Do catch CTRL-C, so that "got_int" is set.
@@ -4993,6 +5052,16 @@ mch_call_shell_fork(
49935052 UNBLOCK_SIGNALS (& curset );
49945053#if TARGET_OS_IPHONE
49955054 signal (SIGWINCH , (RETSIGTYPE (* )())sig_winch );
5055+ // iOS: listen to tty, write to output
5056+ keyboardParameters kp ;
5057+ kp .toshell_fd = fd_toshell [1 ];
5058+ kp .stdin = thread_stdin ;
5059+ kp .stdout = thread_stdout ;
5060+ kp .stderr = thread_stderr ;
5061+ volatile pthread_t _tid = NULL ;
5062+ pthread_create (& _tid , NULL , forwardKeyboard , (void * )& kp );
5063+ while (_tid == NULL ) { }
5064+ pthread_detach (_tid );
49965065#endif
49975066# ifdef FEAT_JOB_CHANNEL
49985067 ++ dont_check_job_ended ;
@@ -5034,7 +5103,7 @@ mch_call_shell_fork(
50345103 else
50355104# endif
50365105 {
5037- # ifndef TARGET_OS_IPHONE
5106+ # if ! TARGET_OS_IPHONE
50385107 close (fd_toshell [0 ]);
50395108 close (fd_fromshell [1 ]);
50405109# endif
@@ -5513,6 +5582,8 @@ mch_call_shell_fork(
55135582
55145583 if (wait_pid != pid )
55155584 wait_pid = wait4pid (pid , & status );
5585+ if (_tid != NULL ) pthread_cancel (_tid );
5586+
55165587
55175588# ifdef FEAT_GUI
55185589 /* Close slave side of pty. Only do this after the child has
0 commit comments