rsalz@bbn.com (Rich Salz) (04/26/88)
Submitted-by: Jonathan Payne <jpayne@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@uunet.uu.net.