# include "ed.h"
# include "buffer.h"
/*
* This file defines the basic editing operations.
*/
/*
* NAME: editbuf->new()
* DESCRIPTION: create a new edit buffer
*/
editbuf *eb_new(tmpfile)
char *tmpfile;
{
register editbuf *eb;
eb = ALLOC(editbuf, 1);
eb->lb = lb_new((linebuf *) NULL, tmpfile);
eb->buffer = (block) 0;
eb->lines = 0;
return eb;
}
/*
* NAME: editbuf->del()
* DESCRIPTION: delete an edit buffer
*/
void eb_del(eb)
editbuf *eb;
{
lb_del(eb->lb);
FREE(eb);
}
/*
* NAME: editbuf->clear()
* DESCRIPTION: reinitialize an edit buffer
*/
void eb_clear(eb)
register editbuf *eb;
{
lb_new(eb->lb, (char *) NULL);
eb->buffer = (block) 0;
eb->lines = 0;
}
/*
* NAME: editbuf->add()
* DESCRIPTION: add a new block of lines to the edit buffer after a given line.
* If this line is 0 the block is inserted before the other lines
* in the edit buffer.
*/
void eb_add(eb, ln, getline, context)
register editbuf *eb;
register Int ln;
char *(*getline) P((char*)), *context;
{
register block b;
b = bk_new(eb->lb, getline, context);
if (b != (block) 0) {
Int size;
size = eb->lines + bk_size(eb->lb, b);
if (size < 0) {
error("Too many lines");
}
if (ln == 0) {
if (eb->lines == 0) {
eb->buffer = b;
} else {
eb->buffer = bk_cat(eb->lb, b, eb->buffer);
}
} else if (ln == eb->lines) {
eb->buffer = bk_cat(eb->lb, eb->buffer, b);
} else {
block head, tail;
bk_split(eb->lb, eb->buffer, ln, &head, &tail);
eb->buffer = bk_cat(eb->lb, bk_cat(eb->lb, head, b), tail);
}
eb->lines = size;
}
}
/*
* NAME: editbuf->delete()
* DESCRIPTION: delete a subrange of lines in the edit buffer
*/
block eb_delete(eb, first, last)
register editbuf *eb;
register Int first, last;
{
block head, mid, tail;
Int size;
size = last - first + 1;
if (last < eb->lines) {
bk_split(eb->lb, eb->buffer, last, &mid, &tail);
if (first > 1) {
bk_split(eb->lb, mid, first - 1, &head, &mid);
eb->buffer = bk_cat(eb->lb, head, tail);
} else {
eb->buffer = tail;
}
} else {
mid = eb->buffer;
if (first > 1) {
bk_split(eb->lb, mid, first - 1, &head, &mid);
eb->buffer = head;
} else {
eb->buffer = (block) 0;
}
}
eb->lines -= size;
return mid;
}
/*
* NAME: editbuf->change()
* DESCRIPTION: change a subrange of lines in the edit buffer
*/
void eb_change(eb, first, last, b)
register editbuf *eb;
register Int first, last;
register block b;
{
Int size;
block head, tail;
size = eb->lines - (last - first + 1);
if (b != (block) 0) {
size += bk_size(eb->lb, b);
if (size < 0) {
error("Too many lines");
}
}
if (last < eb->lines) {
if (first > 1) {
bk_split(eb->lb, eb->buffer, first - 1, &head, (block *) NULL);
bk_split(eb->lb, eb->buffer, last, (block *) NULL, &tail);
if (b != (block) 0) {
b = bk_cat(eb->lb, bk_cat(eb->lb, head, b), tail);
} else {
b = bk_cat(eb->lb, head, tail);
}
} else {
bk_split(eb->lb, eb->buffer, last, (block *) NULL, &tail);
if (b != (block) 0) {
b = bk_cat(eb->lb, b, tail);
} else {
b = tail;
}
}
} else if (first > 1) {
bk_split(eb->lb, eb->buffer, first - 1, &head, (block *) NULL);
if (b != (block) 0) {
b = bk_cat(eb->lb, head, b);
} else {
b = head;
}
}
eb->buffer = b;
eb->lines = size;
}
/*
* NAME: editbuf->yank()
* DESCRIPTION: return a subrange block of the edit buffer
*/
block eb_yank(eb, first, last)
register editbuf *eb;
register Int first, last;
{
block head, mid, tail;
if (last < eb->lines) {
bk_split(eb->lb, eb->buffer, last, &mid, &tail);
} else {
mid = eb->buffer;
}
if (first > 1) {
bk_split(eb->lb, mid, first - 1, &head, &mid);
}
return mid;
}
/*
* NAME: editbuf->put()
* DESCRIPTION: put a block after a line in the edit buffer. The block is
* supplied immediately.
*/
void eb_put(eb, ln, b)
register editbuf *eb;
register Int ln;
register block b;
{
Int size;
size = eb->lines + bk_size(eb->lb, b);
if (size < 0) {
error("Too many lines");
}
if (ln == 0) {
if (eb->lines == 0) {
eb->buffer = b;
} else {
eb->buffer = bk_cat(eb->lb, b, eb->buffer);
}
} else if (ln == eb->lines) {
eb->buffer = bk_cat(eb->lb, eb->buffer, b);
} else {
block head, tail;
bk_split(eb->lb, eb->buffer, ln, &head, &tail);
eb->buffer = bk_cat(eb->lb, bk_cat(eb->lb, head, b), tail);
}
eb->lines = size;
}
/*
* NAME: editbuf->range()
* DESCRIPTION: output a subrange of the edit buffer, without first making
* a subrange block for it
*/
void eb_range(eb, first, last, putline, context, reverse)
register editbuf *eb;
Int first, last;
void (*putline) P((char*, char*));
char *context;
int reverse;
{
bk_put(eb->lb, eb->buffer, first - 1, last - first + 1, putline, context,
reverse);
}
/*
* Routines to add lines to a block in pieces. It would be nice if bk_new could
* be used for this, but this is only possible if the editor functions as a
* stand-alone program.
* Lines are stored in a local buffer, which is flushed into a block when full.
*/
/*
* NAME: add_line()
* DESCRIPTION: return the next line from the lines buffer
*/
static char *add_line(ptr)
char *ptr;
{
register editbuf *eb;
eb = (editbuf *) ptr;
if (eb->szlines > 0) {
char *p;
int len;
len = strlen(p = eb->llines) + 1;
eb->llines += len;
eb->szlines -= len;
return p;
}
return (char *) NULL;
}
/*
* NAME: flush_line()
* DESCRIPTION: flush the lines buffer into a block
*/
static void flush_line(eb)
register editbuf *eb;
{
block b;
eb->llines = eb->llbuf;
b = bk_new(eb->lb, add_line, (char *) eb);
if (eb->flines == (block) 0) {
eb->flines = b;
} else {
eb->flines = bk_cat(eb->lb, eb->flines, b);
}
}
/*
* NAME: editbuf->startblock()
* DESCRIPTION: start a block of lines
*/
void eb_startblock(eb)
register editbuf *eb;
{
eb->flines = (block) 0;
eb->szlines = 0;
}
/*
* NAME: editbuf->addblock()
* DESCRIPTION: add a line to the current block of lines
*/
void eb_addblock(eb, text)
register editbuf *eb;
register char *text;
{
register int len;
len = strlen(text) + 1;
if (eb->szlines + len >= sizeof(eb->llines)) {
flush_line(eb);
}
memcpy(eb->llbuf + eb->szlines, text, len);
eb->szlines += len;
}
/*
* NAME: editbuf->endblock()
* DESCRIPTION: finish the current block
*/
void eb_endblock(eb)
register editbuf *eb;
{
if (eb->szlines > 0) {
flush_line(eb);
}
}