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