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

Annotation of src/usr.bin/mg/undo.c, Revision 1.42

1.42    ! kjell       1: /* $OpenBSD: undo.c,v 1.41 2006/07/25 08:22:32 kjell Exp $ */
1.1       vincent     2: /*
1.25      db          3:  * Copyright (c) 2002 Vincent Labrecque <vincent@openbsd.org>
1.39      kjell       4:  * Copyright (c) 2005, 2006 Kjell Wooding <kjell@openbsd.org>
1.10      vincent     5:  * All rights reserved.
1.1       vincent     6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     18:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     19:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     20:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     21:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     22:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     23:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     24:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     25:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     26:  */
                     27:
                     28: #include "def.h"
                     29: #include "kbd.h"
                     30:
                     31: #define MAX_FREE_RECORDS       32
                     32:
                     33: /*
                     34:  * Local variables
                     35:  */
1.7       vincent    36: static LIST_HEAD(, undo_rec)    undo_free;
                     37: static int                      undo_free_num;
1.42    ! kjell      38: static int                      boundary_flag = TRUE;
        !            39: static int                      undo_enable_flag = TRUE;
1.1       vincent    40:
                     41: /*
                     42:  * Local functions
                     43:  */
1.35      deraadt    44: static int find_dot(struct line *, int);
1.39      kjell      45: static int find_lo(int, struct line **, int *, int *);
1.1       vincent    46: static struct undo_rec *new_undo_record(void);
                     47: static int drop_oldest_undo_record(void);
                     48:
1.9       vincent    49: /*
1.24      vincent    50:  * find_dot, find_lo()
1.9       vincent    51:  *
                     52:  * Find an absolute dot in the buffer from a line/offset pair, and vice-versa.
                     53:  *
1.13      deraadt    54:  * Since lines can be deleted while they are referenced by undo record, we
1.9       vincent    55:  * need to have an absolute dot to have something reliable.
                     56:  */
1.1       vincent    57: static int
1.35      deraadt    58: find_dot(struct line *lp, int off)
1.1       vincent    59: {
1.25      db         60:        int      count = 0;
1.35      deraadt    61:        struct line     *p;
1.1       vincent    62:
1.41      kjell      63:        for (p = curbp->b_headp; p != lp; p = lforw(p)) {
1.1       vincent    64:                if (count != 0) {
1.41      kjell      65:                        if (p == curbp->b_headp) {
1.1       vincent    66:                                ewprintf("Error: Undo stuff called with a"
1.9       vincent    67:                                    "nonexistent line");
1.11      vincent    68:                                return (FALSE);
1.1       vincent    69:                        }
                     70:                }
                     71:                count += llength(p) + 1;
                     72:        }
                     73:        count += off;
                     74:
1.11      vincent    75:        return (count);
1.1       vincent    76: }
                     77:
                     78: static int
1.39      kjell      79: find_lo(int pos, struct line **olp, int *offset, int *lnum)
1.1       vincent    80: {
1.35      deraadt    81:        struct line *p;
1.39      kjell      82:        int lineno;
1.1       vincent    83:
1.41      kjell      84:        p = curbp->b_headp;
1.39      kjell      85:        lineno = 0;
1.9       vincent    86:        while (pos > llength(p)) {
1.1       vincent    87:                pos -= llength(p) + 1;
1.41      kjell      88:                if ((p = lforw(p)) == curbp->b_headp) {
1.1       vincent    89:                        *olp = NULL;
                     90:                        *offset = 0;
1.11      vincent    91:                        return (FALSE);
1.1       vincent    92:                }
1.39      kjell      93:                lineno++;
1.1       vincent    94:        }
                     95:        *olp = p;
                     96:        *offset = pos;
1.39      kjell      97:        *lnum = lineno;
1.1       vincent    98:
1.11      vincent    99:        return (TRUE);
1.1       vincent   100: }
                    101:
                    102: static struct undo_rec *
                    103: new_undo_record(void)
                    104: {
                    105:        struct undo_rec *rec;
                    106:
                    107:        rec = LIST_FIRST(&undo_free);
1.9       vincent   108:        if (rec != NULL) {
1.1       vincent   109:                LIST_REMOVE(rec, next); /* Remove it from the free-list */
1.9       vincent   110:                undo_free_num--;
                    111:        } else {
1.25      db        112:                if ((rec = malloc(sizeof(*rec))) == NULL)
1.1       vincent   113:                        panic("Out of memory in undo code (record)");
                    114:        }
                    115:        memset(rec, 0, sizeof(struct undo_rec));
1.9       vincent   116:
1.11      vincent   117:        return (rec);
1.1       vincent   118: }
                    119:
