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

Annotation of src/usr.bin/mg/line.c, Revision 1.32

1.32    ! kjell       1: /*     $OpenBSD: line.c,v 1.31 2005/11/21 19:47:23 deraadt Exp $       */
1.23      kjell       2:
                      3: /* This file is in the public domain. */
1.5       niklas      4:
1.1       deraadt     5: /*
                      6:  *             Text line handling.
1.8       mickey      7:  *
1.4       millert     8:  * The functions in this file are a general set of line management
1.8       mickey      9:  * utilities. They are the only routines that touch the text. They
                     10:  * also touch the buffer and window structures to make sure that the
                     11:  * necessary updating gets done.  There are routines in this file that
1.4       millert    12:  * handle the kill buffer too.  It isn't here for any good reason.
1.1       deraadt    13:  *
1.8       mickey     14:  * Note that this code only updates the dot and mark values in the window
                     15:  * list.  Since all the code acts on the current window, the buffer that
                     16:  * we are editing must be displayed, which means that "b_nwnd" is non-zero,
                     17:  * which means that the dot and mark values in the buffer headers are
1.1       deraadt    18:  * nonsense.
                     19:  */
                     20:
1.4       millert    21: #include "def.h"
                     22:
1.32    ! kjell      23: #include <stdlib.h>
        !            24: #include <string.h>
        !            25:
1.4       millert    26: /*
1.8       mickey     27:  * The number of bytes member from the start of the structure type should be
1.4       millert    28:  * computed at compile time.
                     29:  */
1.1       deraadt    30:
                     31: #ifndef KBLOCK
1.3       millert    32: #define KBLOCK 256             /* Kill buffer block size.       */
1.1       deraadt    33: #endif
                     34:
1.4       millert    35: static char    *kbufp = NULL;  /* Kill buffer data.             */
                     36: static RSIZE    kused = 0;     /* # of bytes used in KB.        */
                     37: static RSIZE    ksize = 0;     /* # of bytes allocated in KB.   */
                     38: static RSIZE    kstart = 0;    /* # of first used byte in KB.   */
                     39:
1.12      millert    40: static int      kgrow(int);
1.1       deraadt    41:
                     42: /*
1.9       vincent    43:  * Allocate a new line of size `used'.  lrealloc() can be called if the line
                     44:  * ever needs to grow beyond that.
1.1       deraadt    45:  */
1.28      deraadt    46: struct line *
1.9       vincent    47: lalloc(int used)
1.3       millert    48: {
1.28      deraadt    49:        struct line *lp;
1.1       deraadt    50:
1.22      db         51:        if ((lp = malloc(sizeof(*lp))) == NULL)
                     52:                return (NULL);
1.9       vincent    53:        lp->l_text = NULL;
                     54:        lp->l_size = 0;
                     55:        lp->l_used = used;      /* XXX */
                     56:        if (lrealloc(lp, used) == FALSE) {
                     57:                free(lp);
1.22      db         58:                return (NULL);
1.1       deraadt    59:        }
1.22      db         60:        return (lp);
1.1       deraadt    61: }
                     62:
1.9       vincent    63: int
1.28      deraadt    64: lrealloc(struct line *lp, int newsize)
1.1       deraadt    65: {
1.9       vincent    66:        char *tmp;
1.1       deraadt    67:
1.18      millert    68:        if (lp->l_size < newsize) {
                     69:                if ((tmp = realloc(lp->l_text, newsize)) == NULL)
1.22      db         70:                        return (FALSE);
1.18      millert    71:                lp->l_text = tmp;
                     72:                lp->l_size = newsize;
                     73:        }
1.22      db         74:        return (TRUE);
1.1       deraadt    75: }
                     76:
                     77: /*
1.4       millert    78:  * Delete line "lp".  Fix all of the links that might point to it (they are
1.8       mickey     79:  * moved to offset 0 of the next line.  Unlink the line from whatever buffer
                     80:  * it might be in, and release the memory.  The buffers are updated too; the
1.4       millert    81:  * magic conditions described in the above comments don't hold here.
1.1       deraadt    82:  */
1.6       art        83: void
1.28      deraadt    84: lfree(struct line *lp)
1.3       millert    85: {
1.28      deraadt    86:        struct buffer   *bp;
                     87:        struct mgwin    *wp;
1.1       deraadt    88:
1.3       millert    89:        for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1       deraadt    90:                if (wp->w_linep == lp)
                     91:                        wp->w_linep = lp->l_fp;
1.3       millert    92:                if (wp->w_dotp == lp) {
                     93:                        wp->w_dotp = lp->l_fp;
                     94:                        wp->w_doto = 0;
1.1       deraadt    95:                }
                     96:                if (wp->w_markp == lp) {
                     97:                        wp->w_markp = lp->l_fp;
                     98:                        wp->w_marko = 0;
                     99:                }
                    100:        }
