xref: /dflybsd-src/contrib/nvi2/common/delete.c (revision 07bc39c2f4bbca56f12568e06d89da17f2eeb965)
1e0b8e63eSJohn Marino /*-
2e0b8e63eSJohn Marino  * Copyright (c) 1992, 1993, 1994
3e0b8e63eSJohn Marino  *	The Regents of the University of California.  All rights reserved.
4e0b8e63eSJohn Marino  * Copyright (c) 1992, 1993, 1994, 1995, 1996
5e0b8e63eSJohn Marino  *	Keith Bostic.  All rights reserved.
6e0b8e63eSJohn Marino  *
7e0b8e63eSJohn Marino  * See the LICENSE file for redistribution information.
8e0b8e63eSJohn Marino  */
9e0b8e63eSJohn Marino 
10e0b8e63eSJohn Marino #include "config.h"
11e0b8e63eSJohn Marino 
12e0b8e63eSJohn Marino #include <sys/types.h>
13e0b8e63eSJohn Marino #include <sys/queue.h>
14e0b8e63eSJohn Marino #include <sys/time.h>
15e0b8e63eSJohn Marino 
16e0b8e63eSJohn Marino #include <bitstring.h>
17e0b8e63eSJohn Marino #include <errno.h>
18e0b8e63eSJohn Marino #include <limits.h>
19e0b8e63eSJohn Marino #include <stdio.h>
20e0b8e63eSJohn Marino #include <stdlib.h>
21e0b8e63eSJohn Marino #include <string.h>
22e0b8e63eSJohn Marino 
23e0b8e63eSJohn Marino #include "common.h"
24e0b8e63eSJohn Marino 
25e0b8e63eSJohn Marino /*
26e0b8e63eSJohn Marino  * del --
27e0b8e63eSJohn Marino  *	Delete a range of text.
28e0b8e63eSJohn Marino  *
29e0b8e63eSJohn Marino  * PUBLIC: int del(SCR *, MARK *, MARK *, int);
30e0b8e63eSJohn Marino  */
31e0b8e63eSJohn Marino int
del(SCR * sp,MARK * fm,MARK * tm,int lmode)32*b1ac2ebbSDaniel Fojt del(SCR *sp, MARK *fm, MARK *tm, int lmode)
33e0b8e63eSJohn Marino {
34e0b8e63eSJohn Marino 	recno_t lno;
35e0b8e63eSJohn Marino 	size_t blen, len, nlen, tlen;
36e0b8e63eSJohn Marino 	CHAR_T *bp, *p;
37e0b8e63eSJohn Marino 	int eof, rval;
38e0b8e63eSJohn Marino 
39e0b8e63eSJohn Marino 	bp = NULL;
40e0b8e63eSJohn Marino 
41e0b8e63eSJohn Marino 	/* Case 1 -- delete in line mode. */
42e0b8e63eSJohn Marino 	if (lmode) {
43e0b8e63eSJohn Marino 		for (lno = tm->lno; lno >= fm->lno; --lno) {
44e0b8e63eSJohn Marino 			if (db_delete(sp, lno))
45e0b8e63eSJohn Marino 				return (1);
46e0b8e63eSJohn Marino 			++sp->rptlines[L_DELETED];
47e0b8e63eSJohn Marino 			if (lno % INTERRUPT_CHECK == 0 && INTERRUPTED(sp))
48e0b8e63eSJohn Marino 				break;
49e0b8e63eSJohn Marino 		}
50e0b8e63eSJohn Marino 		goto done;
51e0b8e63eSJohn Marino 	}
52e0b8e63eSJohn Marino 
53e0b8e63eSJohn Marino 	/*
54e0b8e63eSJohn Marino 	 * Case 2 -- delete to EOF.  This is a special case because it's
55e0b8e63eSJohn Marino 	 * easier to pick it off than try and find it in the other cases.
56e0b8e63eSJohn Marino  	 */
57e0b8e63eSJohn Marino 	if (db_last(sp, &lno))
58e0b8e63eSJohn Marino 		return (1);
59e0b8e63eSJohn Marino 	if (tm->lno >= lno) {
60e0b8e63eSJohn Marino 		if (tm->lno == lno) {
61e0b8e63eSJohn Marino 			if (db_get(sp, lno, DBG_FATAL, &p, &len))
62e0b8e63eSJohn Marino 				return (1);
63e0b8e63eSJohn Marino 			eof = tm->cno != ENTIRE_LINE && tm->cno >= len ? 1 : 0;
64e0b8e63eSJohn Marino 		} else
65e0b8e63eSJohn Marino 			eof = 1;
66e0b8e63eSJohn Marino 		if (eof) {
67e0b8e63eSJohn Marino 			for (lno = tm->lno; lno > fm->lno; --lno) {
68e0b8e63eSJohn Marino 				if (db_delete(sp, lno))
69e0b8e63eSJohn Marino 					return (1);
70e0b8e63eSJohn Marino 				++sp->rptlines[L_DELETED];
71e0b8e63eSJohn Marino 				if (lno %
72e0b8e63eSJohn Marino 				    INTERRUPT_CHECK == 0 && INTERRUPTED(sp))
73e0b8e63eSJohn Marino 					break;
74e0b8e63eSJohn Marino 			}
75e0b8e63eSJohn Marino 			if (db_get(sp, fm->lno, DBG_FATAL, &p, &len))
76e0b8e63eSJohn Marino 				return (1);
77e0b8e63eSJohn Marino 			GET_SPACE_RETW(sp, bp, blen, fm->cno);
78e0b8e63eSJohn Marino 			MEMCPY(bp, p, fm->cno);
79e0b8e63eSJohn Marino 			if (db_set(sp, fm->lno, bp, fm->cno))
80e0b8e63eSJohn Marino 				return (1);
81e0b8e63eSJohn Marino 			goto done;
82e0b8e63eSJohn Marino 		}
83e0b8e63eSJohn Marino 	}
84e0b8e63eSJohn Marino 
85e0b8e63eSJohn Marino 	/* Case 3 -- delete within a single line. */
86e0b8e63eSJohn Marino 	if (tm->lno == fm->lno) {
87e0b8e63eSJohn Marino 		if (db_get(sp, fm->lno, DBG_FATAL, &p, &len))
88e0b8e63eSJohn Marino 			return (1);
89*b1ac2ebbSDaniel Fojt 		if (len != 0) {
90e0b8e63eSJohn Marino 			GET_SPACE_RETW(sp, bp, blen, len);
91e0b8e63eSJohn Marino 			if (fm->cno != 0)
92e0b8e63eSJohn Marino 				MEMCPY(bp, p, fm->cno);
93e0b8e63eSJohn Marino 			MEMCPY(bp + fm->cno, p + (tm->cno + 1),
94e0b8e63eSJohn Marino 			    len - (tm->cno + 1));
95e0b8e63eSJohn Marino 			if (db_set(sp, fm->lno,
96e0b8e63eSJohn Marino 			    bp, len - ((tm->cno - fm->cno) + 1)))
97e0b8e63eSJohn Marino 				goto err;
98*b1ac2ebbSDaniel Fojt 		}
99e0b8e63eSJohn Marino 		goto done;
100e0b8e63eSJohn Marino 	}
101e0b8e63eSJohn Marino 
102e0b8e63eSJohn Marino 	/*
103e0b8e63eSJohn Marino 	 * Case 4 -- delete over multiple lines.
104e0b8e63eSJohn Marino 	 *
105e0b8e63eSJohn Marino 	 * Copy the start partial line into place.
106e0b8e63eSJohn Marino 	 */
107e0b8e63eSJohn Marino 	if ((tlen = fm->cno) != 0) {
108e0b8e63eSJohn Marino 		if (db_get(sp, fm->lno, DBG_FATAL, &p, NULL))
109e0b8e63eSJohn Marino 			return (1);
110e0b8e63eSJohn Marino 		GET_SPACE_RETW(sp, bp, blen, tlen + 256);
111e0b8e63eSJohn Marino 		MEMCPY(bp, p, tlen);
112e0b8e63eSJohn Marino 	}
113e0b8e63eSJohn Marino 
114e0b8e63eSJohn Marino 	/* Copy the end partial line into place. */
115e0b8e63eSJohn Marino 	if (db_get(sp, tm->lno, DBG_FATAL, &p, &len))
116e0b8e63eSJohn Marino 		goto err;
117e0b8e63eSJohn Marino 	if (len != 0 && tm->cno != len - 1) {
118e0b8e63eSJohn Marino 		/*
119e0b8e63eSJohn Marino 		 * XXX
120e0b8e63eSJohn Marino 		 * We can overflow memory here, if the total length is greater
121e0b8e63eSJohn Marino 		 * than SIZE_T_MAX.  The only portable way I've found to test
122e0b8e63eSJohn Marino 		 * is depending on the overflow being less than the value.
123e0b8e63eSJohn Marino 		 */
124e0b8e63eSJohn Marino 		nlen = (len - (tm->cno + 1)) + tlen;
125e0b8e63eSJohn Marino 		if (tlen > nlen) {
126e0b8e63eSJohn Marino 			msgq(sp, M_ERR, "002|Line length overflow");
127e0b8e63eSJohn Marino 			goto err;
128e0b8e63eSJohn Marino 		}
129e0b8e63eSJohn Marino 		if (tlen == 0) {
130e0b8e63eSJohn Marino 			GET_SPACE_RETW(sp, bp, blen, nlen);
131e0b8e63eSJohn Marino 		} else
132e0b8e63eSJohn Marino 			ADD_SPACE_RETW(sp, bp, blen, nlen);
133e0b8e63eSJohn Marino 
134e0b8e63eSJohn Marino 		MEMCPY(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1));
135e0b8e63eSJohn Marino 		tlen += len - (tm->cno + 1);
136e0b8e63eSJohn Marino 	}
137e0b8e63eSJohn Marino 
138e0b8e63eSJohn Marino 	/* Set the current line. */
139e0b8e63eSJohn Marino 	if (db_set(sp, fm->lno, bp, tlen))
140e0b8e63eSJohn Marino 		goto err;
141e0b8e63eSJohn Marino 
142e0b8e63eSJohn Marino 	/* Delete the last and intermediate lines. */
143e0b8e63eSJohn Marino 	for (lno = tm->lno; lno > fm->lno; --lno) {
144e0b8e63eSJohn Marino 		if (db_delete(sp, lno))
145e0b8e63eSJohn Marino 			goto err;
146e0b8e63eSJohn Marino 		++sp->rptlines[L_DELETED];
147e0b8e63eSJohn Marino 		if (lno % INTERRUPT_CHECK == 0 && INTERRUPTED(sp))
148e0b8e63eSJohn Marino 			break;
149e0b8e63eSJohn Marino 	}
150e0b8e63eSJohn Marino 
151e0b8e63eSJohn Marino done:	rval = 0;
152e0b8e63eSJohn Marino 	if (0)
153e0b8e63eSJohn Marino err:		rval = 1;
154e0b8e63eSJohn Marino 	if (bp != NULL)
155e0b8e63eSJohn Marino 		FREE_SPACEW(sp, bp, blen);
156e0b8e63eSJohn Marino 	return (rval);
157e0b8e63eSJohn Marino }
158