sources-request@mirror.UUCP (02/04/87)
Submitted by: seismo!rochester!jpayne (Jonathan Payne) Mod.sources: Volume 8, Issue 23 Archive-name: jove/Part04 #! /bin/sh # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # If all goes well, you will see the message "End of archive 4 (of 13)." # Contents: io.c iproc-pipes.c iproc-ptys.c iproc.c keymaps.txt rec.c PATH=/bin:/usr/bin:/usr/ucb; export PATH echo shar: extracting "'io.c'" '(20767 characters)' if test -f 'io.c' ; then echo shar: will not over-write existing file "'io.c'" else sed 's/^X//' >io.c <<'@//E*O*F io.c//' X/************************************************************************ X * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is * X * provided to you without charge, and with no warranty. You may give * X * away copies of JOVE, including sources, provided that this notice is * X * included in all the files. * X ************************************************************************/ X X#include "jove.h" X#include "io.h" X#include "termcap.h" X X#ifdef IPROCS X# include <signal.h> X#endif X X#include <sys/stat.h> X#include <sys/file.h> X#include <errno.h> X X#ifndef W_OK X# define W_OK 2 X# define F_OK 0 X#endif X Xlong io_chars; /* number of chars in this open_file */ Xint io_lines; /* number of lines in this open_file */ Xprivate int tellall; /* display file io info? */ X X#ifdef VMUNIX Xchar iobuff[LBSIZE], X genbuf[LBSIZE], X linebuf[LBSIZE]; X#else Xchar *iobuff, X *genbuf, X *linebuf; X#endif X X#ifdef BACKUPFILES Xint BkupOnWrite = 0; X#endif X Xclose_file(fp) XFile *fp; X{ X if (fp) { X f_close(fp); X if (tellall != QUIET) X add_mess(" %d lines, %D characters.", X io_lines, X io_chars); X } X} X X/* Write the region from line1/char1 to line2/char2 to FP. This X never CLOSES the file since we don't know if we want to. */ X Xint EndWNewline = 1; X Xputreg(fp, line1, char1, line2, char2, makesure) Xregister File *fp; XLine *line1, X *line2; X{ X register int c; X register char *lp; X X if (makesure) X (void) fixorder(&line1, &char1, &line2, &char2); X while (line1 != line2->l_next) { X lp = lcontents(line1) + char1; X if (line1 == line2) { X fputnchar(lp, (char2 - char1), fp); X io_chars += (char2 - char1); X } else while (c = *lp++) { X putc(c, fp); X io_chars++; X } X if (line1 != line2) { X io_lines++; X io_chars++; X putc('\n', fp); X } X line1 = line1->l_next; X char1 = 0; X } X flush(fp); X} X Xread_file(file, is_insert) Xchar *file; X{ X Bufpos save; X File *fp; X X if (!is_insert) { X curbuf->b_ntbf = 0; X set_ino(curbuf); X } X fp = open_file(file, iobuff, F_READ, !COMPLAIN, !QUIET); X if (fp == NIL) { X if (!is_insert && errno == ENOENT) X s_mess("(new file)"); X else X s_mess(IOerr("open", file)); X return; X } X DOTsave(&save); X dofread(fp); X SetDot(&save); X if (is_insert && io_chars > 0) X modify(); X getDOT(); X close_file(fp); X} X Xdofread(fp) Xregister File *fp; X{ X char end[LBSIZE]; X int xeof = 0; X Line *savel = curline; X int savec = curchar; X disk_line f_getputl() ; X X strcpy(end, linebuf + curchar); X xeof = f_gets(fp, linebuf + curchar, LBSIZE - curchar); X SavLine(curline, linebuf); X if (!xeof) do { X curline = listput(curbuf, curline); X xeof = f_getputl(curline, fp); X } while (!xeof); X getDOT(); X linecopy(linebuf, (curchar = strlen(linebuf)), end); X SavLine(curline, linebuf); X IFixMarks(savel, savec, curline, curchar); X} X XSaveFile() X{ X if (IsModified(curbuf)) { X if (curbuf->b_fname == 0) X WriteFile(); X else { X filemunge(curbuf->b_fname); X chk_mtime(curbuf, curbuf->b_fname, "save"); X file_write(curbuf->b_fname, 0); X unmodify(); X } X } else X message("No changes need to be written."); X} X Xchar *HomeDir; /* home directory */ Xint HomeLen = -1; /* length of home directory string */ X X#ifndef CHDIR X Xchar * Xpr_name(fname) Xchar *fname; X{ X if (fname == 0) X return 0; X X if (strncmp(fname, HomeDir, HomeLen) == 0) { X static char name_buf[100]; X X sprintf(name_buf, "~%s", fname + HomeLen); X return name_buf; X } X X return fname; X} X X#else X X#define NDIRS 5 X Xprivate char *DirStack[NDIRS] = {0}; Xprivate int DirSP = 0; /* Directory stack pointer */ X#define PWD (DirStack[DirSP]) X Xchar * Xpwd() X{ X return PWD; X} X Xchar * Xpr_name(fname) Xchar *fname; X{ X int n; X X if (fname == 0) X return 0; X n = numcomp(fname, PWD); X X if ((PWD[n] == 0) && /* Matched to end of PWD */ X (fname[n] == '/')) X return fname + n + 1; X X if (strcmp(HomeDir, "/") != 0 && strncmp(fname, HomeDir, HomeLen) == 0) { X static char name_buf[100]; X X sprintf(name_buf, "~%s", fname + HomeLen); X return name_buf; X } X X return fname; /* return entire path name */ X} X XChdir() X{ X char dirbuf[FILESIZE]; X X (void) ask_file((char *) 0, PWD, dirbuf); X if (chdir(dirbuf) == -1) { X s_mess("cd: cannot change into %s.", dirbuf); X return; X } X UpdModLine++; X setCWD(dirbuf); X} X X#ifndef JOB_CONTROL Xchar * Xgetwd() X{ X Buffer *old = curbuf; X char *ret_val; X X SetBuf(do_select((Window *) 0, "pwd-output")); X curbuf->b_type = B_PROCESS; X (void) UnixToBuf("pwd-output", NO, 0, YES, "/bin/pwd", (char *) 0); X ToFirst(); X ret_val = sprint(linebuf); X SetBuf(old); X return ret_val; X} X#endif X XsetCWD(d) Xchar *d; X{ X if (PWD == 0) X PWD = malloc((unsigned) strlen(d) + 1); X else { X extern char *ralloc(); X X PWD = ralloc(PWD, strlen(d) + 1); X } X strcpy(PWD, d); X} X XgetCWD() X{ X char *cwd = getenv("CWD"); X#ifdef JOB_CONTROL X extern char *getwd(); X char pathname[FILESIZE]; X#endif X X if (cwd == 0) X#ifdef JOB_CONTROL X cwd = getwd(pathname); X#else X cwd = getwd(); X#endif X X setCWD(cwd); X} X XprDIRS() X{ X register int i; X X s_mess(": %f "); X for (i = DirSP; i >= 0; i--) X add_mess("%s ", pr_name(DirStack[i])); X} X XprCWD() X{ X s_mess(": %f => \"%s\"", PWD); X} X XPushd() X{ X char *newdir, X dirbuf[FILESIZE]; X X newdir = ask_file((char *) 0, NullStr, dirbuf); X UpdModLine++; X if (*newdir == 0) { /* Wants to swap top two entries */ X char *old_top; X X if (DirSP == 0) X complain("pushd: no other directory."); X old_top = PWD; X DirStack[DirSP] = DirStack[DirSP - 1]; X DirStack[DirSP - 1] = old_top; X (void) chdir(PWD); X } else { X if (chdir(dirbuf) == -1) { X s_mess("pushd: cannot change into %s.", dirbuf); X return; X } X X if (DirSP + 1 >= NDIRS) X complain("pushd: full stack; max of %d pushes.", NDIRS); X DirSP++; X setCWD(dirbuf); X } X prDIRS(); X} X XPopd() X{ X if (DirSP == 0) X complain("popd: directory stack is empty."); X UpdModLine++; X free(PWD); X PWD = 0; X DirSP--; X (void) chdir(PWD); /* If this doesn't work, we's in deep shit. */ X prDIRS(); X} X Xprivate char * Xdbackup(base, offset, c) Xregister char *base, X *offset, X c; X{ X while (offset > base && *--offset != c) X ; X return offset; X} X Xdfollow(file, into) Xchar *file, X *into; X{ X char *dp, X *sp; X X if (*file == '/') { /* Absolute pathname */ X strcpy(into, "/"); X file++; X } else X strcpy(into, PWD); X dp = into + strlen(into); X X sp = file; X do { X if (*file == 0) X break; X if (sp = index(file, '/')) X *sp = 0; X if (strcmp(file, ".") == 0) X ; /* So it will get to the end of the loop */ X else if (strcmp(file, "..") == 0) { X *(dp = dbackup(into, dp, '/')) = 0; X if (dp == into) X strcpy(into, "/"), dp = into + 1; X } else { X if (into[strlen(into) - 1] != '/') X (void) strcat(into, "/"); X (void) strcat(into, file); X dp += strlen(file); /* stay at the end */ X } X file = sp + 1; X } while (sp != 0); X} X X#endif CHDIR X Xget_hdir(user, buf) Xregister char *user, X *buf; X{ X char fbuf[LBSIZE], X pattern[100]; X register int u_len; X File *fp; X X u_len = strlen(user); X fp = open_file("/etc/passwd", fbuf, F_READ, COMPLAIN, QUIET); X sprintf(pattern, "%s:[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]*\\):", user); X while (f_gets(fp, genbuf, LBSIZE) != EOF) X if ((strncmp(genbuf, user, u_len) == 0) && X (LookingAt(pattern, genbuf, 0))) { X putmatch(1, buf, FILESIZE); X close_file(fp); X return; X } X f_close(fp); X complain("[unknown user: %s]", user); X} X XPathParse(name, intobuf) Xchar *name, X *intobuf; X{ X char localbuf[FILESIZE]; X X intobuf[0] = localbuf[0] = '\0'; X if (*name == '\0') X return; X if (*name == '~') { X if (name[1] == '/' || name[1] == '\0') { X strcpy(localbuf, HomeDir); X name++; X } else { X char *uendp = index(name, '/'), X unamebuf[30]; X X if (uendp == 0) X uendp = name + strlen(name); X name = name + 1; X null_ncpy(unamebuf, name, uendp - name); X get_hdir(unamebuf, localbuf); X name = uendp; X } X } else if (*name == '\\') X name++; X (void) strcat(localbuf, name); X#ifdef CHDIR X dfollow(localbuf, intobuf); X#else X strcpy(intobuf, localbuf); X#endif X} X Xfilemunge(newname) Xchar *newname; X{ X struct stat stbuf; X X if (newname == 0) X return; X if (stat(newname, &stbuf)) X return; X if ((stbuf.st_ino != curbuf->b_ino) && X ((stbuf.st_mode & S_IFMT) != S_IFCHR) && X (strcmp(newname, curbuf->b_fname) != 0)) { X rbell(); X confirm("\"%s\" already exists; overwrite it? ", newname); X } X} X XWrtReg() X{ X DoWriteReg(0); X} X XAppReg() X{ X DoWriteReg(1); X} X Xint CreatMode = DFLT_MODE; X XDoWriteReg(app) X{ X char fnamebuf[FILESIZE], X *fname; X Mark *mp = CurMark(); X File *fp; X X /* Won't get here if there isn't a Mark */ X fname = ask_file((char *) 0, (char *) 0, fnamebuf); X X#ifdef BACKUPFILES X if (!app) { X filemunge(fname); X X if (BkupOnWrite) X file_backup(fname); X } X#else X if (!app) X filemunge(fname); X#endif X X fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, COMPLAIN, !QUIET); X putreg(fp, mp->m_line, mp->m_char, curline, curchar, YES); X close_file(fp); X} X Xint OkayBadChars = 0; X XWriteFile() X{ X char *fname, X fnamebuf[FILESIZE]; X X fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf); X /* Don't allow bad characters when creating new files. */ X if (!OkayBadChars && strcmp(curbuf->b_fname, fnamebuf) != 0) { X static char *badchars = "!$^&*()~`{}\"'\\|<>? "; X register char *cp = fnamebuf; X register int c; X X while (c = *cp++) X if (c < ' ' || c == '\177' || index(badchars, c)) X complain("'%p': bad character in filename.", c); X } X X chk_mtime(curbuf, fname, "write"); X filemunge(fname); X curbuf->b_type = B_FILE; /* In case it wasn't before. */ X setfname(curbuf, fname); X file_write(fname, 0); X unmodify(); X} X XFile * Xopen_file(fname, buf, how, ifbad, loudness) Xregister char *fname; Xchar *buf; Xregister int how; X{ X register File *fp; X X io_chars = 0; X io_lines = 0; X tellall = loudness; X X fp = f_open(fname, how, buf, LBSIZE); X if (fp == NIL) { X message(IOerr((how == F_READ) ? "open" : "create", fname)); X if (ifbad == COMPLAIN) X complain((char *) 0); X } else { X int readonly = FALSE; X X if (access(fname, W_OK) == -1 && errno != ENOENT) X readonly = TRUE; X X if (loudness != QUIET) X f_mess("\"%s\"%s", pr_name(fname), X readonly ? " [Read only]" : NullStr); X } X return fp; X} X X/* Check to see if the file has been modified since it was X last written. If so, make sure they know what they're X doing. X X I hate to use another stat(), but to use confirm we gotta X do this before we open the file. */ X Xchk_mtime(thisbuf, fname, how) XBuffer *thisbuf; Xchar *fname, X *how; X{ X struct stat stbuf; X Buffer *b; X char *mesg = "Shall I go ahead and %s anyway? "; X X if ((thisbuf->b_mtime != 0) && /* if we care ... */ X (b = file_exists(fname)) && /* we already have this file */ X (b == thisbuf) && /* and it's the current buffer */ X (stat(fname, &stbuf) != -1) && /* and we can stat it */ X (stbuf.st_mtime != b->b_mtime)) { /* and there's trouble. */ X rbell(); X redisplay(); /* Ring that bell! */ X TOstart("Warning", TRUE); X Typeout("\"%s\" now saved on disk is not what you last", pr_name(fname)); X Typeout("visited or saved. Probably someone else is editing"); X Typeout("your file at the same time."); X if (how) { X Typeout(""); X Typeout("Type \"y\" if I should %s, anyway.", how); X f_mess(mesg, how); X } X TOstop(); X if (how) X confirm(mesg, how); X } X} X Xfile_write(fname, app) Xchar *fname; X{ X File *fp; X X#ifdef BACKUPFILES X if (!app && BkupOnWrite) X file_backup(fname); X#endif X X fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, COMPLAIN, !QUIET); X X if (EndWNewline) { /* Make sure file ends with a newLine */ X Bufpos save; X X DOTsave(&save); X ToLast(); X if (length(curline)) /* Not a blank Line */ X LineInsert(1); X SetDot(&save); X } X putreg(fp, curbuf->b_first, 0, curbuf->b_last, length(curbuf->b_last), NO); X set_ino(curbuf); X close_file(fp); X} X XReadFile() X{ X char *fname, X fnamebuf[FILESIZE]; X X fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf); X chk_mtime(curbuf, fname, "read"); X X if (IsModified(curbuf)) { X char *y_or_n; X int c; X X for (;;) { X rbell(); X y_or_n = ask(NullStr, "Shall I make your changes to \"%s\" permanent? ", curbuf->b_name); X c = Upper(*y_or_n); X if (c == 'Y' || c == 'N') X break; X } X if (c == 'Y') X SaveFile(); X } X X unmodify(); X initlist(curbuf); X setfname(curbuf, fname); X read_file(fname, 0); X} X XInsFile() X{ X char *fname, X fnamebuf[FILESIZE]; X X fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf); X read_file(fname, 1); X} X X#include "temp.h" X Xint DOLsave = 0; /* Do Lsave flag. If lines aren't being save X when you think they should have been, this X flag is probably not being set, or is being X cleared before lsave() was called. */ X Xprivate int nleft, /* number of good characters left in current block */ X tmpfd = -1; Xprivate disk_line DFree = 1; X /* pointer to end of tmp file */ Xprivate char *tfname; X Xtmpinit() X{ X char buf[FILESIZE]; X X sprintf(buf, "%s/%s", TmpFilePath, d_tempfile); X tfname = copystr(buf); X tfname = mktemp(tfname); X (void) close(creat(tfname, 0600)); X tmpfd = open(tfname, 2); X if (tmpfd == -1) X complain("Warning: cannot create tmp file!"); X} X Xtmpclose() X{ X (void) close(tmpfd); X tmpfd = -1; X (void) unlink(tfname); X} X X/* Get a line at `tl' in the tmp file into `buf' which should be LBSIZE X long. */ X Xint Jr_Len; /* Length of Just Read Line. */ Xprivate char *getblock(); X Xgetline(addr, buf) Xdisk_line addr; Xregister char *buf; X{ X register char *bp, X *lp; X X lp = buf; X bp = getblock(addr >> 1, READ); X while (*lp++ = *bp++) X ; X Jr_Len = (lp - buf) - 1; X} X X/* Put `buf' and return the disk address */ X Xdisk_line Xputline(buf) Xchar *buf; X{ X register char *bp, X *lp; X register int nl; X disk_line free_ptr; X X lp = buf; X free_ptr = DFree; X bp = getblock(free_ptr, WRITE); X nl = nleft; X free_ptr = blk_round(free_ptr); X while (*bp = *lp++) { X if (*bp++ == '\n') { X *--bp = 0; X break; X } X if (--nl == 0) { X free_ptr = forward_block(free_ptr); X DFree = free_ptr; X bp = getblock(free_ptr, WRITE); X lp = buf; /* start over ... */ X nl = nleft; X } X } X free_ptr = DFree; X DFree += (((lp - buf) + CH_SIZE - 1) / CH_SIZE); X /* (lp - buf) includes the null */ X return (free_ptr << 1); X} X X/* The theory is that critical section of code inside this procedure X will never cause a problem to occur. Basically, we need to ensure X that two blocks are in memory at the same time, but I think that X this can never screw up. */ X X#define lockblock(addr) X#define unlockblock(addr) X Xdisk_line Xf_getputl(line, fp) XLine *line; Xregister File *fp; X{ X register char *bp; X register int c, X nl, X max = LBSIZE; X disk_line free_ptr; X char *base; X X free_ptr = DFree; X base = bp = getblock(free_ptr, WRITE); X nl = nleft; X free_ptr = blk_round(free_ptr); X while (--max > 0) { X c = getc(fp); X if (c == EOF || c == '\n') X break; X if (--nl == 0) { X char *newbp; X int nbytes; X X lockblock(free_ptr); X DFree = free_ptr = forward_block(free_ptr); X nbytes = bp - base; X newbp = getblock(free_ptr, WRITE); X nl = nleft; X byte_copy(base, newbp, nbytes); X bp = newbp + nbytes; X base = newbp; X unlockblock(free_ptr); X } X *bp++ = c; X } X *bp++ = '\0'; X free_ptr = DFree; X DFree += (((bp - base) + CH_SIZE - 1) / CH_SIZE); X line->l_dline = (free_ptr << 1); X if (max == 0) { X add_mess(" [Line too long]"); X rbell(); X return EOF; X } X if (c == EOF) { X if (--bp != base) X add_mess(" [Incomplete last line]"); X return EOF; X } X io_lines++; X return NIL; X} X Xtypedef struct block { X short b_dirty, X b_bno; X char b_buf[BUFSIZ]; X struct block X *b_LRUnext, X *b_LRUprev, X *b_HASHnext; X} Block; X X#define HASHSIZE 7 /* Primes work best (so I'm told) */ X#define B_HASH(bno) (bno % HASHSIZE) X Xprivate Block b_cache[NBUF], X *bht[HASHSIZE] = {0}, /* Block hash table */ X *f_block = 0, X *l_block = 0; Xprivate int max_bno = -1, X NBlocks; X Xprivate int (*blkio)(); X Xprivate Xreal_blkio(b, iofcn) Xregister Block *b; Xregister int (*iofcn)(); X{ X (void) lseek(tmpfd, (long) ((unsigned) b->b_bno) * BUFSIZ, 0); X if ((*iofcn)(tmpfd, b->b_buf, BUFSIZ) != BUFSIZ) X error("Tmp file %s error.", (iofcn == read) ? "read" : "write"); X} X Xprivate Xfake_blkio(b, iofcn) Xregister Block *b; Xregister int (*iofcn)(); X{ X tmpinit(); X blkio = real_blkio; X real_blkio(b, iofcn); X} X Xd_cache_init() X{ X register Block *bp, /* Block pointer */ X **hp; /* Hash pointer */ X register short bno; X X for (bp = b_cache, bno = NBUF; --bno >= 0; bp++) { X NBlocks++; X bp->b_dirty = 0; X bp->b_bno = bno; X if (l_block == 0) X l_block = bp; X bp->b_LRUprev = 0; X bp->b_LRUnext = f_block; X if (f_block != 0) X f_block->b_LRUprev = bp; X f_block = bp; X X bp->b_HASHnext = *(hp = &bht[B_HASH(bno)]); X *hp = bp; X } X blkio = fake_blkio; X} X XSyncTmp() X{ X#ifdef MSDOS X register int bno = 0; X BLock *lookup(); X X for (bno = 0; bno <= max_bno; ) X (*blkio)(lookup(bno++), write); X#else X register Block *b; X X for (b = f_block; b != 0; b = b->b_LRUnext) X if (b->b_dirty) { X (*blkio)(b, write); X b->b_dirty = 0; X } X#endif X} X Xprivate Block * Xlookup(bno) Xregister short bno; X{ X register Block *bp; X X for (bp = bht[B_HASH(bno)]; bp != 0; bp = bp->b_HASHnext) X if (bp->b_bno == bno) X break; X return bp; X} X Xprivate XLRUunlink(b) Xregister Block *b; X{ X if (b->b_LRUprev == 0) X f_block = b->b_LRUnext; X else X b->b_LRUprev->b_LRUnext = b->b_LRUnext; X if (b->b_LRUnext == 0) X l_block = b->b_LRUprev; X else X b->b_LRUnext->b_LRUprev = b->b_LRUprev; X} X Xprivate Block * Xb_unlink(bp) Xregister Block *bp; X{ X register Block *hp, X *prev = 0; X X LRUunlink(bp); X /* Now that we have the block, we remove it from its position X in the hash table, so we can THEN put it somewhere else with X it's new block assignment. */ X X for (hp = bht[B_HASH(bp->b_bno)]; hp != 0; prev = hp, hp = hp->b_HASHnext) X if (hp == bp) X break; X if (hp == 0) { X printf("\rBlock %d missing!", bp->b_bno); X finish(0); X } X if (prev) X prev->b_HASHnext = hp->b_HASHnext; X else X bht[B_HASH(bp->b_bno)] = hp->b_HASHnext; X X if (bp->b_dirty) { /* Do, now, the delayed write */ X (*blkio)(bp, write); X bp->b_dirty = 0; X } X X return bp; X} X X/* Get a block which contains at least part of the line with the address X atl. Returns a pointer to the block and sets the global variable X nleft (number of good characters left in the buffer). */ X Xprivate char * Xgetblock(atl, iof) Xdisk_line atl; X{ X register int bno, X off; X register Block *bp; X static Block *lastb = 0; X X bno = daddr_to_bno(atl); X off = daddr_to_off(atl); X if (bno >= MAX_BLOCKS) X error("Tmp file too large. Get help!"); X nleft = BUFSIZ - off; X if (lastb != 0 && lastb->b_bno == bno) { X lastb->b_dirty |= iof; X return lastb->b_buf + off; X } X X /* The requested block already lives in memory, so we move X it to the end of the LRU list (making it Most Recently Used) X and then return a pointer to it. */ X if (bp = lookup(bno)) { X if (bp != l_block) { X LRUunlink(bp); X if (l_block == 0) X f_block = l_block = bp; X else X l_block->b_LRUnext = bp; X bp->b_LRUprev = l_block; X l_block = bp; X bp->b_LRUnext = 0; X } X if (bp->b_bno > max_bno) X max_bno = bp->b_bno; X bp->b_dirty |= iof; X lastb = bp; X return bp->b_buf + off; X } X X /* The block we want doesn't reside in memory so we take the X least recently used clean block (if there is one) and use X it. */ X bp = f_block; X if (bp->b_dirty) /* The best block is dirty ... */ X SyncTmp(); X X bp = b_unlink(bp); X if (l_block == 0) X l_block = f_block = bp; X else X l_block->b_LRUnext = bp; /* Place it at the end ... */ X bp->b_LRUprev = l_block; X l_block = bp; X bp->b_LRUnext = 0; /* so it's Most Recently Used */ X X bp->b_dirty = iof; X bp->b_bno = bno; X bp->b_HASHnext = bht[B_HASH(bno)]; X bht[B_HASH(bno)] = bp; X X /* Get the current contents of the block UNLESS this is a new X block that's never been looked at before, i.e., it's past X the end of the tmp file. */ X X if (bp->b_bno <= max_bno) X (*blkio)(bp, read); X else X max_bno = bno; X X lastb = bp; X return bp->b_buf + off; X} X Xchar * Xlbptr(line) XLine *line; X{ X return getblock(line->l_dline >> 1, READ); X} X X/* save the current contents of linebuf, if it has changed */ X Xlsave() X{ X if (curbuf == 0 || !DOLsave) /* Nothing modified recently */ X return; X X if (strcmp(lbptr(curline), linebuf) != 0) X SavLine(curline, linebuf); /* Put linebuf on the disk. */ X DOLsave = 0; X} X X#ifdef BACKUPFILES Xfile_backup(fname) Xchar *fname; X{ X char *s; X register int i; X int fd1, X fd2; X char tmp1[BUFSIZ], X tmp2[BUFSIZ]; X X strcpy(tmp1, fname); X X if ((s = rindex(tmp1, '/')) == NULL) X sprintf(tmp2, "#%s", fname); X else { X *s++ = '\0'; X sprintf(tmp2, "%s/#%s", tmp1, s); X } X X if ((fd1 = open(fname, 0)) < 0) X return; X X if ((fd2 = creat(tmp2, CreatMode)) < 0) { X (void) close(fd1); X return; X } X X while ((i = read(fd1, tmp1, sizeof(tmp1))) > 0) X write(fd2, tmp1, i); X X#ifdef BSD4_2 X (void) fsync(fd2); X#endif X (void) close(fd2); X (void) close(fd1); X} X#endif @//E*O*F io.c// if test 20767 -ne "`wc -c <'io.c'`"; then echo shar: error transmitting "'io.c'" '(should have been 20767 characters)' fi fi # end of overwriting check echo shar: extracting "'iproc-pipes.c'" '(5738 characters)' if test -f 'iproc-pipes.c' ; then echo shar: will not over-write existing file "'iproc-pipes.c'" else sed 's/^X//' >iproc-pipes.c <<'@//E*O*F iproc-pipes.c//' X/************************************************************************ X * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is * X * provided to you without charge, and with no warranty. You may give * X * away copies of JOVE, including sources, provided that this notice is * X * included in all the files. * X ************************************************************************/ X X#ifdef BSD4_2 X# include <sys/wait.h> X#else X# include <wait.h> X#endif X#include <signal.h> X#include <sgtty.h> X Xtypedef struct process Process; X X#define DEAD 1 /* Dead but haven't informed user yet */ X#define STOPPED 2 /* Job stopped */ X#define RUNNING 3 /* Just running */ X#define NEW 4 /* This process is brand new */ X X/* If process is dead, flags says how. */ X#define EXITED 1 X#define KILLED 2 X X#define isdead(p) (p == 0 || proc_state(p) == DEAD || p->p_toproc == -1) X X#define proc_buf(p) (p->p_buffer->b_name) X#define proc_cmd(p) (p->p_name) X#define proc_state(p) (p->p_state) X Xprivate Process *procs = 0; X Xint ProcInput, X ProcOutput, X NumProcs = 0; X Xstatic char * Xpstate(p) XProcess *p; X{ X switch (proc_state(p)) { X case NEW: X return "Pre-birth"; X X case STOPPED: X return "Stopped"; X X case RUNNING: X return "Running"; X X case DEAD: X if (p->p_howdied == EXITED) { X if (p->p_reason == 0) X return "Done"; X return sprint("[Exit %d]", p->p_reason); X } X return sprint("[Killed %d]", p->p_reason); X X default: X return "Unknown state."; X } X} X Xstatic Process * Xproc_pid(pid) X{ X register Process *p; X X for (p = procs; p != 0; p = p->p_next) X if (p->p_portpid == pid) X break; X X return p; X} X Xprocs_read() X{ X struct header { X int pid; X int nbytes; X } header; X int n; X long nbytes; X static int here = 0; X X if (here) X return; X sighold(SIGCHLD); /* Block any other children. */ X here++; X for (;;) { X (void) ioctl(ProcInput, FIONREAD, (struct sgttyb *) &nbytes); X if (nbytes < sizeof header) X break; X n = read(ProcInput, (char *) &header, sizeof header); X if (n != sizeof header) X finish(1); X read_proc(header.pid, header.nbytes); X } X redisplay(); X here = 0; X sigrelse(SIGCHLD); X} X Xread_proc(pid, nbytes) Xint pid; Xregister int nbytes; X{ X register Process *p; X int n; X char ibuf[512]; X X if ((p = proc_pid(pid)) == 0) { X printf("\riproc: unknown pid (%d)", pid); X return; X } X if (proc_state(p) == NEW) { X int rpid; X /* Pid of real child, not of portsrv. */ X X doread(ProcInput, (char *) &rpid, nbytes); X nbytes -= sizeof rpid; X p->p_pid = rpid; X p->p_state = RUNNING; X } X X if (nbytes == EOF) { /* Okay to clean up this process */ X p->p_eof = 1; X NumProcs--; /* As far as getch() in main is concerned */ X return; X } X X while (nbytes > 0) { X n = min((sizeof ibuf) - 1, nbytes); X doread(ProcInput, ibuf, n); X ibuf[n] = 0; /* Null terminate for convenience */ X nbytes -= n; X proc_rec(p, ibuf); X } X} X XProcKill() X{ X proc_kill(curbuf->b_process, SIGKILL); X} X XProcInt() X{ X proc_kill(curbuf->b_process, SIGINT); X} X XProcQuit() X{ X proc_kill(curbuf->b_process, SIGQUIT); X} X Xstatic Xproc_close(p) XProcess *p; X{ X (void) close(p->p_toproc); X p->p_toproc = -1; /* Writes will fail. */ X} X Xdo_rtp(mp) Xregister Mark *mp; X{ X register Process *p = curbuf->b_process; X Line *line1 = curline, X *line2 = mp->m_line; X int char1 = curchar, X char2 = mp->m_char; X char *gp; X X if (isdead(p) || p->p_buffer != curbuf) X return; X X (void) fixorder(&line1, &char1, &line2, &char2); X while (line1 != line2->l_next) { X gp = ltobuf(line1, genbuf) + char1; X if (line1 == line2) X gp[char2] = '\0'; X else X strcat(gp, "\n"); X (void) write(p->p_toproc, gp, strlen(gp)); X line1 = line1->l_next; X char1 = 0; X } X} X X/* VARARGS3 */ X Xprivate Xproc_strt(bufname, clobber, va_alist) Xchar *bufname; Xva_dcl X{ X Window *owind = curwind; X int toproc[2], X pid; X Process *newp; X Buffer *newbuf; X char *argv[32], X *cp, X foo[10], X cmdbuf[128]; X int i; X va_list ap; X X isprocbuf(bufname); /* make sure BUFNAME is either nonexistant X or is of type B_PROCESS */ X dopipe(toproc); X X switch (pid = fork()) { X case -1: X pclose(toproc); X complain("[Fork failed.]"); X X case 0: X argv[0] = "portsrv"; X argv[1] = foo; X sprintf(foo, "%d", ProcInput); X va_start(ap); X make_argv(&argv[2], ap); X va_end(ap); X (void) dup2(toproc[0], 0); X (void) dup2(ProcOutput, 1); X (void) dup2(ProcOutput, 2); X pclose(toproc); X execv(Portsrv, args); X printf("Execl failed.\n"); X _exit(1); X } X X sighold(SIGCHLD); X newp = (Process *) malloc(sizeof *newp); X newp->p_next = procs; X newp->p_state = NEW; X newp->p_cmd = 0; X X cmdbuf[0] = '\0'; X va_start(ap); X while (cp = va_arg(ap, char *)) X sprintf(&cmdbuf[strlen(cmdbuf)], "%s ", cp); X va_end(ap); X newp->p_name = copystr(cmdbuf); X procs = newp; X newp->p_portpid = pid; X newp->p_pid = -1; X X newbuf = do_select((Window *) 0, bufname); X newbuf->b_type = B_PROCESS; X newp->p_buffer = newbuf; X newbuf->b_process = newp; /* sorta circular, eh? */ X pop_wind(bufname, clobber, B_PROCESS); X ToLast(); X if (!bolp()) X LineInsert(1); X /* Pop_wind() after everything is set up; important! X Bindings won't work right unless newbuf->b_process is already X set up BEFORE NEWBUF is first SetBuf()'d. */ X newp->p_mark = MakeMark(curline, curchar, FLOATER); X X newp->p_toproc = toproc[1]; X newp->p_reason = 0; X newp->p_eof = 0; X NumProcs++; X (void) close(toproc[0]); X sigrelse(SIGCHLD); X SetWind(owind); X} X Xpinit() X{ X int p[2]; X X (void) signal(SIGCHLD, proc_child); X (void) pipe(p); X ProcInput = p[0]; X ProcOutput = p[1]; X (void) signal(INPUT_SIG, procs_read); X sighold(INPUT_SIG); /* Released during terminal read */ X} X Xdoread(fd, buf, n) Xchar *buf; X{ X int nread; X X if ((nread = read(fd, buf, n)) != n) X complain("Cannot read %d (got %d) bytes.", n, nread); X} @//E*O*F iproc-pipes.c// if test 5738 -ne "`wc -c <'iproc-pipes.c'`"; then echo shar: error transmitting "'iproc-pipes.c'" '(should have been 5738 characters)' fi fi # end of overwriting check echo shar: extracting "'iproc-ptys.c'" '(7160 characters)' if test -f 'iproc-ptys.c' ; then echo shar: will not over-write existing file "'iproc-ptys.c'" else sed 's/^X//' >iproc-ptys.c <<'@//E*O*F iproc-ptys.c//' X/************************************************************************ X * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is * X * provided to you without charge, and with no warranty. You may give * X * away copies of JOVE, including sources, provided that this notice is * X * included in all the files. * X ************************************************************************/ X X#ifdef BSD4_2 X# include <sys/wait.h> X#else X# include <wait.h> X#endif X#include <signal.h> X#include <sgtty.h> X X#define DEAD 1 /* Dead but haven't informed user yet */ X#define STOPPED 2 /* Job stopped */ X#define RUNNING 3 /* Just running */ X#define NEW 4 /* This process is brand new */ X X/* If process is dead, flags says how. */ X#define EXITED 1 X#define KILLED 2 X X#define isdead(p) (p == 0 || proc_state(p) == DEAD || p->p_fd == -1) X X#define proc_buf(p) (p->p_buffer->b_name) X#define proc_cmd(p) (p->p_name) X#define proc_state(p) (p->p_state) X Xprivate Process *procs = 0; X Xint global_fd = 1, X NumProcs = 0; X X#ifdef BRLUNIX X extern struct sg_brl sg1; X#else X extern struct sgttyb sg1; X#endif X Xextern struct tchars tc1; X X#ifdef TIOCSLTC X extern struct ltchars ls1; X#endif X Xstatic char * Xpstate(p) XProcess *p; X{ X switch (proc_state(p)) { X case STOPPED: X return "Stopped"; X X case RUNNING: X return "Running"; X X case DEAD: X if (p->p_howdied == EXITED) { X if (p->p_reason == 0) X return "Done"; X return sprint("exit(%d)", p->p_reason); X } X return sprint("Killed(%d)", p->p_reason); X X default: X return "Unknown state."; X } X} X Xstatic Process * Xproc_pid(pid) X{ X register Process *p; X X for (p = procs; p != 0; p = p->p_next) X if (p->p_pid == pid) X break; X X return p; X} X Xread_proc(fd) Xregister int fd; X{ X register Process *p; X unsigned int n; X char ibuf[1024]; X X for (p = procs; p != 0; p = p->p_next) X if (p->p_fd == fd) X break; X X if (p == 0) { X printf("\riproc: unknown fd %d", fd); X return; X } X X n = read(fd, ibuf, sizeof(ibuf) - 1); X if (n == 0) { X proc_close(p); X NumProcs--; X return; X } X ibuf[n] = '\0'; X proc_rec(p, ibuf); X redisplay(); X} X XProcKill() X{ X register Buffer *b; X Process *buf_to_proc(); X char *bname; X X bname = ask_buf(curbuf); X X if ((b = buf_exists(bname)) == 0) X complain("[No such buffer]"); X if (b->b_process == 0) X complain("%s not tied to a process.", bname); X proc_kill(b->b_process, SIGKILL); X} X XProcCont() X{ X Process *p; X X if ((p = curbuf->b_process) == 0) X complain("[No process]"); X if (p->p_state != DEAD) { X proc_kill(p, SIGCONT); X p->p_state = RUNNING; X } X} X XProcEof() X{ X send_p(tc1.t_eofc); X} X XProcInt() X{ X send_p(tc1.t_intrc); X} X XProcQuit() X{ X send_p(tc1.t_quitc); X} X XProcStop() X{ X send_p(ls1.t_suspc); X} X XProcDStop() X{ X send_p(ls1.t_dsuspc); X} X Xsend_p(c) Xchar c; X{ X Process *p; X X if ((p = curbuf->b_process) == 0) X complain("[No process]"); X ToLast(); X (void) write(p->p_fd, &c, 1); X} X Xstatic Xproc_close(p) XProcess *p; X{ X (void) close(p->p_fd); X global_fd &= ~(1 << p->p_fd); X p->p_eof++; X} X Xdo_rtp(mp) Xregister Mark *mp; X{ X register Process *p = curbuf->b_process; X Line *line1 = curline, X *line2 = mp->m_line; X int char1 = curchar, X char2 = mp->m_char; X char *gp; X X if (isdead(p) || p->p_buffer != curbuf) X return; X X (void) fixorder(&line1, &char1, &line2, &char2); X while (line1 != line2->l_next) { X gp = ltobuf(line1, genbuf) + char1; X if (line1 == line2) X gp[char2] = '\0'; X else X strcat(gp, "\n"); X (void) write(p->p_fd, gp, strlen(gp)); X line1 = line1->l_next; X char1 = 0; X } X} X X/* VARARGS3 */ X Xprivate Xproc_strt(bufname, clobber, va_alist) Xchar *bufname; Xva_dcl X{ X va_list ap; X char *argv[32], X *cp; X Window *owind = curwind; X int pid; X Process *newp; X Buffer *newbuf; X int i, X f, X ttyfd; X long ldisc, X lmode; X register char *s, X *t; X extern int errno; X static char ttybuf[11], X ptybuf[11]; X char cmdbuf[128]; X#ifdef BRLUNIX X struct sg_brl sg; X#else X struct sgttyb sg; X#endif X X#ifdef TIOCGWINSZ X struct winsize win; X#else X# ifdef BTL_BLIT X# include <sys/jioctl.h> X struct jwinsize jwin; X# endif X#endif X X isprocbuf(bufname); /* make sure BUFNAME is either nonexistant X or is of type B_PROCESS */ X for (s = "pqrs"; *s; s++) { X for (t = "0123456789abcdef"; *t; t++) { X sprintf(ptybuf, "/dev/pty%c%c", *s, *t); X if ((ttyfd = open(ptybuf, 2)) >= 0) { X strcpy(ttybuf, ptybuf); X ttybuf[5] = 't'; X /* make sure both ends are available */ X if ((i = open(ttybuf, 2)) < 0) X continue; X (void) close(i); X goto out; X } X } X } X Xout: if (s == 0 && t == 0) X complain("[Out of ptys!]"); X X#ifdef TIOCGETD X (void) ioctl(0, TIOCGETD, (struct sgttyb *) &ldisc); X#endif X#ifdef TIOCLGET X (void) ioctl(0, TIOCLGET, (struct sgttyb *) &lmode); X#endif X#ifdef TIOCGWINSZ X (void) ioctl(0, TIOCGWINSZ, (struct sgttyb *) &win); X#else X# ifdef BTL_BLIT X (void) ioctl(0, JWINSIZE, (struct sgttyb *) &jwin); X# endif BTL_BLIT X#endif X X switch (pid = fork()) { X case -1: X (void) close(ttyfd); X complain("[Fork failed!]"); X X case 0: X for (i = 0; i < 32; i++) X (void) close(i); X X#ifdef TIOCNOTTY X if ((i = open("/dev/tty", 2)) >= 0) { X (void) ioctl(i, TIOCNOTTY, (struct sgttyb *) 0); X (void) close(i); X } X#endif X i = open(ttybuf, 2); X for (f = 0; f <= 2; f++) X (void) dup2(i, f); X X#ifdef TIOCSETD X (void) ioctl(0, TIOCSETD, (struct sgttyb *) &ldisc); X#endif X#ifdef TIOCLSET X (void) ioctl(0, TIOCLSET, (struct sgttyb *) &lmode); X#endif X#ifdef TIOCSETC X (void) ioctl(0, TIOCSETC, (struct sgttyb *) &tc1); X#endif X#ifdef TIOCSLTC X (void) ioctl(0, TIOCSLTC, (struct sgttyb *) &ls1); X#endif X X#ifdef TIOCGWINSZ X# ifdef SIGWINCH X (void) signal(SIGWINCH, SIG_IGN); X# endif X win.ws_row = curwind->w_height; X (void) ioctl(0, TIOCSWINSZ, (struct sgttyb *) &win); X#else X# ifdef BTL_BLIT X jwin.bytesy = curwind->w_height; X (void) ioctl(0, JSWINSIZE, (struct sgttyb *) &jwin); X# endif X#endif X X sg = sg1; X sg.sg_flags &= ~(ECHO | CRMOD); X (void) stty(0, &sg); X X i = getpid(); X (void) ioctl(0, TIOCSPGRP, (struct sgttyb *) &i); X (void) setpgrp(0, i); X va_start(ap); X make_argv(argv, ap); X va_end(ap); X execv(argv[0], &argv[1]); X (void) write(1, "execve failed!\n", 15); X _exit(errno + 1); X } X X sighold(SIGCHLD); X#ifdef SIGWINCH X sighold(SIGWINCH); X#endif X newp = (Process *) emalloc(sizeof *newp); X X newp->p_fd = ttyfd; X newp->p_pid = pid; X newp->p_eof = 0; X X newbuf = do_select((Window *) 0, bufname); X newbuf->b_type = B_PROCESS; X newp->p_buffer = newbuf; X newbuf->b_process = newp; /* sorta circular, eh? */ X pop_wind(bufname, clobber, B_PROCESS); X /* Pop_wind() after everything is set up; important! X Bindings won't work right unless newbuf->b_process is already X set up BEFORE NEWBUF is first SetBuf()'d. */ X ToLast(); X if (!bolp()) X LineInsert(1); X X cmdbuf[0] = '\0'; X va_start(ap); X while (cp = va_arg(ap, char *)) X sprintf(&cmdbuf[strlen(cmdbuf)], "%s ", cp++); X va_end(ap); X X newp->p_name = copystr(cmdbuf); X newp->p_state = RUNNING; X newp->p_reason = 0; X newp->p_mark = MakeMark(curline, curchar, FLOATER); X X newp->p_next = procs; X procs = newp; X NumProcs++; X global_fd |= 1 << newp->p_fd; X sigrelse(SIGCHLD); X SetWind(owind); X} X Xpinit() X{ X (void) signal(SIGCHLD, proc_child); X} @//E*O*F iproc-ptys.c// if test 7160 -ne "`wc -c <'iproc-ptys.c'`"; then echo shar: error transmitting "'iproc-ptys.c'" '(should have been 7160 characters)' fi fi # end of overwriting check echo shar: extracting "'iproc.c'" '(6421 characters)' if test -f 'iproc.c' ; then echo shar: will not over-write existing file "'iproc.c'" else sed 's/^X//' >iproc.c <<'@//E*O*F iproc.c//' X/************************************************************************ X * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is * X * provided to you without charge, and with no warranty. You may give * X * away copies of JOVE, including sources, provided that this notice is * X * included in all the files. * X ************************************************************************/ X X#include "jove.h" X#include <varargs.h> X X#ifdef IPROCS X Xint proc_child(); X X#ifdef PIPEPROCS X# include "iproc-pipes.c" X#else X# include "iproc-ptys.c" X#endif X Xchar proc_prompt[80] = "% "; X XKillProcs() X{ X register Process *p; X register int killem = -1; /* -1 means undetermined */ X register char *yorn; X X for (p = procs; p != 0; p = p->p_next) X if (!isdead(p)) { X if (killem == -1) { X yorn = ask("y", "Should I kill your i-processes? "); X killem = (Upper(*yorn) == 'Y'); X } X if (killem) X proc_kill(p, SIGKILL); X } X} X Xpbuftiedp(b) Xregister Buffer *b; X{ X register Process *p = b->b_process; X X if (!isdead(p)) X complain("Process %s, attached to %b, is %s.", X proc_cmd(p), b, pstate(p)); X} X X/* Process receive: receives the characters in buf, and appends them to X the buffer associated with p. */ X Xstatic Xproc_rec(p, buf) Xregister Process *p; Xchar *buf; X{ X Buffer *saveb = curbuf; X register Window *w; X register Mark *savepoint; X int sameplace = 0, X do_disp = 0; X X if (curwind->w_bufp == p->p_buffer) X w = curwind; X else X w = windbp(p->p_buffer); /* Is this window visible? */ X if (w != 0) X do_disp = (in_window(w, p->p_mark->m_line) != -1); X SetBuf(p->p_buffer); X savepoint = MakeMark(curline, curchar, FLOATER); X ToMark(p->p_mark); /* Where output last stopped. */ X if (savepoint->m_line == curline && savepoint->m_char == curchar) X sameplace++; X X ins_str(buf, YES); X if (do_disp) { X w->w_line = curline; X w->w_char = curchar; X redisplay(); X } X MarkSet(p->p_mark, curline, curchar); X if (!sameplace) X ToMark(savepoint); /* Back to where we were. */ X DelMark(savepoint); X SetBuf(saveb); X} X Xproc_kill(p, sig) Xregister Process *p; X{ X if (isdead(p)) X return; X if (killpg(p->p_pid, sig) == -1) X s_mess("Cannot kill %s!", proc_buf(p)); X} X X/* Deal with a process' death. proc_rec turns on the FREEUP bit when it X it gets the "EOF" from portsrv. FREEUP'd processes get unlinked from X the list, and the proc stucture and proc_buf(p) get free'd up, here. */ X Xprivate XDealWDeath() X{ X register Process *p, X *next, X *prev = 0; X X for (p = procs; p != 0; p = next) { X next = p->p_next; X if (!p->p_eof) { X prev = p; X continue; X } X proc_close(p); X PopPBs(); /* not a process anymore */ X p->p_buffer->b_process = 0; /* we're killing ourself */ X free((char *) p->p_name); X free((char *) p); X if (prev) X prev->p_next = next; X else X procs = next; X } X} X XProcList() X{ X register Process *p; X char *fmt = "%-15s %-15s %-8s %s", X pidstr[10]; X X if (procs == 0) { X message("[No subprocesses]"); X return; X } X TOstart("Process list", TRUE); X X Typeout(fmt, "Buffer", "Status", "Pid ", "Command"); X Typeout(fmt, "------", "------", "--- ", "-------"); X for (p = procs; p != 0; p = p->p_next) { X sprintf(pidstr, "%d", p->p_pid); X Typeout(fmt, proc_buf(p), pstate(p), pidstr, p->p_name); X } X DealWDeath(); X TOstop(); X} X XProcNewline() X{ X SendData(YES); X} X XProcSendData() X{ X SendData(NO); X} X Xprivate XSendData(newlinep) X{ X register Process *p = curbuf->b_process; X X if (isdead(p)) X return; X if (lastp(curline)) { X Eol(); X if (newlinep) X LineInsert(1); X do_rtp(p->p_mark); X MarkSet(p->p_mark, curline, curchar); X } else { X Bol(); X while (LookingAt(proc_prompt, linebuf, curchar)) X SetDot(dosearch(proc_prompt, 1, 1)); X strcpy(genbuf, linebuf + curchar); X ToLast(); X ins_str(genbuf, NO); X } X} X XShellProc() X{ X char *shbuf = "*shell*"; X register Buffer *b; X X b = buf_exists(shbuf); X if (b == 0 || isdead(b->b_process)) X proc_strt(shbuf, NO, Shell, "-i", (char *) 0); X pop_wind(shbuf, NO, -1); X} X XIprocess() X{ X extern char ShcomBuf[100], X *MakeName(); X register char *command; X X command = ask(ShcomBuf, ProcFmt); X null_ncpy(ShcomBuf, command, (sizeof ShcomBuf) - 1); X proc_strt(MakeName(command), YES, Shell, ShFlags, command, (char *) 0); X} X Xproc_child() X{ X union wait w; X register int pid; X X for (;;) { X#ifndef VMUNIX X pid = wait2(&w.w_status, (WNOHANG | WUNTRACED)); X#else X pid = wait3(&w, (WNOHANG | WUNTRACED), (struct rusage *) 0); X#endif X if (pid <= 0) X break; X kill_off(pid, w); X } X} X Xkill_off(pid, w) Xregister int pid; Xunion wait w; X{ X char str[128]; X register Process *child; X X if ((child = proc_pid(pid)) == 0) X return; X X if (WIFSTOPPED(w)) X child->p_state = STOPPED; X else { X child->p_state = DEAD; X if (WIFEXITED(w)) X child->p_howdied = EXITED; X else if (WIFSIGNALED(w)) { X child->p_reason = w.w_termsig; X child->p_howdied = KILLED; X } X proc_close(child); X } X sprintf(str, "[Process %s: %s]\n", X proc_cmd(child), X pstate(child)); X proc_rec(child, str); X} X X/* Push/pod process bindings. I openly acknowledge that this is a X kludge, but I can't be bothered making it right. */ X Xstruct proc_bind { X int pb_key; X data_obj **pb_map; X data_obj *pb_push; X data_obj *pb_cmd; X struct proc_bind *pb_next; X}; X Xstruct proc_bind *PBinds = 0; X XPopPBs() X{ X register struct proc_bind *p; X X for (p = PBinds; p != 0; p = p->pb_next) X p->pb_map[p->pb_key] = p->pb_push; X} X XPushPBs() X{ X register struct proc_bind *p; X X for (p = PBinds; p != 0; p = p->pb_next) { X p->pb_push = p->pb_map[p->pb_key]; X p->pb_map[p->pb_key] = p->pb_cmd; X } X} X/* VARARGS0 */ X XProcBind() X{ X register data_obj *d; X X if ((d = findcom(ProcFmt)) == 0) X return; X s_mess(": %f %s ", d->Name); X ProcB2(mainmap, EOF, d); X} X XProcB2(map, lastkey, cmd) Xdata_obj **map, X *cmd; X{ X register struct proc_bind *p; X register data_obj **nextmap; X int c; X X c = addgetc(); X if (c == EOF) { X if (lastkey == EOF) X complain("[Empty key sequence]"); X complain("[Unexpected end-of-line]"); X } else { X if (nextmap = IsPrefix(map[c])) X ProcB2(nextmap, c, cmd); X else { X if (curbuf->b_process) X PopPBs(); X X for (p = PBinds; p != 0; p = p->pb_next) X if (p->pb_key == c && p->pb_map == map) X break; X if (p == 0) { X p = (struct proc_bind *) emalloc(sizeof *p); X p->pb_next = PBinds; X PBinds = p; X } X p->pb_map = map; X p->pb_key = c; X p->pb_cmd = cmd; X X if (curbuf->b_process) X PushPBs(); X } X } X} X X#endif IPROCS @//E*O*F iproc.c// if test 6421 -ne "`wc -c <'iproc.c'`"; then echo shar: error transmitting "'iproc.c'" '(should have been 6421 characters)' fi fi # end of overwriting check echo shar: extracting "'keymaps.txt'" '(10930 characters)' if test -f 'keymaps.txt' ; then echo shar: will not over-write existing file "'keymaps.txt'" else sed 's/^X//' >keymaps.txt <<'@//E*O*F keymaps.txt//' X/************************************************************************ X * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is * X * provided to you without charge, and with no warranty. You may give * X * away copies of JOVE, including sources, provided that this notice is * X * included in all the files. * X ************************************************************************/ X X/* Warning: You probably shouldn't put ifdefs anywhere *inside* the keymaps X definitions. It'll screw up the stuff in comments (at least), and maybe X a few other things. Yes, it *WILL* screw up the comments ... but it's X not clear that you care ... */ X X#include "jove.h" X Xkeymap mainmap = { X "set-mark", /* ^@ */ X "beginning-of-line", /* ^A */ X "backward-character", /* ^B */ X "unbound", /* ^C */ X "delete-next-character", /* ^D */ X "end-of-line", /* ^E */ X "forward-character", /* ^F */ X "unbound", /* ^G */ X "delete-previous-character", /* ^H */ X "handle-tab", /* ^I */ X "newline-and-indent", /* ^J */ X "kill-to-end-of-line", /* ^K */ X "redraw-display", /* ^L */ X "newline", /* ^M */ X "next-line", /* ^N */ X "newline-and-backup", /* ^O */ X "previous-line", /* ^P */ X "quoted-insert", /* ^Q */ X "search-reverse", /* ^R */ X "search-forward", /* ^S */ X "transpose-characters", /* ^T */ X "quadruple-numeric-argument", /* ^U */ X "next-page", /* ^V */ X "kill-region", /* ^W */ X "prefix-2", /* ^X */ X "yank", /* ^Y */ X "scroll-up", /* ^Z */ X "prefix-1", /* ^[ */ X "search-forward", /* ^\ */ X "unbound", /* ^] */ X "quoted-insert", /* ^^ */ X "unbound", /* ^_ */ X "self-insert", /* */ X "self-insert", /* ! */ X "self-insert", /* " */ X "self-insert", /* # */ X "self-insert", /* $ */ X "self-insert", /* % */ X "self-insert", /* & */ X "self-insert", /* ' */ X "self-insert", /* ( */ X "paren-flash", /* ) */ X "self-insert", /* * */ X "self-insert", /* + */ X "self-insert", /* , */ X "self-insert", /* - */ X "self-insert", /* . */ X "self-insert", /* / */ X "self-insert", /* 0 */ X "self-insert", /* 1 */ X "self-insert", /* 2 */ X "self-insert", /* 3 */ X "self-insert", /* 4 */ X "self-insert", /* 5 */ X "self-insert", /* 6 */ X "self-insert", /* 7 */ X "self-insert", /* 8 */ X "self-insert", /* 9 */ X "self-insert", /* : */ X "self-insert", /* ; */ X "self-insert", /* < */ X "self-insert", /* = */ X "self-insert", /* > */ X "self-insert", /* ? */ X "self-insert", /* @ */ X "self-insert", /* A */ X "self-insert", /* B */ X "self-insert", /* C */ X "self-insert", /* D */ X "self-insert", /* E */ X "self-insert", /* F */ X "self-insert", /* G */ X "self-insert", /* H */ X "self-insert", /* I */ X "self-insert", /* J */ X "self-insert", /* K */ X "self-insert", /* L */ X "self-insert", /* M */ X "self-insert", /* N */ X "self-insert", /* O */ X "self-insert", /* P */ X "self-insert", /* Q */ X "self-insert", /* R */ X "self-insert", /* S */ X "self-insert", /* T */ X "self-insert", /* U */ X "self-insert", /* V */ X "self-insert", /* W */ X "self-insert", /* X */ X "self-insert", /* Y */ X "self-insert", /* Z */ X "self-insert", /* [ */ X "self-insert", /* \ */ X "paren-flash", /* ] */ X "self-insert", /* ^ */ X "self-insert", /* _ */ X "self-insert", /* ` */ X "self-insert", /* a */ X "self-insert", /* b */ X "self-insert", /* c */ X "self-insert", /* d */ X "self-insert", /* e */ X "self-insert", /* f */ X "self-insert", /* g */ X "self-insert", /* h */ X "self-insert", /* i */ X "self-insert", /* j */ X "self-insert", /* k */ X "self-insert", /* l */ X "self-insert", /* m */ X "self-insert", /* n */ X "self-insert", /* o */ X "self-insert", /* p */ X "self-insert", /* q */ X "self-insert", /* r */ X "self-insert", /* s */ X "self-insert", /* t */ X "self-insert", /* u */ X "self-insert", /* v */ X "self-insert", /* w */ X "self-insert", /* x */ X "self-insert", /* y */ X "self-insert", /* z */ X "self-insert", /* { */ X "self-insert", /* | */ X "paren-flash", /* } */ X "self-insert", /* ~ */ X "delete-previous-character" /* ^? */ X}; X Xstruct data_obj *pref1map[0200] = { X "unbound", /* ^@ */ X "unbound", /* ^A */ X "backward-s-expression", /* ^B */ X "unbound", /* ^C */ X "down-list", /* ^D */ X "unbound", /* ^E */ X "forward-s-expression", /* ^F */ X "unbound", /* ^G */ X "unbound", /* ^H */ X "unbound", /* ^I */ X "unbound", /* ^J */ X "kill-s-expression", /* ^K */ X "clear-and-redraw", /* ^L */ X "unbound", /* ^M */ X "forward-list", /* ^N */ X "unbound", /* ^O */ X "backward-list", /* ^P */ X "unbound", /* ^Q */ X "unbound", /* ^R */ X "unbound", /* ^S */ X "unbound", /* ^T */ X "backward-up-list", /* ^U */ X "page-next-window", /* ^V */ X "unbound", /* ^W */ X "unbound", /* ^X */ X "unbound", /* ^Y */ X "unbound", /* ^Z */ X "unbound", /* ^[ */ X "unbound", /* ^\ */ X "unbound", /* ^] */ X "unbound", /* ^^ */ X "unbound", /* ^_ */ X "unbound", /* */ X "unbound", /* ! */ X "unbound", /* " */ X "unbound", /* # */ X "unbound", /* $ */ X "unbound", /* % */ X "unbound", /* & */ X "unbound", /* ' */ X "unbound", /* ( */ X "unbound", /* ) */ X "unbound", /* * */ X "unbound", /* + */ X "beginning-of-window", /* , */ X "digit", /* - */ X "end-of-window", /* . */ X "unbound", /* / */ X "digit", /* 0 */ X "digit", /* 1 */ X "digit", /* 2 */ X "digit", /* 3 */ X "digit", /* 4 */ X "digit", /* 5 */ X "digit", /* 6 */ X "digit", /* 7 */ X "digit", /* 8 */ X "digit", /* 9 */ X "unbound", /* : */ X "unbound", /* ; */ X "beginning-of-file", /* < */ X "unbound", /* = */ X "end-of-file", /* > */ X "describe-command", /* ? */ X "unbound", /* @ */ X "backward-sentence", /* A */ X "backward-word", /* B */ X "case-word-capitalize", /* C */ X "kill-next-word", /* D */ X "forward-sentence", /* E */ X "forward-word", /* F */ X "goto-line", /* G */ X "unbound", /* H */ X "make-macro-interactive", /* I */ X "fill-paragraph", /* J */ X "kill-to-end-of-sentence", /* K */ X "case-word-lower", /* L */ X "first-non-blank", /* M */ X "unbound", /* N */ X "unbound", /* O */ X "unbound", /* P */ X "query-replace-string", /* Q */ X "replace-string", /* R */ X "unbound", /* S */ X "unbound", /* T */ X "case-word-upper", /* U */ X "previous-page", /* V */ X "copy-region", /* W */ X "execute-named-command", /* X */ X "yank-pop", /* Y */ X "scroll-down", /* Z */ X "backward-paragraph", /* [ */ X "delete-white-space", /* \ */ X "forward-paragraph", /* ] */ X "unbound", /* ^ */ X "unbound", /* _ */ X "unbound", /* ` */ X "backward-sentence", /* a */ X "backward-word", /* b */ X "case-word-capitalize", /* c */ X "kill-next-word", /* d */ X "forward-sentence", /* e */ X "forward-word", /* f */ X "goto-line", /* g */ X "unbound", /* h */ X "make-macro-interactive", /* i */ X "fill-paragraph", /* j */ X "kill-to-end-of-sentence", /* k */ X "case-word-lower", /* l */ X "first-non-blank", /* m */ X "unbound", /* n */ X "unbound", /* o */ X "unbound", /* p */ X "query-replace-string", /* q */ X "replace-string", /* r */ X "unbound", /* s */ X "unbound", /* t */ X "case-word-upper", /* u */ X "previous-page", /* v */ X "copy-region", /* w */ X "execute-named-command", /* x */ X "yank-pop", /* y */ X "scroll-down", /* z */ X "unbound", /* { */ X "unbound", /* | */ X "unbound", /* } */ X "make-buffer-unmodified", /* ~ */ X "kill-previous-word" /* ^? */ X}; X Xkeymap pref2map = { X "unbound", /* ^@ */ X "unbound", /* ^A */ X "list-buffers", /* ^B */ X "exit-jove", /* ^C */ X "unbound", /* ^D */ X "compile-it", /* ^E */ X "find-file", /* ^F */ X "unbound", /* ^G */ X "unbound", /* ^H */ X "insert-file", /* ^I */ X "unbound", /* ^J */ X "unbound", /* ^K */ X "unbound", /* ^L */ X "write-modified-files", /* ^M */ X "next-error", /* ^N */ X "delete-blank-lines", /* ^O */ X "previous-error", /* ^P */ X "unbound", /* ^Q */ X "visit-file", /* ^R */ X "save-file", /* ^S */ X "transpose-lines", /* ^T */ X "unbound", /* ^U */ X "visit-file", /* ^V */ X "write-file", /* ^W */ X "exchange-point-and-mark", /* ^X */ X "unbound", /* ^Y */ X "unbound", /* ^Z */ X "unbound", /* ^[ */ X "save-file", /* ^\ */ X "unbound", /* ^] */ X "unbound", /* ^^ */ X "unbound", /* ^_ */ X "unbound", /* */ X "shell-command", /* ! */ X "unbound", /* " */ X "unbound", /* # */ X "unbound", /* $ */ X "unbound", /* % */ X "unbound", /* & */ X "unbound", /* ' */ X "start-remember", /* ( */ X "stop-remembering", /* ) */ X "unbound", /* * */ X "unbound", /* + */ X "unbound", /* , */ X "unbound", /* - */ X "unbound", /* . */ X "unbound", /* / */ X "unbound", /* 0 */ X "delete-other-windows", /* 1 */ X "split-current-window", /* 2 */ X "unbound", /* 3 */ X "window-find", /* 4 */ X "unbound", /* 5 */ X "unbound", /* 6 */ X "unbound", /* 7 */ X "unbound", /* 8 */ X "unbound", /* 9 */ X "unbound", /* : */ X "unbound", /* ; */ X "unbound", /* < */ X "unbound", /* = */ X "unbound", /* > */ X "describe-key", /* ? */ X "unbound", /* @ */ X "unbound", /* A */ X "select-buffer", /* B */ X "unbound", /* C */ X "delete-current-window", /* D */ X "execute-keyboard-macro", /* E */ X "unbound", /* F */ X "unbound", /* G */ X "unbound", /* H */ X "unbound", /* I */ X "unbound", /* J */ X "delete-buffer", /* K */ X "unbound", /* L */ X "unbound", /* M */ X "next-window", /* N */ X "previous-window", /* O */ X "previous-window", /* P */ X "unbound", /* Q */ X "unbound", /* R */ X "save-file", /* S */ X "find-tag", /* T */ X "unbound", /* U */ X "unbound", /* V */ X "unbound", /* W */ X "unbound", /* X */ X "unbound", /* Y */ X "unbound", /* Z */ X "unbound", /* [ */ X "unbound", /* \ */ X "unbound", /* ] */ X "grow-window", /* ^ */ X "unbound", /* _ */ X "unbound", /* ` */ X "unbound", /* a */ X "select-buffer", /* b */ X "unbound", /* c */ X "delete-current-window", /* d */ X "execute-keyboard-macro", /* e */ X "unbound", /* f */ X "unbound", /* g */ X "unbound", /* h */ X "unbound", /* i */ X "unbound", /* j */ X "delete-buffer", /* k */ X "unbound", /* l */ X "unbound", /* m */ X "next-window", /* n */ X "previous-window", /* o */ X "previous-window", /* p */ X "unbound", /* q */ X "unbound", /* r */ X "save-file", /* s */ X "find-tag", /* t */ X "unbound", /* u */ X "unbound", /* v */ X "unbound", /* w */ X "unbound", /* x */ X "unbound", /* y */ X "unbound", /* z */ X "unbound", /* { */ X "unbound", /* | */ X "unbound", /* } */ X "unbound", /* ~ */ X "kill-to-beginning-of-sentence" /* ^? */ X}; X Xkeymap miscmap = {0}; @//E*O*F keymaps.txt// if test 10930 -ne "`wc -c <'keymaps.txt'`"; then echo shar: error transmitting "'keymaps.txt'" '(should have been 10930 characters)' fi fi # end of overwriting check echo shar: extracting "'rec.c'" '(2901 characters)' if test -f 'rec.c' ; then echo shar: will not over-write existing file "'rec.c'" else sed 's/^X//' >rec.c <<'@//E*O*F rec.c//' X/************************************************************************ X * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is * X * provided to you without charge, and with no warranty. You may give * X * away copies of JOVE, including sources, provided that this notice is * X * included in all the files. * X ************************************************************************/ X X#include "jove.h" X#include "io.h" X#include "rec.h" X#include <sys/file.h> X Xprivate int rec_fd = 0; Xprivate char *recfname; Xprivate File *rec_out; X X#ifndef L_SET X# define L_SET 0 X#endif X Xprivate struct rec_head Header; X Xrecinit() X{ X char buf[128]; X X sprintf(buf, "%s/%s", TmpFilePath, p_tempfile); X recfname = copystr(buf); X recfname = mktemp(recfname); X rec_fd = creat(recfname, 0644); X if (rec_fd == -1) { X complain("Cannot create \"%s\"; recovery disabled.", recfname); X return; X } X /* Initialize the record IO. */ X rec_out = fd_open(recfname, F_WRITE|F_LOCKED, rec_fd, iobuff, LBSIZE); X X /* Initialize the record header. */ X Header.Uid = getuid(); X Header.Pid = getpid(); X Header.UpdTime = 0L; X Header.Nbuffers = 0; X (void) write(rec_fd, (char *) &Header, sizeof Header); X} X Xrecclose() X{ X if (rec_fd == -1) X return; X (void) close(rec_fd); X (void) unlink(recfname); X} X Xstatic Xputaddr(addr, p) Xdisk_line addr; Xregister File *p; X{ X register char *cp = (char *) &addr; X register int nchars = sizeof (disk_line); X X while (--nchars >= 0) X putc(*cp++ & 0377, p); X} X Xstatic Xputn(cp, nbytes) Xregister char *cp; Xregister int nbytes; X{ X while (--nbytes >= 0) X putc(*cp++ & 0377, rec_out); X} X X/* Write out the line pointers for buffer B. */ X Xstatic Xdmppntrs(b) Xregister Buffer *b; X{ X register Line *lp; X X for (lp = b->b_first; lp != 0; lp = lp->l_next) X putaddr(lp->l_dline, rec_out); X} X X/* dump the buffer info and then the actual line pointers. */ X Xstatic Xdmp_buf(b) Xregister Buffer *b; X{ X static struct rec_entry record; X register Line *lp; X register int nlines = 0; X X for (lp = b->b_first; lp != 0; lp = lp->l_next, nlines++) X ; X strcpy(record.r_fname, b->b_fname ? b->b_fname : NullStr); X strcpy(record.r_bname, b->b_name); X record.r_nlines = nlines; X putn((char *) &record, sizeof record); X dmppntrs(b); X} X X/* Goes through all the buffers and syncs them to the disk. */ X Xint SyncFreq = 50; X XSyncRec() X{ X register Buffer *b; X X if (rec_fd == 0) X recinit(); /* Init recover file. */ X if (rec_fd == -1) X return; X lseek(rec_fd, 0L, L_SET); X (void) time(&Header.UpdTime); X Header.Nbuffers = 0; X for (b = world; b != 0; b = b->b_next) X if (b->b_type == B_SCRATCH || !IsModified(b)) X continue; X else X Header.Nbuffers++; X putn((char *) &Header, sizeof Header); X if (Header.Nbuffers != 0) { X SyncTmp(); X for (b = world; b != 0; b = b->b_next) X if (b->b_type == B_SCRATCH || !IsModified(b)) X continue; X else X dmp_buf(b); X } X flush(rec_out); X} @//E*O*F rec.c// if test 2901 -ne "`wc -c <'rec.c'`"; then echo shar: error transmitting "'rec.c'" '(should have been 2901 characters)' fi fi # end of overwriting check echo shar: "End of archive 4 (of 13)." cp /dev/null ark4isdone DONE=true for I in 1 2 3 4 5 6 7 8 9 10 11 12 13; do if test -f ark${I}isdone; then echo "You have run archive ${I}." else echo "You still need to run archive ${I}." DONE=false fi done case $DONE in true) echo "You have run all 13 archives." echo 'Now read the README and Makefile.' ;; esac ## End of shell archive. exit 0