xref: /dflybsd-src/contrib/nvi2/common/log.c (revision e0b8e63ec8faba710eccfbba72a18b7831676e0c)
1*e0b8e63eSJohn Marino /*-
2*e0b8e63eSJohn Marino  * Copyright (c) 1992, 1993, 1994
3*e0b8e63eSJohn Marino  *	The Regents of the University of California.  All rights reserved.
4*e0b8e63eSJohn Marino  * Copyright (c) 1992, 1993, 1994, 1995, 1996
5*e0b8e63eSJohn Marino  *	Keith Bostic.  All rights reserved.
6*e0b8e63eSJohn Marino  *
7*e0b8e63eSJohn Marino  * See the LICENSE file for redistribution information.
8*e0b8e63eSJohn Marino  */
9*e0b8e63eSJohn Marino 
10*e0b8e63eSJohn Marino #include "config.h"
11*e0b8e63eSJohn Marino 
12*e0b8e63eSJohn Marino #ifndef lint
13*e0b8e63eSJohn Marino static const char sccsid[] = "$Id: log.c,v 10.27 2011/07/13 06:25:50 zy Exp $";
14*e0b8e63eSJohn Marino #endif /* not lint */
15*e0b8e63eSJohn Marino 
16*e0b8e63eSJohn Marino #include <sys/types.h>
17*e0b8e63eSJohn Marino #include <sys/queue.h>
18*e0b8e63eSJohn Marino #include <sys/stat.h>
19*e0b8e63eSJohn Marino 
20*e0b8e63eSJohn Marino #include <bitstring.h>
21*e0b8e63eSJohn Marino #include <errno.h>
22*e0b8e63eSJohn Marino #include <fcntl.h>
23*e0b8e63eSJohn Marino #include <limits.h>
24*e0b8e63eSJohn Marino #include <stdint.h>
25*e0b8e63eSJohn Marino #include <stdio.h>
26*e0b8e63eSJohn Marino #include <stdlib.h>
27*e0b8e63eSJohn Marino #include <string.h>
28*e0b8e63eSJohn Marino 
29*e0b8e63eSJohn Marino #include "common.h"
30*e0b8e63eSJohn Marino 
31*e0b8e63eSJohn Marino /*
32*e0b8e63eSJohn Marino  * The log consists of records, each containing a type byte and a variable
33*e0b8e63eSJohn Marino  * length byte string, as follows:
34*e0b8e63eSJohn Marino  *
35*e0b8e63eSJohn Marino  *	LOG_CURSOR_INIT		MARK
36*e0b8e63eSJohn Marino  *	LOG_CURSOR_END		MARK
37*e0b8e63eSJohn Marino  *	LOG_LINE_APPEND 	recno_t		char *
38*e0b8e63eSJohn Marino  *	LOG_LINE_DELETE		recno_t		char *
39*e0b8e63eSJohn Marino  *	LOG_LINE_INSERT		recno_t		char *
40*e0b8e63eSJohn Marino  *	LOG_LINE_RESET_F	recno_t		char *
41*e0b8e63eSJohn Marino  *	LOG_LINE_RESET_B	recno_t		char *
42*e0b8e63eSJohn Marino  *	LOG_MARK		LMARK
43*e0b8e63eSJohn Marino  *
44*e0b8e63eSJohn Marino  * We do before image physical logging.  This means that the editor layer
45*e0b8e63eSJohn Marino  * MAY NOT modify records in place, even if simply deleting or overwriting
46*e0b8e63eSJohn Marino  * characters.  Since the smallest unit of logging is a line, we're using
47*e0b8e63eSJohn Marino  * up lots of space.  This may eventually have to be reduced, probably by
48*e0b8e63eSJohn Marino  * doing logical logging, which is a much cooler database phrase.
49*e0b8e63eSJohn Marino  *
50*e0b8e63eSJohn Marino  * The implementation of the historic vi 'u' command, using roll-forward and
51*e0b8e63eSJohn Marino  * roll-back, is simple.  Each set of changes has a LOG_CURSOR_INIT record,
52*e0b8e63eSJohn Marino  * followed by a number of other records, followed by a LOG_CURSOR_END record.
53*e0b8e63eSJohn Marino  * LOG_LINE_RESET records come in pairs.  The first is a LOG_LINE_RESET_B
54*e0b8e63eSJohn Marino  * record, and is the line before the change.  The second is LOG_LINE_RESET_F,
55*e0b8e63eSJohn Marino  * and is the line after the change.  Roll-back is done by backing up to the
56*e0b8e63eSJohn Marino  * first LOG_CURSOR_INIT record before a change.  Roll-forward is done in a
57*e0b8e63eSJohn Marino  * similar fashion.
58*e0b8e63eSJohn Marino  *
59*e0b8e63eSJohn Marino  * The 'U' command is implemented by rolling backward to a LOG_CURSOR_END
60*e0b8e63eSJohn Marino  * record for a line different from the current one.  It should be noted that
61*e0b8e63eSJohn Marino  * this means that a subsequent 'u' command will make a change based on the
62*e0b8e63eSJohn Marino  * new position of the log's cursor.  This is okay, and, in fact, historic vi
63*e0b8e63eSJohn Marino  * behaved that way.
64*e0b8e63eSJohn Marino  */
65*e0b8e63eSJohn Marino 
66*e0b8e63eSJohn Marino static int	log_cursor1(SCR *, int);
67*e0b8e63eSJohn Marino static void	log_err(SCR *, char *, int);
68*e0b8e63eSJohn Marino #if defined(DEBUG) && 0
69*e0b8e63eSJohn Marino static void	log_trace(SCR *, char *, recno_t, u_char *);
70*e0b8e63eSJohn Marino #endif
71*e0b8e63eSJohn Marino static int	apply_with(int (*)(SCR *, recno_t, CHAR_T *, size_t),
72*e0b8e63eSJohn Marino 					SCR *, recno_t, u_char *, size_t);
73*e0b8e63eSJohn Marino 
74*e0b8e63eSJohn Marino /* Try and restart the log on failure, i.e. if we run out of memory. */
75*e0b8e63eSJohn Marino #define	LOG_ERR {							\
76*e0b8e63eSJohn Marino 	log_err(sp, __FILE__, __LINE__);				\
77*e0b8e63eSJohn Marino 	return (1);							\
78*e0b8e63eSJohn Marino }
79*e0b8e63eSJohn Marino 
80*e0b8e63eSJohn Marino /* offset of CHAR_T string in log needs to be aligned on some systems
81*e0b8e63eSJohn Marino  * because it is passed to db_set as a string
82*e0b8e63eSJohn Marino  */
83*e0b8e63eSJohn Marino typedef struct {
84*e0b8e63eSJohn Marino 	char    data[sizeof(u_char) /* type */ + sizeof(recno_t)];
85*e0b8e63eSJohn Marino 	CHAR_T  str[1];
86*e0b8e63eSJohn Marino } log_t;
87*e0b8e63eSJohn Marino #define CHAR_T_OFFSET ((char *)(((log_t*)0)->str) - (char *)0)
88*e0b8e63eSJohn Marino 
89*e0b8e63eSJohn Marino /*
90*e0b8e63eSJohn Marino  * log_init --
91*e0b8e63eSJohn Marino  *	Initialize the logging subsystem.
92*e0b8e63eSJohn Marino  *
93*e0b8e63eSJohn Marino  * PUBLIC: int log_init(SCR *, EXF *);
94*e0b8e63eSJohn Marino  */
95*e0b8e63eSJohn Marino int
96*e0b8e63eSJohn Marino log_init(
97*e0b8e63eSJohn Marino 	SCR *sp,
98*e0b8e63eSJohn Marino 	EXF *ep)
99*e0b8e63eSJohn Marino {
100*e0b8e63eSJohn Marino 	/*
101*e0b8e63eSJohn Marino 	 * !!!
102*e0b8e63eSJohn Marino 	 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
103*e0b8e63eSJohn Marino 	 *
104*e0b8e63eSJohn Marino 	 * Initialize the buffer.  The logging subsystem has its own
105*e0b8e63eSJohn Marino 	 * buffers because the global ones are almost by definition
106*e0b8e63eSJohn Marino 	 * going to be in use when the log runs.
107*e0b8e63eSJohn Marino 	 */
108*e0b8e63eSJohn Marino 	ep->l_lp = NULL;
109*e0b8e63eSJohn Marino 	ep->l_len = 0;
110*e0b8e63eSJohn Marino 	ep->l_cursor.lno = 1;		/* XXX Any valid recno. */
111*e0b8e63eSJohn Marino 	ep->l_cursor.cno = 0;
112*e0b8e63eSJohn Marino 	ep->l_high = ep->l_cur = 1;
113*e0b8e63eSJohn Marino 
114*e0b8e63eSJohn Marino 	ep->log = dbopen(NULL, O_CREAT | O_NONBLOCK | O_RDWR,
115*e0b8e63eSJohn Marino 	    S_IRUSR | S_IWUSR, DB_RECNO, NULL);
116*e0b8e63eSJohn Marino 	if (ep->log == NULL) {
117*e0b8e63eSJohn Marino 		msgq(sp, M_SYSERR, "009|Log file");
118*e0b8e63eSJohn Marino 		F_SET(ep, F_NOLOG);
119*e0b8e63eSJohn Marino 		return (1);
120*e0b8e63eSJohn Marino 	}
121*e0b8e63eSJohn Marino 
122*e0b8e63eSJohn Marino 	return (0);
123*e0b8e63eSJohn Marino }
124*e0b8e63eSJohn Marino 
125*e0b8e63eSJohn Marino /*
126*e0b8e63eSJohn Marino  * log_end --
127*e0b8e63eSJohn Marino  *	Close the logging subsystem.
128*e0b8e63eSJohn Marino  *
129*e0b8e63eSJohn Marino  * PUBLIC: int log_end(SCR *, EXF *);
130*e0b8e63eSJohn Marino  */
131*e0b8e63eSJohn Marino int
132*e0b8e63eSJohn Marino log_end(
133*e0b8e63eSJohn Marino 	SCR *sp,
134*e0b8e63eSJohn Marino 	EXF *ep)
135*e0b8e63eSJohn Marino {
136*e0b8e63eSJohn Marino 	/*
137*e0b8e63eSJohn Marino 	 * !!!
138*e0b8e63eSJohn Marino 	 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
139*e0b8e63eSJohn Marino 	 */
140*e0b8e63eSJohn Marino 	if (ep->log != NULL) {
141*e0b8e63eSJohn Marino 		(void)(ep->log->close)(ep->log);
142*e0b8e63eSJohn Marino 		ep->log = NULL;
143*e0b8e63eSJohn Marino 	}
144*e0b8e63eSJohn Marino 	if (ep->l_lp != NULL) {
145*e0b8e63eSJohn Marino 		free(ep->l_lp);
146*e0b8e63eSJohn Marino 		ep->l_lp = NULL;
147*e0b8e63eSJohn Marino 	}
148*e0b8e63eSJohn Marino 	ep->l_len = 0;
149*e0b8e63eSJohn Marino 	ep->l_cursor.lno = 1;		/* XXX Any valid recno. */
150*e0b8e63eSJohn Marino 	ep->l_cursor.cno = 0;
151*e0b8e63eSJohn Marino 	ep->l_high = ep->l_cur = 1;
152*e0b8e63eSJohn Marino 	return (0);
153*e0b8e63eSJohn Marino }
154*e0b8e63eSJohn Marino 
155*e0b8e63eSJohn Marino /*
156*e0b8e63eSJohn Marino  * log_cursor --
157*e0b8e63eSJohn Marino  *	Log the current cursor position, starting an event.
158*e0b8e63eSJohn Marino  *
159*e0b8e63eSJohn Marino  * PUBLIC: int log_cursor(SCR *);
160*e0b8e63eSJohn Marino  */
161*e0b8e63eSJohn Marino int
162*e0b8e63eSJohn Marino log_cursor(SCR *sp)
163*e0b8e63eSJohn Marino {
164*e0b8e63eSJohn Marino 	EXF *ep;
165*e0b8e63eSJohn Marino 
166*e0b8e63eSJohn Marino 	ep = sp->ep;
167*e0b8e63eSJohn Marino 	if (F_ISSET(ep, F_NOLOG))
168*e0b8e63eSJohn Marino 		return (0);
169*e0b8e63eSJohn Marino 
170*e0b8e63eSJohn Marino 	/*
171*e0b8e63eSJohn Marino 	 * If any changes were made since the last cursor init,
172*e0b8e63eSJohn Marino 	 * put out the ending cursor record.
173*e0b8e63eSJohn Marino 	 */
174*e0b8e63eSJohn Marino 	if (ep->l_cursor.lno == OOBLNO) {
175*e0b8e63eSJohn Marino 		ep->l_cursor.lno = sp->lno;
176*e0b8e63eSJohn Marino 		ep->l_cursor.cno = sp->cno;
177*e0b8e63eSJohn Marino 		return (log_cursor1(sp, LOG_CURSOR_END));
178*e0b8e63eSJohn Marino 	}
179*e0b8e63eSJohn Marino 	ep->l_cursor.lno = sp->lno;
180*e0b8e63eSJohn Marino 	ep->l_cursor.cno = sp->cno;
181*e0b8e63eSJohn Marino 	return (0);
182*e0b8e63eSJohn Marino }
183*e0b8e63eSJohn Marino 
184*e0b8e63eSJohn Marino /*
185*e0b8e63eSJohn Marino  * log_cursor1 --
186*e0b8e63eSJohn Marino  *	Actually push a cursor record out.
187*e0b8e63eSJohn Marino  */
188*e0b8e63eSJohn Marino static int
189*e0b8e63eSJohn Marino log_cursor1(
190*e0b8e63eSJohn Marino 	SCR *sp,
191*e0b8e63eSJohn Marino 	int type)
192*e0b8e63eSJohn Marino {
193*e0b8e63eSJohn Marino 	DBT data, key;
194*e0b8e63eSJohn Marino 	EXF *ep;
195*e0b8e63eSJohn Marino 
196*e0b8e63eSJohn Marino 	ep = sp->ep;
197*e0b8e63eSJohn Marino 
198*e0b8e63eSJohn Marino 	BINC_RETC(sp, ep->l_lp, ep->l_len, sizeof(u_char) + sizeof(MARK));
199*e0b8e63eSJohn Marino 	ep->l_lp[0] = type;
200*e0b8e63eSJohn Marino 	memmove(ep->l_lp + sizeof(u_char), &ep->l_cursor, sizeof(MARK));
201*e0b8e63eSJohn Marino 
202*e0b8e63eSJohn Marino 	key.data = &ep->l_cur;
203*e0b8e63eSJohn Marino 	key.size = sizeof(recno_t);
204*e0b8e63eSJohn Marino 	data.data = ep->l_lp;
205*e0b8e63eSJohn Marino 	data.size = sizeof(u_char) + sizeof(MARK);
206*e0b8e63eSJohn Marino 	if (ep->log->put(ep->log, &key, &data, 0) == -1)
207*e0b8e63eSJohn Marino 		LOG_ERR;
208*e0b8e63eSJohn Marino 
209*e0b8e63eSJohn Marino #if defined(DEBUG) && 0
210*e0b8e63eSJohn Marino 	TRACE(sp, "%lu: %s: %u/%u\n", ep->l_cur,
211*e0b8e63eSJohn Marino 	    type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end",
212*e0b8e63eSJohn Marino 	    sp->lno, sp->cno);
213*e0b8e63eSJohn Marino #endif
214*e0b8e63eSJohn Marino 	/* Reset high water mark. */
215*e0b8e63eSJohn Marino 	ep->l_high = ++ep->l_cur;
216*e0b8e63eSJohn Marino 
217*e0b8e63eSJohn Marino 	return (0);
218*e0b8e63eSJohn Marino }
219*e0b8e63eSJohn Marino 
220*e0b8e63eSJohn Marino /*
221*e0b8e63eSJohn Marino  * log_line --
222*e0b8e63eSJohn Marino  *	Log a line change.
223*e0b8e63eSJohn Marino  *
224*e0b8e63eSJohn Marino  * PUBLIC: int log_line(SCR *, recno_t, u_int);
225*e0b8e63eSJohn Marino  */
226*e0b8e63eSJohn Marino int
227*e0b8e63eSJohn Marino log_line(
228*e0b8e63eSJohn Marino 	SCR *sp,
229*e0b8e63eSJohn Marino 	recno_t lno,
230*e0b8e63eSJohn Marino 	u_int action)
231*e0b8e63eSJohn Marino {
232*e0b8e63eSJohn Marino 	DBT data, key;
233*e0b8e63eSJohn Marino 	EXF *ep;
234*e0b8e63eSJohn Marino 	size_t len;
235*e0b8e63eSJohn Marino 	CHAR_T *lp;
236*e0b8e63eSJohn Marino 	recno_t lcur;
237*e0b8e63eSJohn Marino 
238*e0b8e63eSJohn Marino 	ep = sp->ep;
239*e0b8e63eSJohn Marino 	if (F_ISSET(ep, F_NOLOG))
240*e0b8e63eSJohn Marino 		return (0);
241*e0b8e63eSJohn Marino 
242*e0b8e63eSJohn Marino 	/*
243*e0b8e63eSJohn Marino 	 * XXX
244*e0b8e63eSJohn Marino 	 *
245*e0b8e63eSJohn Marino 	 * Kluge for vi.  Clear the EXF undo flag so that the
246*e0b8e63eSJohn Marino 	 * next 'u' command does a roll-back, regardless.
247*e0b8e63eSJohn Marino 	 */
248*e0b8e63eSJohn Marino 	F_CLR(ep, F_UNDO);
249*e0b8e63eSJohn Marino 
250*e0b8e63eSJohn Marino 	/* Put out one initial cursor record per set of changes. */
251*e0b8e63eSJohn Marino 	if (ep->l_cursor.lno != OOBLNO) {
252*e0b8e63eSJohn Marino 		if (log_cursor1(sp, LOG_CURSOR_INIT))
253*e0b8e63eSJohn Marino 			return (1);
254*e0b8e63eSJohn Marino 		ep->l_cursor.lno = OOBLNO;
255*e0b8e63eSJohn Marino 	}
256*e0b8e63eSJohn Marino 
257*e0b8e63eSJohn Marino 	/*
258*e0b8e63eSJohn Marino 	 * Put out the changes.  If it's a LOG_LINE_RESET_B call, it's a
259*e0b8e63eSJohn Marino 	 * special case, avoid the caches.  Also, if it fails and it's
260*e0b8e63eSJohn Marino 	 * line 1, it just means that the user started with an empty file,
261*e0b8e63eSJohn Marino 	 * so fake an empty length line.
262*e0b8e63eSJohn Marino 	 */
263*e0b8e63eSJohn Marino 	if (action == LOG_LINE_RESET_B) {
264*e0b8e63eSJohn Marino 		if (db_get(sp, lno, DBG_NOCACHE, &lp, &len)) {
265*e0b8e63eSJohn Marino 			if (lno != 1) {
266*e0b8e63eSJohn Marino 				db_err(sp, lno);
267*e0b8e63eSJohn Marino 				return (1);
268*e0b8e63eSJohn Marino 			}
269*e0b8e63eSJohn Marino 			len = 0;
270*e0b8e63eSJohn Marino 			lp = L("");
271*e0b8e63eSJohn Marino 		}
272*e0b8e63eSJohn Marino 	} else
273*e0b8e63eSJohn Marino 		if (db_get(sp, lno, DBG_FATAL, &lp, &len))
274*e0b8e63eSJohn Marino 			return (1);
275*e0b8e63eSJohn Marino 	BINC_RETC(sp,
276*e0b8e63eSJohn Marino 	    ep->l_lp, ep->l_len,
277*e0b8e63eSJohn Marino 	    len * sizeof(CHAR_T) + CHAR_T_OFFSET);
278*e0b8e63eSJohn Marino 	ep->l_lp[0] = action;
279*e0b8e63eSJohn Marino 	memmove(ep->l_lp + sizeof(u_char), &lno, sizeof(recno_t));
280*e0b8e63eSJohn Marino 	memmove(ep->l_lp + CHAR_T_OFFSET, lp, len * sizeof(CHAR_T));
281*e0b8e63eSJohn Marino 
282*e0b8e63eSJohn Marino 	lcur = ep->l_cur;
283*e0b8e63eSJohn Marino 	key.data = &lcur;
284*e0b8e63eSJohn Marino 	key.size = sizeof(recno_t);
285*e0b8e63eSJohn Marino 	data.data = ep->l_lp;
286*e0b8e63eSJohn Marino 	data.size = len * sizeof(CHAR_T) + CHAR_T_OFFSET;
287*e0b8e63eSJohn Marino 	if (ep->log->put(ep->log, &key, &data, 0) == -1)
288*e0b8e63eSJohn Marino 		LOG_ERR;
289*e0b8e63eSJohn Marino 
290*e0b8e63eSJohn Marino #if defined(DEBUG) && 0
291*e0b8e63eSJohn Marino 	switch (action) {
292*e0b8e63eSJohn Marino 	case LOG_LINE_APPEND:
293*e0b8e63eSJohn Marino 		TRACE(sp, "%lu: log_line: append: %lu {%u}\n",
294*e0b8e63eSJohn Marino 		    ep->l_cur, lno, len);
295*e0b8e63eSJohn Marino 		break;
296*e0b8e63eSJohn Marino 	case LOG_LINE_DELETE:
297*e0b8e63eSJohn Marino 		TRACE(sp, "%lu: log_line: delete: %lu {%u}\n",
298*e0b8e63eSJohn Marino 		    ep->l_cur, lno, len);
299*e0b8e63eSJohn Marino 		break;
300*e0b8e63eSJohn Marino 	case LOG_LINE_INSERT:
301*e0b8e63eSJohn Marino 		TRACE(sp, "%lu: log_line: insert: %lu {%u}\n",
302*e0b8e63eSJohn Marino 		    ep->l_cur, lno, len);
303*e0b8e63eSJohn Marino 		break;
304*e0b8e63eSJohn Marino 	case LOG_LINE_RESET_F:
305*e0b8e63eSJohn Marino 		TRACE(sp, "%lu: log_line: reset_f: %lu {%u}\n",
306*e0b8e63eSJohn Marino 		    ep->l_cur, lno, len);
307*e0b8e63eSJohn Marino 		break;
308*e0b8e63eSJohn Marino 	case LOG_LINE_RESET_B:
309*e0b8e63eSJohn Marino 		TRACE(sp, "%lu: log_line: reset_b: %lu {%u}\n",
310*e0b8e63eSJohn Marino 		    ep->l_cur, lno, len);
311*e0b8e63eSJohn Marino 		break;
312*e0b8e63eSJohn Marino 	}
313*e0b8e63eSJohn Marino #endif
314*e0b8e63eSJohn Marino 	/* Reset high water mark. */
315*e0b8e63eSJohn Marino 	ep->l_high = ++ep->l_cur;
316*e0b8e63eSJohn Marino 
317*e0b8e63eSJohn Marino 	return (0);
318*e0b8e63eSJohn Marino }
319*e0b8e63eSJohn Marino 
320*e0b8e63eSJohn Marino /*
321*e0b8e63eSJohn Marino  * log_mark --
322*e0b8e63eSJohn Marino  *	Log a mark position.  For the log to work, we assume that there
323*e0b8e63eSJohn Marino  *	aren't any operations that just put out a log record -- this
324*e0b8e63eSJohn Marino  *	would mean that undo operations would only reset marks, and not
325*e0b8e63eSJohn Marino  *	cause any other change.
326*e0b8e63eSJohn Marino  *
327*e0b8e63eSJohn Marino  * PUBLIC: int log_mark(SCR *, LMARK *);
328*e0b8e63eSJohn Marino  */
329*e0b8e63eSJohn Marino int
330*e0b8e63eSJohn Marino log_mark(
331*e0b8e63eSJohn Marino 	SCR *sp,
332*e0b8e63eSJohn Marino 	LMARK *lmp)
333*e0b8e63eSJohn Marino {
334*e0b8e63eSJohn Marino 	DBT data, key;
335*e0b8e63eSJohn Marino 	EXF *ep;
336*e0b8e63eSJohn Marino 
337*e0b8e63eSJohn Marino 	ep = sp->ep;
338*e0b8e63eSJohn Marino 	if (F_ISSET(ep, F_NOLOG))
339*e0b8e63eSJohn Marino 		return (0);
340*e0b8e63eSJohn Marino 
341*e0b8e63eSJohn Marino 	/* Put out one initial cursor record per set of changes. */
342*e0b8e63eSJohn Marino 	if (ep->l_cursor.lno != OOBLNO) {
343*e0b8e63eSJohn Marino 		if (log_cursor1(sp, LOG_CURSOR_INIT))
344*e0b8e63eSJohn Marino 			return (1);
345*e0b8e63eSJohn Marino 		ep->l_cursor.lno = OOBLNO;
346*e0b8e63eSJohn Marino 	}
347*e0b8e63eSJohn Marino 
348*e0b8e63eSJohn Marino 	BINC_RETC(sp, ep->l_lp,
349*e0b8e63eSJohn Marino 	    ep->l_len, sizeof(u_char) + sizeof(LMARK));
350*e0b8e63eSJohn Marino 	ep->l_lp[0] = LOG_MARK;
351*e0b8e63eSJohn Marino 	memmove(ep->l_lp + sizeof(u_char), lmp, sizeof(LMARK));
352*e0b8e63eSJohn Marino 
353*e0b8e63eSJohn Marino 	key.data = &ep->l_cur;
354*e0b8e63eSJohn Marino 	key.size = sizeof(recno_t);
355*e0b8e63eSJohn Marino 	data.data = ep->l_lp;
356*e0b8e63eSJohn Marino 	data.size = sizeof(u_char) + sizeof(LMARK);
357*e0b8e63eSJohn Marino 	if (ep->log->put(ep->log, &key, &data, 0) == -1)
358*e0b8e63eSJohn Marino 		LOG_ERR;
359*e0b8e63eSJohn Marino 
360*e0b8e63eSJohn Marino #if defined(DEBUG) && 0
361*e0b8e63eSJohn Marino 	TRACE(sp, "%lu: mark %c: %lu/%u\n",
362*e0b8e63eSJohn Marino 	    ep->l_cur, lmp->name, lmp->lno, lmp->cno);
363*e0b8e63eSJohn Marino #endif
364*e0b8e63eSJohn Marino 	/* Reset high water mark. */
365*e0b8e63eSJohn Marino 	ep->l_high = ++ep->l_cur;
366*e0b8e63eSJohn Marino 	return (0);
367*e0b8e63eSJohn Marino }
368*e0b8e63eSJohn Marino 
369*e0b8e63eSJohn Marino /*
370*e0b8e63eSJohn Marino  * Log_backward --
371*e0b8e63eSJohn Marino  *	Roll the log backward one operation.
372*e0b8e63eSJohn Marino  *
373*e0b8e63eSJohn Marino  * PUBLIC: int log_backward(SCR *, MARK *);
374*e0b8e63eSJohn Marino  */
375*e0b8e63eSJohn Marino int
376*e0b8e63eSJohn Marino log_backward(
377*e0b8e63eSJohn Marino 	SCR *sp,
378*e0b8e63eSJohn Marino 	MARK *rp)
379*e0b8e63eSJohn Marino {
380*e0b8e63eSJohn Marino 	DBT key, data;
381*e0b8e63eSJohn Marino 	EXF *ep;
382*e0b8e63eSJohn Marino 	LMARK lm;
383*e0b8e63eSJohn Marino 	MARK m;
384*e0b8e63eSJohn Marino 	recno_t lno;
385*e0b8e63eSJohn Marino 	int didop;
386*e0b8e63eSJohn Marino 	u_char *p;
387*e0b8e63eSJohn Marino 
388*e0b8e63eSJohn Marino 	ep = sp->ep;
389*e0b8e63eSJohn Marino 	if (F_ISSET(ep, F_NOLOG)) {
390*e0b8e63eSJohn Marino 		msgq(sp, M_ERR,
391*e0b8e63eSJohn Marino 		    "010|Logging not being performed, undo not possible");
392*e0b8e63eSJohn Marino 		return (1);
393*e0b8e63eSJohn Marino 	}
394*e0b8e63eSJohn Marino 
395*e0b8e63eSJohn Marino 	if (ep->l_cur == 1) {
396*e0b8e63eSJohn Marino 		msgq(sp, M_BERR, "011|No changes to undo");
397*e0b8e63eSJohn Marino 		return (1);
398*e0b8e63eSJohn Marino 	}
399*e0b8e63eSJohn Marino 
400*e0b8e63eSJohn Marino 	F_SET(ep, F_NOLOG);		/* Turn off logging. */
401*e0b8e63eSJohn Marino 
402*e0b8e63eSJohn Marino 	key.data = &ep->l_cur;		/* Initialize db request. */
403*e0b8e63eSJohn Marino 	key.size = sizeof(recno_t);
404*e0b8e63eSJohn Marino 	for (didop = 0;;) {
405*e0b8e63eSJohn Marino 		--ep->l_cur;
406*e0b8e63eSJohn Marino 		if (ep->log->get(ep->log, &key, &data, 0))
407*e0b8e63eSJohn Marino 			LOG_ERR;
408*e0b8e63eSJohn Marino #if defined(DEBUG) && 0
409*e0b8e63eSJohn Marino 		log_trace(sp, "log_backward", ep->l_cur, data.data);
410*e0b8e63eSJohn Marino #endif
411*e0b8e63eSJohn Marino 		switch (*(p = (u_char *)data.data)) {
412*e0b8e63eSJohn Marino 		case LOG_CURSOR_INIT:
413*e0b8e63eSJohn Marino 			if (didop) {
414*e0b8e63eSJohn Marino 				memmove(rp, p + sizeof(u_char), sizeof(MARK));
415*e0b8e63eSJohn Marino 				F_CLR(ep, F_NOLOG);
416*e0b8e63eSJohn Marino 				return (0);
417*e0b8e63eSJohn Marino 			}
418*e0b8e63eSJohn Marino 			break;
419*e0b8e63eSJohn Marino 		case LOG_CURSOR_END:
420*e0b8e63eSJohn Marino 			break;
421*e0b8e63eSJohn Marino 		case LOG_LINE_APPEND:
422*e0b8e63eSJohn Marino 		case LOG_LINE_INSERT:
423*e0b8e63eSJohn Marino 			didop = 1;
424*e0b8e63eSJohn Marino 			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
425*e0b8e63eSJohn Marino 			if (db_delete(sp, lno))
426*e0b8e63eSJohn Marino 				goto err;
427*e0b8e63eSJohn Marino 			++sp->rptlines[L_DELETED];
428*e0b8e63eSJohn Marino 			break;
429*e0b8e63eSJohn Marino 		case LOG_LINE_DELETE:
430*e0b8e63eSJohn Marino 			didop = 1;
431*e0b8e63eSJohn Marino 			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
432*e0b8e63eSJohn Marino 			if (apply_with(db_insert, sp, lno,
433*e0b8e63eSJohn Marino 				p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET))
434*e0b8e63eSJohn Marino 				goto err;
435*e0b8e63eSJohn Marino 			++sp->rptlines[L_ADDED];
436*e0b8e63eSJohn Marino 			break;
437*e0b8e63eSJohn Marino 		case LOG_LINE_RESET_F:
438*e0b8e63eSJohn Marino 			break;
439*e0b8e63eSJohn Marino 		case LOG_LINE_RESET_B:
440*e0b8e63eSJohn Marino 			didop = 1;
441*e0b8e63eSJohn Marino 			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
442*e0b8e63eSJohn Marino 			if (apply_with(db_set, sp, lno,
443*e0b8e63eSJohn Marino 				p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET))
444*e0b8e63eSJohn Marino 				goto err;
445*e0b8e63eSJohn Marino 			if (sp->rptlchange != lno) {
446*e0b8e63eSJohn Marino 				sp->rptlchange = lno;
447*e0b8e63eSJohn Marino 				++sp->rptlines[L_CHANGED];
448*e0b8e63eSJohn Marino 			}
449*e0b8e63eSJohn Marino 			break;
450*e0b8e63eSJohn Marino 		case LOG_MARK:
451*e0b8e63eSJohn Marino 			didop = 1;
452*e0b8e63eSJohn Marino 			memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
453*e0b8e63eSJohn Marino 			m.lno = lm.lno;
454*e0b8e63eSJohn Marino 			m.cno = lm.cno;
455*e0b8e63eSJohn Marino 			if (mark_set(sp, lm.name, &m, 0))
456*e0b8e63eSJohn Marino 				goto err;
457*e0b8e63eSJohn Marino 			break;
458*e0b8e63eSJohn Marino 		default:
459*e0b8e63eSJohn Marino 			abort();
460*e0b8e63eSJohn Marino 		}
461*e0b8e63eSJohn Marino 	}
462*e0b8e63eSJohn Marino 
463*e0b8e63eSJohn Marino err:	F_CLR(ep, F_NOLOG);
464*e0b8e63eSJohn Marino 	return (1);
465*e0b8e63eSJohn Marino }
466*e0b8e63eSJohn Marino 
467*e0b8e63eSJohn Marino /*
468*e0b8e63eSJohn Marino  * Log_setline --
469*e0b8e63eSJohn Marino  *	Reset the line to its original appearance.
470*e0b8e63eSJohn Marino  *
471*e0b8e63eSJohn Marino  * XXX
472*e0b8e63eSJohn Marino  * There's a bug in this code due to our not logging cursor movements
473*e0b8e63eSJohn Marino  * unless a change was made.  If you do a change, move off the line,
474*e0b8e63eSJohn Marino  * then move back on and do a 'U', the line will be restored to the way
475*e0b8e63eSJohn Marino  * it was before the original change.
476*e0b8e63eSJohn Marino  *
477*e0b8e63eSJohn Marino  * PUBLIC: int log_setline(SCR *);
478*e0b8e63eSJohn Marino  */
479*e0b8e63eSJohn Marino int
480*e0b8e63eSJohn Marino log_setline(SCR *sp)
481*e0b8e63eSJohn Marino {
482*e0b8e63eSJohn Marino 	DBT key, data;
483*e0b8e63eSJohn Marino 	EXF *ep;
484*e0b8e63eSJohn Marino 	LMARK lm;
485*e0b8e63eSJohn Marino 	MARK m;
486*e0b8e63eSJohn Marino 	recno_t lno;
487*e0b8e63eSJohn Marino 	u_char *p;
488*e0b8e63eSJohn Marino 
489*e0b8e63eSJohn Marino 	ep = sp->ep;
490*e0b8e63eSJohn Marino 	if (F_ISSET(ep, F_NOLOG)) {
491*e0b8e63eSJohn Marino 		msgq(sp, M_ERR,
492*e0b8e63eSJohn Marino 		    "012|Logging not being performed, undo not possible");
493*e0b8e63eSJohn Marino 		return (1);
494*e0b8e63eSJohn Marino 	}
495*e0b8e63eSJohn Marino 
496*e0b8e63eSJohn Marino 	if (ep->l_cur == 1)
497*e0b8e63eSJohn Marino 		return (1);
498*e0b8e63eSJohn Marino 
499*e0b8e63eSJohn Marino 	F_SET(ep, F_NOLOG);		/* Turn off logging. */
500*e0b8e63eSJohn Marino 
501*e0b8e63eSJohn Marino 	key.data = &ep->l_cur;		/* Initialize db request. */
502*e0b8e63eSJohn Marino 	key.size = sizeof(recno_t);
503*e0b8e63eSJohn Marino 	for (;;) {
504*e0b8e63eSJohn Marino 		--ep->l_cur;
505*e0b8e63eSJohn Marino 		if (ep->log->get(ep->log, &key, &data, 0))
506*e0b8e63eSJohn Marino 			LOG_ERR;
507*e0b8e63eSJohn Marino #if defined(DEBUG) && 0
508*e0b8e63eSJohn Marino 		log_trace(sp, "log_setline", ep->l_cur, data.data);
509*e0b8e63eSJohn Marino #endif
510*e0b8e63eSJohn Marino 		switch (*(p = (u_char *)data.data)) {
511*e0b8e63eSJohn Marino 		case LOG_CURSOR_INIT:
512*e0b8e63eSJohn Marino 			memmove(&m, p + sizeof(u_char), sizeof(MARK));
513*e0b8e63eSJohn Marino 			if (m.lno != sp->lno || ep->l_cur == 1) {
514*e0b8e63eSJohn Marino 				F_CLR(ep, F_NOLOG);
515*e0b8e63eSJohn Marino 				return (0);
516*e0b8e63eSJohn Marino 			}
517*e0b8e63eSJohn Marino 			break;
518*e0b8e63eSJohn Marino 		case LOG_CURSOR_END:
519*e0b8e63eSJohn Marino 			memmove(&m, p + sizeof(u_char), sizeof(MARK));
520*e0b8e63eSJohn Marino 			if (m.lno != sp->lno) {
521*e0b8e63eSJohn Marino 				++ep->l_cur;
522*e0b8e63eSJohn Marino 				F_CLR(ep, F_NOLOG);
523*e0b8e63eSJohn Marino 				return (0);
524*e0b8e63eSJohn Marino 			}
525*e0b8e63eSJohn Marino 			break;
526*e0b8e63eSJohn Marino 		case LOG_LINE_APPEND:
527*e0b8e63eSJohn Marino 		case LOG_LINE_INSERT:
528*e0b8e63eSJohn Marino 		case LOG_LINE_DELETE:
529*e0b8e63eSJohn Marino 		case LOG_LINE_RESET_F:
530*e0b8e63eSJohn Marino 			break;
531*e0b8e63eSJohn Marino 		case LOG_LINE_RESET_B:
532*e0b8e63eSJohn Marino 			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
533*e0b8e63eSJohn Marino 			if (lno == sp->lno &&
534*e0b8e63eSJohn Marino 				apply_with(db_set, sp, lno,
535*e0b8e63eSJohn Marino 				p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET))
536*e0b8e63eSJohn Marino 				goto err;
537*e0b8e63eSJohn Marino 			if (sp->rptlchange != lno) {
538*e0b8e63eSJohn Marino 				sp->rptlchange = lno;
539*e0b8e63eSJohn Marino 				++sp->rptlines[L_CHANGED];
540*e0b8e63eSJohn Marino 			}
541*e0b8e63eSJohn Marino 		case LOG_MARK:
542*e0b8e63eSJohn Marino 			memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
543*e0b8e63eSJohn Marino 			m.lno = lm.lno;
544*e0b8e63eSJohn Marino 			m.cno = lm.cno;
545*e0b8e63eSJohn Marino 			if (mark_set(sp, lm.name, &m, 0))
546*e0b8e63eSJohn Marino 				goto err;
547*e0b8e63eSJohn Marino 			break;
548*e0b8e63eSJohn Marino 		default:
549*e0b8e63eSJohn Marino 			abort();
550*e0b8e63eSJohn Marino 		}
551*e0b8e63eSJohn Marino 	}
552*e0b8e63eSJohn Marino 
553*e0b8e63eSJohn Marino err:	F_CLR(ep, F_NOLOG);
554*e0b8e63eSJohn Marino 	return (1);
555*e0b8e63eSJohn Marino }
556*e0b8e63eSJohn Marino 
557*e0b8e63eSJohn Marino /*
558*e0b8e63eSJohn Marino  * Log_forward --
559*e0b8e63eSJohn Marino  *	Roll the log forward one operation.
560*e0b8e63eSJohn Marino  *
561*e0b8e63eSJohn Marino  * PUBLIC: int log_forward(SCR *, MARK *);
562*e0b8e63eSJohn Marino  */
563*e0b8e63eSJohn Marino int
564*e0b8e63eSJohn Marino log_forward(
565*e0b8e63eSJohn Marino 	SCR *sp,
566*e0b8e63eSJohn Marino 	MARK *rp)
567*e0b8e63eSJohn Marino {
568*e0b8e63eSJohn Marino 	DBT key, data;
569*e0b8e63eSJohn Marino 	EXF *ep;
570*e0b8e63eSJohn Marino 	LMARK lm;
571*e0b8e63eSJohn Marino 	MARK m;
572*e0b8e63eSJohn Marino 	recno_t lno;
573*e0b8e63eSJohn Marino 	int didop;
574*e0b8e63eSJohn Marino 	u_char *p;
575*e0b8e63eSJohn Marino 
576*e0b8e63eSJohn Marino 	ep = sp->ep;
577*e0b8e63eSJohn Marino 	if (F_ISSET(ep, F_NOLOG)) {
578*e0b8e63eSJohn Marino 		msgq(sp, M_ERR,
579*e0b8e63eSJohn Marino 	    "013|Logging not being performed, roll-forward not possible");
580*e0b8e63eSJohn Marino 		return (1);
581*e0b8e63eSJohn Marino 	}
582*e0b8e63eSJohn Marino 
583*e0b8e63eSJohn Marino 	if (ep->l_cur == ep->l_high) {
584*e0b8e63eSJohn Marino 		msgq(sp, M_BERR, "014|No changes to re-do");
585*e0b8e63eSJohn Marino 		return (1);
586*e0b8e63eSJohn Marino 	}
587*e0b8e63eSJohn Marino 
588*e0b8e63eSJohn Marino 	F_SET(ep, F_NOLOG);		/* Turn off logging. */
589*e0b8e63eSJohn Marino 
590*e0b8e63eSJohn Marino 	key.data = &ep->l_cur;		/* Initialize db request. */
591*e0b8e63eSJohn Marino 	key.size = sizeof(recno_t);
592*e0b8e63eSJohn Marino 	for (didop = 0;;) {
593*e0b8e63eSJohn Marino 		++ep->l_cur;
594*e0b8e63eSJohn Marino 		if (ep->log->get(ep->log, &key, &data, 0))
595*e0b8e63eSJohn Marino 			LOG_ERR;
596*e0b8e63eSJohn Marino #if defined(DEBUG) && 0
597*e0b8e63eSJohn Marino 		log_trace(sp, "log_forward", ep->l_cur, data.data);
598*e0b8e63eSJohn Marino #endif
599*e0b8e63eSJohn Marino 		switch (*(p = (u_char *)data.data)) {
600*e0b8e63eSJohn Marino 		case LOG_CURSOR_END:
601*e0b8e63eSJohn Marino 			if (didop) {
602*e0b8e63eSJohn Marino 				++ep->l_cur;
603*e0b8e63eSJohn Marino 				memmove(rp, p + sizeof(u_char), sizeof(MARK));
604*e0b8e63eSJohn Marino 				F_CLR(ep, F_NOLOG);
605*e0b8e63eSJohn Marino 				return (0);
606*e0b8e63eSJohn Marino 			}
607*e0b8e63eSJohn Marino 			break;
608*e0b8e63eSJohn Marino 		case LOG_CURSOR_INIT:
609*e0b8e63eSJohn Marino 			break;
610*e0b8e63eSJohn Marino 		case LOG_LINE_APPEND:
611*e0b8e63eSJohn Marino 		case LOG_LINE_INSERT:
612*e0b8e63eSJohn Marino 			didop = 1;
613*e0b8e63eSJohn Marino 			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
614*e0b8e63eSJohn Marino 			if (apply_with(db_insert, sp, lno,
615*e0b8e63eSJohn Marino 				p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET))
616*e0b8e63eSJohn Marino 				goto err;
617*e0b8e63eSJohn Marino 			++sp->rptlines[L_ADDED];
618*e0b8e63eSJohn Marino 			break;
619*e0b8e63eSJohn Marino 		case LOG_LINE_DELETE:
620*e0b8e63eSJohn Marino 			didop = 1;
621*e0b8e63eSJohn Marino 			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
622*e0b8e63eSJohn Marino 			if (db_delete(sp, lno))
623*e0b8e63eSJohn Marino 				goto err;
624*e0b8e63eSJohn Marino 			++sp->rptlines[L_DELETED];
625*e0b8e63eSJohn Marino 			break;
626*e0b8e63eSJohn Marino 		case LOG_LINE_RESET_B:
627*e0b8e63eSJohn Marino 			break;
628*e0b8e63eSJohn Marino 		case LOG_LINE_RESET_F:
629*e0b8e63eSJohn Marino 			didop = 1;
630*e0b8e63eSJohn Marino 			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
631*e0b8e63eSJohn Marino 			if (apply_with(db_set, sp, lno,
632*e0b8e63eSJohn Marino 				p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET))
633*e0b8e63eSJohn Marino 				goto err;
634*e0b8e63eSJohn Marino 			if (sp->rptlchange != lno) {
635*e0b8e63eSJohn Marino 				sp->rptlchange = lno;
636*e0b8e63eSJohn Marino 				++sp->rptlines[L_CHANGED];
637*e0b8e63eSJohn Marino 			}
638*e0b8e63eSJohn Marino 			break;
639*e0b8e63eSJohn Marino 		case LOG_MARK:
640*e0b8e63eSJohn Marino 			didop = 1;
641*e0b8e63eSJohn Marino 			memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
642*e0b8e63eSJohn Marino 			m.lno = lm.lno;
643*e0b8e63eSJohn Marino 			m.cno = lm.cno;
644*e0b8e63eSJohn Marino 			if (mark_set(sp, lm.name, &m, 0))
645*e0b8e63eSJohn Marino 				goto err;
646*e0b8e63eSJohn Marino 			break;
647*e0b8e63eSJohn Marino 		default:
648*e0b8e63eSJohn Marino 			abort();
649*e0b8e63eSJohn Marino 		}
650*e0b8e63eSJohn Marino 	}
651*e0b8e63eSJohn Marino 
652*e0b8e63eSJohn Marino err:	F_CLR(ep, F_NOLOG);
653*e0b8e63eSJohn Marino 	return (1);
654*e0b8e63eSJohn Marino }
655*e0b8e63eSJohn Marino 
656*e0b8e63eSJohn Marino /*
657*e0b8e63eSJohn Marino  * log_err --
658*e0b8e63eSJohn Marino  *	Try and restart the log on failure, i.e. if we run out of memory.
659*e0b8e63eSJohn Marino  */
660*e0b8e63eSJohn Marino static void
661*e0b8e63eSJohn Marino log_err(
662*e0b8e63eSJohn Marino 	SCR *sp,
663*e0b8e63eSJohn Marino 	char *file,
664*e0b8e63eSJohn Marino 	int line)
665*e0b8e63eSJohn Marino {
666*e0b8e63eSJohn Marino 	EXF *ep;
667*e0b8e63eSJohn Marino 
668*e0b8e63eSJohn Marino 	msgq(sp, M_SYSERR, "015|%s/%d: log put error", tail(file), line);
669*e0b8e63eSJohn Marino 	ep = sp->ep;
670*e0b8e63eSJohn Marino 	(void)ep->log->close(ep->log);
671*e0b8e63eSJohn Marino 	if (!log_init(sp, ep))
672*e0b8e63eSJohn Marino 		msgq(sp, M_ERR, "267|Log restarted");
673*e0b8e63eSJohn Marino }
674*e0b8e63eSJohn Marino 
675*e0b8e63eSJohn Marino #if defined(DEBUG) && 0
676*e0b8e63eSJohn Marino static void
677*e0b8e63eSJohn Marino log_trace(
678*e0b8e63eSJohn Marino 	SCR *sp,
679*e0b8e63eSJohn Marino 	char *msg,
680*e0b8e63eSJohn Marino 	recno_t rno,
681*e0b8e63eSJohn Marino 	u_char *p)
682*e0b8e63eSJohn Marino {
683*e0b8e63eSJohn Marino 	LMARK lm;
684*e0b8e63eSJohn Marino 	MARK m;
685*e0b8e63eSJohn Marino 	recno_t lno;
686*e0b8e63eSJohn Marino 
687*e0b8e63eSJohn Marino 	switch (*p) {
688*e0b8e63eSJohn Marino 	case LOG_CURSOR_INIT:
689*e0b8e63eSJohn Marino 		memmove(&m, p + sizeof(u_char), sizeof(MARK));
690*e0b8e63eSJohn Marino 		TRACE(sp, "%lu: %s:  C_INIT: %u/%u\n", rno, msg, m.lno, m.cno);
691*e0b8e63eSJohn Marino 		break;
692*e0b8e63eSJohn Marino 	case LOG_CURSOR_END:
693*e0b8e63eSJohn Marino 		memmove(&m, p + sizeof(u_char), sizeof(MARK));
694*e0b8e63eSJohn Marino 		TRACE(sp, "%lu: %s:   C_END: %u/%u\n", rno, msg, m.lno, m.cno);
695*e0b8e63eSJohn Marino 		break;
696*e0b8e63eSJohn Marino 	case LOG_LINE_APPEND:
697*e0b8e63eSJohn Marino 		memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
698*e0b8e63eSJohn Marino 		TRACE(sp, "%lu: %s:  APPEND: %lu\n", rno, msg, lno);
699*e0b8e63eSJohn Marino 		break;
700*e0b8e63eSJohn Marino 	case LOG_LINE_INSERT:
701*e0b8e63eSJohn Marino 		memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
702*e0b8e63eSJohn Marino 		TRACE(sp, "%lu: %s:  INSERT: %lu\n", rno, msg, lno);
703*e0b8e63eSJohn Marino 		break;
704*e0b8e63eSJohn Marino 	case LOG_LINE_DELETE:
705*e0b8e63eSJohn Marino 		memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
706*e0b8e63eSJohn Marino 		TRACE(sp, "%lu: %s:  DELETE: %lu\n", rno, msg, lno);
707*e0b8e63eSJohn Marino 		break;
708*e0b8e63eSJohn Marino 	case LOG_LINE_RESET_F:
709*e0b8e63eSJohn Marino 		memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
710*e0b8e63eSJohn Marino 		TRACE(sp, "%lu: %s: RESET_F: %lu\n", rno, msg, lno);
711*e0b8e63eSJohn Marino 		break;
712*e0b8e63eSJohn Marino 	case LOG_LINE_RESET_B:
713*e0b8e63eSJohn Marino 		memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
714*e0b8e63eSJohn Marino 		TRACE(sp, "%lu: %s: RESET_B: %lu\n", rno, msg, lno);
715*e0b8e63eSJohn Marino 		break;
716*e0b8e63eSJohn Marino 	case LOG_MARK:
717*e0b8e63eSJohn Marino 		memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
718*e0b8e63eSJohn Marino 		TRACE(sp,
719*e0b8e63eSJohn Marino 		    "%lu: %s:    MARK: %u/%u\n", rno, msg, lm.lno, lm.cno);
720*e0b8e63eSJohn Marino 		break;
721*e0b8e63eSJohn Marino 	default:
722*e0b8e63eSJohn Marino 		abort();
723*e0b8e63eSJohn Marino 	}
724*e0b8e63eSJohn Marino }
725*e0b8e63eSJohn Marino #endif
726*e0b8e63eSJohn Marino 
727*e0b8e63eSJohn Marino /*
728*e0b8e63eSJohn Marino  * apply_with --
729*e0b8e63eSJohn Marino  *	Apply a realigned line from the log db to the file db.
730*e0b8e63eSJohn Marino  */
731*e0b8e63eSJohn Marino static int
732*e0b8e63eSJohn Marino apply_with(
733*e0b8e63eSJohn Marino 	int (*db_func)(SCR *, recno_t, CHAR_T *, size_t),
734*e0b8e63eSJohn Marino 	SCR *sp,
735*e0b8e63eSJohn Marino 	recno_t lno,
736*e0b8e63eSJohn Marino 	u_char *p,
737*e0b8e63eSJohn Marino 	size_t len)
738*e0b8e63eSJohn Marino {
739*e0b8e63eSJohn Marino #ifdef USE_WIDECHAR
740*e0b8e63eSJohn Marino 	typedef unsigned long nword;
741*e0b8e63eSJohn Marino 
742*e0b8e63eSJohn Marino 	static size_t blen;
743*e0b8e63eSJohn Marino 	static nword *bp;
744*e0b8e63eSJohn Marino 	nword *lp = (nword *)((uintptr_t)p / sizeof(nword) * sizeof(nword));
745*e0b8e63eSJohn Marino 
746*e0b8e63eSJohn Marino 	if (lp != (nword *)p) {
747*e0b8e63eSJohn Marino 		int offl = ((uintptr_t)p - (uintptr_t)lp) << 3;
748*e0b8e63eSJohn Marino 		int offr = (sizeof(nword) << 3) - offl;
749*e0b8e63eSJohn Marino 		size_t i, cnt = (len + sizeof(nword) / 2) / sizeof(nword);
750*e0b8e63eSJohn Marino 
751*e0b8e63eSJohn Marino 		if (len > blen) {
752*e0b8e63eSJohn Marino 			blen = p2roundup(MAX(len, 512));
753*e0b8e63eSJohn Marino 			REALLOC(sp, bp, nword *, blen);
754*e0b8e63eSJohn Marino 			if (bp == NULL)
755*e0b8e63eSJohn Marino 				return (1);
756*e0b8e63eSJohn Marino 		}
757*e0b8e63eSJohn Marino 		for (i = 0; i < cnt; ++i)
758*e0b8e63eSJohn Marino #if BYTE_ORDER == BIG_ENDIAN
759*e0b8e63eSJohn Marino 			bp[i] = (lp[i] << offl) ^ (lp[i+1] >> offr);
760*e0b8e63eSJohn Marino #else
761*e0b8e63eSJohn Marino 			bp[i] = (lp[i] >> offl) ^ (lp[i+1] << offr);
762*e0b8e63eSJohn Marino #endif
763*e0b8e63eSJohn Marino 		p = (u_char *)bp;
764*e0b8e63eSJohn Marino 	}
765*e0b8e63eSJohn Marino #endif
766*e0b8e63eSJohn Marino 	return db_func(sp, lno, (CHAR_T *)p, len / sizeof(CHAR_T));
767*e0b8e63eSJohn Marino }
768