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