Annotation of 43BSDReno/contrib/emacs-18.55/src/undo.c, revision 1.1.1.1

1.1       root        1: /* Support routines for the undo facility.
                      2:    Copyright (C) 1985, 1986 Free Software Foundation, Inc.
                      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 int NUndone;
                     41: static int NCharsLeft;
                     42: static int LastUndoneC;
                     43: static int 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: record_undo (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: record_insert (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:     record_undo (Uunmod, pos, bf_cur->modtime);
                    120: 
                    121:   if (p && p -> kind == Udelete && p -> pos + p -> len == pos)
                    122:     p -> len += n;
                    123:   else
                    124:     record_undo (Udelete, pos, n);
                    125: }
                    126: 
                    127: record_delete (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:     record_undo (Uunmod, pos, bf_cur->modtime);
                    142: 
                    143:   if (p && p->kind == Uinsert && p->pos == pos && p->len > 0)
                    144:     p->len += n;
                    145:   else if (point == pos + n)
                    146:     record_undo (Uinsert, pos + n, - n);
                    147:   else
                    148:     record_undo (Uinsert, pos, n);
                    149: 
                    150:   record_chars (pos, n);
                    151: }
                    152: 
                    153: record_chars (pos, n)
                    154:      register int pos, n;
                    155: {
                    156:   if (pos < bf_s1 + 1 && pos + n > bf_s1 + 1)
                    157:     {
                    158:       record_block (&CharAt (pos), bf_s1 + 1 - pos);
                    159:       n -= bf_s1 + 1 - pos;
                    160:       pos = bf_s1 + 1;
                    161:     }
                    162: 
                    163:   record_block (&CharAt (pos), n);
                    164: }
                    165: 
                    166: record_block (p, n)
                    167:      register char *p;
                    168:      register int n;
                    169: {
                    170:   register char *cp;
                    171:   register struct UndoData *u = bf_cur->undodata;
                    172:   register int i;
                    173: 
                    174:   NCharsLeft -= n;
                    175:   cp = &UndoCQ[FillCQ];
                    176: 
                    177:   while (n > 0)
                    178:     {
                    179:       i = u->num_undochars - FillCQ;
                    180:       if (i > n) i = n;
                    181:       if (i > 0)
                    182:        {
                    183:          bcopy (p, cp, i);
                    184:          p += i;
                    185:          FillCQ += i;
                    186:          n -= i;
                    187:        }
                    188: 
                    189:       if (n == 0)
                    190:        break;
                    191: 
                    192:       if (FillCQ >= NUndoC)
                    193:        {
                    194:          FillCQ = 0;
                    195:          cp = UndoCQ;
                    196:        }
                    197:       else
                    198:        {
                    199:          cp = (char *) xrealloc (UndoCQ, NUndoC);
                    200:          UndoCQ = cp;
                    201:          cp += FillCQ;
                    202:          NCharsLeft += NUndoC - u->num_undochars;
                    203:          u->num_undochars = NUndoC;
                    204:        }
                    205:     }
                    206: }
                    207: 
                    208: record_change (pos, n)
                    209:      int pos, n;
                    210: {
                    211:   register struct UndoRec *p = LastUndoRec;
                    212:   if (!bf_cur->undodata)
                    213:     return;
                    214:   if (LastUndoBuf != bf_cur)
                    215:     {
                    216:       Fundo_boundary ();
                    217:       p = 0;
                    218:     }
                    219: 
                    220:   if (bf_modified <= bf_cur->save_modified)
                    221:     record_undo (Uunmod, pos, bf_cur->modtime);
                    222: 
                    223:   if (p && p->kind == Uchange && p->len > 0 && p->pos + p->len == pos)
                    224:     p->len += n;
                    225:   else if (point == pos + n)
                    226:     record_undo (Uchange, pos + n, -n);
                    227:   else
                    228:     record_undo (Uchange, pos, n);
                    229: 
                    230:   record_chars (pos, n);
                    231: }
                    232: 
                    233: record_change1 (pos, bufp, n)
                    234:      int pos;
                    235:      char *bufp;
                    236:      int n;
                    237: {
                    238:   register struct UndoRec *p = LastUndoRec;
                    239:   if (!bf_cur->undodata)
                    240:     return;
                    241:   if (LastUndoBuf != bf_cur)
                    242:     {
                    243:       Fundo_boundary ();
                    244:       p = 0;
                    245:     }
                    246:   if (p && p->kind == Uchange && p->len > 0 && p->pos + p->len == pos)
                    247:     p -> len += n;
                    248:   else
                    249:     record_undo (Uchange, pos, n);
                    250: 
                    251:   record_block (bufp, n);
                    252: }
                    253: 
                    254: DoneIsDone ()
                    255: {
                    256:   register struct UndoData *u = bf_cur->undodata;
                    257:   register struct UndoRec *p;
                    258: 
                    259:   if (!u)
                    260:     return 0;
                    261: 
                    262:   p = &UndoRQ[(FillRQ + u->num_undorecs - 1) % u->num_undorecs];
                    263:   if (p->kind != Unundoable)
                    264:     record_undo (Unundoable, point, 0);
                    265:   return 0;
                    266: }
                    267: 
                    268: DEFUN ("undo-boundary", Fundo_boundary, Sundo_boundary, 0, 0, 0,
                    269:   "Mark a boundary between units of undo.\n\
                    270: An undo command will stop at this point,\n\
                    271: but another undo command will undo to the previous boundary.")
                    272:   ()
                    273: {
                    274:   register struct UndoData *u = bf_cur->undodata;
                    275:   register struct UndoRec *p;
                    276: 
                    277:   if (!u)
                    278:     return Qnil;
                    279: 
                    280:   p = &UndoRQ[(FillRQ + u->num_undorecs - 1) % u->num_undorecs];
                    281:   if (p->kind != Uboundary)
                    282:     record_undo (Uboundary, point, 0);
                    283:   return Qnil;
                    284: }
                    285: 
                    286: DEFUN ("undo-more", Fundo_more, Sundo_more, 1, 1, 0,
                    287:   "Undo back N undo-boundaries beyond what was already undone recently.\n\
                    288: Call undo-start to get ready to undo recent changes,\n\
                    289: then call undo-more one or more times to undo them.")
                    290:   (pfxarg)
                    291:      Lisp_Object pfxarg;
                    292: {
                    293:   register struct UndoData *u = bf_cur->undodata;
                    294:   register int n = 0;
                    295:   register int chars;
                    296:   register int i = LastUndone;
                    297:   register int arg = XINT (pfxarg);
                    298:   register int len, pos;
                    299:   char tembuf[NUndoC];
                    300: 
                    301:   if (!u)
                    302:     return Qnil;
                    303: 
                    304:   if (LastUndoneBuf != bf_cur ||
                    305:       i == -1)
                    306:     error ("Cannot undo more: changes have been made since the last undo");
                    307: 
                    308:   while (1)
                    309:     {
                    310:       while (UndoRQ[i = (!i ? u->num_undorecs-1 : i-1)].kind != Uboundary)
                    311:        {
                    312:          len = UndoRQ[i].len;
                    313:          if (len < 0) len = - len;
                    314:          if (((UndoRQ[i].kind == Uinsert || UndoRQ[i].kind == Uchange)
                    315:               && (NCharsLeft -= len) < 0)
                    316:              || UndoRQ[i].kind == Unundoable || NUndone >= u->num_undorecs)
                    317:            error ("No further undo information available");
                    318:          NUndone++;
                    319:          n++;
                    320:        }
                    321:       NUndone++;
                    322:       n++;
                    323:       if (--arg <= 0)
                    324:        break;
                    325:     }
                    326: 
                    327:   i = LastUndone;
                    328:   chars = LastUndoneC;
                    329:   while (--n >= 0)
                    330:     {
                    331:       if (!i)
                    332:        i = u->num_undorecs;
                    333:       i--;
                    334: 
                    335:       len = UndoRQ[i].len;
                    336:       pos = UndoRQ[i].pos;
                    337: 
                    338:       if (UndoRQ[i].kind == Uchange || UndoRQ[i].kind == Uinsert)
                    339:        if (len < 0)
                    340:          {
                    341:            pos += len;
                    342:            len = - len;
                    343:          }
                    344: 
                    345: #ifdef SWITCH_ENUM_BUG
                    346:       switch ((int) UndoRQ[i].kind)
                    347: #else
                    348:       switch (UndoRQ[i].kind)
                    349: #endif
                    350:        {
                    351:        case Uchange:
                    352:        case Udelete:
                    353:          if (pos < FirstCharacter || pos + len > NumCharacters + 1)
                    354:            error ("Changes to be undone are outside visible portion of buffer");
                    355:          SetPoint (pos);
                    356:          break;
                    357: 
                    358:        case Uinsert:
                    359:          if (pos < FirstCharacter || pos > NumCharacters + 1)
                    360:            error ("Changes to be undone are outside visible portion of buffer");
                    361:          SetPoint (pos);
                    362:        }
                    363: 
                    364: #ifdef SWITCH_ENUM_BUG
                    365:       switch ((int) UndoRQ[i].kind)
                    366: #else
                    367:       switch (UndoRQ[i].kind)
                    368: #endif
                    369:        {
                    370:        case Uboundary: 
                    371:          break;
                    372: 
                    373:        case Udelete: 
                    374:          del_range (point, point + len);
                    375:          break;
                    376: 
                    377:        case Uchange:
                    378:          if (len > NUndoC)
                    379:            /* Should have already said "No more undo info available" */
                    380:            abort ();
                    381:          save_undone_chars (pos, len, tembuf);
                    382:          chars -= len;
                    383:          if (chars < 0)
                    384:            {
                    385:              replace_chars (point - chars, len + chars, UndoCQ);
                    386:              replace_chars (point, - chars, UndoCQ + chars + u->num_undochars);
                    387:              chars += u->num_undochars;
                    388:            }
                    389:          else
                    390:            replace_chars (point, len, UndoCQ + chars);
                    391:          record_change1 (point, tembuf, len);
                    392:          SetPoint (UndoRQ[i].pos);
                    393:          break;
                    394: 
                    395:        case Uinsert:
                    396:          chars -= len;
                    397:          if (chars < 0)
                    398:            {
                    399:              InsCStr (UndoCQ + chars + u->num_undochars, - chars);
                    400:              InsCStr (UndoCQ, len + chars);
                    401:              chars += u->num_undochars;
                    402:            }
                    403:          else
                    404:            InsCStr (UndoCQ + chars, len);
                    405:          SetPoint (UndoRQ[i].pos);
                    406:          break;
                    407: 
                    408:        case Uunmod:
                    409:          /* If this Uunmod records an obsolete save
                    410:             (not matching the actual disk file)
                    411:             then don't mark unmodified.  */
                    412:          if (len != bf_cur->modtime)
                    413:            break;
                    414: #ifdef CLASH_DETECTION
                    415:          Funlock_buffer ();
                    416: #endif /* CLASH_DETECTION */
                    417:          bf_cur->save_modified = bf_modified;
                    418:          RedoModes++;
                    419:          break;
                    420: 
                    421:        default: 
                    422:          error ("Changes to great to be undone");
                    423:          return Qnil;
                    424:        }
                    425:     }
                    426:   LastUndone = i;
                    427:   LastUndoneC = chars;
                    428:   return Qnil;
                    429: }
                    430: 
                    431: replace_chars (pos, n, string)
                    432:      register int pos, n;
                    433:      register unsigned char *string;
                    434: {
                    435:   modify_region (pos, pos + n);
                    436:   while (--n >= 0)
                    437:     {
                    438:       CharAt (pos) = *string++;
                    439:       pos++;
                    440:     }
                    441: }
                    442: 
                    443: save_undone_chars (pos, n, p)
                    444:      register int pos, n;
                    445:      register char *p;
                    446: {
                    447:   if (pos < bf_s1 + 1 && pos + n > bf_s1 + 1)
                    448:     {
                    449:       bcopy (&CharAt (pos), p, bf_s1 + 1 - pos);
                    450:       p += bf_s1 + 1 - pos;
                    451:       n -= bf_s1 + 1 - pos;
                    452:       pos = bf_s1 + 1;
                    453:     }
                    454: 
                    455:   bcopy (&CharAt (pos), p, n);
                    456: }
                    457: 
                    458: DEFUN ("undo-start", Fundo_start, Sundo_start, 0, 0, 0,
                    459:   "Move undo-pointer to front of undo records.\n\
                    460: The next call to undo-more will undo the most recently made change.")
                    461:   ()
                    462: {
                    463:   register struct UndoData *u = bf_cur->undodata;
                    464: 
                    465:   if (!u)
                    466:     error ("Undo information not kept for this buffer");
                    467:   LastUndoneBuf = bf_cur;
                    468:   NCharsLeft = u->num_undochars;
                    469:   NUndone = 0;
                    470:   LastUndone = FillRQ;
                    471:   LastUndoneC = FillCQ;
                    472:   return Qnil;
                    473: }
                    474: 
                    475: syms_of_undo ()
                    476: {
                    477:   defsubr (&Sundo_start);
                    478:   defsubr (&Sundo_boundary);
                    479:   defsubr (&Sundo_more);
                    480: }

unix.superglobalmegacorp.com

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