Minix1.5/commands/elvis/system.c

Compare this file to the similar file:
Show the results in this format:

/* system.c  -- UNIX version */

/* Author:
 *	Steve Kirkendall
 *	16820 SW Tallac Way
 *	Beaverton, OR 97006
 *	kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
 */


/* This file contains a new version of the system() function and related stuff.
 *
 * Entry points are:
 *	system(cmd)	- run a single shell command
 *	wildcard(names)	- expand wildcard characters in filanames
 *	filter(m,n,cmd)	- run text lines through a filter program
 *
 * This is probably the single least portable file in the program.  The code
 * shown here should work correctly if it links at all; it will work on UNIX
 * and any O.S./Compiler combination which adheres to UNIX forking conventions.
 * For DOS, these three functions will have to be reimplemented from scratch.
 */

#include <sys/types.h>
#include <signal.h>
#include "vi.h"
extern		trapint();
extern char	**environ;


/* This is a new version of the system() function.  The only difference
 * between this one and the library one is: this one uses the o_shell option.
 */
int system(cmd)
	char	*cmd;	/* a command to run */
{
	int	status;	/* exit status of the command */

	switch (fork())
	{
	  case -1:						/* error */
		status = -1;
		break;

	  case 0:						/* child */
		execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
		exit(1); /* if we get here, the exec failed */

	  default:						/* parent */
		signal(SIGINT, SIG_IGN);
		wait(&status);
		signal(SIGINT, trapint);
	}

	return status;
}


/* This private function opens a pipe from a filter.  It is similar to the
 * system() function above, and to popen(cmd, "r").
 */
static int rpipe(cmd, in)
	char	*cmd;	/* the filter command to use */
	int	in;	/* the fd to use for stdin */
{
	int	r0w1[2];/* the pipe fd's */

	/* make the pipe */
	if (pipe(r0w1) < 0)
	{
		return -1;	/* pipe failed */
	}

	switch (fork())
	{
	  case -1:						/* error */
		return -1;

	  case 0:						/* child */
		/* close the "read" end of the pipe */
		close(r0w1[0]);

		/* redirect stdout to go to the "write" end of the pipe */
		close(1);
		dup(r0w1[1]);
		close(2);
		dup(r0w1[1]);
		close(r0w1[1]);

		/* redirect stdin */
		if (in != 0)
		{
			close(0);
			dup(in);
			close(in);
		}

		/* exec the shell to run the command */
		execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
		exit(1); /* if we get here, exec failed */

	  default:						/* parent */
		signal(SIGINT, SIG_IGN);	/* <- reset after the wait() */

		/* close the "write" end of the pipe */	
		close(r0w1[1]);

		return r0w1[0];
	}
}

/* This function closes the pipe opened by rpipe(), and returns 0 for success */
int rpclose(fd)
	int	fd;
{
	int	status;

	close(fd);
	wait(&status);
	signal(SIGINT, trapint);
	return status;
}

/* This function expands wildcards in a filename or filenames.  It does this
 * by running the "echo" command on the filenames via the shell; it is assumed
 * that the shell will expand the names for you.  If for any reason it can't
 * run echo, then it returns the names unmodified.
 */
char *wildcard(names)
	char	*names;
{
	int	i, j, fd;

	/* build the echo command */
	if (names != tmpblk.c)
	{
		/* the names aren't in tmpblk.c, so we can do it the easy way */
		strcpy(tmpblk.c, "echo ");
		strcat(tmpblk.c, names);
	}
	else
	{
		register char *s, *d;

		/* the names are already in tmpblk.c, so shift them to make
		 * room for the word "echo "
		 */
		for (s = names + strlen(names) + 1, d = s + 5; s > names; )
		{
			*--d = *--s;
		}
		strncpy(names, "echo ", 5);
	}

	/* run the command & read the resulting names */
	fd = rpipe(tmpblk.c, 0);
	if (fd < 0) return names;
	i = 0;
	do
	{
		j = read(fd, tmpblk.c, BLKSIZE - i);
		i += j;
	} while (j > 0);

	/* successful? */
	if (rpclose(fd) == 0 && j == 0 && i < BLKSIZE && i > 0)
	{
		tmpblk.c[i-1] = '\0'; /* "i-1" so we clip off the newline */
		return tmpblk.c;
	}
	else
	{
		return names;
	}
}

/* This function runs a range of lines through a filter program, and replaces
 * the original text with the filtered version.
 */
int filter(from, to, cmd)
	MARK	from, to;	/* the range of lines to filter */
	char	*cmd;		/* the filter command */
{
	int	scratch;	/* fd of the scratch file */
	int	fd;		/* fd of the pipe from the filter */
	int	i;

	/* write the lines to a temp file */
	cmd_write(from, to, CMD_BANG, 0, SCRATCHFILE);

	/* start the filter program */
	scratch = open(SCRATCHFILE, O_RDONLY);
	if (scratch < 0)
	{
		unlink(SCRATCHFILE);
		return -1;
	}
	fd = rpipe(cmd, scratch);
	if (fd < 0)
	{
		close(scratch);
		unlink(SCRATCHFILE);
		return -1;
	}

	ChangeText
	{
		/* delete the original lines.  Lines!  */
		from &= ~(BLKSIZE - 1);
		to &= ~(BLKSIZE - 1);
		to += BLKSIZE;
		delete(from, to);

		/* repeatedly read in new text and add it */
		while ((i = read(fd, tmpblk.c, BLKSIZE)) > 0)
		{
			tmpblk.c[i] = '\0';
			add(from, tmpblk.c);
			for (i = 0; tmpblk.c[i]; i++)
			{
				if (tmpblk.c[i] == '\n')
				{
					from = (from & ~(BLKSIZE - 1)) + BLKSIZE;
				}
				else
				{
					from++;
				}
			}
		}
	}

	/* cleanup */
	rpclose(fd);
	close(scratch);
	unlink(SCRATCHFILE);
	return 0;
}