undo.c revision 81220
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
281057Salm#ifndef lint
2981220Smikestatic const char rcsid[] =
3050471Speter  "$FreeBSD: head/bin/ed/undo.c 81220 2001-08-06 22:01:31Z mike $";
311057Salm#endif /* not lint */
321057Salm
331057Salm#include "ed.h"
341057Salm
351057Salm
361057Salm#define USIZE 100				/* undo stack size */
371057Salmundo_t *ustack = NULL;				/* undo stack */
381057Salmlong usize = 0;					/* stack size variable */
391057Salmlong u_p = 0;					/* undo stack pointer */
401057Salm
4146684Skris/* push_undo_stack: return pointer to initialized undo node */
421057Salmundo_t *
431057Salmpush_undo_stack(type, from, to)
441057Salm	int type;
451057Salm	long from;
461057Salm	long to;
471057Salm{
481057Salm	undo_t *t;
491057Salm
501057Salm#if defined(sun) || defined(NO_REALLOC_NULL)
511057Salm	if (ustack == NULL &&
521057Salm	    (ustack = (undo_t *) malloc((usize = USIZE) * sizeof(undo_t))) == NULL) {
531057Salm		fprintf(stderr, "%s\n", strerror(errno));
5481220Smike		errmsg = "out of memory";
551057Salm		return NULL;
561057Salm	}
571057Salm#endif
581057Salm	t = ustack;
591057Salm	if (u_p < usize ||
601057Salm	    (t = (undo_t *) realloc(ustack, (usize += USIZE) * sizeof(undo_t))) != NULL) {
611057Salm		ustack = t;
621057Salm		ustack[u_p].type = type;
631057Salm		ustack[u_p].t = get_addressed_line_node(to);
641057Salm		ustack[u_p].h = get_addressed_line_node(from);
651057Salm		return ustack + u_p++;
661057Salm	}
671057Salm	/* out of memory - release undo stack */
681057Salm	fprintf(stderr, "%s\n", strerror(errno));
6981220Smike	errmsg = "out of memory";
701057Salm	clear_undo_stack();
711057Salm	free(ustack);
721057Salm	ustack = NULL;
731057Salm	usize = 0;
741057Salm	return NULL;
751057Salm}
761057Salm
771057Salm
781057Salm/* USWAP: swap undo nodes */
791057Salm#define USWAP(x,y) { \
801057Salm	undo_t utmp; \
811057Salm	utmp = x, x = y, y = utmp; \
821057Salm}
831057Salm
841057Salm
851057Salmlong u_current_addr = -1;	/* if >= 0, undo enabled */
861057Salmlong u_addr_last = -1;		/* if >= 0, undo enabled */
871057Salm
881057Salm/* pop_undo_stack: undo last change to the editor buffer */
891057Salmint
901057Salmpop_undo_stack()
911057Salm{
921057Salm	long n;
931057Salm	long o_current_addr = current_addr;
941057Salm	long o_addr_last = addr_last;
951057Salm
961057Salm	if (u_current_addr == -1 || u_addr_last == -1) {
9781220Smike		errmsg = "nothing to undo";
981057Salm		return ERR;
991057Salm	} else if (u_p)
1001057Salm		modified = 1;
1011057Salm	get_addressed_line_node(0);	/* this get_addressed_line_node last! */
1021057Salm	SPL1();
1031057Salm	for (n = u_p; n-- > 0;) {
1041057Salm		switch(ustack[n].type) {
1051057Salm		case UADD:
1061057Salm			REQUE(ustack[n].h->q_back, ustack[n].t->q_forw);
1071057Salm			break;
1081057Salm		case UDEL:
1091057Salm			REQUE(ustack[n].h->q_back, ustack[n].h);
1101057Salm			REQUE(ustack[n].t, ustack[n].t->q_forw);
1111057Salm			break;
1121057Salm		case UMOV:
1131057Salm		case VMOV:
1141057Salm			REQUE(ustack[n - 1].h, ustack[n].h->q_forw);
1151057Salm			REQUE(ustack[n].t->q_back, ustack[n - 1].t);
1161057Salm			REQUE(ustack[n].h, ustack[n].t);
1171057Salm			n--;
1181057Salm			break;
1191057Salm		default:
1201057Salm			/*NOTREACHED*/
1211057Salm			;
1221057Salm		}
1231057Salm		ustack[n].type ^= 1;
1241057Salm	}
1251057Salm	/* reverse undo stack order */
1261057Salm	for (n = u_p; n-- > (u_p + 1)/ 2;)
1271057Salm		USWAP(ustack[n], ustack[u_p - 1 - n]);
1281057Salm	if (isglobal)
1291057Salm		clear_active_list();
1301057Salm	current_addr = u_current_addr, u_current_addr = o_current_addr;
1311057Salm	addr_last = u_addr_last, u_addr_last = o_addr_last;
1321057Salm	SPL0();
1331057Salm	return 0;
1341057Salm}
1351057Salm
1361057Salm
1371057Salm/* clear_undo_stack: clear the undo stack */
1381057Salmvoid
1391057Salmclear_undo_stack()
1401057Salm{
1411057Salm	line_t *lp, *ep, *tl;
1421057Salm
1431057Salm	while (u_p--)
1441057Salm		if (ustack[u_p].type == UDEL) {
1451057Salm			ep = ustack[u_p].t->q_forw;
1461057Salm			for (lp = ustack[u_p].h; lp != ep; lp = tl) {
1471057Salm				unmark_line_node(lp);
1481057Salm				tl = lp->q_forw;
1491057Salm				free(lp);
1501057Salm			}
1511057Salm		}
1521057Salm	u_p = 0;
1531057Salm	u_current_addr = current_addr;
1541057Salm	u_addr_last = addr_last;
1551057Salm}
156