[m-rev.] for review: source-linking for mdb

Mark Brown dougl at cs.mu.OZ.AU
Fri Oct 26 22:23:25 AEST 2001


Hi,

Vim 6.0 has a new client/server feature which Ralph recently suggested
could be used by mdb.  Below is a diff for a source-linking feature
of mdb.  The implementation is a bit crude and inefficient (especially
when using a forwarded X11 connection), but I thought it might be
desirable to have a vim version of source-linking, so we aren't forced
to use evil emacs.

A version of vim with the required feature is in /usr/local/bin/vim
on mars.

Anyone like to review this?

Cheers,
Mark.

Estimated hours taken: 6
Branches: main

Implement source-linking commands for mdb, using the new client/server
feature of vim.  New commands added to mdb are 'source_window', which
opens a source-linked window if there is not one already open, and
'source_window_close' which shuts any open source window.

This feature requires a version of vim compiled with '+clientserver'.
If such a program cannot be found, the mdb commands produce an error
message and do nothing else.

trace/mercury_trace_internal.c:
	Implement the new mdb commands.

	Add a new global variable which stores the information required
	for one source server.
	
	Every time mdb stops at an event, synchronise the source window
	if present with the source context of the event.  At interface
	events, we use the parent context if possible, since that is more
	useful information.

	When leaving mdb, close the source window if there is one open.

trace/mercury_trace_source.c:
trace/mercury_trace_source.h:
	Code for starting up and manipulating a source-server in a vim
	window.

trace/Mmakefile:
	Add the new module to the trace library.

doc/user_guide.texi:
doc/mdb_categories:
	Document the new mdb commands.

Index: doc/mdb_categories
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/mdb_categories,v
retrieving revision 1.10
diff -u -r1.10 mdb_categories
--- doc/mdb_categories	18 Jan 2001 03:01:52 -0000	1.10
+++ doc/mdb_categories	26 Oct 2001 07:00:57 -0000
@@ -26,7 +26,8 @@
 document_category 400 browsing
 browsing   - Commands that let users explore the state of the computation.
              The browsing commands are `vars', `print', `browse',
