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