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