1.7       vincent   120: void
1.1       vincent   121: free_undo_record(struct undo_rec *rec)
                    122: {
1.9       vincent   123:        static int initialised = 0;
                    124:
                    125:        /*
                    126:         * On the first run, do initialisation of the free list.
                    127:         */
                    128:        if (initialised == 0) {
                    129:                LIST_INIT(&undo_free);
                    130:                initialised = 1;
                    131:        }
1.1       vincent   132:        if (rec->content != NULL) {
                    133:                free(rec->content);
                    134:                rec->content = NULL;
                    135:        }
                    136:        if (undo_free_num >= MAX_FREE_RECORDS) {
                    137:                free(rec);
                    138:                return;
                    139:        }
                    140:        undo_free_num++;
1.9       vincent   141:
1.1       vincent   142:        LIST_INSERT_HEAD(&undo_free, rec, next);
                    143: }
                    144:
                    145: /*
                    146:  * Drop the oldest undo record in our list. Return 1 if we could remove it,
1.25      db        147:  * 0 if the undo list was empty.
1.1       vincent   148:  */
                    149: static int
                    150: drop_oldest_undo_record(void)
                    151: {
                    152:        struct undo_rec *rec;
                    153:
1.29      kjell     154:        rec = LIST_END(&curbp->b_undo);
1.1       vincent   155:        if (rec != NULL) {
                    156:                undo_free_num--;
1.9       vincent   157:                LIST_REMOVE(rec, next);
1.1       vincent   158:                free_undo_record(rec);
1.11      vincent   159:                return (1);
1.1       vincent   160:        }
1.11      vincent   161:        return (0);
1.1       vincent   162: }
1.9       vincent   163:
                    164: static __inline__ int
1.22      vincent   165: lastrectype(void)
1.1       vincent   166: {
1.9       vincent   167:        struct undo_rec *rec;
                    168:
1.29      kjell     169:        if ((rec = LIST_FIRST(&curbp->b_undo)) != NULL)
1.22      vincent   170:                return (rec->type);
1.11      vincent   171:        return (0);
1.1       vincent   172: }
                    173:
1.30      kjell     174: /*
1.42    ! kjell     175:  * Returns TRUE if undo is enabled, FALSE otherwise.
        !           176:  */
        !           177: int
        !           178: undo_enabled(void)
        !           179: {
        !           180:        return (undo_enable_flag);
        !           181: }
        !           182:
        !           183: /*
1.30      kjell     184:  * undo_enable(TRUE/FALSE) will enable / disable the undo mechanism.
                    185:  * Returns TRUE if previously enabled, FALSE otherwise.
                    186:  */
1.1       vincent   187: int
                    188: undo_enable(int on)
                    189: {
1.42    ! kjell     190:        int pon = undo_enable_flag;
1.22      vincent   191:
1.42    ! kjell     192:        undo_enable_flag = on;
        !           193:        return (pon);
1.5       vincent   194: }
                    195:
1.30      kjell     196: /*
                    197:  * If undo is enabled, then:
1.42    ! kjell     198:  *   undo_boundary_enable(FALS) stops recording undo boundaries between actions.
        !           199:  *   undo_boundary_enable(TRUE) enables undo boundaries.
1.30      kjell     200:  * If undo is disabled, this function has no effect.
                    201:  */
1.42    ! kjell     202:
1.28      kjell     203: void
1.42    ! kjell     204: undo_boundary_enable(int flag)
1.28      kjell     205: {
1.42    ! kjell     206:        if (undo_enable_flag == TRUE)
        !           207:                boundary_flag = flag;
1.28      kjell     208: }
                    209:
