Annotation of 43BSD/contrib/emacs/src/undo.c, revision 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.