[BACK]Return to yank.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/yank.c, Revision 1.15

1.15    ! lum         1: /*     $OpenBSD: yank.c,v 1.14 2015/12/11 20:21:23 mmcc Exp $  */
1.1       kjell       2:
                      3: /* This file is in the public domain. */
                      4:
                      5: /*
                      6:  *     kill ring functions
                      7:  */
                      8:
1.13      bcallah     9: #include <sys/queue.h>
                     10: #include <signal.h>
                     11: #include <stdio.h>
                     12: #include <stdlib.h>
                     13: #include <string.h>
                     14:
1.1       kjell      15: #include "def.h"
                     16:
1.13      bcallah    17: #define KBLOCK  8192           /* Kill grow.                    */
1.1       kjell      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) {
1.2       kjell      35:                free(kbufp);
1.1       kjell      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.
1.6       deraadt    47:  * This call is ignored if  KNONE is set.
1.1       kjell      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 */
1.11      lum        79:                dobeep();
1.1       kjell      80:                ewprintf("Kill buffer size at maximum");
                     81:                return (FALSE);
                     82:        }
                     83:        if ((nbufp = malloc((unsigned)(ksize + KBLOCK))) == NULL) {
1.11      lum        84:                dobeep();
1.1       kjell      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));
1.14      mmcc       90:        free(kbufp);
1.1       kjell      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:
1.9       kjell     125:        if (kflag & KFORW) {
1.1       kjell     126:                while (ksize - kused < chunk)
                    127:                        if (kgrow(kflag) == FALSE)
                    128:                                return (FALSE);
                    129:                bcopy(cp1, &(kbufp[kused]), (int)chunk);
                    130:                kused += chunk;
1.9       kjell     131:        } else if (kflag & KBACK) {
1.1       kjell     132:                while (kstart < chunk)
                    133:                        if (kgrow(kflag) == FALSE)
                    134:                                return (FALSE);
                    135:                bcopy(cp1, &(kbufp[kstart - chunk]), (int)chunk);
                    136:                kstart -= chunk;
1.9       kjell     137:        }
1.1       kjell     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) {
1.10      deraadt   175:                chunk = llength(curwp->w_dotp) - curwp->w_doto;
1.1       kjell     176:                nextp = lforw(curwp->w_dotp);
1.10      deraadt   177:                if (nextp != curbp->b_headp)
                    178:                        chunk++;                /* newline */
                    179:                if (nextp == curbp->b_headp)
                    180:                        goto done;              /* EOL */
1.1       kjell     181:                i = n;
                    182:                while (--i) {
1.10      deraadt   183:                        chunk += llength(nextp);
                    184:                        nextp = lforw(nextp);
                    185:                        if (nextp != curbp->b_headp)
                    186:                                chunk++;        /* newline */
1.4       kjell     187:                        if (nextp == curbp->b_headp)
1.10      deraadt   188:                                break;          /* EOL */
1.1       kjell     189:                }
                    190:        } else {
                    191:                /* n <= 0 */
                    192:                chunk = curwp->w_doto;
                    193:                curwp->w_doto = 0;
                    194:                i = n;
                    195:                while (i++) {
1.10      deraadt   196:                        if (lforw(curwp->w_dotp))
                    197:                                chunk++;
1.1       kjell     198:                        curwp->w_dotp = lback(curwp->w_dotp);
1.8       kjell     199:                        curwp->w_rflag |= WFMOVE;
1.10      deraadt   200:                        chunk += llength(curwp->w_dotp);
1.1       kjell     201:                }
                    202:        }
                    203:        /*
                    204:         * KFORW here is a bug.  Should be KBACK/KFORW, but we need to
                    205:         * rewrite the ldelete code (later)?
                    206:         */
1.10      deraadt   207: done:
                    208:        if (chunk)
                    209:                return (ldelete(chunk, KFORW));
                    210:        return (TRUE);
1.1       kjell     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:
1.7       kjell     236:        undo_boundary_enable(FFRAND, 0);
1.1       kjell     237:        while (n--) {
                    238:                /* mark around last yank */
                    239:                isetmark();
                    240:                i = 0;
                    241:                while ((c = kremove(i)) >= 0) {
1.15    ! lum       242:                        if (c == *curbp->b_nlchr) {
1.12      bcallah   243:                                if (enewline(FFRAND, 1) == FALSE)
1.1       kjell     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) {
1.4       kjell     258:                while (nline-- && lback(lp) != curbp->b_headp)
1.1       kjell     259:                        lp = lback(lp);
                    260:                /* adjust framing */
                    261:                curwp->w_linep = lp;
1.8       kjell     262:                curwp->w_rflag |= WFFULL;
1.1       kjell     263:        }
1.7       kjell     264:        undo_boundary_enable(FFRAND, 1);
1.1       kjell     265:        return (TRUE);
                    266: }
                    267: