I am trying to understand why TeXmacs' shell plugin doesn't work on
Tiger. This plugin is a simple binary executable compiled from the C+
+ code I am attaching below. It is supposed to run /bin/sh as a
child and run its stdin/out through the calling process. This works
on OSX 10.3, but not on 10.4. What has changed on Tiger with respect
to fork/pipes?
If you compile the attached file tm_shell.cpp simply with
g++ -o tm_shell tm_shell.cpp
and then run ./tm_shell from the command line, it should just look
like a new shell with a different prompt. This is also what happens
on Panther. On Tiger, what happens is
% ./tm_shell
verbatim:Shell session inside TeXmacsverbatim:
[1] + 21241 Suspended (tty input) ./tm_shell
If I fg the process, it suspends itself immediately again. This is
also what happens when one tries to run the shell plugin from within
TeXmacs; the whole TeXmacs process gets suspended and has to be
forcibly killed.
It doesn't matter where the binary is compiled, on Panther or on
Tiger, or with which version of g++. If the identical binary is run
on Panther, it works; if it is run on Tiger, it doesn't.
Does anyone see what is wrong with the code or why it wouldn't work
on Tiger?
Here is the code:
/
******************************************************************************
* MODULE : tm_shell.cpp
* DESCRIPTION: TeXmacs shell
* COPYRIGHT : (C) 2000 Joris van der Hoeven
*******************************************************************************
* This software falls under the GNU general public license and comes
WITHOUT
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for
more details.
* If you don't have this file, write to the Free Software
Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/wait.h>
using namespace std;
typedef char* charp;
extern charp* environ;
#define ERROR (-1)
#define STDIN 0
#define STDOUT 1
#define STDERR 2
#define IN 0
#define OUT 1
#define DATA_BEGIN ((char) 2)
#define DATA_END ((char) 5)
#define DATA_ESCAPE ((char) 27)
//#define DATA_BEGIN "[BEGIN]"
//#define DATA_END "[END]"
//#define DATA_ESCAPE "[ESCAPE]"
int pid; // process identifier of the child
int tochild[2]; // for data going to the child
int fromchild[2]; // for data coming from the child
int in; // file descriptor for data going to the child
int out; // file descriptor for data coming from the
child
FILE* fin; // file associated to in
/
******************************************************************************
* Handling shell input and output
******************************************************************************/
void
append (charp &s, char c, int& pos, int& max) {
if (pos == max) {
int i;
charp r= s;
max <<= 1;
s= (charp) malloc (max);
for (i=0; i<pos; i++) s[i]=r[i];
free (r);
}
s[pos++]= c;
}
void
shell_output (bool hide= false) {
int output_pos= 0;
int output_max= 1024;
charp output= (charp) malloc (output_max);
cout << DATA_BEGIN << "verbatim:";
while (true) {
fd_set rfds;
FD_ZERO (&rfds);
FD_SET (out, &rfds);
int max_fd= out+1;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100;
int nr= select (max_fd, &rfds, NULL, NULL, &tv);
if (nr==0) {
fflush (stdout);
continue;
}
if (FD_ISSET (out, &rfds)) {
int i, r;
char outbuf[1024];
r = read (out, outbuf, 1024);
if (r == ERROR) {
cerr << "TeXmacs shell] read failed\n";
wait (NULL);
exit (1);
}
else if (r == 0) {
kill (pid, SIGKILL);
cout << DATA_END;
fflush (stdout);
exit (0);
}
else for (i=0; i<r; i++) {
append (output, outbuf[i], output_pos, output_max);
if (outbuf[i]=='\n') {
append (output, '\0', output_pos, output_max);
if (hide) hide= false;
else cout << output;
fflush (stdout);
output_pos= 0;
}
}
}
if (strncmp (output, "tmshell$ ", 9) == 0)
break;
}
cout << DATA_END;
fflush (stdout);
free (output);
}
void
shell_input () {
char input [10000];
cin.getline (input, 10000, '\n');
strcat (input, "\n");
write (in, input, strlen (input));
fflush (fin);
}
void
shell_interrupt (int sig) {
cout << DATA_BEGIN << "scheme:(with \"color\" \"red\" \"";
cout << "Interrupted TeXmacs shell";
cout << "\")" << DATA_END;
cout << DATA_END;
// kill (pid, SIGINT); // Why does this not work ???
kill (pid, SIGKILL);
exit (0);
}
/
******************************************************************************
* Launching the shell using a fork
******************************************************************************/
volatile void
invoke_shell () {
charp argv[3];
argv[0] = "sh";
argv[1] = "-i";
argv[2] = 0;
execve("/bin/sh", argv, environ);
exit(127);
}
int
main () {
setenv ("PS1", "tmshell$ ", true);
cout << DATA_BEGIN << "verbatim:";
cout << "Shell session inside TeXmacs";
pipe (tochild);
pipe (fromchild);
pid= fork ();
if (pid==0) { // the child
dup2 (tochild [IN], STDIN);
close (tochild [IN]);
close (fromchild [IN]);
close (tochild [OUT]);
dup2 (fromchild [OUT], STDOUT);
dup2 (STDOUT, STDERR);
close (fromchild [OUT]);
invoke_shell ();
exit (127);
}
else { // the main process
int sig;
out= fromchild [IN];
close (fromchild [OUT]);
in= tochild [OUT];
close (tochild [IN]);
fin= fdopen (in, "w");
signal (SIGINT, shell_interrupt);
shell_output (true);
cout << DATA_END;
while (true) {
shell_input ();
shell_output ();
}
}
return 0;
}
/**************************/
--
Martin
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Unix-porting mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/unix-porting/email@hidden
This email sent to email@hidden