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

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