[m-rev.] for review: improve `mdb --window'

Simon Taylor stayl at cs.mu.OZ.AU
Tue Jan 29 05:18:15 AEDT 2002


Estimated hours taken: 10

Improve the handling of the mdb's `--window' option.
`mdb --window' now creates a window for mdb, not the program.
The main advantage of this is that redirection of the program's
input and output now works. The new behaviour should also be
implementable using the Windows API. The old behaviour is still
available with `mdb --program-in-window'.

Unfortunately, the code to open a pseudo-terminal for mdb's I/O
isn't very portable. It works on everything we run nightly tests on,
but isn't likely to work on older systems or BSD systems.

NEWS:
	Document the change.

scripts/mdb.in:
	Handle the new behaviour of `--window'.
	Add `--program-in-window'.

trace/mercury_trace_internal.c:
	If `--window' was passed in MERCURY_OPTIONS, redirect
	mdb's I/O to a window created using `xterm -S'.

	Rename occurrences of `close' to avoid gcc warnings.

runtime/mercury_trace_base.h:
runtime/mercury_trace_base.c:
	Kill the mdb window on exit.

runtime/mercury_wrapper.h:
runtime/mercury_wrapper.c:
	Add a runtime options `--mdb-in-window' for use by the mdb script.

runtime/mercury_signal.h:
runtime/mercury_signal.c:
	Add a version of MR_do_setup_signal which doesn't cause
	system calls to be restarted after a signal is received.
	This is needed to allow a read() from the mdb window 
	to timeout if the window failed to start.

configure.in:
runtime/mercury_conf.h.in:
runtime/RESERVED_MACRO_NAMES.
	Check for functions open, close, dup, dup2, fdopen, setpgid,
	fork, execlp, wait, kill, grantpt, unlockpt, pstname, tcgetattr,
	tcsetattr and ioctl.

	Check for type pid_t.

	Check for header files <fcntl.h>, <termios.h>, <sys/ioctl.h>,
	<sys/stropts.h>.

	Check for /dev/ptmx, used to open pseudo-terminals.


Index: NEWS
===================================================================
RCS file: /home/mercury1/repository/mercury/NEWS,v
retrieving revision 1.239
diff -u -u -r1.239 NEWS
--- NEWS	25 Jan 2002 05:56:37 -0000	1.239
+++ NEWS	28 Jan 2002 09:01:18 -0000
@@ -186,6 +186,11 @@
   requires X11 and a version of `vim' with the `clientserver' feature
   enabled.
 
+* The `--window' mdb option now creates a window for mdb, not
+  the program.  The main advantage of the new behaviour is that
+  redirection of the program's input and output works.  The old
+  behaviour is still available with `mdb --program-in-window'.
+
 * We've fixed a long-standing bug in the handling of module imports.
   Previously, if `module1' imported `module2' which imported `module3' in
   its interface section, then any types, insts, modes and typeclasses defined
Index: configure.in
===================================================================
RCS file: /home/mercury1/repository/mercury/configure.in,v
retrieving revision 1.291
diff -u -u -r1.291 configure.in
--- configure.in	25 Jan 2002 08:22:20 -0000	1.291
+++ configure.in	28 Jan 2002 15:50:55 -0000
@@ -443,10 +443,13 @@
 	*-cygwin*)
 		ac_cv_func_mprotect=no ;;
 esac
-AC_HAVE_FUNCS(sysconf getpagesize memalign mprotect sigaction setitimer)
-AC_HAVE_FUNCS(strerror memmove dup fileno fdopen fstat stat isatty)
-AC_HAVE_FUNCS(snprintf vsnprintf _vsnprintf)
-AC_HAVE_FUNCS(gethostname getpid)
+AC_HAVE_FUNCS(sysconf getpagesize gethostname)
+AC_HAVE_FUNCS(mprotect memalign memmove)
+AC_HAVE_FUNCS(sigaction setitimer)
+AC_HAVE_FUNCS(snprintf vsnprintf _vsnprintf strerror)
+AC_HAVE_FUNCS(open close dup dup2 fdopen fileno fstat stat isatty)
+AC_HAVE_FUNCS(getpid setpgid fork execlp wait kill)
+AC_HAVE_FUNCS(grantpt unlockpt ptsname tcgetattr tcsetattr ioctl)
 #-----------------------------------------------------------------------------#
 AC_CHECK_HEADER(unistd.h, HAVE_UNISTD_H=1)
 if test "$HAVE_UNISTD_H" = 1; then
@@ -508,6 +511,31 @@
 	AC_DEFINE(HAVE_SYS_STAT_H)
 fi
 #-----------------------------------------------------------------------------#
