This is paste.c in view mode; [Download] [Up]
/*
* Copyright (c) 1992, 1995 John E. Davis (davis@space.mit.edu)
* All Rights Reserved.
*/
#include <config.h>
#include <stdio.h>
#include <string.h>
#include "buffer.h"
#include "ins.h"
#include "line.h"
#include "paste.h"
#include "screen.h"
#include "misc.h"
#include "cmds.h"
/* SLang user object be larger than 128 */
#define JED_MARK_TYPE 128
Buffer *Paste_Buffer;
Buffer *Rectangle_Buffer;
/* This is used by the narrow command so that multiple windows are
* handled properly. The assumption is that we are dealing with a canonical
* region */
static void touch_windows(void)
{
Window_Type *w;
Line *l;
unsigned int n;
w = JWindow;
JWindow = JWindow->next;
while (JWindow != w)
{
if (CBuf == JWindow->buffer)
{
/* The mark is set with line at top of buffer */
l = CBuf->marks->line;
n = CBuf->marks->n;
while ((l != NULL) && (l != JWindow->mark.line)) l = l->next, n++;
if (l == NULL)
{
JWindow->mark.line = CLine;
JWindow->mark.point = Point;
JWindow->mark.n = n - 1;
}
touch_window();
}
JWindow = JWindow->next;
}
pop_mark(&Number_Zero);
}
#if 0
static int line_in_buffer(Line *line)
{
Line *l;
l = CBuf->beg;
while (l != NULL) if (l == line) return(1); else l = l->next;
return(0);
}
#endif
/* with prefix argument, pop marks */
int set_mark_cmd()
{
Mark *m;
if (Repeat_Factor != NULL)
{
while (CBuf->marks != NULL) pop_mark(&Number_Zero);
Repeat_Factor = NULL;
return(1);
}
if (CBuf->marks == NULL)
{
push_mark();
}
m = CBuf->marks;
m->line = CLine;
m->point = Point;
m->n = LineNum + CBuf->nup;
if ((m->flags & VISIBLE_MARK) == 0)
{
m->flags |= VISIBLE_MARK;
CBuf->vis_marks++;
}
/* if (m != CBuf->marks) m->next = CBuf->marks;
CBuf->marks = m; */
if (Last_Key_Function == (FVOID_STAR) set_mark_cmd) message("Mark Set.");
return(1);
}
int push_spot()
{
Mark *m;
if (CBuf->spot_ptr < SPOT_ARRAY_SIZE)
{
m = &CBuf->spot_array[CBuf->spot_ptr++];
}
else if (NULL == (m = (Mark *) SLMALLOC(sizeof(Mark))))
{
exit_error("push_spot: malloc error!", 0);
}
m->line = CLine;
m->point = Point;
m->n = LineNum + CBuf->nup;
m->next = CBuf->spots;
CBuf->spots = m;
return(1);
}
int push_mark()
{
Mark *m;
if (CBuf->mark_ptr < SPOT_ARRAY_SIZE)
{
m = &CBuf->mark_array[CBuf->mark_ptr++];
}
else if (NULL == (m = (Mark *) SLMALLOC(sizeof(Mark))))
{
exit_error("push_mark: malloc error!", 0);
}
/*
if (NULL == (m = (Mark *) SLMALLOC(sizeof(Mark))))
{
msg_error("push_mark: malloc error!");
return(0);
} */
m->line = CLine;
m->point = Point;
m->n = LineNum + CBuf->nup;
m->next = CBuf->marks;
m->flags = 0;
CBuf->marks = m;
return(1);
}
void goto_mark(Mark *m)
{
Line *l;
l = m->line;
LineNum = m->n;
if (LineNum <= CBuf->nup) bob();
else if (LineNum > CBuf->nup + Max_LineNum) eob();
else
{
CLine = l;
Point = m->point;
LineNum -= CBuf->nup;
}
}
int pop_mark(int *go)
{
Mark *m;
m = CBuf->marks;
if (m == NULL) return(0);
if (*go) goto_mark(m);
if (m->flags & VISIBLE_MARK)
{
CBuf->vis_marks--;
/* touch screen since region may be highlighted */
if (CBuf->vis_marks == 0) touch_screen();
}
CBuf->marks = m->next;
if (m == &CBuf->mark_array[CBuf->mark_ptr - 1])
{
CBuf->mark_ptr--;
}
else SLFREE(m);
return(1);
}
int mark_spot()
{
push_spot();
message("Spot Marked.");
return(1);
}
static int pop_spot_go (int go)
{
Mark *m;
m = CBuf->spots;
if (m == NULL) return(0);
if (go) goto_mark (m);
CBuf->spots = m->next;
if (m == &CBuf->spot_array[CBuf->spot_ptr - 1])
{
CBuf->spot_ptr--;
}
else SLFREE(m);
return(1);
}
int pop_spot ()
{
return pop_spot_go (1);
}
int exchange_point_mark(void)
{
Line *save_line;
int save_point;
unsigned int save_n;
Mark *m;
if ((m = CBuf->marks) == NULL) return(0);
save_point = Point;
save_line = CLine;
save_n = LineNum + CBuf->nup;
goto_mark (m);
m->point = save_point; m->line = save_line; m->n = save_n;
return(1);
}
/*returns 0 if the mark is not set and gives error. Exchanges point and mark
* to produce valid region. A valid region is one with mark
* earlier in the buffer than point. Always call this if using a region
* which reqires point > mark. Also, push spot first then pop at end.
*/
int check_region(int *push)
{
register Line *beg, *tthis = CLine;
int pbeg;
if (CBuf->marks == NULL)
{
msg_error("Set mark first.");
return(0);
}
if (*push) push_spot();
beg = CBuf->marks->line;
pbeg = CBuf->marks->point;
if (beg == CLine)
{
if (pbeg <= Point) return(1);
}
else
{
while((beg != NULL) && (beg != tthis)) beg = beg->next;
if (beg == tthis) return(1);
}
exchange_point_mark();
return(1);
}
int widen_buffer_lines (Buffer *b)
{
Narrow_Type *n;
Buffer *save = CBuf;
if (NULL == (n = b->narrow)) return(0);
/* make sure buffer ends in final newline */
switch_to_buffer(b);
push_spot();
eob();
if ((n->end != NULL)
&& (!CLine->len || ('\n' != *(CLine->data + (CLine->len - 1)))))
{
unsigned int flags = CBuf->flags;
ins('\n');
CBuf->flags = flags;
}
pop_spot();
if (n->end != NULL) n->end->prev = b->end;
if (n->beg != NULL) n->beg->next = b->beg;
b->end->next = n->end;
b->beg->prev = n->beg;
b->beg = n->beg1;
if (n->end != NULL) b->end = n->end1;
Max_LineNum += n->ndown + n->nup;
LineNum += n->nup;
/* adjust absolute offsets */
b->nup -= n->nup;
b->ndown -= n->ndown;
b->narrow = n->next;
SLFREE(n);
switch_to_buffer(save);
return(1);
}
int widen_buffer (Buffer *b)
{
unsigned int flags;
Buffer *save;
if (b->narrow == NULL) return 0;
if (b->narrow->is_region == 0)
return widen_buffer_lines (b);
flags = b->flags;
b->flags &= ~READ_ONLY;
save = CBuf;
switch_to_buffer (b);
push_spot ();
bob ();
push_spot ();
eob ();
widen_buffer_lines (CBuf);
del ();
pop_spot ();
prevline (&Number_One);
del ();
pop_spot ();
switch_to_buffer (save);
b->flags = flags;
return 1;
}
int narrow_to_region (void)
{
int pnt;
Line *line;
unsigned int flags;
if (0 == check_region (&Number_One))/* spot pushed */
return 0;
flags = CBuf->flags;
CBuf->flags &= ~READ_ONLY;
push_spot ();
line = CLine;
pnt = Point;
pop_mark (&Number_One);
/* Special case if region is empty */
if ((CLine == line) && (pnt == Point))
{
pop_spot ();
pop_spot ();
newline ();
push_mark ();
newline ();
prevline (&Number_One);
if (narrow_to_lines ())
CBuf->narrow->is_region = 1;
}
else
{
newline ();
push_mark ();
pop_spot ();
newline ();
prevline (&Number_One);
if (narrow_to_lines ())
CBuf->narrow->is_region = 1;
pop_spot ();
}
CBuf->flags = flags;
return 1;
}
int widen ()
{
return widen_buffer_lines (CBuf);
}
int widen_region (void)
{
return widen_buffer (CBuf);
}
/* not really a region of points but a region of lines. */
int narrow_to_lines ()
{
Line *beg;
Narrow_Type *nt;
if (NULL == (nt = (Narrow_Type *) SLMALLOC(sizeof(Narrow_Type))))
{
msg_error("Malloc Error during narrow.");
return(0);
}
if (!check_region(&Number_One)) return(0); /* spot pushed */
push_spot();
pop_mark(&Number_One);
push_mark(); /* popped and used in touch_windows! */
beg = CLine;
nt->nup = LineNum - 1;
pop_spot(); /* eor now */
nt->ndown = Max_LineNum - LineNum;
Max_LineNum = LineNum = LineNum - nt->nup;
CBuf->nup += nt->nup;
CBuf->ndown += nt->ndown;
nt->next = CBuf->narrow;
CBuf->narrow = nt;
nt->beg = beg->prev;
nt->end = CLine->next;
nt->beg1 = CBuf->beg;
nt->end1 = CBuf->end;
nt->is_region = 0;
CBuf->beg = beg;
CBuf->end = CLine;
beg->prev = NULL;
CLine->next = NULL;
if (CLine->len && (CLine->data[CLine->len - 1] == '\n'))
{
/* I do not think that this will affect undo. */
CLine->len--;
}
pop_spot();
touch_windows();
return(1);
}
int yank()
{
CHECK_READ_ONLY
if (Paste_Buffer == NULL) return(0);
insert_buffer(Paste_Buffer);
return(1);
}
int copy_region_to_buffer(Buffer *b)
{
int first_point, last_point, n, tmpm;
Line *first, *last;
Buffer *save_buffer;
if (b->flags & READ_ONLY)
{
msg_error(Read_Only_Error);
return (0);
}
if (!check_region(&Number_One)) return(0); /* spot pushed */
last = CLine;
last_point = Point;
tmpm = 1; pop_mark(&tmpm);
if (b == CBuf)
{
msg_error("A buffer cannot be inserted upon itself.");
pop_spot();
return(0);
}
first = CLine;
first_point = Point;
save_buffer = CBuf;
switch_to_buffer(b);
/* go through standard routines for undo comapatability */
Suspend_Screen_Update = 1;
if (first == last)
{
n = last_point - first_point;
if (save_buffer == MiniBuffer)
{
ins_chars(first->data + first_point, n);
}
else quick_insert(first->data + first_point, n);
}
else
{
n = first->len - first_point;
quick_insert(first->data + first_point, n);
while (first = first->next, first != last)
{
quick_insert(first->data, first->len);
}
quick_insert(first->data, last_point);
}
switch_to_buffer(save_buffer);
pop_spot();
return(1);
}
int copy_to_pastebuffer()
{
/* delete paste buffer */
if (Paste_Buffer != NULL) delete_buffer(Paste_Buffer);
Paste_Buffer = make_buffer();
strcpy(Paste_Buffer->name, " <paste>");
copy_region_to_buffer(Paste_Buffer);
return(0);
}
int delete_region (void)
{
int beg_point, tmpm, end_point, n;
Line *beg, *end;
CHECK_READ_ONLY
if (!check_region(&Number_Zero)) return(0);
/* make this go through standard ins/del routines to ensure undo */
end = CLine; end_point = Point;
push_spot();
tmpm = 1; pop_mark(&tmpm);
beg = CLine; beg_point = Point;
pop_spot();
Point = 0;
if (end != beg)
{
deln(&end_point);
/* go back because we do not want to mess with Line structures
changing on us --- shouldn't happen anyway */
while (CLine = CLine->prev, LineNum--, CLine != beg)
{
eol();
n = Point + 1;
Point = 0;
generic_deln(&n);
}
eol();
n = Point - beg_point + 1; /* the \n char */
Point = beg_point;
}
else
{
Point = beg_point;
n = end_point - Point;
}
generic_deln(&n);
return(1);
}
int kill_region()
{
int tmpm = 1;
CHECK_READ_ONLY
/* need two marks for this one */
push_spot();
if (!pop_mark(&tmpm))
{
check_region(&Number_Zero);
pop_spot();
return(0);
}
push_mark();
push_mark();
pop_spot();
copy_to_pastebuffer();
delete_region();
return(1);
}
static char *Rect_Error = "Rectangle has 0 width.";
int insert_rectangle()
{
int c1;
Line *rline;
CHECK_READ_ONLY
if (Rectangle_Buffer == NULL) return(0);
Suspend_Screen_Update = 1;
c1 = calculate_column();
rline = Rectangle_Buffer->beg;
if (rline != NULL) while (1)
{
goto_column(&c1);
quick_insert(rline->data, rline->len);
rline = rline->next;
if (rline == NULL) break;
if (CLine->next == NULL)
{
eol();
newline();
}
else
{
CLine = CLine->next;
LineNum++;
}
}
return(1);
}
int open_rectangle()
{
int c1, n, c2, tmpm;
Line *save_line;
CHECK_READ_ONLY
if (!check_region(&Number_One)) return(0); /* push_spot(); performed */
c1 = calculate_column();
save_line = CLine;
tmpm = 1; pop_mark(&tmpm);
c2 = calculate_column();
n = c2 - c1;
if (n < 0)
{
n = -n;
c1 = c2;
}
Suspend_Screen_Update = 1;
while(1)
{
goto_column(&c1);
ins_char_n_times(' ', n);
if (CLine == save_line) break;
CLine = CLine->next;
LineNum++;
}
pop_spot();
return(1);
}
/* rectangle commands */
int copy_rectangle()
{
Line *save_line, *line, *beg;
int c1, c2, dc, tmp, tmpm, dc_malloc;
unsigned char *p1, *p2, *data;
if (!check_region(&Number_One)) return(0); /* spot pushed */
/* delete Rectangle buffer */
if (Rectangle_Buffer != NULL) delete_buffer(Rectangle_Buffer);
Rectangle_Buffer = make_buffer();
strcpy(Rectangle_Buffer->name, " <rect>");
c2 = calculate_column();
save_line = CLine;
tmpm = 1; pop_mark(&tmpm);
c1 = calculate_column();
if (c1 == c2)
{
msg_error(Rect_Error);
pop_spot();
return(0);
}
if (c1 > c2)
{
tmp = c1;
c1 = c2;
c2 = tmp;
goto_column(&c1);
}
/* go through the region copying rectanglar blocks to Rectanglebuffer */
dc = c2 - c1;
if (dc == 1) dc_malloc = 2; else dc_malloc = dc;
line = beg = make_line1(dc_malloc);
beg->prev = NULL;
while (1)
{
data = line->data;
/* p1 = data;
p2 = data + dc;
while (p1 < p2) *p1++ = ' '; */
MEMSET ((char *) data, ' ', dc);
line->len = dc;
if (c1 == goto_column1(&c1))
{
p1 = CLine->data + Point;
(void) goto_column1(&c2);
p2 = CLine->data + Point;
/* while(p1 < p2) *data++ = *p1++; */
MEMCPY((char *) data, (char *) p1, (int) (p2 - p1));
}
if (CLine == save_line) break;
CLine = CLine->next;
LineNum++;
line->next = make_line1(dc_malloc);
line->next->prev = line;
line = line->next;
}
line->next = NULL;
Rectangle_Buffer->line = Rectangle_Buffer->beg = beg;
Rectangle_Buffer->end = line;
Rectangle_Buffer->point = 0;
pop_spot();
return(0);
}
int kill_rectangle()
{
Line *save_line, *line, *beg;
int c1, c2, dc, tmp, n, tmpm, dc_malloc;
unsigned char *p1, *p2, *data;
CHECK_READ_ONLY
if (!check_region(&Number_One)) return(0);
/* delete Rectangle buffer */
if (Rectangle_Buffer != NULL) delete_buffer(Rectangle_Buffer);
Rectangle_Buffer = make_buffer();
strcpy(Rectangle_Buffer->name, " <rect>");
c2 = calculate_column();
save_line = CLine;
tmpm = 1; pop_mark(&tmpm);
c1 = calculate_column();
if (c1 == c2)
{
msg_error(Rect_Error);
pop_spot();
return(0);
}
if (c1 > c2)
{
tmp = c1;
c1 = c2;
c2 = tmp;
goto_column(&c1);
}
Suspend_Screen_Update = 1;
/* go through the region copying rectanglar blocks to Rectanglebuffer */
dc = c2 - c1;
if (dc == 1) dc_malloc = 2; else dc_malloc = dc;
/* length of 1 not usable here.
* See makeline1 to see why
*/
line = beg = make_line1(dc_malloc);
beg->prev = NULL;
while (1)
{
data = line->data;
/* p2 = data + dc; p1 = data;
while (p1 < p2) *p1++ = ' '; */
MEMSET((char *) data, ' ', dc);
line->len = dc;
if (c1 == goto_column1(&c1))
{
p1 = CLine->data + Point;
(void) goto_column1(&c2);
p2 = CLine->data + Point;
Point = (int) (p1 - CLine->data);
n = (int) (p2 - p1);
MEMCPY((char *) data, (char *) p1, n);
deln (&n);
/* while(n-- > 0)
{
*data++ = *p1;
del();
} */
}
if (CLine == save_line) break;
CLine = CLine->next; LineNum++;
line->next = make_line1(dc_malloc);
line->next->prev = line;
line = line->next;
}
line->next = NULL;
Rectangle_Buffer->line = Rectangle_Buffer->beg = beg;
Rectangle_Buffer->end = line;
Rectangle_Buffer->point = 0;
pop_spot();
return(0);
}
int blank_rectangle()
{
int c1, n, c2, pnt, tmpm;
Line *save_line;
int nn;
CHECK_READ_ONLY
if (!check_region(&Number_One)) return(0); /* push_spot(); performed */
c1 = calculate_column();
save_line = CLine;
tmpm = 1; pop_mark(&tmpm);
c2 = calculate_column();
n = c2 - c1;
if (n < 0)
{
n = -n;
c1 = c2;
}
Suspend_Screen_Update = 1;
while(1)
{
goto_column(&c1);
pnt = Point;
eol();
nn = Point - pnt;
if (nn > n) nn = n;
Point = pnt;
deln(&nn);
ins_char_n_times( ' ', nn);
if (CLine == save_line) break;
CLine = CLine->next;
LineNum++;
}
pop_spot();
/* mark_buffer_modified(&Number_One); */
return(1);
}
/* User Marks */
typedef struct
{
Mark m; /* MUST be the first */
Buffer *b;
}
User_Mark_Type;
static void free_user_mark (User_Mark_Type *um)
{
Mark *m, *m1;
Buffer *b;
m1 = &um->m;
/* The mark is only valid if the buffer that it was created for still
* exists.
*/
if ((m1->flags & MARK_INVALID) == 0)
{
/* Unlink the mark from the chain. */
b = um->b;
m = b->user_marks;
if (m == m1) b->user_marks = m1->next;
else
{
while (m->next != m1) m = m->next;
m->next = m1->next;
}
}
SLFREE (um);
}
void free_user_marks (Buffer *b)
{
Mark *m = b->user_marks;
while (m != NULL)
{
m->flags |= MARK_INVALID;
m = m->next;
}
}
static int mark_valid (Mark *m)
{
if (m->flags & MARK_INVALID)
{
msg_error ("Mark is invalid.");
return 0;
}
return 1;
}
int jed_move_user_object_mark (SLuser_Object_Type *uo)
{
User_Mark_Type *um;
Mark *m;
um = (User_Mark_Type *) uo->obj;
m = &um->m;
if (!mark_valid (m)) return 0;
if (CBuf != um->b)
{
msg_error ("Mark not in buffer.");
return 0;
}
m->line = CLine;
m->point = Point;
m->n = LineNum + CBuf->nup;
return 1;
}
void move_user_mark (void)
{
SLuser_Object_Type *uo;
if ((uo = SLang_pop_user_object (JED_MARK_TYPE)) == NULL) return;
(void) jed_move_user_object_mark (uo);
SLang_free_user_object (uo);
}
void goto_user_mark (void)
{
SLuser_Object_Type *uo;
User_Mark_Type *um;
if ((uo = SLang_pop_user_object (JED_MARK_TYPE)) == NULL) return;
um = (User_Mark_Type *) uo->obj;
if (mark_valid (&um->m))
{
if (CBuf != um->b) msg_error ("Mark not in buffer.");
else
goto_mark (&um->m);
}
SLang_free_user_object (uo);
}
SLuser_Object_Type *jed_make_user_object_mark (int main_type)
{
User_Mark_Type *um;
SLuser_Object_Type *uo;
Mark *m;
uo = SLang_create_user_object (JED_MARK_TYPE);
if (uo == NULL) return NULL;
uo->main_type = main_type;
if (NULL == (um = (User_Mark_Type *) SLMALLOC (sizeof(User_Mark_Type))))
{
SLang_Error = SL_MALLOC_ERROR;
SLFREE (uo);
return NULL;
}
m = &um->m;
m->line = CLine;
m->point = Point;
m->n = LineNum + CBuf->nup;
m->next = CBuf->user_marks;
m->flags = 0;
CBuf->user_marks = m;
um->b = CBuf;
uo->obj = (long *) um;
return uo;
}
void jed_free_user_object_mark (SLuser_Object_Type *uo)
{
/* let slang handle this. */
uo->main_type = SLANG_DATA;
SLang_free_user_object (uo);
}
void create_user_mark (void)
{
SLuser_Object_Type *uo = jed_make_user_object_mark (SLANG_DATA);
if (uo != NULL) SLang_push_user_object (uo);
}
char *user_mark_buffer (void)
{
SLuser_Object_Type *uo;
User_Mark_Type *um;
char *s = "";
if (NULL == (uo = SLang_pop_user_object (JED_MARK_TYPE))) return s;
um = (User_Mark_Type *) uo->obj;
if (mark_valid (&um->m))
{
s = um->b->name;
}
SLang_free_user_object (uo);
return s;
}
int register_jed_classes (void)
{
return SLang_register_class (JED_MARK_TYPE, (FVOID_STAR) free_user_mark, NULL);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.