[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.13

1.13    ! bcallah     1: /*     $OpenBSD: yank.c,v 1.12 2015/03/16 13:47:48 bcallah 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));
                     90:        if (kbufp != NULL)
1.2       kjell      91:                free(kbufp);
1.1       kjell      92:        kbufp = nbufp;
                     93:        ksize += KBLOCK;
                     94:        kused = kused - kstart + nstart;
                     95:        kstart = nstart;
                     96:        return (TRUE);
                     97: }
                     98:
                     99: /*
                    100:  * This function gets characters from the kill buffer. If the character
                    101:  * index "n" is off the end, it returns "-1". This lets the caller just
                    102:  * scan along until it gets a "-1" back.
                    103:  */
                    104: int
                    105: kremove(int n)
                    106: {
                    107:        if (n < 0 || n + kstart >= kused)
                    108:                return (-1);
                    109:        return (CHARMASK(kbufp[n + kstart]));
                    110: }
                    111:
                    112: /*
                    113:  * Copy a string into the kill buffer. kflag gives direction.
                    114:  * if KNONE, do nothing.
                    115:  */
                    116: int
                    117: kchunk(char *cp1, RSIZE chunk, int kflag)
                    118: {
                    119:        /*
                    120:         * HACK - doesn't matter, and fixes back-over-nl bug for empty
                    121:         *      kill buffers.
                    122:         */
                    123:        if (kused == kstart)
                    124:                kflag = KFORW;
                    125:
1.9       kjell     126:        if (kflag & KFORW) {
1.1       kjell     127:                while (ksize - kused < chunk)
                    128:                        if (kgrow(kflag) == FALSE)
                    129:                                return (FALSE);
                    130:                bcopy(cp1, &(kbufp[kused]), (int)chunk);
                    131:                kused += chunk;
1.9       kjell     132:        } else if (kflag & KBACK) {
1.1       kjell     133:                while (kstart < chunk)
                    134:                        if (kgrow(kflag) == FALSE)
                    135:                                return (FALSE);
                    136:                bcopy(cp1, &(kbufp[kstart - chunk]), (int)chunk);
                    137:                kstart -= chunk;
1.9       kjell     138:        }
1.1       kjell     139:
                    140:        return (TRUE);
                    141: }
                    142:
                    143: /*
                    144:  * Kill line.  If called without an argument, it kills from dot to the end
                    145:  * of the line, unless it is at the end of the line, when it kills the
                    146:  * newline.  If called with an argument of 0, it kills from the start of the
                    147:  * line to dot.  If called with a positive argument, it kills from dot
                    148:  * forward over that number of newlines.  If called with a negative argument
                    149:  * it kills any text before dot on the current line, then it kills back
                    150:  * abs(arg) lines.
                    151:  */
                    152: /* ARGSUSED */
                    153: int
                    154: killline(int f, int n)
                    155: {
                    156:        struct line     *nextp;
                    157:        RSIZE    chunk;
                    158:        int      i, c;
                    159:
                    160:        /* clear kill buffer if last wasn't a kill */
                    161:        if ((lastflag & CFKILL) == 0)
                    162:                kdelete();
                    163:        thisflag |= CFKILL;
                    164:        if (!(f & FFARG)) {
                    165:                for (i = curwp->w_doto; i < llength(curwp->w_dotp); ++i)
                    166:                        if ((c = lgetc(curwp->w_dotp, i)) != ' ' && c != '\t')
                    167:                                break;
                    168:                if (i == llength(curwp->w_dotp))
                    169:                        chunk = llength(curwp->w_dotp) - curwp->w_doto + 1;
                    170:                else {
                    171:                        chunk = llength(curwp->w_dotp) - curwp->w_doto;
                    172:                        if (chunk == 0)
                    173:                                chunk = 1;
                    174:                }
                    175:        } else if (n > 0) {
1.10      deraadt   176:                chunk = llength(curwp->w_dotp) - curwp->w_doto;
1.1       kjell     177:                nextp = lforw(curwp->w_dotp);
1.10      deraadt   178:                if (nextp != curbp->b_headp)
                    179:                        chunk++;                /* newline */
                    180:                if (nextp == curbp->b_headp)
                    181:                        goto done;              /* EOL */
1.1       kjell     182:                i = n;
                    183:                while (--i) {
1.10      deraadt   184:                        chunk += llength(nextp);
                    185:                        nextp = lforw(nextp);
                    186:                        if (nextp != curbp->b_headp)
                    187:                                chunk++;        /* newline */
1.4       kjell     188:                        if (nextp == curbp->b_headp)
1.10      deraadt   189:                                break;          /* EOL */
1.1       kjell     190:                }
                    191:        } else {
                    192:                /* n <= 0 */
                    193:                chunk = curwp->w_doto;
                    194:                curwp->w_doto = 0;
                    195:                i = n;
                    196:                while (i++) {
1.10      deraadt   197:                        if (lforw(curwp->w_dotp))
                    198:                                chunk++;
1.1       kjell     199:                        curwp->w_dotp = lback(curwp->w_dotp);
1.8       kjell     200:                        curwp->w_rflag |= WFMOVE;
1.10      deraadt   201:                        chunk += llength(curwp->w_dotp);
1.1       kjell     202:                }
                    203:        }
                    204:        /*
                    205:         * KFORW here is a bug.  Should be KBACK/KFORW, but we need to
                    206:         * rewrite the ldelete code (later)?
                    207:         */
1.10      deraadt   208: done:
                    209:        if (chunk)
                    210:                return (ldelete(chunk, KFORW));
                    211:        return (TRUE);
1.1       kjell     212: }
                    213:
                    214: /*
                    215:  * Yank text back from the kill buffer.  This is really easy.  All of the work
                    216:  * is done by the standard insert routines.  All you do is run the loop, and
                    217:  * check for errors.  The blank lines are inserted with a call to "newline"
                    218:  * instead of a call to "lnewline" so that the magic stuff that happens when
                    219:  * you type a carriage return also happens when a carriage return is yanked
                    220:  * back from the kill buffer.  An attempt has been made to fix the cosmetic
                    221:  * bug associated with a yank when dot is on the top line of the window
                    222:  * (nothing moves, because all of the new text landed off screen).
                    223:  */
                    224: /* ARGSUSED */
                    225: int
                    226: yank(int f, int n)
                    227: {
                    228:        struct line     *lp;
                    229:        int      c, i, nline;
                    230:
                    231:        if (n < 0)
                    232:                return (FALSE);
                    233:
                    234:        /* newline counting */
                    235:        nline = 0;
                    236:
1.7       kjell     237:        undo_boundary_enable(FFRAND, 0);
1.1       kjell     238:        while (n--) {
                    239:                /* mark around last yank */
                    240:                isetmark();
                    241:                i = 0;
                    242:                while ((c = kremove(i)) >= 0) {
                    243:                        if (c == '\n') {
1.12      bcallah   244:                                if (enewline(FFRAND, 1) == FALSE)
1.1       kjell     245:                                        return (FALSE);
                    246:                                ++nline;
                    247:                        } else {
                    248:                                if (linsert(1, c) == FALSE)
                    249:                                        return (FALSE);
                    250:                        }
                    251:                        ++i;
                    252:                }
                    253:        }
                    254:        /* cosmetic adjustment */
                    255:        lp = curwp->w_linep;
                    256:
                    257:        /* if offscreen insert */
                    258:        if (curwp->w_dotp == lp) {
1.4       kjell     259:                while (nline-- && lback(lp) != curbp->b_headp)
1.1       kjell     260:                        lp = lback(lp);
                    261:                /* adjust framing */
                    262:                curwp->w_linep = lp;
1.8       kjell     263:                curwp->w_rflag |= WFFULL;
1.1       kjell     264:        }
1.7       kjell     265:        undo_boundary_enable(FFRAND, 1);
1.1       kjell     266:        return (TRUE);
                    267: }
                    268: