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: }

Defined functions

DEFUN defined in line 429; never used
DoneIsDone defined in line 248; used 1 times
NewUndo defined in line 72; used 9 times
RecordChange1 defined in line 227; used 1 times
RecordDelete defined in line 127; used 1 times
free_undo_records defined in line 63; used 2 times
make_undo_records defined in line 48; used 2 times
record_block defined in line 164; used 3 times
record_chars defined in line 151; used 2 times
replace_chars defined in line 402; used 3 times
save_undone_chars defined in line 414; used 1 times
syms_of_undo defined in line 446; used 1 times

Defined variables

LastUndoBuf defined in line 37; used 5 times
LastUndoRec defined in line 36; used 5 times
LastUndoneBuf defined in line 44; used 2 times

Defined macros

FillCQ defined in line 33; used 7 times
FillRQ defined in line 32; used 11 times
UndoCQ defined in line 31; used 10 times
UndoRQ defined in line 30; used 16 times
Last modified: 1985-11-23
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1284
Valid CSS Valid XHTML 1.0 Strict