V9/cmd/emacs/emacs_io.c
/* EMACS_MODES: c !fill */
#ifdef v8
#include <sys/types.h>
#endif
#include "emacs_gb.h"
#include "emacs_io.h"
#ifndef PC
#include <signal.h>
#endif
#ifdef bsd
#include <sys/time.h>
#else
#include <time.h>
#endif
#include <errno.h>
#ifdef ux3
#include <termio.h>
#else
#include <sgtty.h>
#endif
#ifdef bsd
/* The following defines turn on the use of the select system call
* and Cbreak mode for berkeley unix. If you are running a version
* of berkeley unix without these features, taken them out */
#define SELECT
#define CBRAKE
#define FLIM
#endif
#ifdef ux3
#define FLIM
#endif
#ifdef COMPRESS
long coutc = 0;
int DOCOMP=0;
char *trtab[128] = {
#include "compress.h"
};
#endif
#ifdef NDLAY
#include <sys/types.h>
#ifdef ux3
#include <fcntl.h>
#endif ux3
int ndfrn; /* file for ndelay I/O */
#endif
extern int SAVEMD;
extern int curbf;
extern char *getenv();
#ifdef PC
#define READM (0)
#define APPEM (1)
#define WRITEM (1)
#else
#define READM 0
#define APPEM 1
#define WRITEM 0666
int READ_WAIT = 255;
int read_miss;
#endif
/* TTY buffer */
/* if unix3.0 (or later) system with no wait raw-mode I/O, use a big tty */
/* buffer to allow type ahead and avoid excessive re-display */
#if (defined(ux3) || defined(bsd) || defined(v8))
#define TTLOOK 16
#else
#define TTLOOK 1
#endif
int ttcnt ;
char ttbuf[18]; /* Make large */
char *ttptr;
int ungc = 0;
extern int ttywarp;
/* Interrupted system command flag */
int irupt = 0;
#define MAXIRUPT 100
/* controlification stuff */
int ctlify;
int CONCHAR = 036; /* ^^ */
ioinit()
{
/* Keywords: internal-initialization standard-I/O files:20 */
register char *ttname;
xclose(3); /* close all files */
_stdout._frn = 1;
_stdout._cnt = 0;
_stdout._flags = _OUTPUT;
incnt = inlev = infrn = 0;
infrn = NULL;
brkflg = 0;
inbuf = _inbuf[0];
#ifdef NDLAY
#ifdef ux3
#ifdef pdp11
#define PDPTEST (ttywarp<2)
#else
#define PDPTEST 0
#endif
/* IF we have NDELAY I/O, close standard error and open it with ndelay */
close(2); /* close standard error */
if ((ttname=getenv("LOGTTY"))==NULL) ttname="/dev/tty";
if (PDPTEST || (open(ttname,O_RDWR+O_NDELAY)<0)) {
dup(1);
ndfrn = 0;
} else ndfrn = 2;
/* if we can't get tty, restore frn2 */
#endif ux3
#ifdef (defined(bsd) || defined(v8))
/*
* we can see how many chars await us in bsd4.1,
* so set ndfrn if the tty is fast enough for us. - CRC
*/
ndfrn = 2; /* CRC */
#endif (bsd || v8) /* CRC */
#endif /* CRC */
}
int FLOWMIN=0; /* Mode variable must be present */
#ifdef PC
cook()
{
}
uncook()
{
}
#else
/* into raw mode */
/* Terminal I/O modes, sgttyb for before unix 3.0, termio for later */
int xon;
#ifdef ux3
struct termio ttyjunk;
struct termio nttyjunk;
#else
struct sgttyb ttyjunk;
struct sgttyb nttyjunk;
#endif
#ifdef CBRAKE
/* Additional goodies for 4.2BSD */
int ldisc; /* Line discipline */
struct tchars tchars; /* Basic characters */
int locmode; /* Local mode */
struct ltchars ltchars; /* And at last, local modes */
struct ltchars zchars = {
-1,-1,-1,-1,-1,-1 }; /* Zero characters for ioctl */
struct tchars fcoff = {0,-1,-1,-1,-1,-1};
struct tchars fcon = {0,-1,021,023,-1,-1};
int mylmode = LLITOUT|LDECCTQ; /* Literal output, ^Q starts ^S */
#endif
#define NBAUD 16 /* number of baud rates */
char charms[NBAUD] = { /* ms per char in various rates */
100,
100, /* 50 */
100, /* 75 */
100, /* 110 */
70, /* 134 */
66, /* 150 */
50, /* 200 */
33, /* 300 */
16, /* 600 */
8, /* 1200 */
5, /* 1800 */
4, /* 2400 */
2, /* 4800 */
1, /* 9600 */
1, /* EXTA */
1, /* EXTB */
};
uncook()
{
/* UNIX 3 code thanks to J. Langer and M. Plotnick */
/* Keywords: the-terminal internal-initialization:40 terminal-initialization terminal-modes unix-interface:50 */
#ifdef ux3
ioctl(1, TCGETA, &ttyjunk);
nttyjunk=ttyjunk;
#ifdef u370
nttyjunk.c_iflag |= (BRKINT|ISTRIP|IGNPAR);
nttyjunk.c_iflag &=
~(IGNBRK|IGNPAR|PARMRK|IXON|INLCR|IGNCR|ICRNL|INPCK);
/* accept break, no crnl mapping, no ^S^Q */
nttyjunk.c_oflag = 0; /* no delays, no crlf mapping */
/* nttyjunk.c_cflag |= CS8 ;*/
nttyjunk.c_lflag &= ~(ISIG|ECHO|ICANON); /* no echo, signals,
or erase/kill processing */
#else
nttyjunk.c_iflag |= (BRKINT|ISTRIP);
nttyjunk.c_iflag &= ~(IGNBRK|PARMRK|INLCR|ICRNL|IGNCR|IXON|IXOFF);
/* accept break, no crnl mapping, no ^S^Q */
nttyjunk.c_oflag = 0; /* no delays, no crlf mapping */
nttyjunk.c_lflag &= ~(ISIG|ECHO|ICANON); /* no echo, signals,
or erase/kill processing */
#endif
nttyjunk.c_cc[VMIN] = 0; /* return after every character read */
/* Setting VMIN to 0 causes emacs to time out input every 25.5 seconds,
* updating the display of time (if time mode is on) and received
* mail. Setting it to 1 will cause emacs to wait indefinetely for
* input. */
nttyjunk.c_cc[VTIME] = READ_WAIT; /* Or after 25.5 seconds */
ttywarp = charms[ttyjunk.c_cflag&CBAUD]; /* milliseconds for character */
ioctl(1, TCSETAW, &nttyjunk);
ioctl(1, TCXONC,1); /* Force tty back on */
xon = 0; /* Xon/XOff is now off */
#else
ioctl(1,TIOCGETP,&ttyjunk);
nttyjunk=ttyjunk;
#ifdef CBRAKE
nttyjunk.sg_flags = CBREAK;
ioctl(1,TIOCSETN,&nttyjunk);
/* Now for the real fun, get all of the other 4.2BSD goodies */
ioctl(1,TIOCGETC,&tchars);
ioctl(1,TIOCSETC,&fcoff);
ioctl(1,TIOCLGET,&locmode);
ioctl(1,TIOCLBIS,&mylmode);
ioctl(1,TIOCGLTC,<chars);
ioctl(1,TIOCSLTC,&zchars);
xon = 0;
#else
nttyjunk.sg_flags &= (~ECHO); /* it was so SIMPLE in the old days */
nttyjunk.sg_flags |= (RAW);
ioctl(1,TIOCSETP,&nttyjunk);
#endif
ttywarp = charms[ttyjunk.sg_ospeed]; /* milliseconds for char */
#endif
vinit();
/* Anything above 2500 baud may cause problems */
/* If the user has not selected a limit we'll set one */
/* Commented out, remove this line to enable it
if ((ttywarp < 4)&&(FLOWMIN==0)) FLOWMIN = 64; /* */
}
cook()
{
/* Keywords: the-terminal terminal-modes exit-processing:50 unix-interface:50 */
extern int osert,umode;
/* First, return the terminal to a sane state */
if (no_io) return;
if (umode) unline();
if (osert) unsert();
vexit();
mflush(stdout); /* force output */
#ifdef ux3
ioctl(1,TCSETAW, &ttyjunk);
ioctl(1, TCXONC,1); /* Force tty back on */
xon = 1; /* XON/XOFF is now ON */
#else
#ifdef CBRAKE
ioctl(1,TIOCSETN,&ttyjunk);
ioctl(1,TIOCSETC,&tchars);
ioctl(1,TIOCLSET,&locmode);
ioctl(1,TIOCLBIC,&mylmode);
ioctl(1,TIOCSLTC,<chars);
xon = 1;
#else
ioctl(1,TIOCSETP,&ttyjunk);
#endif
#endif
}
#endif
/*VARARGS2*/
char *
nscan(stptr,ret)
register char *stptr;
register int *ret;
/* Keywords: standard-I/O:20 conversions parsing:20 reading:20 */
{
register int c;
*ret = 0;
while (((c = *stptr)>='0') && (c <= '9')) {
stptr++;
*ret = *ret*10+(c-'0');
}
return(stptr);
}
seprintf(string,fmt,x)
char *string;
char *fmt;
unsigned x;
{
sxprintf(string,fmt,&x); /* Depends on arg list format */
}
/* Internal printf formatter */
sxprintf(string,fmt, adx)
register char *string;
register char *fmt;
register unsigned int *adx;
{
/* Keywords: standard-I/O:50 formatting writing:20 terminal-parameters:20 */
int c;
int width;
extern char *mstrcpy();
if (fmt == NULL) fmt = "";
loop:
while((c = *fmt++) != '%') {
*string++ = c;
if(c == '\0') {
return;
}
}
width = 0;
c = *fmt++;
if ((c >= '0') && (c <= '9')) {
fmt = nscan(fmt-1,&width);
c = *fmt++;
}
switch(c) {
case 'd':
case 'D':
case 'o':
case 'O':
{
register int b;
long n;
long n1;
register int i;
char dstack[20];
b = (((c=='o') || (c == 'O'))? 8: 10); /* number base */
if ((c == 'o') || (c == 'd')) {
n = (long) (*adx);
if (sizeof(n) != sizeof(i)) {
if (n > 32768L) n = n-65536L; /* sign correction */
}
} else {
n = *((long *) adx);
adx += ((sizeof(n)-sizeof(i))/sizeof(i));
}
i = 0;
if (n < 0) {
n = -n;
*string++ = '-';
}
do {
n1 = n/b;
dstack[i++] = (short) (n-(n1*b));
n = n1;
} while (n != 0); /* figure number */
if ((b == 8) && ((i !=1 ) || (dstack[0] != 0))) dstack[i++]=0;
while (i<width) dstack[i++] = 0;
while (i > 0) {
#ifdef PC
char cq;
cq = dstack[--i];
cq += '0';
*string++ = cq;
#else
*string++ = (dstack[--i] + '0'); /* print number */
#endif
}
}
break;
case 'P':
width *= SREGION;
/* Fall through */
case 'p':
while (width > 0) {
*string++ = *NOP;
width -= ttywarp;
}
adx--;
break;
case 's':
string = mstrcpy(string,(char *)*adx);
break;
case 'm':
case 'M':
{
char *cp;
if (c=='m') {
cp = &TMAP[width * (*adx)];
} else {
cp = &SMAP[width * (*adx)];
}
for (c = 0; c < width; c++) {
if (*cp) *string++ = *cp++;
}
}
break;
case 'c':
c = *adx + width;
if (c) {
*string++ = c;
} else {
*string++ = '^';
*string++ = '@'; /* punt */
}
break;
case '%':
*string++ ='%';
adx--;
break;
default:
error(WARN,70); /* Bad character in printf */
}
adx++;
goto loop;
}
char *inget()
{
/* Keywords: command-files:10 */
if (infrn < 0)return(inptr);
else return(NULL);
}
inset(newptr)
char *newptr;
/* Keywords: command-files:10 */
{
if (infrn < 0) inptr = newptr;
}
#ifdef SELECT
int sreadfd = 1;
struct timeval stimeout = {30,0}; /* timeout interval */
#endif
#ifdef v8
fd_set sreadfd;
#endif
int
getchar()
{
/* Keywords: the-terminal standard-I/O terminal-modes:10 reading mail-processing:20 time-processing:20 prompting:30 conversions:10 PC-only:10 keyboard-macros:20 unix-interface:10 */
extern int timemd;
extern int newmail;
extern int mailcnt;
extern int kbdfile;
extern char ctype[];
extern char cbuf[];
register int c;
if (no_io) return(CTRLZ); /* Flush I/O */
if (brkflg) brkit(); /* handle break interrupt */
if (incnt == 0) {
while (1) {
errno = 0;
if (infrn) {
inptr = inbuf;
incnt = read(infrn,inbuf,INLOOK);
} else {
/* The following code expects read from a raw mode tty port to
* return whenever at least one character has been received or a
* timeout expires. It assumes that if it gets 0 characters, the
* timer expired, unless it happens too many times in a row. */
reread: ttptr = ttbuf+2;
#ifdef PC
ttcnt = incnt = rawread(ttbuf+2);
#else
read_miss = 0;
if (donttime) goto notime; /* Avoid time and mail */
/* First, update time and mail */
if (timemd) dtime(0);
if ((mailcnt>=0) && (--mailcnt<=0)) {
ckmail();
}
/* Display them if necessary */
if (newmail) {
int x,y;
x = mline;
y = mcol;
prompt(ECHOL-1,"%s You have mail",cbuf);
if (newmail < 0) beep();
mgo(x,y);
newmail = 1;
} else if (disptime) {
int x,y;
x = mline;
y = mcol;
prompt(ECHOL-1,cbuf);
disptime=0;
mgo(x,y);
}
notime:
/* Now try to read some standard input */
mflush(stdout);
#ifdef FLIM
if (xon && (FLOWMIN>=0)) { /* If xon/xoff is on, turn it off */
#ifdef CBRAKE
quietout();
ioctl(1,TIOCSETC,&fcoff);
#else
nttyjunk.c_iflag &= ~(IXON|IXANY);
ioctl(1,TCSETAW,&nttyjunk);
#endif
xon = 0;
}
#endif
#ifdef SELECT
if (inproc){
sreadfd = 1+(1<<inproc);
ttcnt = select(inproc+1,&sreadfd,NULL,NULL,&stimeout);
if (sreadfd > 1) readproc();
} else {
sreadfd = 1; /* must set up each time since select clobbers it */
ttcnt = select(1,&sreadfd,NULL,NULL,&stimeout);
}
if ((sreadfd & 1) && (brkflg == 0)) ttcnt = incnt = read(0,ttbuf+2,TTLOOK);
else {
incnt = 0;
errno = EINTR; /* Make it look like the read timed out! */
}
#else
#ifdef v8
if (inproc){
FD_ZERO(sreadfd);
FD_SET(0, sreadfd);
FD_SET(inproc, sreadfd);
ttcnt = select(inproc+1,&sreadfd,NULL,30000);
if (FD_ISSET(inproc,sreadfd))
readproc();
} else {
FD_ZERO(sreadfd);
FD_SET(0, sreadfd);
ttcnt = select(1,&sreadfd,NULL,30000);
}
if (FD_ISSET(0,sreadfd) && (brkflg == 0))
ttcnt = incnt = read(0,ttbuf+2,TTLOOK);
else {
incnt = 0;
errno = EINTR; /* Make it look like the read timed out! */
}
#else
ttcnt = incnt = read(0,ttbuf+2,TTLOOK);
if (inproc) readproc(); /* Process any input */
#ifdef ux3
if (ttcnt) ioset(10);
else ioset(READ_WAIT<<1); /* Back off read timeout next time */
#endif ux3
#endif v8
#endif SELECT
if (brkflg) {
incnt=ttcnt=0;
brkit();
disup();
goto reread; /* Try again for a charactger */
}
if (incnt == 0) {
mailcnt = 0; /* Expire mail timer */
if (++read_miss < 1000) goto reread;
}
#endif PC
}
ninch+= incnt; /* count for stats */
if (incnt >= 0) break;
if ((errno != EINTR)|| (++irupt > MAXIRUPT)) break;
}
}
if (infrn < 0) { /* if in macro */
incnt++;
}
if (infrn) {
if (incnt-- >0) return(*inptr++ & 0377);
} else {
if ((incnt= --ttcnt) >= 0) {
if (ungc) {
ungc--;
return(*ttptr++ & 0377);
}
c = (*ttptr++ & 0177);
if (ctlify && (c == CONCHAR)) {
ctlify = 0; /* don't controlify again */
c = getchar();
if ((c>= 'a') && (c <= 'z')) c -= 040;
if ((ctype[c] == PLAIN) ||(ctype[c] == UL)) c ^= 0100;
ctlify++;
}
if (kbdfile) {
char x;
x=c;
write(kbdfile,&x,1);
}
return(c);
}
}
return(CTRLZ);
}
#ifndef PC
#ifdef ux3
/* Set non-blocking terminal timeout appropriately */
/* Note -- this is a very imperfect simulation of the select system
* call in 4.2bsd for system V unix. What is done is that if no
* process is running, the timeout is set to 25.5 seconds. If a
* process is running, the timeout is decreased after every piece of
* input is sent, and rises as reads time out, returning eventually
* to 25.5 seconds. Thus quick processes get good results, but slow
* ones can get dismal response. Emacs polls the sub-process(s)
* each time it reads from the tty, so the timeout just dictates
* how often this happens if there is no tty input. */
ioset(limit)
int limit;
{
/* Keywords: unix-interface reading shell-escape sub-processes look-ahead: 10*/
if (READ_WAIT == 0) return; /* No non-blocking I/O available */
if (limit > 255) limit = 255; /* Clamp it */
if (READ_WAIT == limit) return;
READ_WAIT = limit;
nttyjunk.c_cc[VTIME] = READ_WAIT;
ioctl(1, TCSETA, &nttyjunk);
}
#endif
/* Process input from process in the window */
readproc ()
{
/* Keywords: unix-interface reading shell-escape sub-processes buffers:50 */
char buf[128];
int nc,obuf;
int cnt;
#ifdef v8
ioctl(inproc, FIONREAD, &cnt);
if(cnt <= 0)
return;
#endif
nc = read(inproc,buf,127);
buf[nc]=0;
if (nc) {
if (curbf != procbuf) {
if (procbuf == windbuf()) {
owind();
stuffproc(buf);
disup();
owind();
disup();
} else {
obuf=curbf;
chbuf(procbuf);
stuffproc(buf);
chbuf(obuf);
}
} else {
stuffproc(buf);
disup(); /* Update display for user */
}
} else {
}
}
/* stuffproc -- stuff process input into the current buffer */
stuffproc(string)
char *string;
{
/* Keywords: unix-interface reading shell-escape sub-processes buffers:50 */
bot();
putin(string);
mark(curbf);
}
/* sendproc -- send current line to the process */
sendproc (ptr,count)
char * ptr;
int count;
{
/* Keywords: unix-interface shell-escape buffer-representation:10 buffers:50 writing sub-processes */
if (write(outproc,ptr,count)<0) flushproc();
#ifdef ux3
ioset(1); /* Set back timeout appropriately */
#endif
}
/* brkproc -- send an interrupt to the current sub-process */
brkproc(arg)
/* Keywords: unix-interface shell-escape break-handling sub-processes */
{
if (curbf == procbuf) {
if (arg== 1) arg = SIGINT;
kill(procpid,arg);
}
}
/* flushproc -- rid ourselves of the current sub-process */
flushproc()
{
/* Keywords: unix-interface shell-escape closing sub-processes */
int status;
if (procpid) {
kill (procpid,9);
status=wait(&status);
close(inproc);
close(outproc);
procpid=inproc=outproc=0;
procbuf= -1;
}
}
#else
/* Define some tombstones for this code. It's easier than ifdeffing out all the calls */
brkproc()
{
}
#endif
/* Fill tty buffer if we have ndelay I/O */
ttfill()
/* Keywords: the-terminal terminal-modes lookahead reading unix-interface:50 */
{
#ifdef NDLAY
long i;
register char *addr;
if (no_io || (ndfrn == 0)) return;
mflush(stdout); /* flush tty */
#if (defined(bsd) || defined(v8)) /* CRC */
i = 0; /* CRC */
ioctl(2,FIONREAD,&i); /* CRC */
if( i <= 0) /* CRC */
/* no input awaits us. - CRC */
return; /* CRC */
#endif (bsd || v8)
if (ttcnt) {
/* more input, append to it */
addr = ttptr+ttcnt;
i = read(2,addr,ttbuf+2+TTLOOK-addr);
} else {
i = read(2,ttbuf+2,TTLOOK);
ttptr = ttbuf+2;
}
if (i < 0) i = 0;
ttcnt += i; /* more characters */
if (infrn == 0) { /* reading from tty */
incnt = ttcnt;
inptr = ttptr;
}
#endif
return;
}
pushin(fp)
/* Keywords: command-files:50 keyboard-macros:20 opening unix-interface:10 */
register char *fp;
{
register int frn;
if (fp != NULL) {
while((frn = open(fp,READM)) <= 0) {
if ((errno != EINTR) && (errno != 23))break;
}
} else frn = 0;
if (frn >= 0) {
_incnt[inlev] = incnt;
_infrn[inlev] = infrn;
_inptr[inlev++] = inptr;
infrn = frn;
if (frn) incnt = 0;
else incnt = ttcnt;
return(1);
} else return(0);
}
pshmac(pos)
/* Keywords: macro-invocation */
short pos;
{
if (inlev>= NINP) error(FATAL,64);
_incnt[inlev] = incnt;
_infrn[inlev] = infrn;
_inptr[inlev++] = inptr;
infrn = -1;
incnt = 100; /* will never decrease */
inptr = &bbuf[0][pos]; /* macro buffer position */
return(1);
}
inpop()
/* Keywords: exit-processing:10 macro-invoction:20 command-files:20 */
{
if (inlev > 0) {
--inlev;
if (infrn>0) close(infrn);
infrn = _infrn[inlev];
inptr = _inptr[inlev];
inbuf = _inbuf[inlev];
if (infrn) incnt = _incnt[inlev];
else incnt = ttcnt;
return(1);
} else return(0);
}
#ifdef COMPRESS
#define CRELOAD 0376
translate(buf,count)
/* Keywords: standard-I/O:10 compressed-output conversions writing */
char *buf;
int count;
{
register char *bp;
char *be;
register char *bo;
register char *mp;
register char *tp;
bp=bo=buf;
be=buf+count;
while (bp<be-1) {
if (*bp&0200) {
*bp = 0; /* PUNT all meta characters to 0 */
goto stop;
}
mp=trtab[*bp];
while (*mp) {
tp=bp+1;
while (*tp++ == *mp++);
if ((mp[-1]&0200)){
if (tp > be+1) {
goto stop;
}
/* Matched a substring */
*bo++ = mp[-1];
bp = tp-1;
goto out;
}
while ((*mp++ & 0200) == 0); /* Skip rest of string */
}
stop: *bo++ = *bp++;
out: continue;
}
if (bp < be) *bo++ = *bp++;
return(bo-buf);
}
loadtbl()
/* Load compression table here and remote */
/* Keywords: commands the-terminal:90 conversions compressed-output */
{
extern int macptr;
char *nullp;
char c;
int nc;
FILE fbuf;
FILE *fp;
int i;
if (DOCOMP==0) return; /* Can't do compression */
nullp = &bbuf[0][macptr];
pshchr(0); /* Store a null string for common cases */
fp = xopen(&fbuf,expenv(getname("Compression file: ")),"r");
if (fp == NULL) return;
DOCOMP=0;
mflush(stdout); /* Past the point of no return */
i = 0;
while (getc(fp) != EOF) {
nc = 0;
while (getc(fp) == '\\') {
if (nc == 0) trtab[i] = &bbuf[0][macptr];
nc++;
c = ((getc(fp)&07)<<6);
c += ((getc(fp)&07)<<3);
c += (getc(fp)&07);
pshchr(c);
}
c = getc(fp); /* Eat comma */
c = getc(fp); /* Eat newline */
if (nc) pshchr(0); /* Put in null */
else trtab[i]=nullp; /* Null string */
i++;
}
/* OK, host table loaded, now load the blit */
mclose(fp);
fp = xopen(&fbuf,expenv(getname("Decompression file: ")),"r");
if (fp == NULL) return;
putchar(CRELOAD); /* Tell blit it's time to reload */
while ((c = getc(fp)) != EOF) putchar(c);
putchar(CRELOAD); /* Reload done (let's hope!) */
mflush(stdout); /* Force output out before we turn on compression */
DOCOMP=1; /* Here goes nothing */
clear(); /* refresh screen */
mclose(fp);
}
#endif
ungetch(c)
/* Keywords: the-terminal:90 standard-I/O parsing:10 reading:10 */
{
if (incnt < 0) return; /* Can't unget an eof */
++incnt;
if (infrn==0) {
++ungc;
*(--ttptr) = c;
++ttcnt;
} else {
*(--inptr) = c;
}
}
mflush(p)
register FILE *p;
/* Keywords: writing the-terminal:10 standard-I/O PC-only:40 unix-interface:20 */
{
register int bc;
register int bo;
if (p->_flags & _OUTPUT) {
if (p->_flags & _ERROR) {
p->_cnt = 0;
return;
}
if (p == stdout) {
if (no_io) {
p->_cnt = 0;
return;
}
ntwrite++; /* count for stats */
noutc += p->_cnt;
#ifdef PC
return; /* No output to stdout */
#endif PC
#ifdef COMPRESS
if (DOCOMP&& (p->_cnt > 10)) p->_cnt = translate(p->_buf,p->_cnt);
coutc += p->_cnt;
#endif
#ifdef FLIM
if (FLOWMIN && (p->_cnt > FLOWMIN) && (xon == 0)) {
#ifdef CBRAKE
quietout();
ioctl(1,TIOCSETC,&fcon);
#else
nttyjunk.c_iflag |= IXON+IXANY;
ioctl(1,TCSETA,&nttyjunk);
#endif
xon = 1;
}
#endif
}
#ifdef PC
if (p->_cnt) {
if ((bc = write(p->_frn, p->_buf, p->_cnt)) < p->_cnt) {
error (NORM,errno,"writing");
}
}
#else
bo = 0;
while((bc = write(p->_frn, p->_buf+bo, p->_cnt)) != p->_cnt) {
if (bc >0) {
p->_cnt -= bc;
bo += bc;
}
if ((errno != EINTR)|| (++irupt > MAXIRUPT)) {
if ((p == stdout) || (errno == EPIPE)) break; /* PUNT
* errors on standard output */
p->_flags |= _ERROR;
SAVEMD = 0; /* Give up on autosaving */
error (NORM,errno,"writing");
break;
}
}
#endif PC
p->_cnt = 0;
}
}
#ifdef CBRAKE
/* Wait for quiet output on berkely systems. This is very imperfect */
/* but it's all we can do. */
quietout()
{
int outqs;
struct timeval outime;
long timeout;
ioctl(1,TIOCOUTQ,&outqs);
while (outqs > 0) {
timeout = outqs*1000 /ttywarp - 3000; /* Microseconds of timeout */
if (timeout > 0) {
outime.tv_sec = timeout/1000000;
outime.tv_usec = timeout%1000000;
select(0,NULL,NULL,NULL,&outime); /* Wait for something to happen! */
}
ioctl(1,TIOCOUTQ,&outqs);
}
}
#endif
filbuf(p)
FILE *p;
{
/* Keywords: reading standard-I/O PC-only:40 unix-interface:10 */
#ifdef PC
p->_cnt = read(p->_frn, p->_buf, BUFSIZ);
#else
mflush(stdout); /* Make output come out */
while ((p->_cnt = read(p->_frn, p->_buf, BUFSIZ)) < 0) {
if ((errno != EINTR)|| (++irupt > MAXIRUPT)) break;
}
#endif PC
p->_ptr = &(p->_buf[1]);
if (p->_cnt > 0) {
p->_cnt--;
return(p->_buf[0]&0377);
}
else p->_cnt = 0;
return(EOF);
}
/*VARARGS1*/
eprintf(string,a1)
char *string;
/* Keywords: formatting standard-I/O:50 terminal-parameters:50 */
{
char pbuf[1024];
sxprintf(pbuf,string,&a1);
puts(pbuf,stdout);
}
puts(cp,p)
FILE *p;
register char *cp;
/* Keywords standard-I/O writing */
{
while (*cp) {
putc(*cp++,p);
}
}
mclose(p)
FILE *p;
/* Keywords: standard-I/O closing files unix-interface */
{
mflush(p);
close(p->_frn);
return(p->_flags & _ERROR);
}
FILE *
xopen(p,np,mode)
FILE *p;
char *np;
char *mode;
/* Keywords: files opening standard-I/O unix-interface */
{
int omode;
omode = 0;
if (*mode == 'b') {
#ifdef PC
omode = 4;
#endif
mode++;
}
switch(*mode) {
case 'r': /* read file mode */
while ((p->_frn = open(np,omode+READM)) <0) {
if ((errno != EINTR) && (errno != 23))return(NULL);
}
p->_flags = _INPUT;
break;
case 'a':
while((p->_frn = open(np,omode+APPEM)) <0) {
if ((errno != EINTR) && (errno != 23))return(NULL);
}
lseek (p->_frn,0L,2); /* at end */
p->_flags = _OUTPUT;
break;
case 'w':
while((p->_frn = creat(np,omode+WRITEM)) <=0) {
if ((errno != EINTR)&& (errno != 23)) return(NULL);
}
p->_flags = _OUTPUT;
break;
}
p->_cnt = 0;
p->_ptr = 0;
return(p);
}
FILE *
fdopen(p,frn,mode)
FILE *p;
int frn;
char *mode;
/* Keywords: standard-I/O opening unix-interface */
{
p->_frn = frn;
p->_cnt = 0;
p->_ptr = &(p->_buf[0]);
p->_flags = _DEAD;
switch(*mode) {
case 'r':
p->_flags = _INPUT;
break;
case 'w':
p->_flags = _OUTPUT;
break;
}
return(p);
}
/* ascii to integer */
aint(string)
register char *string;
/* Keywords: standard-I/O:10 conversions string-handling:10 */
{
register int result;
register int base;
base = ((*string == '0') ? 8 : 10);
result = 0;
while ((*string >= '0') && (*string <= '9')) {
result = (result * base) + (*string++ - '0');
}
if (*string == 0) return(result);
else return(-1);
}
xclose(lowfile)
register int lowfile;
/* Keywords: unix-interface files closing */
{
register int fileno;
#ifndef PC
for (fileno = lowfile; fileno < 20; fileno++) {
close(fileno);
}
#endif PC
}
#ifdef PC
/* All the nice? C routines you don't really need! */
signal()
{
return(0);
}
char *
getenv()
{
return(0);
}
char cbuf[2]; /* Fake character buffer */
#else
/* ctime stuff */
char cbuf[26];
char dmsize[12] =
{
31,
28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31
};
long timez = 0;
int daylite = 1;
#define dysize(xyear) ((xyear&03) ? 365 : 366)
struct tm *gmtime();
struct tm *localtime();
char *ctime();
char *asctime();
char *
ctime(t)
long *t;
{
/* Keywords: time-processing */
return(asctime(localtime(t)));
}
#ifdef ux3
void
#endif
tzset()
{
register char *p;
register int n;
int sign;
/* Keywords: time-processing internal-initialization */
if ((p = getenv ("TZ")) && *p) {
p += 3;
if (sign = *p == '-')
p++;
n = 0;
while (*p >= '0' && *p <= '9')
n = (n * 10) + *p++ - '0';
if (sign)
n = -n;
timez = ((long) (n * 60)) * 60;
if (*p) daylite = 1;
else daylite = 0;
}
}
struct tm *
localtime(tim)
long *tim;
{
/* Keywords: time-processing */
register int dayno;
register struct tm *ct;
register daylbegin, daylend;
long copyt;
if (timez == 0) tzset();
copyt = *tim - timez;
ct = gmtime(©t);
if (!daylite) return(ct);
dayno = ct->tm_yday;
daylbegin = 119; /* last Sun in Apr */
daylend = 303; /* Last Sun in Oct */
daylbegin = sunday(ct, daylbegin);
daylend = sunday(ct, daylend);
if ((dayno>daylbegin || (dayno==daylbegin && ct->tm_hour>=2)) &&
(dayno<daylend || (dayno==daylend && ct->tm_hour<1))) {
copyt += 1*60*60;
ct = gmtime(©t);
}
return(ct);
}
/*
* The argument is a 0-origin day number.
* The value is the day number of the first
* Sunday on or after the day.
*/
sunday(t, d)
register struct tm *t;
register int d;
{
/* Keywords: time-processing */
if ((d >= 58) && ((t->tm_year & 03) == 0)) d+=1; /* leap year */
return(d - (d - t->tm_yday + t->tm_wday + 700) % 7);
}
struct tm *
gmtime(tim)
long *tim;
{
/* Keywords: time-processing */
register int d0, d1;
int day;
long hms;
static struct tm xtime;
/*
* break initial number into days
*/
day = *tim / 86400;
hms = *tim - (day*86400);
/*
* generate hours:minutes:seconds
*/
d1 = hms/60;
xtime.tm_sec = hms - (((long)d1)*60L);
xtime.tm_min = d1%60;
d1 /= 60;
xtime.tm_hour = d1;
/*
* day is the day number.
* generate day of the week.
* The addend is 4 mod 7 (1/1/1970 was Thursday)
*/
xtime.tm_wday = (day+4)%7;
/*
* year number
*/
for(d1=70; day >= dysize(d1); d1++)
day -= dysize(d1);
xtime.tm_year = d1;
xtime.tm_yday = d0 = day;
/*
* generate month
*/
if ((d1&03) == 0)dmsize[1] = 29;
else dmsize[1] = 28;
for(d1=0; d0 >= dmsize[d1]; d1++)
d0 -= dmsize[d1];
xtime.tm_mday= d0+1;
xtime.tm_mon = d1;
return(&xtime);
}
char *
asctime(t)
register struct tm *t;
{
/* Keywords: time-processing */
seprintf(cbuf,"%s %s %d %2d:%2d",
&"Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat"[4*t->tm_wday],
&"Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec"[(t->tm_mon)*4],
t->tm_mday,
t->tm_hour,
t->tm_min);
return(cbuf);
}
#endif