[comp.emacs] more MicroEMACS 3.10 patches for Unix

mackenzi@thor.acc.stolaf.edu (David MacKenzie) (06/09/89)

Here are some diffs to MicroEMACS 3.10 for Unix.  They partially
duplicate some patches recently posted by rupley@arizona.edu that put
in the missing <sys/types.h> and <sys/stat.h> for USG.  They also
support POSIX <dirent.h> directory libraries; for this, I added the
symbol DIRENT.

The diffs also fix a bug in signal handling when running a subshell.
As distributed, MicroEMACS receives all keyboard signals generated when
running a subshell (^X-C i-shell).

Finally, they contain code to implement ^X-$ execute-program for real.
The 3.10 distribution fakes it for Unix by making ^X-$ the same as
^X-! shell-command.

*** unix.c.orig	Thu May 11 13:09:36 1989
--- unix.c	Thu May 11 13:01:45 1989
***************
*** 15,21 ****
--- 15,28 ----
  #include	<signal.h>
  #include	<termio.h>
  #include	<fcntl.h>
+ #include	<sys/types.h>
+ #include	<sys/stat.h>
+ #if	DIRENT
+ #include	<dirent.h>
+ #define direct dirent
+ #else
  #include	<ndir.h>
+ #endif
  int kbdflgs;			/* saved keyboard fd flags	*/
  int kbdpoll;			/* in O_NDELAY mode			*/
  int kbdqp;			/* there is a char in kbdq	*/
***************
*** 49,55 ****
  #endif
  
  #if     V7 | USG | HPUX | SUN | XENIX | BSD
- #include        <signal.h>
  extern int vttidy();
  #endif
  
--- 56,61 ----
***************
*** 91,96 ****
--- 97,106 ----
  	signal(SIGCONT,rtfrmshell);	/* suspend & restart emacs */
  #endif
  #endif
+ 	/* if we spawn a subshell we don't want to die if the user hits
+ 	   the interrupt or quit keys */
+ 	signal(SIGINT, SIG_IGN);
+ 	signal(SIGQUIT, SIG_IGN);
  	/* on all screens we are not sure of the initial position
  	   of the cursor					*/
  	ttrow = 999;
***************
*** 217,223 ****
  		if (fcntl(0, F_SETFL, kbdflgs | O_NDELAY) < 0 && kbdpoll)
  			return(FALSE);
  		kbdpoll = TRUE;
! 		kbdqp = (1 == read(0, kbdq, 1));
  	}
  	return(kbdqp);
  #endif
--- 227,233 ----
  		if (fcntl(0, F_SETFL, kbdflgs | O_NDELAY) < 0 && kbdpoll)
  			return(FALSE);
  		kbdpoll = TRUE;
! 		kbdqp = (1 == read(0, kbdq, 1));
  	}
  	return(kbdqp);
  #endif
***************
*** 299,308 ****
          TTclose();                              /* stty to old modes    */
          system(line);
          TTopen();
-         TTflush();
  	/* if we are interactive, pause here */
  	if (clexec == FALSE) {
  	        mlputs(TEXT6);
  /*                     "\r\n\n[End]" */
          	tgetc();
          }
--- 309,318 ----
          TTclose();                              /* stty to old modes    */
          system(line);
          TTopen();
  	/* if we are interactive, pause here */
  	if (clexec == FALSE) {
  	        mlputs(TEXT6);
+ 	        TTflush();
  /*                     "\r\n\n[End]" */
          	tgetc();
          }
***************
*** 317,323 ****
   */
  
  execprg(f, n)
- 
  {
          register int    s;
          char            line[NLINE];
--- 327,332 ----
***************
*** 326,348 ****
  	if (restflag)
  		return(resterr());
  
!         if ((s=mlreply("!", line, NLINE)) != TRUE)
                  return(s);
          TTputc('\n');                /* Already have '\r'    */
          TTflush();
          TTclose();                              /* stty to old modes    */
!         system(line);
          TTopen();
!         mlputs(TEXT188);                        /* Pause.               */
! /*             "[End]" */
!         TTflush();
!         while ((s = tgetc()) != '\r' && s != ' ')
!                 ;
          sgarbf = TRUE;
          return(TRUE);
  }
  
  /*
   * Pipe a one line command into a window
   * Bound to ^X @
   */
--- 335,492 ----
  	if (restflag)
  		return(resterr());
  
!         if ((s=mlreply("$", line, NLINE)) != TRUE)
                  return(s);
          TTputc('\n');                /* Already have '\r'    */
          TTflush();
          TTclose();                              /* stty to old modes    */
!         execpr(line);
          TTopen();
