119304Speter/*- 219304Speter * Copyright (c) 1992, 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 819304Speter */ 919304Speter 1019304Speter#include "config.h" 1119304Speter 1219304Speter#ifndef lint 13254225Speterstatic const char sccsid[] = "$Id: delete.c,v 10.18 2012/02/11 15:52:33 zy Exp $"; 1419304Speter#endif /* not lint */ 1519304Speter 1619304Speter#include <sys/types.h> 1719304Speter#include <sys/queue.h> 18254225Speter#include <sys/time.h> 1919304Speter 2019304Speter#include <bitstring.h> 2119304Speter#include <errno.h> 2219304Speter#include <limits.h> 2319304Speter#include <stdio.h> 2419304Speter#include <stdlib.h> 2519304Speter#include <string.h> 2619304Speter 2719304Speter#include "common.h" 2819304Speter 2919304Speter/* 3019304Speter * del -- 3119304Speter * Delete a range of text. 3219304Speter * 3319304Speter * PUBLIC: int del __P((SCR *, MARK *, MARK *, int)); 3419304Speter */ 3519304Speterint 36254225Speterdel( 37254225Speter SCR *sp, 38254225Speter MARK *fm, 39254225Speter MARK *tm, 40254225Speter int lmode) 4119304Speter{ 4219304Speter recno_t lno; 4319304Speter size_t blen, len, nlen, tlen; 44254225Speter CHAR_T *bp, *p; 4519304Speter int eof, rval; 4619304Speter 4719304Speter bp = NULL; 4819304Speter 4919304Speter /* Case 1 -- delete in line mode. */ 5019304Speter if (lmode) { 5119304Speter for (lno = tm->lno; lno >= fm->lno; --lno) { 5219304Speter if (db_delete(sp, lno)) 5319304Speter return (1); 5419304Speter ++sp->rptlines[L_DELETED]; 5519304Speter if (lno % INTERRUPT_CHECK == 0 && INTERRUPTED(sp)) 5619304Speter break; 5719304Speter } 5819304Speter goto done; 5919304Speter } 6019304Speter 6119304Speter /* 6219304Speter * Case 2 -- delete to EOF. This is a special case because it's 6319304Speter * easier to pick it off than try and find it in the other cases. 6419304Speter */ 6519304Speter if (db_last(sp, &lno)) 6619304Speter return (1); 6719304Speter if (tm->lno >= lno) { 6819304Speter if (tm->lno == lno) { 6919304Speter if (db_get(sp, lno, DBG_FATAL, &p, &len)) 7019304Speter return (1); 71254225Speter eof = tm->cno != ENTIRE_LINE && tm->cno >= len ? 1 : 0; 7219304Speter } else 7319304Speter eof = 1; 7419304Speter if (eof) { 7519304Speter for (lno = tm->lno; lno > fm->lno; --lno) { 7619304Speter if (db_delete(sp, lno)) 7719304Speter return (1); 7819304Speter ++sp->rptlines[L_DELETED]; 7919304Speter if (lno % 8019304Speter INTERRUPT_CHECK == 0 && INTERRUPTED(sp)) 8119304Speter break; 8219304Speter } 8319304Speter if (db_get(sp, fm->lno, DBG_FATAL, &p, &len)) 8419304Speter return (1); 85254225Speter GET_SPACE_RETW(sp, bp, blen, fm->cno); 86254225Speter MEMCPY(bp, p, fm->cno); 8719304Speter if (db_set(sp, fm->lno, bp, fm->cno)) 8819304Speter return (1); 8919304Speter goto done; 9019304Speter } 9119304Speter } 9219304Speter 9319304Speter /* Case 3 -- delete within a single line. */ 9419304Speter if (tm->lno == fm->lno) { 9519304Speter if (db_get(sp, fm->lno, DBG_FATAL, &p, &len)) 9619304Speter return (1); 97254225Speter GET_SPACE_RETW(sp, bp, blen, len); 9819304Speter if (fm->cno != 0) 99254225Speter MEMCPY(bp, p, fm->cno); 100254225Speter MEMCPY(bp + fm->cno, p + (tm->cno + 1), 101254225Speter len - (tm->cno + 1)); 10219304Speter if (db_set(sp, fm->lno, 10319304Speter bp, len - ((tm->cno - fm->cno) + 1))) 10419304Speter goto err; 10519304Speter goto done; 10619304Speter } 10719304Speter 10819304Speter /* 10919304Speter * Case 4 -- delete over multiple lines. 11019304Speter * 11119304Speter * Copy the start partial line into place. 11219304Speter */ 11319304Speter if ((tlen = fm->cno) != 0) { 11419304Speter if (db_get(sp, fm->lno, DBG_FATAL, &p, NULL)) 11519304Speter return (1); 116254225Speter GET_SPACE_RETW(sp, bp, blen, tlen + 256); 117254225Speter MEMCPY(bp, p, tlen); 11819304Speter } 11919304Speter 12019304Speter /* Copy the end partial line into place. */ 12119304Speter if (db_get(sp, tm->lno, DBG_FATAL, &p, &len)) 12219304Speter goto err; 12319304Speter if (len != 0 && tm->cno != len - 1) { 12419304Speter /* 12519304Speter * XXX 12619304Speter * We can overflow memory here, if the total length is greater 12719304Speter * than SIZE_T_MAX. The only portable way I've found to test 12819304Speter * is depending on the overflow being less than the value. 12919304Speter */ 13019304Speter nlen = (len - (tm->cno + 1)) + tlen; 13119304Speter if (tlen > nlen) { 13219304Speter msgq(sp, M_ERR, "002|Line length overflow"); 13319304Speter goto err; 13419304Speter } 13519304Speter if (tlen == 0) { 136254225Speter GET_SPACE_RETW(sp, bp, blen, nlen); 13719304Speter } else 138254225Speter ADD_SPACE_RETW(sp, bp, blen, nlen); 13919304Speter 140254225Speter MEMCPY(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1)); 14119304Speter tlen += len - (tm->cno + 1); 14219304Speter } 14319304Speter 14419304Speter /* Set the current line. */ 14519304Speter if (db_set(sp, fm->lno, bp, tlen)) 14619304Speter goto err; 14719304Speter 14819304Speter /* Delete the last and intermediate lines. */ 14919304Speter for (lno = tm->lno; lno > fm->lno; --lno) { 15019304Speter if (db_delete(sp, lno)) 15119304Speter goto err; 15219304Speter ++sp->rptlines[L_DELETED]; 15319304Speter if (lno % INTERRUPT_CHECK == 0 && INTERRUPTED(sp)) 15419304Speter break; 15519304Speter } 15619304Speter 15719304Speterdone: rval = 0; 15819304Speter if (0) 15919304Spetererr: rval = 1; 16019304Speter if (bp != NULL) 161254225Speter FREE_SPACEW(sp, bp, blen); 16219304Speter return (rval); 16319304Speter} 164