/**************************************************************
 *
 *	CRISP - Custom Reduced Instruction Set Programmers Editor
 *
 *	(C) Paul Fox, 1989
 *
 *    Please See COPYRIGHT notice.
 *
 **************************************************************/

# include	"list.h"


/**********************************************************************/
/*   Prototypes.						      */
/**********************************************************************/
int	check_mark PROTO((void));
int	delregion PROTO((void));
void	transfer PROTO((void));
void	inq_mksize PROTO((void));
void	paste PROTO((void));
void	copy PROTO((void));
void	cut PROTO((void));
int	getregion PROTO((int, int));

extern	int	start_line, start_col;
extern	int	end_line, end_col;
extern	int	mark_type;
int	doing_transfer = FALSE;
int	saved_col;
/*
 * This structure holds the starting position
 * (as a line/offset pair) and the number of characters in a
 * region of a buffer. This makes passing the specification
 * of a region around a little bit easier.
 */
typedef struct  {
	int	r_line;
	int	r_col;			/* Origin LINE offset.          */
	int	r_doffset;
	RSIZE   r_size;                 /* Length in characters.        */
	int	r_type;			/* Mark type.			*/
}       REGION;

REGION region;

void
del_block()
{

	if (rdonly() || check_mark())
		return;

	if (getregion(FALSE, FALSE) != TRUE)
		return;
	delregion();
	infof("Block deleted.");
}
int
check_mark()
{
	if (!doing_transfer && curbp->b_anchor == NULL) {
		errorf("No marked block.");
		return TRUE;
		}
	return FALSE;
}
int
delregion()
{
	if (region.r_size) {
		u_dot();
		*cur_line = region.r_line;
		*cur_col = current_col(region.r_col);
		ldelete(region.r_size);
		if (region.r_type == MK_LINE)
			*cur_col = saved_col;
		}
	raise_anchor();
	return TRUE;
}
void
transfer()
{	extern	BUFFER	*scrbp;
	extern	BUFFER	*scrap_bp;
	BUFFER	*saved_bp = curbp;
	BUFFER	*bp;
	BUFFER	*numberb();

	acc_assign_int(0L);
	if ((bp = numberb(argv[1].l_int)) == NULL)
		return;

	scrbp = curbp;
	curbp = bp;

	start_line = argv[2].l_int;
	start_col = argv[3].l_int;
	end_line = argv[4].l_int + 1;
	end_col = argv[5].l_int;

	doing_transfer = TRUE;
	copy();
	acc_assign_int(1L);
	scrbp = scrap_bp;
	curbp = saved_bp;
	doing_transfer = FALSE;
}
void
inq_mksize()
{
	if (getregion(FALSE, FALSE) != TRUE)
		acc_assign_int(0L);
	else
		acc_assign_int(region.r_size);
}
void
paste()
{	char	*cp;
	register int	n;
	register int line_no = 0;
	int	inserted = FALSE;
	int	col = *cur_col;
	long	numlines;

	acc_assign_int((long) 0L);	
	if (rdonly())
		return;
	lchange(WFEDIT);

	k_seek();
	u_dot();
	if ((region.r_type = k_type()) == MK_LINE)
		*cur_col = 1;

	win_modify(WFEDIT);
	numlines = (long) k_numlines();
	while ((n = k_read(&cp)) >= 0) {
		if (inserted)
			lnewline();
		else
			inserted = TRUE;
		if (n)
			llinsert(cp, (u_int32) n, FALSE);
		line_no++;
		percentage(line_no, numlines, "Paste", "command");
		}
	win_modify(WFEDIT);
	if (region.r_type == MK_LINE)
		*cur_col = col;

	if (inserted) {
		acc_assign_int((long) 1L);
		infof("Scrap inserted.");
		}
	else 
		infof("No scrap to insert.");
}
void
copy()
{	int	append = argv[1].l_flags == F_INT ? (int) argv[1].l_int : 0;

	if (check_mark())
		return;
	if (copyregion((FILE *) NULL, "Copying", append) == 0)
		return;
	if (!doing_transfer) {
		raise_anchor();
		infof("Block copied to scrap.");
		}
}
void
cut()
{	int	append = argv[1].l_flags == F_INT ? (int) argv[1].l_int : 0;

	if (rdonly() || check_mark())
		return;

	if (copyregion((FILE *) NULL, "Cutting", append) == 0)
		return;
	if (delregion())
		infof("Block deleted to scrap.");
	else
		infof("No marked block.");
}
int
copyregion(fp, str, append)
FILE	*fp;
char	*str;
int	append;
{
	register LINE   *lp;
	register int	line;
	RSIZE	size;
	int	r;
	register int	mo;
	int	bytes_to_write;
	
	if (getregion(!append, TRUE) != TRUE || region.r_size == 0)
		return 0;

	line = region.r_line;
	mo = region.r_col;

	if (fp == NULL)
		k_seek();
	for (size = region.r_size; size > 0 && line <= end_line; line++) {
		lp = vm_lock_line(line);
		r = llength(lp) - mo;
		if (size < r)
			r = size;
		/***********************************************/
		/*   If  we  have  a  column  mark  then only  */
		/*   write  the  column but be careful not to  */
		/*   write  more  bytes than there are in the  */
		/*   line.				       */
		/***********************************************/
		bytes_to_write = (int) r;
		if (mark_type == MK_COLUMN) {
			bytes_to_write = end_col - mo + 1;
			if (bytes_to_write > (int) size)
				bytes_to_write = (int) size;
			}
		if (fp)
			fwrite((char *) lp->l_text + mo, bytes_to_write, 1, fp);
		else
			k_write(lp->l_text + mo, bytes_to_write);
		size -= r;
		if (size > 0) {
			if (fp) {
				if ((curbp->b_flag & BFBINARY) == 0)
					fwrite("\n", 1, 1, fp);
				}
			else
				k_newline();
			size--;
			}
		if (mark_type != MK_COLUMN)
			mo = 0;
		vm_unlock(line);
		if (str)
			percentage(region.r_size - size, region.r_size, str, "region");
		}
	k_end();
	return 1;
}
int
getregion(delete, do_undo)
int	delete;
int	do_undo;
{
	register RSIZE	size = 0;
	register LINE	*lp;
	int	current_line;

	saved_col = *cur_col;
	if (check_mark())
		return FALSE;
	if (doing_transfer)
		mark_type = MK_NORMAL;
	else
		get_marked_areas((curwp && curwp->w_bufp == curbp) ? 
			curwp : (WINDOW *) NULL);

	region.r_type = mark_type;
	current_line = *cur_line;
	*cur_line = start_line;
	start_col = current_offset(start_col, FALSE);
	if (end_line == curbp->b_numlines)
		end_col = 0;
	else {
		*cur_line = end_line;
		if (end_col == 0)
			end_col = -1;
		else
			end_col = current_offset(end_col, FALSE);
		*cur_line = current_line;
		}

	if (do_undo || (delete && !doing_transfer))
		u_scrap();
	if (delete && !doing_transfer)
		k_delete(region.r_type);
	region.r_line = start_line;
	region.r_col = start_col;
	region.r_doffset = end_col;
	size -= start_col;
	
	while (start_line < end_line) {
		lp = linep(start_line++);
		size += llength(lp) + 1;
		}

	if (region.r_type == MK_LINE) {
		lp = linep(start_line);
		end_col = llength(lp)+1;
		}
	size += end_col;
	region.r_size = size;

	if (region.r_type != MK_LINE && end_line != curbp->b_numlines)
		region.r_size++;
	return TRUE;
}
