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

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