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

1.1     ! kjell       1: /*     $OpenBSD: line.c,v 1.32 2005/11/22 04:38:57 kjell Exp $ */
        !             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) {
        !            33:                free((char *)kbufp);
        !            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)
        !            87:                free((char *)kbufp);
        !            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;
        !           252:                curwp->w_flag |= WFHARD;
        !           253:        }
        !           254:        undo_no_boundary(FALSE);
        !           255:        undo_add_boundary();
        !           256:        return (TRUE);
        !           257: }
        !           258: