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