v08i025: The JOVE text editor, Part06/13
sources-request at mirror.UUCP
sources-request at mirror.UUCP
Wed Feb 4 15:05:06 AEST 1987
Submitted by: seismo!rochester!jpayne (Jonathan Payne)
Mod.sources: Volume 8, Issue 25
Archive-name: jove/Part06
#! /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 6 (of 13)."
# Contents: misc.c move.c paragraph.c portsrv.c proc.c re1.c table.h
PATH=/bin:/usr/bin:/usr/ucb; export PATH
echo shar: extracting "'misc.c'" '(7568 characters)'
if test -f 'misc.c' ; then
echo shar: will not over-write existing file "'misc.c'"
else
sed 's/^X//' >misc.c <<'@//E*O*F misc.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 "ctype.h"
X#include <signal.h>
X#ifdef ANSICODES
X#include "termcap.h"
X#endif
X
XDigit()
X{
X GetExp(LastKeyStruck);
X}
X
XDigit0()
X{
X GetExp('0');
X}
X
XDigit1()
X{
X GetExp('1');
X}
X
XDigit2()
X{
X GetExp('2');
X}
X
XDigit3()
X{
X GetExp('3');
X}
X
XDigit4()
X{
X GetExp('4');
X}
X
XDigit5()
X{
X GetExp('5');
X}
X
XDigit6()
X{
X GetExp('6');
X}
X
XDigit7()
X{
X GetExp('7');
X}
X
XDigit8()
X{
X GetExp('8');
X}
X
XDigit9()
X{
X GetExp('9');
X}
X
XprCTIME()
X{
X s_mess(": %f %s", get_time((time_t *) 0, (char *) 0, 0, -1));
X}
X
Xextern int alarmed;
X
XFourTime()
X{
X int oldc = LastKeyStruck,
X newc;
X int nexp;
X
X alarmed = 0;
X exp_p = YES;
X this_cmd = ARG_CMD;
X do {
X if ((nexp = exp * 4) != 0)
X exp = nexp;
X if (!alarmed)
X newc = waitchar();
X else
X newc = getch();
X if (alarmed)
X message(key_strokes);
X } while (newc == oldc);
X Ungetc(newc);
X}
X
Xint exp_p,
X exp;
X
XGetExp(c)
X{
X int sign = 0;
X static int digited;
X
X if (!isdigit(c) && c != '-')
X complain((char *) 0);
X if (exp_p == NO) { /* if we just got here */
X exp = 0; /* start over */
X digited = NO;
X } else if (exp_p == YES_NODIGIT) {
X sign = (exp < 0) ? -1 : 1;
X exp = 0;
X }
X
X if (!sign)
X sign = (exp < 0) ? -1 : 1;
X if (sign == -1)
X exp = -exp;
X if (c == '-') {
X sign = -sign;
X goto goread;
X }
X for (;;) {
X if (alarmed)
X message(key_strokes);
X if (isdigit(c)) {
X exp = (exp * 10) + (c - '0');
X digited++;
X } else {
X if (digited)
X exp_p = YES;
X else {
X exp = 1;
X if (exp_p == NO)
X exp_p = YES_NODIGIT;
X }
X exp *= sign;
X this_cmd = ARG_CMD;
X Ungetc(c);
X return;
X }
Xgoread: if (!alarmed)
X c = waitchar();
X else {
X add_mess(NullStr);
X c = getch();
X }
X }
X}
X
XChrToOct()
X{
X int c;
X
X c = waitchar();
X if (alarmed)
X message(key_strokes);
X ins_str(sprint("\\%03o", c), NO);
X}
X
XStrLength()
X{
X static char inquotes[] = "Where are the quotes?";
X char *first = StrIndex(-1, linebuf, curchar, '"'),
X *last = StrIndex(1, linebuf, curchar + 1, '"'),
X c;
X int numchars = 0;
X
X if (first == 0 || last == 0)
X complain(inquotes);
X first++;
X while (first < last) {
X c = *first++;
X if (c == '\\') {
X int num;
X
X if (!isdigit(*first))
X ++first;
X else {
X num = 3;
X while (num-- && isdigit(*first++) && first < last)
X ;
X }
X }
X numchars++;
X }
X s_mess("%d characters", numchars);
X}
X
X/* Transpos cur_char with cur_char - 1 */
X
XTransChar()
X{
X char before;
X
X if (curchar == 0 || (eolp() && curchar == 1))
X complain((char *) 0); /* BEEP */
X exp = 1;
X if (eolp())
X BackChar();
X before = linebuf[curchar - 1];
X DelPChar();
X ForChar();
X Insert(before);
X}
X
X/* Switch current line with previous one */
X
XTransLines()
X{
X disk_line old_prev;
X
X if (firstp(curline))
X return;
X exp = 1;
X lsave();
X old_prev = curline->l_prev->l_dline;
X curline->l_prev->l_dline = curline->l_dline;
X curline->l_dline = old_prev;
X getDOT();
X if (!lastp(curline))
X line_move(FORWARD, NO);
X modify();
X}
X
XLeave()
X{
X longjmp(mainjmp, QUIT);
X}
X
X/* If argument is specified, kill that many lines down. Otherwise,
X if we "appear" to be at the end of a line, i.e. everything to the
X right of the cursor is white space, we delete the line separator
X as if we were at the end of the line. */
X
XKillEOL()
X{
X Line *line2;
X int char2;
X
X if (exp_p) {
X if (exp == 0) { /* Kill to beginning of line */
X line2 = curline;
X char2 = 0;
X } else {
X line2 = next_line(curline, exp);
X if ((LineDist(curline, line2) < exp) || (line2 == curline))
X char2 = length(line2);
X else
X char2 = 0;
X }
X } else if (blnkp(&linebuf[curchar])) {
X line2 = next_line(curline, 1);
X if (line2 == curline)
X char2 = length(curline);
X else
X char2 = 0;
X } else {
X line2 = curline;
X char2 = length(curline);
X }
X reg_kill(line2, char2, 0);
X}
X
X/* Kill to beginning of sentence */
X
XKillBos()
X{
X exp = -exp;
X KillEos();
X}
X
X/* Kill to end of sentence */
X
XKillEos()
X{
X Line *line1;
X int char1;
X
X line1 = curline;
X char1 = curchar;
X Eos();
X reg_kill(line1, char1, 1);
X}
X
XKillExpr()
X{
X Line *line1;
X int char1;
X
X line1 = curline;
X char1 = curchar;
X FSexpr();
X reg_kill(line1, char1, 1);
X}
X
XEscPrefix()
X{
X HandlePref(pref1map);
X}
X
XCtlxPrefix()
X{
X HandlePref(pref2map);
X}
X
XMiscPrefix()
X{
X HandlePref(miscmap);
X}
X
XHandlePref(map)
Xdata_obj **map;
X{
X register data_obj *cp;
X register int c;
X
X c = waitchar();
X if (c == CTL(G)) {
X message("[Aborted]");
X rbell();
X return;
X }
X
X if (alarmed)
X message(key_strokes);
X
X cp = map[c];
X if (cp == 0) {
X s_mess("[%sunbound]", key_strokes);
X rbell();
X } else
X ExecCmd(cp);
X}
X
XYank()
X{
X Line *line,
X *lp;
X Bufpos *dot;
X
X if (killbuf[killptr] == 0)
X complain("[Nothing to yank!]");
X lsave();
X this_cmd = YANKCMD;
X line = killbuf[killptr];
X lp = lastline(line);
X dot = DoYank(line, 0, lp, length(lp), curline, curchar, curbuf);
X SetMark();
X SetDot(dot);
X}
X
XWtModBuf()
X{
X if (!ModBufs(NO))
X message("[No buffers need saving]");
X else
X put_bufs(exp_p);
X}
X
Xput_bufs(askp)
X{
X register Buffer *oldb = curbuf,
X *b;
X
X for (b = world; b != 0; b = b->b_next) {
X if (!IsModified(b) || b->b_type != B_FILE)
X continue;
X SetBuf(b); /* Make this current Buffer */
X if (curbuf->b_fname == 0) {
X char *newname;
X
X newname = ask(NullStr, "Buffer \"%s\" needs a file name; type Return to skip: ", b->b_name);
X if (*newname == 0)
X continue;
X setfname(b, newname);
X }
X if (askp && (yes_or_no_p("Write %s? ", curbuf->b_fname) == NO))
X continue;
X filemunge(curbuf->b_fname);
X chk_mtime(curbuf, curbuf->b_fname, "save");
X file_write(curbuf->b_fname, 0);
X unmodify();
X }
X SetBuf(oldb);
X}
X
XToIndent()
X{
X register char *cp,
X c;
X
X for (cp = linebuf; c = *cp; cp++)
X if (c != ' ' && c != '\t')
X break;
X curchar = cp - linebuf;
X}
X
XGoLine()
X{
X Line *newline;
X
X#ifndef ANSICODES
X if (exp_p == NO)
X return;
X#else
X if (exp_p == NO || exp <= 0) {
X if (SP)
X putpad(SP, 1); /* Ask for cursor position */
X return;
X }
X#endif
X newline = next_line(curbuf->b_first, exp - 1);
X PushPntp(newline);
X SetLine(newline);
X}
X
X#ifdef ANSICODES
XMoveToCursor(line, col)
X{
X register struct scrimage *sp = &PhysScreen[line];
X
X while (sp->s_id == NULL)
X sp = &PhysScreen[--line];
X if (sp->s_flags & MODELINE)
X complain((char *) 0);
X if (curwind != sp->s_window)
X SetWind(sp->s_window);
X SetLine(sp->s_lp);
X curchar = how_far(sp->s_lp, col);
X}
X
XAnsiCodes()
X{
X int c;
X int num1 = 0;
X int num2;
X static char *unsupported = "[Unsupported ANSI code received]";
X
X while (isdigit(c = getch()))
X num1 = (num1*10) + (c - '0');
X
X switch (c) {
X case ';':
X num2 = 0;
X while (isdigit(c = getch()))
X num2 = (num2*10) + (c - '0');
X switch (c) {
X case 'R':
X MoveToCursor(--num1, --num2);
X break;
X case 'H':
X Eow(); Bol();
X break;
X default:
X complain(unsupported);
X }
X break;
X case 'A':
X line_move(BACKWARD, YES);
X break;
X case 'B':
X line_move(FORWARD, YES);
X break;
X case 'C':
X ForChar();
X break;
X case 'D':
X BackChar();
X break;
X case 'H':
X Bow();
X break;
X case 'J':
X if (num1 == 2) {
X ClAndRedraw();
X break;
X }
X /* FALL THROUGH */
X default:
X complain(unsupported);
X }
X}
X#endif ANSICODES
X
XNotModified()
X{
X unmodify();
X}
X
XSetLMargin()
X{
X LMargin = calc_pos(linebuf, curchar);
X}
X
XSetRMargin()
X{
X RMargin = calc_pos(linebuf, curchar);
X}
@//E*O*F misc.c//
if test 7568 -ne "`wc -c <'misc.c'`"; then
echo shar: error transmitting "'misc.c'" '(should have been 7568 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'move.c'" '(4397 characters)'
if test -f 'move.c' ; then
echo shar: will not over-write existing file "'move.c'"
else
sed 's/^X//' >move.c <<'@//E*O*F move.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 "ctype.h"
X
Xstatic int line_pos;
X
XForChar()
X{
X register int num = exp;
X
X if (exp < 0) {
X exp = -exp;
X BackChar();
X return;
X }
X exp = 1;
X while (--num >= 0) {
X if (eolp()) { /* Go to the next Line */
X if (curline->l_next == 0)
X break;
X SetLine(curline->l_next);
X } else
X curchar++;
X }
X}
X
XBackChar()
X{
X register int num = exp;
X
X if (exp < 0) {
X exp = -exp;
X ForChar();
X return;
X }
X exp = 1;
X while (--num >= 0) {
X if (bolp()) {
X if (curline->l_prev == 0)
X break;
X SetLine(curline->l_prev);
X Eol();
X } else
X --curchar;
X }
X}
X
XNextLine()
X{
X if ((curline == curbuf->b_last) && eolp())
X complain(NullStr);
X line_move(FORWARD, YES);
X}
X
XPrevLine()
X{
X if ((curline == curbuf->b_first) && bolp())
X complain(NullStr);
X line_move(BACKWARD, YES);
X}
X
X/* moves to a different line in DIR; LINE_CMD says whether this is
X being called from NextLine() or PrevLine(), in which case it tries
X to line up the column with the column of the current line */
X
Xline_move(dir, line_cmd)
X{
X Line *(*proc)() = (dir == FORWARD) ? next_line : prev_line;
X Line *line;
X
X line = (*proc)(curline, exp);
X if (line == curline) {
X (dir == FORWARD) ? Eol() : Bol();
X return;
X }
X
X if (line_cmd) {
X this_cmd = LINECMD;
X if (last_cmd != LINECMD)
X line_pos = calc_pos(linebuf, curchar);
X }
X SetLine(line); /* curline is in linebuf now */
X if (line_cmd)
X curchar = how_far(curline, line_pos);
X}
X
X/* returns what cur_char should be for that position col */
X
Xhow_far(line, col)
XLine *line;
X{
X register char *lp;
X register int pos,
X c;
X char *base;
X
X base = lp = lcontents(line);
X pos = 0;
X
X while (pos < col && (c = (*lp & 0177))) {
X if (c == '\t')
X pos += (tabstop - (pos % tabstop));
X else if (isctrl(c))
X pos += 2;
X else
X pos++;
X lp++;
X }
X
X return lp - base;
X}
X
XBol()
X{
X curchar = 0;
X}
X
XEol()
X{
X curchar = strlen(linebuf);
X}
X
XEof()
X{
X PushPntp(curbuf->b_last);
X ToLast();
X}
X
XBof()
X{
X PushPntp(curbuf->b_first);
X ToFirst();
X}
X
X/* Move forward (if dir > 0) or backward (if dir < 0) a sentence. Deals
X with all the kludgery involved with paragraphs, and moving backwards
X is particularly yucky. */
X
Xto_sent(dir)
X{
X Bufpos *new,
X old;
X extern char *ParaStr;
X
X DOTsave(&old);
X
X new = dosearch("^[ \t]*$\\|[?.!]", dir, 1);
X if (new == 0) {
X (dir < 0) ? ToFirst() : ToLast();
X return;
X }
X SetDot(new);
X if (dir < 0) {
X to_word(1);
X if ((old.p_line == curline && old.p_char <= curchar) ||
X (inorder(new->p_line, new->p_char, old.p_line, old.p_char) &&
X inorder(old.p_line, old.p_char, curline, curchar))) {
X SetDot(new);
X to_sent(dir);
X }
X return; /* We're there? */
X }
X if (blnkp(linebuf)) {
X Bol();
X BackChar();
X if (old.p_line == curline && old.p_char >= curchar) {
X to_word(1); /* Oh brother this is painful */
X to_sent(1);
X }
X } else {
X extern int REbom;
X
X curchar = REbom + 1; /* Just after the [?.!] */
X if (LookingAt("[\")] *\\|[\")]$", linebuf, curchar))
X curchar++;
X else if (!eolp() && !LookingAt(" *", linebuf, curchar))
X to_sent(dir);
X }
X}
X
XBos()
X{
X int num = exp;
X
X if (exp < 0) {
X exp = -exp;
X Eos();
X return;
X }
X
X exp = 1;
X
X while (--num >= 0) {
X to_sent(-1);
X if (bobp())
X break;
X }
X}
X
XEos()
X{
X int num = exp;
X
X if (exp < 0) {
X exp = -exp;
X Bos();
X return;
X }
X
X exp = 1;
X
X while (--num >= 0) {
X to_sent(1);
X if (eobp())
X break;
X }
X}
X
XForWord()
X{
X register char c;
X register int num = exp;
X
X if (exp < 0) {
X exp = -exp;
X BackWord();
X return;
X }
X exp = 1;
X while (--num >= 0) {
X to_word(1);
X while ((c = linebuf[curchar]) != 0 && isword(c))
X curchar++;
X if (eobp())
X break;
X }
X this_cmd = 0; /* Semi kludge to stop some unfavorable behavior */
X}
X
XBackWord()
X{
X register int num = exp;
X register char c;
X
X if (exp < 0) {
X exp = -exp;
X ForWord();
X return;
X }
X exp = 1;
X while (--num >= 0) {
X to_word(-1);
X while (!bolp() && (c = linebuf[curchar - 1], isword(c)))
X --curchar;
X if (bobp())
X break;
X }
X this_cmd = 0;
X}
@//E*O*F move.c//
if test 4397 -ne "`wc -c <'move.c'`"; then
echo shar: error transmitting "'move.c'" '(should have been 4397 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'paragraph.c'" '(13888 characters)'
if test -f 'paragraph.c' ; then
echo shar: will not over-write existing file "'paragraph.c'"
else
sed 's/^X//' >paragraph.c <<'@//E*O*F paragraph.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
X/* Thanks to Brian Harvey for this paragraph boundery finding algorithm.
X It's really quite hairy figuring it out. This deals with paragraphs that
X are seperated by blank lines, lines beginning with a Period (assumed to
X be an nroff command), lines beginning with BackSlash (assumed to be Tex
X commands). Also handles paragraphs that are separated by lines of
X different indent; and it deals with outdented paragraphs, too. It's
X really quite nice. Here's Brian's algorithm.
X
X Definitions:
X
X THIS means the line containing the cursor.
X PREV means the line above THIS.
X NEXT means the line below THIS.
X
X BLANK means empty, empty except for spaces and tabs, starts with a period
X or a backslash, or nonexistent (because the edge of the buffer is
X reached). ((BH 12/24/85 A line starting with backslash is blank only if
X the following line also starts with backslash. This is so that \noindent
X is part of a paragraph, but long strings of TeX commands don't get
X rearranged. It still isn't perfect but it's better.))
X
X BSBLANK means BLANK or starts with a backslash. (BH 12/24/85)
X
X HEAD means the first (nonblank) line of the paragraph containing THIS.
X BODY means all other (nonblank) lines of the paragraph.
X TAIL means the last (nb) line of the paragraph. (TAIL is part of BODY.)
X
X HEAD INDENT means the indentation of HEAD. M-J should preserve this.
X BODY INDENT means the indentation of BODY. Ditto.
X
X Subprocedures:
X
X TAILRULE(BODYLINE)
X If BODYLINE is BLANK, the paragraph has only one line, and there is no
X BODY and therefore no TAIL. Return. Otherwise, starting from BODYLINE,
X move down until you find a line that either is BSBLANK or has a different
X indentation from BODYLINE. The line above that different line is TAIL.
X Return.
X
X Rules:
X
X 1. If THIS is BLANK, which command are you doing? If M-J or M-[, then go
X up to the first non-BLANK line and start over. (If there is no non-BLANK
X line before THIS, ring the bell.) If M-], then the first non-BLANK line
X below THIS is HEAD, and the second consecutive non-BSBLANK line (if any) is
X the beginning of BODY. (If there is no non-BLANK line after THIS, ring
X the bell.) Do TAILRULE(beginning-of-BODY). Go to rule A.
X
X 2. If PREV is BLANK or THIS is BSBLANK, then THIS is HEAD, and NEXT (if
X not BSBLANK) is in BODY. Do TAILRULE(NEXT). Go to rule A.
X
X 3. If NEXT is BSBLANK, then THIS is TAIL, therefore part of BODY. Go to
X rule 5 to find HEAD.
X
X 4. If either NEXT or PREV has the same indentation as THIS, then THIS is
X part of BODY. Do TAILRULE(THIS). Go to rule 5 to find HEAD. Otherwise,
X go to rule 6.
X
X 5. Go up until you find a line that is either BSBLANK or has a different
X indentation from THIS. If that line is BLANK, the line below it is HEAD.
X If that line is non-BLANK, then call that new line THIS for what follows.
X If (the new) PREV has the same indent as THIS, then (the new) NEXT is
X HEAD. If PREV has a different indent from THIS, then THIS is HEAD. Go to
X rule A.
X
X 6. If you got here, then both NEXT and PREV are nonblank and are
X differently indented from THIS. This is a tricky case and there is no
X guarantee that you're going to win. The most straightforward thing to do
X is assume that we are not using hanging indentation. In that case:
X whichever of PREV and THIS is indented further is HEAD. Do
X TAILRULE(HEAD+1). Go to rule A.
X
X 6+. A more complicated variant would be this: if THIS is indented further
X than PREV, we are using regular indentation and rule 6 applies. If PREV
X is indented further than THIS, look at both NEXT and the line after NEXT.
X If those two lines are indented equally, and more than THIS, then we are
X using hanging indent, THIS is HEAD, and NEXT is the first line of BODY.
X Do TAILRULE(NEXT). Otherwise, rule 6 applies.
X
X A. You now know where HEAD and TAIL are. The indentation of HEAD is HEAD
X INDENT; the indentation of TAIL is BODY INDENT.
X
X B. If you are trying to M-J, you are now ready to do it.
X
X C. If you are trying to M-], leave point after the newline that ends
X TAIL. In other words, leave the cursor at the beginning of the line
X after TAIL. It is not possible for this to leave point where it started
X unless it was already at the end of the buffer.
X
X D. If you are trying to M-[, if the line before HEAD is not BLANK, then
X leave point just before HEAD. That is, leave the cursor at the beginning
X of HEAD. If the line before HEAD is BLANK, then leave the cursor at the
X beginning of that line. If the cursor didn't move, go up to the first
X earlier non-BLANK line and start over.
X
X
X End of Algorithm. I implemented rule 6+ because it seemed nicer. */
X
Xint RMargin = 78,
X LMargin = 0;
XLine *para_head,
X *para_tail;
Xint head_indent,
X body_indent;
Xstatic int use_lmargin;
X
X/* some defines for paragraph boundery checking */
X#define I_EMPTY -1 /* line "looks" empty (spaces and tabs) */
X#define I_PERIOD -2 /* line begins with "." or "\" */
X#define I_BUFEDGE -3 /* line is nonexistent (edge of buffer) */
X
Xstatic int bslash; /* Nonzero if get_indent finds line starting
X with backslash */
X
Xi_bsblank(lp)
XLine *lp;
X{
X if (i_blank(lp))
X return 1;
X return bslash;
X}
X
Xi_blank(lp)
XLine *lp;
X{
X return (get_indent(lp) < 0);
X}
X
Xstatic
Xget_indent(lp)
Xregister Line *lp;
X{
X Bufpos save;
X register int indent;
X
X bslash = 0;
X if (lp == 0)
X return I_BUFEDGE;
X DOTsave(&save);
X SetLine(lp);
X if (blnkp(linebuf))
X indent = I_EMPTY;
X else if (linebuf[0] == '.')
X indent = I_PERIOD;
X else if (linebuf[0] == '\\') {
X /* BH 12/24/85. Backslash is BLANK only if next line
X also starts with Backslash. */
X bslash++;
X SetLine(lp->l_next);
X if (linebuf[0] == '\\')
X indent = I_PERIOD;
X else
X indent = 0;
X } else {
X ToIndent();
X indent = calc_pos(linebuf, curchar);
X }
X SetDot(&save);
X
X return indent;
X}
X
Xstatic Line *
Xtailrule(lp)
Xregister Line *lp;
X{
X int i;
X
X i = get_indent(lp);
X if (i < 0)
X return lp; /* one line paragraph */
X do {
X if ((get_indent(lp->l_next) != i) || bslash)
X /* BH line with backslash is head of next para */
X break;
X } while ((lp = lp->l_next) != 0);
X if (lp == 0)
X complain((char *) 0);
X return lp;
X}
X
X/* Finds the beginning, end and indent of the current paragraph, and sets
X the above global variables. HOW says how to behave when we're between
X paragraphs. That is, it's either FORWARD or BACKWARD depending on which
X way we're favoring. */
X
Xfind_para(how)
X{
X Line *this,
X *prev,
X *next,
X *head = 0,
X *body = 0,
X *tail = 0;
X int this_indent;
X Bufpos orig; /* remember where we were when we started */
X
X exp = 1;
X DOTsave(&orig);
Xstrt:
X this = curline;
X prev = curline->l_prev;
X next = curline->l_next;
X this_indent = get_indent(this);
X
X if (i_blank(this)) { /* rule 1 */
X if (how == BACKWARD) {
X while (i_blank(curline))
X if (firstp(curline))
X complain((char *) 0);
X else
X line_move(BACKWARD, NO);
X goto strt;
X } else {
X while (i_blank(curline))
X if (lastp(curline))
X complain((char *) 0);
X else
X line_move(FORWARD, NO);
X head = curline;
X next = curline->l_next;
X if (!i_bsblank(next))
X body = next;
X else
X body = head;
X }
X } else if (i_bsblank(this) || i_blank(prev)) { /* rule 2 */
X head = this;
X if (!i_bsblank(next))
X body = next;
X } else if (i_bsblank(next)) { /* rule 3 */
X tail = this;
X body = this;
X } else if ((get_indent(next) == this_indent) || /* rule 4 */
X (get_indent(prev) == this_indent))
X body = this;
X else { /* rule 6+ */
X if (get_indent(prev) > this_indent) {
X /* hanging indent maybe? */
X if ((next != 0) &&
X (get_indent(next) == get_indent(next->l_next))) {
X head = this;
X body = next;
X }
X }
X /* Now we handle hanging indent else and the other
X case of this_indent > get_indent(prev). That is,
X if we didn't resolve HEAD in the above if, then
X we are not a hanging indent. */
X if (head == 0) { /* still don't know */
X if (this_indent > get_indent(prev))
X head = this;
X else
X head = prev;
X body = head->l_next;
X }
X }
X /* rule 5 -- find the missing parts */
X if (head == 0) { /* haven't found head of paragraph so do so now */
X Line *lp;
X int i;
X
X lp = this;
X do {
X i = get_indent(lp->l_prev);
X if (i < 0) /* is blank */
X head = lp;
X else if (i != this_indent || bslash) {
X Line *this = lp->l_prev;
X
X if (get_indent(this->l_prev) == i)
X head = this->l_next;
X else
X head = this;
X }
X } while (head == 0 && (lp = lp->l_prev) != 0);
X if (lp == 0)
X complain((char *) 0);
X }
X if (body == 0) /* this must be a one line paragraph */
X body = head;
X if (tail == 0)
X tail = tailrule(body);
X if (tail == 0 || head == 0 || body == 0)
X complain("BUG! tail(%d),head(%d),body(%d)!", tail, head, body);
X para_head = head;
X para_tail = tail;
X head_indent = get_indent(head);
X body_indent = get_indent(body);
X
X SetDot(&orig);
X}
X
XJustify()
X{
X use_lmargin = (exp_p != NO);
X find_para(BACKWARD);
X DoJustify(para_head, 0, para_tail, length(para_tail), NO,
X use_lmargin ? LMargin : body_indent);
X}
X
XLine *
Xmax_line(l1, l2)
XLine *l1,
X *l2;
X{
X if (inorder(l1, 0, l2, 0))
X return l2;
X return l1;
X}
X
XLine *
Xmin_line(l1, l2)
XLine *l1,
X *l2;
X{
X if (inorder(l1, 0, l2, 0))
X return l1;
X return l2;
X}
X
XRegJustify()
X{
X Mark *mp = CurMark(),
X *tailmark;
X Line *l1 = curline,
X *l2 = mp->m_line;
X int c1 = curchar,
X c2 = mp->m_char;
X Line *rl1,
X *rl2;
X
X use_lmargin = (exp_p != NO);
X (void) fixorder(&l1, &c1, &l2, &c2);
X do {
X DotTo(l1, c1);
X find_para(FORWARD);
X rl1 = max_line(l1, para_head);
X rl2 = min_line(l2, para_tail);
X tailmark = MakeMark(para_tail, 0, FLOATER);
X DoJustify(rl1, (rl1 == l1) ? c1 : 0, rl2,
X (rl2 == l2) ? c2 : length(rl2),
X NO, use_lmargin ? LMargin : body_indent);
X l1 = tailmark->m_line->l_next;
X DelMark(tailmark);
X c1 = 0;
X } while (l1 != 0 && l2 != rl2);
X}
X
Xdo_rfill()
X{
X Mark *mp = CurMark();
X Line *l1 = curline,
X *l2 = mp->m_line;
X int c1 = curchar,
X c2 = mp->m_char;
X
X use_lmargin = (exp_p != NO);
X (void) fixorder(&l1, &c1, &l2, &c2);
X DoJustify(l1, c1, l2, c2, NO, use_lmargin ? LMargin : 0);
X}
X
Xdo_space()
X{
X int c1 = curchar,
X c2 = c1,
X diff,
X nspace;
X char ch;
X
X while (c1 > 0 && ((ch = linebuf[c1 - 1]) == ' ' || ch == '\t'))
X c1--;
X while ((ch = linebuf[c2]) == ' ' || ch == '\t')
X c2++;
X diff = (c2 - c1);
X curchar = c2;
X
X if (diff == 0)
X return;
X if (c1 > 0) {
X int topunct = c1 - 1;
X
X nspace = 1;
X if (diff >= 2) {
X while (index("\")]", linebuf[topunct])) {
X if (topunct == 0)
X break;
X topunct--;
X }
X if (index("?!.:", linebuf[topunct]))
X nspace = 2;
X }
X } else
X nspace = 0;
X
X if (diff > nspace)
X DoTimes(DelPChar(), (diff - nspace));
X else if (diff < nspace)
X DoTimes(Insert(' '), (nspace - diff));
X}
X
XDoJustify(l1, c1, l2, c2, scrunch, indent)
XLine *l1,
X *l2;
X{
X int okay_char = -1;
X char *cp;
X Mark *savedot = MakeMark(curline, curchar, FLOATER),
X *endmark;
X
X exp = 1;
X (void) fixorder(&l1, &c1, &l2, &c2); /* l1/c1 will be before l2/c2 */
X DotTo(l1, c1);
X if (get_indent(l1) >= c1) {
X if (use_lmargin) {
X n_indent(indent + (head_indent - body_indent));
X use_lmargin = 0; /* turn this off now */
X }
X ToIndent();
X }
X endmark = MakeMark(l2, c2, FLOATER);
X
X for (;;) {
X cp = StrIndex(1, linebuf, curchar, ' ');
X if (cp == 0)
X Eol();
X else
X curchar = (cp - linebuf);
X if (curline == endmark->m_line && curchar >= endmark->m_char)
X goto outahere;
X if (eolp()) {
X ins_str(" ", NO);
X DelNChar(); /* delete line separator */
X curchar -= 2; /* back over the spaces */
X }
X /* at this point we are ALWAYS sitting right after
X a word - that is, just before some spaces or the
X end of the line */
X if (calc_pos(linebuf, curchar) <= RMargin) {
X okay_char = curchar;
X do_space();
X continue;
X }
X
X /* if we get here, we have done all we can for
X this line - now we split the line, or just move
X to the next one */
X if (okay_char > 0)
X curchar = okay_char;
X if (curline == endmark->m_line && curchar >= endmark->m_char)
X goto outahere;
X /* can't fit in small margin, so we do the best we can */
X if (eolp()) {
X line_move(FORWARD, NO);
X n_indent(indent);
X } else {
X /* insert a line break - line WAS too long */
X DelWtSpace();
X LineInsert(1);
X if (scrunch && TwoBlank()) {
X Eol();
X DelNChar();
X }
X n_indent(indent);
X }
X }
Xoutahere:
X ToMark(savedot); /* Back to where we were */
X DelMark(endmark); /* Free up marks */
X DelMark(savedot);
X this_cmd = last_cmd = 0; /* So everything is under control */
X f_mess("");
X}
X
Xextern Line *para_head,
X *para_tail;
X
XDoPara(dir)
X{
X register int num = exp,
X first_time = TRUE;
X
X while (--num >= 0) {
Xtryagain: find_para(dir); /* find paragraph bounderies */
X if ((dir == BACKWARD) &&
X ((!first_time) || ((para_head == curline) && bolp()))) {
X if (bobp())
X complain((char *) 0);
X BackChar();
X first_time = !first_time;
X goto tryagain;
X }
X SetLine((dir == BACKWARD) ? para_head : para_tail);
X if (dir == BACKWARD && !firstp(curline) &&
X i_blank(curline->l_prev))
X line_move(BACKWARD, NO);
X else if (dir == FORWARD) {
X if (lastp(curline)) {
X Eol();
X break;
X }
X /* otherwise */
X line_move(FORWARD, NO);
X }
X }
X}
X
XBackPara()
X{
X DoPara(BACKWARD);
X}
X
XForPara()
X{
X DoPara(FORWARD);
X}
@//E*O*F paragraph.c//
if test 13888 -ne "`wc -c <'paragraph.c'`"; then
echo shar: error transmitting "'paragraph.c'" '(should have been 13888 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'portsrv.c'" '(3209 characters)'
if test -f 'portsrv.c' ; then
echo shar: will not over-write existing file "'portsrv.c'"
else
sed 's/^X//' >portsrv.c <<'@//E*O*F portsrv.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/* This is a server for jove sub processes. It runs the command and
X signals jove when there is some output ready to send to jove. By the
X time we get here, out standard output goes to jove's process input. */
X
X#include "tune.h"
X
X#ifdef PIPEPROCS /* the whole file! */
X
X#include "jove.h"
X
X#include <signal.h>
X#include <sys/ioctl.h>
X#ifdef BSD4_2
X# include <sys/wait.h>
X#else
X# include <wait.h>
X#endif
X
Xstruct header {
X int pid;
X int nbytes;
X char buf[512];
X} header;
X
X#define HEADSIZE ((sizeof header.pid) + sizeof (header.nbytes))
X
Xerror(str)
Xchar *str;
X{
X header.pid = getpid();
X header.nbytes = strlen(str);
X strcpy(header.buf, str);
X proc_write(&header, header.nbytes + 8);
X exit(-2);
X}
X
Xint ppid,
X InputFD,
X JovesInput;
X
Xp_inform()
X{
X long nbytes;
X
X ioctl(JovesInput, FIONREAD, (char *) &nbytes);
X if (nbytes > 0)
X kill(ppid, INPUT_SIG);
X}
X
Xproc_write(ptr, n)
Xchar *ptr;
X{
X long nbytes;
X
X ioctl(1, FIONREAD, (char *) &nbytes);
X
X if (nbytes == 0)
X kill(ppid, INPUT_SIG);
X
X (void) write(1, ptr, n);
X alarm(1);
X}
X
Xread_pipe()
X{
X register int n;
X
X (void) signal(SIGALRM, p_inform);
X
X while ((header.nbytes = read(InputFD, header.buf, sizeof header.buf)) > 0) {
X n = HEADSIZE + header.nbytes;
X proc_write(&header, n);
X }
X}
X
X/* ARGSUSED */
Xmain(argc, argv)
Xchar *argv[];
X{
X int p[2];
X int pid;
X
X if (pipe(p) == -1)
X error("Cannot pipe jove portsrv.\n");
X
X ppid = getppid();
X switch (pid = fork()) {
X case -1:
X error("portsrv: cannot fork.\n");
X
X case 0:
X /* We'll intercept childs output in p[0] */
X (void) dup2(p[1], 1);
X (void) dup2(p[1], 2);
X (void) close(p[0]);
X (void) close(p[1]);
X
X (void) setpgrp(getpid(), getpid());
X execv(argv[2], &argv[3]);
X _exit(-4);
X
X default:
X (void) close(0);
X /* Don't want this guy to read anything
X jove sends to our soon to be created
X child */
X
X JovesInput = atoi(argv[1]);
X (void) signal(SIGINT, SIG_IGN);
X (void) signal(SIGQUIT, SIG_IGN);
X (void) close(p[1]);
X
X /* Tell jove the pid of the real child as opposed to us. */
X header.pid = getpid();
X header.nbytes = sizeof (int);
X *(int *) header.buf = pid;
X (void) write(1, (char *) &header, sizeof pid + HEADSIZE);
X p_inform(); /* Inform jove */
X
X /* Read proc's output and send it to jove */
X InputFD = p[0];
X read_pipe();
X (void) close(p[0]);
X header.pid = getpid();
X header.nbytes = EOF; /* Tell jove we are finished */
X (void) write(1, (char *) &header, HEADSIZE);
X p_inform();
X /* Try to exit like our child did ... */
X {
X union wait w;
X
X#ifndef VMUNIX
X while (wait2(&w.w_status, 0) != pid)
X#else
X while (wait3(&w.w_status, 0, 0) != pid)
X#endif
X ;
X if (WIFEXITED(w))
X exit(w.w_retcode);
X else if (WIFSIGNALED(w))
X kill(getpid(), w.w_termsig);
X }
X }
X}
X
X#else PIPEPROCS
Xmain()
X{
X}
X#endif
@//E*O*F portsrv.c//
if test 3209 -ne "`wc -c <'portsrv.c'`"; then
echo shar: error transmitting "'portsrv.c'" '(should have been 3209 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'proc.c'" '(14390 characters)'
if test -f 'proc.c' ; then
echo shar: will not over-write existing file "'proc.c'"
else
sed 's/^X//' >proc.c <<'@//E*O*F proc.c//'
X/************************************************************************
X * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is *
X * provided to you without charge, and with no warranty. You may give *
X * away copies of JOVE, including sources, provided that this notice is *
X * included in all the files. *
X ************************************************************************/
X
X#include "jove.h"
X#include "io.h"
X#include "termcap.h"
X
X#include <signal.h>
X#include <varargs.h>
X
X/* This disgusting RE search string parses output from the GREP
X family, from the pdp11 compiler, pcc, and lint. Jay (HACK)
X Fenlasen changed this to work for the lint errors. */
Xprivate char
X *errfmt = "^\\{\",\\}\\([^:\"( \t]*\\)\\{\"\\, line ,:,(\\} *\\([0-9][0-9]*\\)[:)]\
X\\|:: *\\([^(]*\\)(\\([0-9]*\\))$\
X\\|( \\([^(]*\\)(\\([0-9]*\\)) ),";
X
Xstruct error {
X Buffer *er_buf; /* Buffer error is in */
X Line *er_mess, /* Actual error message */
X *er_text; /* Actual error */
X int er_char; /* char pos of error */
X struct error *er_prev, /* List of errors */
X *er_next;
X};
X
Xstruct error *cur_error = 0,
X *errorlist = 0;
XBuffer *perr_buf = 0; /* Buffer with error messages */
X
Xint WtOnMk = 1; /* Write the modified files when we make */
X
X/* Add an error to the end of the list of errors. This is used for
X parse-{C,LINT}-errors and for the spell-buffer command */
X
Xprivate struct error *
XAddError(laste, errline, buf, line, charpos)
Xstruct error *laste;
XLine *errline,
X *line;
XBuffer *buf;
X{
X struct error *new = (struct error *) emalloc(sizeof *new);
X
X new->er_prev = laste;
X if (laste)
X laste->er_next = new;
X else {
X if (errorlist) /* Free up old errors */
X ErrFree();
X cur_error = errorlist = new;
X }
X laste = new;
X new->er_next = 0;
X new->er_buf = buf;
X new->er_text = line;
X new->er_char = charpos;
X new->er_mess = errline;
X
X return new;
X}
X
XParseAll()
X{
X ErrParse(errfmt);
X}
X
XXParse()
X{
X char *sstr;
X
X sstr = ask(errfmt, ProcFmt);
X ErrParse(sstr);
X}
X
X/* Parse for {C,LINT} errors (or anything that matches fmtstr) in the
X current buffer. Set up for the next-error command. This is neat
X because this will work for any kind of output that prints a file
X name and a line number on the same line. */
X
XErrParse(fmtstr)
Xchar *fmtstr;
X{
X Bufpos *bp;
X char fname[FILESIZE],
X lineno[10],
X REbuf[256],
X *REalts[10];
X int lnum,
X last_lnum = -1;
X struct error *ep = 0;
X Buffer *buf,
X *lastb = 0;
X Line *err_line;
X
X ErrFree(); /* This is important! */
X ToFirst();
X perr_buf = curbuf;
X REcompile(fmtstr, 1, REbuf, REalts);
X /* Find a line with a number on it. */
X while (bp = docompiled(FORWARD, REbuf, REalts)) {
X SetDot(bp);
X putmatch(1, fname, sizeof fname);
X putmatch(2, lineno, sizeof lineno);
X buf = do_find((Window *) 0, fname, 1);
X if (buf != lastb) {
X lastb = buf;
X last_lnum = -1; /* signals new file */
X err_line = buf->b_first;
X }
X lnum = chr_to_int(lineno, 10, 0);
X if (lnum == last_lnum) /* one error per line is nicer */
X continue;
X if (last_lnum == -1)
X last_lnum = 1; /* that's where we really are */
X err_line = next_line(err_line, lnum - last_lnum);
X ep = AddError(ep, curline, buf, err_line, 0);
X last_lnum = lnum;
X }
X if (cur_error != 0)
X ShowErr();
X exp = 1;
X}
X
X/* Free up all the errors */
X
XErrFree()
X{
X register struct error *ep;
X
X for (ep = errorlist; ep != 0; ep = ep->er_next)
X free((char *) ep);
X errorlist = cur_error = 0;
X}
X
X/* Internal next error sets cur_error to the next error, taking the
X argument count, supplied by the user, into consideration. */
X
Xprivate char errbounds[] = "You're at the %s error.",
X noerrs[] = "No errors!";
X
Xprivate
Xtoerror(forward)
X{
X register int i;
X register struct error *e = cur_error;
X
X if (e == 0)
X complain(noerrs);
X if ((forward && (e->er_next == 0)) ||
X (!forward && (e->er_prev == 0)))
X complain(errbounds, forward ? "last" : "first");
X
X for (i = 0; i < exp; i++) {
X if ((e = forward ? e->er_next : e->er_prev) == 0)
X break;
X cur_error = e;
X }
X}
X
XNextError()
X{
X ToError(1);
X}
X
XPrevError()
X{
X ToError(0);
X}
X
Xprivate
Xokay_error()
X{
X return ((inlist(perr_buf->b_first, cur_error->er_mess)) &&
X (inlist(cur_error->er_buf->b_first, cur_error->er_text)));
X}
X
X/* Go the the next error, if there is one. Put the error buffer in
X one window and the buffer with the error in another window.
X It checks to make sure that the error actually exists. */
X
XToError(forward)
X{
X do {
X toerror(forward);
X exp = 1;
X } while (!okay_error());
X ShowErr();
X}
X
Xint EWSize = 20; /* percentage of screen the error window
X should be */
X
Xset_wsize(wsize)
Xint wsize;
X{
X wsize = (LI * wsize) / 100;
X if (wsize >= 1 && !one_windp())
X WindSize(curwind, wsize - (curwind->w_height - 1));
X}
X
X/* Show the current error, i.e. put the line containing the error message
X in one window, and the buffer containing the actual error in another
X window. */
X
XShowErr()
X{
X Window *err_wind,
X *buf_wind;
X
X if (cur_error == 0)
X complain(noerrs);
X if (!okay_error()) {
X rbell();
X return;
X }
X err_wind = windbp(perr_buf);
X buf_wind = windbp(cur_error->er_buf);
X
X if (err_wind && !buf_wind) {
X SetWind(err_wind);
X pop_wind(cur_error->er_buf->b_name, NO, -1);
X buf_wind = curwind;
X } else if (!err_wind && buf_wind) {
X SetWind(buf_wind);
X pop_wind(perr_buf->b_name, NO, -1);
X err_wind = curwind;
X } else if (!err_wind && !buf_wind) {
X pop_wind(perr_buf->b_name, NO, -1);
X err_wind = curwind;
X pop_wind(cur_error->er_buf->b_name, NO, -1);
X buf_wind = curwind;
X }
X
X /* Put the current error message at the top of its Window */
X SetWind(err_wind);
X SetLine(cur_error->er_mess);
X SetTop(curwind, (curwind->w_line = cur_error->er_mess));
X set_wsize(EWSize);
X
X /* now go to the the line with the error in the other window */
X SetWind(buf_wind);
X DotTo(cur_error->er_text, cur_error->er_char);
X}
X
Xchar ShcomBuf[128] = {0};
X
X/* Make a buffer name given the command `command', i.e. "fgrep -n foo *.c"
X will return the buffer name "fgrep". */
X
Xchar *
XMakeName(command)
Xchar *command;
X{
X static char bufname[50];
X register char *cp = bufname,
X c;
X
X while ((c = *command++) && (c == ' ' || c == '\t'))
X ;
X do
X *cp++ = c;
X while ((c = *command++) && (c != ' ' && c != '\t'));
X *cp = 0;
X strcpy(bufname, basename(bufname));
X
X return bufname;
X}
X
X/* Run make, first writing all the modified buffers (if the WtOnMk flag is
X non-zero), parse the errors, and go the first error. */
X
Xchar make_cmd[128] = "make";
X
XMakeErrors()
X{
X Window *old = curwind;
X int status,
X compilation;
X
X if (WtOnMk)
X put_bufs(0);
X /* When we're not doing make or cc (i.e., the last command
X was probably a grep or something) and the user just types
X C-X C-E, he probably (possibly, hopefully, usually (in my
X case)) doesn't want to do the grep again but rather wants
X to do a make again; so we ring the bell and insert the
X default command and let the person decide. */
X
X compilation = (sindex("make", make_cmd) || sindex("cc", make_cmd));
X if (exp_p || !compilation) {
X if (!compilation) {
X rbell();
X Inputp = make_cmd; /* insert the default for the
X user */
X }
X null_ncpy(make_cmd, ask(make_cmd, "Compilation command: "),
X sizeof (make_cmd) - 1);
X }
X status = UnixToBuf(MakeName(make_cmd), YES, EWSize, YES, Shell, ShFlags, make_cmd, (char *) 0);
X com_finish(status, make_cmd);
X
X ErrParse(errfmt);
X
X if (!cur_error)
X SetWind(old);
X}
X
X#ifdef SPELL
X
XSpelBuffer()
X{
X char *Spell = "Spell",
X com[100];
X Window *savewp = curwind;
X
X put_bufs(0);
X sprintf(com, "spell %s", curbuf->b_fname);
X (void) UnixToBuf(Spell, YES, EWSize, YES, Shell, ShFlags, com, (char *) 0);
X message("[Delete the irrelevant words and then type C-X C-C]");
X Recur();
X SetWind(savewp);
X SpelParse(Spell);
X}
X
XSpelWords()
X{
X char *buftospel;
X Buffer *wordsb = curbuf;
X
X if ((buftospel = ask_buf((Buffer *) 0)) == 0)
X return;
X SetBuf(do_select(curwind, buftospel));
X SpelParse(wordsb->b_name);
X}
X
XSpelParse(bname)
Xchar *bname;
X{
X Buffer *buftospel,
X *wordsb;
X char wordspel[100];
X Bufpos *bp;
X struct error *ep = 0;
X
X ErrFree(); /* This is important! */
X
X buftospel = curbuf;
X wordsb = buf_exists(bname);
X perr_buf = wordsb; /* This is important (buffer containing
X error messages) */
X SetBuf(wordsb);
X ToFirst();
X f_mess("Finding misspelled words ... ");
X while (!lastp(curline)) {
X sprintf(wordspel, "\\<%s\\>", linebuf);
X SetBuf(buftospel);
X ToFirst();
X while (bp = dosearch(wordspel, 1, 1)) {
X SetDot(bp);
X ep = AddError(ep, wordsb->b_dot, buftospel,
X curline, curchar);
X }
X SetBuf(wordsb);
X line_move(FORWARD, NO);
X }
X add_mess("Done.");
X SetBuf(buftospel);
X ShowErr();
X}
X
X#endif SPELL
X
XShToBuf()
X{
X char bufname[100];
X
X strcpy(bufname, ask((char *) 0, "Buffer: "));
X DoShell(bufname, ask(ShcomBuf, "Command: "));
X}
X
XShellCom()
X{
X null_ncpy(ShcomBuf, ask(ShcomBuf, ProcFmt), (sizeof ShcomBuf) - 1);
X DoShell(MakeName(ShcomBuf), ShcomBuf);
X}
X
X/* Run the shell command into `bufname'. Empty the buffer except when we
X give a numeric argument, in which case it inserts the output at the
X current position in the buffer. */
X
Xprivate
XDoShell(bufname, command)
Xchar *bufname,
X *command;
X{
X Window *savewp = curwind;
X int status;
X
X exp = 1;
X status = UnixToBuf(bufname, YES, 0, !exp_p, Shell,
X ShFlags, command, (char *) 0);
X com_finish(status, command);
X SetWind(savewp);
X}
X
Xprivate
Xcom_finish(status, cmd)
Xregister int status;
Xchar *cmd;
X{
X s_mess("[%s: ", cmd);
X if (status == 0)
X add_mess("completed successfully");
X else
X add_mess("exited (%d)", status);
X add_mess("]");
X}
X
Xdowait(pid, status)
Xint pid,
X *status;
X{
X#ifndef IPROCS
X
X int rpid;
X
X while ((rpid = wait(status)) != pid)
X ;
X#else
X
X#ifdef BSD4_2
X# include <sys/wait.h>
X#else
X# include <wait.h>
X#endif
X
X union wait w;
X int rpid;
X
X for (;;) {
X#ifndef VMUNIX
X rpid = wait2(&w.w_status, 0);
X#else
X rpid = wait3(&w, 0, (struct rusage *) 0);
X#endif
X if (rpid == pid) {
X if (status)
X *status = w.w_status;
X break;
X } else
X kill_off(rpid, w);
X }
X#endif IPROCS
X}
X
X/* Run the command to bufname, erase the buffer if clobber is non-zero,
X and redisplay if disp is non-zero. Leaves current buffer in `bufname'
X and leaves any windows it creates lying around. It's up to the caller
X to fix everything up after we're done. (Usually there's nothing to
X fix up.) */
X
X/* VARARGS5 */
X
XUnixToBuf(bufname, disp, wsize, clobber, va_alist)
Xchar *bufname;
Xva_dcl
X{
X int p[2],
X pid,
X eof,
X status;
X va_list ap;
X char *argv[32],
X *mess;
X File *fp;
X int (*old_int)();
X
X va_start(ap);
X make_argv(argv, ap);
X va_end(ap);
X if (clobber)
X isprocbuf(bufname);
X if (disp) {
X message("Starting up...");
X pop_wind(bufname, clobber, clobber ? B_PROCESS : B_FILE);
X set_wsize(wsize);
X redisplay();
X }
X /* Now I will attempt to describe how I deal with signals during
X the execution of the shell command. My desire was to be able
X to interrupt the shell command AS SOON AS the window pops up.
X So, if we have JOB_CONTROL (i.e., the new signal mechanism) I
X hold SIGINT, meaning if we interrupt now, we will eventually
X see the interrupt, but not before we are ready for it. We
X fork, the child releases the interrupt, it then sees the
X interrupt, and so exits. Meanwhile the parent ignores the
X signal, so if there was a pending one, it's now lost.
X
X With no JOB_CONTROL, the best behavior you can expect is, when
X you type ^] too very quickly after the window pops up, it may
X be ignored. The behavior BEFORE was that it would interrupt
X JOVE and then you would have to continue JOVE and wait a
X little while longer before trying again. Now that is fixed,
X in that you just have to type it twice. */
X
X#ifdef IPROCS
X sighold(SIGCHLD);
X#endif
X#ifdef JOB_CONTROL
X sighold(SIGINT);
X#else
X old_int = signal(SIGINT, SIG_IGN),
X#endif
X exp = 1;
X dopipe(p);
X pid = fork();
X if (pid == -1) {
X pclose(p);
X complain("[Fork failed]");
X }
X if (pid == 0) {
X#ifdef IPROCS
X sigrelse(SIGCHLD); /* don't know if this matters */
X#endif IPROCS
X (void) signal(SIGINT, SIG_DFL);
X#ifdef JOB_CONTROL
X sigrelse(SIGINT);
X#endif
X (void) close(0);
X (void) open("/dev/null", 0);
X (void) close(1);
X (void) close(2);
X (void) dup(p[1]);
X (void) dup(p[1]);
X pclose(p);
X execv(argv[0], &argv[1]);
X (void) write(1, "Execl failed.\n", 14);
X _exit(1);
X }
X#ifdef JOB_CONTROL
X old_int = signal(SIGINT, SIG_IGN);
X#endif
X (void) close(p[1]);
X fp = fd_open(argv[1], F_READ, p[0], iobuff, LBSIZE);
X do {
X inIOread = 1;
X eof = f_gets(fp, genbuf, LBSIZE);
X inIOread = 0;
X ins_str(genbuf, YES);
X if (!eof)
X LineInsert(1);
X if (disp != 0 && fp->f_cnt <= 0) {
X#ifdef LOAD_AV
X {
X double theavg;
X
X get_la(&theavg);
X if (theavg < 2.0)
X mess = "Screaming along...";
X else if (theavg < 5.0)
X mess = "Chugging along...";
X else
X mess = "Crawling along...";
X }
X#else
X mess = "Chugging along...";
X#endif LOAD_AV
X message(mess);
X redisplay();
X }
X } while (!eof);
X if (disp)
X DrawMesg(NO);
X close_file(fp);
X dowait(pid, &status);
X#ifdef JOB_CONTROL
X (void) sigrelse(SIGINT);
X#endif
X (void) signal(SIGINT, old_int);
X#ifdef IPROCS
X sigrelse(SIGCHLD);
X#endif
X return status;
X}
X
X#ifdef BSD4_2
X
Xprivate int SigMask = 0;
X
Xsighold(sig)
X{
X (void) sigblock(SigMask |= (1 << (sig - 1)));
X}
X
Xsigrelse(sig)
X{
X (void) sigsetmask(SigMask &= ~(1 << (sig - 1)));
X}
X
X#endif
X
XFilterRegion()
X{
X char *cmd = ask((char *) 0, ": %f (through command) ", ProcFmt);
X
X RegToUnix(curbuf, cmd);
X}
X
X/* Send the current region to CMD and insert the output from the
X command into OUT_BUF. */
X
XRegToUnix(outbuf, cmd)
XBuffer *outbuf;
Xchar *cmd;
X{
X Mark *m = CurMark();
X char *tname = mktemp("/tmp/jfilterXXXXXX"),
X combuf[130];
X Window *save_wind = curwind;
X int status;
X File *fp;
X
X CATCH
X fp = open_file(tname, iobuff, F_WRITE, COMPLAIN, QUIET);
X putreg(fp, m->m_line, m->m_char, curline, curchar, YES);
X DelReg();
X sprintf(combuf, "%s < %s", cmd, tname);
X status = UnixToBuf(outbuf->b_name, NO, 0, outbuf->b_type == B_SCRATCH,
X Shell, ShFlags, combuf, (char *) 0);
X ONERROR
X ; /* Do nothing ... but fall through and delete the tmp
X file. */
X ENDCATCH
X f_close(fp);
X (void) unlink(tname);
X SetWind(save_wind);
X com_finish(status, combuf);
X}
X
Xisprocbuf(bufname)
Xchar *bufname;
X{
X Buffer *bp;
X
X if ((bp = buf_exists(bufname)) != 0 && bp->b_type != B_PROCESS)
X confirm("Over-write buffer %s?", bufname);
X}
@//E*O*F proc.c//
if test 14390 -ne "`wc -c <'proc.c'`"; then
echo shar: error transmitting "'proc.c'" '(should have been 14390 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'re1.c'" '(9617 characters)'
if test -f 're1.c' ; then
echo shar: will not over-write existing file "'re1.c'"
else
sed 's/^X//' >re1.c <<'@//E*O*F re1.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 "re.h"
X
Xstatic
Xsubstitute(query, l1, char1, l2, char2)
XLine *l1,
X *l2;
X{
X Line *lp;
X int numdone = 0,
X offset = curchar,
X stop = 0;
X disk_line UNDO_da = 0;
X Line *UNDO_lp = 0;
X
X lsave();
X REdirection = FORWARD;
X
X lp = l1;
X for (lp = l1; (lp != l2->l_next) && !stop; lp = lp->l_next) {
X offset = (lp == l1) ? char1 : 0;
X while (!stop && re_lindex(lp, offset, compbuf, alternates, 0)) {
X if (lp == l2 && REeom > char2) /* nope, leave this alone */
X break;
X DotTo(lp, REeom);
X offset = curchar;
X if (query) {
X message("Replace (Type '?' for help)? ");
Xreswitch: redisplay();
X switch (Upper(getchar())) {
X case '.':
X stop++;
X /* Fall into ... */
X
X case ' ':
X case 'Y':
X break;
X
X case BS:
X case RUBOUT:
X case 'N':
X if (linebuf[offset++] == '\0')
X goto nxtline;
X continue;
X
X case CTL(W):
X re_dosub(linebuf, YES);
X numdone++;
X offset = curchar = REbom;
X makedirty(curline);
X /* Fall into ... */
X
X case CTL(R):
X case 'R':
X RErecur();
X offset = curchar;
X lp = curline;
X continue;
X
X case CTL(U):
X case 'U':
X if (UNDO_lp == 0)
X continue;
X lp = UNDO_lp;
X lp->l_dline = UNDO_da | DIRTY;
X offset = 0;
X numdone--;
X continue;
X
X case 'P':
X case '!':
X query = 0;
X break;
X
X case CR:
X case LF:
X case 'Q':
X goto done;
X
X case CTL(L):
X RedrawDisplay();
X goto reswitch;
X
X default:
X rbell();
Xmessage("Space or Y, Period, Rubout or N, C-R or R, C-W, C-U or U, P or !, Return.");
X goto reswitch;
X }
X }
X re_dosub(linebuf, NO);
X numdone++;
X modify();
X offset = curchar = REeom;
X makedirty(curline);
X if (query) {
X message(mesgbuf); /* No blinking. */
X redisplay(); /* Show the change. */
X }
X UNDO_da = curline->l_dline;
X UNDO_lp = curline;
X if (linebuf[offset] == 0)
Xnxtline: break;
X }
X }
X SetMark();
Xdone: s_mess("%d substitution%n.", numdone, numdone);
X}
X
X/* Prompt for search and replacement strings and do the substitution. The
X point is restored when we're done. */
X
Xstatic
Xreplace(query, inreg)
X{
X Mark *save = MakeMark(curline, curchar, FLOATER),
X *m;
X char *rep_ptr;
X Line *l1 = curline,
X *l2 = curbuf->b_last;
X int char1 = curchar,
X char2 = length(curbuf->b_last);
X
X if (inreg) {
X m = CurMark();
X l2 = m->m_line;
X char2 = m->m_char;
X (void) fixorder(&l1, &char1, &l2, &char2);
X }
X
X /* Get search string. */
X strcpy(rep_search, ask(rep_search[0] ? rep_search : (char *) 0, ProcFmt));
X REcompile(rep_search, UseRE, compbuf, alternates);
X /* Now the replacement string. Do_ask() so the user can play with
X the default (previous) replacement string by typing C-R in ask(),
X OR, he can just hit Return to replace with nothing. */
X rep_ptr = do_ask("\r\n", (int (*)()) 0, rep_str, ": %f %s with ", rep_search);
X if (rep_ptr == 0)
X rep_ptr = NullStr;
X strcpy(rep_str, rep_ptr);
X
X substitute(query, l1, char1, l2, char2);
X ToMark(save);
X DelMark(save);
X}
X
XRegReplace()
X{
X replace(0, YES);
X}
X
XQRepSearch()
X{
X replace(1, NO);
X}
X
XRepSearch()
X{
X replace(0, NO);
X}
X
X/* C tags package. */
X
Xstatic
Xlookup(searchbuf, filebuf, tag, file)
Xchar *searchbuf,
X *filebuf,
X *tag,
X *file;
X{
X register int taglen = strlen(tag);
X char line[128],
X pattern[100];
X File *fp;
X
X fp = open_file(file, iobuff, F_READ, !COMPLAIN, QUIET);
X if (fp == NIL)
X return 0;
X sprintf(pattern, "^%s[^\t]*\t\\([^\t]*\\)\t[?/]\\(.*\\)[?/]$", tag);
X while (f_gets(fp, line, sizeof line) != EOF) {
X if (line[0] != *tag || strncmp(tag, line, taglen) != 0)
X continue;
X if (!LookingAt(pattern, line, 0)) {
X complain("I thought I saw it!");
X break;
X } else {
X putmatch(2, searchbuf, 100);
X putmatch(1, filebuf, 100);
X close_file(fp);
X return 1;
X }
X }
X f_close(fp);
X s_mess("Can't find tag \"%s\".", tag);
X return 0;
X}
X
Xchar TagFile[128] = "./tags";
X
Xfind_tag(tag, localp)
Xchar *tag;
X{
X char filebuf[FILESIZE],
X sstr[100],
X tfbuf[FILESIZE];
X register Bufpos *bp;
X register Buffer *b;
X char *tagfname;
X
X if (!localp) {
X char prompt[128];
X
X sprintf(prompt, "With tag file (%s default): ", TagFile);
X tagfname = ask_file(prompt, TagFile, tfbuf);
X } else
X tagfname = TagFile;
X if (lookup(sstr, filebuf, tag, tagfname) == 0)
X return;
X SetMark();
X b = do_find(curwind, filebuf, 0);
X if (curbuf != b)
X SetABuf(curbuf);
X SetBuf(b);
X if ((bp = dosearch(sstr, BACKWARD, 0)) == 0 &&
X (WrapScan || ((bp = dosearch(sstr, FORWARD, 0)) == 0)))
X message("Well, I found the file, but the tag is missing.");
X else
X SetDot(bp);
X}
X
XFindTag()
X{
X int localp = !exp_p;
X char tag[128];
X
X strcpy(tag, ask((char *) 0, ProcFmt));
X find_tag(tag, localp);
X}
X
X/* Find Tag at Dot. */
X
XFDotTag()
X{
X int c1 = curchar,
X c2 = c1;
X char tagname[50];
X
X if (!ismword(linebuf[curchar]))
X complain("Not a tag!");
X while (c1 > 0 && ismword(linebuf[c1 - 1]))
X c1--;
X while (ismword(linebuf[c2]))
X c2++;
X
X null_ncpy(tagname, linebuf + c1, c2 - c1);
X find_tag(tagname, !exp_p);
X}
X
X/* I-search returns a code saying what to do:
X STOP: We found the match, so unwind the stack and leave
X where it is.
X DELETE: Rubout the last command.
X BACKUP: Back up to where the isearch was last NOT failing.
X
X When a character is typed it is appended to the search string, and
X then, isearch is called recursively. When C-S or C-R is typed, isearch
X is again called recursively. */
X
X#define STOP 1
X#define DELETE 2
X#define BACKUP 3
X#define TOSTART 4
X
Xstatic char ISbuf[128],
X *incp = 0;
Xint SExitChar = CR;
X
X#define cmp_char(a, b) ((a) == (b) || (CaseIgnore && (Upper(a) == Upper(b))))
X
Xstatic Bufpos *
Xdoisearch(dir, c, failing)
Xregister int c,
X dir,
X failing;
X{
X static Bufpos buf;
X Bufpos *bp;
X extern int okay_wrap;
X
X if (c == CTL(S) || c == CTL(R))
X goto dosrch;
X
X if (failing)
X return 0;
X DOTsave(&buf);
X if (dir == FORWARD) {
X if (cmp_char(linebuf[curchar], c)) {
X buf.p_char = curchar + 1;
X return &buf;
X }
X } else {
X if (look_at(ISbuf))
X return &buf;
X }
Xdosrch: okay_wrap = YES;
X if ((bp = dosearch(ISbuf, dir, 0)) == 0)
X rbell(); /* ring the first time there's no match */
X okay_wrap = NO;
X return bp;
X}
X
XIncFSearch()
X{
X IncSearch(FORWARD);
X}
X
XIncRSearch()
X{
X IncSearch(BACKWARD);
X}
X
Xstatic
XIncSearch(dir)
X{
X Bufpos save_env;
X
X DOTsave(&save_env);
X ISbuf[0] = 0;
X incp = ISbuf;
X if (isearch(dir, &save_env) == TOSTART)
X SetDot(&save_env);
X else {
X if (LineDist(curline, save_env.p_line) >= MarkThresh)
X DoSetMark(save_env.p_line, save_env.p_char);
X }
X setsearch(ISbuf);
X}
X
X/* Nicely recursive. */
X
Xstatic
Xisearch(dir, bp)
XBufpos *bp;
X{
X Bufpos pushbp;
X int c,
X ndir,
X failing;
X char *orig_incp;
X
X if (bp != 0) { /* Move to the new position. */
X pushbp.p_line = bp->p_line;
X pushbp.p_char = bp->p_char;
X SetDot(bp);
X failing = 0;
X } else {
X DOTsave(&pushbp);
X failing = 1;
X }
X orig_incp = incp;
X ndir = dir; /* Same direction as when we got here, unless
X we change it with C-S or C-R. */
X for (;;) {
X SetDot(&pushbp);
X message(NullStr);
X if (failing)
X add_mess("Failing ");
X if (dir == BACKWARD)
X add_mess("reverse-");
X add_mess("I-search: %s", ISbuf);
X DrawMesg(NO);
X add_mess(NullStr); /* tell me this is disgusting ... */
X c = getch();
X if (c == SExitChar)
X return STOP;
X switch (c) {
X case RUBOUT:
X case BS:
X return DELETE;
X
X case CTL(G):
X /* If we're failing, we backup until we're no longer
X failing or we've reached the beginning; else, we
X just about the search and go back to the start. */
X if (failing)
X return BACKUP;
X return TOSTART;
X
X case CTL(\\):
X c = CTL(S);
X case CTL(S):
X case CTL(R):
X /* If this is the first time through and we have a
X search string left over from last time, use that
X one now. */
X if (incp == ISbuf) {
X strcpy(ISbuf, getsearch());
X incp = &ISbuf[strlen(ISbuf)];
X }
X ndir = (c == CTL(S)) ? FORWARD : BACKWARD;
X /* If we're failing and we're not changing our
X direction, don't recur since there's no way
X the search can work. */
X if (failing && ndir == dir) {
X rbell();
X continue;
X }
X break;
X
X case '\\':
X if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
X rbell();
X continue;
X }
X *incp++ = '\\';
X add_mess("\\");
X /* Fall into ... */
X
X case CTL(Q):
X case CTL(^):
X add_mess("");
X c = getch() | 0400;
X /* Fall into ... */
X
X default:
X if (c & 0400)
X c &= 0177;
X else {
X if (c > RUBOUT || (c < ' ' && c != '\t')) {
X Ungetc(c);
X return STOP;
X }
X }
X if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
X rbell();
X continue;
X }
X *incp++ = c;
X *incp = 0;
X break;
X }
X add_mess("%s", orig_incp);
X add_mess(" ..."); /* so we know what's going on */
X DrawMesg(NO); /* do it now */
X switch (isearch(ndir, doisearch(ndir, c, failing))) {
X case TOSTART:
X return TOSTART;
X
X case STOP:
X return STOP;
X
X case BACKUP:
X /* If we're not failing, we just continue to to the
X for loop; otherwise we keep returning to the
X previous levels until we find one that isn't
X failing OR we reach the beginning. */
X if (failing)
X return BACKUP;
X /* Fall into ... */
X
X case DELETE:
X incp = orig_incp;
X *incp = 0;
X continue;
X }
X }
X}
@//E*O*F re1.c//
if test 9617 -ne "`wc -c <'re1.c'`"; then
echo shar: error transmitting "'re1.c'" '(should have been 9617 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'table.h'" '(870 characters)'
if test -f 'table.h' ; then
echo shar: will not over-write existing file "'table.h'"
else
sed 's/^X//' >table.h <<'@//E*O*F table.h//'
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
Xtypedef struct word Word;
Xtypedef struct table Table;
X
Xstruct word {
X Word *wd_next;
X char *wd_text;
X};
X
Xstruct table {
X Table *t_next;
X Word *t_wordlist;
X};
X
Xextern Table *make_table();
Xextern Word *word_in_table();
X
X#define table_top(table) (table->t_wordlist)
X#define next_word(w) (w->wd_next)
X#define last_word_p(w) (w->wd_next == NIL)
X#define word_text(w) (w->wd_text)
X#define word_length(w) (strlen(word_text(w)))
@//E*O*F table.h//
if test 870 -ne "`wc -c <'table.h'`"; then
echo shar: error transmitting "'table.h'" '(should have been 870 characters)'
fi
fi # end of overwriting check
echo shar: "End of archive 6 (of 13)."
cp /dev/null ark6isdone
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