update to 1.01
[nvi.git] / common / delete.c
blob08fbab96c896e65f02cf500c918c77b04e778dfe
1 /*-
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
6 */
8 #ifndef lint
9 static char sccsid[] = "$Id: delete.c,v 8.7 1993/12/09 19:42:05 bostic Exp $ (Berkeley) $Date: 1993/12/09 19:42:05 $";
10 #endif /* not lint */
12 #include <sys/types.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <string.h>
18 #include "vi.h"
21 * delete --
22 * Delete a range of text.
24 int
25 delete(sp, ep, fm, tm, lmode)
26 SCR *sp;
27 EXF *ep;
28 MARK *fm, *tm;
29 int lmode;
31 recno_t lno;
32 size_t blen, len, tlen;
33 char *bp, *p;
34 int eof;
36 #if defined(DEBUG) && 0
37 TRACE(sp, "delete: from %lu/%d to %lu/%d%s\n",
38 fm->lno, fm->cno, tm->lno, tm->cno, lmode ? " (LINE MODE)" : "");
39 #endif
40 bp = NULL;
42 /* Case 1 -- delete in line mode. */
43 if (lmode) {
44 for (lno = tm->lno; lno >= fm->lno; --lno)
45 if (file_dline(sp, ep, lno))
46 return (1);
47 goto vdone;
51 * Case 2 -- delete to EOF. This is a special case because it's
52 * easier to pick it off than try and find it in the other cases.
54 if (file_lline(sp, ep, &lno))
55 return (1);
56 if (tm->lno >= lno) {
57 if (tm->lno == lno) {
58 if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
59 GETLINE_ERR(sp, lno);
60 return (1);
62 eof = tm->cno >= len ? 1 : 0;
63 } else
64 eof = 1;
65 if (eof) {
66 for (lno = tm->lno; lno > fm->lno; --lno) {
67 if (file_dline(sp, ep, lno))
68 return (1);
69 ++sp->rptlines[L_DELETED];
71 if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
72 GETLINE_ERR(sp, fm->lno);
73 return (1);
75 GET_SPACE_RET(sp, bp, blen, fm->cno);
76 memmove(bp, p, fm->cno);
77 if (file_sline(sp, ep, fm->lno, bp, fm->cno))
78 return (1);
79 goto done;
83 /* Case 3 -- delete within a single line. */
84 if (tm->lno == fm->lno) {
85 if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
86 GETLINE_ERR(sp, fm->lno);
87 return (1);
89 GET_SPACE_RET(sp, bp, blen, len);
90 memmove(bp, p, fm->cno);
91 memmove(bp + fm->cno, p + tm->cno, len - tm->cno);
92 if (file_sline(sp, ep, fm->lno, bp, len - (tm->cno - fm->cno)))
93 goto err;
94 goto done;
98 * Case 4 -- delete over multiple lines.
100 * Figure out how big a buffer we need.
102 if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
103 GETLINE_ERR(sp, fm->lno);
104 return (1);
106 tlen = len;
107 if ((p = file_gline(sp, ep, tm->lno, &len)) == NULL) {
108 GETLINE_ERR(sp, tm->lno);
109 return (1);
113 * XXX
114 * We can overflow memory here, if (len + tlen) > SIZE_T_MAX. The
115 * only portable way I've found to test is to depend on the overflow
116 * being less than the value.
118 tlen += len;
119 if (len > tlen) {
120 msgq(sp, M_ERR, "Error: line length overflow");
121 return (1);
124 GET_SPACE_RET(sp, bp, blen, tlen);
126 /* Copy the start partial line into place. */
127 if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
128 GETLINE_ERR(sp, fm->lno);
129 goto err;
131 memmove(bp, p, fm->cno);
132 tlen = fm->cno;
134 /* Copy the end partial line into place. */
135 if ((p = file_gline(sp, ep, tm->lno, &len)) == NULL) {
136 GETLINE_ERR(sp, tm->lno);
137 goto err;
139 memmove(bp + tlen, p + tm->cno, len - tm->cno);
140 tlen += len - tm->cno;
142 /* Set the current line. */
143 if (file_sline(sp, ep, fm->lno, bp, tlen))
144 goto err;
146 /* Delete the last and intermediate lines. */
147 for (lno = tm->lno; lno > fm->lno; --lno)
148 if (file_dline(sp, ep, lno))
149 return (1);
151 /* Reporting. */
152 vdone: sp->rptlines[L_DELETED] += tm->lno - fm->lno + 1;
154 done: if (bp != NULL)
155 FREE_SPACE(sp, bp, blen);
157 return (0);
159 /* Free memory. */
160 err: FREE_SPACE(sp, bp, blen);
162 return (1);