1  | 
     | 
     | 
    /*	$OpenBSD: ex_move.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 <limits.h>  | 
    
    
    19  | 
     | 
     | 
    #include <stdio.h>  | 
    
    
    20  | 
     | 
     | 
    #include <stdlib.h>  | 
    
    
    21  | 
     | 
     | 
    #include <string.h>  | 
    
    
    22  | 
     | 
     | 
     | 
    
    
    23  | 
     | 
     | 
    #include "../common/common.h"  | 
    
    
    24  | 
     | 
     | 
     | 
    
    
    25  | 
     | 
     | 
    /*  | 
    
    
    26  | 
     | 
     | 
     * ex_copy -- :[line [,line]] co[py] line [flags]  | 
    
    
    27  | 
     | 
     | 
     *	Copy selected lines.  | 
    
    
    28  | 
     | 
     | 
     *  | 
    
    
    29  | 
     | 
     | 
     * PUBLIC: int ex_copy(SCR *, EXCMD *);  | 
    
    
    30  | 
     | 
     | 
     */  | 
    
    
    31  | 
     | 
     | 
    int  | 
    
    
    32  | 
     | 
     | 
    ex_copy(SCR *sp, EXCMD *cmdp)  | 
    
    
    33  | 
     | 
     | 
    { | 
    
    
    34  | 
     | 
     | 
    	CB cb;  | 
    
    
    35  | 
     | 
     | 
    	MARK fm1, fm2, m, tm;  | 
    
    
    36  | 
     | 
     | 
    	recno_t cnt;  | 
    
    
    37  | 
     | 
     | 
    	int rval;  | 
    
    
    38  | 
     | 
     | 
     | 
    
    
    39  | 
     | 
     | 
    	rval = 0;  | 
    
    
    40  | 
     | 
     | 
     | 
    
    
    41  | 
     | 
     | 
    	NEEDFILE(sp, cmdp);  | 
    
    
    42  | 
     | 
     | 
     | 
    
    
    43  | 
     | 
     | 
    	/*  | 
    
    
    44  | 
     | 
     | 
    	 * It's possible to copy things into the area that's being  | 
    
    
    45  | 
     | 
     | 
    	 * copied, e.g. "2,5copy3" is legitimate.  Save the text to  | 
    
    
    46  | 
     | 
     | 
    	 * a cut buffer.  | 
    
    
    47  | 
     | 
     | 
    	 */  | 
    
    
    48  | 
     | 
     | 
    	fm1 = cmdp->addr1;  | 
    
    
    49  | 
     | 
     | 
    	fm2 = cmdp->addr2;  | 
    
    
    50  | 
     | 
     | 
    	memset(&cb, 0, sizeof(cb));  | 
    
    
    51  | 
     | 
     | 
    	TAILQ_INIT(&cb.textq);  | 
    
    
    52  | 
     | 
     | 
    	for (cnt = fm1.lno; cnt <= fm2.lno; ++cnt)  | 
    
    
    53  | 
     | 
     | 
    		if (cut_line(sp, cnt, 0, CUT_LINE_TO_EOL, &cb)) { | 
    
    
    54  | 
     | 
     | 
    			rval = 1;  | 
    
    
    55  | 
     | 
     | 
    			goto err;  | 
    
    
    56  | 
     | 
     | 
    		}  | 
    
    
    57  | 
     | 
     | 
    	cb.flags |= CB_LMODE;  | 
    
    
    58  | 
     | 
     | 
     | 
    
    
    59  | 
     | 
     | 
    	/* Put the text into place. */  | 
    
    
    60  | 
     | 
     | 
    	tm.lno = cmdp->lineno;  | 
    
    
    61  | 
     | 
     | 
    	tm.cno = 0;  | 
    
    
    62  | 
     | 
     | 
    	if (put(sp, &cb, NULL, &tm, &m, 1))  | 
    
    
    63  | 
     | 
     | 
    		rval = 1;  | 
    
    
    64  | 
     | 
     | 
    	else { | 
    
    
    65  | 
     | 
     | 
    		/*  | 
    
    
    66  | 
     | 
     | 
    		 * Copy puts the cursor on the last line copied.  The cursor  | 
    
    
    67  | 
     | 
     | 
    		 * returned by the put routine is the first line put, not the  | 
    
    
    68  | 
     | 
     | 
    		 * last, because that's the historic semantic of vi.  | 
    
    
    69  | 
     | 
     | 
    		 */  | 
    
    
    70  | 
     | 
     | 
    		cnt = (fm2.lno - fm1.lno) + 1;  | 
    
    
    71  | 
     | 
     | 
    		sp->lno = m.lno + (cnt - 1);  | 
    
    
    72  | 
     | 
     | 
    		sp->cno = 0;  | 
    
    
    73  | 
     | 
     | 
    	}  | 
    
    
    74  | 
     | 
     | 
    err:	text_lfree(&cb.textq);  | 
    
    
    75  | 
     | 
     | 
    	return (rval);  | 
    
    
    76  | 
     | 
     | 
    }  | 
    
    
    77  | 
     | 
     | 
     | 
    
    
    78  | 
     | 
     | 
    /*  | 
    
    
    79  | 
     | 
     | 
     * ex_move -- :[line [,line]] mo[ve] line  | 
    
    
    80  | 
     | 
     | 
     *	Move selected lines.  | 
    
    
    81  | 
     | 
     | 
     *  | 
    
    
    82  | 
     | 
     | 
     * PUBLIC: int ex_move(SCR *, EXCMD *);  | 
    
    
    83  | 
     | 
     | 
     */  | 
    
    
    84  | 
     | 
     | 
    int  | 
    
    
    85  | 
     | 
     | 
    ex_move(SCR *sp, EXCMD *cmdp)  | 
    
    
    86  | 
     | 
     | 
    { | 
    
    
    87  | 
     | 
     | 
    	LMARK *lmp;  | 
    
    
    88  | 
     | 
     | 
    	MARK fm1, fm2;  | 
    
    
    89  | 
     | 
     | 
    	recno_t cnt, diff, fl, tl, mfl, mtl;  | 
    
    
    90  | 
     | 
     | 
    	size_t blen, len;  | 
    
    
    91  | 
     | 
     | 
    	int mark_reset;  | 
    
    
    92  | 
     | 
     | 
    	char *bp, *p;  | 
    
    
    93  | 
     | 
     | 
     | 
    
    
    94  | 
     | 
     | 
    	NEEDFILE(sp, cmdp);  | 
    
    
    95  | 
     | 
     | 
     | 
    
    
    96  | 
     | 
     | 
    	/*  | 
    
    
    97  | 
     | 
     | 
    	 * It's not possible to move things into the area that's being  | 
    
    
    98  | 
     | 
     | 
    	 * moved.  | 
    
    
    99  | 
     | 
     | 
    	 */  | 
    
    
    100  | 
     | 
     | 
    	fm1 = cmdp->addr1;  | 
    
    
    101  | 
     | 
     | 
    	fm2 = cmdp->addr2;  | 
    
    
    102  | 
     | 
     | 
    	if (cmdp->lineno >= fm1.lno && cmdp->lineno <= fm2.lno) { | 
    
    
    103  | 
     | 
     | 
    		msgq(sp, M_ERR, "Destination line is inside move range");  | 
    
    
    104  | 
     | 
     | 
    		return (1);  | 
    
    
    105  | 
     | 
     | 
    	}  | 
    
    
    106  | 
     | 
     | 
     | 
    
    
    107  | 
     | 
     | 
    	/*  | 
    
    
    108  | 
     | 
     | 
    	 * Log the positions of any marks in the to-be-deleted lines.  This  | 
    
    
    109  | 
     | 
     | 
    	 * has to work with the logging code.  What happens is that we log  | 
    
    
    110  | 
     | 
     | 
    	 * the old mark positions, make the changes, then log the new mark  | 
    
    
    111  | 
     | 
     | 
    	 * positions.  Then the marks end up in the right positions no matter  | 
    
    
    112  | 
     | 
     | 
    	 * which way the log is traversed.  | 
    
    
    113  | 
     | 
     | 
    	 *  | 
    
    
    114  | 
     | 
     | 
    	 * XXX  | 
    
    
    115  | 
     | 
     | 
    	 * Reset the MARK_USERSET flag so that the log can undo the mark.  | 
    
    
    116  | 
     | 
     | 
    	 * This isn't very clean, and should probably be fixed.  | 
    
    
    117  | 
     | 
     | 
    	 */  | 
    
    
    118  | 
     | 
     | 
    	fl = fm1.lno;  | 
    
    
    119  | 
     | 
     | 
    	tl = cmdp->lineno;  | 
    
    
    120  | 
     | 
     | 
     | 
    
    
    121  | 
     | 
     | 
    	/* Log the old positions of the marks. */  | 
    
    
    122  | 
     | 
     | 
    	mark_reset = 0;  | 
    
    
    123  | 
     | 
     | 
    	LIST_FOREACH(lmp, &sp->ep->marks, q)  | 
    
    
    124  | 
     | 
     | 
    		if (lmp->name != ABSMARK1 &&  | 
    
    
    125  | 
     | 
     | 
    		    lmp->lno >= fl && lmp->lno <= tl) { | 
    
    
    126  | 
     | 
     | 
    			mark_reset = 1;  | 
    
    
    127  | 
     | 
     | 
    			F_CLR(lmp, MARK_USERSET);  | 
    
    
    128  | 
     | 
     | 
    			(void)log_mark(sp, lmp);  | 
    
    
    129  | 
     | 
     | 
    		}  | 
    
    
    130  | 
     | 
     | 
     | 
    
    
    131  | 
     | 
     | 
    	/* Get memory for the copy. */  | 
    
    
    132  | 
     | 
     | 
    	GET_SPACE_RET(sp, bp, blen, 256);  | 
    
    
    133  | 
     | 
     | 
     | 
    
    
    134  | 
     | 
     | 
    	/* Move the lines. */  | 
    
    
    135  | 
     | 
     | 
    	diff = (fm2.lno - fm1.lno) + 1;  | 
    
    
    136  | 
     | 
     | 
    	if (tl > fl) {				/* Destination > source. */ | 
    
    
    137  | 
     | 
     | 
    		mfl = tl - diff;  | 
    
    
    138  | 
     | 
     | 
    		mtl = tl;  | 
    
    
    139  | 
     | 
     | 
    		for (cnt = diff; cnt--;) { | 
    
    
    140  | 
     | 
     | 
    			if (db_get(sp, fl, DBG_FATAL, &p, &len))  | 
    
    
    141  | 
     | 
     | 
    				return (1);  | 
    
    
    142  | 
     | 
     | 
    			BINC_RET(sp, bp, blen, len);  | 
    
    
    143  | 
     | 
     | 
    			memcpy(bp, p, len);  | 
    
    
    144  | 
     | 
     | 
    			if (db_append(sp, 1, tl, bp, len))  | 
    
    
    145  | 
     | 
     | 
    				return (1);  | 
    
    
    146  | 
     | 
     | 
    			if (mark_reset)  | 
    
    
    147  | 
     | 
     | 
    				LIST_FOREACH(lmp, &sp->ep->marks, q)  | 
    
    
    148  | 
     | 
     | 
    					if (lmp->name != ABSMARK1 &&  | 
    
    
    149  | 
     | 
     | 
    					    lmp->lno == fl)  | 
    
    
    150  | 
     | 
     | 
    						lmp->lno = tl + 1;  | 
    
    
    151  | 
     | 
     | 
    			if (db_delete(sp, fl))  | 
    
    
    152  | 
     | 
     | 
    				return (1);  | 
    
    
    153  | 
     | 
     | 
    		}  | 
    
    
    154  | 
     | 
     | 
    	} else {				/* Destination < source. */ | 
    
    
    155  | 
     | 
     | 
    		mfl = tl;  | 
    
    
    156  | 
     | 
     | 
    		mtl = tl + diff;  | 
    
    
    157  | 
     | 
     | 
    		for (cnt = diff; cnt--;) { | 
    
    
    158  | 
     | 
     | 
    			if (db_get(sp, fl, DBG_FATAL, &p, &len))  | 
    
    
    159  | 
     | 
     | 
    				return (1);  | 
    
    
    160  | 
     | 
     | 
    			BINC_RET(sp, bp, blen, len);  | 
    
    
    161  | 
     | 
     | 
    			memcpy(bp, p, len);  | 
    
    
    162  | 
     | 
     | 
    			if (db_append(sp, 1, tl++, bp, len))  | 
    
    
    163  | 
     | 
     | 
    				return (1);  | 
    
    
    164  | 
     | 
     | 
    			if (mark_reset)  | 
    
    
    165  | 
     | 
     | 
    				LIST_FOREACH(lmp, &sp->ep->marks, q)  | 
    
    
    166  | 
     | 
     | 
    					if (lmp->name != ABSMARK1 &&  | 
    
    
    167  | 
     | 
     | 
    					    lmp->lno == fl)  | 
    
    
    168  | 
     | 
     | 
    						lmp->lno = tl;  | 
    
    
    169  | 
     | 
     | 
    			++fl;  | 
    
    
    170  | 
     | 
     | 
    			if (db_delete(sp, fl))  | 
    
    
    171  | 
     | 
     | 
    				return (1);  | 
    
    
    172  | 
     | 
     | 
    		}  | 
    
    
    173  | 
     | 
     | 
    	}  | 
    
    
    174  | 
     | 
     | 
    	FREE_SPACE(sp, bp, blen);  | 
    
    
    175  | 
     | 
     | 
     | 
    
    
    176  | 
     | 
     | 
    	sp->lno = tl;				/* Last line moved. */  | 
    
    
    177  | 
     | 
     | 
    	sp->cno = 0;  | 
    
    
    178  | 
     | 
     | 
     | 
    
    
    179  | 
     | 
     | 
    	/* Log the new positions of the marks. */  | 
    
    
    180  | 
     | 
     | 
    	if (mark_reset)  | 
    
    
    181  | 
     | 
     | 
    		LIST_FOREACH(lmp, &sp->ep->marks, q)  | 
    
    
    182  | 
     | 
     | 
    			if (lmp->name != ABSMARK1 &&  | 
    
    
    183  | 
     | 
     | 
    			    lmp->lno >= mfl && lmp->lno <= mtl)  | 
    
    
    184  | 
     | 
     | 
    				(void)log_mark(sp, lmp);  | 
    
    
    185  | 
     | 
     | 
     | 
    
    
    186  | 
     | 
     | 
     | 
    
    
    187  | 
     | 
     | 
    	sp->rptlines[L_MOVED] += diff;  | 
    
    
    188  | 
     | 
     | 
    	return (0);  | 
    
    
    189  | 
     | 
     | 
    }  |