+AC_CHECK_HEADER(fcntl.h, HAVE_FCNTL_H=1)
+if test "$HAVE_FCNTL_H" = 1; then
+	AC_DEFINE(HAVE_FCNTL_H)
+fi
+#-----------------------------------------------------------------------------#
+AC_CHECK_HEADER(termios.h, HAVE_TERMIOS_H=1)
+if test "$HAVE_TERMIOS_H" = 1; then
+	AC_DEFINE(HAVE_TERMIOS_H)
+fi
+#-----------------------------------------------------------------------------#
+AC_CHECK_HEADER(sys/ioctl.h, HAVE_SYS_IOCTL_H=1)
+if test "$HAVE_SYS_IOCTL_H" = 1; then
+	AC_DEFINE(HAVE_SYS_IOCTL_H)
+fi
+#-----------------------------------------------------------------------------#
+AC_CHECK_HEADER(sys/stropts.h, HAVE_SYS_STROPTS_H=1)
+if test "$HAVE_SYS_STROPTS_H" = 1; then
+	AC_DEFINE(HAVE_SYS_STROPTS_H)
+fi
+#-----------------------------------------------------------------------------#
+AC_CHECK_FILE(/dev/ptmx, HAVE_DEV_PTMX=1)
+if test "$HAVE_DEV_PTMX" = 1; then
+	AC_DEFINE(HAVE_DEV_PTMX)
+fi
+#-----------------------------------------------------------------------------#
 #
 # check the basics of sigaction
 #
@@ -1078,7 +1106,8 @@
 fi
 AC_SUBST(MR_INT_LEAST32_MAX)
 AC_SUBST(MR_UINT_LEAST32_MAX)
