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

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