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