jcs's openbsd hax
openbsd
1/* $OpenBSD: undo.c,v 1.15 2026/01/05 03:34:18 jsg 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 <stdio.h>
32#include <stdlib.h>
33
34#include "ed.h"
35
36#define USIZE 100 /* undo stack size */
37static undo_t *ustack = NULL; /* undo stack */
38static int usize = 0; /* stack size variable */
39static int u_p = 0; /* undo stack pointer */
40
41/* push_undo_stack: return pointer to initialized undo node */
42undo_t *
43push_undo_stack(int type, int from, int to)
44{
45 undo_t *t;
46
47 t = ustack;
48 if (u_p < usize ||
49 (t = reallocarray(ustack, (usize += USIZE), sizeof(undo_t))) != NULL) {
50 ustack = t;
51 ustack[u_p].type = type;
52 ustack[u_p].t = get_addressed_line_node(to);
53 ustack[u_p].h = get_addressed_line_node(from);
54 return ustack + u_p++;
55 }
56 /* out of memory - release undo stack */
57 perror(NULL);
58 seterrmsg("out of memory");
59 clear_undo_stack();
60 free(ustack);
61 ustack = NULL;
62 usize = 0;
63 return NULL;
64}
65
66
67/* USWAP: swap undo nodes */
68#define USWAP(x,y) { \
69 undo_t utmp; \
70 utmp = x, x = y, y = utmp; \
71}
72
73
74int u_current_addr = -1; /* if >= 0, undo enabled */
75int u_addr_last = -1; /* if >= 0, undo enabled */
76
77/* pop_undo_stack: undo last change to the editor buffer */
78int
79pop_undo_stack(void)
80{
81 int n;
82 int o_current_addr = current_addr;
83 int o_addr_last = addr_last;
84
85 if (u_current_addr == -1 || u_addr_last == -1) {
86 seterrmsg("nothing to undo");
87 return ERR;
88 } else if (u_p)
89 modified = 1;
90 get_addressed_line_node(0); /* this get_addressed_line_node last! */
91 SPL1();
92 for (n = u_p; n-- > 0;) {
93 switch(ustack[n].type) {
94 case UADD:
95 REQUE(ustack[n].h->q_back, ustack[n].t->q_forw);
96 break;
97 case UDEL:
98 REQUE(ustack[n].h->q_back, ustack[n].h);
99 REQUE(ustack[n].t, ustack[n].t->q_forw);
100 break;
101 case UMOV:
102 case VMOV:
103 REQUE(ustack[n - 1].h, ustack[n].h->q_forw);
104 REQUE(ustack[n].t->q_back, ustack[n - 1].t);
105 REQUE(ustack[n].h, ustack[n].t);
106 n--;
107 break;
108 default:
109 /*NOTREACHED*/
110 ;
111 }
112 ustack[n].type ^= 1;
113 }
114 /* reverse undo stack order */
115 for (n = u_p; n-- > (u_p + 1)/ 2;)
116 USWAP(ustack[n], ustack[u_p - 1 - n]);
117 if (isglobal)
118 clear_active_list();
119 current_addr = u_current_addr, u_current_addr = o_current_addr;
120 addr_last = u_addr_last, u_addr_last = o_addr_last;
121 SPL0();
122 return 0;
123}
124
125
126/* clear_undo_stack: clear the undo stack */
127void
128clear_undo_stack(void)
129{
130 line_t *lp, *ep, *tl;
131
132 while (u_p--)
133 if (ustack[u_p].type == UDEL) {
134 ep = ustack[u_p].t->q_forw;
135 for (lp = ustack[u_p].h; lp != ep; lp = tl) {
136 unmark_line_node(lp);
137 tl = lp->q_forw;
138 free(lp);
139 }
140 }
141 u_p = 0;
142 u_current_addr = current_addr;
143 u_addr_last = addr_last;
144}