[comp.sys.atari.st] GNU-Emacs wrapper for Gulam

roeder@sbsvax.UUCP (Edgar Roeder) (08/09/89)

Some people have reported trouble when they use GNU-Emacs under the Gulam shell.
The reason why suspend-emacs does not work as expected is that i assumed that
the shell saves all registers it uses and restores their original values on
exit from the shell. But Gulam trashes them. Now GCC has put some subroutine
address in a register which is no longer valid. This must lead to a crash.

I have fixed this in my library which will soon be posted but apparently i can
not post again 16 Parts of GNU-Emacs just for this fix.

So the appended little program tries to fix the problem. It intercepts a system
call from Emacs going to Gulam and saves all registers before the actual call
and restores them when the call comes back.

Another problem with Gulam is that you cannot get an interactive shell by just
passing "-i" or "" to the shell (older Gulam versions allowed ""). Therefore
i am changing "-i" to "ue". You will get into the build-in micro-Emacs of
Gulam where you can do some work. To go back to GNU-Emacs you type ^Z or ^X^C.
If you type 'exit' then GNU-Emacs is terminated.

Just a few notes about other problems which people have reported:
	- The \etc\termcap file must not contain CR after '\' at the end of a
	  line. Otherwise the entry is read incorrect by Emacs.
	- The documentation files are not searched in $EMACSLOADPATH. This is
	  a problem from the original Emacs. If your shell has no symbolic
	  links you have to use the original directory structure.
	- The functions suspend-emacs/call-process can ONLY work with shells
	  that use the _shell_p system variable. In other shells you get the
	  message "Program stopped!!!" but Emacs resumes instantly.
	- Emacs cannot understand the use of drives in strings like
	  "A:\homedir" but it understands both "\dev\a\homedir" and "\homedir"
	  and of cource the same with slashes in place of the backslashes.
	  This applies to all environment vars read in by Emacs (eg. HOME).

On just another topic: if you recompile Emacs with the new malloc-routines from
Piet van Oostrum and Atze Dijkstra you will get less memory for system calls
(almost nothing) but even on a 1 MB system you could work some hours without
running out of memory. This is because i had to use the C-alloca in the posted
version.

- Edgar
------------------------------ cut here ----------------------------------------
#include <osbind.h>

#define kByte	* 1024

extern long	_stksize = 1 kByte;

extern	void	(*old_shell)(char *cmd);

/* The xbra protocoll specifies that the old_call can be found just before   */
/* the new entry point. If we would use the following two strings literally  */
/* in gulam_call the compiler would put them just before the functions image */

char	*shell_interactive = "-i";
char	*gulam_interactive = "ue";

/* the gulam_call function substitutes "-i" by "ue" and saves all registers */
/* so that gulam can do with them what it wants */
asm(".ascii \"XBRA\"");		/* this is the magic number for the protocol */
asm(".ascii \"GUSH\"");		/* that's our own magic */
asm("_old_shell: .long 0");	/* this points to Gulams shell call */

long
gulam_call(char *cmd)
{
	 if(!strcmp(cmd,shell_interactive)) cmd = gulam_interactive;
	 asm("moveml d1-a5, sp@-");
		 /* this ugly little piece of code is needed because gcc */
		 /* thinks it can optimize away the 'addql #4, sp'       */
		 asm("link a6, #0");
		 (*old_shell)(cmd);
		 asm("unlk a6");
	 asm("moveml sp@+, d1-a5");
	 /* no return - d0 holds the result already */
}

/* save old _shell_p according to the xbra protocol and install our routine */
int
install_shell(void)
{
	long	*_shell_p = (long *) 0x4F6L;

	old_shell = (void (*)()) (*_shell_p);
	if(!(long) old_shell) return 0;
	if((*((long *)(((long) old_shell)-10)) != 0x00420135L)) return 0;
	*_shell_p = (long) gulam_call;
	return 1;
}

void
remove_shell(void)
{
	long	*_shell_p = (long *) 0x4F6L;

	*_shell_p = (long)old_shell;
}

/* instead of calling gulam with gulam_call() we could also do a Ptermres() */
/* this way the intermediate shell is removed as soon as we exit from Gulam */
main()
{
	if(Supexec(install_shell)) {
		gulam_call(gulam_interactive);
		Supexec(remove_shell);
		exit(0);
	}
	else exit(1);
}