xref: /minix3/external/bsd/nvi/dist/common/log4.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: log4.c,v 1.3 2014/01/26 21:43:45 christos Exp $	*/
284d9c625SLionel Sambuc /*-
384d9c625SLionel Sambuc  * Copyright (c) 1992, 1993, 1994
484d9c625SLionel Sambuc  *	The Regents of the University of California.  All rights reserved.
584d9c625SLionel Sambuc  * Copyright (c) 1992, 1993, 1994, 1995, 1996
684d9c625SLionel Sambuc  *	Keith Bostic.  All rights reserved.
784d9c625SLionel Sambuc  *
884d9c625SLionel Sambuc  * See the LICENSE file for redistribution information.
984d9c625SLionel Sambuc  */
1084d9c625SLionel Sambuc 
1184d9c625SLionel Sambuc #include "config.h"
1284d9c625SLionel Sambuc 
13*0a6a1f1dSLionel Sambuc #include <sys/cdefs.h>
14*0a6a1f1dSLionel Sambuc #if 0
1584d9c625SLionel Sambuc #ifndef lint
1684d9c625SLionel Sambuc static const char sccsid[] = "Id: log4.c,v 10.3 2002/06/08 21:00:33 skimo Exp ";
1784d9c625SLionel Sambuc #endif /* not lint */
18*0a6a1f1dSLionel Sambuc #else
19*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: log4.c,v 1.3 2014/01/26 21:43:45 christos Exp $");
20*0a6a1f1dSLionel Sambuc #endif
2184d9c625SLionel Sambuc 
2284d9c625SLionel Sambuc #include <sys/types.h>
2384d9c625SLionel Sambuc #include <sys/queue.h>
2484d9c625SLionel Sambuc #include <sys/stat.h>
2584d9c625SLionel Sambuc 
2684d9c625SLionel Sambuc #include <bitstring.h>
2784d9c625SLionel Sambuc #include <errno.h>
2884d9c625SLionel Sambuc #include <fcntl.h>
2984d9c625SLionel Sambuc #include <limits.h>
3084d9c625SLionel Sambuc #include <stdio.h>
3184d9c625SLionel Sambuc #include <stdlib.h>
3284d9c625SLionel Sambuc #include <string.h>
3384d9c625SLionel Sambuc 
3484d9c625SLionel Sambuc #include "common.h"
3584d9c625SLionel Sambuc 
3684d9c625SLionel Sambuc /*
3784d9c625SLionel Sambuc  * The log consists of records, each containing a type byte and a variable
3884d9c625SLionel Sambuc  * length byte string, as follows:
3984d9c625SLionel Sambuc  *
4084d9c625SLionel Sambuc  *	LOG_CURSOR_INIT		MARK
4184d9c625SLionel Sambuc  *	LOG_CURSOR_END		MARK
4284d9c625SLionel Sambuc  *	LOG_LINE_APPEND_F 	db_recno_t		char *
4384d9c625SLionel Sambuc  *	LOG_LINE_APPEND_B 	db_recno_t		char *
4484d9c625SLionel Sambuc  *	LOG_LINE_DELETE_F	db_recno_t		char *
4584d9c625SLionel Sambuc  *	LOG_LINE_DELETE_B	db_recno_t		char *
4684d9c625SLionel Sambuc  *	LOG_LINE_RESET_F	db_recno_t		char *
4784d9c625SLionel Sambuc  *	LOG_LINE_RESET_B	db_recno_t		char *
4884d9c625SLionel Sambuc  *	LOG_MARK		LMARK
4984d9c625SLionel Sambuc  *
5084d9c625SLionel Sambuc  * We do before image physical logging.  This means that the editor layer
5184d9c625SLionel Sambuc  * MAY NOT modify records in place, even if simply deleting or overwriting
5284d9c625SLionel Sambuc  * characters.  Since the smallest unit of logging is a line, we're using
5384d9c625SLionel Sambuc  * up lots of space.  This may eventually have to be reduced, probably by
5484d9c625SLionel Sambuc  * doing logical logging, which is a much cooler database phrase.
5584d9c625SLionel Sambuc  *
5684d9c625SLionel Sambuc  * The implementation of the historic vi 'u' command, using roll-forward and
5784d9c625SLionel Sambuc  * roll-back, is simple.  Each set of changes has a LOG_CURSOR_INIT record,
5884d9c625SLionel Sambuc  * followed by a number of other records, followed by a LOG_CURSOR_END record.
5984d9c625SLionel Sambuc  * LOG_LINE_RESET records come in pairs.  The first is a LOG_LINE_RESET_B
6084d9c625SLionel Sambuc  * record, and is the line before the change.  The second is LOG_LINE_RESET_F,
6184d9c625SLionel Sambuc  * and is the line after the change.  Roll-back is done by backing up to the
6284d9c625SLionel Sambuc  * first LOG_CURSOR_INIT record before a change.  Roll-forward is done in a
6384d9c625SLionel Sambuc  * similar fashion.
6484d9c625SLionel Sambuc  *
6584d9c625SLionel Sambuc  * The 'U' command is implemented by rolling backward to a LOG_CURSOR_END
6684d9c625SLionel Sambuc  * record for a line different from the current one.  It should be noted that
6784d9c625SLionel Sambuc  * this means that a subsequent 'u' command will make a change based on the
6884d9c625SLionel Sambuc  * new position of the log's cursor.  This is okay, and, in fact, historic vi
6984d9c625SLionel Sambuc  * behaved that way.
7084d9c625SLionel Sambuc  */
7184d9c625SLionel Sambuc 
7284d9c625SLionel Sambuc static int	log_cursor1 __P((SCR *, int));
7384d9c625SLionel Sambuc 
7484d9c625SLionel Sambuc /*
7584d9c625SLionel Sambuc  * log_init --
7684d9c625SLionel Sambuc  *	Initialize the logging subsystem.
7784d9c625SLionel Sambuc  *
7884d9c625SLionel Sambuc  * PUBLIC: int log_init __P((SCR *, EXF *));
7984d9c625SLionel Sambuc  */
8084d9c625SLionel Sambuc int
log_init(SCR * sp,EXF * ep)8184d9c625SLionel Sambuc log_init(SCR *sp, EXF *ep)
8284d9c625SLionel Sambuc {
8384d9c625SLionel Sambuc 	DB_LOGC *logc;
8484d9c625SLionel Sambuc 	DBT data;
8584d9c625SLionel Sambuc 	size_t nlen;
8684d9c625SLionel Sambuc 
8784d9c625SLionel Sambuc 	/*
8884d9c625SLionel Sambuc 	 * !!!
8984d9c625SLionel Sambuc 	 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
9084d9c625SLionel Sambuc 	 *
9184d9c625SLionel Sambuc 	 * Initialize the buffer.  The logging subsystem has its own
9284d9c625SLionel Sambuc 	 * buffers because the global ones are almost by definition
9384d9c625SLionel Sambuc 	 * going to be in use when the log runs.
9484d9c625SLionel Sambuc 	 */
9584d9c625SLionel Sambuc 	sp->wp->l_lp = NULL;
9684d9c625SLionel Sambuc 	sp->wp->l_len = 0;
9784d9c625SLionel Sambuc 	ep->l_cursor.lno = 1;		/* XXX Any valid recno. */
9884d9c625SLionel Sambuc 	ep->l_cursor.cno = 0;
9984d9c625SLionel Sambuc 	ep->l_high = ep->l_cur = 1;
10084d9c625SLionel Sambuc 
10184d9c625SLionel Sambuc 	if ((sp->db_error = ep->env->log_cursor(ep->env, &logc, 0))
10284d9c625SLionel Sambuc 		    != 0) {
10384d9c625SLionel Sambuc 		msgq(sp, M_DBERR, "env->log_cursor");
10484d9c625SLionel Sambuc 		F_SET(ep, F_NOLOG);
10584d9c625SLionel Sambuc 		return (1);
10684d9c625SLionel Sambuc 	}
10784d9c625SLionel Sambuc 	nlen = 1024;
10884d9c625SLionel Sambuc retry:
10984d9c625SLionel Sambuc 	BINC_GOTO(sp, sp->wp->l_lp, sp->wp->l_len, nlen);
11084d9c625SLionel Sambuc 	memset(&data, 0, sizeof(data));
11184d9c625SLionel Sambuc 	data.data = sp->wp->l_lp;
11284d9c625SLionel Sambuc 	data.ulen = sp->wp->l_len;
11384d9c625SLionel Sambuc 	data.flags = DB_DBT_USERMEM;
11484d9c625SLionel Sambuc 	switch ((sp->db_error =
11584d9c625SLionel Sambuc 	    logc->get(logc, &ep->lsn_first, &data, DB_LAST))) {
11684d9c625SLionel Sambuc 	case ENOMEM:
11784d9c625SLionel Sambuc 		nlen = data.size;
11884d9c625SLionel Sambuc 		goto retry;
11984d9c625SLionel Sambuc 	default:
12084d9c625SLionel Sambuc alloc_err:
12184d9c625SLionel Sambuc 		msgq(sp, M_DBERR, "logc->get");
12284d9c625SLionel Sambuc 		F_SET(ep, F_NOLOG);
12384d9c625SLionel Sambuc 		return (1);
12484d9c625SLionel Sambuc 	case 0:
12584d9c625SLionel Sambuc 		;
12684d9c625SLionel Sambuc 	}
12784d9c625SLionel Sambuc 	MEMCPY(&ep->lsn_cur, &ep->lsn_first, 1);
12884d9c625SLionel Sambuc 	MEMCPY(&ep->lsn_high, &ep->lsn_first, 1);
12984d9c625SLionel Sambuc 	logc->close(logc, 0);
13084d9c625SLionel Sambuc 
13184d9c625SLionel Sambuc 	ep->l_win = NULL;
13284d9c625SLionel Sambuc 	/*LOCK_INIT(sp->wp, ep);*/
13384d9c625SLionel Sambuc 
13484d9c625SLionel Sambuc 	return (0);
13584d9c625SLionel Sambuc }
13684d9c625SLionel Sambuc 
13784d9c625SLionel Sambuc /*
13884d9c625SLionel Sambuc  * log_end --
13984d9c625SLionel Sambuc  *	Close the logging subsystem.
14084d9c625SLionel Sambuc  *
14184d9c625SLionel Sambuc  * PUBLIC: int log_end __P((SCR *, EXF *));
14284d9c625SLionel Sambuc  */
14384d9c625SLionel Sambuc int
log_end(SCR * sp,EXF * ep)14484d9c625SLionel Sambuc log_end(SCR *sp, EXF *ep)
14584d9c625SLionel Sambuc {
14684d9c625SLionel Sambuc 	/*
14784d9c625SLionel Sambuc 	 * !!!
14884d9c625SLionel Sambuc 	 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
14984d9c625SLionel Sambuc 	 */
15084d9c625SLionel Sambuc 	/*LOCK_END(sp->wp, ep);*/
15184d9c625SLionel Sambuc 	if (sp->wp->l_lp != NULL) {
15284d9c625SLionel Sambuc 		free(sp->wp->l_lp);
15384d9c625SLionel Sambuc 		sp->wp->l_lp = NULL;
15484d9c625SLionel Sambuc 	}
15584d9c625SLionel Sambuc 	sp->wp->l_len = 0;
15684d9c625SLionel Sambuc 	ep->l_cursor.lno = 1;		/* XXX Any valid recno. */
15784d9c625SLionel Sambuc 	ep->l_cursor.cno = 0;
15884d9c625SLionel Sambuc 	ep->l_high = ep->l_cur = 1;
15984d9c625SLionel Sambuc 	return (0);
16084d9c625SLionel Sambuc }
16184d9c625SLionel Sambuc 
16284d9c625SLionel Sambuc /*
16384d9c625SLionel Sambuc  * log_cursor --
16484d9c625SLionel Sambuc  *	Log the current cursor position, starting an event.
16584d9c625SLionel Sambuc  *
16684d9c625SLionel Sambuc  * PUBLIC: int log_cursor __P((SCR *));
16784d9c625SLionel Sambuc  */
16884d9c625SLionel Sambuc int
log_cursor(SCR * sp)16984d9c625SLionel Sambuc log_cursor(SCR *sp)
17084d9c625SLionel Sambuc {
17184d9c625SLionel Sambuc 	EXF *ep;
17284d9c625SLionel Sambuc 
17384d9c625SLionel Sambuc 	ep = sp->ep;
17484d9c625SLionel Sambuc 	if (F_ISSET(ep, F_NOLOG))
17584d9c625SLionel Sambuc 		return (0);
17684d9c625SLionel Sambuc 
17784d9c625SLionel Sambuc 	/*
17884d9c625SLionel Sambuc 	 * If any changes were made since the last cursor init,
17984d9c625SLionel Sambuc 	 * put out the ending cursor record.
18084d9c625SLionel Sambuc 	 */
18184d9c625SLionel Sambuc 	if (ep->l_cursor.lno == OOBLNO) {
18284d9c625SLionel Sambuc 		if (ep->l_win && ep->l_win != sp->wp)
18384d9c625SLionel Sambuc 			return 0;
18484d9c625SLionel Sambuc 		ep->l_cursor.lno = sp->lno;
18584d9c625SLionel Sambuc 		ep->l_cursor.cno = sp->cno;
18684d9c625SLionel Sambuc 		ep->l_win = NULL;
18784d9c625SLionel Sambuc 		return (log_cursor1(sp, LOG_CURSOR_END));
18884d9c625SLionel Sambuc 	}
18984d9c625SLionel Sambuc 	ep->l_cursor.lno = sp->lno;
19084d9c625SLionel Sambuc 	ep->l_cursor.cno = sp->cno;
19184d9c625SLionel Sambuc 	return (0);
19284d9c625SLionel Sambuc }
19384d9c625SLionel Sambuc 
19484d9c625SLionel Sambuc /*
19584d9c625SLionel Sambuc  * log_cursor1 --
19684d9c625SLionel Sambuc  *	Actually push a cursor record out.
19784d9c625SLionel Sambuc  */
19884d9c625SLionel Sambuc static int
log_cursor1(SCR * sp,int type)19984d9c625SLionel Sambuc log_cursor1(SCR *sp, int type)
20084d9c625SLionel Sambuc {
20184d9c625SLionel Sambuc 	DBT data, key;
20284d9c625SLionel Sambuc 	EXF *ep;
20384d9c625SLionel Sambuc 
20484d9c625SLionel Sambuc 	ep = sp->ep;
20584d9c625SLionel Sambuc 
20684d9c625SLionel Sambuc 	/*
20784d9c625SLionel Sambuc 	if (type == LOG_CURSOR_INIT &&
20884d9c625SLionel Sambuc 	    LOCK_TRY(sp->wp, ep))
20984d9c625SLionel Sambuc 		return 1;
21084d9c625SLionel Sambuc 	*/
21184d9c625SLionel Sambuc 
21284d9c625SLionel Sambuc 	if (type == LOG_CURSOR_INIT &&
21384d9c625SLionel Sambuc 	    (sp->db_error = __vi_log_truncate(ep)) != 0) {
21484d9c625SLionel Sambuc 		msgq(sp, M_DBERR, "truncate");
21584d9c625SLionel Sambuc 		return 1;
21684d9c625SLionel Sambuc 	}
21784d9c625SLionel Sambuc 	if ((sp->db_error =
21884d9c625SLionel Sambuc 		__vi_cursor_log(ep->env, NULL, &ep->lsn_cur, 0, type,
21984d9c625SLionel Sambuc 			    ep->l_cursor.lno, ep->l_cursor.cno)) != 0) {
22084d9c625SLionel Sambuc 		msgq(sp, M_DBERR, "cursor_log");
22184d9c625SLionel Sambuc 		return 1;
22284d9c625SLionel Sambuc 	}
22384d9c625SLionel Sambuc 	if (type == LOG_CURSOR_END) {
22484d9c625SLionel Sambuc 		MEMCPY(&ep->lsn_high, &ep->lsn_cur, 1);
22584d9c625SLionel Sambuc 		/* XXXX should not be needed */
22684d9c625SLionel Sambuc 		ep->env->log_flush(ep->env, NULL);
22784d9c625SLionel Sambuc 	}
22884d9c625SLionel Sambuc 
22984d9c625SLionel Sambuc #if defined(DEBUG) && 0
23084d9c625SLionel Sambuc 	vtrace(sp, "%lu: %s: %u/%u\n", ep->l_cur,
23184d9c625SLionel Sambuc 	    type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end",
23284d9c625SLionel Sambuc 	    sp->lno, sp->cno);
23384d9c625SLionel Sambuc #endif
23484d9c625SLionel Sambuc 	/* Reset high water mark. */
23584d9c625SLionel Sambuc 	ep->l_high = ++ep->l_cur;
23684d9c625SLionel Sambuc 
23784d9c625SLionel Sambuc 	/*
23884d9c625SLionel Sambuc 	if (type == LOG_CURSOR_END)
23984d9c625SLionel Sambuc 		LOCK_UNLOCK(sp->wp, ep);
24084d9c625SLionel Sambuc 	*/
24184d9c625SLionel Sambuc 	return (0);
24284d9c625SLionel Sambuc }
24384d9c625SLionel Sambuc 
24484d9c625SLionel Sambuc /*
24584d9c625SLionel Sambuc  * log_line --
24684d9c625SLionel Sambuc  *	Log a line change.
24784d9c625SLionel Sambuc  *
24884d9c625SLionel Sambuc  * PUBLIC: int log_line __P((SCR *, db_recno_t, u_int));
24984d9c625SLionel Sambuc  */
25084d9c625SLionel Sambuc int
log_line(SCR * sp,db_recno_t lno,u_int action)25184d9c625SLionel Sambuc log_line(SCR *sp, db_recno_t lno, u_int action)
25284d9c625SLionel Sambuc {
25384d9c625SLionel Sambuc 	DBT data, key;
25484d9c625SLionel Sambuc 	EXF *ep;
25584d9c625SLionel Sambuc 	size_t len;
25684d9c625SLionel Sambuc 	CHAR_T *lp;
25784d9c625SLionel Sambuc 	db_recno_t lcur;
25884d9c625SLionel Sambuc 
25984d9c625SLionel Sambuc 	ep = sp->ep;
26084d9c625SLionel Sambuc 	if (F_ISSET(ep, F_NOLOG))
26184d9c625SLionel Sambuc 		return (0);
26284d9c625SLionel Sambuc 
26384d9c625SLionel Sambuc 	/*
26484d9c625SLionel Sambuc 	 * XXX
26584d9c625SLionel Sambuc 	 *
26684d9c625SLionel Sambuc 	 * Kluge for vi.  Clear the EXF undo flag so that the
26784d9c625SLionel Sambuc 	 * next 'u' command does a roll-back, regardless.
26884d9c625SLionel Sambuc 	 */
26984d9c625SLionel Sambuc 	F_CLR(ep, F_UNDO);
27084d9c625SLionel Sambuc 
27184d9c625SLionel Sambuc 	/* Put out one initial cursor record per set of changes. */
27284d9c625SLionel Sambuc 	if (ep->l_cursor.lno != OOBLNO) {
27384d9c625SLionel Sambuc 		if (log_cursor1(sp, LOG_CURSOR_INIT))
27484d9c625SLionel Sambuc 			return (1);
27584d9c625SLionel Sambuc 		ep->l_cursor.lno = OOBLNO;
27684d9c625SLionel Sambuc 		ep->l_win = sp->wp;
27784d9c625SLionel Sambuc 	} /*else if (ep->l_win != sp->wp) {
27884d9c625SLionel Sambuc 		printf("log_line own: %p, this: %p\n", ep->l_win, sp->wp);
27984d9c625SLionel Sambuc 		return 1;
28084d9c625SLionel Sambuc 	}*/
28184d9c625SLionel Sambuc 
28284d9c625SLionel Sambuc 	if ((sp->db_error =
28384d9c625SLionel Sambuc 		__vi_change_log(ep->env, NULL, &ep->lsn_cur, 0, action,
28484d9c625SLionel Sambuc 			    lno)) != 0) {
28584d9c625SLionel Sambuc 		msgq(sp, M_DBERR, "change_log");
28684d9c625SLionel Sambuc 		return 1;
28784d9c625SLionel Sambuc 	}
28884d9c625SLionel Sambuc 
28984d9c625SLionel Sambuc #if defined(DEBUG) && 0
29084d9c625SLionel Sambuc 	switch (action) {
29184d9c625SLionel Sambuc 	case LOG_LINE_APPEND_F:
29284d9c625SLionel Sambuc 		vtrace(sp, "%u: log_line: append_f: %lu {%u}\n",
29384d9c625SLionel Sambuc 		    ep->l_cur, lno, len);
29484d9c625SLionel Sambuc 		break;
29584d9c625SLionel Sambuc 	case LOG_LINE_APPEND_B:
29684d9c625SLionel Sambuc 		vtrace(sp, "%u: log_line: append_b: %lu {%u}\n",
29784d9c625SLionel Sambuc 		    ep->l_cur, lno, len);
29884d9c625SLionel Sambuc 		break;
29984d9c625SLionel Sambuc 	case LOG_LINE_DELETE_F:
30084d9c625SLionel Sambuc 		vtrace(sp, "%lu: log_line: delete_f: %lu {%u}\n",
30184d9c625SLionel Sambuc 		    ep->l_cur, lno, len);
30284d9c625SLionel Sambuc 		break;
30384d9c625SLionel Sambuc 	case LOG_LINE_DELETE_B:
30484d9c625SLionel Sambuc 		vtrace(sp, "%lu: log_line: delete_b: %lu {%u}\n",
30584d9c625SLionel Sambuc 		    ep->l_cur, lno, len);
30684d9c625SLionel Sambuc 		break;
30784d9c625SLionel Sambuc 	case LOG_LINE_RESET_F:
30884d9c625SLionel Sambuc 		vtrace(sp, "%lu: log_line: reset_f: %lu {%u}\n",
30984d9c625SLionel Sambuc 		    ep->l_cur, lno, len);
31084d9c625SLionel Sambuc 		break;
31184d9c625SLionel Sambuc 	case LOG_LINE_RESET_B:
31284d9c625SLionel Sambuc 		vtrace(sp, "%lu: log_line: reset_b: %lu {%u}\n",
31384d9c625SLionel Sambuc 		    ep->l_cur, lno, len);
31484d9c625SLionel Sambuc 		break;
31584d9c625SLionel Sambuc 	}
31684d9c625SLionel Sambuc #endif
31784d9c625SLionel Sambuc 	/* Reset high water mark. */
31884d9c625SLionel Sambuc 	ep->l_high = ++ep->l_cur;
31984d9c625SLionel Sambuc 
32084d9c625SLionel Sambuc 	return (0);
32184d9c625SLionel Sambuc }
32284d9c625SLionel Sambuc 
32384d9c625SLionel Sambuc /*
32484d9c625SLionel Sambuc  * log_mark --
32584d9c625SLionel Sambuc  *	Log a mark position.  For the log to work, we assume that there
32684d9c625SLionel Sambuc  *	aren't any operations that just put out a log record -- this
32784d9c625SLionel Sambuc  *	would mean that undo operations would only reset marks, and not
32884d9c625SLionel Sambuc  *	cause any other change.
32984d9c625SLionel Sambuc  *
33084d9c625SLionel Sambuc  * PUBLIC: int log_mark __P((SCR *, LMARK *));
33184d9c625SLionel Sambuc  */
33284d9c625SLionel Sambuc int
log_mark(SCR * sp,LMARK * lmp)33384d9c625SLionel Sambuc log_mark(SCR *sp, LMARK *lmp)
33484d9c625SLionel Sambuc {
33584d9c625SLionel Sambuc 	DBT data, key;
33684d9c625SLionel Sambuc 	EXF *ep;
33784d9c625SLionel Sambuc 
33884d9c625SLionel Sambuc 	ep = sp->ep;
33984d9c625SLionel Sambuc 	if (F_ISSET(ep, F_NOLOG))
34084d9c625SLionel Sambuc 		return (0);
34184d9c625SLionel Sambuc 
34284d9c625SLionel Sambuc 	/* Put out one initial cursor record per set of changes. */
34384d9c625SLionel Sambuc 	if (ep->l_cursor.lno != OOBLNO) {
34484d9c625SLionel Sambuc 		if (log_cursor1(sp, LOG_CURSOR_INIT))
34584d9c625SLionel Sambuc 			return (1);
34684d9c625SLionel Sambuc 		ep->l_cursor.lno = OOBLNO;
34784d9c625SLionel Sambuc 		ep->l_win = sp->wp;
34884d9c625SLionel Sambuc 	}
34984d9c625SLionel Sambuc 
35084d9c625SLionel Sambuc 	if ((sp->db_error =
35184d9c625SLionel Sambuc 		__vi_mark_log(ep->env, NULL, &ep->lsn_cur, 0,
35284d9c625SLionel Sambuc 			    lmp)) != 0) {
35384d9c625SLionel Sambuc 		msgq(sp, M_DBERR, "cursor_log");
35484d9c625SLionel Sambuc 		return 1;
35584d9c625SLionel Sambuc 	}
35684d9c625SLionel Sambuc 
35784d9c625SLionel Sambuc #if defined(DEBUG) && 0
35884d9c625SLionel Sambuc 	vtrace(sp, "%lu: mark %c: %lu/%u\n",
35984d9c625SLionel Sambuc 	    ep->l_cur, lmp->name, lmp->lno, lmp->cno);
36084d9c625SLionel Sambuc #endif
36184d9c625SLionel Sambuc 	/* Reset high water mark. */
36284d9c625SLionel Sambuc 	ep->l_high = ++ep->l_cur;
36384d9c625SLionel Sambuc 	return (0);
36484d9c625SLionel Sambuc }
36584d9c625SLionel Sambuc 
36684d9c625SLionel Sambuc /*
36784d9c625SLionel Sambuc  * Log_backward --
36884d9c625SLionel Sambuc  *	Roll the log backward one operation.
36984d9c625SLionel Sambuc  *
37084d9c625SLionel Sambuc  * PUBLIC: int log_backward __P((SCR *, MARK *));
37184d9c625SLionel Sambuc  */
37284d9c625SLionel Sambuc int
log_backward(SCR * sp,MARK * rp)37384d9c625SLionel Sambuc log_backward(SCR *sp, MARK *rp)
37484d9c625SLionel Sambuc {
37584d9c625SLionel Sambuc 	EXF *ep;
37684d9c625SLionel Sambuc 	LMARK lm;
37784d9c625SLionel Sambuc 	MARK m;
37884d9c625SLionel Sambuc 	db_recno_t lno;
37984d9c625SLionel Sambuc 	int didop;
38084d9c625SLionel Sambuc 	u_char *p;
38184d9c625SLionel Sambuc 	size_t size;
38284d9c625SLionel Sambuc 
38384d9c625SLionel Sambuc 	ep = sp->ep;
38484d9c625SLionel Sambuc 	if (F_ISSET(ep, F_NOLOG)) {
38584d9c625SLionel Sambuc 		msgq(sp, M_ERR,
38684d9c625SLionel Sambuc 		    "010|Logging not being performed, undo not possible");
38784d9c625SLionel Sambuc 		return (1);
38884d9c625SLionel Sambuc 	}
38984d9c625SLionel Sambuc 
39084d9c625SLionel Sambuc 	if (log_compare(&ep->lsn_cur, &ep->lsn_first) <= 0) {
39184d9c625SLionel Sambuc 		msgq(sp, M_BERR, "011|No changes to undo");
39284d9c625SLionel Sambuc 		return (1);
39384d9c625SLionel Sambuc 	}
39484d9c625SLionel Sambuc 	return __vi_log_traverse(sp, UNDO_BACKWARD, rp);
39584d9c625SLionel Sambuc }
39684d9c625SLionel Sambuc 
39784d9c625SLionel Sambuc /*
39884d9c625SLionel Sambuc  * Log_setline --
39984d9c625SLionel Sambuc  *	Reset the line to its original appearance.
40084d9c625SLionel Sambuc  *
40184d9c625SLionel Sambuc  * XXX
40284d9c625SLionel Sambuc  * There's a bug in this code due to our not logging cursor movements
40384d9c625SLionel Sambuc  * unless a change was made.  If you do a change, move off the line,
40484d9c625SLionel Sambuc  * then move back on and do a 'U', the line will be restored to the way
40584d9c625SLionel Sambuc  * it was before the original change.
40684d9c625SLionel Sambuc  *
40784d9c625SLionel Sambuc  * PUBLIC: int log_setline __P((SCR *));
40884d9c625SLionel Sambuc  */
40984d9c625SLionel Sambuc int
log_setline(SCR * sp)41084d9c625SLionel Sambuc log_setline(SCR *sp)
41184d9c625SLionel Sambuc {
41284d9c625SLionel Sambuc 	EXF *ep;
41384d9c625SLionel Sambuc 	LMARK lm;
41484d9c625SLionel Sambuc 	MARK m;
41584d9c625SLionel Sambuc 	db_recno_t lno;
41684d9c625SLionel Sambuc 	u_char *p;
41784d9c625SLionel Sambuc 	size_t size;
41884d9c625SLionel Sambuc 
41984d9c625SLionel Sambuc 	ep = sp->ep;
42084d9c625SLionel Sambuc 	if (F_ISSET(ep, F_NOLOG)) {
42184d9c625SLionel Sambuc 		msgq(sp, M_ERR,
42284d9c625SLionel Sambuc 		    "012|Logging not being performed, undo not possible");
42384d9c625SLionel Sambuc 		return (1);
42484d9c625SLionel Sambuc 	}
42584d9c625SLionel Sambuc 
42684d9c625SLionel Sambuc 	if (log_compare(&ep->lsn_cur, &ep->lsn_first) <= 0) {
42784d9c625SLionel Sambuc 		msgq(sp, M_BERR, "011|No changes to undo");
42884d9c625SLionel Sambuc 		return (1);
42984d9c625SLionel Sambuc 	}
43084d9c625SLionel Sambuc 	return __vi_log_traverse(sp, UNDO_SETLINE, &m);
43184d9c625SLionel Sambuc }
43284d9c625SLionel Sambuc 
43384d9c625SLionel Sambuc /*
43484d9c625SLionel Sambuc  * Log_forward --
43584d9c625SLionel Sambuc  *	Roll the log forward one operation.
43684d9c625SLionel Sambuc  *
43784d9c625SLionel Sambuc  * PUBLIC: int log_forward __P((SCR *, MARK *));
43884d9c625SLionel Sambuc  */
43984d9c625SLionel Sambuc int
log_forward(SCR * sp,MARK * rp)44084d9c625SLionel Sambuc log_forward(SCR *sp, MARK *rp)
44184d9c625SLionel Sambuc {
44284d9c625SLionel Sambuc 	EXF *ep;
44384d9c625SLionel Sambuc 	LMARK lm;
44484d9c625SLionel Sambuc 	MARK m;
44584d9c625SLionel Sambuc 	db_recno_t lno;
44684d9c625SLionel Sambuc 	int didop;
44784d9c625SLionel Sambuc 	u_char *p;
44884d9c625SLionel Sambuc 	size_t size;
44984d9c625SLionel Sambuc 
45084d9c625SLionel Sambuc 	ep = sp->ep;
45184d9c625SLionel Sambuc 	if (F_ISSET(ep, F_NOLOG)) {
45284d9c625SLionel Sambuc 		msgq(sp, M_ERR,
45384d9c625SLionel Sambuc 	    "013|Logging not being performed, roll-forward not possible");
45484d9c625SLionel Sambuc 		return (1);
45584d9c625SLionel Sambuc 	}
45684d9c625SLionel Sambuc 
45784d9c625SLionel Sambuc 	if (log_compare(&ep->lsn_cur, &ep->lsn_high) >= 0) {
45884d9c625SLionel Sambuc 		msgq(sp, M_BERR, "014|No changes to re-do");
45984d9c625SLionel Sambuc 		return (1);
46084d9c625SLionel Sambuc 	}
46184d9c625SLionel Sambuc 	return __vi_log_traverse(sp, UNDO_FORWARD, rp);
46284d9c625SLionel Sambuc }
463