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