1.3       millert   101:        for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
1.1       deraadt   102:                if (bp->b_nwnd == 0) {
1.3       millert   103:                        if (bp->b_dotp == lp) {
1.1       deraadt   104:                                bp->b_dotp = lp->l_fp;
                    105:                                bp->b_doto = 0;
                    106:                        }
                    107:                        if (bp->b_markp == lp) {
                    108:                                bp->b_markp = lp->l_fp;
                    109:                                bp->b_marko = 0;
                    110:                        }
                    111:                }
                    112:        }
                    113:        lp->l_bp->l_fp = lp->l_fp;
                    114:        lp->l_fp->l_bp = lp->l_bp;
1.9       vincent   115:        if (lp->l_text != NULL)
                    116:                free(lp->l_text);
                    117:        free(lp);
1.1       deraadt   118: }
                    119:
                    120: /*
1.8       mickey    121:  * This routine is called when a character changes in place in the current
                    122:  * buffer. It updates all of the required flags in the buffer and window
                    123:  * system. The flag used is passed as an argument; if the buffer is being
                    124:  * displayed in more than 1 window we change EDIT to HARD. Set MODE if the
1.4       millert   125:  * mode line needs to be updated (the "*" has to be set).
1.1       deraadt   126:  */
1.6       art       127: void
1.15      vincent   128: lchange(int flag)
1.3       millert   129: {
1.28      deraadt   130:        struct mgwin    *wp;
1.1       deraadt   131:
1.4       millert   132:        /* update mode lines if this is the first change. */
                    133:        if ((curbp->b_flag & BFCHG) == 0) {
                    134:                flag |= WFMODE;
1.1       deraadt   135:                curbp->b_flag |= BFCHG;
                    136:        }
1.3       millert   137:        for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1       deraadt   138:                if (wp->w_bufp == curbp) {
                    139:                        wp->w_flag |= flag;
1.3       millert   140:                        if (wp != curwp)
                    141:                                wp->w_flag |= WFHARD;
1.1       deraadt   142:                }
                    143:        }
                    144: }
                    145:
                    146: /*
1.20      vincent   147:  * Insert "n" bytes from "s" at the current location of dot.
                    148:  * In the easy case all that happens is the text is stored in the line.
                    149:  * In the hard case, the line has to be reallocated.  When the window list
                    150:  * is updated, take special care; I screwed it up once.  You always update
                    151:  * dot in the current window.  You update mark and a dot in another window
                    152:  * if it is greater than the place where you did the insert. Return TRUE
                    153:  * if all is well, and FALSE on errors.
                    154:  */
                    155: int
                    156: linsert_str(const char *s, int n)
                    157: {
1.28      deraadt   158:        struct line     *lp1;
                    159:        struct mgwin    *wp;
1.20      vincent   160:        RSIZE    i;
                    161:        int      doto;
                    162:
                    163:        if (curbp->b_flag & BFREADONLY) {
                    164:                ewprintf("Buffer is read only");
1.22      db        165:                return (FALSE);
1.20      vincent   166:        }
                    167:
                    168:        if (!n)
                    169:                return (TRUE);
                    170:
                    171:        lchange(WFHARD);
                    172:
                    173:        /* current line */
                    174:        lp1 = curwp->w_dotp;
                    175:
                    176:        /* special case for the end */
                    177:        if (lp1 == curbp->b_linep) {
1.28      deraadt   178:                struct line *lp2, *lp3;
1.20      vincent   179:
                    180:                /* now should only happen in empty buffer */
                    181:                if (curwp->w_doto != 0)
                    182:                        panic("bug: linsert_str");
                    183:                /* allocate a new line */
                    184:                if ((lp2 = lalloc(n)) == NULL)
1.22      db        185:                        return (FALSE);
1.20      vincent   186:                /* previous line */
                    187:                lp3 = lp1->l_bp;
                    188:                /* link in */
                    189:                lp3->l_fp = lp2;
                    190:                lp2->l_fp = lp1;
                    191:                lp1->l_bp = lp2;
                    192:                lp2->l_bp = lp3;
                    193:                for (i = 0; i < n; ++i)
                    194:                        lp2->l_text[i] = s[i];
                    195:                for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
                    196:                        if (wp->w_linep == lp1)
                    197:                                wp->w_linep = lp2;
                    198:                        if (wp->w_dotp == lp1)
                    199:                                wp->w_dotp = lp2;
                    200:                        if (wp->w_markp == lp1)
                    201:                                wp->w_markp = lp2;
                    202:                }
                    203:                undo_add_insert(lp2, 0, n);
                    204:                curwp->w_doto = n;
1.22      db        205:                return (TRUE);
1.20      vincent   206:        }
                    207:        /* save for later */
                    208:        doto = curwp->w_doto;
                    209:
                    210:        if ((lp1->l_used + n) > lp1->l_size) {
                    211:                if (lrealloc(lp1, lp1->l_used + n) == FALSE)
1.22      db        212:                        return (FALSE);
1.20      vincent   213:        }
                    214:        lp1->l_used += n;
                    215:        if (lp1->l_used != n)
                    216:                memmove(&lp1->l_text[doto + n], &lp1->l_text[doto],
                    217:                    lp1->l_used - n - doto);
                    218:
                    219:        /* Add the characters */
                    220:        for (i = 0; i < n; ++i)
                    221:                lp1->l_text[doto + i] = s[i];
                    222:        for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
                    223:                if (wp->w_dotp == lp1) {
                    224:                        if (wp == curwp || wp->w_doto > doto)
                    225:                                wp->w_doto += n;
                    226:                }
                    227:                if (wp->w_markp == lp1) {
                    228:                        if (wp->w_marko > doto)
                    229:                                wp->w_marko += n;
                    230:                }
                    231:        }
                    232:        undo_add_insert(curwp->w_dotp, doto, n);
