undo.c revision 90109
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 90109 2002-02-02 06:36:49Z imp $";
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 *
4390109Simppush_undo_stack(int type, long from, long to)
441057Salm{
451057Salm	undo_t *t;
461057Salm
471057Salm#if defined(sun) || defined(NO_REALLOC_NULL)
481057Salm	if (ustack == NULL &&
491057Salm	    (ustack = (undo_t *) malloc((usize = USIZE) * sizeof(undo_t))) == NULL) {
501057Salm		fprintf(stderr, "%s\n", strerror(errno));
5181220Smike		errmsg = "out of memory";
521057Salm		return NULL;
531057Salm	}
541057Salm#endif
551057Salm	t = ustack;
561057Salm	if (u_p < usize ||
571057Salm	    (t = (undo_t *) realloc(ustack, (usize += USIZE) * sizeof(undo_t))) != NULL) {
581057Salm		ustack = t;
591057Salm		ustack[u_p].type = type;
601057Salm		ustack[u_p].t = get_addressed_line_node(to);
611057Salm		ustack[u_p].h = get_addressed_line_node(from);
621057Salm		return ustack + u_p++;
631057Salm	}
641057Salm	/* out of memory - release undo stack */
651057Salm	fprintf(stderr, "%s\n", strerror(errno));
6681220Smike	errmsg = "out of memory";
671057Salm	clear_undo_stack();
681057Salm	free(ustack);
691057Salm	ustack = NULL;
701057Salm	usize = 0;
711057Salm	return NULL;
721057Salm}
731057Salm
741057Salm
751057Salm/* USWAP: swap undo nodes */
761057Salm#define USWAP(x,y) { \
771057Salm	undo_t utmp; \
781057Salm	utmp = x, x = y, y = utmp; \
791057Salm}
801057Salm
811057Salm
821057Salmlong u_current_addr = -1;	/* if >= 0, undo enabled */
831057Salmlong u_addr_last = -1;		/* if >= 0, undo enabled */
841057Salm
851057Salm/* pop_undo_stack: undo last change to the editor buffer */
861057Salmint
8790109Simppop_undo_stack(void)
881057Salm{
891057Salm	long n;
901057Salm	long o_current_addr = current_addr;
911057Salm	long o_addr_last = addr_last;
921057Salm
931057Salm	if (u_current_addr == -1 || u_addr_last == -1) {
9481220Smike		errmsg = "nothing to undo";
951057Salm		return ERR;
961057Salm	} else if (u_p)
971057Salm		modified = 1;
981057Salm	get_addressed_line_node(0);	/* this get_addressed_line_node last! */
991057Salm	SPL1();
1001057Salm	for (n = u_p; n-- > 0;) {
1011057Salm		switch(ustack[n].type) {
1021057Salm		case UADD:
1031057Salm			REQUE(ustack[n].h->q_back, ustack[n].t->q_forw);
1041057Salm			break;
1051057Salm		case UDEL:
1061057Salm			REQUE(ustack[n].h->q_back, ustack[n].h);
1071057Salm			REQUE(ustack[n].t, ustack[n].t->q_forw);
1081057Salm			break;
1091057Salm		case UMOV:
1101057Salm		case VMOV:
1111057Salm			REQUE(ustack[n - 1].h, ustack[n].h->q_forw);
1121057Salm			REQUE(ustack[n].t->q_back, ustack[n - 1].t);
1131057Salm			REQUE(ustack[n].h, ustack[n].t);
1141057Salm			n--;
1151057Salm			break;
1161057Salm		default:
1171057Salm			/*NOTREACHED*/
1181057Salm			;
1191057Salm		}
1201057Salm		ustack[n].type ^= 1;
1211057Salm	}
1221057Salm	/* reverse undo stack order */
1231057Salm	for (n = u_p; n-- > (u_p + 1)/ 2;)
1241057Salm		USWAP(ustack[n], ustack[u_p - 1 - n]);
1251057Salm	if (isglobal)
1261057Salm		clear_active_list();
1271057Salm	current_addr = u_current_addr, u_current_addr = o_current_addr;
1281057Salm	addr_last = u_addr_last, u_addr_last = o_addr_last;
1291057Salm	SPL0();
1301057Salm	return 0;
1311057Salm}
1321057Salm
1331057Salm
1341057Salm/* clear_undo_stack: clear the undo stack */
1351057Salmvoid
13690109Simpclear_undo_stack(void)
1371057Salm{
1381057Salm	line_t *lp, *ep, *tl;
1391057Salm
1401057Salm	while (u_p--)
1411057Salm		if (ustack[u_p].type == UDEL) {
1421057Salm			ep = ustack[u_p].t->q_forw;
1431057Salm			for (lp = ustack[u_p].h; lp != ep; lp = tl) {
1441057Salm				unmark_line_node(lp);
1451057Salm				tl = lp->q_forw;
1461057Salm				free(lp);
1471057Salm			}
1481057Salm		}
1491057Salm	u_p = 0;
1501057Salm	u_current_addr = current_addr;
1511057Salm	u_addr_last = addr_last;
1521057Salm}
153