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

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