|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 17055 (0x429f)
Types: TextFile
Names: »sys.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/Cchess/sys.c«
/* 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