DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T s

⟦36a99dc84⟧ TextFile

    Length: 17055 (0x429f)
    Types: TextFile
    Names: »sys.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/Cchess/sys.c« 

TextFile

/* CCHESS SYSTEM ROUTINES.					Version 1.00
 *
 *   This is mostly low level i/o stuff and machine dependent routines.
 *
 *   (C) Copyright Jan Wolter - Apr 1986.
 */

#include "cchess.h"
#ifdef U42BSD
#  include <sys/time.h>
#  include <sys/types.h>
#else
   long time();
#endif U42BSD
#ifdef NODUP2
#  include <fcntl.h>
#endif NODUP2

/* Default mode setting systems */

#ifndef TSTTY
#  ifndef TTERMIO
#    ifndef TIOCTL
#      ifdef USYS_5
#        define TTERMIO
#      else
#        define TSTTY
#      endif USYS_5
#    endif TIOCTL
#  endif TTERMIO
#endif TSTTY

/* Make sure at most one of the mode setting variables is defined */

#ifndef TSTTY
#  ifndef TTERMIO
#    ifdef TIOCTL
#      define TSTTY
#      define setmode(x) ioctl(0,TIOCSETN,&x);
#      define getmode(x) ioctl(2,TIOCGETP,&x);
#    endif TIOCTL
#  endif TTERMIO
#else TSTTY
#  undef TTERMIO
#  define setmode(x) stty(0,&x);
#  define getmode(x) gtty(2,&x);
#endif TSTTY


/* Names for the signal definition routine in various signal handlers */

#ifdef LSIGNAL
#  define sigdef signal
#endif LSIGNAL
#ifdef LSIGSYS
#  define sigdef sigset
#endif LSIGSYS
#ifdef LSIGVEC
#  define sigdef signal
#endif LSIGVEC

#ifndef NOTERMCAP
short ospeed;			/* The output baud rate */
#endif NOTERMCAP

/* Stuff for the stty or old style ioctl() command */

static boolean funnymodes = FALSE;

#ifdef TSTTY
#include <sgtty.h>
static struct sgttyb p;
static short tpf;
#endif TSTTY

#ifdef TTERMIO
#include <termio.h>
static struct termio tio;
static tofg,tlfg;
static tcc4;
static tcc5;
#endif TTERMIO

/* ENTER()
 *
 *   These routines get a character from the keyboard.  Characters are converted
 *   to upper case, and only those appearing in <string> are accepted.  All
 *   other characters are received with a bell, and ignored.  If the character
 *   happens to be ^L, then it isn't echoed.  xenter() is the same as enter,
 *   but never echos the character.  While reading input, it maps the backspace
 *   character defined by the user via the "stty erase" command to '\b'.
 *   Thus routines calling these don't have to worry about what the backspace
 *   character really is. xenterd() and enterd() are the same as xenter and
 *   enter, only if the character input is a `\n', it returns the given default
 *   value instead.
 */

char enter(string)
char *string;
{
register char ch;
	ch = xenter(string);
	if (ch != '\014')
		wputchar(ch);
	return(ch);
}

char enterd(string,def)
char *string;
char def;
{
register char ch;
	wputchar(ch = xenterd(string,def));
	return(ch);
}

char xenter(string)
char *string;
{
register char ch;

	for (;;)
	{
#ifdef LSIGNAL
		ch = getchar();
#else
		if (susp1_flg)
			ch = getchar();
		else
		{
			if ((susp2_flg || setjmp(susp_env)) &&
				index(string,'\014') != 0)
			{
				susp2_flg = FALSE;
				return('\014');
			}
			susp1_flg = TRUE;
			ch = getchar();
			susp1_flg = FALSE;
		}
#endif LSIGNAL
		if (ch == bs_char)
			ch = '\b';
#ifdef TSTTY
		/* Map CR to NL on input, because we had to turn it off */
		else if (ch == '\r')
			ch = '\n';
#endif TSTTY
		else if (ch >= 'a' && ch <= 'z')
			ch -= 'a'-'A';
		if (index(string,ch) != 0)
			return(ch);
		bell();
	}
}

char xenterd(string,def)
char *string;
char def;
{
register char ch;

	for (;;)
	{
#ifdef LSIGNAL
		ch = getchar();
#else
		if (susp1_flg)
			ch = getchar();
		else
		{
			if ((susp2_flg || setjmp(susp_env)) &&
				index(string,'\014') != 0)
			{
				susp2_flg = FALSE;
				return('\014');
			}
			susp1_flg = TRUE;
			ch = getchar();
			susp1_flg = FALSE;
		}
#endif LSIGNAL
		if (ch == '\n' || ch == '\r')
			return(def);

		if (ch == bs_char)
			ch = '\b';
		else if (ch >= 'a' && ch <= 'z')
			ch -= 'a'-'A';

		if (index(string,ch) != 0)
			return(ch);
		bell();
	}
}


