v14i063: Jove, an emacs variant, version 4.9, Part07/21
Rich Salz
rsalz at bbn.com
Wed Apr 27 02:37:18 AEST 1988
Submitted-by: Jonathan Payne <jpayne at cs.rochester.edu>
Posting-number: Volume 14, Issue 63
Archive-name: jove4.9/part07
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 7 (of 21)."
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f './c.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'./c.c'\"
else
echo shar: Extracting \"'./c.c'\" \(14160 characters\)
sed "s/^X//" >'./c.c' <<'END_OF_FILE'
X/***************************************************************************
X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE *
X * is 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/* Contains commands for C mode. Paren matching routines are in here. */
X
X#include "jove.h"
X#include "re.h"
X#include "ctype.h"
X
X#ifdef MAC
X# undef private
X# define private
X#endif
X
X#ifdef LINT_ARGS
private int
X backslashed(char *, int);
private void
X do_expr(int, int),
X FindMatch(int),
X parse_cmt_fmt(char *),
X strip_c(char *, char *);
X#else
private int
X backslashed();
private void
X do_expr(),
X FindMatch(),
X parse_cmt_fmt(),
X strip_c();
X#endif /* LINT_ARGS */
X
X#ifdef MAC
X# undef private
X# define private static
X#endif
X
X
private int
backslashed(lp, cpos)
register char *lp;
register int cpos;
X{
X register int cnt = 0;
X
X while (cpos > 0 && lp[--cpos] == '\\')
X cnt += 1;
X return (cnt % 2);
X}
X
private char *p_types = "(){}[]";
private int mp_kind;
X#define MP_OKAY 0
X#define MP_MISMATCH 1
X#define MP_UNBALANCED 2
X
void
mp_error()
X{
X switch (mp_kind) {
X case MP_MISMATCH:
X message("[Mismatched parentheses]");
X break;
X
X case MP_UNBALANCED:
X message("[Unbalanced parenthesis]");
X break;
X
X case MP_OKAY:
X default:
X return;
X }
X rbell();
X}
X
X/* Search from the current position for the paren that matches p_type.
X Search in the direction dir. If can_mismatch is YES then it is okay
X to have mismatched parens. If stop_early is YES then when an open
X paren is found at the beginning of a line, it is assumed that there
X is no point in backing up further. This is so when you hit tab or
X LineFeed outside, in-between procedure/function definitions, it won't
X sit there searching all the way to the beginning of the file for a
X match that doesn't exist. {forward,backward}-s-expression are the
X only ones that insist on getting the "true" story. */
X
Bufpos *
m_paren(p_type, dir, can_mismatch, can_stop)
char p_type;
register int dir;
X{
X static Bufpos ret;
X Bufpos savedot,
X *sp;
X char re_buf[100],
X *re_alts[NALTS];
X int count = 0;
X register char *lp,
X c;
X char p_match,
X re_str[128],
X *cp,
X quote_c = 0;
X register int c_char;
X int in_comment = -1,
X stopped = NO;
X
X sprintf(re_str, "[(){}[\\]%s]", (MajorMode(CMODE)) ? "/\"'" : "\"");
X REcompile(re_str, 1, re_buf, re_alts);
X if (cp = index(p_types, p_type))
X p_match = cp[dir];
X else
X complain("[Cannot match %c's]", p_type);
X DOTsave(&savedot);
X
X /* To make things a little faster I avoid copying lines into
X linebuf by setting curline and curchar by hand. Warning:
X this is slightly to very risky. When I did this there were
X lots of problems with procedures that expect the contents of
X curline to be in linebuf. */
X while (count >= 0) {
X sp = docompiled(dir, re_buf, re_alts);
X if (sp == 0)
X break;
X lp = lbptr(sp->p_line);
X
X if (sp->p_line != curline)
X /* let's assume that strings do NOT go over line
X bounderies (for now don't check for wrapping
X strings) */
X quote_c = 0;
X curline = sp->p_line;
X curchar = sp->p_char; /* here's where I cheat */
X c_char = curchar;
X if (dir == FORWARD)
X c_char -= 1;
X if (backslashed(lp, c_char))
X continue;
X c = lp[c_char];
X /* check if this is a comment (if we're not inside quotes) */
X if (quote_c == 0 && c == '/') {
X int new_ic;
X
X if ((c_char != 0) && lp[c_char - 1] == '*') {
X new_ic = (dir == FORWARD) ? NO : YES;
X if (new_ic == NO && in_comment == -1) {
X count = 0;
X quote_c = 0;
X }
X } else if (lp[c_char + 1] == '*') {
X new_ic = (dir == FORWARD) ? YES : NO;
X if (new_ic == NO && in_comment == -1) {
X count = 0;
X quote_c = 0;
X }
X }
X in_comment = new_ic;
X }
X if (in_comment == YES)
X continue;
X if (c == '"' || c == '\'') {
X if (quote_c == c)
X quote_c = 0;
X else if (quote_c == 0)
X quote_c = c;
X }
X if (quote_c != 0)
X continue;
X if (isopenp(c)) {
X count += dir;
X if (c_char == 0 && can_stop == YES && count >= 0) {
X stopped = YES;
X break;
X }
X } else if (isclosep(c))
X count -= dir;
X }
X
X ret.p_line = curline;
X ret.p_char = curchar;
X
X curline = savedot.p_line;
X curchar = savedot.p_char; /* here's where I undo it */
X
X if (count >= 0)
X mp_kind = MP_UNBALANCED;
X else if (c != p_match)
X mp_kind = MP_MISMATCH;
X else
X mp_kind = MP_OKAY;
X
X /* If we stopped (which means we were allowed to stop) and there
X was an error, we clear the error so no error message is printed.
X An error should be printed ONLY when we are sure about the fact,
X namely we didn't stop prematurely HOPING that it was the right
X answer. */
X if (stopped && mp_kind != MP_OKAY) {
X mp_kind = MP_OKAY;
X return 0;
X }
X if (mp_kind == MP_OKAY || (mp_kind == MP_MISMATCH && can_mismatch == YES))
X return &ret;
X return 0;
X}
X
private void
do_expr(dir, skip_words)
register int dir;
X{
X register char c,
X syntax = (dir == FORWARD) ? _Op : _Cl;
X
X if (dir == BACKWARD)
X b_char(1);
X c = linebuf[curchar];
X for (;;) {
X if (!skip_words && ismword(c)) {
X WITH_TABLE(curbuf->b_major)
X if(dir == FORWARD) f_word(1);
X else b_word(1);
X END_TABLE();
X break;
X } else if (has_syntax(c, syntax)) {
X FindMatch(dir);
X break;
X }
X f_char(dir);
X if (eobp() || bobp())
X return;
X c = linebuf[curchar];
X }
X}
X
void
FSexpr()
X{
X register int num = arg_value();
X
X if (num < 0) {
X set_arg_value(-num);
X BSexpr();
X }
X while (--num >= 0)
X do_expr(FORWARD, NO);
X}
X
void
FList()
X{
X register int num = arg_value();
X
X if (num < 0) {
X set_arg_value(-num);
X BList();
X }
X while (--num >= 0)
X do_expr(FORWARD, YES);
X}
X
void
BSexpr()
X{
X register int num = arg_value();
X
X if (num < 0) {
X negate_arg_value();
X FSexpr();
X }
X while (--num >= 0)
X do_expr(BACKWARD, NO);
X}
X
void
BList()
X{
X register int num = arg_value();
X
X if (num < 0) {
X negate_arg_value();
X FList();
X }
X while (--num >= 0)
X do_expr(BACKWARD, YES);
X}
X
void
BUpList()
X{
X Bufpos *mp;
X char c = (MajorMode(CMODE) ? '}' : ')');
X
X mp = m_paren(c, BACKWARD, NO, YES);
X if (mp == 0)
X mp_error();
X else
X SetDot(mp);
X}
X
void
FDownList()
X{
X Bufpos *sp;
X char *sstr = (MajorMode(CMODE) ? "[{([\\])}]" : "[()]"),
X *lp;
X
X sp = dosearch(sstr, FORWARD, YES);
X if (sp != 0)
X lp = lcontents(sp->p_line);
X if (sp == 0 || has_syntax(lp[sp->p_char - 1], _Cl))
X complain("[No contained expression]");
X SetDot(sp);
X}
X
X/* Move to the matching brace or paren depending on the current position
X in the buffer. */
X
private void
FindMatch(dir)
X{
X register Bufpos *bp;
X register char c = linebuf[curchar];
X
X if ((index(p_types, c) == 0) ||
X (backslashed(linebuf, curchar)))
X complain((char *) 0);
X if (dir == FORWARD)
X f_char(1);
X bp = m_paren(c, dir, YES, NO);
X if (dir == FORWARD)
X b_char(1);
X if (bp != 0)
X SetDot(bp);
X mp_error(); /* if there is an error the user wants to
X know about it */
X}
X
Bufpos *
c_indent(incrmt)
X{
X Bufpos *bp;
X int indent = 0;
X
X if (bp = m_paren('}', BACKWARD, NO, YES)) {
X Bufpos save;
X
X DOTsave(&save);
X SetDot(bp);
X ToIndent();
X indent = calc_pos(linebuf, curchar);
X SetDot(&save);
X }
X if (incrmt) {
X if (indent == 0)
X incrmt = tabstop;
X else
X incrmt = (tabstop - (indent%tabstop));
X }
X n_indent(indent + incrmt);
X return bp;
X}
X
X#ifdef CMT_FMT
X
char CmtFmt[80] = "/*%n%! * %c%!%n */";
X
void
Comment()
X{
X FillComment(CmtFmt);
X}
X
X/* Strip leading and trailing white space. Skip over any imbedded '\r's. */
X
private void
strip_c(from, to)
char *from,
X *to;
X{
X register char *fr_p = from,
X *to_p = to,
X c;
X
X while (c = *fr_p) {
X if (c == ' ' || c == '\t' || c == '\r')
X fr_p += 1;
X else
X break;
X }
X while (c = *fr_p) {
X if (c != '\r')
X *to_p++ = c;
X fr_p += 1;
X }
X while (--to_p >= to)
X if (*to_p != ' ' && *to_p != '\t')
X break;
X *++to_p = '\0';
X}
X
private char open_c[20], /* the open comment format string */
X open_pat[20], /* the search pattern for open comment */
X l_header[20], /* the prefix for each comment line */
X l_trailer[20], /* the suffix ... */
X close_c[20],
X close_pat[20];
X
private char *comment_body[] = {
X open_c,
X l_header,
X l_trailer,
X close_c
X};
X
private int nlflags;
X
X/* Fill in the data structures above from the format string. Don't return
X if there's trouble. */
X
private void
parse_cmt_fmt(str)
char *str;
X{
X register char *fmtp = str;
X register char **c_body = comment_body,
X *body_p = *c_body;
X int c,
X newlines = 1;
X
X /* pick apart the comment string */
X while (c = *fmtp++) {
X if (c != '%') {
X *body_p++ = c;
X continue;
X }
X switch(c = *fmtp++) {
X case 'n':
X if (newlines == 2 || newlines == 3)
X complain("%n not allowed in line header or trailer: %s",
X fmtp - 2);
X nlflags += newlines;
X *body_p++ = '\r';
X break;
X case 't':
X *body_p++ = '\t';
X break;
X case '%':
X *body_p++ = '%';
X break;
X case '!':
X case 'c':
X newlines += 1;
X *body_p++ = '\0';
X body_p = *++c_body;
X break;
X default:
X complain("[Unknown comment escape: %%%c]", c);
X /* VARARGS */
X break;
X }
X }
X *body_p = '\0';
X /* make search patterns */
X strip_c(open_c, open_pat);
X strip_c(close_c, close_pat);
X}
X
X#define NL_IN_OPEN_C ((nlflags % 4) == 1)
X#define NL_IN_CLOSE_C (nlflags >= 4)
X
void
FillComment(format)
char *format;
X{
X int saveRMargin,
X indent_pos,
X close_at_dot = NO,
X slen,
X header_len,
X trailer_len;
X register char *cp;
X static char inside_err[] = "[Must be between %s and %s to re-format]";
X Bufpos open_c_pt,
X close_c_pt,
X tmp_bp,
X *match_o,
X *match_c;
X Mark *entry_mark,
X *open_c_mark,
X *savedot;
X
X parse_cmt_fmt(format);
X /* figure out if we're "inside" a comment */
X if ((match_o = dosearch(open_pat, BACKWARD, 0)) == 0)
X /* VARARGS */
X complain("No opening %s to match to.", open_pat);
X open_c_pt = *match_o;
X if ((match_c = dosearch(close_pat, BACKWARD, NO)) != 0 &&
X inorder(open_c_pt.p_line, open_c_pt.p_char,
X match_c->p_line, match_c->p_char))
X complain(inside_err, open_pat, close_pat);
X if ((match_o = dosearch(open_pat, FORWARD, NO)) != 0) {
X tmp_bp = *match_o;
X match_o = &tmp_bp;
X }
X if ((match_c = dosearch(close_pat, FORWARD, 0)) != (Bufpos *) 0)
X close_c_pt = *match_c;
X
X /* Here's where we figure out whether to format from dot or from
X the close comment. Note that we've already searched backwards to
X find the open comment symbol for the comment we are formatting.
X The open symbol mentioned below refers to the possible existence
X of the next comment. There are 5 cases:
X 1) no open or close symbol ==> dot
X 2) open, but no close symbol ==> dot
X 3) close, but no open ==> close
X 4) open, close are inorder ==> dot
X 5) open, close are not inorder ==> close */
X
X
X if (match_o == (Bufpos *) 0) {
X if (match_c == (Bufpos *) 0)
X close_at_dot = YES;
X } else if (match_c == (Bufpos *) 0)
X close_at_dot = YES;
X else if (inorder(match_o->p_line, match_o->p_char,
X match_c->p_line, match_c->p_char))
X close_at_dot = YES;
X if (close_at_dot) {
X close_c_pt.p_line = curline;
X close_c_pt.p_char = curchar;
X } else {
X SetDot(match_c);
X }
X SetDot(&open_c_pt);
X open_c_mark = MakeMark(curline, curchar, M_FLOATER);
X indent_pos = calc_pos(linebuf, curchar);
X /* search for a close comment; delete it if it exits */
X SetDot(&close_c_pt);
X if (close_at_dot == 0) {
X slen = strlen(close_pat);
X while (slen--)
X del_char(BACKWARD, 1);
X }
X entry_mark = MakeMark(curline, curchar, M_FLOATER);
X ToMark(open_c_mark);
X /* always separate the comment body from anything preceeding it */
X LineInsert(1);
X DelWtSpace();
X Bol();
X for (cp = open_c; *cp; cp++) {
X if (*cp == '\r') {
X if (!eolp())
X LineInsert(1);
X else
X line_move(FORWARD, 1, NO);
X } else if (*cp == ' ' || *cp == '\t') {
X if (linebuf[curchar] != *cp)
X insert_c(*cp, 1);
X } else
X /* Since we matched the open comment string on this
X line, we don't need to worry about crossing line
X boundaries. */
X curchar += 1;
X }
X savedot = MakeMark(curline, curchar, M_FLOATER);
X
X /* We need to strip the line header pattern of leading white space
X since we need to match the line after all of its leading
X whitespace is gone. */
X for (cp = l_header; *cp && (isspace(*cp)); cp++)
X ;
X header_len = strlen(cp);
X trailer_len = strlen(l_trailer);
X
X /* Strip each comment line of the open and close comment strings
X before reformatting it. */
X
X do {
X Bol();
X DelWtSpace();
X if (header_len && !strncmp(linebuf, cp, header_len))
X del_char(FORWARD, header_len);
X if (trailer_len) {
X Eol();
X if ((curchar > trailer_len) &&
X (!strncmp(&linebuf[curchar - trailer_len],
X l_trailer, trailer_len)))
X del_char(BACKWARD, trailer_len);
X }
X if (curline->l_next != 0)
X line_move(FORWARD, 1, NO);
X else
X break;
X } while (curline != entry_mark->m_line->l_next);
X
X do_set_mark(savedot->m_line, savedot->m_char);
X ToMark(entry_mark);
X saveRMargin = RMargin;
X RMargin = saveRMargin - strlen(l_header) -
X strlen(l_trailer) - indent_pos + 2;
X do_rfill(NO);
X RMargin = saveRMargin;
X /* get back to the start of the comment */
X PopMark();
X do {
X if (curline == open_c_mark->m_line->l_next) {
X ;
X } else {
X n_indent(indent_pos);
X ins_str(l_header, NO);
X }
X Eol();
X if (!NL_IN_CLOSE_C && (curline == entry_mark->m_line))
X ;
X else
X ins_str(l_trailer, NO);
X if (curline->l_next != 0)
X line_move(FORWARD, 1, NO);
X else
X break;
X } while (curline != entry_mark->m_line->l_next);
X /* handle the close comment symbol */
X if (curline == entry_mark->m_line->l_next) {
X line_move(BACKWARD, 1, NO);
X Eol();
X }
X DelWtSpace();
X /* if the addition of the close symbol would cause the line to be
X too long, put the close symbol on the next line. */
X if (!(NL_IN_CLOSE_C) &&
X strlen(close_c) + calc_pos(linebuf, curchar) > RMargin) {
X LineInsert(1);
X n_indent(indent_pos);
X }
X for (cp = close_c; *cp; cp++) {
X if (*cp == '\r') {
X LineInsert(1);
X n_indent(indent_pos);
X } else
X insert_c(*cp, 1);
X }
X ToMark(open_c_mark);
X Eol();
X del_char(FORWARD, 1);
X}
X
X#endif /* CMT_FMT */
X
END_OF_FILE
if test 14160 -ne `wc -c <'./c.c'`; then
echo shar: \"'./c.c'\" unpacked with wrong size!
fi
# end of './c.c'
fi
if test -f './insert.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'./insert.c'\"
else
echo shar: Extracting \"'./insert.c'\" \(14465 characters\)
sed "s/^X//" >'./insert.c' <<'END_OF_FILE'
X/***************************************************************************
X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE *
X * is 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 "ctype.h"
X#include "table.h"
X
X#ifdef MAC
X# undef private
X# define private
X#endif
X
X#ifdef LINT_ARGS
private int
X newchunk(void);
private void
X init_specials(void),
X remfreelines(struct chunk *);
X#else
private int
X newchunk();
private void
X init_specials(),
X remfreelines();
X#endif /* LINT_ARGS */
X
X#ifdef MAC
X# undef private
X# define private static
X#endif
X
X/* Make a newline after AFTER in buffer BUF, UNLESS after is 0,
X in which case we insert the newline before after. */
X
Line *
listput(buf, after)
register Buffer *buf;
register Line *after;
X{
X register Line *newline = nbufline();
X
X if (after == 0) { /* Before the first line */
X newline->l_next = buf->b_first;
X newline->l_prev = 0;
X buf->b_first = newline;
X } else {
X newline->l_prev = after;
X newline->l_next = after->l_next;
X after->l_next = newline;
X }
X if (newline->l_next)
X newline->l_next->l_prev = newline;
X else
X if (buf)
X buf->b_last = newline;
X if (buf && buf->b_dot == 0)
X buf->b_dot = newline;
X return newline;
X}
X
X/* Divide the current line and move the current line to the next one */
X
void
LineInsert(num)
register int num;
X{
X char newline[LBSIZE];
X register Line *newdot,
X *olddot;
X int oldchar;
X
X olddot = curline;
X oldchar = curchar;
X
X newdot = curline;
X while (--num >= 0) {
X newdot = listput(curbuf, newdot);
X SavLine(newdot, NullStr);
X }
X
X modify();
X if (curchar != 0) {
X strcpy(newline, &linebuf[curchar]);
X linebuf[curchar] = '\0'; /* Shorten this line */
X SavLine(curline, linebuf);
X strcpy(linebuf, newline);
X } else { /* Redisplay optimization */
X newdot->l_dline = curline->l_dline;
X SavLine(curline, NullStr);
X }
X
X makedirty(curline);
X curline = newdot;
X curchar = 0;
X makedirty(curline);
X IFixMarks(olddot, oldchar, curline, curchar);
X}
X
X/* Makes the indent of the current line == goal. If the current indent
X is greater than GOAL it deletes. If more indent is needed, it uses
X tabs and spaces to get to where it's going. */
X
void
n_indent(goal)
register int goal;
X{
X int dotcol,
X incrmt;
X
X ToIndent();
X dotcol = calc_pos(linebuf, curchar);
X if (goal < dotcol) {
X DelWtSpace();
X dotcol = 0;
X }
X
X for (;;) {
X incrmt = (tabstop - (dotcol % tabstop));
X if (dotcol + incrmt > goal)
X break;
X insert_c('\t', 1);
X dotcol += incrmt;
X }
X if (dotcol != goal)
X insert_c(' ', (goal - dotcol));
X}
X
X#ifdef ABBREV
void
MaybeAbbrevExpand()
X{
X if (MinorMode(Abbrev) && !ismword(LastKeyStruck) &&
X !bolp() && ismword(linebuf[curchar - 1]))
X AbbrevExpand();
X}
X#endif
X
void
SelfInsert()
X{
X#ifdef ABBREV
X MaybeAbbrevExpand();
X#endif
X if (LastKeyStruck != CTL('J') && MinorMode(OverWrite)) {
X register int num,
X i;
X
X for (i = 0, num = arg_value(); i < num; i++) {
X int pos = calc_pos(linebuf, curchar);
X
X if (!eolp()) {
X if (linebuf[curchar] == '\t') {
X if ((pos + 1) == ((pos + tabstop) - (pos % tabstop)))
X del_char(FORWARD, 1);
X } else
X del_char(FORWARD, 1);
X }
X insert_c(LastKeyStruck, 1);
X }
X } else
X Insert(LastKeyStruck);
X
X if (MinorMode(Fill) && (curchar >= RMargin ||
X (calc_pos(linebuf, curchar) >= RMargin))) {
X int margin;
X Bufpos save;
X
X if (MinorMode(Indent)) {
X DOTsave(&save);
X ToIndent();
X margin = calc_pos(linebuf, curchar);
X SetDot(&save);
X } else
X margin = LMargin;
X DoJustify(curline, 0, curline,
X curchar + strlen(&linebuf[curchar]), 1, margin);
X }
X}
X
void
Insert(c)
X{
X if (c == CTL('J'))
X LineInsert(arg_value());
X else
X insert_c(c, arg_value());
X}
X
X/* insert character C N times at point */
void
insert_c(c, n)
X{
X if (n <= 0)
X return;
X modify();
X makedirty(curline);
X ins_c(c, linebuf, curchar, n, LBSIZE);
X IFixMarks(curline, curchar, curline, curchar + n);
X curchar += n;
X}
X
X/* Tab in to the right place for C mode */
X
void
Tab()
X{
X#ifdef LISP
X if (MajorMode(LISPMODE) && (bolp() || !eolp())) {
X int dotchar = curchar;
X Mark *m = 0;
X
X ToIndent();
X if (dotchar > curchar)
X m = MakeMark(curline, dotchar, M_FLOATER);
X (void) lisp_indent();
X if (m) {
X ToMark(m);
X DelMark(m);
X } else
X ToIndent();
X return;
X }
X#endif
X if (MajorMode(CMODE) && strlen(linebuf) == 0)
X (void) c_indent(CIndIncrmt);
X else
X SelfInsert();
X}
X
void
QuotChar()
X{
X int c,
X slow;
X
X c = waitchar(&slow);
X if (slow)
X message(key_strokes);
X if (c != CTL('@'))
X Insert(c);
X}
X
X/* Insert the paren. If in C mode and c is a '}' then insert the
X '}' in the "right" place for C indentation; that is indented
X the same amount as the matching '{' is indented. */
X
int PDelay = 5, /* 1/2 a second */
X CIndIncrmt = 8;
X
void
DoParen()
X{
X Bufpos *bp = (Bufpos *) -1;
X int nx,
X c = LastKeyStruck;
X
X if (!isclosep(c)) {
X SelfInsert();
X return;
X }
X
X if (MajorMode(CMODE) && c == '}' && blnkp(linebuf))
X bp = c_indent(0);
X#ifdef LISP
X if (MajorMode(LISPMODE) && c == ')' && blnkp(linebuf))
X bp = lisp_indent();
X#endif
X SelfInsert();
X#ifdef MAC
X if (MinorMode(ShowMatch) && !in_macro()) {
X#else
X if (MinorMode(ShowMatch) && !charp() && !in_macro()) {
X#endif
X b_char(1); /* Back onto the ')' */
X if ((int) bp == -1)
X bp = m_paren(c, BACKWARD, NO, YES);
X f_char(1);
X if (bp != 0) {
X nx = in_window(curwind, bp->p_line);
X if (nx != -1) { /* is visible */
X Bufpos b;
X
X DOTsave(&b);
X SetDot(bp);
X SitFor(PDelay);
X SetDot(&b);
X } else
X s_mess("%s", lcontents(bp->p_line));
X }
X mp_error(); /* display error message */
X }
X}
X
void
LineAI()
X{
X DoNewline(TRUE);
X}
X
void
Newline()
X{
X DoNewline(MinorMode(Indent));
X}
X
void
DoNewline(indentp)
X{
X Bufpos save;
X int indent;
X
X /* first we calculate the indent of the current line */
X DOTsave(&save);
X ToIndent();
X indent = calc_pos(linebuf, curchar);
X SetDot(&save);
X
X#ifdef ABBREV
X MaybeAbbrevExpand();
X#endif
X#ifdef LISP
X if (MajorMode(LISPMODE))
X DelWtSpace();
X else
X#endif
X if (indentp || blnkp(linebuf))
X DelWtSpace();
X
X /* If there is more than 2 blank lines in a row then don't make
X a newline, just move down one. */
X if (arg_value() == 1 && eolp() && TwoBlank())
X SetLine(curline->l_next);
X else
X LineInsert(arg_value());
X
X if (indentp)
X#ifdef LISP
X if (MajorMode(LISPMODE))
X (void) lisp_indent();
X else
X#endif
X n_indent((LMargin == 0) ? indent : LMargin);
X}
X
void
ins_str(str, ok_nl)
register char *str;
X{
X register char c;
X Bufpos save;
X int llen;
X
X if (*str == 0)
X return; /* ain't nothing to insert! */
X DOTsave(&save);
X llen = strlen(linebuf);
X while (c = *str++) {
X if (c == '\n' || (ok_nl && llen >= LBSIZE - 2)) {
X IFixMarks(save.p_line, save.p_char, curline, curchar);
X modify();
X makedirty(curline);
X LineInsert(1);
X DOTsave(&save);
X llen = strlen(linebuf);
X }
X if (c != '\n') {
X ins_c(c, linebuf, curchar++, 1, LBSIZE);
X llen += 1;
X }
X }
X IFixMarks(save.p_line, save.p_char, curline, curchar);
X modify();
X makedirty(curline);
X}
X
void
open_lines(n)
X{
X Bufpos dot;
X
X DOTsave(&dot);
X LineInsert(n); /* Open the lines... */
X SetDot(&dot);
X}
X
void
OpenLine()
X{
X open_lines(arg_value());
X}
X
X/* Take the region FLINE/FCHAR to TLINE/TCHAR and insert it at
X ATLINE/ATCHAR in WHATBUF. */
X
Bufpos *
DoYank(fline, fchar, tline, tchar, atline, atchar, whatbuf)
Line *fline,
X *tline,
X *atline;
Buffer *whatbuf;
X{
X register Line *newline;
X static Bufpos bp;
X char save[LBSIZE],
X buf[LBSIZE];
X Line *startline = atline;
X int startchar = atchar;
X
X lsave();
X if (whatbuf)
X modify();
X (void) ltobuf(atline, genbuf);
X strcpy(save, &genbuf[atchar]);
X
X (void) ltobuf(fline, buf);
X if (fline == tline)
X buf[tchar] = '\0';
X
X linecopy(genbuf, atchar, &buf[fchar]);
X atline->l_dline = putline(genbuf);
X makedirty(atline);
X
X fline = fline->l_next;
X while (fline != tline->l_next) {
X newline = listput(whatbuf, atline);
X newline->l_dline = fline->l_dline;
X makedirty(newline);
X fline = fline->l_next;
X atline = newline;
X atchar = 0;
X }
X
X getline(atline->l_dline, genbuf);
X atchar += tchar;
X linecopy(genbuf, atchar, save);
X atline->l_dline = putline(genbuf);
X makedirty(atline);
X IFixMarks(startline, startchar, atline, atchar);
X bp.p_line = atline;
X bp.p_char = atchar;
X this_cmd = YANKCMD;
X getDOT(); /* Whatever used to be in linebuf */
X return &bp;
X}
X
void
YankPop()
X{
X Line *line,
X *last;
X Mark *mp = CurMark();
X Bufpos *dot;
X int dir = -1; /* Direction to rotate the ring */
X
X if (last_cmd != YANKCMD)
X complain("Yank something first!");
X
X lfreelist(reg_delete(mp->m_line, mp->m_char, curline, curchar));
X
X /* Now must find a recently killed region. */
X
X if (arg_value() < 0)
X dir = 1;
X
X killptr += dir;
X for (;;) {
X if (killptr < 0)
X killptr = NUMKILLS - 1;
X else if (killptr >= NUMKILLS)
X killptr = 0;
X if (killbuf[killptr])
X break;
X killptr += dir;
X }
X
X this_cmd = YANKCMD;
X
X line = killbuf[killptr];
X last = lastline(line);
X dot = DoYank(line, 0, last, length(last), curline, curchar, curbuf);
X MarkSet(CurMark(), curline, curchar);
X SetDot(dot);
X}
X
X/* This is an attempt to reduce the amount of memory taken up by each line.
X Without this each malloc of a line uses sizeof (line) + sizeof(HEADER)
X where line is 3 words and HEADER is 1 word.
X This is going to allocate memory in chucks of CHUNKSIZE * sizeof (line)
X and divide each chuck into lineS. A line is free in a chunk when its
X line->l_dline == 0, so freeline sets dline to 0. */
X
X#define CHUNKSIZE 300
X
struct chunk {
X int c_nlines; /* Number of lines in this chunk (so they
X don't all have to be CHUNKSIZE long). */
X Line *c_block; /* Chunk of memory */
X struct chunk *c_nextfree; /* Next chunk of lines */
X};
X
private struct chunk *fchunk = 0;
private Line *ffline = 0; /* First free line */
X
void
freeline(line)
register Line *line;
X{
X line->l_dline = 0;
X line->l_next = ffline;
X if (ffline)
X ffline->l_prev = line;
X line->l_prev = 0;
X ffline = line;
X}
X
void
lfreelist(first)
register Line *first;
X{
X if (first)
X lfreereg(first, lastline(first));
X}
X
X/* Append region from line1 to line2 onto the free list of lines */
X
void
lfreereg(line1, line2)
register Line *line1,
X *line2;
X{
X register Line *next,
X *last = line2->l_next;
X
X while (line1 != last) {
X next = line1->l_next;
X freeline(line1);
X line1 = next;
X }
X}
X
private int
newchunk()
X{
X register Line *newline;
X register int i;
X struct chunk *f;
X int nlines = CHUNKSIZE;
X
X f = (struct chunk *) emalloc(sizeof (struct chunk));
X if (f == 0)
X return 0;
X
X if ((f->c_block = (Line *) malloc((unsigned) (sizeof (Line) * nlines))) == 0) {
X while (nlines > 0) {
X f->c_block = (Line *) malloc((unsigned) (sizeof (Line) * nlines));
X if (f->c_block != 0)
X break;
X nlines /= 2;
X }
X }
X
X if (nlines <= 0)
X return 0;
X
X f->c_nlines = nlines;
X for (i = 0, newline = f->c_block; i < nlines; newline++, i++)
X freeline(newline);
X f->c_nextfree = fchunk;
X fchunk = f;
X return 1;
X}
X
X/* New BUFfer LINE */
X
Line *
nbufline()
X{
X register Line *newline;
X
X if (ffline == 0) /* No free list */
X if (newchunk() == 0)
X complain("[Out of lines] ");
X newline = ffline;
X ffline = ffline->l_next;
X if (ffline)
X ffline->l_prev = 0;
X return newline;
X}
X
X/* Remove the free lines, in chunk c, from the free list because they are
X no longer free. */
X
private void
remfreelines(c)
register struct chunk *c;
X{
X register Line *lp;
X register int i;
X
X for (lp = c->c_block, i = 0; i < c->c_nlines; i++, lp++) {
X if (lp->l_prev)
X lp->l_prev->l_next = lp->l_next;
X else
X ffline = lp->l_next;
X if (lp->l_next)
X lp->l_next->l_prev = lp->l_prev;
X }
X}
X
X/* This is used to garbage collect the chunks of lines when malloc fails
X and we are NOT looking for a new buffer line. This goes through each
X chunk, and if every line in a given chunk is not allocated, the entire
X chunk is `free'd by "free()". */
X
void
GCchunks()
X{
X register struct chunk *cp;
X struct chunk *prev = 0,
X *next = 0;
X register int i;
X register Line *newline;
X
X for (cp = fchunk; cp != 0; cp = next) {
X for (i = 0, newline = cp->c_block; i < cp->c_nlines; newline++, i++)
X if (newline->l_dline != 0)
X break;
X
X next = cp->c_nextfree;
X
X if (i == cp->c_nlines) { /* Unlink it!!! */
X if (prev)
X prev->c_nextfree = cp->c_nextfree;
X else
X fchunk = cp->c_nextfree;
X remfreelines(cp);
X free((char *) cp->c_block);
X free((char *) cp);
X } else
X prev = cp;
X }
X}
X
X#ifdef LISP
X
X/* Grind S-Expr */
X
void
GSexpr()
X{
X Bufpos dot,
X end;
X
X if (linebuf[curchar] != '(')
X complain((char *) 0);
X DOTsave(&dot);
X FSexpr();
X DOTsave(&end);
X SetDot(&dot);
X for (;;) {
X if (curline == end.p_line)
X break;
X line_move(FORWARD, 1, NO);
X if (!blnkp(linebuf))
X (void) lisp_indent();
X }
X SetDot(&dot);
X}
X
X/* lisp_indent() indents a new line in Lisp Mode, according to where
X the matching close-paren would go if we typed that (sort of). */
X
private Table *specials = NIL;
X
private void
init_specials()
X{
X static char *words[] = {
X "case",
X "def",
X "dolist",
X "fluid-let",
X "lambda",
X "let",
X "lexpr",
X "macro",
X "named-l", /* named-let and named-lambda */
X "nlambda",
X "prog",
X "selectq",
X 0
X };
X char **wordp = words;
X
X specials = make_table();
X while (*wordp)
X add_word(*wordp++, specials);
X}
X
void
AddSpecial()
X{
X char *word;
X
X word = ask((char *) 0, ProcFmt);
X if (specials == NIL)
X init_specials();
X add_word(copystr(word), specials);
X}
X
Bufpos *
lisp_indent()
X{
X Bufpos *bp,
X savedot;
X int goal;
X
X bp = m_paren(')', BACKWARD, NO, YES);
X
X if (bp == 0)
X return 0;
X
X /* We want to end up
X
X (atom atom atom ...
X ^ here.
X */
X
X DOTsave(&savedot);
X SetDot(bp);
X f_char(1);
X if (linebuf[curchar] != '(') {
X register Word *wp;
X
X if (specials == NIL)
X init_specials();
X for (wp = table_top(specials); wp != NIL; wp = next_word(wp))
X if (casencmp(word_text(wp), &linebuf[curchar], word_length(wp)) == 0)
X break;
X if (wp == NIL) { /* not special */
X int c_char = curchar;
X
X WITH_TABLE(curbuf->b_major)
X f_word(1);
X END_TABLE();
X if (LookingAt("[ \t]*;\\|[ \t]*$", linebuf, curchar))
X curchar = c_char;
X else while (linebuf[curchar] == ' ')
X curchar += 1;
X } else
X curchar += 1;
X }
X goal = calc_pos(linebuf, curchar);
X SetDot(&savedot);
X n_indent(goal);
X
X return bp;
X}
X#endif /* LISP */
END_OF_FILE
if test 14465 -ne `wc -c <'./insert.c'`; then
echo shar: \"'./insert.c'\" unpacked with wrong size!
fi
# end of './insert.c'
fi
if test -f './recover.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'./recover.c'\"
else
echo shar: Extracting \"'./recover.c'\" \(14306 characters\)
sed "s/^X//" >'./recover.c' <<'END_OF_FILE'
X/***************************************************************************
X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE *
X * is 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 is
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#undef getchar
X
X#define STDIO
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
char blk_buf[BUFSIZ];
int nleft;
FILE *ptrs_fp;
int data_fd;
struct rec_head Header;
char datafile[40],
X pntrfile[40];
long Nchars,
X Nlines;
char tty[] = "/dev/tty";
int UserID,
X Verbose = 0;
char *Directory = 0; /* the directory we're looking in */
X
struct 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
struct rec_entry *buflist[100] = {0};
X
X#ifndef BSD4_2
X
typedef struct {
X int d_fd; /* File descriptor for this directory */
X} DIR;
X
DIR *
opendir(dir)
char *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
closedir(dp)
DIR *dp;
X{
X (void) close(dp->d_fd);
X free(dp);
X}
X
struct direct *
readdir(dp)
DIR *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#if defined(elxsi) && defined(SYSV)
X /*
X * Elxsi has a BSD4.2 implementation which may or may not use
X * `twisted inodes' ... Anyone able to check?
X */
X while (*(unsigned short *)&dir.d_ino == 0);
X#else
X while (dir.d_ino == 0);
X#endif
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
getline(tl, buf)
disk_line tl;
char *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
char *
getblock(atl)
disk_line atl;
X{
X int bno,
X off;
X static int curblock = -1;
X
X bno = da_to_bno(atl);
X off = da_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
char *
copystr(s)
char *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
scandir(dir, nmptr, qualify, sorter)
char *dir;
struct direct ***nmptr;
int (*qualify)();
struct 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 += 1;
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
alphacomp(a, b)
struct direct **a,
X **b;
X{
X return strcmp((*a)->d_name, (*b)->d_name);
X}
X
char *CurDir;
X
X/* Scan the DIRNAME directory for jove tmp files, and make a linked list
X out of them. */
X
get_files(dirname)
char *dirname;
X{
X int add_name();
X struct direct **nmptr;
X
X CurDir = dirname;
X scandir(dirname, &nmptr, add_name, (int (*)())0);
X}
X
add_name(dp)
struct 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
options()
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
struct rec_entry **
getsrc()
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
static char *
getdest()
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
char *
readword(buf)
char *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
tellme(quest, answer)
char *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
jmp_buf int_env;
X
catch()
X{
X longjmp(int_env, 1);
X}
X
restore()
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);
tryagain:
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 += 1;
X }
X printf("Recovered %d buffers.\n", nrecovered);
X}
X
get(src, dest)
struct rec_entry **src;
char *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 if (dest != tty)
X printf("\"%s\"", dest);
X dump_file(src - buflist, 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
char **
scanvec(args, str)
register char **args,
X *str;
X{
X while (*args) {
X if (strcmp(*args, str) == 0)
X return args;
X args += 1;
X }
X return 0;
X}
X
read_rec(recptr)
struct 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
seekto(which)
X{
X struct rec_entry rec;
X long offset;
X int i;
X
X offset = sizeof (Header) + (Header.Nbuffers * sizeof (rec));
X for (i = 1; i < which; i++)
X offset += buflist[i]->r_nlines * sizeof (disk_line);
X fseek(ptrs_fp, offset, L_SET);
X}
X
makblist()
X{
X int i;
X
X fseek(ptrs_fp, (long) sizeof (Header), L_SET);
X for (i = 1; i <= Header.Nbuffers; i++) {
X if (buflist[i] == 0)
X buflist[i] = (struct rec_entry *) malloc (sizeof (struct rec_entry));
X read_rec(buflist[i]);
X }
X while (buflist[i]) {
X free((char *) buflist[i]);
X buflist[i] = 0;
X i += 1;
X }
X}
X
disk_line
getaddr(fp)
register 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
dump_file(which, out)
FILE *out;
X{
X register int nlines;
X register disk_line daddr;
X char buf[BUFSIZ];
X
X seekto(which);
X nlines = buflist[which]->r_nlines;
X Nchars = Nlines = 0L;
X while (--nlines >= 0) {
X daddr = getaddr(ptrs_fp);
X getline(daddr, buf);
X Nlines += 1;
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
list()
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
doit(fp)
struct 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#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 list();
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
ask_del(prompt, fp)
char *prompt;
struct file_pair *fp;
X{
X char yorn[20];
X
X tellme(prompt, yorn);
X if (yorn[0] == 'y')
X del_files(fp);
X}
X
del_files(fp)
struct file_pair *fp;
X{
X (void) unlink(fp->file_data);
X (void) unlink(fp->file_rec);
X}
X
X#ifdef notdef
savetmps()
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
lookup(dir)
char *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
main(argc, argv)
int argc;
char *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 */
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 = YES;
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}
END_OF_FILE
if test 14306 -ne `wc -c <'./recover.c'`; then
echo shar: \"'./recover.c'\" unpacked with wrong size!
fi
# end of './recover.c'
fi
echo shar: End of archive 7 \(of 21\).
cp /dev/null ark7isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 21 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
More information about the Comp.sources.unix
mailing list