OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [or1ksim/] [peripheral/] [channels/] [xterm.c] - Rev 1146

Go to most recent revision | Compare with Previous | Blame | View Log

/* xterm.c -- Definition of functions and structures for 
   peripheral to communicate with host through an xterm.
   Inspired from SWI-Prolog by Jan Wielemaker (GPL too)
   even if there is really few in common.
 
   Copyright (C) 2002 Richard Prescott <rip@step.polymtl.ca>
 
This file is part of OpenRISC 1000 Architectural Simulator.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
/*
 *  I really dislike using stuff beginning with '_' 
 *  They are suppose to be reserved for the compiler
 *  as explained in C standards.
 */
#define _XOPEN_SOURCE		/* grantpt() and al. */
#define _GNU_SOURCE		/* on_exit */
 
#include <sys/types.h>		/* waitpid() */
#include <sys/wait.h>		/* waitpid() */
#include <stdio.h>		/* sprintf() */
#include <stdlib.h>		/* kill(), on_exit() */
#include <unistd.h>		/* close() */
#include <fcntl.h>		/* O_RDWR */
#include <string.h>		/* strchr() */
 
#ifndef __CYGWIN__
#include <sys/stropts.h>	/* grantpt(), unlockpt() */
#include <libgen.h>		/* basename() */
#endif /* __CYGWIN__ */
 
#include <termios.h>		/* struct termios and al. */
#include <signal.h>		/* signal() and al. */
#include <errno.h>		/* errno and al. */
 
#include "channel.h"
#include "generic.h"
#include "fd.h"
 
struct xterm_channel
{
	struct fd_channel fds;
	int pid;
	char** argv;
};
 
#ifdef __CYGWIN__
char *basename(const char *filename)
{
	char *p = strrchr (filename, '/');
 
	return p ? p + 1 : (char *) filename;
}
#endif /* __CYGWIN__ */
 
static void xterm_close(void * data)
{
	struct xterm_channel * xt = data;
 
	if(!xt)
		return;
 
	if(xt->fds.fdin != -1)
		close(xt->fds.fdin);
 
	if(xt->pid != -1)
	{
		kill(xt->pid, SIGKILL);
		waitpid(xt->pid, NULL, 0);
	}
 
	if (xt->argv)
		free (xt->argv);
 
	xt->fds.fdin = -1;
	xt->fds.fdout = -1;
	xt->pid = -1;
	xt->argv = NULL;
 
}
 
static void xterm_exit(int i, void * data)
{
	xterm_close(data);
}
 
#define MAX_XTERM_ARGS 100
static void * xterm_init(const char * input)
{
	struct xterm_channel * retval = malloc(sizeof(struct xterm_channel));
	if(retval)
	{
		int i;
		char *arglist;
 
		retval->fds.fdin = -1;
		retval->fds.fdout = -1;
		retval->pid = -1;
		/* reset cause exit(1), leaving an xterm opened */
		on_exit(xterm_exit, retval);
 
		i = 2;
		arglist = (char*)input;
		retval->argv = malloc(sizeof(char*) * MAX_XTERM_ARGS);
		if (!retval->argv) {
			free(retval);
			return NULL;
		}
		/* Assume xterm arguments are separated by whitespace */
		while (retval->argv[i++] = strtok(arglist, " \t\n")) {
			arglist = NULL;
			if (i == MAX_XTERM_ARGS - 1) {
				free(retval);
				return NULL;
			}
		}
 
	}
	return (void*)retval;
}
 
 
 
static int xterm_open(void * data)
{
	struct xterm_channel * xt = data;
	int master, retval;
	char * slavename;
	struct termios termio;
	char arg[64], * fin;
 
	if(!data)
	{
		errno = ENODEV;
		return -1;
	}
 
	master = open("/dev/ptmx", O_RDWR);
 
	if(master < 0)
		return -1;
 
	grantpt(master);                             
	unlockpt(master);
	slavename = (char*)ptsname(master);
 
	if(!slavename)
	{
		errno = ENOTTY;
		goto closemastererror;
	}
 
	xt->fds.fdout = xt->fds.fdin = open(slavename, O_RDWR);
	if(xt->fds.fdout < 0) goto closemastererror;
 
#if !defined(linux) && !defined(__CYGWIN__)
	/* Linux does not support STREAMS-style line discipline, even with LiS. */
	retval = ioctl(xt->fds.fdin, I_PUSH, "ptem"); 
	if(retval < 0) goto closeslaveerror;
 
	retval = ioctl(xt->fds.fdin, I_PUSH, "ldterm");
	if(retval < 0) goto closeslaveerror;
#endif
 
	retval = tcgetattr(xt->fds.fdin, &termio);
	if(retval < 0) goto closeslaveerror;
	termio.c_lflag &= ~ECHO;
	retval = tcsetattr(xt->fds.fdin, TCSADRAIN, &termio);
	if(retval < 0) goto closeslaveerror;
 
	xt->pid = fork();
 
	if(xt->pid == -1) goto closeslaveerror;
 
	if(xt->pid == 0)
	{
		/* Ctrl-C on sim still kill the xterm, grrr */
		signal(SIGINT, SIG_IGN);
 
		fin = slavename+strlen(slavename)-2;
		if (strchr(fin, '/' ))
		{
			sprintf(arg, "-S%s/%d",
				basename(slavename),
				master);
		}
		else
		{
		      sprintf(arg, "-S%c%c%d", fin[0], fin[1], master);
		}
		xt->argv[0] = "xterm";
		xt->argv[1] = arg;
		execvp("xterm", xt->argv);
		write(master, "\n", 1);
		exit(1);
	}
 
	do retval = read(xt->fds.fdin, &arg, 1);
	while(retval >= 0 && arg[0] != '\n');
	if(retval < 0) goto closeslaveerror;
 
	termio.c_lflag |= ECHO;
	retval = tcsetattr(xt->fds.fdin, TCSADRAIN, &termio);
 
	if(retval < 0) goto closeslaveerror;
 
	return 0;
 
closeslaveerror:
	close(xt->fds.fdin);
 
closemastererror:
	close(master);
	xt->pid = xt->fds.fdin = xt->fds.fdout = -1;
	return -1;
}
 
struct channel_ops xterm_channel_ops =
{
	init:	xterm_init,
	open:	xterm_open,
	close:	xterm_close,
	read:	fd_read,
	write:	fd_write,
	free:	generic_free,
};
 
/*
 * Local variables:
 * c-file-style: "linux"
 * End:
 */
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.