-
+#-----------------------------------------------------------------------------#
+AC_TYPE_PID_T
 #-----------------------------------------------------------------------------#
 AC_MSG_CHECKING(for an integer type of at least 16 bits)
 AC_CACHE_VAL(mercury_cv_int_least16_type,
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.286
diff -u -u -r1.286 user_guide.texi
--- doc/user_guide.texi	25 Jan 2002 05:56:40 -0000	1.286
+++ doc/user_guide.texi	26 Jan 2002 13:42:19 -0000
@@ -5905,6 +5905,9 @@
 Redirect all three debugger I/O streams -- input, output, and error messages --
 to the file or device specified by @var{filename}.
 
+ at c --mdb-in-window is for use only by the mdb script, so it's
+ at c not documented here.
+
 @end table
 
 @end table
Index: runtime/RESERVED_MACRO_NAMES
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/RESERVED_MACRO_NAMES,v
retrieving revision 1.6
diff -u -u -r1.6 RESERVED_MACRO_NAMES
--- runtime/RESERVED_MACRO_NAMES	11 Dec 2001 09:01:18 -0000	1.6
+++ runtime/RESERVED_MACRO_NAMES	28 Jan 2002 15:49:05 -0000
@@ -50,6 +50,7 @@
 # but it ought to be defined in mercury_conf_param.h,
 # or just deleted, since it is not used at all
 # XXX TAG_BITS is defined in mercury_tags.h
+pid_t
 BOXED_FLOAT
 CONSERVATIVE_GC
 LOW_TAG_BITS
@@ -72,23 +73,36 @@
 USE_SINGLE_PREC_FLOAT
 USE_TYPE_LAYOUT
 HAVE_ASM_SIGCONTEXT
+HAVE_CLOSE
+HAVE_DEV_PTMX
 HAVE_DLCLOSE
 HAVE_DLERROR
 HAVE_DLFCN_H
 HAVE_DLOPEN
 HAVE_DLSYM
+HAVE_DUP
+HAVE_DUP2
+HAVE_EXECLP
+HAVE_FCNTL_H
 HAVE_FDOPEN
 HAVE_FILENO
+HAVE_FORK
 HAVE_FSTAT
 HAVE_GETHOSTNAME
 HAVE_GETPAGESIZE
+HAVE_GRANTPT
+HAVE_IOCTL
 HAVE_ISATTY
+HAVE_KILL
 HAVE_MEMALIGN
 HAVE_MEMMOVE
 HAVE_MPROTECT
 HAVE_GETPID
+HAVE_OPEN
+HAVE_PTSNAME
 HAVE_READLINE_HISTORY
 HAVE_READLINE_READLINE
+HAVE_SETPGID
 HAVE_SETITIMER
 HAVE_SIGACTION
 HAVE_SIGCONTEXT_STRUCT
@@ -96,23 +110,30 @@
 HAVE_SIGCONTEXT_STRUCT_3ARG
 HAVE_SIGINFO
 HAVE_SIGINFO_T
+HAVE_SNPRINTF
 HAVE_STAT
 HAVE_STRERROR
 HAVE_SYSCONF
+HAVE_SYS_IOCTL_H
 HAVE_SYS_PARAM
 HAVE_SYS_STAT_H
 HAVE_SYS_SIGINFO
 HAVE_SYS_SIGNAL
+HAVE_SYS_STROPTS_H
 HAVE_SYS_TIME
 HAVE_SYS_TIMES_H
 HAVE_SYS_TYPES_H
 HAVE_SYS_UCONTEXT
 HAVE_SYS_WAIT
+HAVE_TCGETATTR
+HAVE_TCSETATTR
+HAVE_TERMIOS_H
 HAVE_UCONTEXT
 HAVE_UNISTD_H
-HAVE_SNPRINTF
+HAVE_UNLOCKPT
 HAVE_VSNPRINTF
 HAVE__VSNPRINTF
+HAVE_WAIT
 #-----------------------------------------------------------------------------#
 # These are defined by mercury.h
 # Normally macros should start with capital letters,
Index: runtime/mercury_conf.h.in
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_conf.h.in,v
retrieving revision 1.40
diff -u -u -r1.40 mercury_conf.h.in
--- runtime/mercury_conf.h.in	27 Dec 2001 07:25:22 -0000	1.40
+++ runtime/mercury_conf.h.in	28 Jan 2002 15:48:59 -0000
@@ -121,6 +121,10 @@
 **	HAVE_SYS_TYPES_H	we have <sys/types.h>
 **	HAVE_SYS_TIMES_H	we have <sys/times.h>
 **	HAVE_DLFCN_H		we have <dlfcn.h>
+**	HAVE_FCNTL_H		we have <fcnt.h>
+**	HAVE_TERMIOS_H		we have <termios.h>
+**	HAVE_SYS_IOCTL_H	we have <sys/ioctl.h>
+**	HAVE_SYS_STROPTS_H	we have <sys/stropts.h>
 */
 #undef	HAVE_SYS_SIGINFO
 #undef	HAVE_SYS_SIGNAL
@@ -135,6 +139,16 @@
 #undef	HAVE_SYS_TIMES_H
 #undef	HAVE_SYS_TYPES_H
 #undef	HAVE_DLFCN_H
+#undef	HAVE_FCNTL_H
+#undef	HAVE_TERMIOS_H
+#undef	HAVE_SYS_IOCTL_H
+#undef	HAVE_SYS_STROPTS_H
+
+/*
+** HAVE_DEV_PTMX is defined if /dev/ptmx (used to allocate
+** pseudo-terminals) exists.
+*/
+#undef HAVE_DEV_PTMX
 
 /*
 ** MR_HAVE_POSIX_TIMES is defined if we have the POSIX
@@ -153,10 +167,20 @@
 #undef MR_HAVE_INT_LEASTN_T
 
 /*
+** pid_t is defined as `int' iff the system headers don't define it.
+*/
+#undef pid_t
+
+/*
 ** The following macros are defined iff the corresponding function or
 ** system call is available:
 **
 ** 	HAVE_GETPID		we have the getpid() function.
+** 	HAVE_SETPGID		we have the setpgid() function.
+**	HAVE_FORK		we have the fork() function.
+**	HAVE_EXECLP		we have the execlp() function.
+**	HAVE_WAIT		we have the wait() function.
+**	HAVE_KILL		we have the kill() function.
 ** 	HAVE_GETHOSTNAME	we have the gethostname() function.
 **	HAVE_SNPRINTF 		we have the snprintf() function.
 **	HAVE_VSNPRINTF 		we have the vsnprintf() function.
@@ -176,13 +200,28 @@
 **	HAVE_STAT 		we have the stat() function.
 **	HAVE_FSTAT 		we have the fstat() function.
 **	HAVE_FDOPEN 		we have the fdopen() function.
+**	HAVE_OPEN		we have the open() function.
+**	HAVE_CLOSE		we have the close() function.
+**	HAVE_DUP		we have the dup() function.
+**	HAVE_DUP2		we have the dup2() function.
 **	HAVE_FILENO 		we have the fileno() function.
 **				Note that fileno() may be a macro
 **				rather than a function, so you should use
 **				#if defined(fileno) || defined(HAVE_FILENO)
 **	HAVE_ISATTY 		we have the isatty() function.
+**	HAVE_GRANTPT		we have the grantpt() function.
+**	HAVE_UNLOCKPT		we have the unlockpt() function.
+**	HAVE_PTSNAME		we have the ptsname() function.
+**	HAVE_TCGETATTR		we have the tcgetattr() function.
+**	HAVE_TCSETATTR		we have the tcsetattr() function.
+**	HAVE_IOCTL		we have the ioctl() function.
 */
 #undef	HAVE_GETPID
+#undef	HAVE_SETPGID
+#undef	HAVE_FORK
+#undef	HAVE_EXECLP
+#undef	HAVE_WAIT
+#undef	HAVE_KILL
 #undef	HAVE_GETHOSTNAME
 #undef	HAVE_SNPRINTF
 #undef	HAVE_VSNPRINTF
@@ -202,8 +241,18 @@
 #undef	HAVE_STAT
 #undef	HAVE_FSTAT
 #undef	HAVE_FDOPEN
+#undef	HAVE_OPEN
+#undef	HAVE_CLOSE
+#undef	HAVE_DUP
+#undef	HAVE_DUP2
 #undef	HAVE_FILENO
 #undef	HAVE_ISATTY
+#undef	HAVE_GRANTPT
+#undef	HAVE_UNLOCKPT
+#undef	HAVE_PTSNAME
+#undef	HAVE_TCGETATTR
+#undef	HAVE_TCSETATTR
+#undef	HAVE_IOCTL
 
 /*
 ** RETSIGTYPE: the return type of signal handlers.
Index: runtime/mercury_signal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_signal.c,v
retrieving revision 1.9
diff -u -u -r1.9 mercury_signal.c
--- runtime/mercury_signal.c	12 Sep 2000 19:51:07 -0000	1.9
+++ runtime/mercury_signal.c	28 Jan 2002 11:22:59 -0000
@@ -87,14 +87,33 @@
   #define	SA_SIGINFO 0
 #endif
 
+static void MR_do_setup_signal(int sig, MR_Code *handler, bool need_info,
+		bool restart, const char *error_message);
+
 void
 MR_setup_signal(int sig, MR_Code *handler, bool need_info, 
 		const char *error_message)
 {
+	MR_do_setup_signal(sig, handler, need_info, TRUE, error_message);
+}
+
+void
+MR_setup_signal_no_restart(int sig, MR_Code *handler, bool need_info, 
+		const char *error_message)
+{
+	MR_do_setup_signal(sig, handler, need_info, FALSE, error_message);
+}
+
+void
+MR_do_setup_signal(int sig, MR_Code *handler, bool need_info, bool restart,
+		const char *error_message)
+{
 #if	defined(HAVE_SIGACTION)
 
 	struct sigaction	act;
 
+	act.sa_flags = (restart ? SA_RESTART : 0);
+
 	if (need_info) {
 	/*
 	** If we are using sigcontext struct, it means we have
@@ -102,13 +121,9 @@
 	** request signals, we should not ask for SA_SIGINFO, since our
 	** handler will not be of the right type.
 	*/
-#if	defined(HAVE_SIGCONTEXT_STRUCT)
-		act.sa_flags = SA_RESTART;
-#else	/* not HAVE_SIGCONTEXT_STRUCT */
-		act.sa_flags = SA_SIGINFO | SA_RESTART;
+#if	!defined(HAVE_SIGCONTEXT_STRUCT)
+		act.sa_flags |= SA_SIGINFO;
 #endif
-	} else {
-		act.sa_flags = SA_RESTART;
 	}
 	if (sigemptyset(&act.sa_mask) != 0) {
 		perror("Mercury runtime: cannot set clear signal mask");
Index: runtime/mercury_signal.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_signal.h,v
retrieving revision 1.5
diff -u -u -r1.5 mercury_signal.h
--- runtime/mercury_signal.h	3 Aug 2000 06:18:54 -0000	1.5
+++ runtime/mercury_signal.h	28 Jan 2002 11:04:59 -0000
@@ -30,5 +30,11 @@
 extern void MR_setup_signal(int sig, MR_Code *handler, bool need_info, 
 	const char * error_message);
 
+	/*
+	** As above, but don't arrange for system calls to be
+	** restarted if the signal is received.
+	*/
+extern void MR_setup_signal_no_restart(int sig, MR_Code *handler,
+	bool need_info, const char * error_message);
 
 #endif /* not MERCURY_SIGNAL_H */
Index: runtime/mercury_trace_base.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace_base.c,v
retrieving revision 1.38
diff -u -u -r1.38 mercury_trace_base.c
--- runtime/mercury_trace_base.c	27 Dec 2001 07:08:11 -0000	1.38
+++ runtime/mercury_trace_base.c	28 Jan 2002 08:09:43 -0000
@@ -32,6 +32,10 @@
   #include <unistd.h>		/* for the write system call */
 #endif
 
+#ifdef HAVE_SYS_WAIT
+  #include <sys/wait.h>		/* for the wait system call */
+#endif
+
 /*
 ** Do we want to use the debugger within this process, or do want to use
 ** the Opium-style trace analyzer debugger implemented by an external process.
@@ -52,6 +56,9 @@
 
 bool		MR_trace_enabled = FALSE;
 
+bool		MR_have_mdb_window = FALSE;
+pid_t		MR_mdb_window_pid = 0;
+
 /*
 ** MR_trace_call_seqno counts distinct calls. The prologue of every
 ** procedure assigns the current value of this counter as the sequence number
@@ -210,6 +217,21 @@
 			MR_address_of_trace_final_external();
 		} else {
 			MR_tracing_not_enabled();
+		}
+	}
+#endif
+
+#if defined(HAVE_KILL) && defined(HAVE_WAIT) && defined(SIGTERM)
+	if (MR_have_mdb_window) {
+		int status;
+		status = kill(MR_mdb_window_pid, SIGTERM);
+		if (status != -1) {
+			do {
+				status = wait(NULL);
+				if (status == -1 && errno != EINTR) {
+					break;
+				}
+			} while (status != MR_mdb_window_pid);
 		}
 	}
 #endif
Index: runtime/mercury_trace_base.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace_base.h,v
retrieving revision 1.19
diff -u -u -r1.19 mercury_trace_base.h
--- runtime/mercury_trace_base.h	15 Jun 2001 04:46:23 -0000	1.19
+++ runtime/mercury_trace_base.h	27 Jan 2002 15:15:41 -0000
@@ -19,6 +19,9 @@
 #include "mercury_stack_layout.h"
 #include "mercury_std.h"
 #include "mercury_tabling.h"	/* for MR_TableNode */
+#ifdef HAVE_UNISTD_H
+  #include <unistd.h>           /* for the write system call and pid_t */
+#endif
 
 /*
 ** This enum should EXACTLY match the definition of the `trace_port_type'
@@ -93,6 +96,15 @@
 extern	void	MR_trace_start(bool enabled);
 extern	void	MR_trace_end(void);
 extern	void	MR_trace_final(void);
+
+/*
+** MR_have_mdb_window and MR_mdb_window_pid are set by
+** mercury_trace_internal.c after the xterm window for
+** mdb has been spawned. The window process is killed by 
+** MR_trace_final().
+*/
+extern	bool	MR_have_mdb_window;
+extern	pid_t	MR_mdb_window_pid;
 
 /*
 ** The globals that define the interface between the tracing subsystem
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.95
diff -u -u -r1.95 mercury_wrapper.c
--- runtime/mercury_wrapper.c	13 Jan 2002 10:13:09 -0000	1.95
+++ runtime/mercury_wrapper.c	26 Jan 2002 16:11:38 -0000
@@ -89,6 +89,7 @@
 const char	*MR_mdb_in_filename = NULL;
 const char	*MR_mdb_out_filename = NULL;
 const char	*MR_mdb_err_filename = NULL;
+bool		MR_mdb_in_window = FALSE;
 
 /* other options */
 
@@ -731,7 +732,8 @@
 	MR_MDB_TTY,
 	MR_MDB_IN,
 	MR_MDB_OUT,
-	MR_MDB_ERR
+	MR_MDB_ERR,
+	MR_MDB_IN_WINDOW
 };
 
 struct MR_option MR_long_opts[] = {
@@ -748,7 +750,8 @@
 	{ "mdb-tty", 			1, 0, MR_MDB_TTY },
 	{ "mdb-in", 			1, 0, MR_MDB_IN },
 	{ "mdb-out", 			1, 0, MR_MDB_OUT },
-	{ "mdb-err", 			1, 0, MR_MDB_ERR }
+	{ "mdb-err", 			1, 0, MR_MDB_ERR },
+	{ "mdb-in-window",		0, 0, MR_MDB_IN_WINDOW }
 };
 
 static void
