Home | History | Annotate | Line # | Download | only in common
log4.c revision 1.3.4.2
      1  1.3.4.2  yamt /*	$NetBSD: log4.c,v 1.3.4.2 2014/05/22 15:50:33 yamt Exp $	*/
      2  1.3.4.2  yamt /*-
      3  1.3.4.2  yamt  * Copyright (c) 1992, 1993, 1994
      4  1.3.4.2  yamt  *	The Regents of the University of California.  All rights reserved.
      5  1.3.4.2  yamt  * Copyright (c) 1992, 1993, 1994, 1995, 1996
      6  1.3.4.2  yamt  *	Keith Bostic.  All rights reserved.
      7  1.3.4.2  yamt  *
      8  1.3.4.2  yamt  * See the LICENSE file for redistribution information.
      9  1.3.4.2  yamt  */
     10  1.3.4.2  yamt 
     11  1.3.4.2  yamt #include "config.h"
     12  1.3.4.2  yamt 
     13  1.3.4.2  yamt #include <sys/cdefs.h>
     14  1.3.4.2  yamt #if 0
     15  1.3.4.2  yamt #ifndef lint
     16  1.3.4.2  yamt static const char sccsid[] = "Id: log4.c,v 10.3 2002/06/08 21:00:33 skimo Exp ";
     17  1.3.4.2  yamt #endif /* not lint */
     18  1.3.4.2  yamt #else
     19  1.3.4.2  yamt __RCSID("$NetBSD: log4.c,v 1.3.4.2 2014/05/22 15:50:33 yamt Exp $");
     20  1.3.4.2  yamt #endif
     21  1.3.4.2  yamt 
     22  1.3.4.2  yamt #include <sys/types.h>
     23  1.3.4.2  yamt #include <sys/queue.h>
     24  1.3.4.2  yamt #include <sys/stat.h>
     25  1.3.4.2  yamt 
     26  1.3.4.2  yamt #include <bitstring.h>
     27  1.3.4.2  yamt #include <errno.h>
     28  1.3.4.2  yamt #include <fcntl.h>
     29  1.3.4.2  yamt #include <limits.h>
     30  1.3.4.2  yamt #include <stdio.h>
     31  1.3.4.2  yamt #include <stdlib.h>
     32  1.3.4.2  yamt #include <string.h>
     33  1.3.4.2  yamt 
     34  1.3.4.2  yamt #include "common.h"
     35  1.3.4.2  yamt 
     36  1.3.4.2  yamt /*
     37  1.3.4.2  yamt  * The log consists of records, each containing a type byte and a variable
     38  1.3.4.2  yamt  * length byte string, as follows:
     39  1.3.4.2  yamt  *
     40  1.3.4.2  yamt  *	LOG_CURSOR_INIT		MARK
     41  1.3.4.2  yamt  *	LOG_CURSOR_END		MARK
     42  1.3.4.2  yamt  *	LOG_LINE_APPEND_F 	db_recno_t		char *
     43  1.3.4.2  yamt  *	LOG_LINE_APPEND_B 	db_recno_t		char *
     44  1.3.4.2  yamt  *	LOG_LINE_DELETE_F	db_recno_t		char *
     45  1.3.4.2  yamt  *	LOG_LINE_DELETE_B	db_recno_t		char *
     46  1.3.4.2  yamt  *	LOG_LINE_RESET_F	db_recno_t		char *
     47  1.3.4.2  yamt  *	LOG_LINE_RESET_B	db_recno_t		char *
     48  1.3.4.2  yamt  *	LOG_MARK		LMARK
     49  1.3.4.2  yamt  *
     50  1.3.4.2  yamt  * We do before image physical logging.  This means that the editor layer
     51  1.3.4.2  yamt  * MAY NOT modify records in place, even if simply deleting or overwriting
     52  1.3.4.2  yamt  * characters.  Since the smallest unit of logging is a line, we're using
     53  1.3.4.2  yamt  * up lots of space.  This may eventually have to be reduced, probably by
     54  1.3.4.2  yamt  * doing logical logging, which is a much cooler database phrase.
     55  1.3.4.2  yamt  *
     56  1.3.4.2  yamt  * The implementation of the historic vi 'u' command, using roll-forward and
     57  1.3.4.2  yamt  * roll-back, is simple.  Each set of changes has a LOG_CURSOR_INIT record,
     58  1.3.4.2  yamt  * followed by a number of other records, followed by a LOG_CURSOR_END record.
     59  1.3.4.2  yamt  * LOG_LINE_RESET records come in pairs.  The first is a LOG_LINE_RESET_B
     60  1.3.4.2  yamt  * record, and is the line before the change.  The second is LOG_LINE_RESET_F,
     61  1.3.4.2  yamt  * and is the line after the change.  Roll-back is done by backing up to the
     62  1.3.4.2  yamt  * first LOG_CURSOR_INIT record before a change.  Roll-forward is done in a
     63  1.3.4.2  yamt  * similar fashion.
     64  1.3.4.2  yamt  *
     65  1.3.4.2  yamt  * The 'U' command is implemented by rolling backward to a LOG_CURSOR_END
     66  1.3.4.2  yamt  * record for a line different from the current one.  It should be noted that
     67  1.3.4.2  yamt  * this means that a subsequent 'u' command will make a change based on the
     68  1.3.4.2  yamt  * new position of the log's cursor.  This is okay, and, in fact, historic vi
     69  1.3.4.2  yamt  * behaved that way.
     70  1.3.4.2  yamt  */
     71  1.3.4.2  yamt 
     72  1.3.4.2  yamt static int	log_cursor1 __P((SCR *, int));
     73  1.3.4.2  yamt 
     74  1.3.4.2  yamt /*
     75  1.3.4.2  yamt  * log_init --
     76  1.3.4.2  yamt  *	Initialize the logging subsystem.
     77  1.3.4.2  yamt  *
     78  1.3.4.2  yamt  * PUBLIC: int log_init __P((SCR *, EXF *));
     79  1.3.4.2  yamt  */
     80  1.3.4.2  yamt int
     81  1.3.4.2  yamt log_init(SCR *sp, EXF *ep)
     82  1.3.4.2  yamt {
     83  1.3.4.2  yamt 	DB_LOGC *logc;
     84  1.3.4.2  yamt 	DBT data;
     85  1.3.4.2  yamt 	size_t nlen;
     86  1.3.4.2  yamt 
     87  1.3.4.2  yamt 	/*
     88  1.3.4.2  yamt 	 * !!!
     89  1.3.4.2  yamt 	 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
     90  1.3.4.2  yamt 	 *
     91  1.3.4.2  yamt 	 * Initialize the buffer.  The logging subsystem has its own
     92  1.3.4.2  yamt 	 * buffers because the global ones are almost by definition
     93  1.3.4.2  yamt 	 * going to be in use when the log runs.
     94  1.3.4.2  yamt 	 */
     95  1.3.4.2  yamt 	sp->wp->l_lp = NULL;
     96  1.3.4.2  yamt 	sp->wp->l_len = 0;
     97  1.3.4.2  yamt 	ep->l_cursor.lno = 1;		/* XXX Any valid recno. */
     98  1.3.4.2  yamt 	ep->l_cursor.cno = 0;
     99  1.3.4.2  yamt 	ep->l_high = ep->l_cur = 1;
    100  1.3.4.2  yamt 
    101  1.3.4.2  yamt 	if ((sp->db_error = ep->env->log_cursor(ep->env, &logc, 0))
    102  1.3.4.2  yamt 		    != 0) {
    103  1.3.4.2  yamt 		msgq(sp, M_DBERR, "env->log_cursor");
    104  1.3.4.2  yamt 		F_SET(ep, F_NOLOG);
    105  1.3.4.2  yamt 		return (1);
    106  1.3.4.2  yamt 	}
    107  1.3.4.2  yamt 	nlen = 1024;
    108  1.3.4.2  yamt retry:
    109  1.3.4.2  yamt 	BINC_GOTO(sp, sp->wp->l_lp, sp->wp->l_len, nlen);
    110  1.3.4.2  yamt 	memset(&data, 0, sizeof(data));
    111  1.3.4.2  yamt 	data.data = sp->wp->l_lp;
    112  1.3.4.2  yamt 	data.ulen = sp->wp->l_len;
    113  1.3.4.2  yamt 	data.flags = DB_DBT_USERMEM;
    114  1.3.4.2  yamt 	switch ((sp->db_error =
    115  1.3.4.2  yamt 	    logc->get(logc, &ep->lsn_first, &data, DB_LAST))) {
    116  1.3.4.2  yamt 	case ENOMEM:
    117  1.3.4.2  yamt 		nlen = data.size;
    118  1.3.4.2  yamt 		goto retry;
    119  1.3.4.2  yamt 	default:
    120  1.3.4.2  yamt alloc_err:
    121  1.3.4.2  yamt 		msgq(sp, M_DBERR, "logc->get");
    122  1.3.4.2  yamt 		F_SET(ep, F_NOLOG);
    123  1.3.4.2  yamt 		return (1);
    124  1.3.4.2  yamt 	case 0:
    125  1.3.4.2  yamt 		;
    126  1.3.4.2  yamt 	}
    127  1.3.4.2  yamt 	MEMCPY(&ep->lsn_cur, &ep->lsn_first, 1);
    128  1.3.4.2  yamt 	MEMCPY(&ep->lsn_high, &ep->lsn_first, 1);
    129  1.3.4.2  yamt 	logc->close(logc, 0);
    130  1.3.4.2  yamt 
    131  1.3.4.2  yamt 	ep->l_win = NULL;
    132  1.3.4.2  yamt 	/*LOCK_INIT(sp->wp, ep);*/
    133  1.3.4.2  yamt 
    134  1.3.4.2  yamt 	return (0);
    135  1.3.4.2  yamt }
    136  1.3.4.2  yamt 
    137  1.3.4.2  yamt /*
    138  1.3.4.2  yamt  * log_end --
    139  1.3.4.2  yamt  *	Close the logging subsystem.
    140  1.3.4.2  yamt  *
    141  1.3.4.2  yamt  * PUBLIC: int log_end __P((SCR *, EXF *));
    142  1.3.4.2  yamt  */
    143  1.3.4.2  yamt int
    144  1.3.4.2  yamt log_end(SCR *sp, EXF *ep)
    145  1.3.4.2  yamt {
    146  1.3.4.2  yamt 	/*
    147  1.3.4.2  yamt 	 * !!!
    148  1.3.4.2  yamt 	 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
    149  1.3.4.2  yamt 	 */
    150  1.3.4.2  yamt 	/*LOCK_END(sp->wp, ep);*/
    151  1.3.4.2  yamt 	if (sp->wp->l_lp != NULL) {
    152  1.3.4.2  yamt 		free(sp->wp->l_lp);
    153  1.3.4.2  yamt 		sp->wp->l_lp = NULL;
    154  1.3.4.2  yamt 	}
    155  1.3.4.2  yamt 	sp->wp->l_len = 0;
    156  1.3.4.2  yamt 	ep->l_cursor.lno = 1;		/* XXX Any valid recno. */
    157  1.3.4.2  yamt 	ep->l_cursor.cno = 0;
    158  1.3.4.2  yamt 	ep->l_high = ep->l_cur = 1;
    159  1.3.4.2  yamt 	return (0);
    160  1.3.4.2  yamt }
    161  1.3.4.2  yamt 
    162  1.3.4.2  yamt /*
    163  1.3.4.2  yamt  * log_cursor --
    164  1.3.4.2  yamt  *	Log the current cursor position, starting an event.
    165  1.3.4.2  yamt  *
    166  1.3.4.2  yamt  * PUBLIC: int log_cursor __P((SCR *));
    167  1.3.4.2  yamt  */
    168  1.3.4.2  yamt int
    169  1.3.4.2  yamt log_cursor(SCR *sp)
    170  1.3.4.2  yamt {
    171  1.3.4.2  yamt 	EXF *ep;
    172  1.3.4.2  yamt 
    173  1.3.4.2  yamt 	ep = sp->ep;
    174  1.3.4.2  yamt 	if (F_ISSET(ep, F_NOLOG))
    175  1.3.4.2  yamt 		return (0);
    176  1.3.4.2  yamt 
    177  1.3.4.2  yamt 	/*
    178  1.3.4.2  yamt 	 * If any changes were made since the last cursor init,
    179  1.3.4.2  yamt 	 * put out the ending cursor record.
    180  1.3.4.2  yamt 	 */
    181  1.3.4.2  yamt 	if (ep->l_cursor.lno == OOBLNO) {
    182  1.3.4.2  yamt 		if (ep->l_win && ep->l_win != sp->wp)
    183  1.3.4.2  yamt 			return 0;
    184  1.3.4.2  yamt 		ep->l_cursor.lno = sp->lno;
    185  1.3.4.2  yamt 		ep->l_cursor.cno = sp->cno;
    186  1.3.4.2  yamt 		ep->l_win = NULL;
    187  1.3.4.2  yamt 		return (log_cursor1(sp, LOG_CURSOR_END));
    188  1.3.4.2  yamt 	}
    189  1.3.4.2  yamt 	ep->l_cursor.lno = sp->lno;
    190  1.3.4.2  yamt 	ep->l_cursor.cno = sp->cno;
    191  1.3.4.2  yamt 	return (0);
    192  1.3.4.2  yamt }
    193  1.3.4.2  yamt 
    194  1.3.4.2  yamt /*
    195  1.3.4.2  yamt  * log_cursor1 --
    196  1.3.4.2  yamt  *	Actually push a cursor record out.
    197  1.3.4.2  yamt  */
    198  1.3.4.2  yamt static int
    199  1.3.4.2  yamt log_cursor1(SCR *sp, int type)
    200  1.3.4.2  yamt {
    201  1.3.4.2  yamt 	DBT data, key;
    202  1.3.4.2  yamt 	EXF *ep;
    203  1.3.4.2  yamt 
    204  1.3.4.2  yamt 	ep = sp->ep;
    205  1.3.4.2  yamt 
    206  1.3.4.2  yamt 	/*
    207  1.3.4.2  yamt 	if (type == LOG_CURSOR_INIT &&
    208  1.3.4.2  yamt 	    LOCK_TRY(sp->wp, ep))
    209  1.3.4.2  yamt 		return 1;
    210  1.3.4.2  yamt 	*/
    211  1.3.4.2  yamt 
    212  1.3.4.2  yamt 	if (type == LOG_CURSOR_INIT &&
    213  1.3.4.2  yamt 	    (sp->db_error = __vi_log_truncate(ep)) != 0) {
    214  1.3.4.2  yamt 		msgq(sp, M_DBERR, "truncate");
    215  1.3.4.2  yamt 		return 1;
    216  1.3.4.2  yamt 	}
    217  1.3.4.2  yamt 	if ((sp->db_error =
    218  1.3.4.2  yamt 		__vi_cursor_log(ep->env, NULL, &ep->lsn_cur, 0, type,
    219  1.3.4.2  yamt 			    ep->l_cursor.lno, ep->l_cursor.cno)) != 0) {
    220  1.3.4.2  yamt 		msgq(sp, M_DBERR, "cursor_log");
    221  1.3.4.2  yamt 		return 1;
    222  1.3.4.2  yamt 	}
    223  1.3.4.2  yamt 	if (type == LOG_CURSOR_END) {
    224  1.3.4.2  yamt 		MEMCPY(&ep->lsn_high, &ep->lsn_cur, 1);
    225  1.3.4.2  yamt 		/* XXXX should not be needed */
    226  1.3.4.2  yamt 		ep->env->log_flush(ep->env, NULL);
    227  1.3.4.2  yamt 	}
    228  1.3.4.2  yamt 
    229  1.3.4.2  yamt #if defined(DEBUG) && 0
    230  1.3.4.2  yamt 	vtrace(sp, "%lu: %s: %u/%u\n", ep->l_cur,
    231  1.3.4.2  yamt 	    type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end",
    232  1.3.4.2  yamt 	    sp->lno, sp->cno);
    233  1.3.4.2  yamt #endif
    234  1.3.4.2  yamt 	/* Reset high water mark. */
    235  1.3.4.2  yamt 	ep->l_high = ++ep->l_cur;
    236  1.3.4.2  yamt 
    237  1.3.4.2  yamt 	/*
    238  1.3.4.2  yamt 	if (type == LOG_CURSOR_END)
    239  1.3.4.2  yamt 		LOCK_UNLOCK(sp->wp, ep);
    240  1.3.4.2  yamt 	*/
    241  1.3.4.2  yamt 	return (0);
    242  1.3.4.2  yamt }
    243  1.3.4.2  yamt 
    244  1.3.4.2  yamt /*
    245  1.3.4.2  yamt  * log_line --
    246  1.3.4.2  yamt  *	Log a line change.
    247  1.3.4.2  yamt  *
    248  1.3.4.2  yamt  * PUBLIC: int log_line __P((SCR *, db_recno_t, u_int));
    249  1.3.4.2  yamt  */
    250  1.3.4.2  yamt int
    251  1.3.4.2  yamt log_line(SCR *sp, db_recno_t lno, u_int action)
    252  1.3.4.2  yamt {
    253  1.3.4.2  yamt 	DBT data, key;
    254  1.3.4.2  yamt 	EXF *ep;
    255  1.3.4.2  yamt 	size_t len;
    256  1.3.4.2  yamt 	CHAR_T *lp;
    257  1.3.4.2  yamt 	db_recno_t lcur;
    258  1.3.4.2  yamt 
    259  1.3.4.2  yamt 	ep = sp->ep;
    260  1.3.4.2  yamt 	if (F_ISSET(ep, F_NOLOG))
    261  1.3.4.2  yamt 		return (0);
    262  1.3.4.2  yamt 
    263  1.3.4.2  yamt 	/*
    264  1.3.4.2  yamt 	 * XXX
    265  1.3.4.2  yamt 	 *
    266  1.3.4.2  yamt 	 * Kluge for vi.  Clear the EXF undo flag so that the
    267  1.3.4.2  yamt 	 * next 'u' command does a roll-back, regardless.
    268  1.3.4.2  yamt 	 */
    269  1.3.4.2  yamt 	F_CLR(ep, F_UNDO);
    270  1.3.4.2  yamt 
    271  1.3.4.2  yamt 	/* Put out one initial cursor record per set of changes. */
    272  1.3.4.2  yamt 	if (ep->l_cursor.lno != OOBLNO) {
    273  1.3.4.2  yamt 		if (log_cursor1(sp, LOG_CURSOR_INIT))
    274  1.3.4.2  yamt 			return (1);
    275  1.3.4.2  yamt 		ep->l_cursor.lno = OOBLNO;
    276  1.3.4.2  yamt 		ep->l_win = sp->wp;
    277  1.3.4.2  yamt 	} /*else if (ep->l_win != sp->wp) {
    278  1.3.4.2  yamt 		printf("log_line own: %p, this: %p\n", ep->l_win, sp->wp);
    279  1.3.4.2  yamt 		return 1;
    280  1.3.4.2  yamt 	}*/
    281  1.3.4.2  yamt 
    282  1.3.4.2  yamt 	if ((sp->db_error =
    283  1.3.4.2  yamt 		__vi_change_log(ep->env, NULL, &ep->lsn_cur, 0, action,
    284  1.3.4.2  yamt 			    lno)) != 0) {
    285  1.3.4.2  yamt 		msgq(sp, M_DBERR, "change_log");
    286  1.3.4.2  yamt 		return 1;
    287  1.3.4.2  yamt 	}
    288  1.3.4.2  yamt 
    289  1.3.4.2  yamt #if defined(DEBUG) && 0
    290  1.3.4.2  yamt 	switch (action) {
    291  1.3.4.2  yamt 	case LOG_LINE_APPEND_F:
    292  1.3.4.2  yamt 		vtrace(sp, "%u: log_line: append_f: %lu {%u}\n",
    293  1.3.4.2  yamt 		    ep->l_cur, lno, len);
    294  1.3.4.2  yamt 		break;
    295  1.3.4.2  yamt 	case LOG_LINE_APPEND_B:
    296  1.3.4.2  yamt 		vtrace(sp, "%u: log_line: append_b: %lu {%u}\n",
    297  1.3.4.2  yamt 		    ep->l_cur, lno, len);
    298  1.3.4.2  yamt 		break;
    299  1.3.4.2  yamt 	case LOG_LINE_DELETE_F:
    300  1.3.4.2  yamt 		vtrace(sp, "%lu: log_line: delete_f: %lu {%u}\n",
    301  1.3.4.2  yamt 		    ep->l_cur, lno, len);
    302  1.3.4.2  yamt 		break;
    303  1.3.4.2  yamt 	case LOG_LINE_DELETE_B:
    304  1.3.4.2  yamt 		vtrace(sp, "%lu: log_line: delete_b: %lu {%u}\n",
    305  1.3.4.2  yamt 		    ep->l_cur, lno, len);
    306  1.3.4.2  yamt 		break;
    307  1.3.4.2  yamt 	case LOG_LINE_RESET_F:
    308  1.3.4.2  yamt 		vtrace(sp, "%lu: log_line: reset_f: %lu {%u}\n",
    309  1.3.4.2  yamt 		    ep->l_cur, lno, len);
    310  1.3.4.2  yamt 		break;
    311  1.3.4.2  yamt 	case LOG_LINE_RESET_B:
    312  1.3.4.2  yamt 		vtrace(sp, "%lu: log_line: reset_b: %lu {%u}\n",
    313  1.3.4.2  yamt 		    ep->l_cur, lno, len);
    314  1.3.4.2  yamt 		break;
    315  1.3.4.2  yamt 	}
    316  1.3.4.2  yamt #endif
    317  1.3.4.2  yamt 	/* Reset high water mark. */
    318  1.3.4.2  yamt 	ep->l_high = ++ep->l_cur;
    319  1.3.4.2  yamt 
    320  1.3.4.2  yamt 	return (0);
    321  1.3.4.2  yamt }
    322  1.3.4.2  yamt 
    323  1.3.4.2  yamt /*
    324  1.3.4.2  yamt  * log_mark --
    325  1.3.4.2  yamt  *	Log a mark position.  For the log to work, we assume that there
    326  1.3.4.2  yamt  *	aren't any operations that just put out a log record -- this
    327  1.3.4.2  yamt  *	would mean that undo operations would only reset marks, and not
    328  1.3.4.2  yamt  *	cause any other change.
    329  1.3.4.2  yamt  *
    330  1.3.4.2  yamt  * PUBLIC: int log_mark __P((SCR *, LMARK *));
    331  1.3.4.2  yamt  */
    332  1.3.4.2  yamt int
    333  1.3.4.2  yamt log_mark(SCR *sp, LMARK *lmp)
    334  1.3.4.2  yamt {
    335  1.3.4.2  yamt 	DBT data, key;
    336  1.3.4.2  yamt 	EXF *ep;
    337  1.3.4.2  yamt 
    338  1.3.4.2  yamt 	ep = sp->ep;
    339  1.3.4.2  yamt 	if (F_ISSET(ep, F_NOLOG))
    340  1.3.4.2  yamt 		return (0);
    341  1.3.4.2  yamt 
    342  1.3.4.2  yamt 	/* Put out one initial cursor record per set of changes. */
    343  1.3.4.2  yamt 	if (ep->l_cursor.lno != OOBLNO) {
    344  1.3.4.2  yamt 		if (log_cursor1(sp, LOG_CURSOR_INIT))
    345  1.3.4.2  yamt 			return (1);
    346  1.3.4.2  yamt 		ep->l_cursor.lno = OOBLNO;
    347  1.3.4.2  yamt 		ep->l_win = sp->wp;
    348  1.3.4.2  yamt 	}
    349  1.3.4.2  yamt 
    350  1.3.4.2  yamt 	if ((sp->db_error =
    351  1.3.4.2  yamt 		__vi_mark_log(ep->env, NULL, &ep->lsn_cur, 0,
    352  1.3.4.2  yamt 			    lmp)) != 0) {
    353  1.3.4.2  yamt 		msgq(sp, M_DBERR, "cursor_log");
    354  1.3.4.2  yamt 		return 1;
    355  1.3.4.2  yamt 	}
    356  1.3.4.2  yamt 
    357  1.3.4.2  yamt #if defined(DEBUG) && 0
    358  1.3.4.2  yamt 	vtrace(sp, "%lu: mark %c: %lu/%u\n",
    359  1.3.4.2  yamt 	    ep->l_cur, lmp->name, lmp->lno, lmp->cno);
    360  1.3.4.2  yamt #endif
    361  1.3.4.2  yamt 	/* Reset high water mark. */
    362  1.3.4.2  yamt 	ep->l_high = ++ep->l_cur;
    363  1.3.4.2  yamt 	return (0);
    364  1.3.4.2  yamt }
    365  1.3.4.2  yamt 
    366  1.3.4.2  yamt /*
    367  1.3.4.2  yamt  * Log_backward --
    368  1.3.4.2  yamt  *	Roll the log backward one operation.
    369  1.3.4.2  yamt  *
    370  1.3.4.2  yamt  * PUBLIC: int log_backward __P((SCR *, MARK *));
    371  1.3.4.2  yamt  */
    372  1.3.4.2  yamt int
    373  1.3.4.2  yamt log_backward(SCR *sp, MARK *rp)
    374  1.3.4.2  yamt {
    375  1.3.4.2  yamt 	EXF *ep;
    376  1.3.4.2  yamt 	LMARK lm;
    377  1.3.4.2  yamt 	MARK m;
    378  1.3.4.2  yamt 	db_recno_t lno;
    379  1.3.4.2  yamt 	int didop;
    380  1.3.4.2  yamt 	u_char *p;
    381  1.3.4.2  yamt 	size_t size;
    382  1.3.4.2  yamt 
    383  1.3.4.2  yamt 	ep = sp->ep;
    384  1.3.4.2  yamt 	if (F_ISSET(ep, F_NOLOG)) {
    385  1.3.4.2  yamt 		msgq(sp, M_ERR,
    386  1.3.4.2  yamt 		    "010|Logging not being performed, undo not possible");
    387  1.3.4.2  yamt 		return (1);
    388  1.3.4.2  yamt 	}
    389  1.3.4.2  yamt 
    390  1.3.4.2  yamt 	if (log_compare(&ep->lsn_cur, &ep->lsn_first) <= 0) {
    391  1.3.4.2  yamt 		msgq(sp, M_BERR, "011|No changes to undo");
    392  1.3.4.2  yamt 		return (1);
    393  1.3.4.2  yamt 	}
    394  1.3.4.2  yamt 	return __vi_log_traverse(sp, UNDO_BACKWARD, rp);
    395  1.3.4.2  yamt }
    396  1.3.4.2  yamt 
    397  1.3.4.2  yamt /*
    398  1.3.4.2  yamt  * Log_setline --
    399  1.3.4.2  yamt  *	Reset the line to its original appearance.
    400  1.3.4.2  yamt  *
    401  1.3.4.2  yamt  * XXX
    402  1.3.4.2  yamt  * There's a bug in this code due to our not logging cursor movements
    403  1.3.4.2  yamt  * unless a change was made.  If you do a change, move off the line,
    404  1.3.4.2  yamt  * then move back on and do a 'U', the line will be restored to the way
    405  1.3.4.2  yamt  * it was before the original change.
    406  1.3.4.2  yamt  *
    407  1.3.4.2  yamt  * PUBLIC: int log_setline __P((SCR *));
    408  1.3.4.2  yamt  */
    409  1.3.4.2  yamt int
    410  1.3.4.2  yamt log_setline(SCR *sp)
    411  1.3.4.2  yamt {
    412  1.3.4.2  yamt 	EXF *ep;
    413  1.3.4.2  yamt 	LMARK lm;
    414  1.3.4.2  yamt 	MARK m;
    415  1.3.4.2  yamt 	db_recno_t lno;
    416  1.3.4.2  yamt 	u_char *p;
    417  1.3.4.2  yamt 	size_t size;
    418  1.3.4.2  yamt 
    419  1.3.4.2  yamt 	ep = sp->ep;
    420  1.3.4.2  yamt 	if (F_ISSET(ep, F_NOLOG)) {
    421  1.3.4.2  yamt 		msgq(sp, M_ERR,
    422  1.3.4.2  yamt 		    "012|Logging not being performed, undo not possible");
    423  1.3.4.2  yamt 		return (1);
    424  1.3.4.2  yamt 	}
    425  1.3.4.2  yamt 
    426  1.3.4.2  yamt 	if (log_compare(&ep->lsn_cur, &ep->lsn_first) <= 0) {
    427  1.3.4.2  yamt 		msgq(sp, M_BERR, "011|No changes to undo");
    428  1.3.4.2  yamt 		return (1);
    429  1.3.4.2  yamt 	}
    430  1.3.4.2  yamt 	return __vi_log_traverse(sp, UNDO_SETLINE, &m);
    431  1.3.4.2  yamt }
    432  1.3.4.2  yamt 
    433  1.3.4.2  yamt /*
    434  1.3.4.2  yamt  * Log_forward --
    435  1.3.4.2  yamt  *	Roll the log forward one operation.
    436  1.3.4.2  yamt  *
    437  1.3.4.2  yamt  * PUBLIC: int log_forward __P((SCR *, MARK *));
    438  1.3.4.2  yamt  */
    439  1.3.4.2  yamt int
    440  1.3.4.2  yamt log_forward(SCR *sp, MARK *rp)
    441  1.3.4.2  yamt {
    442  1.3.4.2  yamt 	EXF *ep;
    443  1.3.4.2  yamt 	LMARK lm;
    444  1.3.4.2  yamt 	MARK m;
    445  1.3.4.2  yamt 	db_recno_t lno;
    446  1.3.4.2  yamt 	int didop;
    447  1.3.4.2  yamt 	u_char *p;
    448  1.3.4.2  yamt 	size_t size;
    449  1.3.4.2  yamt 
    450  1.3.4.2  yamt 	ep = sp->ep;
    451  1.3.4.2  yamt 	if (F_ISSET(ep, F_NOLOG)) {
    452  1.3.4.2  yamt 		msgq(sp, M_ERR,
    453  1.3.4.2  yamt 	    "013|Logging not being performed, roll-forward not possible");
    454  1.3.4.2  yamt 		return (1);
    455  1.3.4.2  yamt 	}
    456  1.3.4.2  yamt 
    457  1.3.4.2  yamt 	if (log_compare(&ep->lsn_cur, &ep->lsn_high) >= 0) {
    458  1.3.4.2  yamt 		msgq(sp, M_BERR, "014|No changes to re-do");
    459  1.3.4.2  yamt 		return (1);
    460  1.3.4.2  yamt 	}
    461  1.3.4.2  yamt 	return __vi_log_traverse(sp, UNDO_FORWARD, rp);
    462  1.3.4.2  yamt }
    463