119304Speter/*-
219304Speter * Copyright (c) 1992, 1993, 1994
319304Speter *	The Regents of the University of California.  All rights reserved.
419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996
519304Speter *	Keith Bostic.  All rights reserved.
619304Speter *
719304Speter * See the LICENSE file for redistribution information.
819304Speter */
919304Speter
1019304Speter#include "config.h"
1119304Speter
1219304Speter#ifndef lint
13254225Speterstatic const char sccsid[] = "$Id: delete.c,v 10.18 2012/02/11 15:52:33 zy Exp $";
1419304Speter#endif /* not lint */
1519304Speter
1619304Speter#include <sys/types.h>
1719304Speter#include <sys/queue.h>
18254225Speter#include <sys/time.h>
1919304Speter
2019304Speter#include <bitstring.h>
2119304Speter#include <errno.h>
2219304Speter#include <limits.h>
2319304Speter#include <stdio.h>
2419304Speter#include <stdlib.h>
2519304Speter#include <string.h>
2619304Speter
2719304Speter#include "common.h"
2819304Speter
2919304Speter/*
3019304Speter * del --
3119304Speter *	Delete a range of text.
3219304Speter *
3319304Speter * PUBLIC: int del __P((SCR *, MARK *, MARK *, int));
3419304Speter */
3519304Speterint
36254225Speterdel(
37254225Speter	SCR *sp,
38254225Speter	MARK *fm,
39254225Speter	MARK *tm,
40254225Speter	int lmode)
4119304Speter{
4219304Speter	recno_t lno;
4319304Speter	size_t blen, len, nlen, tlen;
44254225Speter	CHAR_T *bp, *p;
4519304Speter	int eof, rval;
4619304Speter
4719304Speter	bp = NULL;
4819304Speter
4919304Speter	/* Case 1 -- delete in line mode. */
5019304Speter	if (lmode) {
5119304Speter		for (lno = tm->lno; lno >= fm->lno; --lno) {
5219304Speter			if (db_delete(sp, lno))
5319304Speter				return (1);
5419304Speter			++sp->rptlines[L_DELETED];
5519304Speter			if (lno % INTERRUPT_CHECK == 0 && INTERRUPTED(sp))
5619304Speter				break;
5719304Speter		}
5819304Speter		goto done;
5919304Speter	}
6019304Speter
6119304Speter	/*
6219304Speter	 * Case 2 -- delete to EOF.  This is a special case because it's
6319304Speter	 * easier to pick it off than try and find it in the other cases.
6419304Speter 	 */
6519304Speter	if (db_last(sp, &lno))
6619304Speter		return (1);
6719304Speter	if (tm->lno >= lno) {
6819304Speter		if (tm->lno == lno) {
6919304Speter			if (db_get(sp, lno, DBG_FATAL, &p, &len))
7019304Speter				return (1);
71254225Speter			eof = tm->cno != ENTIRE_LINE && tm->cno >= len ? 1 : 0;
7219304Speter		} else
7319304Speter			eof = 1;
7419304Speter		if (eof) {
7519304Speter			for (lno = tm->lno; lno > fm->lno; --lno) {
7619304Speter				if (db_delete(sp, lno))
7719304Speter					return (1);
7819304Speter				++sp->rptlines[L_DELETED];
7919304Speter				if (lno %
8019304Speter				    INTERRUPT_CHECK == 0 && INTERRUPTED(sp))
8119304Speter					break;
8219304Speter			}
8319304Speter			if (db_get(sp, fm->lno, DBG_FATAL, &p, &len))
8419304Speter				return (1);
85254225Speter			GET_SPACE_RETW(sp, bp, blen, fm->cno);
86254225Speter			MEMCPY(bp, p, fm->cno);
8719304Speter			if (db_set(sp, fm->lno, bp, fm->cno))
8819304Speter				return (1);
8919304Speter			goto done;
9019304Speter		}
9119304Speter	}
9219304Speter
9319304Speter	/* Case 3 -- delete within a single line. */
9419304Speter	if (tm->lno == fm->lno) {
9519304Speter		if (db_get(sp, fm->lno, DBG_FATAL, &p, &len))
9619304Speter			return (1);
97254225Speter		GET_SPACE_RETW(sp, bp, blen, len);
9819304Speter		if (fm->cno != 0)
99254225Speter			MEMCPY(bp, p, fm->cno);
100254225Speter		MEMCPY(bp + fm->cno, p + (tm->cno + 1),
101254225Speter			len - (tm->cno + 1));
10219304Speter		if (db_set(sp, fm->lno,
10319304Speter		    bp, len - ((tm->cno - fm->cno) + 1)))
10419304Speter			goto err;
10519304Speter		goto done;
10619304Speter	}
10719304Speter
10819304Speter	/*
10919304Speter	 * Case 4 -- delete over multiple lines.
11019304Speter	 *
11119304Speter	 * Copy the start partial line into place.
11219304Speter	 */
11319304Speter	if ((tlen = fm->cno) != 0) {
11419304Speter		if (db_get(sp, fm->lno, DBG_FATAL, &p, NULL))
11519304Speter			return (1);
116254225Speter		GET_SPACE_RETW(sp, bp, blen, tlen + 256);
117254225Speter		MEMCPY(bp, p, tlen);
11819304Speter	}
11919304Speter
12019304Speter	/* Copy the end partial line into place. */
12119304Speter	if (db_get(sp, tm->lno, DBG_FATAL, &p, &len))
12219304Speter		goto err;
12319304Speter	if (len != 0 && tm->cno != len - 1) {
12419304Speter		/*
12519304Speter		 * XXX
12619304Speter		 * We can overflow memory here, if the total length is greater
12719304Speter		 * than SIZE_T_MAX.  The only portable way I've found to test
12819304Speter		 * is depending on the overflow being less than the value.
12919304Speter		 */
13019304Speter		nlen = (len - (tm->cno + 1)) + tlen;
13119304Speter		if (tlen > nlen) {
13219304Speter			msgq(sp, M_ERR, "002|Line length overflow");
13319304Speter			goto err;
13419304Speter		}
13519304Speter		if (tlen == 0) {
136254225Speter			GET_SPACE_RETW(sp, bp, blen, nlen);
13719304Speter		} else
138254225Speter			ADD_SPACE_RETW(sp, bp, blen, nlen);
13919304Speter
140254225Speter		MEMCPY(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1));
14119304Speter		tlen += len - (tm->cno + 1);
14219304Speter	}
14319304Speter
14419304Speter	/* Set the current line. */
14519304Speter	if (db_set(sp, fm->lno, bp, tlen))
14619304Speter		goto err;
14719304Speter
14819304Speter	/* Delete the last and intermediate lines. */
14919304Speter	for (lno = tm->lno; lno > fm->lno; --lno) {
15019304Speter		if (db_delete(sp, lno))
15119304Speter			goto err;
15219304Speter		++sp->rptlines[L_DELETED];
15319304Speter		if (lno % INTERRUPT_CHECK == 0 && INTERRUPTED(sp))
15419304Speter			break;
15519304Speter	}
15619304Speter
15719304Speterdone:	rval = 0;
15819304Speter	if (0)
15919304Spetererr:		rval = 1;
16019304Speter	if (bp != NULL)
161254225Speter		FREE_SPACEW(sp, bp, blen);
16219304Speter	return (rval);
16319304Speter}
164