v08i026: The JOVE text editor, Part07/13
sources-request at mirror.TMC.COM
sources-request at mirror.TMC.COM
Thu Feb 5 07:32:52 AEST 1987
Submitted by: seismo!rochester!jpayne (Jonathan Payne)
Mod.sources: Volume 8, Issue 26
Archive-name: jove/Part07
#! /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 7 (of 13)."
# Contents: re.c recover.c scandir.c screen.c teachjove.c
# tune.template version.c
PATH=/bin:/usr/bin:/usr/ucb; export PATH
echo shar: extracting "'re.c'" '(17213 characters)'
if test -f 're.c' ; then
echo shar: will not over-write existing file "'re.c'"
else
sed 's/^X//' >re.c <<'@//E*O*F re.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/* search package */
X
X#include "jove.h"
X#include "ctype.h"
X
X#define NALTS 16 /* number of alternate search strings */
X
Xchar searchstr[128],
X compbuf[256], /* global default compbuf */
X rep_search[128], /* replace search string */
X rep_str[128], /* contains replacement string */
X *cur_compb, /* usually points at compbuf */
X REbuf[LBSIZE], /* points at line we're scanning */
X *alternates[NALTS];
X
Xint REdirection;
X
Xint CaseIgnore = 0,
X WrapScan = 0,
X UseRE = 0;
X
Xprivate char CaseEquiv[] = {
X '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
X '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
X '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
X '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
X '\040', '!', '"', '#', '$', '%', '&', '\'',
X '(', ')', '*', '+', ',', '-', '.', '/',
X '0', '1', '2', '3', '4', '5', '6', '7',
X '8', '9', ':', ';', '<', '=', '>', '?',
X '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
X 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
X 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
X 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
X '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
X 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
X 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
X 'X', 'Y', 'Z', '{', '|', '}', '~', '\177'
X};
X
X#define cind_cmp(a, b) (CaseEquiv[a] == CaseEquiv[b])
X
Xprivate int REpeekc;
Xprivate char *REptr;
X
Xprivate
XREgetc()
X{
X int c;
X
X if ((c = REpeekc) != -1)
X REpeekc = -1;
X else if (*REptr)
X c = *REptr++;
X else
X c = 0;
X
X return c;
X}
X
X#define STAR 01 /* Match any number of last RE. */
X#define AT_BOL 2 /* ^ */
X#define AT_EOL 4 /* $ */
X#define AT_BOW 6 /* \< */
X#define AT_EOW 8 /* \> */
X#define OPENP 10 /* \( */
X#define CLOSEP 12 /* \) */
X#define CURLYB 14 /* \{ */
X
X#define NOSTR 14 /* Codes <= NOSTR can't be *'d. */
X
X#define ANYC NOSTR+2 /* . */
X#define NORMC ANYC+2 /* normal character */
X#define CINDC NORMC+2 /* case independent character */
X#define ONE_OF CINDC+2 /* [xxx] */
X#define NONE_OF ONE_OF+2 /* [^xxx] */
X#define BACKREF NONE_OF+2 /* \# */
X#define EOP BACKREF+2 /* end of pattern */
X
X#define NPAR 9 /* [1-9] */
Xprivate int nparens;
Xprivate char *comp_p,
X **alt_p,
X **alt_endp;
X
XREcompile(pattern, re, into_buf, alt_bufp)
Xchar *pattern,
X *into_buf,
X **alt_bufp;
X{
X REptr = pattern;
X REpeekc = -1;
X comp_p = cur_compb = into_buf;
X alt_p = alt_bufp;
X alt_endp = alt_p + NALTS;
X *alt_p++ = comp_p;
X nparens = 0;
X (void) do_comp(re ? OKAY_RE : NORM);
X *alt_p = 0;
X}
X
X/* compile the pattern into an internal code */
X
Xprivate
Xdo_comp(kind)
X{
X char *last_p,
X *chr_cnt = 0;
X int parens[NPAR],
X *parenp,
X c,
X ret_code;
X
X parenp = parens;
X last_p = 0;
X ret_code = 1;
X
X while (c = REgetc()) {
X if (comp_p > &cur_compb[(sizeof compbuf) - 4])
Xtoolong: complain("Search string too long/complex.");
X if (c != '*')
X last_p = comp_p;
X
X if (kind == NORM && index(".[*", c) != 0)
X goto defchar;
X switch (c) {
X case '\\':
X switch (c = REgetc()) {
X case 0:
X complain("Premature end of pattern.");
X
X case '{':
X {
X char *wcntp; /* word count */
X
X *comp_p++ = CURLYB;
X wcntp = comp_p;
X *comp_p++ = 0;
X for (;;) {
X int comp_val;
X char *comp_len;
X
X comp_len = comp_p++;
X comp_val = do_comp(IN_CB);
X *comp_len = comp_p - comp_len;
X (*wcntp)++;
X if (comp_val == 0)
X break;
X }
X break;
X }
X
X case '}':
X if (kind != IN_CB)
X complain("Unexpected \}.");
X ret_code = 0;
X goto outahere;
X
X case '(':
X if (nparens >= NPAR)
X complain("Too many ('s; max is %d.", NPAR);
X *comp_p++ = OPENP;
X *comp_p++ = nparens;
X *parenp++ = nparens++;
X break;
X
X case ')':
X if (parenp == parens)
X complain("Too many )'s.");
X *comp_p++ = CLOSEP;
X *comp_p++ = *--parenp;
X break;
X
X case '|':
X if (alt_p >= alt_endp)
X complain("Too many alternates; max %d.", NALTS);
X *comp_p++ = EOP;
X *alt_p++ = comp_p;
X nparens = 0;
X break;
X
X case '1':
X case '2':
X case '3':
X case '4':
X case '5':
X case '6':
X case '7':
X case '8':
X case '9':
X *comp_p++ = BACKREF;
X *comp_p++ = c - '1';
X break;
X
X case '<':
X *comp_p++ = AT_BOW;
X break;
X
X case '>':
X *comp_p++ = AT_EOW;
X break;
X
X default:
X goto defchar;
X }
X break;
X
X case ',':
X if (kind != IN_CB)
X goto defchar;
X goto outahere;
X
X case '.':
X *comp_p++ = ANYC;
X break;
X
X case '^':
X if (comp_p == cur_compb || comp_p[-1] == EOP) {
X *comp_p++ = AT_BOL;
X break;
X }
X goto defchar;
X
X case '$':
X if ((REpeekc = REgetc()) != 0 && REpeekc != '\\')
X goto defchar;
X *comp_p++ = AT_EOL;
X break;
X
X case '[':
X {
X int chrcnt;
X
X *comp_p++ = ONE_OF;
X if (comp_p + 16 >= &cur_compb[(sizeof compbuf)])
X goto toolong;
X bzero(comp_p, 16);
X if ((REpeekc = REgetc()) == '^') {
X *last_p = NONE_OF;
X /* Get it for real this time. */
X (void) REgetc();
X }
X chrcnt = 1;
X while ((c = REgetc()) != ']' && c != 0) {
X if (c == '\\')
X c = REgetc();
X else if ((REpeekc = REgetc()) == '-') {
X int c2;
X
X (void) REgetc(); /* reread '-' */
X c2 = REgetc();
X while (c < c2) {
X comp_p[c/8] |= (1 << (c%8));
X c++;
X }
X }
X comp_p[c/8] |= (1 << (c%8));
X chrcnt++;
X }
X if (c == 0)
X complain("Missing ].");
X if (chrcnt == 1)
X complain("Empty [].");
X comp_p += 16;
X break;
X }
X
X case '*':
X if (last_p == 0 || *last_p <= NOSTR)
X goto defchar;
X if (chr_cnt) {
X char lastc = chr_cnt[*chr_cnt];
X
X comp_p = chr_cnt + *chr_cnt;
X (*chr_cnt)--;
X *comp_p++ = chr_cnt[-1] | STAR;
X *comp_p++ = lastc;
X } else
X *last_p |= STAR;
X break;
X
X default:
Xdefchar: if (chr_cnt)
X (*chr_cnt)++; /* increment the count */
X else {
X *comp_p++ = (CaseIgnore) ? CINDC : NORMC;
X chr_cnt = comp_p++;
X *chr_cnt = 1; /* last_p[1] = 1; */
X }
X *comp_p++ = c;
X continue;
X }
X chr_cnt = FALSE;
X }
Xoutahere:
X /* End of pattern, let's do some error checking. */
X if (parenp != parens)
X complain("Unmatched ()'s.");
X if (kind == IN_CB && c == 0) /* End of pattern with \}. */
X complain("Missing \}.");
X *comp_p++ = EOP;
X
X return ret_code;
X}
X
Xprivate char *pstrtlst[NPAR], /* index into REbuf */
X *pendlst[NPAR],
X *REbolp,
X *locs,
X *loc1,
X *loc2;
X
Xint REbom,
X REeom, /* beginning and end of match */
X REalt_num; /* if alternatives, which one matched? */
X
Xprivate
Xbackref(n, linep)
Xregister char *linep;
X{
X register char *backsp,
X *backep;
X
X backsp = pstrtlst[n];
X backep = pendlst[n];
X while (*backsp++ == *linep++)
X if (backsp >= backep)
X return 1;
X return 0;
X}
X
Xprivate
Xmember(comp_p, c, af)
Xregister char *comp_p;
Xregister int c,
X af;
X{
X if (c == 0)
X return 0; /* try to match EOL always fails */
X if (comp_p[c/8] & (1 << (c%8)))
X return af;
X return !af;
X}
X
Xprivate
XREmatch(linep, comp_p)
Xregister char *linep,
X *comp_p;
X{
X char *first_p = linep;
X register int n;
X
X for (;;) switch (*comp_p++) {
X case NORMC:
X n = *comp_p++;
X while (--n >= 0)
X if (*linep++ != *comp_p++)
X return 0;
X continue;
X
X case CINDC: /* case independent comparison */
X n = *comp_p++;
X while (--n >= 0)
X if (!cind_cmp(*linep++, *comp_p++))
X return 0;
X continue;
X
X case EOP:
X loc2 = linep;
X REeom = (loc2 - REbolp);
X return 1; /* Success! */
X
X case AT_BOL:
X if (linep == REbolp)
X continue;
X return 0;
X
X case AT_EOL:
X if (*linep == 0)
X continue;
X return 0;
X
X case ANYC:
X if (*linep++ != 0)
X continue;
X return 0;
X
X case AT_BOW:
X if (ismword(*linep) && (linep == REbolp || !ismword(linep[-1])))
X continue;
X return 0;
X
X case AT_EOW:
X if ((*linep == 0 || !ismword(*linep)) &&
X (linep != REbolp && ismword(linep[-1])))
X continue;
X return 0;
X
X case ONE_OF:
X case NONE_OF:
X if (member(comp_p, *linep++, comp_p[-1] == ONE_OF)) {
X comp_p += 16;
X continue;
X }
X return 0;
X
X case OPENP:
X pstrtlst[*comp_p++] = linep;
X continue;
X
X case CLOSEP:
X pendlst[*comp_p++] = linep;
X continue;
X
X case BACKREF:
X if (pstrtlst[n = *comp_p++] == 0) {
X s_mess("\\%d was not specified.", n + 1);
X return 0;
X }
X if (backref(n, linep)) {
X linep += pendlst[n] - pstrtlst[n];
X continue;
X }
X return 0;
X
X case CURLYB:
X {
X int wcnt,
X any;
X
X wcnt = *comp_p++;
X any = 0;
X
X while (--wcnt >= 0) {
X if (any == 0)
X any = REmatch(linep, comp_p + 1);
X comp_p += *comp_p;
X }
X if (any == 0)
X return 0;
X linep = loc2;
X continue;
X }
X
X case ANYC | STAR:
X first_p = linep;
X while (*linep++)
X ;
X goto star;
X
X case NORMC | STAR:
X first_p = linep;
X while (*comp_p == *linep++)
X ;
X comp_p++;
X goto star;
X
X case CINDC | STAR:
X first_p = linep;
X while (cind_cmp(*comp_p, *linep++))
X ;
X comp_p++;
X goto star;
X
X case ONE_OF | STAR:
X case NONE_OF | STAR:
X first_p = linep;
X while (member(comp_p, *linep++, comp_p[-1] == (ONE_OF | STAR)))
X ;
X comp_p += 16;
X goto star;
X
X case BACKREF | STAR:
X first_p = linep;
X n = *comp_p++;
X while (backref(n, linep))
X linep += pendlst[n] - pstrtlst[n];
X while (linep >= first_p) {
X if (REmatch(linep, comp_p))
X return 1;
X linep -= pendlst[n] - pstrtlst[n];
X }
X continue;
X
Xstar: do {
X linep--;
X if (linep < locs)
X break;
X if (REmatch(linep, comp_p))
X return 1;
X } while (linep > first_p);
X return 0;
X
X default:
X complain("RE error match (%d).", comp_p[-1]);
X }
X /* NOTREACHED. */
X}
X
Xprivate
XREreset()
X{
X register int i;
X
X for (i = 0; i < NPAR; i++)
X pstrtlst[i] = pendlst[i] = 0;
X}
X
X/* Index LINE at OFFSET, the compiled EXPR, with alternates ALTS. If
X lbuf_okay is nonzero it's okay to use linebuf if LINE is the current
X line. This should save lots of time in things like paren matching in
X LISP mode. Saves all that copying from linebuf to REbuf. substitute()
X is the guy who calls re_lindex with lbuf_okay as 0, since the substitution
X gets placed in linebuf ... doesn't work too well when the source and
X destination strings are the same. I hate all these arguments!
X
X This code is cumbersome, repetetive for reasons of efficiency. Fast
X search is a must as far as I am concerned. */
X
Xre_lindex(line, offset, expr, alts, lbuf_okay)
XLine *line;
Xchar *expr,
X **alts;
X{
X int isquick;
X register int firstc,
X c;
X register char *resp;
X
X REreset();
X if (lbuf_okay) {
X REbolp = lbptr(line);
X if (offset == -1)
X offset = strlen(REbolp); /* arg! */
X } else {
X REbolp = ltobuf(line, REbuf);
X if (offset == -1) { /* Reverse search, find end of line. */
X extern int Jr_Len;
X
X offset = Jr_Len; /* Just Read Len. */
X }
X }
X resp = REbolp;
X isquick = ((expr[0] == NORMC || expr[0] == CINDC) &&
X (alternates[1] == 0));
X if (isquick) {
X firstc = expr[2];
X if (expr[0] == CINDC)
X firstc = CaseEquiv[firstc];
X }
X locs = REbolp + offset;
X
X if (REdirection == FORWARD) {
X do {
X char **altp = alts;
X
X if (isquick) {
X if (expr[0] == NORMC)
X while ((c = *locs++) != 0 && c != firstc)
X ;
X else
X while (((c = *locs++) != 0) &&
X (CaseEquiv[c] != firstc))
X ;
X if (*--locs == 0)
X break;
X }
X REalt_num = 1;
X while (*altp) {
X if (REmatch(locs, *altp++)) {
X loc1 = locs;
X REbom = loc1 - REbolp;
X return 1;
X }
X REalt_num++;
X }
X } while (*locs++);
X } else {
X do {
X char **altp = alts;
X
X if (isquick) {
X if (expr[0] == NORMC) {
X while (locs >= REbolp && *locs-- != firstc)
X ;
X if (*++locs != firstc)
X break;
X } else {
X while (locs >= REbolp && CaseEquiv[*locs--] != firstc)
X ;
X if (CaseEquiv[*++locs] != firstc)
X break;
X }
X }
X REalt_num = 1;
X while (*altp) {
X if (REmatch(locs, *altp++)) {
X loc1 = locs;
X REbom = loc1 - REbolp;
X return 1;
X }
X REalt_num++;
X }
X } while (--locs >= resp);
X }
X
X return 0;
X}
X
Xint okay_wrap = 0; /* Do a wrap search ... not when we're
X parsing errors ... */
X
XBufpos *
Xdosearch(pattern, dir, re)
Xchar *pattern;
X{
X Bufpos *pos;
X
X if (bobp() && eobp()) /* Can't match! There's no buffer. */
X return 0;
X
X REcompile(pattern, re, compbuf, alternates);
X
X pos = docompiled(dir, compbuf, alternates);
X return pos;
X}
X
XBufpos *
Xdocompiled(dir, expr, alts)
Xchar *expr,
X **alts;
X{
X static Bufpos ret;
X register Line *lp;
X register int offset;
X int we_wrapped = 0;
X
X lsave();
X /* Search now lsave()'s so it doesn't make any assumptions on
X whether the the contents of curline/curchar are in linebuf.
X Nowhere does search write all over linebuf. However, we have to
X be careful about what calls we make here, because many of them
X assume (and rightly so) that curline is in linebuf. */
X
X REdirection = dir;
X lp = curline;
X offset = curchar;
X if (dir == BACKWARD) {
X if (bobp()) {
X if (okay_wrap && WrapScan)
X goto doit;
X return 0;
X }
X /* here we simulate BackChar() */
X if (bolp()) {
X lp = lp->l_prev;
X offset = strlen(lbptr(lp));
X } else
X --offset;
X } else if ((dir == FORWARD) &&
X (lbptr(lp)[offset] == '\0') &&
X !lastp(lp)) {
X lp = lp->l_next;
X offset = 0;
X }
X
X do {
X if (re_lindex(lp, offset, expr, alts, YES))
X break;
Xdoit: lp = (dir == FORWARD) ? lp->l_next : lp->l_prev;
X if (lp == 0) {
X if (okay_wrap && WrapScan) {
X lp = (dir == FORWARD) ?
X curbuf->b_first : curbuf->b_last;
X we_wrapped++;
X } else
X break;
X }
X if (dir == FORWARD)
X offset = 0;
X else
X offset = -1; /* signals re_lindex ... */
X } while (lp != curline);
X
X if (lp == curline && we_wrapped)
X lp = 0;
X if (lp == 0)
X return 0;
X ret.p_line = lp;
X ret.p_char = (dir == FORWARD) ? REeom : REbom;
X return &ret;
X}
X
Xprivate char *
Xinsert(off, endp, which)
Xchar *off,
X *endp;
X{
X register char *pp;
X register int n;
X
X n = pendlst[which] - pstrtlst[which];
X pp = pstrtlst[which];
X while (--n >= 0) {
X *off++ = *pp++;
X if (off >= endp)
X len_error(ERROR);
X }
X return off;
X}
X
X/* Perform the substitution. If DELP is nonzero the matched string is
X deleted, i.e., the substitution string is not inserted. */
X
Xre_dosub(tobuf, delp)
Xchar *tobuf;
X{
X register char *tp,
X *rp,
X *repp;
X int c;
X char *endp;
X
X tp = tobuf;
X endp = tp + LBSIZE;
X rp = REbuf;
X repp = rep_str;
X
X while (rp < loc1)
X *tp++ = *rp++;
X
X if (!delp) while (c = *repp++) {
X if (c == '\\') {
X if ((c = *repp++) == '\0') {
X *tp++ = '\\';
X goto endchk;
X } else if ((c = *repp++) >= '1' && c <= nparens + '1') {
X tp = insert(tp, endp, c - '1');
X continue;
X }
X }
X *tp++ = c;
Xendchk: if (tp >= endp)
X len_error(ERROR);
X }
X rp = loc2;
X loc2 = REbuf + max(1, tp - tobuf);
X REeom = loc2 - REbuf;
X /* At least one character past the match, to prevent an infinite
X number of replacements in the same position, e.g.,
X replace "^" with "". */
X while (*tp++ = *rp++)
X if (tp >= endp)
X len_error(ERROR);
X}
X
Xputmatch(which, buf, size)
Xchar *buf;
X{
X *(insert(buf, buf + size, which - 1)) = 0;
X}
X
Xsetsearch(str)
Xchar *str;
X{
X strcpy(searchstr, str);
X}
X
Xchar *
Xgetsearch()
X{
X return searchstr;
X}
X
XRErecur()
X{
X char sbuf[sizeof searchstr],
X cbuf[sizeof compbuf],
X repbuf[sizeof rep_str],
X *altbuf[NALTS];
X int npars;
X Mark *m = MakeMark(curline, REbom, FLOATER);
X
X message("Type C-X C-C to continue with query replace.");
X
X npars = nparens;
X byte_copy(compbuf, cbuf, sizeof compbuf);
X byte_copy(searchstr, sbuf, sizeof searchstr);
X byte_copy(rep_str, repbuf, sizeof rep_str);
X byte_copy((char *) alternates, (char *) altbuf, sizeof alternates);
X Recur();
X nparens = npars;
X byte_copy(cbuf, compbuf, sizeof compbuf);
X byte_copy(sbuf, searchstr, sizeof searchstr);
X byte_copy(repbuf, rep_str, sizeof rep_str);
X byte_copy((char *) altbuf, (char *) alternates, sizeof alternates);
X if (!exp_p)
X ToMark(m);
X DelMark(m);
X}
X
XForSearch()
X{
X search(FORWARD, UseRE, YES);
X}
X
XRevSearch()
X{
X search(BACKWARD, UseRE, YES);
X}
X
XFSrchND()
X{
X search(FORWARD, UseRE, NO);
X}
X
XRSrchND()
X{
X search(BACKWARD, UseRE, NO);
X}
X
Xprivate
Xsearch(dir, re, setdefault)
X{
X Bufpos *newdot;
X char *s;
X
X s = ask(searchstr, ProcFmt);
X if (setdefault)
X setsearch(s);
X okay_wrap = YES;
X newdot = dosearch(s, dir, re);
X okay_wrap = NO;
X if (newdot == 0) {
X if (WrapScan)
X complain("No \"%s\" in buffer.", s);
X else
X complain("No \"%s\" found to %s.", s,
X (dir == FORWARD) ? "bottom" : "top");
X }
X PushPntp(newdot->p_line);
X SetDot(newdot);
X}
X
X/* Do we match PATTERN at OFFSET in BUF? */
X
XLookingAt(pattern, buf, offset)
Xchar *pattern,
X *buf;
X{
X register char **alt = alternates;
X
X REcompile(pattern, 1, compbuf, alternates);
X REreset();
X locs = buf + offset;
X REbolp = buf;
X
X while (*alt)
X if (REmatch(locs, *alt++))
X return 1;
X return 0;
X}
X
Xlook_at(expr)
Xchar *expr;
X{
X REcompile(expr, 0, compbuf, alternates);
X REreset();
X locs = linebuf + curchar;
X REbolp = linebuf;
X if (REmatch(locs, alternates[0]))
X return 1;
X return 0;
X}
X
@//E*O*F re.c//
if test 17213 -ne "`wc -c <'re.c'`"; then
echo shar: error transmitting "'re.c'" '(should have been 17213 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'recover.c'" '(14068 characters)'
if test -f 'recover.c' ; then
echo shar: will not over-write existing file "'recover.c'"
else
sed 's/^X//' >recover.c <<'@//E*O*F recover.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/* Recovers JOVE files after a system/editor crash.
X Usage: recover [-d directory] [-syscrash]
X The -syscrash option is specified in /etc/rc and what it does it
X move all the jove tmp files from TMP_DIR to REC_DIR.
X
X The -d option lets you specify the directory to search for tmp files when
X the default isn't the right one.
X
X Look in Makefile to change the default directories. */
X
X#include <stdio.h> /* Do stdio first so it doesn't override OUR
X definitions. */
X#undef EOF
X#undef BUFSIZ
X#undef putchar
X
X#include "jove.h"
X#include "temp.h"
X#include "rec.h"
X#include <signal.h>
X#include <sys/file.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X
X#ifndef L_SET
X# define L_SET 0
X# define L_INCR 1
X#endif
X
Xchar blk_buf[BUFSIZ];
Xint nleft;
XFILE *ptrs_fp;
Xint data_fd;
Xstruct rec_head Header;
Xchar datafile[40],
X pntrfile[40];
Xlong Nchars,
X Nlines;
Xchar tty[] = "/dev/tty";
Xint UserID,
X Verbose = 0;
Xchar *Directory = 0; /* the directory we're looking in */
X
Xstruct file_pair {
X char *file_data,
X *file_rec;
X#define INSPECTED 01
X int file_flags;
X struct file_pair *file_next;
X} *First = 0,
X *Last = 0;
X
Xstruct rec_entry *buflist[100] = {0};
X
X#ifndef BSD4_2
X
Xtypedef struct {
X int d_fd; /* File descriptor for this directory */
X} DIR;
X
XDIR *
Xopendir(dir)
Xchar *dir;
X{
X DIR *dp = (DIR *) malloc(sizeof *dp);
X
X if ((dp->d_fd = open(dir, 0)) == -1)
X return NULL;
X return dp;
X}
X
Xclosedir(dp)
XDIR *dp;
X{
X (void) close(dp->d_fd);
X free(dp);
X}
X
Xstruct direct *
Xreaddir(dp)
XDIR *dp;
X{
X static struct direct dir;
X
X do
X if (read(dp->d_fd, &dir, sizeof dir) != sizeof dir)
X return NULL;
X while (dir.d_ino == 0);
X
X return &dir;
X}
X
X#endif BSD4_2
X
X/* Get a line at `tl' in the tmp file into `buf' which should be LBSIZE
X long. */
X
Xgetline(tl, buf)
Xdisk_line tl;
Xchar *buf;
X{
X register char *bp,
X *lp;
X register int nl;
X char *getblock();
X
X lp = buf;
X bp = getblock(tl >> 1);
X nl = nleft;
X tl = blk_round(tl);
X
X while (*lp++ = *bp++) {
X if (--nl == 0) {
X tl = forward_block(tl);
X bp = getblock(tl >> 1);
X nl = nleft;
X }
X }
X}
X
Xchar *
Xgetblock(atl)
Xdisk_line atl;
X{
X int bno,
X off;
X static int curblock = -1;
X
X bno = daddr_to_bno(atl);
X off = daddr_to_off(atl);
X nleft = BUFSIZ - off;
X
X if (bno != curblock) {
X lseek(data_fd, (long) bno * BUFSIZ, L_SET);
X read(data_fd, blk_buf, BUFSIZ);
X curblock = bno;
X }
X return blk_buf + off;
X}
X
Xchar *
Xcopystr(s)
Xchar *s;
X{
X char *str;
X
X str = malloc(strlen(s) + 1);
X strcpy(str, s);
X
X return str;
X}
X
X/* Scandir returns the number of entries or -1 if the directory cannoot
X be opened or malloc fails. */
X
Xscandir(dir, nmptr, qualify, sorter)
Xchar *dir;
Xstruct direct ***nmptr;
Xint (*qualify)();
Xstruct direct *(*sorter)();
X{
X DIR *dirp;
X struct direct *entry,
X **ourarray;
X int nalloc = 10,
X nentries = 0;
X
X if ((dirp = opendir(dir)) == NULL)
X return -1;
X ourarray = (struct direct **) malloc(nalloc * sizeof (struct direct *));
X while ((entry = readdir(dirp)) != NULL) {
X if (qualify != 0 && (*qualify)(entry) == 0)
X continue;
X if (nentries == nalloc) {
X ourarray = (struct direct **) realloc(ourarray, (nalloc += 10) * sizeof (struct direct));
X if (ourarray == NULL)
X return -1;
X }
X ourarray[nentries] = (struct direct *) malloc(sizeof *entry);
X *ourarray[nentries] = *entry;
X nentries++;
X }
X closedir(dirp);
X if (nentries != nalloc)
X ourarray = (struct direct **) realloc(ourarray,
X (nentries * sizeof (struct direct)));
X if (sorter != 0)
X qsort(ourarray, nentries, sizeof (struct direct **), sorter);
X *nmptr = ourarray;
X
X return nentries;
X}
X
Xalphacomp(a, b)
Xstruct direct **a,
X **b;
X{
X return strcmp((*a)->d_name, (*b)->d_name);
X}
X
Xchar *CurDir;
X
X/* Scan the DIRNAME directory for jove tmp files, and make a linked list
X out of them. */
X
Xget_files(dirname)
Xchar *dirname;
X{
X int add_name();
X struct direct **nmptr;
X
X CurDir = dirname;
X scandir(dirname, &nmptr, add_name, (int (*)())0);
X}
X
Xadd_name(dp)
Xstruct direct *dp;
X{
X char dfile[128],
X rfile[128];
X struct file_pair *fp;
X struct rec_head header;
X int fd;
X
X if (strncmp(dp->d_name, "jrec", 4) != 0)
X return 0;
X /* If we get here, we found a "recover" tmp file, so now
X we look for the corresponding "data" tmp file. First,
X though, we check to see whether there is anything in
X the "recover" file. If it's 0 length, there's no point
X in saving its name. */
X (void) sprintf(rfile, "%s/%s", CurDir, dp->d_name);
X (void) sprintf(dfile, "%s/jove%s", CurDir, dp->d_name + 4);
X if ((fd = open(rfile, 0)) != -1) {
X if ((read(fd, (char *) &header, sizeof header) != sizeof header)) {
X close(fd);
X return 0;
X } else
X close(fd);
X }
X if (access(dfile, 0) != 0) {
X fprintf(stderr, "recover: can't find the data file for %s/%s\n", Directory, dp->d_name);
X fprintf(stderr, "so deleting...\n");
X (void) unlink(rfile);
X (void) unlink(dfile);
X return 0;
X }
X /* If we get here, we've found both files, so we put them
X in the list. */
X fp = (struct file_pair *) malloc (sizeof *fp);
X if ((char *) fp == 0) {
X fprintf(stderr, "recover: cannot malloc for file_pair.\n");
X exit(-1);
X }
X fp->file_data = copystr(dfile);
X fp->file_rec = copystr(rfile);
X fp->file_flags = 0;
X fp->file_next = First;
X First = fp;
X
X return 1;
X}
X
Xoptions()
X{
X printf("Options are:\n");
X printf(" ? list options.\n");
X printf(" get get a buffer to a file.\n");
X printf(" list list known buffers.\n");
X printf(" print print a buffer to terminal.\n");
X printf(" quit quit and delete jove tmp files.\n");
X printf(" restore restore all buffers.\n");
X}
X
X/* Returns a legitimate buffer # */
X
Xstruct rec_entry **
Xgetsrc()
X{
X char name[128];
X int number;
X
X for (;;) {
X tellme("Which buffer ('?' for list)? ", name);
X if (name[0] == '?')
X list();
X else if (name[0] == '\0')
X return 0;
X else if ((number = atoi(name)) > 0 && number <= Header.Nbuffers)
X return &buflist[number];
X else {
X int i;
X
X for (i = 1; i <= Header.Nbuffers; i++)
X if (strcmp(buflist[i]->r_bname, name) == 0)
X return &buflist[i];
X printf("%s: unknown buffer.\n", name);
X }
X }
X}
X
X/* Get a destination file name. */
X
Xstatic char *
Xgetdest()
X{
X static char filebuf[256];
X
X tellme("Output file: ", filebuf);
X if (filebuf[0] == '\0')
X return 0;
X return filebuf;
X}
X
X#include "ctype.h"
X
Xchar *
Xreadword(buf)
Xchar *buf;
X{
X int c;
X char *bp = buf;
X
X while (index(" \t\n", c = getchar()))
X ;
X
X do {
X if (index(" \t\n", c))
X break;
X *bp++ = c;
X } while ((c = getchar()) != EOF);
X *bp = 0;
X
X return buf;
X}
X
Xtellme(quest, answer)
Xchar *quest,
X *answer;
X{
X if (stdin->_cnt <= 0) {
X printf("%s", quest);
X fflush(stdout);
X }
X readword(answer);
X}
X
X/* Print the specified file to strandard output. */
X
Xjmp_buf int_env;
X
Xcatch()
X{
X longjmp(int_env, 1);
X}
X
Xrestore()
X{
X register int i;
X char tofile[100],
X answer[30];
X int nrecovered = 0;
X
X for (i = 1; i <= Header.Nbuffers; i++) {
X (void) sprintf(tofile, "#%s", buflist[i]->r_bname);
Xtryagain:
X printf("Restoring %s to %s, okay?", buflist[i]->r_bname,
X tofile);
X tellme(" ", answer);
X switch (answer[0]) {
X case 'y':
X break;
X
X case 'n':
X continue;
X
X default:
X tellme("What file should I use instead? ", tofile);
X goto tryagain;
X }
X get(&buflist[i], tofile);
X nrecovered++;
X }
X printf("Recovered %d buffers.\n", nrecovered);
X}
X
Xget(src, dest)
Xstruct rec_entry **src;
Xchar *dest;
X{
X FILE *outfile;
X
X if (src == 0 || dest == 0)
X return;
X (void) signal(SIGINT, catch);
X if (setjmp(int_env) == 0) {
X if ((outfile = fopen(dest, "w")) == NULL) {
X printf("recover: cannot create %s.\n", dest);
X return;
X }
X seekto(src - buflist);
X if (dest != tty)
X printf("\"%s\"", dest);
X dump_file(outfile);
X } else
X printf("\nAborted!\n");
X fclose(outfile);
X if (dest != tty)
X printf(" %ld lines, %ld characters.\n", Nlines, Nchars);
X (void) signal(SIGINT, SIG_DFL);
X}
X
Xchar **
Xscanvec(args, str)
Xregister char **args,
X *str;
X{
X while (*args) {
X if (strcmp(*args, str) == 0)
X return args;
X args++;
X }
X return 0;
X}
X
Xread_rec(recptr)
Xstruct rec_entry *recptr;
X{
X if (fread((char *) recptr, sizeof *recptr, 1, ptrs_fp) != 1)
X fprintf(stderr, "recover: cannot read record.\n");
X}
X
Xseekto(which)
X{
X struct rec_entry rec;
X
X fseek(ptrs_fp, (long) (sizeof Header), L_SET);
X
X while (which-- > 1) {
X read_rec(&rec);
X if (fseek(ptrs_fp, (long) rec.r_nlines * sizeof (disk_line),
X L_INCR) == -1)
X printf("recover: improper fseek!\n");
X }
X}
X
Xmakblist()
X{
X int i;
X
X for (i = 1; i <= Header.Nbuffers; i++) {
X seekto(i);
X if (buflist[i] == 0)
X buflist[i] = (struct rec_entry *) malloc (sizeof (struct rec_entry));
X read_rec(buflist[i]);
X }
X if (buflist[i]) {
X free((char *) buflist[i]);
X buflist[i] = 0;
X }
X}
X
Xdisk_line
Xgetaddr(fp)
Xregister FILE *fp;
X{
X register int nchars = sizeof (disk_line);
X disk_line addr;
X register char *cp = (char *) &addr;
X
X while (--nchars >= 0)
X *cp++ = getc(fp);
X
X return addr;
X}
X
Xdump_file(out)
XFILE *out;
X{
X struct rec_entry record;
X register int nlines;
X register disk_line daddr;
X char buf[BUFSIZ];
X
X read_rec(&record);
X nlines = record.r_nlines;
X Nchars = Nlines = 0L;
X while (--nlines >= 0) {
X daddr = getaddr(ptrs_fp);
X getline(daddr, buf);
X Nlines++;
X Nchars += 1 + strlen(buf);
X fputs(buf, out);
X if (nlines > 0)
X fputc('\n', out);
X }
X if (out != stdout)
X fclose(out);
X}
X
X/* List all the buffers. */
X
Xlist()
X{
X int i;
X
X for (i = 1; i <= Header.Nbuffers; i++)
X printf("%d) buffer %s \"%s\" (%d lines)\n", i,
X buflist[i]->r_bname,
X buflist[i]->r_fname,
X buflist[i]->r_nlines);
X}
X
Xdoit(fp)
Xstruct file_pair *fp;
X{
X char answer[30];
X char *datafile = fp->file_data,
X *pntrfile = fp->file_rec;
X
X ptrs_fp = fopen(pntrfile, "r");
X if (ptrs_fp == NULL) {
X if (Verbose)
X fprintf(stderr, "recover: cannot read rec file (%s).\n", pntrfile);
X return 0;
X }
X fread((char *) &Header, sizeof Header, 1, ptrs_fp);
X if (Header.Uid != UserID)
X return 0;
X
X /* Don't ask about JOVE's that are still running ... */
X#ifdef KILL0
X if (kill(Header.Pid, 0) == 0)
X return 0;
X#else
X#ifdef LSRHS
X if (pexist(Header.Pid))
X return 0;
X#endif LSRHS
X#endif KILL0
X
X if (Header.Nbuffers == 0) {
X printf("There are no modified buffers in %s; should I delete the tmp file?", pntrfile);
X ask_del(" ", fp);
X return 1;
X }
X
X if (Header.Nbuffers < 0) {
X fprintf(stderr, "recover: %s doesn't look like a jove file.\n", pntrfile);
X ask_del("Should I delete it? ", fp);
X return 1; /* We'll, we sort of found something. */
X }
X printf("Found %d buffer%s last updated: %s",
X Header.Nbuffers,
X Header.Nbuffers != 1 ? "s" : "",
X ctime(&Header.UpdTime));
X data_fd = open(datafile, 0);
X if (data_fd == -1) {
X fprintf(stderr, "recover: but I can't read the data file (%s).\n", datafile);
X ask_del("Should I delete the tmp files? ", fp);
X return 1;
X }
X makblist();
X
X for (;;) {
X tellme("(Type '?' for options): ", answer);
X switch (answer[0]) {
X case '\0':
X continue;
X
X case '?':
X options();
X break;
X
X case 'l':
X list();
X break;
X
X case 'p':
X get(getsrc(), tty);
X break;
X
X case 'q':
X ask_del("Shall I delete the tmp files? ", fp);
X return 1;
X
X case 'g':
X { /* So it asks for src first. */
X char *dest;
X struct rec_entry **src;
X
X if ((src = getsrc()) == 0)
X break;
X dest = getdest();
X get(src, dest);
X break;
X }
X
X case 'r':
X restore();
X break;
X
X default:
X printf("I don't know how to \"%s\"!\n", answer);
X break;
X }
X }
X}
X
Xask_del(prompt, fp)
Xchar *prompt;
Xstruct file_pair *fp;
X{
X char yorn[20];
X
X tellme(prompt, yorn);
X if (yorn[0] == 'y')
X del_files(fp);
X}
X
Xdel_files(fp)
Xstruct file_pair *fp;
X{
X (void) unlink(fp->file_data);
X (void) unlink(fp->file_rec);
X}
X
X#ifdef notdef
Xsavetmps()
X{
X struct file_pair *fp;
X int status,
X pid;
X
X if (strcmp(TMP_DIR, REC_DIR) == 0)
X return; /* Files are moved to the same place. */
X get_files(TMP_DIR);
X for (fp = First; fp != 0; fp = fp->file_next) {
X switch (pid = fork()) {
X case -1:
X fprintf(stderr, "recover: can't fork\n!");
X exit(-1);
X
X case 0:
X execl("/bin/cp", "cp", fp->file_data, fp->file_rec,
X REC_DIR, (char *)0);
X fprintf(stderr, "recover: cannot execl /bin/cp.\n");
X exit(-1);
X
X default:
X while (wait(&status) != pid)
X ;
X if (status != 0)
X fprintf(stderr, "recover: non-zero status (%d) returned from copy.\n", status);
X }
X }
X}
X#endif
X
Xlookup(dir)
Xchar *dir;
X{
X struct file_pair *fp;
X struct rec_head header;
X char yorn[20];
X int nfound = 0,
X this_one;
X
X printf("Checking %s ...\n", dir);
X Directory = dir;
X get_files(dir);
X for (fp = First; fp != 0; fp = fp->file_next) {
X nfound += doit(fp);
X if (ptrs_fp)
X (void) fclose(ptrs_fp);
X if (data_fd > 0)
X (void) close(data_fd);
X }
X return nfound;
X}
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X int nfound;
X char **argvp;
X
X UserID = getuid();
X
X if (scanvec(argv, "-help")) {
X printf("recover: usage: recover [-d directory]\n");
X printf("Use \"recover\" after JOVE has died for some\n");
X printf("unknown reason.\n\n");
X printf("Use \"recover -syscrash\" when the system is in the process\n");
X printf("of rebooting. This is done automatically at reboot time\n");
X printf("and so most of you don't have to worry about that.\n\n");
X printf("Use \"recover -d directory\" when the tmp files are store\n");
X printf("in DIRECTORY instead of the default one (/tmp).\n");
X exit(0);
X }
X if (scanvec(argv, "-v"))
X Verbose++;
X/* if (scanvec(argv, "-syscrash")) {
X printf("Recovering jove files ... ");
X savetmps();
X printf("Done.\n");
X exit(0);
X } */
X if (argvp = scanvec(argv, "-uid"))
X UserID = atoi(argvp[1]);
X if (argvp = scanvec(argv, "-d"))
X nfound = lookup(argvp[1]);
X else
X nfound = lookup(TmpFilePath);
X if (nfound == 0)
X printf("There's nothing to recover.\n");
X}
@//E*O*F recover.c//
if test 14068 -ne "`wc -c <'recover.c'`"; then
echo shar: error transmitting "'recover.c'" '(should have been 14068 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'scandir.c'" '(2708 characters)'
if test -f 'scandir.c' ; then
echo shar: will not over-write existing file "'scandir.c'"
else
sed 's/^X//' >scandir.c <<'@//E*O*F scandir.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 <sys/stat.h>
X#include <sys/dir.h>
X
X#ifdef F_COMPLETION
X
X#ifdef BSD4_2
X
X#define DIRSIZE(entry) DIRSIZ(entry)
X
X#else
X
X#define DIRSIZE(entry) (min(strlen(entry->d_name), DIRSIZ))
X
Xtypedef struct {
X int d_fd; /* File descriptor for this directory */
X} DIR;
X
XDIR *
Xopendir(dir)
Xchar *dir;
X{
X DIR *dp = (DIR *) malloc(sizeof *dp);
X struct stat stbuf;
X
X if ((dp->d_fd = open(dir, 0)) == -1)
X return 0;
X if ((fstat(dp->d_fd, &stbuf) == -1) || !(stbuf.st_mode & S_IFDIR)) {
X closedir(dp);
X return 0; /* this isn't a directory! */
X }
X return dp;
X}
X
Xclosedir(dp)
XDIR *dp;
X{
X (void) close(dp->d_fd);
X free((char *) dp);
X}
X
Xstruct direct *
Xreaddir(dp)
XDIR *dp;
X{
X static struct direct dir;
X
X do
X if (read(dp->d_fd, &dir, sizeof dir) != sizeof dir)
X return 0;
X while (dir.d_ino == 0);
X
X return &dir;
X}
X
X#endif BSD4_2
X
X/* Scandir returns the number of entries or -1 if the directory cannoot
X be opened or malloc fails. */
X
Xscandir(dir, nmptr, qualify, sorter)
Xchar *dir;
Xchar ***nmptr;
Xint (*qualify)();
Xint (*sorter)();
X{
X DIR *dirp;
X struct direct *entry;
X char **ourarray;
X unsigned int nalloc = 10,
X nentries = 0;
X
X if ((dirp = opendir(dir)) == 0)
X return -1;
X if ((ourarray = (char **) malloc(nalloc * sizeof (char *))) == 0)
Xmemfail: complain("[Malloc failed: cannot scandir]");
X while ((entry = readdir(dirp)) != 0) {
X if (qualify != 0 && (*qualify)(entry->d_name) == 0)
X continue;
X if (nentries == nalloc) {
X ourarray = (char **) realloc((char *) ourarray, (nalloc += 10) * sizeof (char *));
X if (ourarray == 0)
X goto memfail;
X }
X ourarray[nentries] = (char *) malloc(DIRSIZE(entry) + 1);
X null_ncpy(ourarray[nentries], entry->d_name, (int) DIRSIZE(entry));
X nentries++;
X }
X closedir(dirp);
X if ((nentries + 1) != nalloc)
X ourarray = (char **) realloc((char *) ourarray,
X ((nentries + 1) * sizeof (char *)));
X if (sorter != 0)
X qsort((char *) ourarray, nentries, sizeof (char **), sorter);
X *nmptr = ourarray;
X ourarray[nentries] = 0; /* guaranteed 0 pointer */
X
X return nentries;
X}
X
Xfreedir(nmptr, nentries)
Xchar ***nmptr;
X{
X char **ourarray = *nmptr;
X
X while (--nentries >= 0)
X free(*ourarray++);
X free((char *) *nmptr);
X *nmptr = 0;
X}
X
Xalphacomp(a, b)
Xchar **a,
X **b;
X{
X return strcmp(*a, *b);
X}
X
X#endif
@//E*O*F scandir.c//
if test 2708 -ne "`wc -c <'scandir.c'`"; then
echo shar: error transmitting "'scandir.c'" '(should have been 2708 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'screen.c'" '(17553 characters)'
if test -f 'screen.c' ; then
echo shar: will not over-write existing file "'screen.c'"
else
sed 's/^X//' >screen.c <<'@//E*O*F screen.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 "ctype.h"
X#include "termcap.h"
X
Xextern int BufSize;
X
Xint OkayAbort,
X tabstop = 8;
X
Xint (*TTins_line)(),
X (*TTdel_line)();
X
Xstruct scrimage
X *DesiredScreen = 0,
X *PhysScreen = 0;
X
Xstruct screenline *Screen = 0, /* the screen (a bunch of screenline) */
X *Savelines = 0, /* another bunch (LI of them) */
X *Curline = 0; /* current line */
Xchar *cursor, /* offset into current Line */
X *cursend;
X
Xint CapCol,
X CapLine,
X
X i_line,
X i_col;
X
Xmake_scr()
X{
X register int i;
X register struct screenline *ns;
X register char *nsp;
X
X#ifdef RESHAPING
X /* In case we are RESHAPING the window! */
X if (DesiredScreen)
X free((char *) DesiredScreen);
X if (PhysScreen)
X free((char *) PhysScreen);
X if (Savelines)
X free((char *) Savelines);
X if (Screen) {
X free(Screen->s_line); /* free all the screen data */
X free((char *) Screen);
X }
X#endif RESHAPING
X
X DesiredScreen = (struct scrimage *) malloc((unsigned) LI * sizeof (struct scrimage));
X PhysScreen = (struct scrimage *) malloc((unsigned) LI * sizeof (struct scrimage));
X
X Savelines = (struct screenline *)
X malloc((unsigned) LI * sizeof(struct screenline));
X ns = Screen = (struct screenline *)
X malloc((unsigned) LI * sizeof(struct screenline));
X
X nsp = (char *) malloc((unsigned)CO * LI);
X if (nsp == 0) {
X printf("\n\rCannot malloc screen!\n");
X finish(1);
X }
X
X for (i = 0; i < LI; i++) {
X ns->s_line = nsp;
X nsp += CO;
X ns->s_length = nsp - 1; /* End of Line */
X ns++;
X }
X cl_scr(0);
X}
X
Xclrline(cp1, cp2)
Xregister char *cp1,
X *cp2;
X{
X while (cp1 <= cp2)
X *cp1++ = ' ';
X}
X
X#define sputc(c) ((*cursor != (char) (c)) ? dosputc(c) : (cursor++, i_col++))
X#define soutputc(c) if (--n <= 0) break; else sputc(c)
X
Xcl_eol()
X{
X if (cursor > cursend)
X return;
X
X if (cursor < Curline->s_length) {
X if (CE) {
X Placur(i_line, i_col);
X putpad(CE, 1);
X clrline(cursor, Curline->s_length);
X } else {
X /* Ugh. The slow way for dumb terminals. */
X register char *savecp = cursor;
X
X while (cursor <= Curline->s_length)
X sputc(' ');
X cursor = savecp;
X }
X Curline->s_length = cursor;
X }
X}
X
Xcl_scr(doit)
X{
X register int i;
X register struct screenline *sp = Screen;
X
X for (i = 0; i < LI; i++, sp++) {
X clrline(sp->s_line, sp->s_length);
X sp->s_length = sp->s_line;
X PhysScreen[i].s_id = 0;
X }
X if (doit) {
X putpad(CL, LI);
X CapCol = CapLine = 0;
X UpdMesg++;
X }
X}
X
X#ifdef ID_CHAR
Xextern int IN_INSmode;
X#endif
X
X/* Output one character (if necessary) at the current position */
X
Xdosputc(c)
Xregister char c;
X{
X if (*cursor != c) {
X#ifdef ID_CHAR
X if (IN_INSmode)
X INSmode(0);
X#endif
X if (i_line != CapLine || i_col != CapCol)
X Placur(i_line, i_col);
X if (UL && (c & 0177) == '_' && (*cursor & 0177) != ' ')
X putstr(" \b"); /* Erase so '_' looks right. */
X *cursor++ = c;
X putchar(c & 0177);
X CapCol++;
X i_col++;
X } else {
X cursor++;
X i_col++;
X }
X}
X
X/* Write `line' at the current position of `cursor'. Stop when we
X reach the end of the screen. Aborts if there is a character
X waiting. */
X
Xswrite(line, inversep, abortable)
Xregister char *line;
Xregister int abortable;
X{
X register int c;
X int col = i_col,
X aborted = 0;
X register int n = cursend - cursor;
X int or_byte = inversep ? 0200 : 0,
X thebyte;
X
X if (n <= 0)
X return 1;
X
X OkayAbort = 0;
X while (c = *line++) {
X if (abortable && OkayAbort) {
X OkayAbort = NO;
X if (InputPending = charp()) {
X aborted = 1;
X break;
X }
X }
X if (c == '\t') {
X int nchars;
X
X nchars = (tabstop - (col % tabstop));
X col += nchars;
X
X thebyte = (' ' | or_byte);
X while (nchars--)
X soutputc(thebyte);
X if (n <= 0)
X break;
X } else if (isctrl(c)) {
X thebyte = ('^' | or_byte);
X soutputc(thebyte);
X thebyte = (((c == '\177') ? '?' : c + '@') | or_byte);
X soutputc(thebyte);
X col += 2;
X } else {
X thebyte = (c | or_byte);
X soutputc(thebyte);
X col++;
X }
X }
X if (n <= 0) {
X if ((*line == '\0') && (c != '\t') && !isctrl(c))
X sputc(c|or_byte);
X else
X sputc('!'|or_byte);
X }
X if (cursor > Curline->s_length)
X Curline->s_length = cursor;
X return !aborted;
X}
X
X/* This is for writing a buffer line to the screen. This is to
X minimize the amount of copying from one buffer to another buffer.
X This gets the info directly from the disk buffers. */
X
XBufSwrite(linenum)
X{
X char *bp;
X register int n = cursend - cursor,
X col = 0,
X c;
X int StartCol = DesiredScreen[linenum].s_offset,
X visspace = DesiredScreen[linenum].s_window->w_flags & W_VISSPACE,
X aborted = 0;
X
X bp = lcontents(DesiredScreen[linenum].s_lp);
X if (*bp) for (;;) {
X if (col >= StartCol) {
X DesiredScreen[linenum].s_offset = col;
X break;
X }
X
X c = *bp++ & 0177;
X if (c == '\t')
X col += (tabstop - (col % tabstop));
X else if (isctrl(c))
X col += 2;
X else
X col++;
X }
X
X OkayAbort = 0;
X while (c = (*bp++ & 0177)) {
X if (OkayAbort) {
X OkayAbort = NO;
X if (InputPending = charp()) {
X aborted = 1;
X break;
X }
X }
X if (c == '\t') {
X int nchars = (tabstop - (col % tabstop));
X
X col += nchars;
X if (visspace) {
X soutputc('>');
X nchars--;
X }
X while (--nchars >= 0)
X soutputc(' ');
X if (n <= 0)
X break;
X } else if (isctrl(c)) {
X soutputc('^');
X soutputc((c == '\177') ? '?' : c + '@');
X col += 2;
X } else {
X if (c == ' ' && visspace)
X c = '_';
X soutputc(c);
X col++;
X }
X }
X if (n <= 0) {
X if ((*bp == '\0') && (c != '\t') && !isctrl(c))
X sputc(c);
X else
X sputc('!');
X }
X if (cursor > Curline->s_length)
X Curline->s_length = cursor;
X return !aborted; /* Didn't abort */
X}
X
Xi_set(nline, ncol)
Xregister int nline,
X ncol;
X{
X Curline = &Screen[nline];
X cursor = Curline->s_line + ncol;
X cursend = &Curline->s_line[CO - 1];
X i_line = nline;
X i_col = ncol;
X}
X
X/* Insert `num' lines a top, but leave all the lines BELOW `bottom'
X alone (at least they won't look any different when we are done).
X This changes the screen array AND does the physical changes. */
X
Xv_ins_line(num, top, bottom)
X{
X register int i;
X
X /* Save the screen pointers. */
X
X for(i = 0; i < num && top + i <= bottom; i++)
X Savelines[i] = Screen[bottom - i];
X
X /* Num number of bottom lines will be lost.
X Copy everything down num number of times. */
X
X for (i = bottom; i > top && i-num >= 0; i--)
X Screen[i] = Screen[i - num];
X
X /* Restore the saved ones, making them blank. */
X
X for (i = 0; i < num; i++) {
X Screen[top + i] = Savelines[i];
X clrline(Screen[top + i].s_line, Screen[top + i].s_length);
X Screen[top + i].s_length = Screen[top + i].s_line;
X }
X
X (*TTins_line)(top, bottom, num);
X}
X
X/* Delete `num' lines starting at `top' leaving the lines below `bottom'
X alone. This updates the internal image as well as the physical image. */
X
Xv_del_line(num, top, bottom)
X{
X register int i,
X bot;
X
X bot = bottom;
X
X /* Save the lost lines. */
X
X for (i = 0; i < num && top + i <= bottom; i++)
X Savelines[i] = Screen[top + i];
X
X /* Copy everything up num number of lines. */
X
X for (i = top; num + i <= bottom; i++)
X Screen[i] = Screen[i + num];
X
X /* Restore the lost ones, clearing them. */
X
X for (i = 0; i < num; i++) {
X Screen[bottom - i] = Savelines[i];
X clrline(Screen[bot].s_line, Screen[bot].s_length);
X Screen[bot].s_length = Screen[bot].s_line;
X bot--;
X }
X
X (*TTdel_line)(top, bottom, num);
X}
X
X
X/* The cursor optimization happens here. You may decide that this
X is going too far with cursor optimization, or perhaps it should
X limit the amount of checking to when the output speed is slow.
X What ever turns you on ... */
X
Xprivate struct cursaddr {
X int c_numchars,
X (*c_proc)();
X};
X
Xprivate char *Cmstr;
Xprivate struct cursaddr *HorMin,
X *VertMin,
X *DirectMin;
X
Xprivate ForMotion(),
X ForTab(),
X BackMotion(),
X RetTab(),
X DownMotion(),
X UpMotion(),
X GoDirect(),
X HomeGo(),
X BottomUp();
X
X
Xprivate struct cursaddr WarpHor[] = {
X 0, ForMotion,
X 0, ForTab,
X 0, BackMotion,
X 0, RetTab
X};
X
Xprivate struct cursaddr WarpVert[] = {
X 0, DownMotion,
X 0, UpMotion
X};
X
Xprivate struct cursaddr WarpDirect[] = {
X 0, GoDirect,
X 0, HomeGo,
X 0, BottomUp
X};
X
X#undef FORWARD
X#define FORWARD 0 /* Move forward */
X#define FORTAB 1 /* Forward using tabs */
X#undef BACKWARD
X#define BACKWARD 2 /* Move backward */
X#define RETFORWARD 3 /* Beginning of line and then tabs */
X#define NUMHOR 4
X
X#define DOWN 0 /* Move down */
X#define UPMOVE 1 /* Move up */
X#define NUMVERT 2
X
X#define DIRECT 0 /* Using CM */
X#define HOME 1 /* HOME */
X#define LOWER 2 /* Lower Line */
X#define NUMDIRECT 3
X
X#define home() Placur(0, 0)
X#define LowLine() putpad(LL, 1), CapLine = ILI, CapCol = 0
X#define PrintHo() putpad(HO, 1), CapLine = CapCol = 0
X
Xint phystab = 8;
X
Xprivate
XGoDirect(line, col)
Xregister int line,
X col;
X{
X putpad(Cmstr, 1);
X CapLine = line;
X CapCol = col;
X}
X
Xprivate
XRetTab(col)
Xregister int col;
X{
X putchar('\r');
X CapCol = 0;
X ForTab(col);
X}
X
Xprivate
XHomeGo(line, col)
X{
X PrintHo();
X DownMotion(line);
X ForTab(col);
X}
X
Xprivate
XBottomUp(line, col)
Xregister int line,
X col;
X{
X LowLine();
X UpMotion(line);
X ForTab(col);
X}
X
X/* Tries to move forward using tabs (if possible). It tabs to the
X closest tabstop which means it may go past 'destcol' and backspace
X to it. */
X
Xprivate
XForTab(destcol)
Xint destcol;
X{
X register int tabgoal,
X ntabs,
X tabstp = phystab;
X
X if (TABS && (tabstp > 0)) {
X tabgoal = destcol + (tabstp / 2);
X tabgoal -= (tabgoal % tabstp);
X
X /* Don't tab to last place or else it is likely to screw up. */
X if (tabgoal >= CO)
X tabgoal -= tabstp;
X
X ntabs = (tabgoal / tabstp) - (CapCol / tabstp);
X while (--ntabs >= 0)
X putchar('\t');
X CapCol = tabgoal;
X }
X if (CapCol > destcol)
X BackMotion(destcol);
X else if (CapCol < destcol)
X ForMotion(destcol);
X}
X
Xprivate
XForMotion(destcol)
Xregister int destcol;
X{
X register int nchars = destcol - CapCol;
X register char *cp = &Screen[CapLine].s_line[CapCol];
X
X while (--nchars >= 0)
X putchar(*cp++ & 0177);
X CapCol = destcol;
X}
X
Xprivate
XBackMotion(destcol)
Xregister int destcol;
X{
X register int nchars = CapCol - destcol;
X
X if (BC)
X while (--nchars >= 0)
X putpad(BC, 1);
X else
X while (--nchars >= 0)
X putchar('\b');
X CapCol = destcol;
X}
X
Xprivate
XDownMotion(destline)
Xregister int destline;
X{
X register int nlines = destline - CapLine;
X
X while (--nlines >= 0)
X putchar('\n');
X CapLine = destline;
X}
X
Xprivate
XUpMotion(destline)
Xregister int destline;
X{
X register int nchars = CapLine - destline;
X
X while (--nchars >= 0)
X putpad(UP, 1);
X CapLine = destline;
X}
X
X#ifdef ID_CHAR
Xstatic int EIlen;
X#endif
Xextern int IMlen;
X
XInitCM()
X{
X HOlen = HO ? strlen(HO) : 1000;
X LLlen = LL ? strlen(LL) : 1000;
X UPlen = UP ? strlen(UP) : 1000;
X#ifdef ID_CHAR
X if (EI)
X EIlen = strlen(EI);
X#endif
X}
X
XPlacur(line, col)
X{
X int dline, /* Number of lines to move */
X dcol; /* Number of columns to move */
X register int best,
X i;
X register struct cursaddr *cp;
X int xtracost = 0; /* Misc addition to cost. */
X
X#define CursMin(which,addrs,max) \
X for (best = 0, cp = &addrs[1], i = 1; i < max; i++, cp++) \
X if (cp->c_numchars < addrs[best].c_numchars) \
X best = i; \
X which = &addrs[best];
X
X if (line == CapLine && col == CapCol)
X return; /* We are already there. */
X
X dline = line - CapLine;
X dcol = col - CapCol;
X#ifdef ID_CHAR
X if (IN_INSmode && MI)
X xtracost = EIlen + IMlen;
X /* If we're already in insert mode, it is likely that we will
X want to be in insert mode again, after the insert. */
X#endif
X
X /* Number of characters to move horizontally for each case.
X 1: Just move forward by typing the right character on the screen.
X 2: Print the correct number of back spaces.
X 3: Try tabbing to the correct place.
X 4: Try going to the beginning of the line, and then tab. */
X
X if (dcol == 1 || dcol == 0) { /* Most common case. */
X HorMin = &WarpHor[FORWARD];
X HorMin->c_numchars = dcol + xtracost;
X } else {
X WarpHor[FORWARD].c_numchars = dcol >= 0 ? dcol + xtracost : 1000;
X WarpHor[BACKWARD].c_numchars = dcol < 0 ? -(dcol + xtracost) : 1000;
X WarpHor[FORTAB].c_numchars = dcol >= 0 && TABS ?
X ForNum(CapCol, col) + xtracost : 1000;
X WarpHor[RETFORWARD].c_numchars = (xtracost + 1 + (TABS ? ForNum(0, col) : col));
X
X /* Which is the shortest of the bunch */
X
X CursMin(HorMin, WarpHor, NUMHOR);
X }
X
X /* Moving vertically is more simple. */
X
X WarpVert[DOWN].c_numchars = dline >= 0 ? dline : 1000;
X WarpVert[UPMOVE].c_numchars = dline < 0 ? ((-dline) * UPlen) : 1000;
X
X /* Which of these is simpler */
X CursMin(VertMin, WarpVert, NUMVERT);
X
X /* Homing first and lowering first are considered
X direct motions.
X Homing first's total is the sum of the cost of homing
X and the sum of tabbing (if possible) to the right. */
X
X if (VertMin->c_numchars + HorMin->c_numchars <= 3) {
X DirectMin = &WarpDirect[DIRECT]; /* A dummy ... */
X DirectMin->c_numchars = 100;
X } else {
X WarpDirect[DIRECT].c_numchars = CM ?
X strlen(Cmstr = tgoto(CM, col, line)) : 1000;
X WarpDirect[HOME].c_numchars = HOlen + line +
X WarpHor[RETFORWARD].c_numchars;
X WarpDirect[LOWER].c_numchars = LLlen + ((ILI - line) * UPlen) +
X WarpHor[RETFORWARD].c_numchars;
X CursMin(DirectMin, WarpDirect, NUMDIRECT);
X }
X
X if (HorMin->c_numchars + VertMin->c_numchars < DirectMin->c_numchars) {
X if (line != CapLine)
X (*VertMin->c_proc)(line);
X if (col != CapCol) {
X#ifdef ID_CHAR
X if (IN_INSmode) /* We may use real characters ... */
X INSmode(0);
X#endif
X (*HorMin->c_proc)(col);
X }
X } else {
X#ifdef ID_CHAR
X if (IN_INSmode && !MI)
X INSmode(0);
X#endif
X (*DirectMin->c_proc)(line, col);
X }
X}
X
X#define abs(x) ((x) >= 0 ? (x) : -(x))
X
XForNum(from, to)
Xregister int from;
X{
X register int tabgoal,
X tabstp = phystab;
X int numchars = 0;
X
X if (from >= to)
X return from - to;
X if (TABS && (tabstp > 0)) {
X tabgoal = to + (tabstp / 2);
X tabgoal -= (tabgoal % tabstp);
X if (tabgoal >= CO)
X tabgoal -= tabstp;
X numchars = (tabgoal / tabstop) - (from / tabstp);
X from = tabgoal;
X }
X return numchars + abs(from - to);
X}
X
X#ifdef WIRED_TERMS
X
XBGi_lines(top, bottom, num)
X{
X printf("\033[%d;%dr\033[%dL\033[r", top + 1, bottom + 1, num);
X CapCol = CapLine = 0;
X}
X
XSUNi_lines(top, bottom, num)
X{
X Placur(bottom - num + 1, 0);
X printf("\033[%dM", num);
X Placur(top, 0);
X printf("\033[%dL", num);
X}
X
XC100i_lines(top, bottom, num)
X{
X if (num <= 1) {
X GENi_lines(top, bottom, num);
X return;
X }
X printf("\033v%c%c%c%c", ' ', ' ', ' ' + bottom + 1, ' ' + CO);
X CapLine = CapCol = 0;
X Placur(top, 0);
X while (num--)
X putpad(AL, ILI - CapLine);
X printf("\033v%c%c%c%c", ' ', ' ', ' ' + LI, ' ' + CO);
X CapLine = CapCol = 0;
X}
X
X#endif WIRED_TERMS
X
XGENi_lines(top, bottom, num)
X{
X register int i;
X
X if (CS) {
X putpad(tgoto(CS, bottom, top));
X CapCol = CapLine = 0;
X Placur(top, 0);
X for (i = 0; i < num; i++)
X putpad(SR, bottom - top);
X putpad(tgoto(CS, ILI, 0));
X CapCol = CapLine = 0;
X } else {
X Placur(bottom - num + 1, 0);
X if (M_DL && (num > 1)) {
X char minibuf[16];
X
X sprintf(minibuf, M_DL, num);
X putpad(minibuf, ILI - CapLine);
X } else {
X for (i = 0; i < num; i++)
X putpad(DL, ILI - CapLine);
X }
X Placur(top, 0);
X if (M_AL && (num > 1)) {
X char minibuf[16];
X
X sprintf(minibuf, M_AL, num);
X putpad(minibuf, ILI - CapLine);
X } else {
X for (i = 0; i < num; i++)
X putpad(AL, ILI - CapLine);
X }
X }
X}
X
X#ifdef WIRED_TERMS
X
XBGd_lines(top, bottom, num)
X{
X printf("\033[%d;%dr\033[%dM\033[r", top + 1, bottom + 1, num);
X CapCol = CapLine = 0;
X}
X
XSUNd_lines(top, bottom, num)
X{
X Placur(top, 0);
X printf("\033[%dM", num);
X Placur(bottom + 1 - num, 0);
X printf("\033[%dL", num);
X}
X
XC100d_lines(top, bottom, num)
X{
X if (num <= 1) {
X GENd_lines(top, bottom, num);
X return;
X }
X printf("\033v%c%c%c%c", ' ', ' ', ' ' + bottom + 1, ' ' + CO);
X CapLine = CapCol = 0;
X Placur(top, 0);
X while (num--)
X putpad(DL, ILI - CapLine);
X printf("\033v%c%c%c%c", ' ', ' ', ' ' + LI, ' ' + CO);
X CapLine = CapCol = 0;
X}
X
X#endif WIRED_TERMS
X
XGENd_lines(top, bottom, num)
X{
X register int i;
X
X if (CS) {
X putpad(tgoto(CS, bottom, top));
X CapCol = CapLine = 0;
X Placur(bottom, 0);
X for (i = 0; i < num; i++)
X putpad(SF, bottom - top);
X putpad(tgoto(CS, ILI, 0));
X CapCol = CapLine = 0;
X } else {
X Placur(top, 0);
X if (M_DL && (num > 1)) {
X char minibuf[16];
X
X sprintf(minibuf, M_DL, num);
X putpad(minibuf, ILI - top);
X } else {
X for (i = 0; i < num; i++)
X putpad(DL, ILI - top);
X }
X Placur(bottom + 1 - num, 0);
X if (M_AL && (num > 1)) {
X char minibuf[16];
X
X sprintf(minibuf, M_AL, num);
X putpad(minibuf, ILI - CapLine);
X } else {
X for (i = 0; i < num; i++)
X putpad(AL, ILI - CapLine);
X }
X }
X}
X
Xstruct ID_lookup {
X char *ID_name;
X int (*I_proc)(); /* proc to insert lines */
X int (*D_proc)(); /* proc to delete lines */
X} ID_trms[] = {
X "generic", GENi_lines, GENd_lines, /* This should stay here */
X#ifdef WIRED_TERMS
X "sun", SUNi_lines, SUNd_lines,
X "bg", BGi_lines, BGd_lines,
X "c1", C100i_lines, C100d_lines,
X#endif WIRED_TERMS
X 0, 0, 0
X};
X
XIDline_setup(tname)
Xchar *tname;
X{
X register struct ID_lookup *idp;
X
X for (idp = &ID_trms[1]; idp->ID_name; idp++)
X if (strncmp(idp->ID_name, tname, strlen(idp->ID_name)) == 0)
X break;
X if (idp->ID_name == 0)
X idp = &ID_trms[0];
X TTins_line = idp->I_proc;
X TTdel_line = idp->D_proc;
X}
@//E*O*F screen.c//
if test 17553 -ne "`wc -c <'screen.c'`"; then
echo shar: error transmitting "'screen.c'" '(should have been 17553 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'teachjove.c'" '(1052 characters)'
if test -f 'teachjove.c' ; then
echo shar: will not over-write existing file "'teachjove.c'"
else
sed 's/^X//' >teachjove.c <<'@//E*O*F teachjove.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 <sys/types.h>
X#include <sys/file.h>
X
X#ifndef TEACHJOVE
X# define TEACHJOVE "/usr/lib/jove/teach-jove"
X#endif
X
X#ifndef W_OK
X# define W_OK 2
X# define F_OK 0
X#endif
X
Xextern char *getenv();
X
Xmain()
X{
X char cmd[256],
X fname[256],
X *home;
X
X if ((home = getenv("HOME")) == 0) {
X printf("teachjove: cannot find your home!\n");
X exit(-1);
X }
X (void) sprintf(fname, "%s/teach-jove", home);
X if (access(fname, F_OK) != 0) {
X (void) sprintf(cmd, "cp %s %s", TEACHJOVE, fname);
X system(cmd);
X }
X (void) execlp("jove", "teachjove", fname, (char *) 0);
X printf("teachjove: cannot execl jove!\n");
X}
X
@//E*O*F teachjove.c//
if test 1052 -ne "`wc -c <'teachjove.c'`"; then
echo shar: error transmitting "'teachjove.c'" '(should have been 1052 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'tune.template'" '(882 characters)'
if test -f 'tune.template' ; then
echo shar: will not over-write existing file "'tune.template'"
else
sed 's/^X//' >tune.template <<'@//E*O*F tune.template//'
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#define NOEXTERNS
X
X#include "tune.h"
X
Xchar TmpFilePath[128] = "TMPDIR";
X
Xchar *d_tempfile = "joveXXXXXX", /* buffer lines go here */
X *p_tempfile = "jrecXXXXXX", /* line pointers go here */
X *Recover = "LIBDIR/recover",
X *CmdDb = "LIBDIR/cmds.doc",
X /* copy of "cmds.doc" lives in the doc subdirectory */
X
X *Joverc = "LIBDIR/.joverc",
X
X#ifdef PIPEPROCS
X *Portsrv = "LIBDIR/portsrv",
X#endif
X
X Shell[128] = "SHELL",
X ShFlags[16] = "-c";
@//E*O*F tune.template//
if test 882 -ne "`wc -c <'tune.template'`"; then
echo shar: error transmitting "'tune.template'" '(should have been 882 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'version.c'" '(473 characters)'
if test -f 'version.c' ; then
echo shar: will not over-write existing file "'version.c'"
else
sed 's/^X//' >version.c <<'@//E*O*F version.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
Xchar *version = "4.6.1.4";
@//E*O*F version.c//
if test 473 -ne "`wc -c <'version.c'`"; then
echo shar: error transmitting "'version.c'" '(should have been 473 characters)'
fi
fi # end of overwriting check
echo shar: "End of archive 7 (of 13)."
cp /dev/null ark7isdone
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
More information about the Mod.sources
mailing list