1  | 
     | 
     | 
    /*	$OpenBSD: yank.c,v 1.14 2015/12/11 20:21:23 mmcc Exp $	*/  | 
    
    
    2  | 
     | 
     | 
     | 
    
    
    3  | 
     | 
     | 
    /* This file is in the public domain. */  | 
    
    
    4  | 
     | 
     | 
     | 
    
    
    5  | 
     | 
     | 
    /*  | 
    
    
    6  | 
     | 
     | 
     *	kill ring functions  | 
    
    
    7  | 
     | 
     | 
     */  | 
    
    
    8  | 
     | 
     | 
     | 
    
    
    9  | 
     | 
     | 
    #include <sys/queue.h>  | 
    
    
    10  | 
     | 
     | 
    #include <signal.h>  | 
    
    
    11  | 
     | 
     | 
    #include <stdio.h>  | 
    
    
    12  | 
     | 
     | 
    #include <stdlib.h>  | 
    
    
    13  | 
     | 
     | 
    #include <string.h>  | 
    
    
    14  | 
     | 
     | 
     | 
    
    
    15  | 
     | 
     | 
    #include "def.h"  | 
    
    
    16  | 
     | 
     | 
     | 
    
    
    17  | 
     | 
     | 
    #define KBLOCK	 8192		/* Kill grow.                    */  | 
    
    
    18  | 
     | 
     | 
     | 
    
    
    19  | 
     | 
     | 
    static char	*kbufp = NULL;	/* Kill buffer data.		 */  | 
    
    
    20  | 
     | 
     | 
    static RSIZE	 kused = 0;	/* # of bytes used in KB.	 */  | 
    
    
    21  | 
     | 
     | 
    static RSIZE	 ksize = 0;	/* # of bytes allocated in KB.	 */  | 
    
    
    22  | 
     | 
     | 
    static RSIZE	 kstart = 0;	/* # of first used byte in KB.	 */  | 
    
    
    23  | 
     | 
     | 
     | 
    
    
    24  | 
     | 
     | 
    static int	 kgrow(int);  | 
    
    
    25  | 
     | 
     | 
     | 
    
    
    26  | 
     | 
     | 
    /*  | 
    
    
    27  | 
     | 
     | 
     * Delete all of the text saved in the kill buffer.  Called by commands when  | 
    
    
    28  | 
     | 
     | 
     * a new kill context is created. The kill buffer array is released, just in  | 
    
    
    29  | 
     | 
     | 
     * case the buffer has grown to an immense size.  No errors.  | 
    
    
    30  | 
     | 
     | 
     */  | 
    
    
    31  | 
     | 
     | 
    void  | 
    
    
    32  | 
     | 
     | 
    kdelete(void)  | 
    
    
    33  | 
     | 
     | 
    { | 
    
    
    34  | 
     | 
     | 
    	if (kbufp != NULL) { | 
    
    
    35  | 
     | 
     | 
    		free(kbufp);  | 
    
    
    36  | 
     | 
     | 
    		kbufp = NULL;  | 
    
    
    37  | 
     | 
     | 
    		kstart = kused = ksize = 0;  | 
    
    
    38  | 
     | 
     | 
    	}  | 
    
    
    39  | 
     | 
     | 
    }  | 
    
    
    40  | 
     | 
     | 
     | 
    
    
    41  | 
     | 
     | 
    /*  | 
    
    
    42  | 
     | 
     | 
     * Insert a character to the kill buffer, enlarging the buffer if there  | 
    
    
    43  | 
     | 
     | 
     * isn't any room. Always grow the buffer in chunks, on the assumption  | 
    
    
    44  | 
     | 
     | 
     * that if you put something in the kill buffer you are going to put more  | 
    
    
    45  | 
     | 
     | 
     * stuff there too later. Return TRUE if all is well, and FALSE on errors.  | 
    
    
    46  | 
     | 
     | 
     * Print a message on errors.  Dir says whether to put it at back or front.  | 
    
    
    47  | 
     | 
     | 
     * This call is ignored if  KNONE is set.  | 
    
    
    48  | 
     | 
     | 
     */  | 
    
    
    49  | 
     | 
     | 
    int  | 
    
    
    50  | 
     | 
     | 
    kinsert(int c, int dir)  | 
    
    
    51  | 
     | 
     | 
    { | 
    
    
    52  | 
     | 
     | 
    	if (dir == KNONE)  | 
    
    
    53  | 
     | 
     | 
    		return (TRUE);  | 
    
    
    54  | 
     | 
     | 
    	if (kused == ksize && dir == KFORW && kgrow(dir) == FALSE)  | 
    
    
    55  | 
     | 
     | 
    		return (FALSE);  | 
    
    
    56  | 
     | 
     | 
    	if (kstart == 0 && dir == KBACK && kgrow(dir) == FALSE)  | 
    
    
    57  | 
     | 
     | 
    		return (FALSE);  | 
    
    
    58  | 
     | 
     | 
    	if (dir == KFORW)  | 
    
    
    59  | 
     | 
     | 
    		kbufp[kused++] = c;  | 
    
    
    60  | 
     | 
     | 
    	else if (dir == KBACK)  | 
    
    
    61  | 
     | 
     | 
    		kbufp[--kstart] = c;  | 
    
    
    62  | 
     | 
     | 
    	else  | 
    
    
    63  | 
     | 
     | 
    		panic("broken kinsert call");	/* Oh shit! */ | 
    
    
    64  | 
     | 
     | 
    	return (TRUE);  | 
    
    
    65  | 
     | 
     | 
    }  | 
    
    
    66  | 
     | 
     | 
     | 
    
    
    67  | 
     | 
     | 
    /*  | 
    
    
    68  | 
     | 
     | 
     * kgrow - just get more kill buffer for the callee. If dir = KBACK  | 
    
    
    69  | 
     | 
     | 
     * we are trying to get space at the beginning of the kill buffer.  | 
    
    
    70  | 
     | 
     | 
     */  | 
    
    
    71  | 
     | 
     | 
    static int  | 
    
    
    72  | 
     | 
     | 
    kgrow(int dir)  | 
    
    
    73  | 
     | 
     | 
    { | 
    
    
    74  | 
     | 
     | 
    	int	 nstart;  | 
    
    
    75  | 
     | 
     | 
    	char	*nbufp;  | 
    
    
    76  | 
     | 
     | 
     | 
    
    
    77  | 
     | 
     | 
    	if ((unsigned)(ksize + KBLOCK) <= (unsigned)ksize) { | 
    
    
    78  | 
     | 
     | 
    		/* probably 16 bit unsigned */  | 
    
    
    79  | 
     | 
     | 
    		dobeep();  | 
    
    
    80  | 
     | 
     | 
    		ewprintf("Kill buffer size at maximum"); | 
    
    
    81  | 
     | 
     | 
    		return (FALSE);  | 
    
    
    82  | 
     | 
     | 
    	}  | 
    
    
    83  | 
     | 
     | 
    	if ((nbufp = malloc((unsigned)(ksize + KBLOCK))) == NULL) { | 
    
    
    84  | 
     | 
     | 
    		dobeep();  | 
    
    
    85  | 
     | 
     | 
    		ewprintf("Can't get %ld bytes", (long)(ksize + KBLOCK)); | 
    
    
    86  | 
     | 
     | 
    		return (FALSE);  | 
    
    
    87  | 
     | 
     | 
    	}  | 
    
    
    88  | 
     | 
     | 
    	nstart = (dir == KBACK) ? (kstart + KBLOCK) : (KBLOCK / 4);  | 
    
    
    89  | 
     | 
     | 
    	bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (int)(kused - kstart));  | 
    
    
    90  | 
     | 
     | 
    	free(kbufp);  | 
    
    
    91  | 
     | 
     | 
    	kbufp = nbufp;  | 
    
    
    92  | 
     | 
     | 
    	ksize += KBLOCK;  | 
    
    
    93  | 
     | 
     | 
    	kused = kused - kstart + nstart;  | 
    
    
    94  | 
     | 
     | 
    	kstart = nstart;  | 
    
    
    95  | 
     | 
     | 
    	return (TRUE);  | 
    
    
    96  | 
     | 
     | 
    }  | 
    
    
    97  | 
     | 
     | 
     | 
    
    
    98  | 
     | 
     | 
    /*  | 
    
    
    99  | 
     | 
     | 
     * This function gets characters from the kill buffer. If the character  | 
    
    
    100  | 
     | 
     | 
     * index "n" is off the end, it returns "-1". This lets the caller just  | 
    
    
    101  | 
     | 
     | 
     * scan along until it gets a "-1" back.  | 
    
    
    102  | 
     | 
     | 
     */  | 
    
    
    103  | 
     | 
     | 
    int  | 
    
    
    104  | 
     | 
     | 
    kremove(int n)  | 
    
    
    105  | 
     | 
     | 
    { | 
    
    
    106  | 
     | 
     | 
    	if (n < 0 || n + kstart >= kused)  | 
    
    
    107  | 
     | 
     | 
    		return (-1);  | 
    
    
    108  | 
     | 
     | 
    	return (CHARMASK(kbufp[n + kstart]));  | 
    
    
    109  | 
     | 
     | 
    }  | 
    
    
    110  | 
     | 
     | 
     | 
    
    
    111  | 
     | 
     | 
    /*  | 
    
    
    112  | 
     | 
     | 
     * Copy a string into the kill buffer. kflag gives direction.  | 
    
    
    113  | 
     | 
     | 
     * if KNONE, do nothing.  | 
    
    
    114  | 
     | 
     | 
     */  | 
    
    
    115  | 
     | 
     | 
    int  | 
    
    
    116  | 
     | 
     | 
    kchunk(char *cp1, RSIZE chunk, int kflag)  | 
    
    
    117  | 
     | 
     | 
    { | 
    
    
    118  | 
     | 
     | 
    	/*  | 
    
    
    119  | 
     | 
     | 
    	 * HACK - doesn't matter, and fixes back-over-nl bug for empty  | 
    
    
    120  | 
     | 
     | 
    	 *	kill buffers.  | 
    
    
    121  | 
     | 
     | 
    	 */  | 
    
    
    122  | 
     | 
     | 
    	if (kused == kstart)  | 
    
    
    123  | 
     | 
     | 
    		kflag = KFORW;  | 
    
    
    124  | 
     | 
     | 
     | 
    
    
    125  | 
     | 
     | 
    	if (kflag & KFORW) { | 
    
    
    126  | 
     | 
     | 
    		while (ksize - kused < chunk)  | 
    
    
    127  | 
     | 
     | 
    			if (kgrow(kflag) == FALSE)  | 
    
    
    128  | 
     | 
     | 
    				return (FALSE);  | 
    
    
    129  | 
     | 
     | 
    		bcopy(cp1, &(kbufp[kused]), (int)chunk);  | 
    
    
    130  | 
     | 
     | 
    		kused += chunk;  | 
    
    
    131  | 
     | 
     | 
    	} else if (kflag & KBACK) { | 
    
    
    132  | 
     | 
     | 
    		while (kstart < chunk)  | 
    
    
    133  | 
     | 
     | 
    			if (kgrow(kflag) == FALSE)  | 
    
    
    134  | 
     | 
     | 
    				return (FALSE);  | 
    
    
    135  | 
     | 
     | 
    		bcopy(cp1, &(kbufp[kstart - chunk]), (int)chunk);  | 
    
    
    136  | 
     | 
     | 
    		kstart -= chunk;  | 
    
    
    137  | 
     | 
     | 
    	}  | 
    
    
    138  | 
     | 
     | 
     | 
    
    
    139  | 
     | 
     | 
    	return (TRUE);  | 
    
    
    140  | 
     | 
     | 
    }  | 
    
    
    141  | 
     | 
     | 
     | 
    
    
    142  | 
     | 
     | 
    /*  | 
    
    
    143  | 
     | 
     | 
     * Kill line.  If called without an argument, it kills from dot to the end  | 
    
    
    144  | 
     | 
     | 
     * of the line, unless it is at the end of the line, when it kills the  | 
    
    
    145  | 
     | 
     | 
     * newline.  If called with an argument of 0, it kills from the start of the  | 
    
    
    146  | 
     | 
     | 
     * line to dot.  If called with a positive argument, it kills from dot  | 
    
    
    147  | 
     | 
     | 
     * forward over that number of newlines.  If called with a negative argument  | 
    
    
    148  | 
     | 
     | 
     * it kills any text before dot on the current line, then it kills back  | 
    
    
    149  | 
     | 
     | 
     * abs(arg) lines.  | 
    
    
    150  | 
     | 
     | 
     */  | 
    
    
    151  | 
     | 
     | 
    /* ARGSUSED */  | 
    
    
    152  | 
     | 
     | 
    int  | 
    
    
    153  | 
     | 
     | 
    killline(int f, int n)  | 
    
    
    154  | 
     | 
     | 
    { | 
    
    
    155  | 
     | 
     | 
    	struct line	*nextp;  | 
    
    
    156  | 
     | 
     | 
    	RSIZE	 chunk;  | 
    
    
    157  | 
     | 
     | 
    	int	 i, c;  | 
    
    
    158  | 
     | 
     | 
     | 
    
    
    159  | 
     | 
     | 
    	/* clear kill buffer if last wasn't a kill */  | 
    
    
    160  | 
     | 
     | 
    	if ((lastflag & CFKILL) == 0)  | 
    
    
    161  | 
     | 
     | 
    		kdelete();  | 
    
    
    162  | 
     | 
     | 
    	thisflag |= CFKILL;  | 
    
    
    163  | 
     | 
     | 
    	if (!(f & FFARG)) { | 
    
    
    164  | 
     | 
     | 
    		for (i = curwp->w_doto; i < llength(curwp->w_dotp); ++i)  | 
    
    
    165  | 
     | 
     | 
    			if ((c = lgetc(curwp->w_dotp, i)) != ' ' && c != '\t')  | 
    
    
    166  | 
     | 
     | 
    				break;  | 
    
    
    167  | 
     | 
     | 
    		if (i == llength(curwp->w_dotp))  | 
    
    
    168  | 
     | 
     | 
    			chunk = llength(curwp->w_dotp) - curwp->w_doto + 1;  | 
    
    
    169  | 
     | 
     | 
    		else { | 
    
    
    170  | 
     | 
     | 
    			chunk = llength(curwp->w_dotp) - curwp->w_doto;  | 
    
    
    171  | 
     | 
     | 
    			if (chunk == 0)  | 
    
    
    172  | 
     | 
     | 
    				chunk = 1;  | 
    
    
    173  | 
     | 
     | 
    		}  | 
    
    
    174  | 
     | 
     | 
    	} else if (n > 0) { | 
    
    
    175  | 
     | 
     | 
    		chunk = llength(curwp->w_dotp) - curwp->w_doto;  | 
    
    
    176  | 
     | 
     | 
    		nextp = lforw(curwp->w_dotp);  | 
    
    
    177  | 
     | 
     | 
    		if (nextp != curbp->b_headp)  | 
    
    
    178  | 
     | 
     | 
    			chunk++;		/* newline */  | 
    
    
    179  | 
     | 
     | 
    		if (nextp == curbp->b_headp)  | 
    
    
    180  | 
     | 
     | 
    			goto done;		/* EOL */  | 
    
    
    181  | 
     | 
     | 
    		i = n;  | 
    
    
    182  | 
     | 
     | 
    		while (--i) { | 
    
    
    183  | 
     | 
     | 
    			chunk += llength(nextp);  | 
    
    
    184  | 
     | 
     | 
    			nextp = lforw(nextp);  | 
    
    
    185  | 
     | 
     | 
    			if (nextp != curbp->b_headp)  | 
    
    
    186  | 
     | 
     | 
    				chunk++;	/* newline */  | 
    
    
    187  | 
     | 
     | 
    			if (nextp == curbp->b_headp)  | 
    
    
    188  | 
     | 
     | 
    				break;		/* EOL */  | 
    
    
    189  | 
     | 
     | 
    		}  | 
    
    
    190  | 
     | 
     | 
    	} else { | 
    
    
    191  | 
     | 
     | 
    		/* n <= 0 */  | 
    
    
    192  | 
     | 
     | 
    		chunk = curwp->w_doto;  | 
    
    
    193  | 
     | 
     | 
    		curwp->w_doto = 0;  | 
    
    
    194  | 
     | 
     | 
    		i = n;  | 
    
    
    195  | 
     | 
     | 
    		while (i++) { | 
    
    
    196  | 
     | 
     | 
    			if (lforw(curwp->w_dotp))  | 
    
    
    197  | 
     | 
     | 
    				chunk++;  | 
    
    
    198  | 
     | 
     | 
    			curwp->w_dotp = lback(curwp->w_dotp);  | 
    
    
    199  | 
     | 
     | 
    			curwp->w_rflag |= WFMOVE;  | 
    
    
    200  | 
     | 
     | 
    			chunk += llength(curwp->w_dotp);  | 
    
    
    201  | 
     | 
     | 
    		}  | 
    
    
    202  | 
     | 
     | 
    	}  | 
    
    
    203  | 
     | 
     | 
    	/*  | 
    
    
    204  | 
     | 
     | 
    	 * KFORW here is a bug.  Should be KBACK/KFORW, but we need to  | 
    
    
    205  | 
     | 
     | 
    	 * rewrite the ldelete code (later)?  | 
    
    
    206  | 
     | 
     | 
    	 */  | 
    
    
    207  | 
     | 
     | 
    done:  | 
    
    
    208  | 
     | 
     | 
    	if (chunk)  | 
    
    
    209  | 
     | 
     | 
    		return (ldelete(chunk, KFORW));  | 
    
    
    210  | 
     | 
     | 
    	return (TRUE);  | 
    
    
    211  | 
     | 
     | 
    }  | 
    
    
    212  | 
     | 
     | 
     | 
    
    
    213  | 
     | 
     | 
    /*  | 
    
    
    214  | 
     | 
     | 
     * Yank text back from the kill buffer.  This is really easy.  All of the work  | 
    
    
    215  | 
     | 
     | 
     * is done by the standard insert routines.  All you do is run the loop, and  | 
    
    
    216  | 
     | 
     | 
     * check for errors.  The blank lines are inserted with a call to "newline"  | 
    
    
    217  | 
     | 
     | 
     * instead of a call to "lnewline" so that the magic stuff that happens when  | 
    
    
    218  | 
     | 
     | 
     * you type a carriage return also happens when a carriage return is yanked  | 
    
    
    219  | 
     | 
     | 
     * back from the kill buffer.  An attempt has been made to fix the cosmetic  | 
    
    
    220  | 
     | 
     | 
     * bug associated with a yank when dot is on the top line of the window  | 
    
    
    221  | 
     | 
     | 
     * (nothing moves, because all of the new text landed off screen).  | 
    
    
    222  | 
     | 
     | 
     */  | 
    
    
    223  | 
     | 
     | 
    /* ARGSUSED */  | 
    
    
    224  | 
     | 
     | 
    int  | 
    
    
    225  | 
     | 
     | 
    yank(int f, int n)  | 
    
    
    226  | 
     | 
     | 
    { | 
    
    
    227  | 
     | 
     | 
    	struct line	*lp;  | 
    
    
    228  | 
     | 
     | 
    	int	 c, i, nline;  | 
    
    
    229  | 
     | 
     | 
     | 
    
    
    230  | 
     | 
     | 
    	if (n < 0)  | 
    
    
    231  | 
     | 
     | 
    		return (FALSE);  | 
    
    
    232  | 
     | 
     | 
     | 
    
    
    233  | 
     | 
     | 
    	/* newline counting */  | 
    
    
    234  | 
     | 
     | 
    	nline = 0;  | 
    
    
    235  | 
     | 
     | 
     | 
    
    
    236  | 
     | 
     | 
    	undo_boundary_enable(FFRAND, 0);  | 
    
    
    237  | 
     | 
     | 
    	while (n--) { | 
    
    
    238  | 
     | 
     | 
    		/* mark around last yank */  | 
    
    
    239  | 
     | 
     | 
    		isetmark();  | 
    
    
    240  | 
     | 
     | 
    		i = 0;  | 
    
    
    241  | 
     | 
     | 
    		while ((c = kremove(i)) >= 0) { | 
    
    
    242  | 
     | 
     | 
    			if (c == '\n') { | 
    
    
    243  | 
     | 
     | 
    				if (enewline(FFRAND, 1) == FALSE)  | 
    
    
    244  | 
     | 
     | 
    					return (FALSE);  | 
    
    
    245  | 
     | 
     | 
    				++nline;  | 
    
    
    246  | 
     | 
     | 
    			} else { | 
    
    
    247  | 
     | 
     | 
    				if (linsert(1, c) == FALSE)  | 
    
    
    248  | 
     | 
     | 
    					return (FALSE);  | 
    
    
    249  | 
     | 
     | 
    			}  | 
    
    
    250  | 
     | 
     | 
    			++i;  | 
    
    
    251  | 
     | 
     | 
    		}  | 
    
    
    252  | 
     | 
     | 
    	}  | 
    
    
    253  | 
     | 
     | 
    	/* cosmetic adjustment */  | 
    
    
    254  | 
     | 
     | 
    	lp = curwp->w_linep;  | 
    
    
    255  | 
     | 
     | 
     | 
    
    
    256  | 
     | 
     | 
    	/* if offscreen insert */  | 
    
    
    257  | 
     | 
     | 
    	if (curwp->w_dotp == lp) { | 
    
    
    258  | 
     | 
     | 
    		while (nline-- && lback(lp) != curbp->b_headp)  | 
    
    
    259  | 
     | 
     | 
    			lp = lback(lp);  | 
    
    
    260  | 
     | 
     | 
    		/* adjust framing */  | 
    
    
    261  | 
     | 
     | 
    		curwp->w_linep = lp;  | 
    
    
    262  | 
     | 
     | 
    		curwp->w_rflag |= WFFULL;  | 
    
    
    263  | 
     | 
     | 
    	}  | 
    
    
    264  | 
     | 
     | 
    	undo_boundary_enable(FFRAND, 1);  | 
    
    
    265  | 
     | 
     | 
    	return (TRUE);  | 
    
    
    266  | 
     | 
     | 
    }  | 
    
    
    267  | 
     | 
     | 
     |