1.30      kjell     210: /*
1.42    ! kjell     211:  * Record an undo boundary, unless boundary_flag == FALSE.
1.40      kjell     212:  * Does nothing if previous undo entry is already a boundary or 'modified' flag.
1.30      kjell     213:  */
1.37      kjell     214: void
1.9       vincent   215: undo_add_boundary(void)
1.5       vincent   216: {
                    217:        struct undo_rec *rec;
1.40      kjell     218:        int last;
1.5       vincent   219:
1.42    ! kjell     220:        if (boundary_flag == FALSE)
1.37      kjell     221:                return;
1.12      vincent   222:
1.40      kjell     223:        last = lastrectype();
                    224:        if (last == BOUNDARY || last == MODIFIED)
1.37      kjell     225:                return;
1.31      deraadt   226:
1.5       vincent   227:        rec = new_undo_record();
1.9       vincent   228:        rec->type = BOUNDARY;
1.5       vincent   229:
1.29      kjell     230:        LIST_INSERT_HEAD(&curbp->b_undo, rec, next);
1.9       vincent   231:
1.37      kjell     232:        return;
1.1       vincent   233: }
                    234:
1.40      kjell     235: /*
                    236:  * Record an undo "modified" boundary
                    237:  */
                    238: void
                    239: undo_add_modified(void)
                    240: {
                    241:        struct undo_rec *rec;
                    242:
                    243:        rec = new_undo_record();
                    244:        rec->type = MODIFIED;
                    245:
                    246:        LIST_INSERT_HEAD(&curbp->b_undo, rec, next);
                    247:
                    248:        return;
                    249: }
                    250:
1.1       vincent   251: int
1.35      deraadt   252: undo_add_insert(struct line *lp, int offset, int size)
1.1       vincent   253: {
1.35      deraadt   254:        struct region   reg;
1.25      db        255:        struct  undo_rec *rec;
                    256:        int     pos;
1.9       vincent   257:
1.42    ! kjell     258:        if (undo_enable_flag == FALSE)
1.11      vincent   259:                return (TRUE);
1.1       vincent   260:        reg.r_linep = lp;
                    261:        reg.r_offset = offset;
                    262:        reg.r_size = size;
1.9       vincent   263:
1.24      vincent   264:        pos = find_dot(lp, offset);
1.9       vincent   265:
1.1       vincent   266:        /*
                    267:         * We try to reuse the last undo record to `compress' things.
1.13      deraadt   268:         */
1.29      kjell     269:        rec = LIST_FIRST(&curbp->b_undo);
1.23      vincent   270:        if (rec != NULL && rec->type == INSERT) {
                    271:                if (rec->pos + rec->region.r_size == pos) {
                    272:                        rec->region.r_size += reg.r_size;
                    273:                        return (TRUE);
1.1       vincent   274:                }
                    275:        }
1.9       vincent   276:
1.1       vincent   277:        /*
1.25      db        278:         * We couldn't reuse the last undo record, so prepare a new one.
1.1       vincent   279:         */
                    280:        rec = new_undo_record();
1.9       vincent   281:        rec->pos = pos;
1.1       vincent   282:        rec->type = INSERT;
1.35      deraadt   283:        memmove(&rec->region, &reg, sizeof(struct region));
1.1       vincent   284:        rec->content = NULL;
1.9       vincent   285:
1.27      cloder    286:        undo_add_boundary();
1.9       vincent   287:
1.29      kjell     288:        LIST_INSERT_HEAD(&curbp->b_undo, rec, next);
1.1       vincent   289:
1.11      vincent   290:        return (TRUE);
1.1       vincent   291: }
                    292:
                    293: /*
1.25      db        294:  * This of course must be done _before_ the actual deletion is done.
1.1       vincent   295:  */
                    296: int
