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