1 /* @(#)storage.c 1.54 16/08/05 Copyright 1984-2016 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)storage.c 1.54 16/08/05 Copyright 1984-2016 J. Schilling";
6 #endif
7 /*
8 * Storage management based on the paged virtual memory
9 * provided by buffer.c
10 *
11 * Copyright (c) 1984-2016 J. Schilling
12 */
13 /*
14 * The contents of this file are subject to the terms of the
15 * Common Development and Distribution License, Version 1.0 only
16 * (the "License"). You may not use this file except in compliance
17 * with the License.
18 *
19 * See the file CDDL.Schily.txt in this distribution for details.
20 * A copy of the CDDL is also available via the Internet at
21 * http://www.opensource.org/licenses/cddl1.txt
22 *
23 * When distributing Covered Code, include this CDDL HEADER in each
24 * file and include the License file CDDL.Schily.txt from this distribution.
25 */
26
27 /*
28 * The basic buffer operations:
29 *
30 * insertion, deletion, loading/storing from/to a file and extracting
31 *
32 * are handled in this package. Findpos() gives direct buffer access for
33 * a given buffer offset. All operations are based on:
34 *
35 * dot - The current corsor position offset in the buffer
36 *
37 * eof - The offset that comes directly after the last valid
38 * character in the buffer, 'eof' is the number of valid
39 * characters in the buffer. The 'eof' position contains a
40 * space charcter to be able to access this position.
41 *
42 * gap - The offset in the buffer memory where the gap is. It
43 * has been prepared for insertions or deletions by
44 * splitting the actual buffer at the 'gap' position.
45 * The 'gap' position is maintained by the insertion
46 * and deletion routines.
47 *
48 * To speed up findpos() on very long files, we maintain an 'anker' that
49 * is at or close before the start or the current screen window. This allows
50 * findpos() to work relative to this 'anker'. The variables that are
51 * used to maintain this 'anker' are 'winlink', 'winpos' and 'winoff'.
52 */
53
54 /*
55 * Include code to speed up findpos().
56 */
57 /*#define FASTPOS*/
58 /*
59 * Include code to time the fastpos code.
60 */
61 /*#define TIMEPOS*/
62 /*
63 * Include code for extended fastpos debugging.
64 */
65 /*#define XPOSDEBUG*/
66
67 #include "ved.h"
68 #include "buffer.h"
69 #ifdef TIMEPOS
70 # include <schily/time.h> /* Nur f�r Zeitmessungen */
71 #endif
72 #include <schily/errno.h>
73
74 #define wp_gaplink(p) ((headr_t *)((p)->gaplink))
75 #define wp_winlink(p) ((headr_t *)((p)->winlink))
76
77 EXPORT void insert __PR((ewin_t *wp, Uchar* str, long size));
78 EXPORT void delete __PR((ewin_t *wp, epos_t size));
79 EXPORT void rubout __PR((ewin_t *wp, epos_t size));
80 EXPORT BOOL loadfile __PR((ewin_t *wp, Uchar* filename, BOOL newdefault));
81 EXPORT BOOL savefile __PR((ewin_t *wp, epos_t begin, epos_t end, FILE * f, char *name));
82 EXPORT BOOL backsavefile __PR((ewin_t *wp, epos_t begin, epos_t end, FILE * f, char *name));
83 EXPORT void getfile __PR((ewin_t *wp, FILE * f, epos_t size, char *name));
84 EXPORT void backgetfile __PR((ewin_t *wp, FILE * f, epos_t size, char *name));
85 LOCAL void reversebuffer __PR((Uchar* from, Uchar* to, long size));
86 EXPORT BOOL isdos __PR((ewin_t *wp));
87 EXPORT int extract __PR((ewin_t *wp, epos_t begin, Uchar *str, int size));
88 EXPORT int extr_line __PR((ewin_t *wp, epos_t begin, char *str, int size));
89 EXPORT int retractline __PR((ewin_t *wp, epos_t begin, char *str, int size));
90 LOCAL void movegap __PR((ewin_t *wp, epos_t pos));
91 EXPORT void clearifwpos __PR((ewin_t *wp, headr_t *this));
92 EXPORT void clearwpos __PR((ewin_t *wp));
93 EXPORT void backwpos __PR((ewin_t *wp));
94 EXPORT void findwpos __PR((ewin_t *wp, epos_t new));
95 EXPORT void findpos __PR((ewin_t *wp, epos_t pos, headr_t ** returnlinkp, int *returnoff));
96 #ifdef FASTPOS
97 #ifdef CHECKPOS
98 LOCAL void ckfindpos __PR((ewin_t *wp, epos_t pos, headr_t ** returnlinkp, int *returnoff));
99 #endif
100 LOCAL void rfindpos __PR((ewin_t *wp, epos_t pos, headr_t ** returnlinkp, int *returnoff));
101 #endif
102
103 /*
104 * Insert 'size' characters at dot.
105 * Then put the dot after the inserted characters.
106 */
107 EXPORT void
insert(wp,str,size)108 insert(wp, str, size)
109 ewin_t *wp;
110 register Uchar *str;
111 register long size;
112 {
113 register Uchar *to;
114 register long n = size;
115 register int amount;
116
117 if (n <= 0)
118 return;
119
120 movegap(wp, wp->dot);
121 readybuffer(wp, wp_gaplink(wp)); /* Make sure buffer is incore */
122
123 #ifdef FASTPOS
124 if (wp->winlink && wp->dot <= wp->winoff)
125 clearwpos(wp);
126 #endif
127
128 if (wp->markvalid && wp->mark == wp->dot) {
129 resetmark(wp);
130 wp->markvalid = 1;
131 }
132
133 while (n > 0) {
134 /*
135 * There is no leading gap after a movegap() call.
136 */
137 amount = min(n, BUFFERSIZE - wp_gaplink(wp)->size);
138 to = wp_gaplink(wp)->cont + wp_gaplink(wp)->size;
139 wp_gaplink(wp)->flags |= MODIFIED;
140 wp_gaplink(wp)->size += amount;
141 n -= amount;
142 if (amount > 16) {
143 movebytes(C str, C to, amount);
144 str += amount;
145 } else {
146 while (amount--)
147 *to++ = *str++;
148 }
149 if (n)
150 wp->gaplink = addbuffer(wp, wp_gaplink(wp));
151 }
152 wp->eof += size;
153 wp->gap += size;
154 if (wp->markvalid && wp->mark > wp->dot)
155 wp->mark += size;
156 wp->dot += size;
157 }
158
159 /*
160 * Delete 'size' characters after the dot.
161 * Leave 'dot' at the old position.
162 */
163 EXPORT void
delete(wp,size)164 delete(wp, size)
165 ewin_t *wp;
166 epos_t size;
167 {
168 register headr_t *next;
169 register epos_t n;
170 register int amount;
171
172 #ifdef DEBUG
173 cdbg("delete(%lld)", (Llong)size);
174 #endif
175 if (size > wp->eof-wp->dot)
176 size = wp->eof-wp->dot;
177 n = size;
178 if (n <= 0)
179 return;
180
181 movegap(wp, wp->dot); /* No need to have the buffer incore */
182
183 while (n > 0) {
184 if ((next = wp_gaplink(wp)->next) == NULL) /* Paranoia */
185 break;
186 #ifdef FASTPOS
187 if (next == wp->winlink)
188 clearwpos(wp);
189 #endif
190 /* readybuffer(wp, next);*/
191 amount = min(n, next->size);
192 n -= amount;
193 next->size -= amount;
194 next->cont += amount;
195 /*
196 * We are modifying next->cont and thus must set the MODIFIED
197 * flag in the header. This is needed because we swap out from
198 * linkp->cont and remove any leading gap when we swap in.
199 * If we don't want to set the MODIFIED flag here, we must
200 * always swap out the complete buffer and restore the old
201 * leading gap and the linkp->cont offset when swapping in
202 * again.
203 */
204 next->flags |= MODIFIED;
205 if (n)
206 deletebuffer(wp, next);
207 }
208 wp->eof -= size;
209 if (wp->markvalid) {
210 if (wp->mark >= wp->dot && wp->mark < wp->dot+size) {
211 setmark(wp, wp->dot);
212 } else if (wp->mark >= wp->dot+size) {
213 wp->mark -= size;
214 }
215 }
216 #ifdef DEBUG
217 cdbg("delete() done");
218 #endif
219 }
220
221 /*
222 * Delete 'size' characters before the dot.
223 * Then move the dot back 'size' characters.
224 */
225 EXPORT void
rubout(wp,size)226 rubout(wp, size)
227 ewin_t *wp;
228 epos_t size;
229 {
230 register epos_t n;
231 epos_t savedot = wp->dot;
232 register int amount;
233
234 if (size > wp->dot)
235 size = wp->dot;
236 n = size;
237 if (n <= 0)
238 return;
239
240 movegap(wp, wp->dot); /* No need to have the buffer incore */
241
242 while (n > 0) {
243 if (! wp_gaplink(wp)->next) /* Paranoia */
244 break;
245 #ifdef FASTPOS
246 if (wp_gaplink(wp) == wp->winlink)
247 clearwpos(wp);
248 #endif
249 amount = min(n, wp_gaplink(wp)->size);
250 n -= amount;
251 wp_gaplink(wp)->size -= amount;
252 if (n)
253 wp->gaplink = deletebuffer(wp, wp_gaplink(wp));
254 /* readybuffer(wp, wp_gaplink(wp));*/
255 }
256 wp->dot -= size;
257 wp->eof -= size;
258 wp->gap -= size;
259 if (wp->markvalid) {
260 if (wp->mark < savedot && wp->mark >= wp->dot) {
261 setmark(wp, wp->dot);
262 } else if (wp->mark >= savedot) {
263 wp->mark -= size;
264 }
265 }
266 }
267
268 /*
269 * Load the content of a file at dot position.
270 */
271 EXPORT BOOL
loadfile(wp,filename,newdefault)272 loadfile(wp, filename, newdefault)
273 ewin_t *wp;
274 Uchar *filename;
275 BOOL newdefault; /* if true: this is the currenlty edited file*/
276 {
277 FILE *infile;
278 Uchar str[BUFSIZ < 8192 ? 8192 : BUFSIZ];
279 long size;
280 #if defined(IS_CYGWIN) || defined(__DJGPP__)
281 BOOL retry = FALSE;
282 #endif
283
284 if (newdefault) {
285 wp->eflags &= ~(FREADONLY|FNOLOCK);
286 if (wp->curfd >= 0)
287 close(wp->curfd);
288 wp->curfd = -1;
289 if (wp->curfp != NULL)
290 fclose(wp->curfp);
291 wp->curfp = NULL;
292 if (!ReadOnly && writable(filename))
293 lockfile(wp, C filename);
294 }
295 if ((infile = fileopen(C filename, "rub")) == (FILE *) NULL) {
296 if (geterrno() == ENOENT) {
297 if (newdefault && ReadOnly == 0) {
298 defaulterr(wp, UC "NEW FILE");
299 } else {
300 writeerr(wp, "FILE DOES NOT EXIST");
301 }
302 } else {
303 write_errno(wp, "CAN'T OPEN FILE");
304 }
305 return (FALSE);
306 }
307 file_raise(infile, FALSE);
308 #if defined(IS_CYGWIN) || defined(__DJGPP__)
309 again:
310 #endif
311 while ((size = readsyserr(wp, infile, str, sizeof (str), UC "FILE")) > 0) {
312 insert(wp, str, size);
313 }
314
315 if (size < 0) {
316 #if defined(IS_CYGWIN) || defined(__DJGPP__)
317 /*
318 * On Cygwin, we cannot lock correctly.
319 * Locks are on a fd base not on a process base.
320 * In addition, we may not even read from a diffrerent fd
321 * if we wold a write lock on another fd.
322 */
323 if (newdefault && !retry && wp->eof == 0 &&
324 wp->curfd >= 0 && geterrno() == EACCES) {
325 /*
326 * If read did not work and we did nothing
327 * until now, this is a Cygwin locking problem
328 * and we must destroy the locking.
329 */
330 close(wp->curfd);
331 wp->curfd = -1;
332 retry = TRUE;
333 goto again;
334 }
335 #endif
336 fclose(infile);
337 return (FALSE);
338 }
339 #if defined(IS_CYGWIN) || defined(__DJGPP__)
340 if (newdefault && !retry && wp->curfd >= 0) {
341 write_errno(wp, "LOCK WORKED!");
342 #ifdef SLEEP_ON_WORKING_CYGWIN_LOCK
343 sleep(2);
344 #endif
345 }
346 #ifdef NONOONO
347 if (newdefault && wp->curfd < 0) {
348 if (!ReadOnly && writable(C filename))
349 lockfile(wp, C filename);
350 }
351 #endif
352 #endif
353 if (wp->curfd >= 0) {
354 /*
355 * Due to a conceptional bug of lockf()/fcntl(f, F_SETLK)
356 * we will loose the lock if we close any fd associated
357 * with the loked file.
358 */
359 wp->curfp = infile;
360 } else {
361 fclose(infile);
362 wp->curfp = NULL;
363 }
364 return (TRUE);
365 }
366
367 /*
368 * Save a part of the current buffer into a file.
369 */
370 EXPORT BOOL
savefile(wp,begin,end,f,name)371 savefile(wp, begin, end, f, name)
372 ewin_t *wp;
373 epos_t begin;
374 epos_t end;
375 FILE *f;
376 char *name;
377 {
378 register headr_t *linkp = wp->bhead;
379 headr_t *passlinkp;
380 register int amount;
381 int pos = 0;
382 int nextsize;
383 Uchar *from;
384
385 #ifdef JOS
386 getpid();
387 #else
388 seterrno(0); /* Damit write_errno korrekt arbeitet */
389 #endif
390
391 if (end >= wp->eof)
392 end = wp->eof;
393 if (begin >= end)
394 return (FALSE);
395 if (f == (FILE *) NULL)
396 return (FALSE);
397
398 findpos(wp, begin, &passlinkp, &pos);
399 linkp = passlinkp;
400 from = linkp->cont + pos;
401 nextsize = linkp->size - pos;
402
403 while (begin < end) {
404 amount = min(end-begin, nextsize);
405 if (writesyserr(wp, f, from, amount, UC name) != amount)
406 return (FALSE);
407 begin += amount;
408 if (begin < end) {
409 linkp = linkp->next;
410 readybuffer(wp, linkp);
411 from = linkp->cont;
412 nextsize = linkp->size;
413 }
414 }
415 return (fflush(f) != EOF);
416 }
417
418 /*
419 * Save a part of the current buffer into a file, write the buffer backwards.
420 */
421 EXPORT BOOL
backsavefile(wp,begin,end,f,name)422 backsavefile(wp, begin, end, f, name)
423 ewin_t *wp;
424 epos_t begin;
425 epos_t end;
426 FILE *f;
427 char *name;
428 {
429 register headr_t *linkp;
430 headr_t *passlinkp;
431 register int amount;
432 Uchar buf[BUFFERSIZE];
433 int pos = 0;
434 int nextsize;
435 register int n;
436 Uchar *from;
437 Uchar *to;
438
439 #ifdef JOS
440 getpid();
441 #else
442 seterrno(0); /* Damit write_errno korrekt arbeitet */
443 #endif
444
445 if (end > wp->eof)
446 end = wp->eof;
447 if (end == 0)
448 return (FALSE);
449 if (begin >= end)
450 return (FALSE);
451 if (f == (FILE *) NULL)
452 return (FALSE);
453
454 findpos(wp, end-1, &passlinkp, &pos);
455 linkp = passlinkp;
456 from = linkp->cont + pos;
457 nextsize = pos + 1;
458
459 while (end > begin) {
460 amount = min(end-begin, nextsize);
461 end -= amount;
462 n = amount;
463 to = buf;
464 while (--n >= 0) {
465 *to++ = *from--;
466 }
467 if (writesyserr(wp, f, buf, amount, UC name) != amount)
468 return (FALSE);
469 if (end > begin) {
470 linkp = linkp->prev;
471 readybuffer(wp, linkp);
472 from = linkp->cont + linkp->size - 1;
473 nextsize = linkp->size;
474 }
475 }
476 return (fflush(f) != EOF);
477 }
478
479 /*
480 * Get the content of a file and insert it 'curnum' times at dot position.
481 * The dot position remains at the old position.
482 */
483 EXPORT void
getfile(wp,f,size,name)484 getfile(wp, f, size, name)
485 ewin_t *wp;
486 FILE *f;
487 epos_t size;
488 char *name;
489 {
490 Uchar buf[BUFSIZ];
491 epos_t left;
492 int this;
493 long result;
494 register ecnt_t n = wp->curnum;
495 epos_t save = wp->dot;
496
497 if (size <= 0)
498 return;
499
500 while (--n >= 0) {
501 lseek(fdown(f), (off_t)0, SEEK_SET);
502 for (left = size; left > 0; ) {
503 if (left > sizeof (buf))
504 this = sizeof (buf);
505 else
506 this = (int)left;
507 if ((result = readsyserr(wp, f, buf, this, UC name)) < 0)
508 break;
509 insert(wp, buf, result);
510 left -= result;
511 }
512 }
513 dispup(wp, wp->dot, save);
514 wp->dot = save;
515 modified(wp);
516 }
517
518 /*
519 * Get the content of a file and insert it backwards 'curnum' times at
520 * dot position.
521 * Then put the dot after the inserted characters.
522 */
523 EXPORT void
backgetfile(wp,f,size,name)524 backgetfile(wp, f, size, name)
525 ewin_t *wp;
526 FILE *f;
527 epos_t size;
528 char *name;
529 {
530 Uchar buf[BUFSIZ];
531 Uchar rbuf[BUFSIZ];
532 epos_t left;
533 int this;
534 long result;
535 register ecnt_t n = wp->curnum;
536 epos_t save = wp->dot;
537
538 if (size <= 0)
539 return;
540
541 while (--n >= 0) {
542 for (left = size; left > 0; ) {
543 if (left > sizeof (buf))
544 this = sizeof (buf);
545 else
546 this = (int)left;
547 left -= this;
548 lseek(fdown(f), (off_t)left, SEEK_SET);
549 if ((result = readsyserr(wp, f, buf, this, UC name)) < 0)
550 break;
551 reversebuffer(buf, rbuf, result);
552 insert(wp, rbuf, result);
553 }
554 }
555 dispup(wp, wp->dot, save);
556 modified(wp);
557 }
558
559 /*
560 * Reverse the content of a buffer while copying it to another location
561 */
562 LOCAL void
reversebuffer(from,to,size)563 reversebuffer(from, to, size)
564 register Uchar *from;
565 register Uchar *to;
566 long size;
567 {
568 to += (size-1);
569 while (--size >= 0)
570 *to-- = *from++;
571 }
572
573 /*
574 * Look into the first block of the buffer memory and find out whether
575 * it is using DOS newlines.
576 */
577 EXPORT BOOL
isdos(wp)578 isdos(wp)
579 ewin_t *wp;
580 {
581 register headr_t *linkp;
582 headr_t *passlinkp;
583 int pos;
584 int linksize;
585 Uchar *from;
586 register Uchar *cp;
587 int dosnlcnt = 0;
588
589 if (wp->eof <= (epos_t)0)
590 return (FALSE);
591
592 findpos(wp, (epos_t)0, &passlinkp, &pos);
593 linkp = passlinkp;
594 linksize = linkp->size - pos;
595 cp = from = linkp->cont + pos;
596
597 while (--linksize >= 0) {
598 register Uchar c;
599
600 c = *cp++;
601 if (c == '\0') /* Is binary, cannot be DOS */
602 return (FALSE);
603 if (c == '\n') {
604 if ((cp - from) < 2) /* First char is Newline */
605 return (FALSE);
606
607 if (cp[-2] == '\r') {
608 dosnlcnt++;
609 continue;
610 }
611 if (dosnlcnt > 0) {
612 error(
613 "Non DOS newline at %d after (line %d).\r\n",
614 linkp->size - pos - linksize - 1, dosnlcnt+1);
615 }
616 return (FALSE); /* Found '\n' without '\r' */
617 }
618 }
619 return (dosnlcnt > 0);
620 }
621
622 /*
623 * Extract a portion of the buffer memory.
624 * Fill in up to 'size' characters and return the amount of characters read.
625 * NOTE: a NULL byte is added to the extracted string so it must be able
626 * to hold up to size + 1 characters.
627 */
628 EXPORT int
extract(wp,begin,str,size)629 extract(wp, begin, str, size)
630 ewin_t *wp;
631 epos_t begin;
632 Uchar *str;
633 int size;
634 {
635 register headr_t *linkp;
636 headr_t *passlinkp;
637 int pos;
638 int savesize = size;
639 int amount;
640 int linksize;
641 Uchar *out = str;
642 Uchar *from;
643
644 /* if (begin > wp->eof) {*/
645 if (begin >= wp->eof) {
646 *out = 0;
647 return (0);
648 }
649 findpos(wp, begin, &passlinkp, &pos);
650 linkp = passlinkp;
651 linksize = linkp->size - pos;
652 from = linkp->cont + pos;
653
654 while (size) {
655 amount = min(size, linksize);
656 movebytes(C from, C out, (int)amount);
657 size -= amount;
658 out += amount;
659 if (size) {
660 linkp = linkp->next;
661 if (! linkp)
662 break;
663 readybuffer(wp, linkp);
664 linksize = linkp->size;
665 from = linkp->cont;
666 }
667 }
668 amount = savesize - size;
669 str[amount] = '\0';
670 return (amount);
671 }
672
673 /*
674 * Extract a portion of the buffer memory,
675 * stop after extracting a new-line character.
676 * Fill in up to 'size' characters and return the amount of characters read.
677 * NOTE: a NULL byte is added to the extracted string so it must be able
678 * to hold up to size + 1 characters.
679 */
680 EXPORT int
extr_line(wp,begin,str,size)681 extr_line(wp, begin, str, size)
682 ewin_t *wp;
683 epos_t begin;
684 char *str;
685 int size;
686 {
687 register headr_t *linkp;
688 headr_t *passlinkp;
689 int pos;
690 int length = 0;
691 int amount;
692 int linksize;
693 Uchar *from;
694
695 /* if (begin > wp->eof) {*/
696 if (begin >= wp->eof) {
697 *str = 0;
698 return (0);
699 }
700 findpos(wp, begin, &passlinkp, &pos);
701 linkp = passlinkp;
702 linksize = linkp->size - pos;
703 from = linkp->cont + pos;
704
705 while (size) {
706 amount = min(size, linksize);
707 while (amount-- > 0) {
708 size--, length++;
709 if ((*str++ = *from++) == '\n') {
710 size = 0;
711 break;
712 }
713 }
714 if (size) {
715 linkp = linkp->next;
716 if (! linkp)
717 break;
718 readybuffer(wp, linkp);
719 linksize = linkp->size;
720 from = linkp->cont;
721 }
722 }
723 *str = '\0';
724 return (length);
725 }
726
727 /*
728 * Extract a portion of the buffer memory, after searching backwards for
729 * the previous new-line, stop after extracting a new-line character.
730 * Fill in up to 'size' characters and return the amount of characters read.
731 * The 'begin' character position is not extracted to make it complementary
732 * to 'extr_line' and allow symmetrical behavior in search functions.
733 * The new-line that was found before 'begin' is not included.
734 * NOTE: a NULL byte is added to the extracted string so it must be able
735 * to hold up to size + 1 characters.
736 */
737 EXPORT int
retractline(wp,begin,str,size)738 retractline(wp, begin, str, size)
739 ewin_t *wp;
740 epos_t begin; /* Start searching backw. from here */
741 char *str;
742 int size;
743 {
744 epos_t newpos;
745
746 if (begin == 0) {
747 *str = 0;
748 return (0);
749 }
750 if (begin == 1)
751 return (extr_line(wp, (epos_t)0, str, min(size, 1)));
752 newpos = srevchar(wp, begin-2, '\n') + 1;
753 if (newpos >= wp->eof)
754 newpos = 0;
755 if (begin-newpos > size)
756 newpos = begin-size;
757 return (extr_line(wp, newpos, str, (int)min(size, begin-newpos)));
758 }
759
760 /*
761 * Move the gap to a new position.
762 * First remove the current gap with compressbuffer().
763 * Then find the header where the new gap position is in and compress the
764 * buffer in case it has a leading gap. This helps us not to waste too much
765 * space with partially filled buffers.
766 * If the new gap position is at the end of the buffer, we are done.
767 * If not, we must split the buffer at the new gap position.
768 * When we are done, the gap is at the end if the current buffer.
769 *
770 * Note that there is no grant that the new buffer at the gap is always ready
771 * and incore when movegap() returns. This is in special true if the gap is
772 * already at the right position (see first return).
773 */
774 LOCAL void
movegap(wp,pos)775 movegap(wp, pos)
776 ewin_t *wp;
777 epos_t pos;
778 {
779 #ifdef DEBUG
780 cdbg("movegap(%lld) gaplink: %p", (Llong)pos, (void *)wp_gaplink(wp));
781 #endif
782 if (pos == wp->gap && wp_gaplink(wp) != (headr_t *)0)
783 return;
784 if (wp_gaplink(wp))
785 compressbuffer(wp, wp_gaplink(wp));
786 findpos(wp, wp->gap = pos, (headr_t **)&wp->gaplink, &wp->gapoff);
787 if (wp_gaplink(wp)->buf != wp_gaplink(wp)->cont)
788 compressbuffer(wp, wp_gaplink(wp));
789 if (wp_gaplink(wp)->size > wp->gapoff)
790 splitbuffer(wp, wp_gaplink(wp), wp->gapoff);
791 }
792
793 /*
794 * If we are removing the buffer that is pointed to by winlink, we
795 * must invalidate winlink.
796 */
797 EXPORT void
clearifwpos(wp,this)798 clearifwpos(wp, this)
799 ewin_t *wp;
800 headr_t *this;
801 {
802 #ifdef FASTPOS
803 if (this == wp->winlink)
804 clearwpos(wp);
805 #endif
806 }
807
808 #ifdef FASTPOS
809
810 /*
811 * Invalidate winlink.
812 *
813 * 'winlink' wird ung�ltig wenn:
814 * 1) der Header entfernt wird auf den 'winlink' zeigt
815 * 2) vor 'winoff' eingef�gt oder gel�scht wird
816 */
817 EXPORT void
clearwpos(wp)818 clearwpos(wp)
819 ewin_t *wp;
820 {
821 #ifdef XPOSDEBUG
822 writeerr(wp, "winlink: %p winpos: %lld winoff: %lld",
823 wp->winlink, (Llong)wp->winpos, (Llong)wp->winoff);
824 sleep(1);
825 #endif
826 /*
827 * Das Neuberechnen dauert bei 200000 Headern mit einer Sparcstation-2
828 * ca. 0,25 Sekunden. Das entspricht bei der aktuellen Buffersize
829 * einer Datei von 1,5 GB.
830 * Gibt es einen besseren Weg als loeschen?
831 */
832 wp->winlink = NULL;
833 wp->winpos = 0L;
834 wp->winoff = 0L;
835 }
836
837 /*
838 * Try to move winpos/winlink backwards.
839 */
840 /* ARGSUSED */
841 EXPORT void
backwpos(wp)842 backwpos(wp)
843 ewin_t *wp;
844 {
845 /*
846 * Das geht nicht!!! Es ist hier nur als Anregung.
847 */
848 #ifdef used
849 if (winlink(wp)->prev != NULL) {
850 wp->winlink = winlink(wp)->prev;
851 wp->winpos -= winlink(wp)->size;
852 }
853 wp->winoff = 0L;
854 #endif
855 }
856
857 /*
858 * Find current window start position.
859 */
860 EXPORT void
findwpos(wp,new)861 findwpos(wp, new)
862 ewin_t *wp;
863 epos_t new;
864 {
865 int xp;
866
867 findpos(wp, new, (headr_t **)&wp->winlink, &xp);
868 wp->winpos = new; /* The position of the start of the window */
869 wp->winoff = new - xp; /* The position of the first char in winlink */
870 }
871
872 #else /* FASTPOS */
873
874 /*
875 * Find current window start position (dummy).
876 */
877 EXPORT void
findwpos(new)878 findwpos(new)
879 epos_t new;
880 {
881 }
882
883 #endif /* FASTPOS */
884
885 /*
886 * Find link pointer and offset in found buffer for 'pos'.
887 */
888 EXPORT void
findpos(wp,pos,returnlinkp,returnoff)889 findpos(wp, pos, returnlinkp, returnoff)
890 ewin_t *wp;
891 register epos_t pos;
892 headr_t **returnlinkp; /* To return found link header */
893 int *returnoff; /* To return found link offset */
894 {
895 register headr_t *linkp = wp->bhead;
896 #ifdef FASTPOS
897 epos_t SAVE = pos;
898 #ifdef TIMEPOS
899 struct timeval t1, t2;
900
901 gettimeofday(&t1, 0);
902 #endif /* TIMEPOS */
903 #endif /* FASTPOS */
904
905 /*cdbg("findpos(%d) caller %x", pos, getcaller());*/
906 if (pos > wp->eof)
907 pos = wp->eof;
908
909 #ifdef FASTPOS
910 if (wp->eof < wp->winoff)
911 clearwpos(wp);
912
913 #ifdef XPOSDEBUG
914 if (wp->winlink) {
915 if (((headr_t *)wp->winlink)->flags & INVALID)
916 cdbg("winoff: %lld INVALID", (Llong)wp->winoff);
917 if (((headr_t *)wp->winlink)->next == 0) {
918 cdbg("winoff: %lld winoff+winlink->size: %lld eof: %lld",
919 (Llong)wp->winoff,
920 (Llong)wp->winoff+((headr_t *)wp->winlink)->size,
921 (Llong)wp->eof);
922 }
923 }
924 #endif
925 if (wp->winlink) {
926 if (pos >= wp->winoff) {
927 linkp = wp->winlink;
928 pos -= wp->winoff;
929 } else {
930 rfindpos(wp, pos, returnlinkp, returnoff);
931 #ifdef CHECKPOS
932 goto checkpos;
933 #else
934 return;
935 #endif
936 }
937 }
938 #endif /* FASTPOS */
939 /*
940 * Find header that contains 'pos'
941 */
942 while (linkp->size <= pos) {
943 pos -= linkp->size;
944 linkp = linkp->next;
945 if (linkp == 0 || linkp->flags & INVALID) { /* Paranoia */
946 rsttmodes(wp);
947 #ifdef FASTPOS
948 error("findpos: winlink: %p winpos: %lld winoff: %lld pos: %lld eof: %lld\n",
949 (void *)wp->winlink,
950 (Llong)wp->winpos, (Llong)wp->winoff,
951 (Llong)SAVE, (Llong)wp->eof);
952 error("findpos: winlink->next: %p\n", (void *)wp_winlink(wp)->next);
953 if (linkp)
954 error("linkp: %p linkp->flags = %X\n", (void *)linkp, linkp->flags);
955 #endif
956 error("pos: %lld linkp: %p\n", (Llong)pos, (void *)linkp);
957 error("\nBAD POSITION TO BE FOUND\n");
958 flushprot(wp);
959 abort();
960 }
961 }
962 readybuffer(wp, linkp);
963 /*cdbg("findpos() returnoff: %d linkp: %X", pos, linkp);*/
964 *returnlinkp = linkp;
965 *returnoff = (int)pos;
966 #ifdef FASTPOS
967 #ifdef CHECKPOS
968 checkpos:
969 ;
970 #endif
971 #ifdef TIMEPOS
972 gettimeofday(&t2, 0);
973 t2.tv_sec -= t1.tv_sec;
974 t2.tv_usec -= t1.tv_usec;
975 while (t2.tv_usec < 0) {
976 t2.tv_usec += 1000000;
977 t2.tv_sec -= 1;
978 }
979 if (t2.tv_usec)
980 cdbg("time: %d.%06d", t2.tv_sec, t2.tv_usec);
981 #endif /* TIMEPOS */
982 #ifdef CHECKPOS
983 #ifdef TIMEPOS
984 gettimeofday(&t1, 0);
985 #endif
986 /*
987 * Uncomment to force a difference that needs to be found.
988 */
989 /* (*returnoff)++;*/
990 ckfindpos(wp, SAVE, returnlinkp, returnoff);
991 #ifdef TIMEPOS
992 gettimeofday(&t2, 0);
993 t2.tv_sec -= t1.tv_sec;
994 t2.tv_usec -= t1.tv_usec;
995 while (t2.tv_usec < 0) {
996 t2.tv_usec += 1000000;
997 t2.tv_sec -= 1;
998 }
999 if (t2.tv_usec)
1000 cdbg("Time: %d.%06d", t2.tv_sec, t2.tv_usec);
1001 #endif /* TIMEPOS */
1002 #endif /* CHECKPOS */
1003 #endif /* FASTPOS */
1004 }
1005
1006 #ifdef FASTPOS
1007 #ifdef CHECKPOS
1008 /*
1009 * Find link pointer and offset in found buffer for 'pos'.
1010 * This is the old version that may be called after the new one and
1011 * checks for diffs.
1012 */
1013 LOCAL void
ckfindpos(wp,pos,returnlinkp,returnoff)1014 ckfindpos(wp, pos, returnlinkp, returnoff)
1015 ewin_t *wp;
1016 register epos_t pos;
1017 headr_t **returnlinkp; /* To return found link header */
1018 int *returnoff; /* To return found link offset */
1019 {
1020 register headr_t *linkp = wp->bhead;
1021
1022 /*cdbg("findpos(%d) caller %x", pos, getcaller());*/
1023 if (pos > wp->eof)
1024 pos = wp->eof;
1025
1026 /*
1027 * Find header that contains 'pos'
1028 */
1029 while (linkp->size <= pos) {
1030 pos -= linkp->size;
1031 linkp = linkp->next;
1032 if (linkp == 0 || linkp->flags & INVALID) { /* Paranoia */
1033 rsttmodes(wp);
1034 error("pos: %d linkp: %X\n", pos, linkp);
1035 error("\nBAD POSITION TO BE FOUND\n");
1036 flushprot(wp);
1037 abort();
1038 }
1039 }
1040 readybuffer(wp, linkp);
1041 /*cdbg("ckfindpos() returnoff: %d linkp: %X", pos, linkp);*/
1042 if (*returnlinkp != linkp || *returnoff != pos) {
1043 cdbg("DIFF: %X o%X %d o%d caller: %X", *returnlinkp, linkp, *returnoff, pos,
1044 getcaller());
1045 writeerr(wp, "DIFF: %X o%X %d o%d", *returnlinkp, linkp, *returnoff, pos); sleep(10);
1046 }
1047 *returnlinkp = linkp;
1048 *returnoff = (int)pos;
1049 }
1050 #endif /* CHECKPOS */
1051
1052 /*
1053 * Find link pointer and offset in found buffer for 'pos'.
1054 * This is a version that only counts backwards from winlink.
1055 */
1056 LOCAL void
rfindpos(wp,pos,returnlinkp,returnoff)1057 rfindpos(wp, pos, returnlinkp, returnoff)
1058 ewin_t *wp;
1059 register epos_t pos;
1060 headr_t **returnlinkp; /* To return found link header */
1061 int *returnoff; /* To return found link offset */
1062 {
1063 register headr_t *linkp;
1064 register epos_t linkpos;
1065 epos_t SAVE = pos;
1066
1067 #ifdef TEST_FROM_EOF
1068 linkp = wp->bhead;
1069 while (linkp->next)
1070 linkp = linkp->next;
1071 linkpos = wp->eof + 1; /* XXX see buffer.c/initbufs() */
1072 linkpos -= linkp->size;
1073 #else
1074 linkp = wp->winlink;
1075 linkpos = wp->winoff;
1076 #endif
1077 /* cdbg("last: %X", linkp);*/
1078
1079 while (linkpos > pos) {
1080 linkp = linkp->prev;
1081 if (linkp == 0 || linkp->flags & INVALID) { /* Paranoia */
1082 rsttmodes(wp);
1083 #ifdef FASTPOS
1084 error("rfindpos: winlink: %p winpos: %lld winoff: %lld pos: %lld eof: %lld\n",
1085 (void *)wp->winlink,
1086 (Llong)wp->winpos, (Llong)wp->winoff,
1087 (Llong)SAVE, (Llong)wp->eof);
1088 if (linkp)
1089 error("linkp: %p linkp->flags = %X\n", (void *)linkp, linkp->flags);
1090 #endif
1091 error("pos: %lld linkp: %p\n", (Llong)pos, (void *)linkp);
1092 error("\nBAD POSITION TO BE FOUND\n");
1093 flushprot(wp);
1094 abort();
1095 }
1096 linkpos -= linkp->size;
1097 }
1098 readybuffer(wp, linkp);
1099
1100 /* cdbg("pos: %d linkp: %X linksz: %d lpos: %d loff: %d next: %X",*/
1101 /* pos, linkp, linkp->size, linkpos, pos - linkpos, linkp->next);*/
1102
1103 pos -= linkpos;
1104 *returnlinkp = linkp;
1105 *returnoff = (int)pos;
1106 }
1107 #endif /* FASTPOS */
1108