1.35      deraadt   297: undo_add_delete(struct line *lp, int offset, int size)
1.1       vincent   298: {
1.35      deraadt   299:        struct region   reg;
1.25      db        300:        struct  undo_rec *rec;
                    301:        int     pos;
1.1       vincent   302:
1.42    ! kjell     303:        if (undo_enable_flag == FALSE)
1.11      vincent   304:                return (TRUE);
1.1       vincent   305:
                    306:        reg.r_linep = lp;
                    307:        reg.r_offset = offset;
                    308:        reg.r_size = size;
                    309:
1.24      vincent   310:        pos = find_dot(lp, offset);
1.3       vincent   311:
1.10      vincent   312:        if (offset == llength(lp))      /* if it's a newline... */
1.9       vincent   313:                undo_add_boundary();
1.29      kjell     314:        else if ((rec = LIST_FIRST(&curbp->b_undo)) != NULL) {
1.9       vincent   315:                /*
                    316:                 * Separate this command from the previous one if we're not
                    317:                 * just before the previous record...
                    318:                 */
1.10      vincent   319:                if (rec->type == DELETE) {
1.9       vincent   320:                        if (rec->pos - rec->region.r_size != pos)
                    321:                                undo_add_boundary();
1.23      vincent   322:                }
1.3       vincent   323:        }
1.1       vincent   324:        rec = new_undo_record();
                    325:        rec->pos = pos;
                    326:
                    327:        rec->type = DELETE;
1.35      deraadt   328:        memmove(&rec->region, &reg, sizeof(struct region));
1.1       vincent   329:        do {
                    330:                rec->content = malloc(reg.r_size + 1);
                    331:        } while ((rec->content == NULL) && drop_oldest_undo_record());
1.9       vincent   332:
1.1       vincent   333:        if (rec->content == NULL)
                    334:                panic("Out of memory");
1.9       vincent   335:
1.1       vincent   336:        region_get_data(&reg, rec->content, reg.r_size);
                    337:
1.22      vincent   338:        if (lastrectype() != DELETE)
                    339:                undo_add_boundary();
                    340:
1.29      kjell     341:        LIST_INSERT_HEAD(&curbp->b_undo, rec, next);
1.1       vincent   342:
1.11      vincent   343:        return (TRUE);
1.1       vincent   344: }
                    345:
                    346: /*
1.25      db        347:  * This of course must be called before the change takes place.
1.1       vincent   348:  */
                    349: int
1.35      deraadt   350: undo_add_change(struct line *lp, int offset, int size)
1.1       vincent   351: {
1.42    ! kjell     352:        if (undo_enable_flag == FALSE)
1.11      vincent   353:                return (TRUE);
1.12      vincent   354:        undo_add_boundary();
1.42    ! kjell     355:        boundary_flag = FALSE;
1.12      vincent   356:        undo_add_delete(lp, offset, size);
                    357:        undo_add_insert(lp, offset, size);
1.42    ! kjell     358:        boundary_flag = TRUE;
1.9       vincent   359:        undo_add_boundary();
                    360:
1.11      vincent   361:        return (TRUE);
1.8       vincent   362: }
                    363:
                    364: /*
                    365:  * Show the undo records for the current buffer in a new buffer.
                    366:  */
1.32      kjell     367: /* ARGSUSED */
1.8       vincent   368: int
1.18      vincent   369: undo_dump(int f, int n)
1.8       vincent   370: {
1.25      db        371:        struct   undo_rec *rec;
1.35      deraadt   372:        struct buffer   *bp;
                    373:        struct mgwin    *wp;
1.25      db        374:        char     buf[4096], tmp[1024];
                    375:        int      num;
1.8       vincent   376:
                    377:        /*
                    378:         * Prepare the buffer for insertion.
                    379:         */
                    380:        if ((bp = bfind("*undo*", TRUE)) == NULL)
1.11      vincent   381:                return (FALSE);
1.9       vincent   382:        bp->b_flag |= BFREADONLY;
1.8       vincent   383:        bclear(bp);
                    384:        popbuf(bp);
                    385:
1.10      vincent   386:        for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.8       vincent   387:                if (wp->w_bufp == bp) {
1.41      kjell     388:                        wp->w_dotp = bp->b_headp;
1.8       vincent   389:                        wp->w_doto = 0;
                    390:                }
1.10      vincent   391:        }
1.8       vincent   392:
                    393:        num = 0;
