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