xref: /minix3/external/bsd/nvi/dist/common/log1.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: log1.c,v 1.4 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: log.c,v 10.26 2002/03/02 23:12:13 skimo Exp  (Berkeley) Date: 2002/03/02 23:12:13 ";
1784d9c625SLionel Sambuc #endif /* not lint */
18*0a6a1f1dSLionel Sambuc #else
19*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: log1.c,v 1.4 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 static void	log_err __P((SCR *, const char *, int));
7484d9c625SLionel Sambuc #if defined(LOGDEBUG) && defined(TRACE)
7584d9c625SLionel Sambuc static void	log_trace __P((SCR *, const char *, db_recno_t, u_char *));
7684d9c625SLionel Sambuc #endif
7784d9c625SLionel Sambuc 
7884d9c625SLionel Sambuc /* Try and restart the log on failure, i.e. if we run out of memory. */
7984d9c625SLionel Sambuc #define	LOG_ERR {							\
8084d9c625SLionel Sambuc 	log_err(sp, __FILE__, __LINE__);				\
8184d9c625SLionel Sambuc 	return (1);							\
8284d9c625SLionel Sambuc }
8384d9c625SLionel Sambuc 
8484d9c625SLionel Sambuc /* offset of CHAR_T string in log needs to be aligned on some systems
8584d9c625SLionel Sambuc  * because it is passed to db_set as a string
8684d9c625SLionel Sambuc  */
8784d9c625SLionel Sambuc typedef struct {
8884d9c625SLionel Sambuc     char    data[sizeof(u_char) /* type */ + sizeof(db_recno_t)];
8984d9c625SLionel Sambuc     CHAR_T  str[1];
9084d9c625SLionel Sambuc } log_t;
9184d9c625SLionel Sambuc #define CHAR_T_OFFSET ((char *)(((log_t*)0)->str) - (char *)0)
9284d9c625SLionel Sambuc 
9384d9c625SLionel Sambuc /*
9484d9c625SLionel Sambuc  * log_init --
9584d9c625SLionel Sambuc  *	Initialize the logging subsystem.
9684d9c625SLionel Sambuc  *
9784d9c625SLionel Sambuc  * PUBLIC: int log_init __P((SCR *, EXF *));
9884d9c625SLionel Sambuc  */
9984d9c625SLionel Sambuc int
log_init(SCR * sp,EXF * ep)10084d9c625SLionel Sambuc log_init(SCR *sp, EXF *ep)
10184d9c625SLionel Sambuc {
10284d9c625SLionel Sambuc 	/*
10384d9c625SLionel Sambuc 	 * !!!
10484d9c625SLionel Sambuc 	 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
10584d9c625SLionel Sambuc 	 *
10684d9c625SLionel Sambuc 	 * Initialize the buffer.  The logging subsystem has its own
10784d9c625SLionel Sambuc 	 * buffers because the global ones are almost by definition
10884d9c625SLionel Sambuc 	 * going to be in use when the log runs.
10984d9c625SLionel Sambuc 	 */
11084d9c625SLionel Sambuc 	sp->wp->l_lp = NULL;
11184d9c625SLionel Sambuc 	sp->wp->l_len = 0;
11284d9c625SLionel Sambuc 	ep->l_cursor.lno = 1;		/* XXX Any valid recno. */
11384d9c625SLionel Sambuc 	ep->l_cursor.cno = 0;
11484d9c625SLionel Sambuc 	ep->l_high = ep->l_cur = 1;
11584d9c625SLionel Sambuc 
11684d9c625SLionel Sambuc 	ep->log = dbopen(NULL, O_CREAT | O_NONBLOCK | O_RDWR,
11784d9c625SLionel Sambuc 	    S_IRUSR | S_IWUSR, DB_RECNO, NULL);
11884d9c625SLionel Sambuc 	if (ep->log == NULL) {
11984d9c625SLionel Sambuc 		msgq(sp, M_SYSERR, "009|Log file");
12084d9c625SLionel Sambuc 		F_SET(ep, F_NOLOG);
12184d9c625SLionel Sambuc 		return (1);
12284d9c625SLionel Sambuc 	}
12384d9c625SLionel Sambuc 
12484d9c625SLionel Sambuc 	ep->l_win = NULL;
12584d9c625SLionel Sambuc 	/*LOCK_INIT(sp->wp, ep);*/
12684d9c625SLionel Sambuc 
12784d9c625SLionel Sambuc 	return (0);
12884d9c625SLionel Sambuc }
12984d9c625SLionel Sambuc 
13084d9c625SLionel Sambuc /*
13184d9c625SLionel Sambuc  * log_end --
13284d9c625SLionel Sambuc  *	Close the logging subsystem.
13384d9c625SLionel Sambuc  *
13484d9c625SLionel Sambuc  * PUBLIC: int log_end __P((SCR *, EXF *));
13584d9c625SLionel Sambuc  */
13684d9c625SLionel Sambuc int
log_end(SCR * sp,EXF * ep)13784d9c625SLionel Sambuc log_end(SCR *sp, EXF *ep)
13884d9c625SLionel Sambuc {
13984d9c625SLionel Sambuc 	/*
14084d9c625SLionel Sambuc 	 * !!!
14184d9c625SLionel Sambuc 	 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
14284d9c625SLionel Sambuc 	 */
14384d9c625SLionel Sambuc 	/*LOCK_END(sp->wp, ep);*/
14484d9c625SLionel Sambuc 	if (ep->log != NULL) {
14584d9c625SLionel Sambuc 		(void)(ep->log->close)(ep->log);
14684d9c625SLionel Sambuc 		ep->log = NULL;
14784d9c625SLionel Sambuc 	}
14884d9c625SLionel Sambuc 	if (sp->wp->l_lp != NULL) {
14984d9c625SLionel Sambuc 		free(sp->wp->l_lp);
15084d9c625SLionel Sambuc 		sp->wp->l_lp = NULL;
15184d9c625SLionel Sambuc 	}
15284d9c625SLionel Sambuc 	sp->wp->l_len = 0;
15384d9c625SLionel Sambuc 	ep->l_cursor.lno = 1;		/* XXX Any valid recno. */
15484d9c625SLionel Sambuc 	ep->l_cursor.cno = 0;
15584d9c625SLionel Sambuc 	ep->l_high = ep->l_cur = 1;
15684d9c625SLionel Sambuc 	return (0);
15784d9c625SLionel Sambuc }
15884d9c625SLionel Sambuc 
15984d9c625SLionel Sambuc /*
16084d9c625SLionel Sambuc  * log_cursor --
16184d9c625SLionel Sambuc  *	Log the current cursor position, starting an event.
16284d9c625SLionel Sambuc  *
16384d9c625SLionel Sambuc  * PUBLIC: int log_cursor __P((SCR *));
16484d9c625SLionel Sambuc  */
16584d9c625SLionel Sambuc int
log_cursor(SCR * sp)16684d9c625SLionel Sambuc log_cursor(SCR *sp)
16784d9c625SLionel Sambuc {
16884d9c625SLionel Sambuc 	EXF *ep;
16984d9c625SLionel Sambuc 
17084d9c625SLionel Sambuc 	ep = sp->ep;
17184d9c625SLionel Sambuc 	if (F_ISSET(ep, F_NOLOG))
17284d9c625SLionel Sambuc 		return (0);
17384d9c625SLionel Sambuc 
17484d9c625SLionel Sambuc 	/*
17584d9c625SLionel Sambuc 	 * If any changes were made since the last cursor init,
17684d9c625SLionel Sambuc 	 * put out the ending cursor record.
17784d9c625SLionel Sambuc 	 */
17884d9c625SLionel Sambuc 	if (ep->l_cursor.lno == OOBLNO) {
17984d9c625SLionel Sambuc 		if (ep->l_win && ep->l_win != sp->wp)
18084d9c625SLionel Sambuc 			return 0;
18184d9c625SLionel Sambuc 		ep->l_cursor.lno = sp->lno;
18284d9c625SLionel Sambuc 		ep->l_cursor.cno = sp->cno;
18384d9c625SLionel Sambuc 		ep->l_win = NULL;
18484d9c625SLionel Sambuc 		return (log_cursor1(sp, LOG_CURSOR_END));
18584d9c625SLionel Sambuc 	}
18684d9c625SLionel Sambuc 	ep->l_cursor.lno = sp->lno;
18784d9c625SLionel Sambuc 	ep->l_cursor.cno = sp->cno;
18884d9c625SLionel Sambuc 	return (0);
18984d9c625SLionel Sambuc }
19084d9c625SLionel Sambuc 
19184d9c625SLionel Sambuc /*
19284d9c625SLionel Sambuc  * log_cursor1 --
19384d9c625SLionel Sambuc  *	Actually push a cursor record out.
19484d9c625SLionel Sambuc  */
19584d9c625SLionel Sambuc static int
log_cursor1(SCR * sp,int type)19684d9c625SLionel Sambuc log_cursor1(SCR *sp, int type)
19784d9c625SLionel Sambuc {
19884d9c625SLionel Sambuc 	DBT data, key;
19984d9c625SLionel Sambuc 	EXF *ep;
20084d9c625SLionel Sambuc 
20184d9c625SLionel Sambuc 	ep = sp->ep;
20284d9c625SLionel Sambuc 
20384d9c625SLionel Sambuc 	/*
20484d9c625SLionel Sambuc 	if (type == LOG_CURSOR_INIT &&
20584d9c625SLionel Sambuc 	    LOCK_TRY(sp->wp, ep))
20684d9c625SLionel Sambuc 		return 1;
20784d9c625SLionel Sambuc 	*/
20884d9c625SLionel Sambuc 
20984d9c625SLionel Sambuc 	BINC_RETC(sp, sp->wp->l_lp, sp->wp->l_len, sizeof(u_char) + sizeof(MARK));
21084d9c625SLionel Sambuc 	sp->wp->l_lp[0] = type;
21184d9c625SLionel Sambuc 	memmove(sp->wp->l_lp + sizeof(u_char), &ep->l_cursor, sizeof(MARK));
21284d9c625SLionel Sambuc 
21384d9c625SLionel Sambuc 	memset(&key, 0, sizeof(key));
21484d9c625SLionel Sambuc 	key.data = &ep->l_cur;
21584d9c625SLionel Sambuc 	key.size = sizeof(db_recno_t);
21684d9c625SLionel Sambuc 	memset(&data, 0, sizeof(data));
21784d9c625SLionel Sambuc 	data.data = sp->wp->l_lp;
21884d9c625SLionel Sambuc 	data.size = sizeof(u_char) + sizeof(MARK);
21984d9c625SLionel Sambuc 	if (ep->log->put(ep->log, &key, &data, 0) == -1)
22084d9c625SLionel Sambuc 		LOG_ERR;
22184d9c625SLionel Sambuc 
22284d9c625SLionel Sambuc #if defined(LOGDEBUG) && defined(TRACE)
22384d9c625SLionel Sambuc 	vtrace("%lu: %s: %u/%u\n", ep->l_cur,
22484d9c625SLionel Sambuc 	    type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end",
22584d9c625SLionel Sambuc 	    sp->lno, sp->cno);
22684d9c625SLionel Sambuc #endif
22784d9c625SLionel Sambuc 	/* Reset high water mark. */
22884d9c625SLionel Sambuc 	ep->l_high = ++ep->l_cur;
22984d9c625SLionel Sambuc 
23084d9c625SLionel Sambuc 	/*
23184d9c625SLionel Sambuc 	if (type == LOG_CURSOR_END)
23284d9c625SLionel Sambuc 		LOCK_UNLOCK(sp->wp, ep);
23384d9c625SLionel Sambuc 	*/
23484d9c625SLionel Sambuc 	return (0);
23584d9c625SLionel Sambuc }
23684d9c625SLionel Sambuc 
23784d9c625SLionel Sambuc /*
23884d9c625SLionel Sambuc  * log_line --
23984d9c625SLionel Sambuc  *	Log a line change.
24084d9c625SLionel Sambuc  *
24184d9c625SLionel Sambuc  * PUBLIC: int log_line __P((SCR *, db_recno_t, u_int));
24284d9c625SLionel Sambuc  */
24384d9c625SLionel Sambuc int
log_line(SCR * sp,db_recno_t lno,u_int action)24484d9c625SLionel Sambuc log_line(SCR *sp, db_recno_t lno, u_int action)
24584d9c625SLionel Sambuc {
24684d9c625SLionel Sambuc 	DBT data, key;
24784d9c625SLionel Sambuc 	EXF *ep;
24884d9c625SLionel Sambuc 	size_t len;
24984d9c625SLionel Sambuc 	CHAR_T *lp;
25084d9c625SLionel Sambuc 	db_recno_t lcur;
25184d9c625SLionel Sambuc 
25284d9c625SLionel Sambuc 	ep = sp->ep;
25384d9c625SLionel Sambuc 	if (F_ISSET(ep, F_NOLOG))
25484d9c625SLionel Sambuc 		return (0);
25584d9c625SLionel Sambuc 
25684d9c625SLionel Sambuc 	/*
25784d9c625SLionel Sambuc 	 * XXX
25884d9c625SLionel Sambuc 	 *
25984d9c625SLionel Sambuc 	 * Kluge for vi.  Clear the EXF undo flag so that the
26084d9c625SLionel Sambuc 	 * next 'u' command does a roll-back, regardless.
26184d9c625SLionel Sambuc 	 */
26284d9c625SLionel Sambuc 	F_CLR(ep, F_UNDO);
26384d9c625SLionel Sambuc 
26484d9c625SLionel Sambuc 	/* Put out one initial cursor record per set of changes. */
26584d9c625SLionel Sambuc 	if (ep->l_cursor.lno != OOBLNO) {
26684d9c625SLionel Sambuc 		if (log_cursor1(sp, LOG_CURSOR_INIT))
26784d9c625SLionel Sambuc 			return (1);
26884d9c625SLionel Sambuc 		ep->l_cursor.lno = OOBLNO;
26984d9c625SLionel Sambuc 		ep->l_win = sp->wp;
27084d9c625SLionel Sambuc 	} /*else if (ep->l_win != sp->wp) {
27184d9c625SLionel Sambuc 		printf("log_line own: %p, this: %p\n", ep->l_win, sp->wp);
27284d9c625SLionel Sambuc 		return 1;
27384d9c625SLionel Sambuc 	}*/
27484d9c625SLionel Sambuc 
27584d9c625SLionel Sambuc 	switch (action) {
27684d9c625SLionel Sambuc 	/* newly added for DB4 logging */
27784d9c625SLionel Sambuc 	case LOG_LINE_APPEND_B:
27884d9c625SLionel Sambuc 	case LOG_LINE_DELETE_F:
27984d9c625SLionel Sambuc 		return 0;
28084d9c625SLionel Sambuc 	}
28184d9c625SLionel Sambuc 
28284d9c625SLionel Sambuc 	/*
28384d9c625SLionel Sambuc 	 * Put out the changes.  If it's a LOG_LINE_RESET_B call, it's a
28484d9c625SLionel Sambuc 	 * special case, avoid the caches.  Also, if it fails and it's
28584d9c625SLionel Sambuc 	 * line 1, it just means that the user started with an empty file,
28684d9c625SLionel Sambuc 	 * so fake an empty length line.
28784d9c625SLionel Sambuc 	 */
28884d9c625SLionel Sambuc 	if (action == LOG_LINE_RESET_B) {
28984d9c625SLionel Sambuc 		if (db_get(sp, lno, DBG_NOCACHE, &lp, &len)) {
29084d9c625SLionel Sambuc 			static CHAR_T nul = 0;
29184d9c625SLionel Sambuc 			if (lno != 1) {
29284d9c625SLionel Sambuc 				db_err(sp, lno);
29384d9c625SLionel Sambuc 				return (1);
29484d9c625SLionel Sambuc 			}
29584d9c625SLionel Sambuc 			len = 0;
29684d9c625SLionel Sambuc 			lp = &nul;
29784d9c625SLionel Sambuc 		}
29884d9c625SLionel Sambuc 	} else
29984d9c625SLionel Sambuc 		if (db_get(sp, lno, DBG_FATAL, &lp, &len))
30084d9c625SLionel Sambuc 			return (1);
30184d9c625SLionel Sambuc 	BINC_RETC(sp,
30284d9c625SLionel Sambuc 	    sp->wp->l_lp, sp->wp->l_len,
30384d9c625SLionel Sambuc 	    len * sizeof(CHAR_T) + CHAR_T_OFFSET);
30484d9c625SLionel Sambuc 	sp->wp->l_lp[0] = action;
30584d9c625SLionel Sambuc 	memmove(sp->wp->l_lp + sizeof(u_char), &lno, sizeof(db_recno_t));
30684d9c625SLionel Sambuc 	MEMMOVEW(sp->wp->l_lp + CHAR_T_OFFSET, lp, len);
30784d9c625SLionel Sambuc 
30884d9c625SLionel Sambuc 	lcur = ep->l_cur;
30984d9c625SLionel Sambuc 	memset(&key, 0, sizeof(key));
31084d9c625SLionel Sambuc 	key.data = &lcur;
31184d9c625SLionel Sambuc 	key.size = sizeof(db_recno_t);
31284d9c625SLionel Sambuc 	memset(&data, 0, sizeof(data));
31384d9c625SLionel Sambuc 	data.data = sp->wp->l_lp;
31484d9c625SLionel Sambuc 	data.size = len * sizeof(CHAR_T) + CHAR_T_OFFSET;
31584d9c625SLionel Sambuc 	if (ep->log->put(ep->log, &key, &data, 0) == -1)
31684d9c625SLionel Sambuc 		LOG_ERR;
31784d9c625SLionel Sambuc 
31884d9c625SLionel Sambuc #if defined(LOGDEBUG) && defined(TRACE)
31984d9c625SLionel Sambuc 	switch (action) {
32084d9c625SLionel Sambuc 	case LOG_LINE_APPEND_F:
32184d9c625SLionel Sambuc 		vtrace("%u: log_line: append_f: %lu {%u}\n",
32284d9c625SLionel Sambuc 		    ep->l_cur, lno, len);
32384d9c625SLionel Sambuc 		break;
32484d9c625SLionel Sambuc 	case LOG_LINE_APPEND_B:
32584d9c625SLionel Sambuc 		vtrace("%u: log_line: append_b: %lu {%u}\n",
32684d9c625SLionel Sambuc 		    ep->l_cur, lno, len);
32784d9c625SLionel Sambuc 		break;
32884d9c625SLionel Sambuc 	case LOG_LINE_DELETE_F:
32984d9c625SLionel Sambuc 		vtrace("%lu: log_line: delete_f: %lu {%u}\n",
33084d9c625SLionel Sambuc 		    ep->l_cur, lno, len);
33184d9c625SLionel Sambuc 		break;
33284d9c625SLionel Sambuc 	case LOG_LINE_DELETE_B:
33384d9c625SLionel Sambuc 		vtrace("%lu: log_line: delete_b: %lu {%u}\n",
33484d9c625SLionel Sambuc 		    ep->l_cur, lno, len);
33584d9c625SLionel Sambuc 		break;
33684d9c625SLionel Sambuc 	case LOG_LINE_RESET_F:
33784d9c625SLionel Sambuc 		vtrace("%lu: log_line: reset_f: %lu {%u}\n",
33884d9c625SLionel Sambuc 		    ep->l_cur, lno, len);
33984d9c625SLionel Sambuc 		break;
34084d9c625SLionel Sambuc 	case LOG_LINE_RESET_B:
34184d9c625SLionel Sambuc 		vtrace("%lu: log_line: reset_b: %lu {%u}\n",
34284d9c625SLionel Sambuc 		    ep->l_cur, lno, len);
34384d9c625SLionel Sambuc 		break;
34484d9c625SLionel Sambuc 	}
34584d9c625SLionel Sambuc #endif
34684d9c625SLionel Sambuc 	/* Reset high water mark. */
34784d9c625SLionel Sambuc 	ep->l_high = ++ep->l_cur;
34884d9c625SLionel Sambuc 
34984d9c625SLionel Sambuc 	return (0);
35084d9c625SLionel Sambuc }
35184d9c625SLionel Sambuc 
35284d9c625SLionel Sambuc /*
35384d9c625SLionel Sambuc  * log_mark --
35484d9c625SLionel Sambuc  *	Log a mark position.  For the log to work, we assume that there
35584d9c625SLionel Sambuc  *	aren't any operations that just put out a log record -- this
35684d9c625SLionel Sambuc  *	would mean that undo operations would only reset marks, and not
35784d9c625SLionel Sambuc  *	cause any other change.
35884d9c625SLionel Sambuc  *
35984d9c625SLionel Sambuc  * PUBLIC: int log_mark __P((SCR *, LMARK *));
36084d9c625SLionel Sambuc  */
36184d9c625SLionel Sambuc int
log_mark(SCR * sp,LMARK * lmp)36284d9c625SLionel Sambuc log_mark(SCR *sp, LMARK *lmp)
36384d9c625SLionel Sambuc {
36484d9c625SLionel Sambuc 	DBT data, key;
36584d9c625SLionel Sambuc 	EXF *ep;
36684d9c625SLionel Sambuc 
36784d9c625SLionel Sambuc 	ep = sp->ep;
36884d9c625SLionel Sambuc 	if (F_ISSET(ep, F_NOLOG))
36984d9c625SLionel Sambuc 		return (0);
37084d9c625SLionel Sambuc 
37184d9c625SLionel Sambuc 	/* Put out one initial cursor record per set of changes. */
37284d9c625SLionel Sambuc 	if (ep->l_cursor.lno != OOBLNO) {
37384d9c625SLionel Sambuc 		if (log_cursor1(sp, LOG_CURSOR_INIT))
37484d9c625SLionel Sambuc 			return (1);
37584d9c625SLionel Sambuc 		ep->l_cursor.lno = OOBLNO;
37684d9c625SLionel Sambuc 		ep->l_win = sp->wp;
37784d9c625SLionel Sambuc 	}
37884d9c625SLionel Sambuc 
37984d9c625SLionel Sambuc 	BINC_RETC(sp, sp->wp->l_lp,
38084d9c625SLionel Sambuc 	    sp->wp->l_len, sizeof(u_char) + sizeof(LMARK));
38184d9c625SLionel Sambuc 	sp->wp->l_lp[0] = LOG_MARK;
38284d9c625SLionel Sambuc 	memmove(sp->wp->l_lp + sizeof(u_char), lmp, sizeof(LMARK));
38384d9c625SLionel Sambuc 
38484d9c625SLionel Sambuc 	memset(&key, 0, sizeof(key));
38584d9c625SLionel Sambuc 	key.data = &ep->l_cur;
38684d9c625SLionel Sambuc 	key.size = sizeof(db_recno_t);
38784d9c625SLionel Sambuc 	memset(&data, 0, sizeof(data));
38884d9c625SLionel Sambuc 	data.data = sp->wp->l_lp;
38984d9c625SLionel Sambuc 	data.size = sizeof(u_char) + sizeof(LMARK);
39084d9c625SLionel Sambuc 	if (ep->log->put(ep->log, &key, &data, 0) == -1)
39184d9c625SLionel Sambuc 		LOG_ERR;
39284d9c625SLionel Sambuc 
39384d9c625SLionel Sambuc #if defined(LOGDEBUG) && defined(TRACE)
39484d9c625SLionel Sambuc 	vtrace("%lu: mark %c: %lu/%u\n",
39584d9c625SLionel Sambuc 	    ep->l_cur, lmp->name, lmp->lno, lmp->cno);
39684d9c625SLionel Sambuc #endif
39784d9c625SLionel Sambuc 	/* Reset high water mark. */
39884d9c625SLionel Sambuc 	ep->l_high = ++ep->l_cur;
39984d9c625SLionel Sambuc 	return (0);
40084d9c625SLionel Sambuc }
40184d9c625SLionel Sambuc 
40284d9c625SLionel Sambuc /*
40384d9c625SLionel Sambuc  * Log_backward --
40484d9c625SLionel Sambuc  *	Roll the log backward one operation.
40584d9c625SLionel Sambuc  *
40684d9c625SLionel Sambuc  * PUBLIC: int log_backward __P((SCR *, MARK *));
40784d9c625SLionel Sambuc  */
40884d9c625SLionel Sambuc int
log_backward(SCR * sp,MARK * rp)40984d9c625SLionel Sambuc log_backward(SCR *sp, MARK *rp)
41084d9c625SLionel Sambuc {
41184d9c625SLionel Sambuc 	DBT key, data;
41284d9c625SLionel Sambuc 	EXF *ep;
41384d9c625SLionel Sambuc 	LMARK lm;
41484d9c625SLionel Sambuc 	MARK m;
41584d9c625SLionel Sambuc 	db_recno_t lno;
41684d9c625SLionel Sambuc 	int didop;
41784d9c625SLionel Sambuc 	u_char *p;
41884d9c625SLionel Sambuc 
41984d9c625SLionel Sambuc 	ep = sp->ep;
42084d9c625SLionel Sambuc 	if (F_ISSET(ep, F_NOLOG)) {
42184d9c625SLionel Sambuc 		msgq(sp, M_ERR,
42284d9c625SLionel Sambuc 		    "010|Logging not being performed, undo not possible");
42384d9c625SLionel Sambuc 		return (1);
42484d9c625SLionel Sambuc 	}
42584d9c625SLionel Sambuc 
42684d9c625SLionel Sambuc 	if (ep->l_cur == 1) {
42784d9c625SLionel Sambuc 		msgq(sp, M_BERR, "011|No changes to undo");
42884d9c625SLionel Sambuc 		return (1);
42984d9c625SLionel Sambuc 	}
43084d9c625SLionel Sambuc 
43184d9c625SLionel Sambuc 	if (ep->l_win && ep->l_win != sp->wp) {
43284d9c625SLionel Sambuc 		ex_emsg(sp, NULL, EXM_LOCKED);
43384d9c625SLionel Sambuc 		return 1;
43484d9c625SLionel Sambuc 	}
43584d9c625SLionel Sambuc 	ep->l_win = sp->wp;
43684d9c625SLionel Sambuc 
43784d9c625SLionel Sambuc 
43884d9c625SLionel Sambuc 	F_SET(ep, F_NOLOG);		/* Turn off logging. */
43984d9c625SLionel Sambuc 
44084d9c625SLionel Sambuc 	key.data = &ep->l_cur;		/* Initialize db request. */
44184d9c625SLionel Sambuc 	key.size = sizeof(recno_t);
44284d9c625SLionel Sambuc 	for (didop = 0;;) {
44384d9c625SLionel Sambuc 		--ep->l_cur;
44484d9c625SLionel Sambuc 		if (ep->log->get(ep->log, &key, &data, 0))
44584d9c625SLionel Sambuc 			LOG_ERR;
44684d9c625SLionel Sambuc #if defined(LOGDEBUG) && defined(TRACE)
44784d9c625SLionel Sambuc 		log_trace(sp, "log_backward", ep->l_cur, data.data);
44884d9c625SLionel Sambuc #endif
44984d9c625SLionel Sambuc 		switch (*(p = (u_char *)data.data)) {
45084d9c625SLionel Sambuc 		case LOG_CURSOR_INIT:
45184d9c625SLionel Sambuc 			if (didop) {
45284d9c625SLionel Sambuc 				memmove(rp, p + sizeof(u_char), sizeof(MARK));
45384d9c625SLionel Sambuc 				F_CLR(ep, F_NOLOG);
45484d9c625SLionel Sambuc 				ep->l_win = NULL;
45584d9c625SLionel Sambuc 				return (0);
45684d9c625SLionel Sambuc 			}
45784d9c625SLionel Sambuc 			break;
45884d9c625SLionel Sambuc 		case LOG_CURSOR_END:
45984d9c625SLionel Sambuc 			break;
46084d9c625SLionel Sambuc 		case LOG_LINE_APPEND_F:
46184d9c625SLionel Sambuc 			didop = 1;
46284d9c625SLionel Sambuc 			memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
46384d9c625SLionel Sambuc 			if (db_delete(sp, lno))
46484d9c625SLionel Sambuc 				goto err;
46584d9c625SLionel Sambuc 			++sp->rptlines[L_DELETED];
46684d9c625SLionel Sambuc 			break;
46784d9c625SLionel Sambuc 		case LOG_LINE_DELETE_B:
46884d9c625SLionel Sambuc 			didop = 1;
46984d9c625SLionel Sambuc 			memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
47084d9c625SLionel Sambuc 			if (db_insert(sp, lno,
47184d9c625SLionel Sambuc 			    (CHAR_T *)(p + CHAR_T_OFFSET),
47284d9c625SLionel Sambuc 			    (data.size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
47384d9c625SLionel Sambuc 				goto err;
47484d9c625SLionel Sambuc 			++sp->rptlines[L_ADDED];
47584d9c625SLionel Sambuc 			break;
47684d9c625SLionel Sambuc 		case LOG_LINE_RESET_F:
47784d9c625SLionel Sambuc 			break;
47884d9c625SLionel Sambuc 		case LOG_LINE_RESET_B:
47984d9c625SLionel Sambuc 			didop = 1;
48084d9c625SLionel Sambuc 			memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
48184d9c625SLionel Sambuc 			if (db_set(sp, lno,
48284d9c625SLionel Sambuc 			    (CHAR_T *)(p + CHAR_T_OFFSET),
48384d9c625SLionel Sambuc 			    (data.size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
48484d9c625SLionel Sambuc 				goto err;
48584d9c625SLionel Sambuc 			if (sp->rptlchange != lno) {
48684d9c625SLionel Sambuc 				sp->rptlchange = lno;
48784d9c625SLionel Sambuc 				++sp->rptlines[L_CHANGED];
48884d9c625SLionel Sambuc 			}
48984d9c625SLionel Sambuc 			break;
49084d9c625SLionel Sambuc 		case LOG_MARK:
49184d9c625SLionel Sambuc 			didop = 1;
49284d9c625SLionel Sambuc 			memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
49384d9c625SLionel Sambuc 			m.lno = lm.lno;
49484d9c625SLionel Sambuc 			m.cno = lm.cno;
49584d9c625SLionel Sambuc 			if (mark_set(sp, lm.name, &m, 0))
49684d9c625SLionel Sambuc 				goto err;
49784d9c625SLionel Sambuc 			break;
49884d9c625SLionel Sambuc 		default:
49984d9c625SLionel Sambuc 			abort();
50084d9c625SLionel Sambuc 		}
50184d9c625SLionel Sambuc 	}
50284d9c625SLionel Sambuc 
50384d9c625SLionel Sambuc err:	F_CLR(ep, F_NOLOG);
50484d9c625SLionel Sambuc 	ep->l_win = NULL;
50584d9c625SLionel Sambuc 	return (1);
50684d9c625SLionel Sambuc }
50784d9c625SLionel Sambuc 
50884d9c625SLionel Sambuc /*
50984d9c625SLionel Sambuc  * Log_setline --
51084d9c625SLionel Sambuc  *	Reset the line to its original appearance.
51184d9c625SLionel Sambuc  *
51284d9c625SLionel Sambuc  * XXX
51384d9c625SLionel Sambuc  * There's a bug in this code due to our not logging cursor movements
51484d9c625SLionel Sambuc  * unless a change was made.  If you do a change, move off the line,
51584d9c625SLionel Sambuc  * then move back on and do a 'U', the line will be restored to the way
51684d9c625SLionel Sambuc  * it was before the original change.
51784d9c625SLionel Sambuc  *
51884d9c625SLionel Sambuc  * PUBLIC: int log_setline __P((SCR *));
51984d9c625SLionel Sambuc  */
52084d9c625SLionel Sambuc int
log_setline(SCR * sp)52184d9c625SLionel Sambuc log_setline(SCR *sp)
52284d9c625SLionel Sambuc {
52384d9c625SLionel Sambuc 	DBT key, data;
52484d9c625SLionel Sambuc 	EXF *ep;
52584d9c625SLionel Sambuc 	LMARK lm;
52684d9c625SLionel Sambuc 	MARK m;
52784d9c625SLionel Sambuc 	db_recno_t lno;
52884d9c625SLionel Sambuc 	u_char *p;
52984d9c625SLionel Sambuc 
53084d9c625SLionel Sambuc 	ep = sp->ep;
53184d9c625SLionel Sambuc 	if (F_ISSET(ep, F_NOLOG)) {
53284d9c625SLionel Sambuc 		msgq(sp, M_ERR,
53384d9c625SLionel Sambuc 		    "012|Logging not being performed, undo not possible");
53484d9c625SLionel Sambuc 		return (1);
53584d9c625SLionel Sambuc 	}
53684d9c625SLionel Sambuc 
53784d9c625SLionel Sambuc 	if (ep->l_cur == 1)
53884d9c625SLionel Sambuc 		return (1);
53984d9c625SLionel Sambuc 
54084d9c625SLionel Sambuc 	if (ep->l_win && ep->l_win != sp->wp) {
54184d9c625SLionel Sambuc 		ex_emsg(sp, NULL, EXM_LOCKED);
54284d9c625SLionel Sambuc 		return 1;
54384d9c625SLionel Sambuc 	}
54484d9c625SLionel Sambuc 	ep->l_win = sp->wp;
54584d9c625SLionel Sambuc 
54684d9c625SLionel Sambuc 	F_SET(ep, F_NOLOG);		/* Turn off logging. */
54784d9c625SLionel Sambuc 
54884d9c625SLionel Sambuc 	key.data = &ep->l_cur;		/* Initialize db request. */
54984d9c625SLionel Sambuc 	key.size = sizeof(recno_t);
55084d9c625SLionel Sambuc 
55184d9c625SLionel Sambuc 	for (;;) {
55284d9c625SLionel Sambuc 		--ep->l_cur;
55384d9c625SLionel Sambuc 		if (ep->log->get(ep->log, &key, &data, 0))
55484d9c625SLionel Sambuc 			LOG_ERR;
55584d9c625SLionel Sambuc #if defined(LOGDEBUG) && defined(TRACE)
55684d9c625SLionel Sambuc 		log_trace(sp, "log_setline", ep->l_cur, data.data);
55784d9c625SLionel Sambuc #endif
55884d9c625SLionel Sambuc 		switch (*(p = (u_char *)data.data)) {
55984d9c625SLionel Sambuc 		case LOG_CURSOR_INIT:
56084d9c625SLionel Sambuc 			memmove(&m, p + sizeof(u_char), sizeof(MARK));
56184d9c625SLionel Sambuc 			if (m.lno != sp->lno || ep->l_cur == 1) {
56284d9c625SLionel Sambuc 				F_CLR(ep, F_NOLOG);
56384d9c625SLionel Sambuc 				ep->l_win = NULL;
56484d9c625SLionel Sambuc 				return (0);
56584d9c625SLionel Sambuc 			}
56684d9c625SLionel Sambuc 			break;
56784d9c625SLionel Sambuc 		case LOG_CURSOR_END:
56884d9c625SLionel Sambuc 			memmove(&m, p + sizeof(u_char), sizeof(MARK));
56984d9c625SLionel Sambuc 			if (m.lno != sp->lno) {
57084d9c625SLionel Sambuc 				++ep->l_cur;
57184d9c625SLionel Sambuc 				F_CLR(ep, F_NOLOG);
57284d9c625SLionel Sambuc 				ep->l_win = NULL;
57384d9c625SLionel Sambuc 				return (0);
57484d9c625SLionel Sambuc 			}
57584d9c625SLionel Sambuc 			break;
57684d9c625SLionel Sambuc 		case LOG_LINE_APPEND_F:
57784d9c625SLionel Sambuc 		case LOG_LINE_DELETE_B:
57884d9c625SLionel Sambuc 		case LOG_LINE_RESET_F:
57984d9c625SLionel Sambuc 			break;
58084d9c625SLionel Sambuc 		case LOG_LINE_RESET_B:
58184d9c625SLionel Sambuc 			memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
58284d9c625SLionel Sambuc 			if (lno == sp->lno &&
58384d9c625SLionel Sambuc 			    db_set(sp, lno, (CHAR_T *)(p + CHAR_T_OFFSET),
58484d9c625SLionel Sambuc 				(data.size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
58584d9c625SLionel Sambuc 				goto err;
58684d9c625SLionel Sambuc 			if (sp->rptlchange != lno) {
58784d9c625SLionel Sambuc 				sp->rptlchange = lno;
58884d9c625SLionel Sambuc 				++sp->rptlines[L_CHANGED];
58984d9c625SLionel Sambuc 			}
59084d9c625SLionel Sambuc 		case LOG_MARK:
59184d9c625SLionel Sambuc 			memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
59284d9c625SLionel Sambuc 			m.lno = lm.lno;
59384d9c625SLionel Sambuc 			m.cno = lm.cno;
59484d9c625SLionel Sambuc 			if (mark_set(sp, lm.name, &m, 0))
59584d9c625SLionel Sambuc 				goto err;
59684d9c625SLionel Sambuc 			break;
59784d9c625SLionel Sambuc 		default:
59884d9c625SLionel Sambuc 			abort();
59984d9c625SLionel Sambuc 		}
60084d9c625SLionel Sambuc 	}
60184d9c625SLionel Sambuc 
60284d9c625SLionel Sambuc err:	F_CLR(ep, F_NOLOG);
60384d9c625SLionel Sambuc 	ep->l_win = NULL;
60484d9c625SLionel Sambuc 	return (1);
60584d9c625SLionel Sambuc }
60684d9c625SLionel Sambuc 
60784d9c625SLionel Sambuc /*
60884d9c625SLionel Sambuc  * Log_forward --
60984d9c625SLionel Sambuc  *	Roll the log forward one operation.
61084d9c625SLionel Sambuc  *
61184d9c625SLionel Sambuc  * PUBLIC: int log_forward __P((SCR *, MARK *));
61284d9c625SLionel Sambuc  */
61384d9c625SLionel Sambuc int
log_forward(SCR * sp,MARK * rp)61484d9c625SLionel Sambuc log_forward(SCR *sp, MARK *rp)
61584d9c625SLionel Sambuc {
61684d9c625SLionel Sambuc 	DBT key, data;
61784d9c625SLionel Sambuc 	EXF *ep;
61884d9c625SLionel Sambuc 	LMARK lm;
61984d9c625SLionel Sambuc 	MARK m;
62084d9c625SLionel Sambuc 	db_recno_t lno;
62184d9c625SLionel Sambuc 	int didop;
62284d9c625SLionel Sambuc 	u_char *p;
62384d9c625SLionel Sambuc 
62484d9c625SLionel Sambuc 	ep = sp->ep;
62584d9c625SLionel Sambuc 	if (F_ISSET(ep, F_NOLOG)) {
62684d9c625SLionel Sambuc 		msgq(sp, M_ERR,
62784d9c625SLionel Sambuc 	    "013|Logging not being performed, roll-forward not possible");
62884d9c625SLionel Sambuc 		return (1);
62984d9c625SLionel Sambuc 	}
63084d9c625SLionel Sambuc 
63184d9c625SLionel Sambuc 	if (ep->l_cur == ep->l_high) {
63284d9c625SLionel Sambuc 		msgq(sp, M_BERR, "014|No changes to re-do");
63384d9c625SLionel Sambuc 		return (1);
63484d9c625SLionel Sambuc 	}
63584d9c625SLionel Sambuc 
63684d9c625SLionel Sambuc 	if (ep->l_win && ep->l_win != sp->wp) {
63784d9c625SLionel Sambuc 		ex_emsg(sp, NULL, EXM_LOCKED);
63884d9c625SLionel Sambuc 		return 1;
63984d9c625SLionel Sambuc 	}
64084d9c625SLionel Sambuc 	ep->l_win = sp->wp;
64184d9c625SLionel Sambuc 
64284d9c625SLionel Sambuc 	F_SET(ep, F_NOLOG);		/* Turn off logging. */
64384d9c625SLionel Sambuc 
64484d9c625SLionel Sambuc 	key.data = &ep->l_cur;		/* Initialize db request. */
64584d9c625SLionel Sambuc 	key.size = sizeof(recno_t);
64684d9c625SLionel Sambuc 	for (didop = 0;;) {
64784d9c625SLionel Sambuc 		++ep->l_cur;
64884d9c625SLionel Sambuc 		if (ep->log->get(ep->log, &key, &data, 0))
64984d9c625SLionel Sambuc 			LOG_ERR;
65084d9c625SLionel Sambuc #if defined(LOGDEBUG) && defined(TRACE)
65184d9c625SLionel Sambuc 		log_trace(sp, "log_forward", ep->l_cur, data.data);
65284d9c625SLionel Sambuc #endif
65384d9c625SLionel Sambuc 		switch (*(p = (u_char *)data.data)) {
65484d9c625SLionel Sambuc 		case LOG_CURSOR_END:
65584d9c625SLionel Sambuc 			if (didop) {
65684d9c625SLionel Sambuc 				++ep->l_cur;
65784d9c625SLionel Sambuc 				memmove(rp, p + sizeof(u_char), sizeof(MARK));
65884d9c625SLionel Sambuc 				F_CLR(ep, F_NOLOG);
65984d9c625SLionel Sambuc 				ep->l_win = NULL;
66084d9c625SLionel Sambuc 				return (0);
66184d9c625SLionel Sambuc 			}
66284d9c625SLionel Sambuc 			break;
66384d9c625SLionel Sambuc 		case LOG_CURSOR_INIT:
66484d9c625SLionel Sambuc 			break;
66584d9c625SLionel Sambuc 		case LOG_LINE_APPEND_F:
66684d9c625SLionel Sambuc 			didop = 1;
66784d9c625SLionel Sambuc 			memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
66884d9c625SLionel Sambuc 			if (db_insert(sp, lno,
66984d9c625SLionel Sambuc 			    (CHAR_T *)(p + CHAR_T_OFFSET),
67084d9c625SLionel Sambuc 			    (data.size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
67184d9c625SLionel Sambuc 				goto err;
67284d9c625SLionel Sambuc 			++sp->rptlines[L_ADDED];
67384d9c625SLionel Sambuc 			break;
67484d9c625SLionel Sambuc 		case LOG_LINE_DELETE_B:
67584d9c625SLionel Sambuc 			didop = 1;
67684d9c625SLionel Sambuc 			memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
67784d9c625SLionel Sambuc 			if (db_delete(sp, lno))
67884d9c625SLionel Sambuc 				goto err;
67984d9c625SLionel Sambuc 			++sp->rptlines[L_DELETED];
68084d9c625SLionel Sambuc 			break;
68184d9c625SLionel Sambuc 		case LOG_LINE_RESET_B:
68284d9c625SLionel Sambuc 			break;
68384d9c625SLionel Sambuc 		case LOG_LINE_RESET_F:
68484d9c625SLionel Sambuc 			didop = 1;
68584d9c625SLionel Sambuc 			memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
68684d9c625SLionel Sambuc 			if (db_set(sp, lno,
68784d9c625SLionel Sambuc 			    (CHAR_T *)(p + CHAR_T_OFFSET),
68884d9c625SLionel Sambuc 			    (data.size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
68984d9c625SLionel Sambuc 				goto err;
69084d9c625SLionel Sambuc 			if (sp->rptlchange != lno) {
69184d9c625SLionel Sambuc 				sp->rptlchange = lno;
69284d9c625SLionel Sambuc 				++sp->rptlines[L_CHANGED];
69384d9c625SLionel Sambuc 			}
69484d9c625SLionel Sambuc 			break;
69584d9c625SLionel Sambuc 		case LOG_MARK:
69684d9c625SLionel Sambuc 			didop = 1;
69784d9c625SLionel Sambuc 			memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
69884d9c625SLionel Sambuc 			m.lno = lm.lno;
69984d9c625SLionel Sambuc 			m.cno = lm.cno;
70084d9c625SLionel Sambuc 			if (mark_set(sp, lm.name, &m, 0))
70184d9c625SLionel Sambuc 				goto err;
70284d9c625SLionel Sambuc 			break;
70384d9c625SLionel Sambuc 		default:
70484d9c625SLionel Sambuc 			abort();
70584d9c625SLionel Sambuc 		}
70684d9c625SLionel Sambuc 	}
70784d9c625SLionel Sambuc 
70884d9c625SLionel Sambuc err:	F_CLR(ep, F_NOLOG);
70984d9c625SLionel Sambuc 	ep->l_win = NULL;
71084d9c625SLionel Sambuc 	return (1);
71184d9c625SLionel Sambuc }
71284d9c625SLionel Sambuc 
71384d9c625SLionel Sambuc /*
71484d9c625SLionel Sambuc  * log_err --
71584d9c625SLionel Sambuc  *	Try and restart the log on failure, i.e. if we run out of memory.
71684d9c625SLionel Sambuc  */
71784d9c625SLionel Sambuc static void
log_err(SCR * sp,const char * file,int line)71884d9c625SLionel Sambuc log_err(SCR *sp, const char *file, int line)
71984d9c625SLionel Sambuc {
72084d9c625SLionel Sambuc 	EXF *ep;
72184d9c625SLionel Sambuc 
72284d9c625SLionel Sambuc 	msgq(sp, M_SYSERR, "015|%s/%d: log put error", tail(file), line);
72384d9c625SLionel Sambuc 	ep = sp->ep;
72484d9c625SLionel Sambuc 	(void)ep->log->close(ep->log);
72584d9c625SLionel Sambuc 	if (!log_init(sp, ep))
72684d9c625SLionel Sambuc 		msgq(sp, M_ERR, "267|Log restarted");
72784d9c625SLionel Sambuc }
72884d9c625SLionel Sambuc 
72984d9c625SLionel Sambuc #if defined(LOGDEBUG) && defined(TRACE)
73084d9c625SLionel Sambuc static void
log_trace(sp,msg,rno,p)73184d9c625SLionel Sambuc log_trace(sp, msg, rno, p)
73284d9c625SLionel Sambuc 	SCR *sp;
73384d9c625SLionel Sambuc 	const char *msg;
73484d9c625SLionel Sambuc 	db_recno_t rno;
73584d9c625SLionel Sambuc 	u_char *p;
73684d9c625SLionel Sambuc {
73784d9c625SLionel Sambuc 	LMARK lm;
73884d9c625SLionel Sambuc 	MARK m;
73984d9c625SLionel Sambuc 	db_recno_t lno;
74084d9c625SLionel Sambuc 
74184d9c625SLionel Sambuc 	switch (*p) {
74284d9c625SLionel Sambuc 	case LOG_CURSOR_INIT:
74384d9c625SLionel Sambuc 		memmove(&m, p + sizeof(u_char), sizeof(MARK));
74484d9c625SLionel Sambuc 		vtrace("%lu: %s:  C_INIT: %u/%u\n", rno, msg, m.lno, m.cno);
74584d9c625SLionel Sambuc 		break;
74684d9c625SLionel Sambuc 	case LOG_CURSOR_END:
74784d9c625SLionel Sambuc 		memmove(&m, p + sizeof(u_char), sizeof(MARK));
74884d9c625SLionel Sambuc 		vtrace("%lu: %s:   C_END: %u/%u\n", rno, msg, m.lno, m.cno);
74984d9c625SLionel Sambuc 		break;
75084d9c625SLionel Sambuc 	case LOG_LINE_APPEND_F:
75184d9c625SLionel Sambuc 		memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
75284d9c625SLionel Sambuc 		vtrace("%lu: %s:  APPEND_F: %lu\n", rno, msg, lno);
75384d9c625SLionel Sambuc 		break;
75484d9c625SLionel Sambuc 	case LOG_LINE_APPEND_B:
75584d9c625SLionel Sambuc 		memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
75684d9c625SLionel Sambuc 		vtrace("%lu: %s:  APPEND_B: %lu\n", rno, msg, lno);
75784d9c625SLionel Sambuc 		break;
75884d9c625SLionel Sambuc 	case LOG_LINE_DELETE_F:
75984d9c625SLionel Sambuc 		memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
76084d9c625SLionel Sambuc 		vtrace("%lu: %s:  DELETE_F: %lu\n", rno, msg, lno);
76184d9c625SLionel Sambuc 		break;
76284d9c625SLionel Sambuc 	case LOG_LINE_DELETE_B:
76384d9c625SLionel Sambuc 		memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
76484d9c625SLionel Sambuc 		vtrace("%lu: %s:  DELETE_B: %lu\n", rno, msg, lno);
76584d9c625SLionel Sambuc 		break;
76684d9c625SLionel Sambuc 	case LOG_LINE_RESET_F:
76784d9c625SLionel Sambuc 		memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
76884d9c625SLionel Sambuc 		vtrace("%lu: %s: RESET_F: %lu\n", rno, msg, lno);
76984d9c625SLionel Sambuc 		break;
77084d9c625SLionel Sambuc 	case LOG_LINE_RESET_B:
77184d9c625SLionel Sambuc 		memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
77284d9c625SLionel Sambuc 		vtrace("%lu: %s: RESET_B: %lu\n", rno, msg, lno);
77384d9c625SLionel Sambuc 		break;
77484d9c625SLionel Sambuc 	case LOG_MARK:
77584d9c625SLionel Sambuc 		memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
77684d9c625SLionel Sambuc 		vtrace("%lu: %s:    MARK: %u/%u\n", rno, msg, lm.lno, lm.cno);
77784d9c625SLionel Sambuc 		break;
77884d9c625SLionel Sambuc 	default:
77984d9c625SLionel Sambuc 		abort();
78084d9c625SLionel Sambuc 	}
78184d9c625SLionel Sambuc }
78284d9c625SLionel Sambuc #endif
783