1.29      kjell     394:        for (rec = LIST_FIRST(&curbp->b_undo); rec != NULL;
1.13      deraadt   395:            rec = LIST_NEXT(rec, next)) {
1.8       vincent   396:                num++;
1.25      db        397:                snprintf(buf, sizeof(buf),
1.38      kjell     398:                    "%d:\t %s at %d ", num,
1.8       vincent   399:                    (rec->type == DELETE) ? "DELETE":
                    400:                    (rec->type == INSERT) ? "INSERT":
1.40      kjell     401:                    (rec->type == BOUNDARY) ? "----" :
                    402:                    (rec->type == MODIFIED) ? "MODIFIED": "UNKNOWN",
1.8       vincent   403:                    rec->pos);
1.10      vincent   404:
1.12      vincent   405:                if (rec->content) {
1.38      kjell     406:                        (void)strlcat(buf, "\"", sizeof(buf));
1.25      db        407:                        snprintf(tmp, sizeof(tmp), "%.*s", rec->region.r_size,
1.8       vincent   408:                            rec->content);
1.38      kjell     409:                        (void)strlcat(buf, tmp, sizeof(buf));
                    410:                        (void)strlcat(buf, "\"", sizeof(buf));
1.8       vincent   411:                }
1.25      db        412:                snprintf(tmp, sizeof(tmp), " [%d]", rec->region.r_size);
1.33      kjell     413:                if (strlcat(buf, tmp, sizeof(buf)) >= sizeof(buf)) {
                    414:                        ewprintf("Undo record too large. Aborted.");
                    415:                        return (FALSE);
                    416:                }
1.17      deraadt   417:                addlinef(bp, "%s", buf);
1.8       vincent   418:        }
1.11      vincent   419:        return (TRUE);
1.1       vincent   420: }
                    421:
1.9       vincent   422: /*
1.25      db        423:  * After the user did action1, then action2, then action3:
1.9       vincent   424:  *
                    425:  *     [action3] <--- Undoptr
                    426:  *     [action2]
                    427:  *     [action1]
                    428:  *      ------
                    429:  *      [undo]
                    430:  *
                    431:  * After undo:
                    432:  *
                    433:  *     [undo of action3]
                    434:  *     [action2] <--- Undoptr
                    435:  *     [action1]
                    436:  *      ------
                    437:  *      [undo]
1.13      deraadt   438:  *
1.9       vincent   439:  * After another undo:
                    440:  *
                    441:  *
                    442:  *     [undo of action2]
                    443:  *     [undo of action3]
                    444:  *     [action1]  <--- Undoptr
                    445:  *      ------
                    446:  *      [undo]
1.13      deraadt   447:  *
1.25      db        448:  * Note that the "undo of actionX" have no special meaning. Only when
                    449:  * we undo a deletion, the insertion will be recorded just as if it
1.10      vincent   450:  * was typed on the keyboard. Resulting in the inverse operation being
1.9       vincent   451:  * saved in the list.
                    452:  *
                    453:  * If undoptr reaches the bottom of the list, or if we moved between
                    454:  * two undo actions, we make it point back at the topmost record. This is
                    455:  * how we handle redoing.
                    456:  */
