4.4BSD/usr/src/contrib/ed/u.c
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Rodney Ruddock of the University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)u.c 8.1 (Berkeley) 5/31/93";
#endif /* not lint */
#include <sys/types.h>
#include <regex.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef DBI
#include <db.h>
#endif
#include "ed.h"
#include "extern.h"
struct d_layer *old_d_stk=NULL;
/*
* This restores the buffer to the state it was in just before the
* last buffer modifying command - the global commands (with command
* list) are looked at as one buffer modifying command. Note: this
* just manipulates the undo stack (u_stk); x-ref u_add_stk(),
* u_clr_stk(), d_add(), and d_do().
*/
void
u(inputt, errnum)
FILE *inputt;
int *errnum;
{
if (rol(inputt, errnum))
return;
undo(); /* call even when u_stk==nil */
*errnum = 1;
}
/* This function does the "real work" of the undo.
* It is separated out from u() so that the SIGHUP handling
* routine can call it without dealing with rol(), in turn so that
* the buffer is in a "good" state when saved to the 'ed.hup' file.
*/
void
undo()
{
LINE *l_current, *l_bottom, *l_top;
struct u_layer *l_old_u_stk, *l_temp;
struct d_layer *l_d_temp;
sigspecial++;
/* This is done because undo can be undone. */
l_current = u_current;
l_top = u_top;
l_bottom = u_bottom;
u_current = current;
u_top = top;
u_bottom = bottom;
l_d_temp = old_d_stk;
old_d_stk = d_stk;
d_stk = l_d_temp;
l_old_u_stk = u_stk;
u_stk = NULL;
while (l_old_u_stk != NULL) {
u_add_stk(l_old_u_stk->cell);
(*(l_old_u_stk->cell)) = (l_old_u_stk->val);
l_temp = l_old_u_stk;
l_old_u_stk = l_old_u_stk->below;
free(l_temp);
}
current = l_current;
top = l_top;
bottom = l_bottom;
sigspecial--;
if (sigint_flag && (!sigspecial))
SIGINT_ACTION;
}
/*
* This function should be called before u_add_stk is in each command
* function, _except_ when the global flag is high (>0) -- otherwise,
* we couldn't undo all of the global commands, only the last iteration
* of the last command -- and the u command.
* This is where we begin to dispose of ed's undo knowledge of a line.
* The call to d_do() gets rid of the rest.
*/
void
u_clr_stk()
{
register struct u_layer *l_temp;
u_current = current;
u_top = top;
u_bottom = bottom;
sigspecial++;
/* Only if there is something to delete in the buffer. */
if ((u_stk) && (d_stk))
d_do();
while (u_stk != NULL) {
l_temp = u_stk;
u_stk = u_stk->below;
free(l_temp);
}
u_stk = NULL; /* Just to sure. */
old_d_stk = NULL; /* so something in use isn't freed! */
sigspecial--;
if (sigint_flag && (!sigspecial))
SIGINT_ACTION;
}
/*
* Place the addresses of and the pointer values of the LINE structures
* that are being changed on the undo stack. This is a quick, simple,
* and effective way to preserve what could be be brought back on request
* without keeping a copy of every bleep'n thing.
*/
void
u_add_stk(in)
LINE **in;
{
register struct u_layer *l_now;
if (in == NULL)
return;
l_now = malloc(sizeof(struct u_layer));
if (l_now == NULL) {
strcpy(help_msg, "undo: out of memory error");
return;
}
sigspecial++;
if (u_stk == NULL)
(l_now->below) = NULL;
else
(l_now->below) = u_stk;
u_stk = l_now;
(u_stk->cell) = in;
(u_stk->val) = (*(u_stk->cell));
sigspecial--;
if (sigint_flag && (!sigspecial))
SIGINT_ACTION;
}
/* This 'u' function is just for when 's' notices that a series
* of adjacent lines are changing. It reduces the undo stack height
* and lowers the number of (costly) malloc's with reuse. For
* the environmentally aware the third 'R' is with the 'g' code.
*/
void
u_pop_n_swap(in)
LINE **in;
{
sigspecial++;
/* put the old value back */
(*(u_stk->cell)) = (u_stk->val);
/* put the new values */
(u_stk->cell) = in;
(u_stk->val) = (*(u_stk->cell));
sigspecial--;
if (sigint_flag && (!sigspecial))
SIGINT_ACTION;
}