/* ENTERYN()
 *
 *   Enter Yes or No - Just like (enter("YN")=='Y' but it completes the word
 *   "Yes" or "No" with a linefeed at the end.  Enterdyn() uses the given
 *   default if return is entered.
 */

char enteryn()
{
register boolean f;

	f = (xenter("YN") == 'Y');
	wprint(yorn(f));
	wputchar('\n');
	return(f);
}

boolean enterdyn(def)
boolean def;
{
register char ch;
register boolean f;

	f = ((ch = xenter("YN\n")) == 'Y' || (ch == '\n' && def));
	wprint(yorn(f));
	wputchar('\n');
	return(f);
}

/* FGETL()
 *
 *   This is fgets() fixed to throw away the reminants of lines that are too
 *   long for the input buffer.  It does not include the newline on the end
 *   of the line.
 */

char *fgetl(buf,len,fp)
REGISTER char *buf;
REGISTER int len;
FILE *fp;
{
register int c,i;

	i=0;
	while((c=getc(fp)) != '\n')
	{
		if (c == EOF) return(NULL);
		if (i < len) buf[i++] = c;
	}
	buf[i] = '\0';
	return(buf);
}

/* READSTR()
 *
 *   This routine reads a string into <buffer> starting at character index <a>
 *   and with the last character not beyond the <l>th character.  It returns the
 *   index of the null at the end of the string.  If the flag <isfile> is set,
 *   ~'s are expanded out automatically in the first column and spaces are
 *   turned into underscores.  Neither leading nor tailing spaces are allowed.
 */

int readstr(buffer,a,l,isfile)
REGISTER char *buffer;
int a,l;
{
register int i = a;

	while((buffer[i] = getchar()) != '\n' && buffer[i] != '\r')
	{
		if (i == a )
		{
			/* No leading spaces or backspaces */
			if (buffer[a] == ' ' || buffer[a] == bs_char) continue;

			/* Expand a tilde into the home directory name */
			if (isfile && buffer[a] == '~')
			{
				strcpy(buffer+a,getenv("HOME"));
				while(buffer[i] != 0)
					wputchar(buffer[i++]);
				continue;
			}
		}

		/* Do backspaces */
		if (buffer[i]==bs_char)
		{
			i--;
			if (erases)
			{
				backspace();
				wputchar(' ');
				backspace();
			}
			else wputchar(buffer[i]);
		}
		else if (i < l && !iscntrl(buffer[i]))
		{
			if (isfile && buffer[i] == ' ')
				buffer[i] = '_';
			wputchar(buffer[i++]);
		}
		else
			/* Bell all other nonprintables */
			bell();
	}
	/* delete trailing spaces */
	while(i > 0 && buffer[--i] == (isfile ? '_' : ' '))
		;
	if (i > 0) i++;
	buffer[i] = '\0';
	wputchar('\n');
	return(i);
}

/* READDINT()
 *
 *   This is like readint(), but it prints and returns the default value
 *   given if the person doesn't type anything.
 */

int readdint(max,def)
int max,def;
{
int x;
	if (x = readint(max)) return(x);
	wprintf("%d",def);
	return(def);
}

/* READINT()
 *
 *   This routine reads an integer between 1 and <max> from the user.  It
 *   fights desparately to keep him from entering anything out of range.
 *   It returns 0 if the user doesn't type anything.
 */

static char digitstr[] = "0123456789\b\n";

int readint(max)
int max;
{
register int i,j;
char ch;
short ox=cx;

	i = 0;
	while ((ch=xenter(digitstr))!='\n')
	{
		if ((ch == '0') && (i == 0))
		{
			bell();
			continue;
		}
		if (ch == '\b')
		{
			if (i == 0)
				bell();
			else
			{
				i /= 10;
				if (erases)
				{
					backspace();
					wputchar(' ');
					backspace();
				}
				else
				{
					indent(ox-1);
					if (i>0) wprintf("%d",i);
				}
			}
			continue;
		}
		j = i*10 + ch - '0';
		if (j > max)
			bell();
		else
		{
			i = j;
			wputchar(ch);
		}
	}
	return(i);
}

/* RESETTY
 *
 * Return ttymodes to normal.
 *
 */