1.22      db        233:        return (TRUE);
1.20      vincent   234: }
                    235:
                    236: /*
1.8       mickey    237:  * Insert "n" copies of the character "c" at the current location of dot.
                    238:  * In the easy case all that happens is the text is stored in the line.
                    239:  * In the hard case, the line has to be reallocated.  When the window list
                    240:  * is updated, take special care; I screwed it up once.  You always update
1.4       millert   241:  * dot in the current window.  You update mark and a dot in another window
                    242:  * if it is greater than the place where you did the insert. Return TRUE
1.1       deraadt   243:  * if all is well, and FALSE on errors.
                    244:  */
1.4       millert   245: int
1.15      vincent   246: linsert(int n, int c)
1.1       deraadt   247: {
1.28      deraadt   248:        struct line     *lp1;
                    249:        struct mgwin    *wp;
1.4       millert   250:        RSIZE    i;
                    251:        int      doto;
1.1       deraadt   252:
1.20      vincent   253:        if (!n)
                    254:                return (TRUE);
                    255:
1.15      vincent   256:        if (curbp->b_flag & BFREADONLY) {
                    257:                ewprintf("Buffer is read only");
1.22      db        258:                return (FALSE);
1.15      vincent   259:        }
                    260:
1.1       deraadt   261:        lchange(WFEDIT);
1.4       millert   262:
                    263:        /* current line */
                    264:        lp1 = curwp->w_dotp;
1.15      vincent   265:
1.4       millert   266:        /* special case for the end */
                    267:        if (lp1 == curbp->b_linep) {
1.28      deraadt   268:                struct line *lp2, *lp3;
1.11      deraadt   269:
1.4       millert   270:                /* now should only happen in empty buffer */
1.1       deraadt   271:                if (curwp->w_doto != 0) {
                    272:                        ewprintf("bug: linsert");
1.22      db        273:                        return (FALSE);
1.1       deraadt   274:                }
1.4       millert   275:                /* allocate a new line */
1.9       vincent   276:                if ((lp2 = lalloc(n)) == NULL)
1.22      db        277:                        return (FALSE);
1.4       millert   278:                /* previous line */
                    279:                lp3 = lp1->l_bp;
                    280:                /* link in */
                    281:                lp3->l_fp = lp2;
1.1       deraadt   282:                lp2->l_fp = lp1;
                    283:                lp1->l_bp = lp2;
                    284:                lp2->l_bp = lp3;
1.3       millert   285:                for (i = 0; i < n; ++i)
1.1       deraadt   286:                        lp2->l_text[i] = c;
1.3       millert   287:                for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1       deraadt   288:                        if (wp->w_linep == lp1)
                    289:                                wp->w_linep = lp2;
                    290:                        if (wp->w_dotp == lp1)
                    291:                                wp->w_dotp = lp2;
                    292:                        if (wp->w_markp == lp1)
                    293:                                wp->w_markp = lp2;
                    294:                }
1.16      vincent   295:                undo_add_insert(lp2, 0, n);
1.1       deraadt   296:                curwp->w_doto = n;
1.22      db        297:                return (TRUE);
1.1       deraadt   298:        }
1.4       millert   299:        /* save for later */
                    300:        doto = curwp->w_doto;
