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