resetty()
{
	if (funnymodes)
	{
		term_exit();
		funnymodes = FALSE;
#ifdef TSTTY
		p.sg_flags = tpf;
		setmode(p);
#endif TSTTY
#ifdef TTERMIO
		tio.c_lflag = tlfg;
		tio.c_oflag = tofg;
		tio.c_cc[4] = tcc4;
		tio.c_cc[5] = tcc5;
		ioctl(0,TCSETA,&tio);
#endif TTERMIO
	}
}

/* DONE()
 *
 *   This is used as the exit routine after we are in cbreak mode.
 *   It resets to whatever mode we were in originally before exiting
 *   with the error code in the arguement.
 */

done(code)
int code;
{
	/* If we are doing each game, go on to the next */
	if (eachgame)
	{
		fclose(wfp);
		fclose(rfp);
		longjmp(jmpenv,code?code:10);
	}

	/* restore modes */
	resetty();
	exit(code);
}

/* INTR()
 *
 *   This is the BREAK interupt service routine.  It refuses to do anything
 *   if the interupt flag is not set true.
 */

intr()
{
	if (interupt)
	{
		resetty();
		sigdef(SIGINT,SIG_DFL);
		kill(getpid(),SIGINT);
#ifdef LSIGNAL
		pause(SIGINT);
#endif LSIGNAL
#ifdef LSIGSYS
		sigpause(SIGINT);
#endif LSIGSYS
#ifdef LSIGVEC
		sigpause(0);
#endif LSIGVEC
	}
}

#ifndef LSIGNAL

/* SUSP()
 *
 *   This is the suspend interupt service routine.  It's a kludge but it works
 *   real well.  Resets fancy modes before exiting, and puts them back on
 *   restart.
 */
susp()
{
#ifdef LSIGVEC
int mask;
#endif LSIGVEC
#ifdef TSTTY
short tpf2;
#endif TSTTY
#ifdef TTERMIO
short tofg2,tlfg2;
#endif TTERMIO

	if (interupt)
	{
#ifdef LSIGVEC
		/* record current signal mask */
		mask = sigblock(sigmask(SIGTSTP));
#endif LSIGVEC
		/* reset modes before suspending */
		term_exit();
#ifdef TSTTY
		tpf2 = p.sg_flags;
		p.sg_flags = tpf;
		setmode(p);
#endif TSTTY
#ifdef TTERMIO
		tlfg2 = tio.c_lflag;
		tofg2 = tio.c_oflag;
		tio.c_lflag = tlfg;
		tio.c_lflag = tofg;
		ioctl(0,TCSETA,&tio);
#endif TTERMIO
#ifdef LSIGSYS
		/* The sigsys way: */
		sigset(SIGTSTP,SIG_DFL);
		kill(getpid(),SIGTSTP);
		sigrelse(SIGTSTP);

		/* STOP HERE */

		/* put modes back before resuming */
		sighold(SIGTSTP);
		sigset(SIGTSTP,susp);
		sigset(SIGINT,intr);
#endif LSIGSYS
#ifdef LSIGVEC
		/* The sigvec way: */
		sigdef(SIGTSTP,SIG_DFL);
		sigsetmask(0);
		kill(getpid(),SIGTSTP);

		/* STOP HERE */

		sigsetmask(mask);
		sigdef(SIGTSTP,susp);
		sigdef(SIGINT,intr);
#endif LSIGVEC
#ifdef TSTTY
		p.sg_flags = tpf2;
		setmode(p);
#endif TSTTY
#ifdef TTERMIO
		tio.c_lflag = tlfg2;
		tio.c_oflag = tofg2;
		tio.c_cc[4] = 1;
		tio.c_cc[5] = 0;
		ioctl(0,TCSETA,&tio);
#endif TTERMIO
		term_init();
		susp2_flg = TRUE;
		if (susp1_flg) longjmp(susp_env,1);
	}
}
#endif LSIGNAL

#ifdef U43BSD
/* This is to sort of handle the Berkeley window size change interupt */
window_change()
{
int oldcols=COLS, oldlines=LINES;

	getwindow();
	if (oldcols != COLS || oldlines != LINES)
	{
		susp2_flg = TRUE;
		if (susp1_flg) longjmp(susp_env,1);
	}
}
#endif U43BSD

/* MESG()
 *
 *   Send Mail to the other player.  Use the the given text and subject
 *   heading.  Making this come out right may take some fooling around on
 *   any given system.
 */

#ifdef DEBUG
# define SENDTO (debugon ? DEBUG : hisid)
#else
# define SENDTO hisid
#endif DEBUG

