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