@@ -854,6 +857,11 @@
 			MR_mdb_in_filename = MR_copy_string(MR_optarg);
 			MR_mdb_out_filename = MR_copy_string(MR_optarg);
 			MR_mdb_err_filename = MR_copy_string(MR_optarg);
+			break;
+
+		case 'w':
+		case MR_MDB_IN_WINDOW:
+			MR_mdb_in_window = TRUE;
 			break;
 
 		case 'a':
Index: runtime/mercury_wrapper.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.h,v
retrieving revision 1.45
diff -u -u -r1.45 mercury_wrapper.h
--- runtime/mercury_wrapper.h	13 Jan 2002 10:13:10 -0000	1.45
+++ runtime/mercury_wrapper.h	26 Jan 2002 12:38:58 -0000
@@ -209,6 +209,9 @@
 extern	const char	*MR_mdb_out_filename;
 extern	const char	*MR_mdb_err_filename;
 
+/* should mdb be started in a window */
+extern	bool		MR_mdb_in_window;
+
 /* size of the primary cache */
 extern	size_t		MR_pcache_size;
 
Index: scripts/mdb.in
===================================================================
RCS file: /home/mercury1/repository/mercury/scripts/mdb.in,v
retrieving revision 1.3
diff -u -u -r1.3 mdb.in
--- scripts/mdb.in	21 Dec 1998 04:39:44 -0000	1.3
+++ scripts/mdb.in	27 Jan 2002 07:30:15 -0000
@@ -32,22 +32,32 @@
 		specified by <file-name>.  The I/O for the program
 		being debugged will not be redirected.
 