/* Choose default mailer */
#ifndef MAILER
#  ifdef U41BSD
#    define MAILER "/etc/delivermail"
#  else
#    ifdef U42BSD
#      define MAILER "/usr/lib/sendmail"
#    else
#      define MAILER "/bin/mail"
#    endif U42BSD
#  endif U41BSD
#endif MAILER

mesg(subj,text)
char *subj, *text;
{
static boolean sent = FALSE;
char cmd[60];
FILE *cmdfd;
	
	/* No mail on solo games, and no more than one message per run */
	if (solo || sent) return;
	sent = TRUE;

	/* Turn off interupts */
	sigdef(SIGINT,SIG_IGN);
	sigdef(SIGQUIT,SIG_IGN);

	sprintf(cmd,"%s %s",MAILER,SENDTO);
	cmdfd = upopen(cmd,"w");

#ifdef UBERK
	fprintf(cmdfd,"To: %s\n",SENDTO);
#endif UBERK

	fprintf(cmdfd,"Subject: %s\n\n",subj);
	fprintf(cmdfd,"%s",text);

	fclose(cmdfd);		/* Don't use pclose -- don't want to wait */

	/* Replace signal handlers */
	sigdef(SIGINT,intr);
	sigdef(SIGQUIT,SIG_DFL);
}


/* INITTERM()
 *
 *   This routine Sets cbreak and no echo mode, and it reads in the termcap.
 *   It also sets the interupt routines up.
 */

initterm()
{
	readterm();			/* Get terminal IQ */
#ifdef TSTTY
	getmode(p);			/* Get tty driver mode */
	tpf = p.sg_flags;		/* Save old settings */
	bs_char = p.sg_erase;		/* Get backspace character */
#ifndef NOTERMCAP
	ospeed = p.sg_ospeed;		/* Terminal speed for tputs */
#endif NOTERMCAP
#endif TSTTY
#ifdef TTERMIO
	ioctl(2,TCGETA,&tio);		/* Get termio driver mode */
	tlfg = tio.c_lflag;		/* Save old settings */
	tofg = tio.c_oflag;		/* Save old settings */
	bs_char = tio.c_cc[2];		/* Get user's backspace character */
	tcc4 = tio.c_cc[4];		/* Save EOF character */
	tcc5 = tio.c_cc[5];		/* Save EOL character */
#ifndef NOTERMCAP
	ospeed = tio.c_cflag & CBAUD;	/* Terminal speed for tputs */
#endif NOTERMCAP
#endif TTERMIO

	/* Trap interupts from now on */
	sigdef(SIGINT,intr);		/* Fix cbreak/echo on interupt */
#ifndef LSIGNAL
	sigdef(SIGTSTP,susp);		/* Fix cbreak/echo on suspend */
#endif LSIGNAL
#ifdef U43BSD
	sigdef(SIGWINCH,window_change);
#endif U43BSD

	/* set cbreak and no echo */
	funnymodes = TRUE;
#ifdef TSTTY
	p.sg_flags |= CBREAK;		/* Turn on cbreak mode */
	p.sg_flags &= ~ECHO;		/* Turn off echo mode */
	p.sg_flags &= ~CRMOD;		/* Turn off nl to cr-nl mapping */
	setmode(p);			/* Set new modes */
#endif TSTTY
#ifdef TTERMIO
	tio.c_lflag &= ~(ICANON | ECHO); /* Turn off icanon and echo */
	tio.c_oflag &= ~(ONLCR | OCRNL); /* Turn off output nl mapping */
	tio.c_cc[4] = 1;		  /* Wait for only one character */
	tio.c_cc[5] = 0;		  /* No minimum delay */
	ioctl(0,TCSETA,&tio);		  /* Set new termio driver modes */
#endif TTERMIO
}


/* UPOPEN - Run command on a pipe
 *
 *    This is just like the Unix popen() call, except it runs the command
 *    with the original user id.  This is done for the same reasons mentioned
 *    in the usystem routine.
 */