1.9       vincent   301:
                    302:        if ((lp1->l_used + n) > lp1->l_size) {
                    303:                if (lrealloc(lp1, lp1->l_used + n) == FALSE)
1.22      db        304:                        return (FALSE);
1.11      deraadt   305:        }
1.9       vincent   306:        lp1->l_used += n;
1.11      deraadt   307:        if (lp1->l_used != n)
1.9       vincent   308:                memmove(&lp1->l_text[doto + n], &lp1->l_text[doto],
                    309:                    lp1->l_used - n - doto);
                    310:
1.4       millert   311:        /* Add the characters */
                    312:        for (i = 0; i < n; ++i)
1.9       vincent   313:                lp1->l_text[doto + i] = c;
1.3       millert   314:        for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1       deraadt   315:                if (wp->w_dotp == lp1) {
1.3       millert   316:                        if (wp == curwp || wp->w_doto > doto)
1.1       deraadt   317:                                wp->w_doto += n;
                    318:                }
                    319:                if (wp->w_markp == lp1) {
                    320:                        if (wp->w_marko > doto)
                    321:                                wp->w_marko += n;
                    322:                }
                    323:        }
1.16      vincent   324:        undo_add_insert(curwp->w_dotp, doto, n);
1.22      db        325:        return (TRUE);
1.1       deraadt   326: }
                    327:
1.4       millert   328: int
1.28      deraadt   329: lnewline_at(struct line *lp1, int doto)
1.1       deraadt   330: {
1.28      deraadt   331:        struct line     *lp2;
1.21      vincent   332:        int      nlen;
1.28      deraadt   333:        struct mgwin    *wp;
1.24      kjell     334:        int      retval = TRUE;
1.1       deraadt   335:
                    336:        lchange(WFHARD);
1.14      vincent   337:
1.4       millert   338:        /* avoid unnecessary copying */
                    339:        if (doto == 0) {
                    340:                /* new first part */
1.24      kjell     341:                if ((lp2 = lalloc(0)) == NULL) {
                    342:                        retval = FALSE;
                    343:                        goto lnl_done;
                    344:                }
1.1       deraadt   345:                lp2->l_bp = lp1->l_bp;
                    346:                lp1->l_bp->l_fp = lp2;
                    347:                lp2->l_fp = lp1;
                    348:                lp1->l_bp = lp2;
1.3       millert   349:                for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
                    350:                        if (wp->w_linep == lp1)
                    351:                                wp->w_linep = lp2;
1.24      kjell     352:                goto lnl_done;
1.1       deraadt   353:        }
1.4       millert   354:
                    355:        /* length of new part */
                    356:        nlen = llength(lp1) - doto;
                    357:
                    358:        /* new second half line */
1.24      kjell     359:        if ((lp2 = lalloc(nlen)) == NULL) {
                    360:                retval = FALSE;
                    361:                goto lnl_done;
                    362:        }
1.3       millert   363:        if (nlen != 0)
                    364:                bcopy(&lp1->l_text[doto], &lp2->l_text[0], nlen);
1.1       deraadt   365:        lp1->l_used = doto;
                    366:        lp2->l_bp = lp1;
                    367:        lp2->l_fp = lp1->l_fp;
                    368:        lp1->l_fp = lp2;
                    369:        lp2->l_fp->l_bp = lp2;
1.4       millert   370:        /* Windows */
                    371:        for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1       deraadt   372:                if (wp->w_dotp == lp1 && wp->w_doto >= doto) {
                    373:                        wp->w_dotp = lp2;
                    374:                        wp->w_doto -= doto;
                    375:                }
                    376:                if (wp->w_markp == lp1 && wp->w_marko >= doto) {
                    377:                        wp->w_markp = lp2;
                    378:                        wp->w_marko -= doto;
                    379:                }
                    380:        }
