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