Annotation of 43BSD/contrib/emacs/src/undo.c, revision 1.1.1.1

1.1       root        1: /* Support routines for the undo facility.
                      2:    Copyright (C) 1985 Fen Labalme and Richard M. Stallman.
                      3: 
                      4: This file is part of GNU Emacs.
                      5: 
                      6: GNU Emacs is distributed in the hope that it will be useful,
                      7: but WITHOUT ANY WARRANTY.  No author or distributor
                      8: accepts responsibility to anyone for the consequences of using it
                      9: or for whether it serves any particular purpose or works at all,
                     10: unless he says so in writing.  Refer to the GNU Emacs General Public
                     11: License for full details.
                     12: 
                     13: Everyone is granted permission to copy, modify and redistribute
                     14: GNU Emacs, but only under the conditions described in the
                     15: GNU Emacs General Public License.   A copy of this license is
                     16: supposed to have been given to you along with GNU Emacs so you
                     17: can know your rights and responsibilities.  It should be in a
                     18: file named COPYING.  Among other things, the copyright notice
                     19: and this notice must be preserved on all copies.  */
                     20: 
                     21: 
                     22: #include "config.h"
                     23: #include "lisp.h"
                     24: #include "undo.h"
                     25: #include "commands.h"
                     26: #include "buffer.h"
                     27: 
                     28: /* Access undo records of current buffer */
                     29: /* These assume that `u' points to the buffer's undodata */
                     30: #define UndoRQ (u->undorecs)
                     31: #define UndoCQ (u->undochars)
                     32: #define FillRQ (u->nextrec)
                     33: #define FillCQ (u->nextchar)
                     34: 
                     35: /* Record last undo record made, and what buffer made in */
                     36: static struct UndoRec *LastUndoRec;
                     37: static struct buffer *LastUndoBuf;
                     38: 
                     39: /* Record progress of undoing */
                     40: static NUndone;
                     41: static NCharsLeft;
                     42: static LastUndoneC;
                     43: static LastUndone;
                     44: static struct buffer *LastUndoneBuf;
                     45: 
                     46: Lisp_Object Fundo_boundary ();
                     47: 
                     48: make_undo_records (b)
                     49:      struct buffer *b;
                     50: {
                     51:   register struct UndoData *u;
                     52:   b->undodata = u = (struct UndoData *) xmalloc (sizeof (struct UndoData));
                     53:   u->undorecs
                     54:     = (struct UndoRec *) xmalloc (sizeof (struct UndoRec) * InitNUndoR);
                     55:   u->undochars = (char *) xmalloc (InitNUndoC);
                     56:   u->undorecs[InitNUndoR - 1].kind = Unundoable;
                     57:   u->nextrec = 0;
                     58:   u->nextchar = 0;
                     59:   u->num_undorecs = InitNUndoR;
                     60:   u->num_undochars = InitNUndoC;
                     61: }
                     62: 
                     63: free_undo_records (b)
                     64:      struct buffer *b;
                     65: {
                     66:   register struct UndoData *u = b->undodata;
                     67:   free (u->undorecs);
                     68:   free (u->undochars);
                     69:   free (u);
                     70: }
                     71: 
                     72: struct UndoRec *
                     73: NewUndo (kind, pos, len)
                     74:      enum Ukinds kind;
                     75: {
                     76:   register struct UndoData *u = bf_cur->undodata;
                     77:   register struct UndoRec *p = &UndoRQ[FillRQ];
                     78:   register struct UndoRec *np;
                     79: 
                     80:   FillRQ++;
                     81:   if (FillRQ >= NUndoR)
                     82:     FillRQ = 0;
                     83:   else if (FillRQ >= u->num_undorecs)
                     84:     {
                     85:       np = (struct UndoRec *) xrealloc (UndoRQ, NUndoR * sizeof *p);
                     86:       if (np)
                     87:        {
                     88:          UndoRQ = np;
                     89:          p = &UndoRQ[FillRQ-1];
                     90:          u->num_undorecs = NUndoR;
                     91:          np[NUndoR - 1].kind = Unundoable;
                     92:        }
                     93:       else
                     94:        FillRQ = 0;
                     95:     }
                     96:   UndoRQ[FillRQ].kind = Unundoable;
                     97:   p -> kind = kind;
                     98:   p -> pos = pos;
                     99:   p -> len = len;
                    100:   LastUndoRec = p;
                    101:   LastUndoBuf = bf_cur;
                    102:   if (kind != Uboundary)
                    103:     LastUndone = -1;
                    104:   return p;
                    105: }
                    106: 
                    107: RecordInsert (pos, n)
                    108: {
                    109:   register struct UndoRec *p = LastUndoRec;
                    110:   if (!bf_cur->undodata)
                    111:     return;
                    112:   if (LastUndoBuf != bf_cur)
                    113:     {
                    114:       Fundo_boundary ();
                    115:       p = 0;
                    116:     }
                    117: 
                    118:   if (bf_modified <= bf_cur->save_modified)
                    119:     NewUndo (Uunmod, pos, 0);
                    120: 
                    121:   if (p && p -> kind == Udelete && p -> pos + p -> len == pos)
                    122:     p -> len += n;
                    123:   else
                    124:     NewUndo (Udelete, pos, n);
                    125: }
                    126: 
                    127: RecordDelete (pos, n)
                    128:      int pos, n;
                    129: {
                    130:   register struct UndoRec *p = LastUndoRec;
                    131: 
                    132:   if (!bf_cur->undodata)
                    133:     return;
                    134:   if (LastUndoBuf != bf_cur)
                    135:     {
                    136:       Fundo_boundary ();
                    137:       p = 0;
                    138:     }
                    139: 
                    140:   if (bf_modified <= bf_cur->save_modified)
                    141:     NewUndo (Uunmod, pos, 0);
                    142: 
                    143:   if (p && p->kind == Uinsert && p->pos == pos)
                    144:     p->len += n;
                    145:   else
                    146:     NewUndo (Uinsert, pos, n);
                    147: 
                    148:   record_chars (pos, n);
                    149: }
                    150: 
                    151: record_chars (pos, n)
                    152:      register int pos, n;
                    153: {
                    154:   if (pos < bf_s1 + 1 && pos + n > bf_s1 + 1)
                    155:     {
                    156:       record_block (&CharAt (pos), bf_s1 + 1 - pos);
                    157:       n -= bf_s1 + 1 - pos;
                    158:       pos = bf_s1 + 1;
                    159:     }
                    160: 
                    161:   record_block (&CharAt (pos), n);
                    162: }
                    163: 
                    164: record_block (p, n)
                    165:      register char *p;
                    166:      register int n;
                    167: {
                    168:   register char *cp;
                    169:   register struct UndoData *u = bf_cur->undodata;
                    170:   register int i;
                    171: 
                    172:   NCharsLeft -= n;
                    173:   cp = &UndoCQ[FillCQ];
                    174: 
                    175:   while (n > 0)
                    176:     {
                    177:       i = u->num_undochars - FillCQ;
                    178:       if (i > n) i = n;
                    179:       if (i > 0)
                    180:        {
                    181:          bcopy (p, cp, i);
                    182:          p += i;
                    183:          cp += i;
                    184:          FillCQ += i;
                    185:          n -= i;
                    186:        }
                    187: 
                    188:       if (FillCQ >= NUndoC)
                    189:        {
                    190:          FillCQ = 0;
                    191:          cp = UndoCQ;
                    192:        }
                    193:       else
                    194:        {
                    195:          cp = (char *) xrealloc (UndoCQ, NUndoC);
                    196:          UndoCQ = cp;
                    197:          cp += FillCQ;
                    198:          NCharsLeft += NUndoC - u->num_undochars;
                    199:          u->num_undochars = NUndoC;
                    200:        }
                    201:     }
                    202: }
                    203: 
                    204: RecordChange (pos, n)
                    205:      int pos, n;
                    206: {
                    207:   register struct UndoRec *p = LastUndoRec;
                    208:   if (!bf_cur->undodata)
                    209:     return;
                    210:   if (LastUndoBuf != bf_cur)
                    211:     {
                    212:       Fundo_boundary ();
                    213:       p = 0;
                    214:     }
                    215: 
                    216:   if (bf_modified <= bf_cur->save_modified)
                    217:     NewUndo (Uunmod, pos, 0);
                    218: 
                    219:   if (p && p -> kind == Uchange && p -> pos + p -> len == pos)
                    220:     p -> len += n;
                    221:   else
                    222:     NewUndo (Uchange, pos, n);
                    223: 
                    224:   record_chars (pos, n);
                    225: }
                    226: 
                    227: RecordChange1 (pos, bufp, n)
                    228:      int pos;
                    229:      char *bufp;
                    230:      int n;
                    231: {
                    232:   register struct UndoRec *p = LastUndoRec;
                    233:   if (!bf_cur->undodata)
                    234:     return;
                    235:   if (LastUndoBuf != bf_cur)
                    236:     {
                    237:       Fundo_boundary ();
                    238:       p = 0;
                    239:     }
                    240:   if (p && p -> kind == Uchange && p -> pos + p -> len == pos)
                    241:     p -> len += n;
                    242:   else
                    243:     NewUndo (Uchange, pos, n);
                    244: 
                    245:   record_block (bufp, n);
                    246: }
                    247: 
                    248: DoneIsDone ()
                    249: {
                    250:   register struct UndoData *u = bf_cur->undodata;
                    251:   register struct UndoRec *p;
                    252: 
                    253:   if (!u)
                    254:     return 0;
                    255: 
                    256:   p = &UndoRQ[(FillRQ + u->num_undorecs - 1) % u->num_undorecs];
                    257:   if (p->kind != Unundoable)
                    258:     NewUndo (Unundoable, point, 0);
                    259:   return 0;
                    260: }
                    261: 
                    262: DEFUN ("undo-boundary", Fundo_boundary, Sundo_boundary, 0, 0, 0,
                    263:   "Mark a boundary between units of undo.\n\
                    264: An undo command will stop at this point,\n\
                    265: but another undo command will undo to the previous boundary.")
                    266:   ()
                    267: {
                    268:   register struct UndoData *u = bf_cur->undodata;
                    269:   register struct UndoRec *p;
                    270: 
                    271:   if (!u)
                    272:     return Qnil;
                    273: 
                    274:   p = &UndoRQ[(FillRQ + u->num_undorecs - 1) % u->num_undorecs];
                    275:   if (p->kind != Uboundary)
                    276:     NewUndo (Uboundary, point, 0);
                    277:   return Qnil;
                    278: }
                    279: 
                    280: DEFUN ("undo-more", Fundo_more, Sundo_more, 1, 1, 0,
                    281:   "Undo back N undo-boundaries beyond what was already undone recently.\n\
                    282: Call undo-start to get ready to undo recent changes,\n\
                    283: then call undo-more one or more times to undo them.")
                    284:   (pfxarg)
                    285:      Lisp_Object pfxarg;
                    286: {
                    287:   register struct UndoData *u = bf_cur->undodata;
                    288:   register int n = 0;
                    289:   register int chars;
                    290:   register int i = LastUndone;
                    291:   register int arg = XINT (pfxarg);
                    292:   register int len, pos;
                    293:   char tembuf[NUndoC];
                    294: 
                    295:   if (!u)
                    296:     return Qnil;
                    297: 
                    298:   if (LastUndoneBuf != bf_cur ||
                    299:       i == -1)
                    300:     error ("Cannot undo more: changes have been made since the last undo");
                    301: 
                    302:   while (1)
                    303:     {
                    304:       while (UndoRQ[i = (!i ? u->num_undorecs-1 : i-1)].kind != Uboundary)
                    305:        {
                    306:          if (((UndoRQ[i].kind == Uinsert || UndoRQ[i].kind == Uchange)
                    307:               && (NCharsLeft -= UndoRQ[i].len) < 0)
                    308:              || UndoRQ[i].kind == Unundoable || NUndone >= u->num_undorecs)
                    309:            error ("No further undo information available");
                    310:          NUndone++;
                    311:          n++;
                    312:        }
                    313:       NUndone++;
                    314:       n++;
                    315:       if (--arg <= 0)
                    316:        break;
                    317:     }
                    318: 
                    319:   i = LastUndone;
                    320:   chars = LastUndoneC;
                    321:   while (--n >= 0)
                    322:     {
                    323:       if (!i)
                    324:        i = u->num_undorecs;
                    325:       i--;
                    326: 
                    327:       len = UndoRQ[i].len;
                    328:       pos = UndoRQ[i].pos;
                    329: #ifdef SWITCH_ENUM_BUG
                    330:       switch ((int) UndoRQ[i].kind)
                    331: #else
                    332:       switch (UndoRQ[i].kind)
                    333: #endif
                    334:        {
                    335:        case Uboundary: 
                    336:          break;
                    337: 
                    338:        case Udelete: 
                    339:          if (pos < FirstCharacter
                    340:              || pos + len > NumCharacters + 1)
                    341:            error ("Changes to be undone are outside visible portion of buffer");
                    342:          SetPoint (pos);
                    343:          del_range (point, point + len);
                    344:          break;
                    345: 
                    346:        case Uchange:
                    347:          if (pos < FirstCharacter
                    348:              || pos + len > NumCharacters + 1)
                    349:            error ("Changes to be undone are outside visible portion of buffer");
                    350:          SetPoint (pos);
                    351:          if (len > NUndoC)
                    352:            /* Should have already said "No more undo info available" */
                    353:            abort ();
                    354:          save_undone_chars (pos, len, tembuf);
                    355:          chars -= len;
                    356:          if (chars < 0)
                    357:            {
                    358:              replace_chars (point - chars, len + chars, UndoCQ);
                    359:              replace_chars (point, - chars, UndoCQ + chars + u->num_undochars);
                    360:              chars += u->num_undochars;
                    361:            }
                    362:          else
                    363:            replace_chars (point, len, UndoCQ + chars);
                    364:          RecordChange1 (point, tembuf, len);
                    365:          break;
                    366: 
                    367:        case Uinsert:
                    368:          if (pos < FirstCharacter
                    369:              || pos > NumCharacters + 1)
                    370:            error ("Changes to be undone are outside visible portion of buffer");
                    371:          SetPoint (pos);
                    372:          chars -= len;
                    373:          if (chars < 0)
                    374:            {
                    375:              InsCStr (UndoCQ + chars + u->num_undochars, - chars);
                    376:              InsCStr (UndoCQ, len + chars);
                    377:              chars += u->num_undochars;
                    378:            }
                    379:          else
                    380:            InsCStr (UndoCQ + chars, len);
                    381:          SetPoint (pos);
                    382:          break;
                    383: 
                    384:        case Uunmod:
                    385: #ifdef CLASH_DETECTION
                    386:          Funlock_buffer ();
                    387: #endif /* CLASH_DETECTION */
                    388:          bf_cur->save_modified = bf_modified;
                    389:          RedoModes++;
                    390:          break;
                    391: 
                    392:        default: 
                    393:          error ("Something rotten in undo");
                    394:          return Qnil;
                    395:        }
                    396:     }
                    397:   LastUndone = i;
                    398:   LastUndoneC = chars;
                    399:   return Qnil;
                    400: }
                    401: 
                    402: replace_chars (pos, n, string)
                    403:      register int pos, n;
                    404:      register unsigned char *string;
                    405: {
                    406:   modify_region (pos, pos + n);
                    407:   while (--n >= 0)
                    408:     {
                    409:       CharAt (pos) = *string++;
                    410:       pos++;
                    411:     }
                    412: }
                    413: 
                    414: save_undone_chars (pos, n, p)
                    415:      register int pos, n;
                    416:      register char *p;
                    417: {
                    418:   if (pos < bf_s1 + 1 && pos + n > bf_s1 + 1)
                    419:     {
                    420:       bcopy (&CharAt (pos), p, bf_s1 + 1 - pos);
                    421:       p += bf_s1 + 1 - pos;
                    422:       n -= bf_s1 + 1 - pos;
                    423:       pos = bf_s1 + 1;
                    424:     }
                    425: 
                    426:   bcopy (&CharAt (pos), p, n);
                    427: }
                    428: 
                    429: DEFUN ("undo-start", Fundo_start, Sundo_start, 0, 0, 0,
                    430:   "Move undo-pointer to front of undo records.\n\
                    431: The next call to undo-more will undo the most recently made change.")
                    432:   ()
                    433: {
                    434:   register struct UndoData *u = bf_cur->undodata;
                    435: 
                    436:   if (!u)
                    437:     error ("Undo information not kept for this buffer");
                    438:   LastUndoneBuf = bf_cur;
                    439:   NCharsLeft = u->num_undochars;
                    440:   NUndone = 0;
                    441:   LastUndone = FillRQ;
                    442:   LastUndoneC = FillCQ;
                    443:   return Qnil;
                    444: }
                    445: 
                    446: syms_of_undo ()
                    447: {
                    448:   defsubr (&Sundo_start);
                    449:   defsubr (&Sundo_boundary);
                    450:   defsubr (&Sundo_more);
                    451: }

unix.superglobalmegacorp.com

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