source: trunk/third/nvi/common/delete.c @ 14302

Revision 14302, 3.5 KB checked in by ghudson, 25 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14301, which included commits to RCS files with non-trunk default branches.
Line 
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
13static const char sccsid[] = "@(#)delete.c      10.12 (Berkeley) 10/23/96";
14#endif /* not lint */
15
16#include <sys/types.h>
17#include <sys/queue.h>
18
19#include <bitstring.h>
20#include <errno.h>
21#include <limits.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include "common.h"
27
28/*
29 * del --
30 *      Delete a range of text.
31 *
32 * PUBLIC: int del __P((SCR *, MARK *, MARK *, int));
33 */
34int
35del(sp, fm, tm, lmode)
36        SCR *sp;
37        MARK *fm, *tm;
38        int lmode;
39{
40        recno_t lno;
41        size_t blen, len, nlen, tlen;
42        char *bp, *p;
43        int eof, rval;
44
45        bp = NULL;
46
47        /* Case 1 -- delete in line mode. */
48        if (lmode) {
49                for (lno = tm->lno; lno >= fm->lno; --lno) {
50                        if (db_delete(sp, lno))
51                                return (1);
52                        ++sp->rptlines[L_DELETED];
53                        if (lno % INTERRUPT_CHECK == 0 && INTERRUPTED(sp))
54                                break;
55                }
56                goto done;
57        }
58
59        /*
60         * Case 2 -- delete to EOF.  This is a special case because it's
61         * easier to pick it off than try and find it in the other cases.
62         */
63        if (db_last(sp, &lno))
64                return (1);
65        if (tm->lno >= lno) {
66                if (tm->lno == lno) {
67                        if (db_get(sp, lno, DBG_FATAL, &p, &len))
68                                return (1);
69                        eof = tm->cno >= len ? 1 : 0;
70                } else
71                        eof = 1;
72                if (eof) {
73                        for (lno = tm->lno; lno > fm->lno; --lno) {
74                                if (db_delete(sp, lno))
75                                        return (1);
76                                ++sp->rptlines[L_DELETED];
77                                if (lno %
78                                    INTERRUPT_CHECK == 0 && INTERRUPTED(sp))
79                                        break;
80                        }
81                        if (db_get(sp, fm->lno, DBG_FATAL, &p, &len))
82                                return (1);
83                        GET_SPACE_RET(sp, bp, blen, fm->cno);
84                        memcpy(bp, p, fm->cno);
85                        if (db_set(sp, fm->lno, bp, fm->cno))
86                                return (1);
87                        goto done;
88                }
89        }
90
91        /* Case 3 -- delete within a single line. */
92        if (tm->lno == fm->lno) {
93                if (db_get(sp, fm->lno, DBG_FATAL, &p, &len))
94                        return (1);
95                GET_SPACE_RET(sp, bp, blen, len);
96                if (fm->cno != 0)
97                        memcpy(bp, p, fm->cno);
98                memcpy(bp + fm->cno, p + (tm->cno + 1), len - (tm->cno + 1));
99                if (db_set(sp, fm->lno,
100                    bp, len - ((tm->cno - fm->cno) + 1)))
101                        goto err;
102                goto done;
103        }
104
105        /*
106         * Case 4 -- delete over multiple lines.
107         *
108         * Copy the start partial line into place.
109         */
110        if ((tlen = fm->cno) != 0) {
111                if (db_get(sp, fm->lno, DBG_FATAL, &p, NULL))
112                        return (1);
113                GET_SPACE_RET(sp, bp, blen, tlen + 256);
114                memcpy(bp, p, tlen);
115        }
116
117        /* Copy the end partial line into place. */
118        if (db_get(sp, tm->lno, DBG_FATAL, &p, &len))
119                goto err;
120        if (len != 0 && tm->cno != len - 1) {
121                /*
122                 * XXX
123                 * We can overflow memory here, if the total length is greater
124                 * than SIZE_T_MAX.  The only portable way I've found to test
125                 * is depending on the overflow being less than the value.
126                 */
127                nlen = (len - (tm->cno + 1)) + tlen;
128                if (tlen > nlen) {
129                        msgq(sp, M_ERR, "002|Line length overflow");
130                        goto err;
131                }
132                if (tlen == 0) {
133                        GET_SPACE_RET(sp, bp, blen, nlen);
134                } else
135                        ADD_SPACE_RET(sp, bp, blen, nlen);
136
137                memcpy(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1));
138                tlen += len - (tm->cno + 1);
139        }
140
141        /* Set the current line. */
142        if (db_set(sp, fm->lno, bp, tlen))
143                goto err;
144
145        /* Delete the last and intermediate lines. */
146        for (lno = tm->lno; lno > fm->lno; --lno) {
147                if (db_delete(sp, lno))
148                        goto err;
149                ++sp->rptlines[L_DELETED];
150                if (lno % INTERRUPT_CHECK == 0 && INTERRUPTED(sp))
151                        break;
152        }
153
154done:   rval = 0;
155        if (0)
156err:            rval = 1;
157        if (bp != NULL)
158                FREE_SPACE(sp, bp, blen);
159        return (rval);
160}
Note: See TracBrowser for help on using the repository browser.