-	-w, --window
+	-w, --window, --mdb-in-window
+		Run mdb in a new window, with mdb's I/O going to that
+		window, but with the program's I/O going to the current
+		terminal.  Note that this will not work on all systems.
+
+	--program-in-window
 		Run the program in a new window, with the program's I/O
 		going to that window, but with mdb's I/O going to the
-		current terminal.
+		current terminal.  Note that input and output redirection
+		will not work with the \`--program-in-window' option.
+		\`--program-in-window' will work on most UNIX systems
+		running the X Window System, even those for which
+		\`--mdb-in-window' is not supported.
 
 	-c <window-command>, --window-command <window-command>
-		Specify the command used by the \`--window' option for
-		executing a command in a new window.  The default such
-		command is \`xterm -e'.
+		Specify the command used by the \`--program-in-window'
+		option for executing a command in a new window.
+		The default such command is \`xterm -e'.
 
 Environment variables:
 	MERCURY_OPTIONS, MERCURY_DEBUGGER_INIT.
 "
 
 tty=
-window=false
+# Possible values "none", "program", "mdb".
+window=none
 window_cmd="xterm -e"
 
 #-----------------------------------------------------------------------------#
@@ -71,14 +81,20 @@
 		-t*)
 			tty="` expr $1 : '-t\(.*\)' `"
 			shift ;;
-		-w|--window)
-			window=true
+		-w|--window|--mdb-in-window)
+			window=mdb
+			shift ;;
+		-w-|--no-window|--no-mdb-in-window)
+			window=none
+			shift ;;
+		--program-in-window)
+			window=program
 			shift ;;
-		-w-|--no-window)
-			window=false
+		--no-program-in-window)
+			window=none
 			shift ;;
 		-c|--window-command)
-			window_cmd="$2";
+			window_cmd="$2"
 			shift; shift ;;
 		--)
 			shift; break ;;
@@ -96,8 +112,12 @@
 #
 
 invoke_cmd=
-case "$window" in true)
+case "$window" in program)
 	invoke_cmd="$window_cmd"
+esac
+
+case "$window" in
+    program|mdb)
 	#
 	# If windowing is enabled, check that DISPLAY is set, and if not,
 	# issue a warning message.  This is needed because the default error
@@ -113,10 +133,15 @@
 # Figure out if/how we should redirect the mdb I/O streams
 #
 
+mdb_in_window_opt=""
+
 case "$tty" in
     "")
 	case "$window" in
-	    true)
+	    mdb)
+	    	mdb_in_window_opt="--mdb-in-window"
+	    	;;
+	    program)
 		#
 		# On Linux, we can use special files in /proc
 		# that refer to the file descriptors for a
@@ -144,7 +169,7 @@
 			redirect_opts="--mdb-tty $tty"
 		fi
 		;;
-	    false)
+	    none)
 		redirect_opts=""
 		;;
 	esac ;;
@@ -161,7 +186,7 @@
 #
 
 enable_mdb_opt="-Di"
-MERCURY_OPTIONS="$MERCURY_OPTIONS $redirect_opts $enable_mdb_opt"
+MERCURY_OPTIONS="$MERCURY_OPTIONS $redirect_opts $enable_mdb_opt $mdb_in_window_opt"
 export MERCURY_OPTIONS
 MERCURY_DEBUGGER_INIT=${MERCURY_DEBUGGER_INIT- at DEFAULT_MERCURY_DEBUGGER_INIT_DIR@/mdbrc}
 export MERCURY_DEBUGGER_INIT
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.111
diff -u -u -r1.111 mercury_trace_internal.c
--- trace/mercury_trace_internal.c	12 Jan 2002 09:08:14 -0000	1.111
+++ trace/mercury_trace_internal.c	28 Jan 2002 18:12:46 -0000
@@ -14,6 +14,7 @@
 #include "mercury_layout_util.h"
 #include "mercury_array_macros.h"
 #include "mercury_getopt.h"
+#include "mercury_signal.h"
 
 #include "mercury_trace.h"
 #include "mercury_trace_internal.h"
@@ -37,6 +38,35 @@
 #include <string.h>
 #include <ctype.h>
 #include <errno.h>
+#include <signal.h>
+
+#ifdef HAVE_UNISTD_H
+  #include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+  #include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT
+  #include <sys/wait.h>
+#endif
+
+#ifdef HAVE_TERMIOS_H
+  #include <termios.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+  #include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+  #include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_STROPTS_H
+  #include <sys/stropts.h>
+#endif
 
 /* The initial size of arrays of words. */
 #define	MR_INIT_WORD_COUNT	20
@@ -167,6 +197,7 @@
 } MR_MultiMatch;
 
 static	void	MR_trace_internal_ensure_init(void);
+static	bool	MR_trace_internal_create_mdb_window(void);
 static	void	MR_trace_internal_init_from_env(void);
 static	void	MR_trace_internal_init_from_local(void);
 static	void	MR_trace_internal_init_from_home_dir(void);
@@ -217,7 +248,7 @@
 static	bool	MR_trace_options_view(const char **window_cmd,
 			const char **server_cmd, const char **server_name,
 			int *timeout, bool *force, bool *verbose, bool *split,
-			bool *close, char ***words, int *word_count,
+			bool *close_window, char ***words, int *word_count,
 			const char *cat, const char*item);
 static	void	MR_trace_usage(const char *cat, const char *item);
 static	void	MR_trace_do_noop(void);
@@ -362,9 +393,23 @@
 		char	*env;
 		int	n;
 
-		MR_mdb_in = MR_try_fopen(MR_mdb_in_filename, "r", stdin);
-		MR_mdb_out = MR_try_fopen(MR_mdb_out_filename, "w", stdout);
-		MR_mdb_err = MR_try_fopen(MR_mdb_err_filename, "w", stderr);
+		if (MR_mdb_in_window) {
+			MR_mdb_in_window =
+				MR_trace_internal_create_mdb_window();
+			if (! MR_mdb_in_window) {
+				fprintf(stderr,
+				"Try `mdb --program-in-window' instead.\n");
+			}
+		}
+
+		if (! MR_mdb_in_window) {
+			MR_mdb_in = MR_try_fopen(MR_mdb_in_filename,
+					"r", stdin);
+			MR_mdb_out = MR_try_fopen(MR_mdb_out_filename,
+					"w", stdout);
+			MR_mdb_err = MR_try_fopen(MR_mdb_err_filename,
+					"w", stderr);
+		}
 
 		/* Ensure that MR_mdb_err is not buffered */
 		setvbuf(MR_mdb_err, NULL, _IONBF, 0);
