|
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