1.24      kjell     381: lnl_done:
                    382:        undo_add_boundary();
                    383:        undo_add_insert(lp1, llength(lp1), 1);
                    384:        undo_add_boundary();
                    385:        return (retval);
1.1       deraadt   386: }
                    387:
                    388: /*
1.21      vincent   389:  * Insert a newline into the buffer at the current location of dot in the
                    390:  * current window.
                    391:  */
                    392: int
                    393: lnewline(void)
                    394: {
                    395:        if (curbp->b_flag & BFREADONLY) {
                    396:                ewprintf("Buffer is read only");
1.22      db        397:                return (FALSE);
1.21      vincent   398:        }
1.22      db        399:        return (lnewline_at(curwp->w_dotp, curwp->w_doto));
1.21      vincent   400: }
                    401:
                    402: /*
1.8       mickey    403:  * This function deletes "n" bytes, starting at dot. It understands how to
                    404:  * deal with end of lines, etc.  It returns TRUE if all of the characters
                    405:  * were deleted, and FALSE if they were not (because dot ran into the end
                    406:  * of the buffer.  The "kflag" indicates either no insertion, or direction
1.4       millert   407:  * of insertion into the kill buffer.
1.1       deraadt   408:  */
1.4       millert   409: int
1.15      vincent   410: ldelete(RSIZE n, int kflag)
1.3       millert   411: {
1.28      deraadt   412:        struct line     *dotp;
1.4       millert   413:        RSIZE    chunk;
1.28      deraadt   414:        struct mgwin    *wp;
1.4       millert   415:        int      doto;
                    416:        char    *cp1, *cp2;
1.32    ! kjell     417:        size_t   len;
        !           418:        char    *sv;
        !           419:        int      end;
1.1       deraadt   420:
1.15      vincent   421:        if (curbp->b_flag & BFREADONLY) {
                    422:                ewprintf("Buffer is read only");
1.22      db        423:                return (FALSE);
1.15      vincent   424:        }
1.32    ! kjell     425:        len = n;
        !           426:        if ((sv = calloc(1, len + 1)) == NULL)
        !           427:                return (FALSE);
        !           428:        end = 0;
1.15      vincent   429:
1.16      vincent   430:        undo_add_delete(curwp->w_dotp, curwp->w_doto, n);
1.15      vincent   431:
1.1       deraadt   432:        while (n != 0) {
                    433:                dotp = curwp->w_dotp;
                    434:                doto = curwp->w_doto;
1.4       millert   435:                /* Hit the end of the buffer */
                    436:                if (dotp == curbp->b_linep)
1.22      db        437:                        return (FALSE);
1.4       millert   438:                /* Size of the chunk */
                    439:                chunk = dotp->l_used - doto;
1.20      vincent   440:
1.1       deraadt   441:                if (chunk > n)
                    442:                        chunk = n;
1.4       millert   443:                /* End of line, merge */
                    444:                if (chunk == 0) {
1.3       millert   445:                        if (dotp == lback(curbp->b_linep))
1.4       millert   446:                                /* End of buffer */
1.22      db        447:                                return (FALSE);
1.1       deraadt   448:                        lchange(WFHARD);
1.32    ! kjell     449:                        if (ldelnewline() == FALSE)
1.22      db        450:                                return (FALSE);
1.32    ! kjell     451:                        end = strlcat(sv, "\n", len + 1);
1.1       deraadt   452:                        --n;
                    453:                        continue;
                    454:                }
                    455:                lchange(WFEDIT);
1.4       millert   456:                /* Scrunch text */
                    457:                cp1 = &dotp->l_text[doto];
1.32    ! kjell     458:                memcpy(&sv[end], cp1, chunk);
        !           459:                end += chunk;
        !           460:                sv[end] = '\0';
1.20      vincent   461:                for (cp2 = cp1 + chunk; cp2 < &dotp->l_text[dotp->l_used];
                    462:                    cp2++)
                    463:                        *cp1++ = *cp2;
1.4       millert   464:                dotp->l_used -= (int)chunk;
1.3       millert   465:                for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
                    466:                        if (wp->w_dotp == dotp && wp->w_doto >= doto) {
                    467:                                /* NOSTRICT */
1.1       deraadt   468:                                wp->w_doto -= chunk;
                    469:                                if (wp->w_doto < doto)
                    470:                                        wp->w_doto = doto;
                    471:                        }
1.3       millert   472:                        if (wp->w_markp == dotp && wp->w_marko >= doto) {
                    473:                                /* NOSTRICT */
1.1       deraadt   474:                                wp->w_marko -= chunk;
                    475:                                if (wp->w_marko < doto)
                    476:                                        wp->w_marko = doto;
                    477:                        }
                    478:                }
                    479:                n -= chunk;
                    480:        }
