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 */
39static undo_t *ustack = NULL;			/* undo stack */
40static int usize = 0;				/* stack size variable */
41static int u_p = 0;				/* undo stack pointer */
42
43/* push_undo_stack: return pointer to initialized undo node */
44undo_t *
45push_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
76int u_current_addr = -1;	/* if >= 0, undo enabled */
77int u_addr_last = -1;		/* if >= 0, undo enabled */
78
79/* pop_undo_stack: undo last change to the editor buffer */
80int
81pop_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 */
129void
130clear_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