1 /* $OpenBSD: undo.c,v 1.14 2016/03/22 17:58:28 mmcc Exp $ */ 2 /* $NetBSD: undo.c,v 1.2 1995/03/21 09:04:52 cgd Exp $ */ 3 4 /* undo.c: This file contains the undo routines for the ed line editor */ 5 /*- 6 * Copyright (c) 1993 Andrew Moore, Talke Studio. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <regex.h> 32 #include <signal.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 36 #include "ed.h" 37 38 #define USIZE 100 /* undo stack size */ 39 static undo_t *ustack = NULL; /* undo stack */ 40 static int usize = 0; /* stack size variable */ 41 static int u_p = 0; /* undo stack pointer */ 42 43 /* push_undo_stack: return pointer to initialized undo node */ 44 undo_t * 45 push_undo_stack(int type, int from, int to) 46 { 47 undo_t *t; 48 49 t = ustack; 50 if (u_p < usize || 51 (t = reallocarray(ustack, (usize += USIZE), sizeof(undo_t))) != NULL) { 52 ustack = t; 53 ustack[u_p].type = type; 54 ustack[u_p].t = get_addressed_line_node(to); 55 ustack[u_p].h = get_addressed_line_node(from); 56 return ustack + u_p++; 57 } 58 /* out of memory - release undo stack */ 59 perror(NULL); 60 seterrmsg("out of memory"); 61 clear_undo_stack(); 62 free(ustack); 63 ustack = NULL; 64 usize = 0; 65 return NULL; 66 } 67 68 69 /* USWAP: swap undo nodes */ 70 #define USWAP(x,y) { \ 71 undo_t utmp; \ 72 utmp = x, x = y, y = utmp; \ 73 } 74 75 76 int u_current_addr = -1; /* if >= 0, undo enabled */ 77 int u_addr_last = -1; /* if >= 0, undo enabled */ 78 79 /* pop_undo_stack: undo last change to the editor buffer */ 80 int 81 pop_undo_stack(void) 82 { 83 int n; 84 int o_current_addr = current_addr; 85 int o_addr_last = addr_last; 86 87 if (u_current_addr == -1 || u_addr_last == -1) { 88 seterrmsg("nothing to undo"); 89 return ERR; 90 } else if (u_p) 91 modified = 1; 92 get_addressed_line_node(0); /* this get_addressed_line_node last! */ 93 SPL1(); 94 for (n = u_p; n-- > 0;) { 95 switch(ustack[n].type) { 96 case UADD: 97 REQUE(ustack[n].h->q_back, ustack[n].t->q_forw); 98 break; 99 case UDEL: 100 REQUE(ustack[n].h->q_back, ustack[n].h); 101 REQUE(ustack[n].t, ustack[n].t->q_forw); 102 break; 103 case UMOV: 104 case VMOV: 105 REQUE(ustack[n - 1].h, ustack[n].h->q_forw); 106 REQUE(ustack[n].t->q_back, ustack[n - 1].t); 107 REQUE(ustack[n].h, ustack[n].t); 108 n--; 109 break; 110 default: 111 /*NOTREACHED*/ 112 ; 113 } 114 ustack[n].type ^= 1; 115 } 116 /* reverse undo stack order */ 117 for (n = u_p; n-- > (u_p + 1)/ 2;) 118 USWAP(ustack[n], ustack[u_p - 1 - n]); 119 if (isglobal) 120 clear_active_list(); 121 current_addr = u_current_addr, u_current_addr = o_current_addr; 122 addr_last = u_addr_last, u_addr_last = o_addr_last; 123 SPL0(); 124 return 0; 125 } 126 127 128 /* clear_undo_stack: clear the undo stack */ 129 void 130 clear_undo_stack(void) 131 { 132 line_t *lp, *ep, *tl; 133 134 while (u_p--) 135 if (ustack[u_p].type == UDEL) { 136 ep = ustack[u_p].t->q_forw; 137 for (lp = ustack[u_p].h; lp != ep; lp = tl) { 138 unmark_line_node(lp); 139 tl = lp->q_forw; 140 free(lp); 141 } 142 } 143 u_p = 0; 144 u_current_addr = current_addr; 145 u_addr_last = addr_last; 146 } 147