1.32    ! kjell     481:        if (kchunk(sv, len, kflag) != TRUE)
        !           482:                return (FALSE);
        !           483:        free(sv);
1.22      db        484:        return (TRUE);
1.1       deraadt   485: }
                    486:
                    487: /*
1.8       mickey    488:  * Delete a newline and join the current line with the next line. If the next
1.4       millert   489:  * line is the magic header line always return TRUE; merging the last line
1.8       mickey    490:  * with the header line can be thought of as always being a successful
                    491:  * operation.  Even if nothing is done, this makes the kill buffer work
                    492:  * "right".  Easy cases can be done by shuffling data around.  Hard cases
                    493:  * require that lines be moved about in memory.  Return FALSE on error and
1.4       millert   494:  * TRUE if all looks ok.
1.1       deraadt   495:  */
1.4       millert   496: int
1.15      vincent   497: ldelnewline(void)
1.3       millert   498: {
1.28      deraadt   499:        struct line     *lp1, *lp2, *lp3;
                    500:        struct mgwin    *wp;
1.1       deraadt   501:
1.15      vincent   502:        if (curbp->b_flag & BFREADONLY) {
                    503:                ewprintf("Buffer is read only");
1.22      db        504:                return (FALSE);
1.15      vincent   505:        }
                    506:
1.1       deraadt   507:        lp1 = curwp->w_dotp;
                    508:        lp2 = lp1->l_fp;
1.4       millert   509:        /* at the end of the buffer */
                    510:        if (lp2 == curbp->b_linep)
1.22      db        511:                return (TRUE);
1.1       deraadt   512:        if (lp2->l_used <= lp1->l_size - lp1->l_used) {
                    513:                bcopy(&lp2->l_text[0], &lp1->l_text[lp1->l_used], lp2->l_used);
1.3       millert   514:                for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1       deraadt   515:                        if (wp->w_linep == lp2)
                    516:                                wp->w_linep = lp1;
                    517:                        if (wp->w_dotp == lp2) {
1.3       millert   518:                                wp->w_dotp = lp1;
1.1       deraadt   519:                                wp->w_doto += lp1->l_used;
                    520:                        }
                    521:                        if (wp->w_markp == lp2) {
1.3       millert   522:                                wp->w_markp = lp1;
1.1       deraadt   523:                                wp->w_marko += lp1->l_used;
                    524:                        }
                    525:                }
                    526:                lp1->l_used += lp2->l_used;
                    527:                lp1->l_fp = lp2->l_fp;
                    528:                lp2->l_fp->l_bp = lp1;
1.4       millert   529:                free((char *)lp2);
1.22      db        530:                return (TRUE);
1.1       deraadt   531:        }
1.3       millert   532:        if ((lp3 = lalloc(lp1->l_used + lp2->l_used)) == NULL)
1.22      db        533:                return (FALSE);
1.1       deraadt   534:        bcopy(&lp1->l_text[0], &lp3->l_text[0], lp1->l_used);
                    535:        bcopy(&lp2->l_text[0], &lp3->l_text[lp1->l_used], lp2->l_used);
                    536:        lp1->l_bp->l_fp = lp3;
                    537:        lp3->l_fp = lp2->l_fp;
                    538:        lp2->l_fp->l_bp = lp3;
                    539:        lp3->l_bp = lp1->l_bp;
