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