11057Salm/* undo.c: This file contains the undo routines for the ed line editor */
21057Salm/*-
31057Salm * Copyright (c) 1993 Andrew Moore, Talke Studio.
41057Salm * All rights reserved.
51057Salm *
61057Salm * Redistribution and use in source and binary forms, with or without
71057Salm * modification, are permitted provided that the following conditions
81057Salm * are met:
91057Salm * 1. Redistributions of source code must retain the above copyright
101057Salm *    notice, this list of conditions and the following disclaimer.
111057Salm * 2. Redistributions in binary form must reproduce the above copyright
121057Salm *    notice, this list of conditions and the following disclaimer in the
131057Salm *    documentation and/or other materials provided with the distribution.
141057Salm *
151057Salm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
161057Salm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
171057Salm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
181057Salm * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
191057Salm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201057Salm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
211057Salm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221057Salm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231057Salm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241057Salm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251057Salm * SUCH DAMAGE.
261057Salm */
271057Salm
2899109Sobrien#include <sys/cdefs.h>
2999109Sobrien__FBSDID("$FreeBSD$");
301057Salm
311057Salm#include "ed.h"
321057Salm
331057Salm
341057Salm#define USIZE 100				/* undo stack size */
351057Salmundo_t *ustack = NULL;				/* undo stack */
361057Salmlong usize = 0;					/* stack size variable */
371057Salmlong u_p = 0;					/* undo stack pointer */
381057Salm
3946684Skris/* push_undo_stack: return pointer to initialized undo node */
401057Salmundo_t *
4190109Simppush_undo_stack(int type, long from, long to)
421057Salm{
431057Salm	undo_t *t;
441057Salm
451057Salm#if defined(sun) || defined(NO_REALLOC_NULL)
461057Salm	if (ustack == NULL &&
471057Salm	    (ustack = (undo_t *) malloc((usize = USIZE) * sizeof(undo_t))) == NULL) {
481057Salm		fprintf(stderr, "%s\n", strerror(errno));
4981220Smike		errmsg = "out of memory";
501057Salm		return NULL;
511057Salm	}
521057Salm#endif
531057Salm	t = ustack;
541057Salm	if (u_p < usize ||
551057Salm	    (t = (undo_t *) realloc(ustack, (usize += USIZE) * sizeof(undo_t))) != NULL) {
561057Salm		ustack = t;
571057Salm		ustack[u_p].type = type;
581057Salm		ustack[u_p].t = get_addressed_line_node(to);
591057Salm		ustack[u_p].h = get_addressed_line_node(from);
601057Salm		return ustack + u_p++;
611057Salm	}
621057Salm	/* out of memory - release undo stack */
631057Salm	fprintf(stderr, "%s\n", strerror(errno));
6481220Smike	errmsg = "out of memory";
651057Salm	clear_undo_stack();
661057Salm	free(ustack);
671057Salm	ustack = NULL;
681057Salm	usize = 0;
691057Salm	return NULL;
701057Salm}
711057Salm
721057Salm
731057Salm/* USWAP: swap undo nodes */
741057Salm#define USWAP(x,y) { \
751057Salm	undo_t utmp; \
761057Salm	utmp = x, x = y, y = utmp; \
771057Salm}
781057Salm
791057Salm
801057Salmlong u_current_addr = -1;	/* if >= 0, undo enabled */
811057Salmlong u_addr_last = -1;		/* if >= 0, undo enabled */
821057Salm
831057Salm/* pop_undo_stack: undo last change to the editor buffer */
841057Salmint
8590109Simppop_undo_stack(void)
861057Salm{
871057Salm	long n;
881057Salm	long o_current_addr = current_addr;
891057Salm	long o_addr_last = addr_last;
901057Salm
911057Salm	if (u_current_addr == -1 || u_addr_last == -1) {
9281220Smike		errmsg = "nothing to undo";
931057Salm		return ERR;
941057Salm	} else if (u_p)
951057Salm		modified = 1;
961057Salm	get_addressed_line_node(0);	/* this get_addressed_line_node last! */
971057Salm	SPL1();
981057Salm	for (n = u_p; n-- > 0;) {
991057Salm		switch(ustack[n].type) {
1001057Salm		case UADD:
1011057Salm			REQUE(ustack[n].h->q_back, ustack[n].t->q_forw);
1021057Salm			break;
1031057Salm		case UDEL:
1041057Salm			REQUE(ustack[n].h->q_back, ustack[n].h);
1051057Salm			REQUE(ustack[n].t, ustack[n].t->q_forw);
1061057Salm			break;
1071057Salm		case UMOV:
1081057Salm		case VMOV:
1091057Salm			REQUE(ustack[n - 1].h, ustack[n].h->q_forw);
1101057Salm			REQUE(ustack[n].t->q_back, ustack[n - 1].t);
1111057Salm			REQUE(ustack[n].h, ustack[n].t);
1121057Salm			n--;
1131057Salm			break;
1141057Salm		default:
1151057Salm			/*NOTREACHED*/
1161057Salm			;
1171057Salm		}
1181057Salm		ustack[n].type ^= 1;
1191057Salm	}
1201057Salm	/* reverse undo stack order */
1211057Salm	for (n = u_p; n-- > (u_p + 1)/ 2;)
1221057Salm		USWAP(ustack[n], ustack[u_p - 1 - n]);
1231057Salm	if (isglobal)
1241057Salm		clear_active_list();
1251057Salm	current_addr = u_current_addr, u_current_addr = o_current_addr;
1261057Salm	addr_last = u_addr_last, u_addr_last = o_addr_last;
1271057Salm	SPL0();
1281057Salm	return 0;
1291057Salm}
1301057Salm
1311057Salm
1321057Salm/* clear_undo_stack: clear the undo stack */
1331057Salmvoid
13490109Simpclear_undo_stack(void)
1351057Salm{
1361057Salm	line_t *lp, *ep, *tl;
1371057Salm
1381057Salm	while (u_p--)
1391057Salm		if (ustack[u_p].type == UDEL) {
1401057Salm			ep = ustack[u_p].t->q_forw;
1411057Salm			for (lp = ustack[u_p].h; lp != ep; lp = tl) {
1421057Salm				unmark_line_node(lp);
1431057Salm				tl = lp->q_forw;
1441057Salm				free(lp);
1451057Salm			}
1461057Salm		}
1471057Salm	u_p = 0;
1481057Salm	u_current_addr = current_addr;
1491057Salm	u_addr_last = addr_last;
1501057Salm}
151