FILE *upopen(cmd,mode)
char *cmd;
REGISTER char *mode;
{
int pip[2];
register int chd_pipe,par_pipe;
FILE *fdopen();
#ifdef NODUP2
int t;
#endif NODUP2

	/* Make a pipe */
	if (pipe(pip)) return((FILE *)0);

	/* Choose ends */
	par_pipe = (*mode == 'r') ? pip[0] : pip[1];
	chd_pipe = (*mode == 'r') ? pip[1] : pip[0];

	switch (fork())
	{
	case 0:
		/* Child - run command */
		close(par_pipe);
		if (chd_pipe != (*mode == 'r'?1:0))
		{
#ifdef NODUP2
			close(t = (*mode == 'r'?1:0));
			if (fcntl(chd_pipe,F_DUPFD,t) != t)
			{
				printf("Panic: can dup pipe\n");
				exit(1);
			}
#else
			dup2(chd_pipe,(*mode == 'r'?1:0));
#endif NODUP2
			close(chd_pipe);
		}
		setuid(getuid());
		setgid(getgid());
		execl("/bin/sh","sh","-c",cmd,NULL);
		exit(1);
	case -1:
		close(chd_pipe);
		close(par_pipe);
		return((FILE *)0);
	default:
		close(chd_pipe);
		return(fdopen(par_pipe,mode));
	}
}


/* DAY()
 *
 * Return today's date, in the form of the number of days since Jan 1, 1970.
 * Actually, the 4.2bsd could use the time() call too, but gettimeofday()
 * seems to be prefered.
 */

long day()
{
#define SECSPERDAY 86400L
#ifdef U42BSD
struct timeval tp;
struct timezone tzp;
	gettimeofday(&tp,&tzp);
	return(tp.tv_sec/SECSPERDAY);
#else
	return(time((long *)0)/SECSPERDAY);
#endif U42BSD
}

/* CDAY
 *
 * Find ascii date corrisponding to day number <dy> which was generated by
 * the day() routine.
 */

char *cday(dy)
long dy;
{
register char *db,*dp;
char *ctime();

	dy = dy * SECSPERDAY + SECSPERDAY/2;
	db = ctime(&dy);
	dp = db+10;
	*(dp++) = ',';
	*(dp++) = ' ';
	*(dp++) = db[20];
	*(dp++) = db[21];
	*(dp++) = db[22];
	*(dp++) = db[23];
	*dp = '\0';

	return(db);
}

#ifndef U42BSD
/* READDIR
 *
 *	Here we fake 4.2bsd's readdir() command for older bsd's and at&t
 *	unixs.  The "direct" structure on those systems returned isn't the
 *	same the bsd one, but we do ensure that the file name is null
 *	terminated.  It would be easy enough to add the d_namlen and d_reclen
 *	records and extend d_ino to a long named d_fileno, but I don't
 *	really need that here.
 */

struct direct *readdir(fp)
DIR *fp;
{
/* We allocate one extra byte on the end of the structure for the null */
static char dent[ sizeof(struct direct) + 1 ];

	do
		if (fread(dent,sizeof(struct direct),1,fp) == 0)
			return(NULL);
	while (((struct direct *)dent)->d_ino == 0);
	((struct direct *)dent)->d_name[DIRSIZ] = '\0';
	return((struct direct *)dent);
}
#endif U42BSD

/* GPWUID()
 *
 *   This routine looks up login names for the given uid.  It is designed
 *   to be fast for doing a number of lookups.  It does not close the
 *   password file, and it keeps a lookaside-buffer of the most recently
 *   found names.  You should call igpwuid() before calling this, and
 *   endpwent() after you are done.
 *
 *   WARNING:  The lookaside buffer is kept in the global "mbuffer".
 */

struct pwlab {
	char name[10];
	int uid;
	} *pwlab1,*pwt,*pwlab2,*pwo;

char *gpwuid(uid)
REGISTER int uid;
{
register struct passwd *pwd;
register struct pwlab *l;

	/* First search the look-aside buffer */
	for (l = pwlab1; l < pwt; l++)
		if (uid == l->uid) return(l->name);

	/* Then search the password file */
	while ((pwd = getpwent()) != (struct passwd *) 0 && pwd->pw_uid != uid)
		;
	setpwent();   /* rewind the password file */

	if (pwd == (struct passwd *)0)
		return (NULL);

	/* Add the name to the look-aside buffer */
	if (pwt < pwlab2)
	{
		pwt->uid = uid;
		strcpy(pwt->name,pwd->pw_name);
		pwt++;
	}
	else
	{
		pwo->uid = uid;
		strcpy(pwo->name,pwd->pw_name);
		if (pwo++ == pwlab2)
			pwo = pwlab1;
	}
	return (pwd->pw_name);
}

igpwuid()
{
	setpwent();   /* rewind the password file */
	pwo = pwlab1 = pwt = (struct pwlab *) mbuffer;
	pwlab2 = pwlab1 + sizeof(mbuffer)/sizeof(struct pwlab);
}

#ifdef U43BSD
getwindow()
{
struct winsize x;

	ioctl(2,TIOCGWINSZ,&x);
	LINES = x.ws_row;
	COLS = x.ws_col;
}
#endif U43BSD