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