1.32      kjell     457: /* ARGSUSED */
1.1       vincent   458: int
1.4       vincent   459: undo(int f, int n)
1.1       vincent   460: {
1.25      db        461:        struct undo_rec *ptr, *nptr;
1.31      deraadt   462:        int              done, rval;
1.36      kjell     463:        struct line     *lp;
1.25      db        464:        int              offset, save, dot;
1.28      kjell     465:        static int       nulled = FALSE;
1.39      kjell     466:        int              lineno;
1.23      vincent   467:
1.24      vincent   468:        dot = find_dot(curwp->w_dotp, curwp->w_doto);
1.9       vincent   469:
1.29      kjell     470:        ptr = curbp->b_undoptr;
1.9       vincent   471:
                    472:        /* if we moved, make ptr point back to the top of the list */
1.29      kjell     473:        if ((ptr == NULL && nulled == TRUE) || curbp->b_undopos != dot) {
                    474:                ptr = LIST_FIRST(&curbp->b_undo);
1.28      kjell     475:                nulled = TRUE;
                    476:        }
1.1       vincent   477:
1.9       vincent   478:        rval = TRUE;
1.10      vincent   479:        while (n--) {
1.9       vincent   480:                /* if we have a spurious boundary, free it and move on.... */
                    481:                while (ptr && ptr->type == BOUNDARY) {
                    482:                        nptr = LIST_NEXT(ptr, next);
                    483:                        LIST_REMOVE(ptr, next);
                    484:                        free_undo_record(ptr);
                    485:                        ptr = nptr;
1.4       vincent   486:                }
                    487:                /*
1.9       vincent   488:                 * Ptr is NULL, but on the next run, it will point to the
                    489:                 * top again, redoing all stuff done in the buffer since
                    490:                 * its creation.
1.4       vincent   491:                 */
1.9       vincent   492:                if (ptr == NULL) {
1.11      vincent   493:                        ewprintf("No further undo information");
1.9       vincent   494:                        rval = FALSE;
1.28      kjell     495:                        nulled = TRUE;
1.4       vincent   496:                        break;
                    497:                }
1.28      kjell     498:                nulled = FALSE;
1.6       vincent   499:
1.13      deraadt   500:                /*
1.9       vincent   501:                 * Loop while we don't get a boundary specifying we've
                    502:                 * finished the current action...
                    503:                 */
1.22      vincent   504:
1.28      kjell     505:                undo_add_boundary();
1.22      vincent   506:
1.42    ! kjell     507:                save = boundary_flag;
        !           508:                boundary_flag = FALSE;
1.22      vincent   509:
1.9       vincent   510:                done = 0;
                    511:                do {
                    512:                        /*
                    513:                         * Move to where this has to apply
                    514:                         *
1.40      kjell     515:                         * Boundaries (and the modified flag)  are put as
                    516:                         * position 0 (to save lookup time in find_dot)
                    517:                         * so we must not move there...
1.9       vincent   518:                         */
1.40      kjell     519:                        if (ptr->type != BOUNDARY && ptr->type != MODIFIED) {
1.24      vincent   520:                                if (find_lo(ptr->pos, &lp,
1.39      kjell     521:                                    &offset, &lineno) == FALSE) {
1.9       vincent   522:                                        ewprintf("Internal error in Undo!");
                    523:                                        rval = FALSE;
                    524:                                        break;
                    525:                                }
                    526:                                curwp->w_dotp = lp;
                    527:                                curwp->w_doto = offset;
1.39      kjell     528:                                curwp->w_markline = curwp->w_dotline;
                    529:                                curwp->w_dotline = lineno;
1.9       vincent   530:                        }
                    531:
                    532:                        /*
                    533:                         * Do operation^-1
                    534:                         */
                    535:                        switch (ptr->type) {
                    536:                        case INSERT:
1.34      kjell     537:                                ldelete(ptr->region.r_size, KNONE);
1.9       vincent   538:                                break;
                    539:                        case DELETE:
1.13      deraadt   540:                                region_put_data(ptr->content,
1.9       vincent   541:                                    ptr->region.r_size);
                    542:                                break;
                    543:                        case BOUNDARY:
                    544:                                done = 1;
1.40      kjell     545:                                break;
                    546:                        case MODIFIED:
                    547:                                curbp->b_flag &= ~BFCHG;
1.9       vincent   548:                                break;
                    549:                        default:
                    550:                                break;
                    551:                        }
                    552:
                    553:                        /* And move to next record */
1.22      vincent   554:                        ptr = LIST_NEXT(ptr, next);
1.9       vincent   555:                } while (ptr != NULL && !done);
1.22      vincent   556:
1.42    ! kjell     557:                boundary_flag = save;
1.22      vincent   558:                undo_add_boundary();
1.9       vincent   559:
                    560:                ewprintf("Undo!");
1.1       vincent   561:        }
1.9       vincent   562:        /*
                    563:         * Record where we are. (we have to save our new position at the end
                    564:         * since we change the dot when undoing....)
                    565:         */
1.29      kjell     566:        curbp->b_undoptr = ptr;
1.23      vincent   567:
1.29      kjell     568:        curbp->b_undopos = find_dot(curwp->w_dotp, curwp->w_doto);
1.9       vincent   569:
1.13      deraadt   570:        return (rval);
1.1       vincent   571: }