1.3       millert   540:        for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
                    541:                if (wp->w_linep == lp1 || wp->w_linep == lp2)
1.1       deraadt   542:                        wp->w_linep = lp3;
                    543:                if (wp->w_dotp == lp1)
1.3       millert   544:                        wp->w_dotp = lp3;
1.1       deraadt   545:                else if (wp->w_dotp == lp2) {
1.3       millert   546:                        wp->w_dotp = lp3;
1.1       deraadt   547:                        wp->w_doto += lp1->l_used;
                    548:                }
                    549:                if (wp->w_markp == lp1)
1.3       millert   550:                        wp->w_markp = lp3;
1.1       deraadt   551:                else if (wp->w_markp == lp2) {
1.3       millert   552:                        wp->w_markp = lp3;
1.1       deraadt   553:                        wp->w_marko += lp1->l_used;
                    554:                }
                    555:        }
1.4       millert   556:        free((char *)lp1);
                    557:        free((char *)lp2);
1.22      db        558:        return (TRUE);
1.1       deraadt   559: }
1.9       vincent   560:
1.1       deraadt   561: /*
1.8       mickey    562:  * Replace plen characters before dot with argument string.  Control-J
                    563:  * characters in st are interpreted as newlines.  There is a casehack
                    564:  * disable flag (normally it likes to match case of replacement to what
1.4       millert   565:  * was there).
1.1       deraadt   566:  */
1.4       millert   567: int
1.27      kjell     568: lreplace(RSIZE plen, char *st)
1.4       millert   569: {
                    570:        RSIZE   rlen;   /* replacement length            */
1.15      vincent   571:
                    572:        if (curbp->b_flag & BFREADONLY) {
                    573:                ewprintf("Buffer is read only");
1.22      db        574:                return (FALSE);
1.15      vincent   575:        }
1.24      kjell     576:        undo_add_boundary();
                    577:        undo_no_boundary(TRUE);
1.25      deraadt   578:
1.6       art       579:        (void)backchar(FFARG | FFRAND, (int)plen);
1.24      kjell     580:        (void)ldelete(plen, KNONE);
1.15      vincent   581:
1.1       deraadt   582:        rlen = strlen(st);
1.24      kjell     583:        region_put_data(st, rlen);
                    584:        lchange(WFHARD);
1.1       deraadt   585:
1.24      kjell     586:        undo_no_boundary(FALSE);
                    587:        undo_add_boundary();
1.1       deraadt   588:        return (TRUE);
                    589: }
1.13      vincent   590:
1.1       deraadt   591: /*
1.8       mickey    592:  * Delete all of the text saved in the kill buffer.  Called by commands when
                    593:  * a new kill context is created. The kill buffer array is released, just in
1.4       millert   594:  * case the buffer has grown to an immense size.  No errors.
1.1       deraadt   595:  */
1.6       art       596: void
1.17      vincent   597: kdelete(void)
1.3       millert   598: {
1.1       deraadt   599:        if (kbufp != NULL) {
1.4       millert   600:                free((char *)kbufp);
1.1       deraadt   601:                kbufp = NULL;
                    602:                kstart = kused = ksize = 0;
                    603:        }
                    604: }
                    605:
                    606: /*
1.8       mickey    607:  * Insert a character to the kill buffer, enlarging the buffer if there
                    608:  * isn't any room. Always grow the buffer in chunks, on the assumption
                    609:  * that if you put something in the kill buffer you are going to put more
                    610:  * stuff there too later. Return TRUE if all is well, and FALSE on errors.
1.4       millert   611:  * Print a message on errors.  Dir says whether to put it at back or front.
1.32    ! kjell     612:  * This call is ignored if  KNONE is set.
1.1       deraadt   613:  */
1.4       millert   614: int
1.17      vincent   615: kinsert(int c, int dir)
1.3       millert   616: {
1.32    ! kjell     617:        if (dir == KNONE)
        !           618:                return (TRUE);
1.26      kjell     619:        if (kused == ksize && dir == KFORW && kgrow(dir) == FALSE)
1.22      db        620:                return (FALSE);
1.26      kjell     621:        if (kstart == 0 && dir == KBACK && kgrow(dir) == FALSE)
1.22      db        622:                return (FALSE);
1.3       millert   623:        if (dir == KFORW)
                    624:                kbufp[kused++] = c;
                    625:        else if (dir == KBACK)
                    626:                kbufp[--kstart] = c;
                    627:        else
                    628:                panic("broken kinsert call");   /* Oh shit! */
1.1       deraadt   629:        return (TRUE);
                    630: }
                    631:
                    632: /*
1.26      kjell     633:  * kgrow - just get more kill buffer for the callee. If dir = KBACK
1.1       deraadt   634:  * we are trying to get space at the beginning of the kill buffer.
                    635:  */
