📄 jove.c
字号:
/*************************************************************************** * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE * * is provided to you without charge, and with no warranty. You may give * * away copies of JOVE, including sources, provided that this notice is * * included in all the files. * ***************************************************************************//* Contains the main loop initializations, and some system dependent type things, e.g. putting terminal in CBREAK mode, etc. */#include "jove.h"#include "fp.h"#include "termcap.h"#include "ctype.h"#include "chars.h"#include "disp.h"#include "re.h" /* for find_tag() */#include "rec.h"#ifdef IPROCS# include "iproc.h"#endif#ifdef UNIX#include "ttystate.h"#endif#ifdef SCO#undef TIOCGWINSZ#include <sys/stream.h>#include <sys/ptem.h>#endif#ifdef MAC# include "mac.h"#else# ifdef STDARGS# include <stdarg.h># else# include <varargs.h># endif# include <sys/stat.h>#endif#include <signal.h>#include <errno.h>#ifdef MSDOS# include <process.h>#endif /* MSDOS */#ifndef MAC# include <fcntl.h>#endif#ifdef MSDOSprivate void break_off proto((void)), break_rst proto((void));#endif#ifdef MAC# define WINRESIZE 1#else# ifdef TIOCGWINSZ# ifdef SIGWINCH# define WINRESIZE 1# endif# endif#endifprivate void DoKeys proto((bool firsttime));#ifdef MSDOSextern#elseprivate#endif void UnsetTerm proto((char *)), do_sgtty proto((void));/* Various tty state structures. * Each is an array, subscripted by one of "OFF" or "ON". */#ifdef UNIX# ifdef TIOCSLTCstruct ltchars ls[2];# endif /* TIOCSLTC */# ifdef TIOCGETCstruct tchars tc[2];# endif# ifdef PASS8 /* use pass8 instead of raw for meta-key */private int lmword[2]; /* local mode word */# endif# ifdef BRLUNIXstruct sg_brl sg[2];#endif#ifdef TERMIOstruct termio sg[2];#endif#ifdef TERMIOSstruct termios sg[2];#endif#ifdef SGTTYstruct sgttyb sg[2];#endif# ifdef BIFFprivate struct stat tt_stat; /* for biff */# ifndef BSD4_2private char *tt_name = NULL; /* name of the control tty */extern char *ttyname(); /* for systems w/o fchmod ... */# endifprivate bool dw_biff = NO; /* whether or not to fotz at all */# endif /* BIFF */#endif /* UNIX */bool errormsg;char NullStr[] = "";jmp_buf mainjmp;#ifdef MSDOS# define SIGHUP 99# define SIGIOT 99#endif /* MSDOS *//* finish() does not return, so it is funny that it returns a non-void * result. This is because most systems claim that signal(2) deals * with functions of type int (). ANSI changes this: the function * type must be void (int). This bridge must soon be crossed. */SIGRESULTfinish(code)int code;{ int save_errno = errno; /* Subtle, but necessary! */ static int Crashing = 0; /* we are in the middle of crashing */ bool CoreDump = (code != 0 && code != SIGHUP), DelTmps = YES; /* Usually we delete them. */ if (code == SIGINT) { char c;#ifdef PIPEPROCS int started;#endif#ifndef MENLO_JCL (void) signal(code, finish);#endif f_mess("Abort (Type 'n' if you're not sure)? ");#ifndef MSDOS# ifdef PIPEPROCS started = kbd_stop();# endif#ifdef SYSV if (read(0, (UnivPtr) &c, (size_t) 1) != 1)#endif (void) read(0, (UnivPtr) &c, (size_t) 1);# ifdef PIPEPROCS if (started) (void) kbd_strt();# endif#else /* MSDOS */ c = getrawinchar();#endif /* MSDOS */ message(NullStr); if ((c & 0377) != 'y') { redisplay(); errno = save_errno; SIGRETURN; } } DisabledRedisplay = YES;#ifndef MAC UnsetTerm(NullStr);#endif#ifdef PIPEPROCS kbd_kill(); /* kill the keyboard process */#endif#ifndef MSDOS if (code != 0) { if (!Crashing) { Crashing = YES; lsave(); SyncRec(); writef("JOVE CRASH!! (code %d): %s\n", code, strerror(errno)); if (ModBufs(YES)) { writef("Your buffers have been saved.\n"); writef("Use \"jove -r\" to have a look at them.\n"); DelTmps = NO; /* Don't delete anymore. */ } else writef("You didn't lose any work.\n"); } else writef("\r\nYou may have lost your work!\n"); }#endif /* MSDOS */ flushscreen(); if (DelTmps) {#ifdef PTYPROCS (void) signal(SIGCHLD, SIG_IGN);#endif tmpremove();#ifndef MSDOS recremove();#endif /* MSDOS */ }#ifdef UNIX if (CoreDump) abort();#ifdef PROFILING exit(0);#else _exit(0);#endif#else /* !UNIX */#ifdef MSDOS break_rst(); /* restore previous ctrl-c handling */#endif exit(0);#endif /* !UNIX */ /*NOTREACHED*/}private char smbuf[20], *bp = smbuf;private int nchars = 0;private char peekbuf[10], *peekp = peekbuf;#if defined(SYSV) || defined(M_XENIX)#define NONBLOCKINGREAD 1private voidsetblock(fd, on) /* turn blocking on or off */register int fd;bool on;{ static int blockf, nonblockf; static bool first = TRUE; if (first) { int flags; first = FALSE; if ((flags = fcntl(fd, F_GETFL, 0)) == -1) finish(SIGHUP); blockf = flags & ~O_NDELAY; /* make sure O_NDELAY is off */ nonblockf = flags | O_NDELAY; /* make sure O_NDELAY is on */ } if (fcntl(fd, F_SETFL, on ? blockf : nonblockf) == -1) finish(SIGHUP);}#endif /* defined(SYSV) || defined(M_XENIX) */private intPeekc(){ return peekp == peekbuf? EOF : *--peekp & 0377;}voidUngetc(c)int c;{ if (peekp != &peekbuf[(sizeof peekbuf) - 1]) *peekp++ = c;}bool InputPending = NO;char *Inputp = NULL;#ifdef PTYPROCSintjgetchar(){ fd_set reads; register int max = getdtablesize(); register int tmp, nfds; int c; if (nchars <= 0) { /* Get a character from the keyboard, first checking for any input from a process. Handle that first, and then deal with the terminal input. */ do { do { reads = global_fd; nfds = select(max, &reads, (fd_set *)0, (fd_set *)0, (struct timeval *)NULL); } while (nfds < 0 && errno == EINTR); if (nfds == -1) complain("\rerror in select %ld: %s", global_fd, strerror(errno)); else { if (FD_ISSET(0, &reads)) { nchars = read(0, (UnivPtr) smbuf, sizeof(smbuf)); FD_CLR(0, &reads); nfds--; } for (tmp = 1; tmp < max; tmp++) { if (FD_ISSET(tmp, &reads)) { read_proc(tmp); FD_CLR(tmp, &reads); if (--nfds == 0) break; } } } } while (nchars <= 0); if (nchars <= 0) finish(SIGHUP); bp = smbuf; InputPending = (nchars > 1); } if (((c = *bp) & 0200) && MetaKey) { *bp = (c & CHARMASK); return '\033'; } nchars -= 1; return *bp++ & 0377;}#else /* !PTYPROCS */intjgetchar(){ register int c; struct header { int pid; int nbytes; } header;normal: if (nchars <= 0) { bp = smbuf;#ifdef MSDOS *bp = getrawinchar(); nchars = 1;#else /* !MSDOS */# ifdef IPROCS if (NumProcs > 0) { for (;;) { size_t n = f_readn(ProcInput, (char *) &header, sizeof(header)); if (n != sizeof(header)) { raw_complain("\r\nError reading kbd process, expected %d, got %d bytes\r\n", sizeof header, n); finish(SIGHUP); } /* data is from the keyboard process */ if (header.pid == kbd_pid) { nchars = f_readn(ProcInput, smbuf, header.nbytes); if (nchars != header.nbytes) { raw_complain("\r\nError reading kbd process, expected %d, got %d bytes.\r\n", header.nbytes, nchars); finish(SIGHUP); } break; } read_proc(header.pid, header.nbytes); if (NumProcs == 0) { (void) kbd_stop(); goto normal; } } } else /*...*/# endif /*...*/ { for (;;) { nchars = read(0, (UnivPtr) smbuf, sizeof smbuf); if (nchars > 0) break;# ifdef SYSV /* System V seems to allow zero-length results */ if (nchars == 0) continue;# endif /* SYSV */ /* retry on interrupt */ if (!(nchars < 0 && errno == EINTR)) finish(SIGHUP); } }#endif /* !MSDOS */ InputPending = nchars > 0; } if (((c = *bp) & 0200) && MetaKey) { *bp = (c & CHARMASK); return '\033'; } nchars -= 1; return (*bp++ & CHARMASK);}#endif /* !PTYPROCS *//* Returns non-zero if a character waiting */boolcharp(){ bool some = NO; if (InJoverc != 0 || nchars > 0 || Inputp != NULL) return YES;#ifdef BRLUNIX { static struct sg_brl gttyBuf; gtty(0, (char *) >tyBuf); if (gttyBuf.sg_xflags & INWAIT) some = YES; }#else#ifdef FIONREAD { long c; if (ioctl(0, FIONREAD, (UnivPtr) &c) == -1) c = 0; some = (c > 0); }#else#ifdef NONBLOCKINGREAD setblock(0, OFF); /* turn blocking off */ nchars = read(0, (UnivPtr) smbuf, sizeof smbuf); /* Is anything there? */ setblock(0, ON); /* turn blocking on */ if (nchars > 0) /* something was there */ bp = smbuf; /* make sure bp points to it */ some = (nchars > 0); /* just say we found something */#else#ifdef c70 some = !empty(0);#else#ifdef MSDOS some = rawkey_ready();#else#ifdef MAC some = rawchkc();#endif#endif#endif#endif#endif#endif return some;}#ifdef BIFFprivate void biff_init proto((void));#endif#ifdef TERMCAPprivate voidResetTerm(){ do_sgtty(); /* this is so if you change baudrate or stuff like that, JOVE will notice. */ ttyset(ON); putpad(TI, 1); putpad(VS, 1); putpad(KS, 1);#ifdef UNIX (void) chkmail(YES); /* force it to check to we can be accurate */#endif#ifdef BIFF if (BiffChk != dw_biff) biff_init(); /* just in case we changed our minds about whether to deal with biff */#endif}private voidUnsetTerm(mesg)char *mesg;{ ttyset(OFF);#ifdef ID_CHAR INSmode(NO);#endif putpad(KE, 1); putpad(VE, 1); Placur(ILI, 0); putpad(CE, 1); if (TE) putpad(TE, 1); if (mesg[0] != '\0') writef("%s\n", mesg); flushscreen();}#endif /* TERMCAP */#ifdef JOB_CONTROLvoidPauseJove(){ UnsetTerm(ModBufs(NO) ? "[There are modified buffers]" : NullStr); (void) kill(0, SIGTSTP); ResetTerm(); ClAndRedraw();}#endif#ifndef MACvoidjcloseall(){ tmpclose();#ifdef UNIX recclose();#endif#ifdef LOAD_AV closekmem();#endif /* LOAD_AV */}voidPush(){#ifndef MSDOS int pid; SIGRESULT (*old_quit) ptrproto((int)) = signal(SIGQUIT, SIG_IGN);#endif /* !MSDOS */ SIGRESULT (*old_int) ptrproto((int)) = signal(SIGINT, SIG_IGN);# ifdef PIPEPROCS int started;# endif#ifndef MSDOS#ifdef IPROCS SigHold(SIGCHLD);#endif#ifdef WINRESIZE SigHold(SIGWINCH);#endif alarm((unsigned)0);# ifdef PIPEPROCS started = kbd_stop();# endif switch (pid = fork()) { case -1:# ifdef PIPEPROCS if (started) (void) kbd_strt();# endif complain("[Fork failed: %s]", strerror(errno)); /*NOTREACHED*/ case 0: UnsetTerm(ModBufs(NO) ? "[There are modified buffers]" : NullStr);#ifdef WINRESIZE SigRelse(SIGWINCH);#endif#ifdef IPROCS SigRelse(SIGCHLD);#endif (void) signal(SIGTERM, SIG_DFL);#else /* MSDOS */ UnsetTerm(ModBufs(NO) ? "[There are modified buffers]" : NullStr);#endif /* MSDOS */ (void) signal(SIGINT, SIG_DFL);#ifdef UNIX (void) signal(SIGQUIT, SIG_DFL); jcloseall(); /* note that curbuf->bfname may be NULL */ execl(Shell, basename(Shell), "-is", pr_name(curbuf->b_fname, NO), (char *)NULL); raw_complain("[Execl failed: %s]", strerror(errno)); _exit(1); }#ifdef IPROCS SigRelse(SIGCHLD);#endif dowait(pid, (int *) NULL);#endif /* UNIX */#ifdef MSDOS break_rst(); if (spawnl(0, Shell, basename(Shell), (char *)NULL) == -1) message("[Spawn failed]");#endif /* MSDOS */#ifndef MAC ResetTerm();#endif#ifdef WINRESIZE SigRelse(SIGWINCH);#endif ClAndRedraw();#ifndef MSDOS (void) signal(SIGQUIT, old_quit);#else /* MSDOS */ break_off(); getCWD();#endif /* MSDOS */ (void) signal(SIGINT, old_int);#ifdef UNIX if (UpdFreq != 0) (void) alarm((unsigned) (UpdFreq - (time((time_t *)NULL) % UpdFreq)));#endif# ifdef PIPEPROCS if (started) (void) kbd_strt();# endif}#endif /* MAC */bool OKXonXoff = OFF; /* ^S and ^Q initially DON'T work */int IntChar = CTL(']');private voidttsize(){#ifdef UNIX# ifdef TIOCGWINSZ struct winsize win; if (ioctl(0, TIOCGWINSZ, (UnivPtr) &win) == 0) { if (win.ws_col) CO = win.ws_col; if (win.ws_row) LI = win.ws_row; }# else /* !TIOCGWINSZ */# ifdef BTL_BLIT#include <sys/jioctl.h> struct jwinsize jwin; if (ioctl(0, JWINSIZE, &jwin) == 0) { if (jwin.bytesx) CO = jwin.bytesx; if (jwin.bytesy) LI = jwin.bytesy; }# endif /* BTL_BLIT */# endif /* !TIOCGWINSZ */#endif /* UNIX */#ifdef MAC CO = getCO(); /* see mac.c */ LI = getLI(); Windchange = YES; clr_page();#endif ILI = LI - 1;}#ifdef BIFFprivate voidbiff_init(){ dw_biff = ((BiffChk) &&# ifndef BSD4_2 ((tt_name != NULL) || (tt_name = ttyname(0))) && (stat(tt_name, &tt_stat) != -1) &&# else (fstat(0, &tt_stat) != -1) &&# endif (tt_stat.st_mode & S_IEXEC)); /* he's using biff */}private voidbiff(on)int on;{ if (dw_biff == NO) return;# ifndef BSD4_2 (void) chmod(tt_name, on ? tt_stat.st_mode : (tt_stat.st_mode & ~S_IEXEC));# else (void) fchmod(0, on ? tt_stat.st_mode : (tt_stat.st_mode & ~S_IEXEC));# endif}#endif /* BIFF */private voidttinit(){#ifdef BIFF biff_init();#endif#ifdef TIOCSLTC (void) ioctl(0, TIOCGLTC, (UnivPtr) &ls[OFF]); ls[ON] = ls[OFF]; ls[ON].t_suspc = (char) -1; ls[ON].t_dsuspc = (char) -1; ls[ON].t_flushc = (char) -1; ls[ON].t_lnextc = (char) -1;#endif#ifdef TIOCGETC /* Change interupt and quit. */ (void) ioctl(0, TIOCGETC, (UnivPtr) &tc[OFF]); tc[ON] = tc[OFF]; tc[ON].t_intrc = IntChar; tc[ON].t_quitc = (char) -1; if (OKXonXoff) { tc[ON].t_stopc = (char) -1; tc[ON].t_startc = (char) -1; }#endif /* TIOCGETC */ do_sgtty();}private int done_ttinit = NO;#ifndef MSDOSprivate#endifvoiddo_sgtty(){#ifdef UNIX# ifdef TERMIO (void) ioctl(0, TCGETA, (char *) &sg[OFF]);# endif# ifdef TERMIOS (void) tcgetattr(0, &sg[OFF]);# endif# ifdef SGTTY (void) gtty(0, &sg[OFF]);# endif /* SYSV */ sg[ON] = sg[OFF];# ifdef LPASS8 (void) ioctl(0, TIOCLGET, (UnivPtr) &lmword[OFF]); lmword[ON] = lmword[OFF]; if (MetaKey) lmword[ON] |= LPASS8;# endif# ifdef LTILDE if (Hazeltine) lmword[ON] &= ~LTILDE;# endif# if defined(TERMIO) || defined(TERMIOS)#ifdef TAB3 TABS = !((sg[OFF].c_oflag & TAB3) == TAB3);#endif#ifdef CBAUD ospeed = sg[OFF].c_cflag & CBAUD;#endif if (OKXonXoff) sg[ON].c_iflag &= ~(IXON | IXOFF); sg[ON].c_iflag &= ~(INLCR|ICRNL|IGNCR|ISTRIP); /* sg[ON].c_lflag &= ~(ICANON|ECHO); */ sg[ON].c_cflag &= ~(CSIZE|PARENB); sg[ON].c_cflag |= CS8; sg[ON].c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);#ifndef OCRNL#define OCRNL 0#endif sg[ON].c_oflag &= ~(OCRNL|ONLCR);# ifdef _POSIX_VDISABLE /* The following characters cause signals in System Vr4. * We should perhaps handle them; for now, we suppress them. */ sg[ON].c_cc[VQUIT] = _POSIX_VDISABLE;#ifdef VSWTCH sg[ON].c_cc[VSWTCH] = _POSIX_VDISABLE;#endif sg[ON].c_cc[VSUSP] = _POSIX_VDISABLE; sg[ON].c_cc[VDSUSP] = _POSIX_VDISABLE;# else sg[ON].c_cc[VINTR] = IntChar; sg[ON].c_cc[VQUIT] = (char) -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -