Annotation of coherent/g/usr/bin/me/line.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * The functions in this file are a general set of line management utilities.
                      3:  * They are the only routines that touch the text. They also touch the buffer
                      4:  * and window structures, to make sure that the necessary updating gets done.
                      5:  * There are routines in this file that handle the kill buffer too.
                      6:  * It isn't here for any good reason.
                      7:  *
                      8:  * Note that this code only updates the dot and mark values in the window list.
                      9:  * Since all the code acts on the current window, the buffer that we are
                     10:  * editing must be being displayed, which means that "b_nwnd" is non zero,
                     11:  * which means that the dot and mark values in the buffer headers are nonsense.
                     12:  */
                     13: #include       <stdio.h>
                     14: #include       "ed.h"
                     15: 
                     16: #define        NBLOCK  16                      /* Line block chunk size        */
                     17: #define        KBLOCK  256                     /* Kill buffer block size       */
                     18: 
                     19: uchar  *kbufp  = NULL;                 /* Kill buffer data             */
                     20: int    kused   = 0;                    /* # of bytes used in KB        */
                     21: int    ksize   = 0;                    /* # of bytes allocated in KB   */
                     22: 
                     23: /*
                     24:  * This routine allocates a block of memory large enough to hold a LINE
                     25:  * containing "used" characters. The block is always rounded up a bit.
                     26:  * Return a pointer to the new block, or NULL if there isn't any memory left.
                     27:  * Print a message in the message line if no space.
                     28:  */
                     29: LINE   *
                     30: lalloc(used)
                     31: register int   used;
                     32: {
                     33:        register LINE   *lp;
                     34:        register int    size;
                     35: 
                     36:        size = (used+NBLOCK-1) & ~(NBLOCK-1);
                     37:        if (size == 0)                          /* Assume that an empty */
                     38:                size = NBLOCK;                  /* line is for type-in. */
                     39:        if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) {
                     40:                mlwrite("Cannot allocate %d bytes", size);
                     41:                return (NULL);
                     42:        }
                     43:        lp->l_size = size;
                     44:        lp->l_used = used;
                     45:        lp->l_lnumber = 0;                      /* This is a new line... */
                     46:        return (lp);
                     47: }
                     48: 
                     49: /*
                     50:  * Delete line "lp". Fix all of the links that might point at it (they are
                     51:  * moved to offset 0 of the next line. Unlink the line from whatever buffer it
                     52:  * might be in. Release the memory. The buffers are updated too; the magic
                     53:  * conditions described in the above comments don't hold here.
                     54:  */
                     55: lfree(lp)
                     56: register LINE  *lp;
                     57: {
                     58:        register BUFFER *bp;
                     59:        register WINDOW *wp;
                     60: 
                     61:        wp = wheadp;
                     62:        while (wp != NULL) {
                     63:                if (wp->w_linep == lp)
                     64:                        wp->w_linep = lp->l_fp;
                     65:                if (wp->w_dotp  == lp) {
                     66:                        wp->w_dotp  = lp->l_fp;
                     67:                        wp->w_doto  = 0;
                     68:                }
                     69:                if (wp->w_markp == lp) {
                     70:                        wp->w_markp = lp->l_fp;
                     71:                        wp->w_marko = 0;
                     72:                }
                     73:                wp = wp->w_wndp;
                     74:        }
                     75:        bp = bheadp;
                     76:        while (bp != NULL) {
                     77:                if (bp->b_nwnd == 0) {
                     78:                        if (bp->b_dotp  == lp) {
                     79:                                bp->b_dotp = lp->l_fp;
                     80:                                bp->b_doto = 0;
                     81:                        }
                     82:                        if (bp->b_markp == lp) {
                     83:                                bp->b_markp = lp->l_fp;
                     84:                                bp->b_marko = 0;
                     85:                        }
                     86:                }
                     87:                bp = bp->b_bufp;
                     88:        }
                     89:        lp->l_bp->l_fp = lp->l_fp;
                     90:        lp->l_fp->l_bp = lp->l_bp;
                     91:        free((char *) lp);
                     92: }
                     93: 
                     94: /*
                     95:  * This routine gets called when a character is changed in place in the
                     96:  * current buffer. It updates all of the required flags in the buffer and
                     97:  * window system. The flag used is passed as an argument; if the buffer is
                     98:  * being displayed in more than 1 window we change EDIT to HARD.
                     99:  * Set MODE if the mode line needs to be updated (the "*" has to be set).
                    100:  */
                    101: lchange(flag)
                    102: register int   flag;
                    103: {
                    104:        register WINDOW *wp;
                    105: 
                    106:        if (curbp->b_nwnd != 1)                 /* Ensure hard.         */
                    107:                flag = WFHARD;
                    108:        if ((curbp->b_flag&BFCHG) == 0) {       /* First change, so     */
                    109:                flag |= WFMODE;                 /* update mode lines.   */
                    110:                curbp->b_flag |= BFCHG;
                    111:        }
                    112:        wp = wheadp;
                    113:        while (wp != NULL) {
                    114:                if (wp->w_bufp == curbp)
                    115:                        wp->w_flag |= flag;
                    116:                wp = wp->w_wndp;
                    117:        }
                    118: }
                    119: 
                    120: /*
                    121:  * Insert "n" copies of the character "c" at the current location of dot.
                    122:  * In the easy case all that happens is the text is stored in the line.
                    123:  * In the hard case, the line has to be reallocated.
                    124:  * When the window list is updated, take special care; I screwed it up once.
                    125:  * You always update dot in the current window. You update mark, and a
                    126:  * dot in another window, if it is greater than the place where you did
                    127:  * the insert.
                    128:  * Return TRUE if all is well, and FALSE on errors.
                    129:  */
                    130: linsert(n, c)
                    131: {
                    132:        register uchar  *cp1;
                    133:        register uchar  *cp2;
                    134:        register LINE   *lp1;
                    135:        register LINE   *lp2;
                    136:        register LINE   *lp3;
                    137:        register int    doto;
                    138:        register int    i;
                    139:        register WINDOW *wp;
                    140: 
                    141:        lchange(WFEDIT);
                    142:        lp1 = curwp->w_dotp;                    /* Current line         */
                    143:        if (lp1 == curbp->b_linep) {            /* At the end: special  */
                    144:                if (curwp->w_doto != 0) {
                    145:                        mlwrite("bug: linsert");
                    146:                        return (FALSE);
                    147:                }
                    148:                if ((lp2=lalloc(n)) == NULL)    /* Allocate new line    */
                    149:                        return (FALSE);
                    150:                lp3 = lp1->l_bp;                /* Previous line        */
                    151:                lp3->l_fp = lp2;                /* Link in              */
                    152:                lp2->l_fp = lp1;
                    153:                lp1->l_bp = lp2;
                    154:                lp2->l_bp = lp3;
                    155:                for (i=0; i<n; ++i)
                    156:                        lp2->l_text[i] = c;
                    157:                curwp->w_dotp = lp2;
                    158:                curwp->w_doto = n;
                    159:                return (TRUE);
                    160:        }
                    161:        doto = curwp->w_doto;                   /* Save for later.      */
                    162:        if (lp1->l_used+n > lp1->l_size) {      /* Hard: reallocate     */
                    163:                if ((lp2=lalloc(lp1->l_used+n)) == NULL)
                    164:                        return (FALSE);
                    165:                cp1 = &lp1->l_text[0];
                    166:                cp2 = &lp2->l_text[0];
                    167:                while (cp1 != &lp1->l_text[doto])
                    168:                        *cp2++ = *cp1++;
                    169:                cp2 += n;
                    170:                while (cp1 != &lp1->l_text[lp1->l_used])
                    171:                        *cp2++ = *cp1++;
                    172:                lp1->l_bp->l_fp = lp2;
                    173:                lp2->l_fp = lp1->l_fp;
                    174:                lp1->l_fp->l_bp = lp2;
                    175:                lp2->l_bp = lp1->l_bp;
                    176:                free((char *) lp1);
                    177:        } else {                                /* Easy: in place       */
                    178:                lp2 = lp1;                      /* Pretend new line     */
                    179:                lp2->l_used += n;
                    180:                cp2 = &lp1->l_text[lp1->l_used];
                    181:                cp1 = cp2-n;
                    182:                while (cp1 != &lp1->l_text[doto])
                    183:                        *--cp2 = *--cp1;
                    184:        }
                    185:        for (i=0; i<n; ++i)                     /* Add the characters   */
                    186:                lp2->l_text[doto+i] = c;
                    187:        wp = wheadp;                            /* Update windows       */
                    188:        while (wp != NULL) {
                    189:                if (wp->w_linep == lp1)
                    190:                        wp->w_linep = lp2;
                    191:                if (wp->w_dotp == lp1) {
                    192:                        wp->w_dotp = lp2;
                    193:                        if (wp==curwp || wp->w_doto>doto)
                    194:                                wp->w_doto += n;
                    195:                }
                    196:                if (wp->w_markp == lp1) {
                    197:                        wp->w_markp = lp2;
                    198:                        if (wp->w_marko > doto)
                    199:                                wp->w_marko += n;
                    200:                }
                    201:                wp = wp->w_wndp;
                    202:        }
                    203:        return (TRUE);
                    204: }
                    205: 
                    206: /*
                    207:  * Insert a newline into the buffer at the current location of dot in the
                    208:  * current window. The funny ass-backwards way it does things is not a botch;
                    209:  * it just makes the last line in the file not a special case. Return TRUE if
                    210:  * everything works out and FALSE on error (memory allocation failure).
                    211:  * The update of dot and mark is a bit easier then in the above case, because
                    212:  * the split forces more updating.
                    213:  */
                    214: lnewline()
                    215: {
                    216:        register uchar  *cp1;
                    217:        register uchar  *cp2;
                    218:        register LINE   *lp1;
                    219:        register LINE   *lp2;
                    220:        register int    doto;
                    221:        register WINDOW *wp;
                    222: 
                    223:        lchange(WFHARD);
                    224:        lp1  = curwp->w_dotp;                   /* Get the address and  */
                    225:        doto = curwp->w_doto;                   /* offset of "."        */
                    226:        if ((lp2=lalloc(doto)) == NULL)         /* New first half line  */
                    227:                return (FALSE);
                    228:        cp1 = &lp1->l_text[0];                  /* Shuffle text around  */
                    229:        cp2 = &lp2->l_text[0];
                    230:        while (cp1 != &lp1->l_text[doto])
                    231:                *cp2++ = *cp1++;
                    232:        cp2 = &lp1->l_text[0];
                    233:        while (cp1 != &lp1->l_text[lp1->l_used])
                    234:                *cp2++ = *cp1++;
                    235:        lp1->l_used -= doto;
                    236:        lp2->l_bp = lp1->l_bp;
                    237:        lp1->l_bp = lp2;
                    238:        lp2->l_bp->l_fp = lp2;
                    239:        lp2->l_fp = lp1;
                    240:        wp = wheadp;                            /* Windows              */
                    241:        while (wp != NULL) {
                    242:                if (wp->w_linep == lp1)
                    243:                        wp->w_linep = lp2;
                    244:                if (wp->w_dotp == lp1) {
                    245:                        if (wp->w_doto < doto)
                    246:                                wp->w_dotp = lp2;
                    247:                        else
                    248:                                wp->w_doto -= doto;
                    249:                }
                    250:                if (wp->w_markp == lp1) {
                    251:                        if (wp->w_marko < doto)
                    252:                                wp->w_markp = lp2;
                    253:                        else
                    254:                                wp->w_marko -= doto;
                    255:                }
                    256:                wp = wp->w_wndp;
                    257:        }       
                    258:        return (TRUE);
                    259: }
                    260: 
                    261: /*
                    262:  * This function deletes "n" bytes, starting at dot. It understands how to deal
                    263:  * with end of lines, etc. It returns TRUE if all of the characters were
                    264:  * deleted, and FALSE if they were not (because dot ran into the end of
                    265:  * the buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
                    266:  */
                    267: ldelete(n, kflag)
                    268: {
                    269:        register uchar  *cp1;
                    270:        register uchar  *cp2;
                    271:        register LINE   *dotp;
                    272:        register int    doto;
                    273:        register int    chunk;
                    274:        register WINDOW *wp;
                    275: 
                    276:        while (n != 0) {
                    277:                dotp = curwp->w_dotp;
                    278:                doto = curwp->w_doto;
                    279:                if (dotp == curbp->b_linep)     /* Hit end of buffer.   */
                    280:                        return (FALSE);
                    281:                chunk = dotp->l_used-doto;      /* Size of chunk.       */
                    282:                if (chunk > n)
                    283:                        chunk = n;
                    284:                if (chunk == 0) {               /* End of line, merge.  */
                    285:                        lchange(WFHARD);
                    286:                        if (ldelnewline() == FALSE
                    287:                        || (kflag!=FALSE && kinsert('\n')==FALSE))
                    288:                                return (FALSE);
                    289:                        --n;
                    290:                        continue;
                    291:                }
                    292:                lchange(WFEDIT);
                    293:                cp1 = &dotp->l_text[doto];      /* Scrunch text.        */
                    294:                cp2 = cp1 + chunk;
                    295:                if (kflag != FALSE) {           /* Kill?                */
                    296:                        while (cp1 != cp2) {
                    297:                                if (kinsert(*cp1) == FALSE)
                    298:                                        return (FALSE);
                    299:                                ++cp1;
                    300:                        }
                    301:                        cp1 = &dotp->l_text[doto];
                    302:                }
                    303:                while (cp2 != &dotp->l_text[dotp->l_used])
                    304:                        *cp1++ = *cp2++;
                    305:                dotp->l_used -= chunk;
                    306:                wp = wheadp;                    /* Fix windows          */
                    307:                while (wp != NULL) {
                    308:                        if (wp->w_dotp==dotp && wp->w_doto>=doto) {
                    309:                                wp->w_doto -= chunk;
                    310:                                if (wp->w_doto < doto)
                    311:                                        wp->w_doto = doto;
                    312:                        }       
                    313:                        if (wp->w_markp==dotp && wp->w_marko>=doto) {
                    314:                                wp->w_marko -= chunk;
                    315:                                if (wp->w_marko < doto)
                    316:                                        wp->w_marko = doto;
                    317:                        }
                    318:                        wp = wp->w_wndp;
                    319:                }
                    320:                n -= chunk;
                    321:        }
                    322:        return (TRUE);
                    323: }
                    324: 
                    325: /*
                    326:  * Delete a newline. Join the current line with the next line. If the next
                    327:  * line is the magic header line always return TRUE; merging the last line
                    328:  * with the header line can be thought of as always being a successful
                    329:  * operation, even if nothing is done, and this makes the kill buffer
                    330:  * work "right". Easy cases can be done by shuffling data around.
                    331:  * Hard cases require that lines be moved about in memory.
                    332:  * Return FALSE on error and TRUE if all looks ok. Called by "ldelete" only.
                    333:  */
                    334: ldelnewline()
                    335: {
                    336:        register uchar  *cp1;
                    337:        register uchar  *cp2;
                    338:        register LINE   *lp1;
                    339:        register LINE   *lp2;
                    340:        register LINE   *lp3;
                    341:        register WINDOW *wp;
                    342: 
                    343:        lp1 = curwp->w_dotp;                    /* This line...         */
                    344:        lp2 = lp1->l_fp;                        /* The next line...     */
                    345: 
                    346:        if (lp2 == curbp->b_linep) {            /* At the buffer end.   */
                    347:                if (lp1->l_used == 0)           /* Blank line.          */
                    348:                        lfree(lp1);
                    349:                return (TRUE);
                    350:        }
                    351:        /* Fix file-line numbers.               */
                    352:        if ((lp1->l_used == 0) || (lp1->l_lnumber == 0))
                    353:                lp1->l_lnumber = lp2->l_lnumber;
                    354: 
                    355:        if (lp2->l_used <= lp1->l_size-lp1->l_used) {
                    356:                cp1 = &lp1->l_text[lp1->l_used];
                    357:                cp2 = &lp2->l_text[0];
                    358:                while (cp2 != &lp2->l_text[lp2->l_used])
                    359:                        *cp1++ = *cp2++;
                    360:                wp = wheadp;
                    361:                while (wp != NULL) {
                    362:                        if (wp->w_linep == lp2)
                    363:                                wp->w_linep = lp1;
                    364:                        if (wp->w_dotp == lp2) {
                    365:                                wp->w_dotp  = lp1;
                    366:                                wp->w_doto += lp1->l_used;
                    367:                        }
                    368:                        if (wp->w_markp == lp2) {
                    369:                                wp->w_markp  = lp1;
                    370:                                wp->w_marko += lp1->l_used;
                    371:                        }
                    372:                        wp = wp->w_wndp;
                    373:                }               
                    374:                lp1->l_used += lp2->l_used;
                    375:                lp1->l_fp = lp2->l_fp;
                    376:                lp2->l_fp->l_bp = lp1;
                    377:                free((char *) lp2);
                    378:                return (TRUE);
                    379:        }
                    380:        if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
                    381:                return (FALSE);
                    382:        cp1 = &lp1->l_text[0];
                    383:        cp2 = &lp3->l_text[0];
                    384:        while (cp1 != &lp1->l_text[lp1->l_used])
                    385:                *cp2++ = *cp1++;
                    386:        cp1 = &lp2->l_text[0];
                    387:        while (cp1 != &lp2->l_text[lp2->l_used])
                    388:                *cp2++ = *cp1++;
                    389:        lp1->l_bp->l_fp = lp3;
                    390:        lp3->l_fp = lp2->l_fp;
                    391:        lp2->l_fp->l_bp = lp3;
                    392:        lp3->l_bp = lp1->l_bp;
                    393:        wp = wheadp;
                    394:        while (wp != NULL) {
                    395:                if (wp->w_linep==lp1 || wp->w_linep==lp2)
                    396:                        wp->w_linep = lp3;
                    397:                if (wp->w_dotp == lp1)
                    398:                        wp->w_dotp  = lp3;
                    399:                else if (wp->w_dotp == lp2) {
                    400:                        wp->w_dotp  = lp3;
                    401:                        wp->w_doto += lp1->l_used;
                    402:                }
                    403:                if (wp->w_markp == lp1)
                    404:                        wp->w_markp  = lp3;
                    405:                else if (wp->w_markp == lp2) {
                    406:                        wp->w_markp  = lp3;
                    407:                        wp->w_marko += lp1->l_used;
                    408:                }
                    409:                wp = wp->w_wndp;
                    410:        }
                    411:        free((char *) lp1);
                    412:        free((char *) lp2);
                    413:        return (TRUE);
                    414: }
                    415: 
                    416: /*
                    417:  * Delete all of the text saved in the kill buffer.  Called by commands when
                    418:  * a new kill context is being created. The kill buffer array is released,
                    419:  * just in case the buffer has grown to immense size. No errors.
                    420:  */
                    421: kdelete()
                    422: {
                    423:        if (kbufp != NULL) {
                    424:                free((char *) kbufp);
                    425:                kbufp = NULL;
                    426:                kused = 0;
                    427:                ksize = 0;
                    428:        }
                    429: }
                    430: 
                    431: /*
                    432:  * Insert a character to the kill buffer, enlarging the buffer if there
                    433:  * isn't any room. Always grow the buffer in chunks, on the assumption
                    434:  * that if you put something in the kill buffer you are going to put more
                    435:  * stuff there too later. Return TRUE if all is well, and FALSE on errors.
                    436:  */
                    437: kinsert(c)
                    438: {
                    439:        register uchar  *nbufp;
                    440:        register int    i;
                    441: 
                    442:        if (kused == ksize) {
                    443:                if ((nbufp=malloc(ksize+KBLOCK)) == NULL)
                    444:                        return (FALSE);
                    445:                for (i=0; i<ksize; ++i)
                    446:                        nbufp[i] = kbufp[i];
                    447:                if (kbufp != NULL)
                    448:                        free((char *) kbufp);
                    449:                kbufp  = nbufp;
                    450:                ksize += KBLOCK;
                    451:        }
                    452:        kbufp[kused++] = c;
                    453:        return (TRUE);
                    454: }
                    455: 
                    456: /*
                    457:  * This function gets characters from the kill buffer. If the character index
                    458:  * "n" is off the end, it returns "-1". This lets the caller just scan along
                    459:  * until it gets a "-1" back.
                    460:  */
                    461: kremove(n)
                    462: {
                    463:        if (n >= kused)
                    464:                return (-1);
                    465:        else
                    466:                return (kbufp[n] & 0xFF);
                    467: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.