This is undo.c in view mode; [Download] [Up]
/* * Copyright (c) 1992, 1995 John E. Davis (davis@space.mit.edu) * All Rights Reserved. */ #include <config.h> #include <stdio.h> #include "buffer.h" #include "undo.h" #include "ins.h" #include "line.h" #include "misc.h" #define LAST_UNDO CBuf->undo->Last_Undo #define FIRST_UNDO CBuf->undo->First_Undo #define UNDO_RING CBuf->undo->Undo_Ring #ifdef UNDO_HAS_REDO # define CURRENT_UNDO CBuf->undo->Current_Undo #endif static int Undo_In_Progress = 0; int Undo_Buf_Unch_Flag; /* 1 if buffer prev not modified */ #ifdef UNDO_HAS_REDO #define DONT_RECORD_UNDO (!(CBuf->flags & UNDO_ENABLED)\ || (CBuf->undo == NULL)) #else #define DONT_RECORD_UNDO (!(CBuf->flags & UNDO_ENABLED)\ || (CBuf->undo == NULL) || Undo_In_Progress) #endif #define UNDO_BD_FLAG 0x8000 #define UNDO_UNCHANGED_FLAG 0x4000 #ifdef UNDO_HAS_REDO # define IS_UNDO_BD (CURRENT_UNDO->type & UNDO_BD_FLAG) #else # define IS_UNDO_BD (LAST_UNDO->type & UNDO_BD_FLAG) #endif static void prepare_next_undo(void) { LAST_UNDO++; if (LAST_UNDO >= UNDO_RING + MAX_UNDOS) LAST_UNDO = UNDO_RING; if (LAST_UNDO == FIRST_UNDO) { FIRST_UNDO++; #ifdef UNDO_HAS_REDO if (FIRST_UNDO >= UNDO_RING + MAX_UNDOS) FIRST_UNDO = UNDO_RING; #endif } #ifdef UNDO_HAS_REDO if (LAST_UNDO == CURRENT_UNDO) /* undo-ring overflow will trash */ CURRENT_UNDO = NULL; /* further undos */ #else if (FIRST_UNDO >= UNDO_RING + MAX_UNDOS) FIRST_UNDO = UNDO_RING; #endif LAST_UNDO->type = 0; LAST_UNDO->misc = 0; } #ifdef UNDO_HAS_REDO /* Returns True if there is still undo info to be processed. */ #define MORE_UNDO_INFO (CURRENT_UNDO && (CURRENT_UNDO->type)) #endif void record_deletion(unsigned char *p, int n) { int misc; unsigned char *pb; if (DONT_RECORD_UNDO || !n) return; if (((LAST_UNDO->type && 0xFF) == 0) || ((LAST_UNDO->type & CDELETE) && (LAST_UNDO->linenum == LineNum + CBuf->nup) && (LAST_UNDO->point == Point))) { if (LAST_UNDO->type != 0) misc = LAST_UNDO->misc; else misc = 0; pb = LAST_UNDO->buf + misc; while ((misc < 8) && n) { *pb++ = *p++; misc++; n--; } LAST_UNDO->misc = misc; LAST_UNDO->type |= CDELETE; LAST_UNDO->linenum = LineNum + CBuf->nup; LAST_UNDO->point = Point; if (Undo_Buf_Unch_Flag) LAST_UNDO->type |= UNDO_UNCHANGED_FLAG; Undo_Buf_Unch_Flag = 0; } if (n) { prepare_next_undo(); record_deletion(p, n); } if (Undo_Buf_Unch_Flag) LAST_UNDO->type |= UNDO_UNCHANGED_FLAG; #ifdef UNDO_HAS_REDO set_current_undo (); #endif } int undo (void) { int line; CHECK_READ_ONLY if (!(CBuf->flags & UNDO_ENABLED)) { msg_error("Undo not enabled for this buffer."); return(0); } else if ((CBuf->undo == NULL) #ifdef UNDO_HAS_REDO || (0 == MORE_UNDO_INFO) #else || (LAST_UNDO->type == 0) #endif ) { msg_error("No more undo information."); return(0); } Undo_In_Progress = 1; do { #ifdef UNDO_HAS_REDO line = (int) CURRENT_UNDO->linenum; #else line = (int) LAST_UNDO->linenum; #endif if ((line <= CBuf->nup) || (line > CBuf->nup + Max_LineNum)) { msg_error("Next undo lies outside visible buffer."); break; } line -= CBuf->nup; goto_line(&line); #ifdef UNDO_HAS_REDO Point = CURRENT_UNDO->point; #else Point = LAST_UNDO->point; #endif #ifdef UNDO_HAS_REDO switch (CURRENT_UNDO->type & 0xFF) #else switch (LAST_UNDO->type & 0xFF) #endif { #ifdef UNDO_HAS_REDO case CDELETE: ins_chars(CURRENT_UNDO->buf, CURRENT_UNDO->misc); /* Point = CURRENT_UNDO->point; */ #else case CDELETE: ins_chars(LAST_UNDO->buf, LAST_UNDO->misc); /* Point = LAST_UNDO->point; */ #endif break; #ifdef UNDO_HAS_REDO case CINSERT: deln(&CURRENT_UNDO->misc); #else case CINSERT: deln(&LAST_UNDO->misc); #endif break; case NLINSERT: del(); break; default: return(1); } #ifdef UNDO_HAS_REDO if (CURRENT_UNDO == NULL) break; /* no more undo info after overflow */ /* above calls to ins_chars/deln/del may overflow the undo-ring */ if (CURRENT_UNDO->type & UNDO_UNCHANGED_FLAG) { mark_buffer_modified(&Number_Zero); } if (CURRENT_UNDO == FIRST_UNDO) { CURRENT_UNDO = NULL ; break ; /* no more undo info */ } CURRENT_UNDO--; if (CURRENT_UNDO < UNDO_RING) CURRENT_UNDO = UNDO_RING + MAX_UNDOS - 1; #else if (LAST_UNDO->type & UNDO_UNCHANGED_FLAG) { mark_buffer_modified(&Number_Zero); } if (LAST_UNDO == FIRST_UNDO) LAST_UNDO->type = 0; else { LAST_UNDO--; if (LAST_UNDO < UNDO_RING) LAST_UNDO = UNDO_RING + MAX_UNDOS - 1; } #endif } #ifdef UNDO_HAS_REDO while ((!IS_UNDO_BD) && (CURRENT_UNDO->type)); #else while ((!IS_UNDO_BD) && (LAST_UNDO->type)); #endif message("Undo!"); Undo_In_Progress = 0; return(1); } void record_insertion(int n) { if (DONT_RECORD_UNDO || !n) return; if (LAST_UNDO->type == 0) { LAST_UNDO->misc = n; LAST_UNDO->point = Point; } else if ((LAST_UNDO->type & CINSERT) && (LAST_UNDO->linenum == LineNum + CBuf->nup) && (LAST_UNDO->point + LAST_UNDO->misc == Point) && (LAST_UNDO->misc <= 32)) { LAST_UNDO->misc += n; } else { prepare_next_undo(); LAST_UNDO->point = Point; LAST_UNDO->misc = n; } LAST_UNDO->type |= CINSERT; if (Undo_Buf_Unch_Flag) LAST_UNDO->type |= UNDO_UNCHANGED_FLAG; LAST_UNDO->linenum = LineNum + CBuf->nup; #ifdef UNDO_HAS_REDO set_current_undo (); #endif } void record_newline_insertion() { if (DONT_RECORD_UNDO) return; if (LAST_UNDO->type != 0) prepare_next_undo(); if (Undo_Buf_Unch_Flag) LAST_UNDO->type |= UNDO_UNCHANGED_FLAG; LAST_UNDO->point = Point; LAST_UNDO->misc = 0; LAST_UNDO->type |= NLINSERT; LAST_UNDO->linenum = LineNum + CBuf->nup; #ifdef UNDO_HAS_REDO set_current_undo (); #endif } void delete_undo_ring(Buffer *b) { SLFREE (b->undo); /* assume non null-- called by delete buffer */ } void create_undo_ring() { Undo_Type *ur; Undo_Object_Type *uo; int n; if (NULL == (ur = (Undo_Type *) SLMALLOC(sizeof(Undo_Type)))) { msg_error("Unable to malloc space for undo!"); return; } CBuf->undo = ur; uo = ur->Undo_Ring; ur->Last_Undo = ur->First_Undo = uo; #ifdef UNDO_HAS_REDO ur->Current_Undo = NULL; #endif n = MAX_UNDOS; while (n--) { uo->type = 0; uo++; } } void mark_undo_boundary(Buffer *b) { Buffer *s = CBuf; CBuf = b; if (!DONT_RECORD_UNDO && (LAST_UNDO->type != 0)) { LAST_UNDO->type |= UNDO_BD_FLAG; } CBuf = s; } #ifdef UNDO_HAS_REDO void set_current_undo() /* Called when text is inserted, deleted, */ { /* or the abort key is pressed. */ if ((!Undo_In_Progress) && CBuf->undo) { CURRENT_UNDO = LAST_UNDO ; } } void update_undo_unchanged() /* Update unchange flags after a buffer save */ { Undo_Object_Type *uo; int n; if (DONT_RECORD_UNDO) return; uo = UNDO_RING ; n = MAX_UNDOS; while (n--) { uo->type &= ~UNDO_UNCHANGED_FLAG; uo++; } CURRENT_UNDO = LAST_UNDO ; } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.