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