! 	/* if we are interactive, pause here */
! 	if (clexec == FALSE) {
! 	        mlputs(TEXT6);
! 	        TTflush();
! /*                     "\r\n\n[End]" */
!         	tgetc();
!         }
          sgarbf = TRUE;
          return(TRUE);
  }
  
  /*
+  * Run a program with arguments without using a shell.
+  * Line is a string containing a program name and arguments, separated
+  * by whitespace.  Shell metacharacters have no special meaning.
+  */
+ 
+ execpr(line)
+ 	char           *line;
+ {
+ 	char          **stov();
+ 	char          **argv;
+ 	char           *cp;	/* A copy of the line in case it's $SHELL. */
+ 	int             pid;
+ 
+ 	if (line == 0 || *line == 0)
+ 		return;
+ 
+ 	cp = malloc(strlen(line) + 1);
+ 	strcpy(cp, line);
+ 	argv = stov(cp);
+ 
+ 	pid = fork();
+ 	switch (pid) {
+ 	case -1:
+ 		break;
+ 	case 0:		/* Child. */
+ 		signal(SIGINT, SIG_DFL);
+ 		signal(SIGQUIT, SIG_DFL);
+ 		execvp(argv[0], argv);
+ 		/* Might want to print "argv[0]: Command not found.\n". */
+ 		exit(0);
+ 	default:		/* Parent. */
+ 		while (wait((int *) 0) != pid)
+ 			 /* Do nothing. */ ;
+ 		break;
+ 	}
+ 	free(argv);
+ 	free(cp);
+ }
+ 
+ /* Number of arguments between realloc's. */
+ #define GRANULARITY 10
+ 
+ /*
+  * Make an argv-like vector (string array) from a string (such as an
+  * environment variable).  The last element of the vector is null.
+  * Scatters nulls throughout s.
+  */
+ 
+ char **
+ stov(s)
+ 	char           *s;	/* The string to vectorize. */
+ {
+ 	char           *malloc(), *realloc(), *strtok();
+ 	int             argc;
+ 	char          **argv;
+ 
+ 	argc = 0;
+ 	argv = (char **) malloc((unsigned) (sizeof(char *) * GRANULARITY));
+ 
+ 	for (s = strtok(s, " \t\n\r"); s;
+ 		s = strtok((char *) NULL, " \t\n\r")) {
+ 		if (argc > 0 && argc % GRANULARITY == 0)
+ 			argv = (char **) realloc((char *) argv, (unsigned)
+ 				(sizeof(char *) * (argc + GRANULARITY)));
+ 		argv[argc++] = s;
+ 	}
+ 	argv = (char **) realloc((char *) argv,
+ 		(unsigned) (sizeof(char *) * (argc + 1)));
+ 	argv[argc] = NULL;
+ 	return argv;
+ }
+ 
+ #if V7 | BSD
+ /* Return the next token in string, delimited by one or more members of
+    the set separators.  If string is NULL, use the same string as in the
+    last call.  */
+ 
+ char *
+ strtok(string, separators)
+ 	char           *string;
+ 	char           *separators;
+ {
+ 	static char    *pos == NULL;	/* Current location in the string. */
+ 	register int    token_length;
+ 
+ 	if (string)
+ 		pos = string;
+ 	pos += strspn(pos, separators);	/* Skip initial separators. */
+ 	token_length = strcspn(pos, separators);	/* Find token length. */
+ 	if (token_length == 0)
+ 		return NULL;	/* No more tokens; pos is on a 0. */
+ 	separators = pos;	/* Re-use separators to save start of token. */
+ 	pos += token_length;	/* Move onto the 0. */
+ 	if (*pos)		/* If not the last token, */
+ 		*pos++ = 0;	/* null terminate the token. */
+ 	return separators;
+ }
+ 
+ /* Return the length of the span of characters at the start of string
+    that are members of class.  */
+ 
+ strspn(string, class)
+ 	char           *string;
+ 	char           *class;
+ {
+ 	char           *index();
+ 	register int    count;
+ 
+ 	for (count = 0; string[count]; ++count)
+ 		if (!index(class, string[count]))
+ 			break;
+ 	return count;
+ }
+ 
+ /* Return the length of the span of characters at the start of string
+    that are non-members of class.  */
+ 
+ strcspn(string, class)
+ 	char           *string;
+ 	char           *class;
+ {
+ 	char           *index();
+ 	register int    count;
+ 
+ 	for (count = 0; string[count]; ++count)
+ 		if (index(class, string[count]))
+ 			break;
+ 	return count;
+ }
+ 
+ #endif
+ 
+ /*
   * Pipe a one line command into a window
   * Bound to ^X @
   */
***************
*** 570,576 ****
  {
  	register struct direct *dp;	/* directory entry pointer */
  	register int index;		/* index into various strings */
! 	struct stat fstat;
  
  	/* and call for the next file */
  nxtdir:	dp = readdir(dirptr);
--- 714,720 ----
  {
  	register struct direct *dp;	/* directory entry pointer */
  	register int index;		/* index into various strings */
! 	struct stat stats;
  
  	/* and call for the next file */
  nxtdir:	dp = readdir(dirptr);
***************
*** 579,586 ****
  
  	/* check to make sure we skip directory entries */
  	strcpy(nameptr, dp->d_name);
! 	stat(rbuf, &fstat);
! 	if ((fstat.st_mode & S_IFMT) != S_IFREG)
  		goto nxtdir;
  
  	/* return the next file name! */
--- 723,730 ----
  
  	/* check to make sure we skip directory entries */
  	strcpy(nameptr, dp->d_name);
! 	stat(rbuf, &stats);
! 	if ((stats.st_mode & S_IFMT) != S_IFREG)
  		goto nxtdir;
  
  	/* return the next file name! */

-- 
David MacKenzie
mackenzi@thor.stolaf.edu or edf@rocky2.rockefeller.edu