1.4       millert   636: static int
1.26      kjell     637: kgrow(int dir)
1.3       millert   638: {
1.4       millert   639:        int      nstart;
                    640:        char    *nbufp;
1.1       deraadt   641:
1.4       millert   642:        if ((unsigned)(ksize + KBLOCK) <= (unsigned)ksize) {
1.1       deraadt   643:                /* probably 16 bit unsigned */
                    644:                ewprintf("Kill buffer size at maximum");
1.22      db        645:                return (FALSE);
1.1       deraadt   646:        }
1.4       millert   647:        if ((nbufp = malloc((unsigned)(ksize + KBLOCK))) == NULL) {
                    648:                ewprintf("Can't get %ld bytes", (long)(ksize + KBLOCK));
1.22      db        649:                return (FALSE);
1.1       deraadt   650:        }
1.26      kjell     651:        nstart = (dir == KBACK) ? (kstart + KBLOCK) : (KBLOCK / 4);
1.4       millert   652:        bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (int)(kused - kstart));
1.1       deraadt   653:        if (kbufp != NULL)
1.4       millert   654:                free((char *)kbufp);
1.3       millert   655:        kbufp = nbufp;
1.1       deraadt   656:        ksize += KBLOCK;
                    657:        kused = kused - kstart + nstart;
                    658:        kstart = nstart;
1.22      db        659:        return (TRUE);
1.1       deraadt   660: }
                    661:
                    662: /*
1.8       mickey    663:  * This function gets characters from the kill buffer. If the character
                    664:  * index "n" is off the end, it returns "-1". This lets the caller just
1.4       millert   665:  * scan along until it gets a "-1" back.
1.1       deraadt   666:  */
1.4       millert   667: int
1.21      vincent   668: kremove(int n)
1.3       millert   669: {
1.1       deraadt   670:        if (n < 0 || n + kstart >= kused)
1.22      db        671:                return (-1);
                    672:        return (CHARMASK(kbufp[n + kstart]));
1.29      kjell     673: }
                    674:
                    675: /*
                    676:  * Copy a string into the kill buffer. kflag gives direction.
                    677:  * if KNONE, do nothing.
                    678:  */
                    679: int
                    680: kchunk(char *cp1, RSIZE chunk, int kflag)
                    681: {
                    682:        /*
                    683:         * HACK - doesn't matter, and fixes back-over-nl bug for empty
                    684:         *      kill buffers.
                    685:         */
                    686:        if (kused == kstart)
                    687:                kflag = KFORW;
                    688:
                    689:        if (kflag == KFORW) {
                    690:                while (ksize - kused < chunk)
                    691:                        if (kgrow(kflag) == FALSE)
                    692:                                return (FALSE);
                    693:                bcopy(cp1, &(kbufp[kused]), (int)chunk);
                    694:                kused += chunk;
                    695:        } else if (kflag == KBACK) {
                    696:                while (kstart < chunk)
                    697:                        if (kgrow(kflag) == FALSE)
                    698:                                return (FALSE);
                    699:                bcopy(cp1, &(kbufp[kstart - chunk]), (int)chunk);
                    700:                kstart -= chunk;
                    701:        } else if (kflag != KNONE)
                    702:                panic("broken ldelete call");
                    703:
                    704:        return (TRUE);
1.1       deraadt   705: }