@@ -391,6 +436,242 @@
 	}
 }
 
+static bool MR_got_alarm = FALSE;
+
+static void
+MR_trace_internal_alarm_handler(void)
+{
+	MR_got_alarm = TRUE;
+}
+
+static bool
+MR_trace_internal_create_mdb_window(void)
+{
+	/*
+	** XXX Add support for MS Windows.
+	*/
+#if defined(HAVE_OPEN) && defined(HAVE_FDOPEN) && defined(HAVE_CLOSE) && \
+	defined(HAVE_DUP) && defined(HAVE_DUP2) && defined(HAVE_FORK) && \
+	defined(HAVE_EXECLP)
+
+	int master_fd = -1;
+	int slave_fd = -1;
+	char *slave_name;
+	pid_t child_pid;
+#if defined(HAVE_TERMIOS_H) && defined(HAVE_TCGETATTR) && \
+		defined(HAVE_TCSETATTR)
+	struct termios termio;
+#endif
+
+	/*
+	** XXX This code to find and open a pseudo-terminal is nowhere
+	** near as portable as I would like, but given the huge variety
+	** of methods for allocating pseudo-terminals it will have to do.
+	** Most systems seem to be standardising on this method (from UNIX98).
+	** See the xterm or expect source for a more complete version
+	** (it's a bit too entwined in the rest of the code to just lift
+	** it out and use it here).
+	*/
+#if defined(HAVE_DEV_PTMX) && defined(HAVE_GRANTPT) && \
+		defined(HAVE_UNLOCKPT) && defined(HAVE_PTSNAME)
+	master_fd = open("/dev/ptmx", O_RDWR);
+	if (master_fd == -1 || grantpt(master_fd) == -1
+			|| unlockpt(master_fd) == -1) {
+		close(master_fd);
+		perror("error opening master pseudo-terminal for mdb window");
+		return FALSE;
+	}
+	if ((slave_name = ptsname(master_fd)) == NULL) {
+		perror("error getting name of pseudo-terminal for mdb window");
+		close(master_fd);
+		return FALSE;
+	}
+	slave_fd = open(slave_name, O_RDWR);	
+	if (slave_fd == -1) {
+		close(master_fd);
+		perror("opening slave pseudo-terminal for mdb window failed");
+		return FALSE;
+	}
+
+#if defined(HAVE_IOCTL) && defined(I_PUSH)
+	/* Magic STREAMS incantations to make this work on Solaris. */
+	ioctl(slave_fd, I_PUSH, "ptem");
+	ioctl(slave_fd, I_PUSH, "ldterm");
+	ioctl(slave_fd, I_PUSH, "ttcompat");
+#endif
+
+#else
+	fprintf(stderr,
+		"Sorry, `mdb --window' not supported on this platform.\n");
+	return FALSE;
+#endif
+
+#if defined(HAVE_TCGETATTR) && defined(HAVE_TCSETATTR)
+	/*
+	** Turn off echoing before starting the xterm so that
+	** the user doesn't see the window ID printed by xterm
+	** on startup (this behaviour is not documented in the
+	** xterm manual).
+	*/
+	tcgetattr(slave_fd, &termio);
+	termio.c_lflag &= ~ECHO;
+	tcsetattr(slave_fd, TCSADRAIN, &termio);
+#endif
+
+	child_pid = fork();
+	if (child_pid == -1) {
+		perror("fork() for mdb window failed"); 
+		close(master_fd);
+		close(slave_fd);
+		return FALSE;
+	} else if (child_pid == 0) {
+		/*
+		** Child - exec() the xterm.
+		*/
+		char xterm_arg[50];
+
+		close(slave_fd);
+
+#if defined(HAVE_SETPGID)
+		/*
+		** Put the xterm in a new process group so it won't be
+		** killed by SIGINT signals sent to the program.
+		*/
+		if (setpgid(0, 0) < 0) {
+			perror("setpgid() failed");
+			close(master_fd);
+			exit(EXIT_FAILURE);
+		}
+#endif
+
+		/*
+		** The XX part is required by xterm, but it's not
+		** needed for the way we are using xterm (it's meant
+		** to be an identifier for the pseudo-terminal).
+		** Different versions of xterm use different
+		** formats, so it's best to just leave it blank.
+		**
+		** XXX Some versions of xterm (such as that distributed
+		** with XFree86 3.3.6) give a warning about this (but it
+		** still works). The latest version distributed with
+		** XFree86 4 does not given a warning.
+		*/
+		sprintf(xterm_arg, "-SXX%d", master_fd);
+
+		execlp("xterm", "xterm", "-T", "mdb", xterm_arg, NULL);
+		perror("execlp() of xterm failed");
+		exit(EXIT_FAILURE);
+	} else {
+		/*
+		** Parent - set up the mdb I/O streams to point
+		** to the pseudo-terminal.
+		*/
+		MR_Code *old_alarm_handler;
+		int wait_status;
+		int err_fd = -1;
+		int out_fd = -1;
+
+		MR_mdb_in = MR_mdb_out = MR_mdb_err = NULL;
+
+		close(master_fd);
+
+		/*
+		** Read the first line of output -- this is a window ID
+		** written by xterm. The alarm() and associated signal handling
+		** is to gracefully handle the case where the xterm failed to
+		** start, for example because the DISPLAY variable was invalid.
+		** We don't want to restart the read() below if it times out.
+		*/
+		old_alarm_handler = (MR_Code *) signal(SIGALRM, NULL);
+		MR_setup_signal_no_restart(SIGALRM,
+			(MR_Code *) MR_trace_internal_alarm_handler, FALSE,
+			"error setting up alarm handler");
+		alarm(10);
+		while (1) {
+			char c;
+			int status;
+			status = read(slave_fd, &c, 1);
+			if (status == -1) {
+				if (errno != EINTR || MR_got_alarm) {
+					perror(
+					"error reading from pseudo-terminal");
+					goto parent_error;
+				}
+			} else if (status == 0 || c == '\n') {
+				break;
+			}
+		}
+
+		/* Reset the alarm handler. */
+		alarm(0);
+		MR_setup_signal(SIGALRM, (MR_Code *) old_alarm_handler,
+			FALSE, "error resetting alarm handler");
+
+#if defined(HAVE_TCGETATTR) && defined(HAVE_TCSETATTR)
+		/* Restore echoing. */
+		termio.c_lflag |= ECHO;
+		tcsetattr(slave_fd, TCSADRAIN, &termio);
+#endif
+
+		if ((out_fd = dup(slave_fd)) == -1) {
+			perror(
+			    "opening slave pseudo-terminal for xterm failed");
+			goto parent_error;
+		}
+		if ((err_fd = dup(slave_fd)) == -1) {
+			perror(
+			    "opening slave pseudo-terminal for xterm failed");
+			goto parent_error;
+		}
+
+		MR_mdb_in = fdopen(slave_fd, "r");
+		if (MR_mdb_in == NULL) {
+		    perror("opening slave pseudo-terminal for xterm failed");
+		    goto parent_error;
+		}
+		MR_mdb_out = fdopen(out_fd, "w");
+		if (MR_mdb_out == NULL) {
+		    perror("opening slave pseudo-terminal for xterm failed");
+		    goto parent_error;
+		}
+		MR_mdb_err = fdopen(err_fd, "w");
+		if (MR_mdb_err == NULL) {
+		    perror("opening slave pseudo-terminal for xterm failed");
+		    goto parent_error;
+		}
+
+		MR_have_mdb_window = TRUE;
+		MR_mdb_window_pid = child_pid;
+		return TRUE;
+
+parent_error:
+#if defined(HAVE_KILL) && defined(SIGTERM) && defined(HAVE_WAIT)
+		if (kill(child_pid, SIGTERM) != -1) {
+			do {
+				wait_status = wait(NULL);
+				if (wait_status == -1 && errno != EINTR) {
+					break;	
+				}
+			} while (wait_status != child_pid);
+		}
+#endif
+		if (MR_mdb_in) fclose(MR_mdb_in);
+		if (MR_mdb_out) fclose(MR_mdb_out);
+		if (MR_mdb_err) fclose(MR_mdb_err);
+		close(slave_fd);
+		close(out_fd);
+		close(err_fd);
+		return FALSE;
+
+	}
+
+#else 	/* HAVE_OPEN, etc. */
+	fprintf(stderr,
+		"Sorry, `mdb --window' not supported on this platform.\n");
+	return FALSE;
+#endif /* HAVE_OPEN, etc. */
+}
+
 static void
 MR_trace_internal_init_from_env(void)
 {
@@ -1215,18 +1496,18 @@
 		bool			force = FALSE;
 		bool			verbose = FALSE;
 		bool			split = FALSE;
-		bool			close = FALSE;
+		bool			close_window = FALSE;
 		const char		*msg;
 
 		if (! MR_trace_options_view(&window_cmd, &server_cmd,
 				&server_name, &timeout, &force, &verbose,
-				&split, &close, &words, &word_count,
+				&split, &close_window, &words, &word_count,
 				"browsing", "view"))
 		{
 			; /* the usage message has already been printed */
 		} else if (word_count != 1) {
 			MR_trace_usage("browsing", "view");
-		} else if (close) {
+		} else if (close_window) {
 			MR_trace_maybe_close_source_window(verbose);
 		} else {
 			msg = MR_trace_new_source_window(window_cmd,
@@ -3037,7 +3318,7 @@
 static bool
 MR_trace_options_view(const char **window_cmd, const char **server_cmd,
 		const char **server_name, int *timeout, bool *force,
-		bool *verbose, bool *split, bool *close, char ***words,
+		bool *verbose, bool *split, bool *close_window, char ***words,
 		int *word_count, const char *cat, const char *item)
 {
 	int	c;
@@ -3058,11 +3339,11 @@
 					MR_trace_usage(cat, item);
 					return FALSE;
 				}
-				*close = TRUE;
+				*close_window = TRUE;
 				break;
 
 			case 'w':
-				if (*close) {
+				if (*close_window) {
 					MR_trace_usage(cat, item);
 					return FALSE;
 				}
@@ -3089,7 +3370,7 @@
 				break;
 
 			case 't':
-				if (*close ||
+				if (*close_window ||
 					sscanf(MR_optarg, "%d", timeout) != 1)
 				{
 					MR_trace_usage(cat, item);
@@ -3099,7 +3380,7 @@
 				break;
 
 			case 'f':
-				if (*close) {
+				if (*close_window) {
 					MR_trace_usage(cat, item);
 					return FALSE;
 				}
@@ -3112,7 +3393,7 @@
 				break;
 
 			case '2':
-				if (*close) {
+				if (*close_window) {
 					MR_trace_usage(cat, item);
 					return FALSE;
 				}
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list