-             `stack', `up', `down', `level', and `current'.
+             `stack', `up', `down', `level', `current', `source_window'
+             and `source_window_close'.
 
 end
 document_category 500 breakpoint
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.274
diff -u -r1.274 user_guide.texi
--- doc/user_guide.texi	24 Oct 2001 07:10:18 -0000	1.274
+++ doc/user_guide.texi	26 Oct 2001 06:52:37 -0000
@@ -2384,6 +2384,46 @@
 the default is to affect all formats.
 In the case that the format itself is being set,
 these options are ignored.
+ at sp 1
+ at item source_window [-f] [-w @var{window-cmd}] [-s @var{server-cmd}] \
+[-n @var{server-name}] [-t @var{timeout}]
+ at kindex source_window (mdb command)
+Opens a new window displaying the source code,
+at the location of the current event.
+As mdb stops at new events,
+the window is updated to track through the source code.
+This requires a version of @samp{vim}
+compiled with the client/server option enabled.
+ at sp 1
+The debugger only updates one window at a time.
+If there is already a source window open,
+this command aborts with an error message.
+ at sp 1
+The option @samp{-f} (or @samp{--force})
+stops the command from aborting if there is already a window open.
+Instead it attempts to close that window first.
+ at sp 1
+The option @samp{-w} (or @samp{--window-command}) specifies
+the command to open a new window.
+The default is @samp{xterm -e}.
+ at sp 1
+The option @samp{-s} (or @samp{--server-command}) specifies
+the command to start the server.
+The default is @samp{vim}.
+ at sp 1
+The option @samp{-n} (or @samp{--server-name}) specifies
+the name of an existing server.
+Instead of starting up a new server,
+mdb will attempt to connect to the existing one.
+ at sp 1
+The option @samp{-t} (or @samp{--timeout}) specifies
+the maximum number of seconds to wait for the server to start.
+ at sp 1
+ at item source_window_close
+ at kindex source_window_close (mdb command)
+Attempts to close a currently open source window.
+The attempt may fail if, for example,
+the user has modified the source file without saving.
 @end table
 @sp 1
 @node Breakpoint commands
Index: tests/debugger/mdb_command_test.inp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/mdb_command_test.inp,v
retrieving revision 1.15
diff -u -r1.15 mdb_command_test.inp
--- tests/debugger/mdb_command_test.inp	7 Aug 2001 02:16:05 -0000	1.15
+++ tests/debugger/mdb_command_test.inp	26 Oct 2001 06:25:56 -0000
@@ -21,6 +21,8 @@
 level                xyzzy xyzzy xyzzy xyzzy xyzzy
 current              xyzzy xyzzy xyzzy xyzzy xyzzy
 set                  xyzzy xyzzy xyzzy xyzzy xyzzy
+source_window        xyzzy xyzzy xyzzy xyzzy xyzzy
+source_window_close  xyzzy xyzzy xyzzy xyzzy xyzzy
 break                xyzzy xyzzy xyzzy xyzzy xyzzy
 ignore               xyzzy xyzzy xyzzy xyzzy xyzzy
 disable              xyzzy xyzzy xyzzy xyzzy xyzzy
Index: trace/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/Mmakefile,v
retrieving revision 1.23
diff -u -r1.23 Mmakefile
--- trace/Mmakefile	29 Jun 2001 15:55:08 -0000	1.23
+++ trace/Mmakefile	25 Oct 2001 09:43:45 -0000
@@ -45,6 +45,7 @@
 			mercury_trace_help.h		\
 			mercury_trace_internal.h	\
 			mercury_trace_readline.h	\
+			mercury_trace_source.h		\
 			mercury_trace_spy.h		\
 			mercury_trace_tables.h		\
 			mercury_trace_util.h		\
@@ -60,6 +61,7 @@
 			mercury_trace_help.c		\
 			mercury_trace_internal.c	\
 			mercury_trace_readline.c	\
+			mercury_trace_source.c		\
 			mercury_trace_spy.c		\
 			mercury_trace_tables.c		\
 			mercury_trace_util.c		\
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.106
diff -u -r1.106 mercury_trace_internal.c
--- trace/mercury_trace_internal.c	7 Aug 2001 02:16:05 -0000	1.106
+++ trace/mercury_trace_internal.c	26 Oct 2001 05:34:32 -0000
@@ -26,6 +26,7 @@
 #include "mercury_trace_util.h"
 #include "mercury_trace_vars.h"
 #include "mercury_trace_readline.h"
+#include "mercury_trace_source.h"
 
 #include "mdb.browse.h"
 #include "mdb.browser_info.h"
@@ -100,6 +101,11 @@
 #endif
 
 /*
+** The details of the source server, if any.
+*/
+static	MR_Trace_Source_Server	MR_trace_source_server = { NULL, NULL };
+
+/*
 ** We print confirmation of commands (e.g. new aliases) if this is TRUE.
 */
 
@@ -178,6 +184,11 @@
 static	void	MR_print_unsigned_var(FILE *fp, const char *var,
 			MR_Unsigned value);
 static	bool	MR_parse_source_locn(char *word, const char **file, int *line);
+static	const char *MR_trace_new_source_window(const char *window_cmd,
+			const char *server_cmd, const char *server_name,
+			int timeout, bool force);
+static	void	MR_trace_maybe_sync_source_window(MR_Event_Info *event_info);
+static	void	MR_trace_maybe_close_source_window(void);
 static	bool	MR_trace_options_strict_print(MR_Trace_Cmd_Info *cmd,
 			char ***words, int *word_count,
 			const char *cat, const char *item);
@@ -206,6 +217,10 @@
 			MR_Word *verbose_format, MR_Word *pretty_format, 
 			char ***words, int *word_count, const char *cat, 
 			const char *item);
+static	bool	MR_trace_options_source_window(const char **window_cmd,
+			const char **server_cmd, const char **server_name,
+			int *timeout, bool *force, 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);
 
@@ -273,6 +288,7 @@
 	MR_trace_internal_ensure_init();
 
 	MR_trace_event_print_internal_report(event_info);
+	MR_trace_maybe_sync_source_window(event_info);
 
 	/*
 	** These globals can be overwritten when we call Mercury code,
@@ -1135,6 +1151,47 @@
 		{
 			MR_trace_usage("browsing", "set");
 		}
+	} else if (streq(words[0], "source_window")) {
+		const char		*window_cmd = NULL;
+		const char		*server_cmd = NULL;
+		const char		*server_name = NULL;
+		int			timeout = 8;	/* seconds */
+		bool			force = FALSE;
+		const char		*msg;
+
+		if (! MR_trace_options_source_window(&window_cmd, &server_cmd,
+				&server_name, &timeout, &force, &words,
+				&word_count, "browsing", "source_window"))
+		{
+			; /* the usage message has already been printed */
+		}
+		else if (word_count != 1)
+		{
+			MR_trace_usage("browsing", "source_window");
+		}
+		else
+		{
+			msg = MR_trace_new_source_window(window_cmd,
+					server_cmd, server_name, timeout,
+					force);
+			if (msg != NULL) {
+				fflush(MR_mdb_out);
+				fprintf(MR_mdb_err, "mdb: %s.\n", msg);
+			}
+
+			MR_trace_maybe_sync_source_window(event_info);
+		}
+	} else if (streq(words[0], "source_window_close")) {
+		const char		*msg;
+
+		if (word_count != 1)
+		{
+			MR_trace_usage("browsing", "source_window_close");
+		}
+		else
+		{
+			MR_trace_maybe_close_source_window();
+		}
 	} else if (streq(words[0], "break")) {
 		MR_Proc_Spec		spec;
 		MR_Spy_When		when;
@@ -2235,6 +2292,7 @@
 			}
 
 			if (confirmed) {
+				MR_trace_maybe_close_source_window();
 				exit(EXIT_SUCCESS);
 			}
 		} else {
@@ -2327,6 +2385,107 @@
 	return FALSE;
 }
 
+static const char *
+MR_trace_new_source_window(const char *window_cmd, const char *server_cmd,
+		const char *server_name, int timeout, bool force)
+{
+	const char	*msg;
+
+	if (MR_trace_source_server.server_name != NULL) {
+		/*
+		** We are already attached to a server.
+		*/
+		if (force) {
+			MR_trace_maybe_close_source_window();
+		} else {
+			return "error: server already open (use '-f' to force)";
+		}
+	}
+
+	if (server_name == NULL)
+	{
+		msg = MR_trace_source_open_server(&MR_trace_source_server,
+				window_cmd, timeout);
+	}
+	else
+	{
+		MR_trace_source_server.server_name =
+				MR_malloc(strlen(server_name) + 1);
+		strcpy(MR_trace_source_server.server_name, server_name);
+		msg = MR_trace_source_attach(&MR_trace_source_server, timeout);
+		if (msg != NULL) {
+			/*
+			** Something went wrong, so we should free the
+			** server name we allocated just above.
+			*/
+			MR_free(MR_trace_source_server.server_name);
+			MR_trace_source_server.server_name = NULL;
+		}
+	}
+
+	return msg;
+}
+
+static	void
+MR_trace_maybe_sync_source_window(MR_Event_Info *event_info)
+{
+	const MR_Label_Layout	*parent;
+	const char		*filename;
+	int			lineno;
+	const char		*problem; /* not used */
+	MR_Word			*base_sp, *base_curfr;
+	const char		*msg;
+
+	if (MR_trace_source_server.server_name != NULL) {
+		lineno = 0;
+		filename = "";
+
+		/*
+		** At interface ports we use the parent context if we can.
+		** Otherwise, we use the current context.
+		*/
+		if (MR_port_is_interface(event_info->MR_trace_port)) {
+			base_sp = MR_saved_sp(event_info->MR_saved_regs);
+			base_curfr = MR_saved_curfr(event_info->MR_saved_regs);
+			parent = MR_find_nth_ancestor(event_info->MR_event_sll,
+				1, &base_sp, &base_curfr, &problem);
+			if (parent != NULL) {
+				(void) MR_find_context(parent, &filename,
+					&lineno);
+			}
+		}
+
+		if (filename[0] == '\000') {
+			(void) MR_find_context(event_info->MR_event_sll,
+					&filename, &lineno);
+		}
+
+		msg = MR_trace_source_sync(&MR_trace_source_server, filename,
+				lineno);
+		if (msg != NULL) {
+			fflush(MR_mdb_out);
+			fprintf(MR_mdb_err, "mdb: %s.\n", msg);
+		}
+	}
+}
+
+static	void
+MR_trace_maybe_close_source_window(void)
+{
+	const char	*msg;
+
+	if (MR_trace_source_server.server_name != NULL) {
+		msg = MR_trace_source_close(&MR_trace_source_server);
+		if (msg != NULL) {
+			fflush(MR_mdb_out);
+			fprintf(MR_mdb_err, "mdb: %s.\n", msg);
+		}
+
+		MR_free(MR_trace_source_server.server_name);
+		MR_trace_source_server.server_name = NULL;
+	}
+}
+
 static struct MR_option MR_trace_strict_print_opts[] =
 {
 	{ "all",	MR_no_argument,	NULL,	'a' },
@@ -2779,6 +2938,65 @@
 	return TRUE;
 }
 
+static struct MR_option MR_trace_source_window_opts[] =
+{
+	{ "window-command",	MR_required_argument,	NULL,	'w' },
+	{ "server-command",	MR_required_argument,	NULL,	's' },
+	{ "server-name",	MR_required_argument,	NULL,	'n' },
+	{ "timeout",		MR_required_argument,	NULL,	't' },
+	{ "force",		MR_no_argument,		NULL,	'f' },
+	{ NULL,			MR_no_argument,		NULL,	0 }
+};
+
+static bool
+MR_trace_options_source_window(const char **window_cmd,
+		const char **server_cmd, const char **server_name,
+		int *timeout, bool *force, char ***words, int *word_count,
+		const char *cat, const char *item)
+{
+	int	c;
+
+	MR_optind = 0;
+	while ((c = MR_getopt_long(*word_count, *words, "w:s:n:t:f",
+			MR_trace_source_window_opts, NULL)) != EOF)
+	{
+		switch (c) {
+
+			case 'w':
+				*window_cmd = MR_optarg;
+				break;
+
+			case 's':
+				*server_cmd = MR_optarg;
+				break;
+
+			case 'n':
+				*server_name = MR_optarg;
+				break;
+
+			case 't':
+				if (sscanf(MR_optarg, "%d", timeout) != 1)
+				{
+					MR_trace_usage(cat, item);
+					return FALSE;
+				}
+				break;
+
+			case 'f':
+				*force = TRUE;
+				break;
+
+			default:
+				MR_trace_usage(cat, item);
+				return FALSE;
+		}
+	}
+
+	*words = *words + MR_optind - 1;
+	*word_count = *word_count - MR_optind + 1;
+	return TRUE;
+}
+
 static void
 MR_trace_usage(const char *cat, const char *item)
 /* cat is unused now, but could be used later */
@@ -3326,6 +3544,8 @@
 	{ "browsing", "level" },
 	{ "browsing", "current" },
 	{ "browsing", "set" },
+	{ "browsing", "source_window" },
+	{ "browsing", "source_window_close" },
 	{ "breakpoint", "break" },
 	{ "breakpoint", "ignore" },
 	{ "breakpoint", "enable" },
Index: trace/mercury_trace_source.c
===================================================================
RCS file: trace/mercury_trace_source.c
diff -N trace/mercury_trace_source.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ trace/mercury_trace_source.c	26 Oct 2001 10:22:37 -0000
@@ -0,0 +1,315 @@
+/*
+** Copyright (C) 2001 The University of Melbourne.
+** This file may only be copied under the terms of the GNU Library General
+** Public License - see the file COPYING.LIB in the Mercury distribution.
+*/
+
+/*
+** mercury_trace_source.c
+**
+** This file implements routines to open and use a window to display the
+** source code.  Using these requires an X server and a version of
+** vim compiled with '+clientserver'.  If these are not available an
+** error is returned.
+**
+** Main author: Mark Brown
+*/
+
+#include "mercury_imp.h"
+#include "mercury_trace_source.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef HAVE_UNISTD_H
+  #include <unistd.h>
+#endif
+
+#define MR_DEFAULT_SOURCE_WINDOW_COMMAND	"xterm -e"
+#define MR_DEFAULT_SOURCE_SERVER_COMMAND	"vim"
+
+/*
+** The name used for the server will be this basename followed by ".$PID".
+*/
+#define MR_SOURCE_SERVER_BASENAME		"mdb_source_server"
+
+/*
+** Checks whether $DISPLAY is set to something reasonable.  If so,
+** returns NULL, otherwise returns a warning message.
+*/
+static const char *MR_trace_source_check_display(void);
+
+/*
+** Checks whether the server command is valid.  If so, returns NULL,
+** otherwise returns an error message.
+*/
+static const char *MR_trace_source_check_server_cmd(const char *server_cmd);
+
+/*
+** Checks whether a server with the given name is accessible.  If so,
+** returns NULL, otherwise returns an error message.
+*/
+static const char *MR_trace_source_check_server(const char *server_cmd,
+		const char *server_name);
+
+static const char *
+MR_trace_source_check_display(void)
+{
+	if (getenv("DISPLAY") == NULL) {
+		return "warning: DISPLAY environment variable is not set";
+	} else {
+		return NULL;
+	}
+}
+
+#define MR_SYSCALL_BUFFER_SIZE 512
+
+static const char *
+MR_trace_source_check_server_cmd(const char *server_cmd)
+{
+	char		system_call[MR_SYSCALL_BUFFER_SIZE];
+	int		status;
+
+	/*
+	** Try running the server with '--version', and see if the
+	** output contains the string '+clientserver'.
+	**
+	** XXX if either server_cmd or fgrep is not found, the shell
+	** will print an error message that will end up on our terminal.
+	*/
+	sprintf(system_call, "%s --version 2>&1 | fgrep -q '+clientserver'",
+		server_cmd);
+	status = system(system_call);
+	if (status == 0) {
+		return NULL;
+	} else {
+		return "error: source server command is not valid";
+	}
+}
+
+static const char *
+MR_trace_source_check_server(const char *server_cmd, const char *server_name)
+{
+	char		system_call[MR_SYSCALL_BUFFER_SIZE];
+	int		status;
+
+	/*
+	** Try running a server with '--serverlist', and see if the
+	** output contains our server name.  Server names are case
+	** insensitive.
+	*/
+	sprintf(system_call, "%s --serverlist | fgrep -iq '%s'",
+			server_cmd, server_name);
+	status = system(system_call);
+	if (status == 0) {
+		return NULL;
+	} else {
+		return "error: source server not found";
+	}
+}
+
+const char *
+MR_trace_source_open_server(MR_Trace_Source_Server *server,
+		const char *window_cmd, int timeout)
+{
+	const char 	*real_window_cmd;
+	const char	*real_server_cmd;
+	char		*name;
+	const char	*msg;
+	char		system_call[MR_SYSCALL_BUFFER_SIZE];
+	int		status;
+	int		i;
+
+	if (window_cmd != NULL) {
+		real_window_cmd = window_cmd;
+	} else {
+		real_window_cmd = MR_DEFAULT_SOURCE_WINDOW_COMMAND;
+	}
+
+	if (server->server_cmd != NULL) {
+		real_server_cmd = server->server_cmd;
+	} else {
+		real_server_cmd = MR_DEFAULT_SOURCE_SERVER_COMMAND;
+	}
+
+	/*
+	** 1) check that display is set;
+	** 2) check that server is valid;
+	** 3) start a server with a unique name;
+	** 4) wait until the server is found;
+	*/
+
+	msg = MR_trace_source_check_display();
+	if (msg != NULL) {
+		return msg;
+	}
+
+	msg = MR_trace_source_check_server_cmd(real_server_cmd);
+	if (msg != NULL) {
+		return msg;
+	}
+
+	/*
+	** We generate a unique name by appending a number to a fixed
+	** string.  The number used is determined by trying all numbers
+	** in sequence until one is found that is not being used.
+	**
+	** XXX this is quite a slow way of doing things, and there is
+	** also a race condition, but it is difficult to see a better way.
+	** We should let the server pick a unique name for itself, but
+	** how would you communicate this name back to this process?
+	*/
+	i = 0;
+	/* Need to leave enough room for the integer */
+	name = MR_malloc(strlen(MR_SOURCE_SERVER_BASENAME) + 10);
+	do {
+		i++;
+		sprintf(name, "%s.%d", MR_SOURCE_SERVER_BASENAME, i);
+		/*
+		** This should fail if there is no server with this
+		** name.
+		*/
+		msg = MR_trace_source_check_server(real_server_cmd, name);
+	} while (msg == NULL);
+	server->server_name = name;
+
+	/*
+	** Start the server in read-only mode, to discourage the user
+	** from trying to edit the source.
+	*/
+	sprintf(system_call, "%s %s -R --servername \"%s\" &",
+			real_window_cmd, real_server_cmd, name);
+	system(system_call);
+
+	/*
+	** We need to wait until the source server has registered itself
+	** with the X server.  If we don't, we may execute remote
+	** commands before the server has started up, and this will
+	** result in vim (rather inconveniently) starting its own server
+	** on mdb's terminal.
+	*/
+
+	msg = MR_trace_source_attach(server, timeout);
+
+	if (msg != NULL) {
+		/*
+		** Something went wrong, so we should free the server
+		** name we allocated just above.
+		*/
+		MR_free(server->server_name);
+		server->server_name = NULL;
+	}
+
+	return msg;
+}
+
+const char *
+MR_trace_source_attach(MR_Trace_Source_Server *server, int timeout)
+{
+	const char	*real_server_cmd;
+	const char	*msg;
+	int		i;
+
+	if (server->server_cmd != NULL) {
+		real_server_cmd = server->server_cmd;
+	} else {
+		real_server_cmd = MR_DEFAULT_SOURCE_SERVER_COMMAND;
+	}
+
+	msg = MR_trace_source_check_server(real_server_cmd,
+			server->server_name);
+	if (msg == NULL) {
+		return NULL;
+	}
+
+	for (i = 0; i < timeout; i++) {
+		/*
+		** XXX This is an inaccurate way of keeping time.
+		*/
+		sleep(1);
+
+		msg = MR_trace_source_check_server(real_server_cmd,
+				server->server_name);
+		if (msg == NULL) {
+			return NULL;
+		}
+	}
+
+	return "timeout: source server not found";
+}
+
+const char *
+MR_trace_source_sync(MR_Trace_Source_Server *server, const char *filename,
+		int lineno)
+{
+	const char	*real_server_cmd;
+	const char	*msg;
+	char		system_call[MR_SYSCALL_BUFFER_SIZE];
+	int		status;
+
+	if (server->server_cmd != NULL) {
+		real_server_cmd = server->server_cmd;
+	} else {
+		real_server_cmd = MR_DEFAULT_SOURCE_SERVER_COMMAND;
+	}
+
+	msg = MR_trace_source_check_server(real_server_cmd,
+			server->server_name);
+	if (msg != NULL) {
+		return msg;
+	}
+
+	sprintf(system_call, "%s --servername \"%s\" --remote '+%d' %s",
+			real_server_cmd, server->server_name, lineno,
+			filename);
+	status = system(system_call);
+	if (status != 0) {
+		return "warning: source synchronisation failed";
+	} else {
+		return NULL;
+	}
+}
+
+const char *
+MR_trace_source_close(MR_Trace_Source_Server *server)
+{
+	const char	*real_server_cmd;
+	const char	*msg;
+	char		system_call[MR_SYSCALL_BUFFER_SIZE];
+
+	if (server->server_cmd != NULL) {
+		real_server_cmd = server->server_cmd;
+	} else {
+		real_server_cmd = MR_DEFAULT_SOURCE_SERVER_COMMAND;
+	}
+
+	msg = MR_trace_source_check_server(real_server_cmd,
+			server->server_name);
+	if (msg != NULL) {
+		return msg;
+	}
+
+	/*
+	** We first send "Ctrl-\ Ctrl-N", which guarantees we get back to
+	** "normal" mode without beeping, followed by ":q\n" which should
+	** quit.  This won't quit if the user has modified the file, which
+	** is just as well.
+	*/
+	sprintf(system_call,
+			"%s --servername \"%s\" --remote-send '\034\016:q\n'",
+			real_server_cmd, server->server_name);
+	system(system_call);
+
+	/*
+	** We expect the following to fail.  If it doesn't, the server
+	** didn't close properly.
+	*/
+	msg = MR_trace_source_check_server(real_server_cmd,
+			server->server_name);
+	if (msg == NULL) {
+		return "warning: failed to close source server";
+	} else {
+		return NULL;
+	}
+}
+
Index: trace/mercury_trace_source.h
===================================================================
RCS file: trace/mercury_trace_source.h
diff -N trace/mercury_trace_source.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ trace/mercury_trace_source.h	25 Oct 2001 18:41:19 -0000
@@ -0,0 +1,80 @@
+/*
+** Copyright (C) 2001 The University of Melbourne.
+** This file may only be copied under the terms of the GNU Library General
+** Public License - see the file COPYING.LIB in the Mercury distribution.
+*/
+
+/*
+** mercury_trace_source.h
+**
+** This file provides routines to open and use a window to display the
+** source code.  Using these requires an X server and a version of
+** vim compiled with '+clientserver'.  If these are not available an
+** error is returned.
+**
+** Main author: Mark Brown
+*/
+
+#ifndef MERCURY_TRACE_SOURCE_H
+#define MERCURY_TRACE_SOURCE_H
+
+/*
+** This holds the information for one server that the program is
+** attached to.  The fields are:
+** 
+** 	server_name	Name of the source server, or NULL if there
+** 			is no server.
+** 	server_cmd	Command to run to start the server, or connect
+** 			to it, or NULL if to use the default of "vim".
+*/
+typedef struct {
+	char		*server_name;
+	char		*server_cmd;
+} MR_Trace_Source_Server;
+
+/*
+** Start a server in a new window.  The arguments are:
+**
+** 	source_server	Info for the new server.  If server_name is
+** 			NULL, a new name is generated.  If the operation
+** 			succeeds, memory for the name will be MR_malloc'd
+** 			so the caller must MR_free it when no longer
+** 			needed.
+** 	window_cmd	Command to open a new window (NULL means
+** 			default to "xterm -e").
+** 	timeout		Maximum time to wait for the server to start,
+** 			in seconds.  XXX don't rely on the times being
+** 			accurate.
+**
+** If successful it returns NULL, otherwise it returns a string describing
+** the problem.
+*/
+const char *MR_trace_source_open_server(MR_Trace_Source_Server *server,
+		const char *window_cmd, int timeout);
+
+/*
+** Attach to an already running server.  If successful it returns NULL,
+** otherwise it returns a string describing the problem.
+*/
+const char *MR_trace_source_attach(MR_Trace_Source_Server *server,
+		int timeout);
+
+/*
+** Synchronise the server with the current source location.  This first
+** checks if the server is running (since the user could have exited
+** from the server window manually).  If there is no such server, returns
+** a warning message and does nothing else; returns NULL if there were no
+** problems.
+*/
+const char *MR_trace_source_sync(MR_Trace_Source_Server *server,
+		const char *filename, int lineno);
+
+/*
+** Close a server if possible.  If the server appears to be still
+** running after this, returns a warning message.  This can happen if
+** the user has modified the code in the source window, for example.
+*/
+const char *MR_trace_source_close(MR_Trace_Source_Server *server);
+
+#endif /* not MERCURY_TRACE_SOURCE_H */
+
--------------------------------------------------------------------------
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