|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T i
Length: 13582 (0x350e)
Types: TextFile
Names: »insert.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/euug-87hel/sec1/jove/insert.c«
/************************************************************************
* This program is Copyright (C) 1986 by Jonathan Payne. JOVE is *
* provided to you without charge, and with no warranty. You may give *
* away copies of JOVE, including sources, provided that this notice is *
* included in all the files. *
************************************************************************/
#include "jove.h"
#include "ctype.h"
#include "table.h"
/* Make a newline after AFTER in buffer BUF, UNLESS after is 0,
in which case we insert the newline before after. */
Line *
listput(buf, after)
register Buffer *buf;
register Line *after;
{
register Line *newline = nbufline();
if (after == 0) { /* Before the first line */
newline->l_next = buf->b_first;
newline->l_prev = 0;
buf->b_first = newline;
} else {
newline->l_prev = after;
newline->l_next = after->l_next;
after->l_next = newline;
}
if (newline->l_next)
newline->l_next->l_prev = newline;
else
if (buf)
buf->b_last = newline;
if (buf && buf->b_dot == 0)
buf->b_dot = newline;
return newline;
}
/* Divide the current line and move the current line to the next one */
LineInsert(num)
register int num;
{
char newline[LBSIZE];
register Line *newdot,
*olddot;
int oldchar;
olddot = curline;
oldchar = curchar;
newdot = curline;
while (--num >= 0) {
newdot = listput(curbuf, newdot);
SavLine(newdot, NullStr);
}
modify();
if (curchar != 0) {
strcpy(newline, &linebuf[curchar]);
linebuf[curchar] = '\0'; /* Shorten this line */
SavLine(curline, linebuf);
strcpy(linebuf, newline);
} else { /* Redisplay optimization */
newdot->l_dline = curline->l_dline;
SavLine(curline, NullStr);
}
makedirty(curline);
curline = newdot;
curchar = 0;
makedirty(curline);
IFixMarks(olddot, oldchar, curline, curchar);
}
/* Makes the indent of the current line == goal. If the current indent
is greater than GOAL it deletes. If more indent is needed, it uses
tabs and spaces to get to where it's going. */
n_indent(goal)
register int goal;
{
int dotcol,
incrmt;
ToIndent();
dotcol = calc_pos(linebuf, curchar);
if (goal < dotcol) {
DelWtSpace();
dotcol = 0;
}
for (;;) {
incrmt = (tabstop - (dotcol % tabstop));
if (dotcol + incrmt > goal)
break;
Insert('\t');
dotcol += incrmt;
}
if (dotcol != goal)
DoTimes(Insert(' '), (goal - dotcol));
exp_p = NO;
exp = 1;
}
SelfInsert()
{
#ifdef ABBREV
if (MinorMode(Abbrev) && !ismword(LastKeyStruck) &&
!bolp() && ismword(linebuf[curchar - 1]))
AbbrevExpand();
#endif
if (MinorMode(OverWrite)) {
register int num,
i;
for (i = 0, num = exp, exp = 1; i < num; i++) {
int pos = calc_pos(linebuf, curchar);
if (!eolp()) {
if (linebuf[curchar] == '\t') {
if ((pos + 1) == ((pos + tabstop) - (pos % tabstop)))
DelNChar();
} else
DelNChar();
}
Insert(LastKeyStruck);
}
} else
Insert(LastKeyStruck);
if (MinorMode(Fill) && (curchar >= RMargin ||
(calc_pos(linebuf, curchar) >= RMargin)))
DoJustify(curline, 0, curline,
curchar + strlen(&linebuf[curchar]), 1, LMargin);
}
Insert(c)
{
if (exp <= 0)
return;
modify();
makedirty(curline);
ins_c(c, linebuf, curchar, exp, LBSIZE);
IFixMarks(curline, curchar, curline, curchar + exp);
curchar += exp;
}
/* Tab in to the right place for C mode */
Tab()
{
#ifdef LISP
if (MajorMode(LISPMODE)) {
int dotchar = curchar;
Mark *m = 0;
ToIndent();
if (dotchar > curchar)
m = MakeMark(curline, dotchar, FLOATER);
(void) lisp_indent();
if (m) {
ToMark(m);
DelMark(m);
} else
ToIndent();
return;
}
#endif
if (MajorMode(CMODE) && strlen(linebuf) == 0)
(void) c_indent(CIndIncrmt);
else
SelfInsert();
}
QuotChar()
{
int c;
extern int alarmed; /* If waitfor had to wait. */
c = waitchar();
if (alarmed)
message(key_strokes);
if (c == CTL(J))
LineInsert(exp);
else if (c != CTL(@))
Insert(c);
}
/* Insert the paren. If in C mode and c is a '}' then insert the
'}' in the "right" place for C indentation; that is indented
the same amount as the matching '{' is indented. */
int PDelay = 5, /* 1/2 a second */
CIndIncrmt = 8;
DoParen()
{
Bufpos *bp = (Bufpos *) -1;
int nx,
c = LastKeyStruck;
if (!isclosep(c)) {
SelfInsert();
return;
}
if (MajorMode(CMODE) && c == '}' && blnkp(linebuf))
bp = c_indent(0);
#ifdef LISP
if (MajorMode(LISPMODE) && c == ')' && blnkp(linebuf))
bp = lisp_indent();
#endif
SelfInsert();
if (MinorMode(ShowMatch) && !charp() && !in_macro()) {
BackChar(); /* Back onto the ')' */
if ((int) bp == -1)
bp = m_paren(c, BACKWARD, NO, YES);
ForChar();
if (bp != 0) {
nx = in_window(curwind, bp->p_line);
if (nx != -1) { /* is visible */
Bufpos b;
DOTsave(&b);
SetDot(bp);
SitFor(PDelay);
SetDot(&b);
} else
s_mess("%s", lcontents(bp->p_line));
}
mp_error(); /* display error message */
}
}
LineAI()
{
DoNewline(TRUE);
}
Newline()
{
DoNewline(MinorMode(Indent));
}
DoNewline(indentp)
{
Bufpos save;
int indent;
/* first we calculate the indent of the current line */
DOTsave(&save);
ToIndent();
indent = calc_pos(linebuf, curchar);
SetDot(&save);
#ifdef ABBREV
if (MinorMode(Abbrev) && !ismword(LastKeyStruck) &&
!bolp() && ismword(linebuf[curchar - 1]))
AbbrevExpand();
#endif
#ifdef LISP
if (MajorMode(LISPMODE))
DelWtSpace();
#endif
else if (blnkp(linebuf))
DelWtSpace();
/* If there is more than 2 blank lines in a row then don't make
a newline, just move down one. */
if (exp == 1 && eolp() && TwoBlank())
SetLine(curline->l_next);
else
LineInsert(exp);
if (indentp)
#ifdef LISP
if (MajorMode(LISPMODE))
(void) lisp_indent();
else
#endif
n_indent((LMargin == 0) ? indent : LMargin);
}
ins_str(str, ok_nl)
register char *str;
{
register char c;
Bufpos save;
int llen;
if (*str == 0)
return; /* ain't nothing to insert! */
DOTsave(&save);
llen = strlen(linebuf);
while (c = *str++) {
if (c == '\n' || (ok_nl && llen >= LBSIZE - 2)) {
IFixMarks(save.p_line, save.p_char, curline, curchar);
modify();
makedirty(curline);
LineInsert(1);
DOTsave(&save);
llen = strlen(linebuf);
}
if (c != '\n') {
ins_c(c, linebuf, curchar++, 1, LBSIZE);
llen++;
}
}
IFixMarks(save.p_line, save.p_char, curline, curchar);
modify();
makedirty(curline);
}
OpenLine()
{
Bufpos dot;
DOTsave(&dot);
LineInsert(exp); /* Open the lines... */
SetDot(&dot);
}
/* Take the region FLINE/FCHAR to TLINE/TCHAR and insert it at
ATLINE/ATCHAR in WHATBUF. */
Bufpos *
DoYank(fline, fchar, tline, tchar, atline, atchar, whatbuf)
Line *fline,
*tline,
*atline;
Buffer *whatbuf;
{
register Line *newline;
static Bufpos bp;
char save[LBSIZE],
buf[LBSIZE];
Line *startline = atline;
int startchar = atchar;
lsave();
if (whatbuf)
modify();
(void) ltobuf(atline, genbuf);
strcpy(save, &genbuf[atchar]);
(void) ltobuf(fline, buf);
if (fline == tline)
buf[tchar] = '\0';
linecopy(genbuf, atchar, &buf[fchar]);
atline->l_dline = putline(genbuf);
makedirty(atline);
fline = fline->l_next;
while (fline != tline->l_next) {
newline = listput(whatbuf, atline);
newline->l_dline = fline->l_dline;
makedirty(newline);
fline = fline->l_next;
atline = newline;
atchar = 0;
}
getline(atline->l_dline, genbuf);
atchar += tchar;
linecopy(genbuf, atchar, save);
atline->l_dline = putline(genbuf);
makedirty(atline);
IFixMarks(startline, startchar, atline, atchar);
bp.p_line = atline;
bp.p_char = atchar;
this_cmd = YANKCMD;
getDOT(); /* Whatever used to be in linebuf */
return &bp;
}
YankPop()
{
Line *line,
*last;
Mark *mp = CurMark();
Bufpos *dot;
int dir = -1; /* Direction to rotate the ring */
if (last_cmd != YANKCMD)
complain("Yank something first!");
lfreelist(reg_delete(mp->m_line, mp->m_char, curline, curchar));
/* Now must find a recently killed region. */
if (exp < 0)
dir = 1;
killptr += dir;
for (;;) {
if (killptr < 0)
killptr = NUMKILLS - 1;
else if (killptr >= NUMKILLS)
killptr = 0;
if (killbuf[killptr])
break;
killptr += dir;
}
this_cmd = YANKCMD;
line = killbuf[killptr];
last = lastline(line);
dot = DoYank(line, 0, last, length(last), curline, curchar, curbuf);
MarkSet(CurMark(), curline, curchar);
SetDot(dot);
}
/* This is an attempt to reduce the amount of memory taken up by each line.
Without this each malloc of a line uses sizeof (line) + sizeof(HEADER)
where line is 3 words and HEADER is 1 word.
This is going to allocate memory in chucks of CHUNKSIZE * sizeof (line)
and divide each chuck into lineS. A line is free in a chunk when its
line->l_dline == 0, so freeline sets dline to 0. */
#define CHUNKSIZE 300
struct chunk {
int c_nlines; /* Number of lines in this chunk (so they
don't all have to be CHUNKSIZE long). */
Line *c_block; /* Chunk of memory */
struct chunk *c_nextfree; /* Next chunk of lines */
};
static struct chunk *fchunk = 0;
static Line *ffline = 0; /* First free line */
freeline(line)
register Line *line;
{
line->l_dline = 0;
line->l_next = ffline;
if (ffline)
ffline->l_prev = line;
line->l_prev = 0;
ffline = line;
}
lfreelist(first)
register Line *first;
{
if (first)
lfreereg(first, lastline(first));
}
/* Append region from line1 to line2 onto the free list of lines */
lfreereg(line1, line2)
register Line *line1,
*line2;
{
register Line *next,
*last = line2->l_next;
while (line1 != last) {
next = line1->l_next;
freeline(line1);
line1 = next;
}
}
static
newchunk()
{
register Line *newline;
register int i;
struct chunk *f;
int nlines = CHUNKSIZE;
f = (struct chunk *) emalloc(sizeof (struct chunk));
if (f == 0)
return 0;
if ((f->c_block = (Line *) malloc((unsigned) (sizeof (Line) * nlines))) == 0) {
while (nlines > 0) {
f->c_block = (Line *) malloc((unsigned) (sizeof (Line) * nlines));
if (f->c_block != 0)
break;
nlines /= 2;
}
}
if (nlines <= 0)
return 0;
f->c_nlines = nlines;
for (i = 0, newline = f->c_block; i < nlines; newline++, i++)
freeline(newline);
f->c_nextfree = fchunk;
fchunk = f;
return 1;
}
/* New BUFfer LINE */
Line *
nbufline()
{
register Line *newline;
if (ffline == 0) /* No free list */
if (newchunk() == 0)
complain("[Out of lines] ");
newline = ffline;
ffline = ffline->l_next;
if (ffline)
ffline->l_prev = 0;
return newline;
}
/* Remove the free lines, in chunk c, from the free list because they are
no longer free. */
static
remfreelines(c)
register struct chunk *c;
{
register Line *lp;
register int i;
for (lp = c->c_block, i = 0; i < c->c_nlines; i++, lp++) {
if (lp->l_prev)
lp->l_prev->l_next = lp->l_next;
else
ffline = lp->l_next;
if (lp->l_next)
lp->l_next->l_prev = lp->l_prev;
}
}
/* This is used to garbage collect the chunks of lines when malloc fails
and we are NOT looking for a new buffer line. This goes through each
chunk, and if every line in a given chunk is not allocated, the entire
chunk is `free'd by "free()". */
GCchunks()
{
register struct chunk *cp;
struct chunk *prev = 0,
*next = 0;
register int i;
register Line *newline;
for (cp = fchunk; cp != 0; cp = next) {
for (i = 0, newline = cp->c_block; i < cp->c_nlines; newline++, i++)
if (newline->l_dline != 0)
break;
next = cp->c_nextfree;
if (i == cp->c_nlines) { /* Unlink it!!! */
if (prev)
prev->c_nextfree = cp->c_nextfree;
else
fchunk = cp->c_nextfree;
remfreelines(cp);
free((char *) cp->c_block);
free((char *) cp);
} else
prev = cp;
}
}
#ifdef LISP
/* Grind S-Expr */
GSexpr()
{
Bufpos dot,
end;
if (linebuf[curchar] != '(')
complain((char *) 0);
DOTsave(&dot);
FSexpr();
DOTsave(&end);
exp = 1;
SetDot(&dot);
for (;;) {
if (curline == end.p_line)
break;
line_move(FORWARD, NO);
if (!blnkp(linebuf))
(void) lisp_indent();
}
SetDot(&dot);
}
/* lisp_indent() indents a new line in Lisp Mode, according to where
the matching close-paren would go if we typed that (sort of). */
private Table *specials = NIL;
private
init_specials()
{
static char *words[] = {
"case",
"def",
"dolist",
"fluid-let",
"lambda",
"let",
"lexpr",
"macro",
"named-l", /* named-let and named-lambda */
"nlambda",
"prog",
"selectq",
0
};
char **wordp = words;
specials = make_table();
while (*wordp)
add_word(*wordp++, specials);
}
AddSpecial()
{
char *word;
word = ask((char *) 0, ProcFmt);
if (specials == NIL)
init_specials();
add_word(copystr(word), specials);
}
Bufpos *
lisp_indent()
{
Bufpos *bp,
savedot;
int goal;
bp = m_paren(')', BACKWARD, NO, YES);
if (bp == 0)
return 0;
/* We want to end up
(atom atom atom ...
^ here.
*/
DOTsave(&savedot);
SetDot(bp);
DoTimes(ForChar(), 1);
if (linebuf[curchar] != '(') {
register Word *wp;
if (specials == NIL)
init_specials();
for (wp = table_top(specials); wp != NIL; wp = next_word(wp))
if (casencmp(word_text(wp), &linebuf[curchar], word_length(wp)) == 0)
break;
if (wp == NIL) { /* not special */
int c_char = curchar;
WITH_TABLE(curbuf->b_major)
ForWord();
END_TABLE();
if (LookingAt("[ \t]*;\\|[ \t]*$", linebuf, curchar))
curchar = c_char;
else while (linebuf[curchar] == ' ')
curchar++;
} else
curchar++;
}
goal = calc_pos(linebuf, curchar);
SetDot(&savedot);
n_indent(goal);
return bp;
}
#endif LISP