1 |
|
|
/* $OpenBSD: delete.c,v 1.11 2016/01/06 22:28:52 millert 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 |
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 |
|
|
GET_SPACE_RET(sp, bp, blen, len); |
91 |
|
|
if (fm->cno != 0) |
92 |
|
|
memcpy(bp, p, fm->cno); |
93 |
|
|
memcpy(bp + fm->cno, p + (tm->cno + 1), len - (tm->cno + 1)); |
94 |
|
|
if (db_set(sp, fm->lno, |
95 |
|
|
bp, len - ((tm->cno - fm->cno) + 1))) |
96 |
|
|
goto err; |
97 |
|
|
goto done; |
98 |
|
|
} |
99 |
|
|
|
100 |
|
|
/* |
101 |
|
|
* Case 4 -- delete over multiple lines. |
102 |
|
|
* |
103 |
|
|
* Copy the start partial line into place. |
104 |
|
|
*/ |
105 |
|
|
if ((tlen = fm->cno) != 0) { |
106 |
|
|
if (db_get(sp, fm->lno, DBG_FATAL, &p, NULL)) |
107 |
|
|
return (1); |
108 |
|
|
GET_SPACE_RET(sp, bp, blen, tlen + 256); |
109 |
|
|
memcpy(bp, p, tlen); |
110 |
|
|
} |
111 |
|
|
|
112 |
|
|
/* Copy the end partial line into place. */ |
113 |
|
|
if (db_get(sp, tm->lno, DBG_FATAL, &p, &len)) |
114 |
|
|
goto err; |
115 |
|
|
if (len != 0 && tm->cno != len - 1) { |
116 |
|
|
if (len < tm->cno + 1 || len - (tm->cno + 1) > SIZE_MAX - tlen) { |
117 |
|
|
msgq(sp, M_ERR, "Line length overflow"); |
118 |
|
|
goto err; |
119 |
|
|
} |
120 |
|
|
nlen = (len - (tm->cno + 1)) + tlen; |
121 |
|
|
if (tlen == 0) { |
122 |
|
|
GET_SPACE_RET(sp, bp, blen, nlen); |
123 |
|
|
} else |
124 |
|
|
ADD_SPACE_RET(sp, bp, blen, nlen); |
125 |
|
|
|
126 |
|
|
memcpy(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1)); |
127 |
|
|
tlen += len - (tm->cno + 1); |
128 |
|
|
} |
129 |
|
|
|
130 |
|
|
/* Set the current line. */ |
131 |
|
|
if (db_set(sp, fm->lno, bp, tlen)) |
132 |
|
|
goto err; |
133 |
|
|
|
134 |
|
|
/* Delete the last and intermediate lines. */ |
135 |
|
|
for (lno = tm->lno; lno > fm->lno; --lno) { |
136 |
|
|
if (db_delete(sp, lno)) |
137 |
|
|
goto err; |
138 |
|
|
++sp->rptlines[L_DELETED]; |
139 |
|
|
if (lno % INTERRUPT_CHECK == 0 && INTERRUPTED(sp)) |
140 |
|
|
break; |
141 |
|
|
} |
142 |
|
|
|
143 |
|
|
done: rval = 0; |
144 |
|
|
if (0) |
145 |
|
|
err: rval = 1; |
146 |
|
|
if (bp != NULL) |
147 |
|
|
FREE_SPACE(sp, bp, blen); |
148 |
|
|
return (rval); |
149 |
|
|
} |