|
|
1.1 ! root 1: /* This is part of libio/iostream, providing -*- C++ -*- input/output. ! 2: Copyright (C) 1993 Free Software Foundation ! 3: ! 4: This file is part of the GNU IO Library. This library is free ! 5: software; you can redistribute it and/or modify it under the ! 6: terms of the GNU General Public License as published by the ! 7: Free Software Foundation; either version 2, or (at your option) ! 8: any later version. ! 9: ! 10: This library is distributed in the hope that it will be useful, ! 11: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 13: GNU General Public License for more details. ! 14: ! 15: You should have received a copy of the GNU General Public License ! 16: along with GNU CC; see the file COPYING. If not, write to ! 17: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ! 18: ! 19: As a special exception, if you link this library with files ! 20: compiled with a GNU compiler to produce an executable, this does not cause ! 21: the resulting executable to be covered by the GNU General Public License. ! 22: This exception does not however invalidate any other reasons why ! 23: the executable file might be covered by the GNU General Public License. ! 24: ! 25: Written by Per Bothner ([email protected]). */ ! 26: ! 27: #ifdef __GNUG__ ! 28: #pragma implementation ! 29: #endif ! 30: #include "libioP.h" ! 31: #include "editbuf.h" ! 32: #include <stddef.h> ! 33: extern "C" { ! 34: #include <stdlib.h> ! 35: } ! 36: /* NOTE: Some of the code here is taken from GNU emacs */ ! 37: /* Hence this file falls under the GNU License! */ ! 38: ! 39: // Invariants for edit_streambuf: ! 40: // An edit_streambuf is associated with a specific edit_string, ! 41: // which again is a sub-string of a specific edit_buffer. ! 42: // An edit_streambuf is always in either get mode or put mode, never both. ! 43: // In get mode, gptr() is the current position, ! 44: // and pbase(), pptr(), and epptr() are all NULL. ! 45: // In put mode, pptr() is the current position, ! 46: // and eback(), gptr(), and egptr() are all NULL. ! 47: // Any edit_streambuf that is actively doing insertion (as opposed to ! 48: // replacing) // must have its pptr() pointing to the start of the gap. ! 49: // Only one edit_streambuf can be actively inserting into a specific ! 50: // edit_buffer; the edit_buffer's _writer field points to that edit_streambuf. ! 51: // That edit_streambuf "owns" the gap, and the actual start of the ! 52: // gap is the pptr() of the edit_streambuf; the edit_buffer::_gap_start pointer ! 53: // will only be updated on an edit_streambuf::overflow(). ! 54: ! 55: int edit_streambuf::truncate() ! 56: { ! 57: str->buffer->delete_range(str->buffer->tell((buf_char*)pptr()), ! 58: str->buffer->tell(str->end)); ! 59: return 0; ! 60: } ! 61: ! 62: #ifdef OLD_STDIO ! 63: inline void disconnect_gap_from_file(edit_buffer* buffer, FILE* fp) ! 64: { ! 65: if (buffer->gap_start_ptr != &fp->__bufp) ! 66: return; ! 67: buffer->gap_start_normal = fp->__bufp; ! 68: buffer->gap_start_ptr = &buffer->gap_start_normal; ! 69: } ! 70: #endif ! 71: ! 72: void edit_streambuf::flush_to_buffer(edit_buffer* buffer) ! 73: { ! 74: if (pptr() > buffer->_gap_start && pptr() < buffer->gap_end()) ! 75: buffer->_gap_start = pptr(); ! 76: } ! 77: ! 78: void edit_streambuf::disconnect_gap_from_file(edit_buffer* buffer) ! 79: { ! 80: if (buffer->_writer != this) return; ! 81: flush_to_buffer(buffer); ! 82: setp(pptr(),pptr()); ! 83: buffer->_writer = NULL; ! 84: } ! 85: ! 86: buf_index edit_buffer::tell(buf_char *ptr) ! 87: { ! 88: if (ptr <= gap_start()) ! 89: return ptr - data; ! 90: else ! 91: return ptr - gap_end() + size1(); ! 92: } ! 93: ! 94: #if 0 ! 95: buf_index buf_cookie::tell() ! 96: { ! 97: return str->buffer->tell(file->__bufp); ! 98: } ! 99: #endif ! 100: ! 101: buf_index edit_buffer::tell(edit_mark*mark) ! 102: { ! 103: return tell(data + mark->index_in_buffer(this)); ! 104: } ! 105: ! 106: // adjust the position of the gap ! 107: ! 108: void edit_buffer::move_gap(buf_offset pos) ! 109: { ! 110: if (pos < size1()) ! 111: gap_left (pos); ! 112: else if (pos > size1()) ! 113: gap_right (pos); ! 114: } ! 115: ! 116: void edit_buffer::gap_left (int pos) ! 117: { ! 118: register buf_char *to, *from; ! 119: register int i; ! 120: int new_s1; ! 121: ! 122: i = size1(); ! 123: from = gap_start(); ! 124: to = from + gap_size(); ! 125: new_s1 = size1(); ! 126: ! 127: /* Now copy the characters. To move the gap down, ! 128: copy characters up. */ ! 129: ! 130: for (;;) ! 131: { ! 132: /* I gets number of characters left to copy. */ ! 133: i = new_s1 - pos; ! 134: if (i == 0) ! 135: break; ! 136: #if 0 ! 137: /* If a quit is requested, stop copying now. ! 138: Change POS to be where we have actually moved the gap to. */ ! 139: if (QUITP) ! 140: { ! 141: pos = new_s1; ! 142: break; ! 143: } ! 144: #endif ! 145: /* Move at most 32000 chars before checking again for a quit. */ ! 146: if (i > 32000) ! 147: i = 32000; ! 148: new_s1 -= i; ! 149: while (--i >= 0) ! 150: *--to = *--from; ! 151: } ! 152: ! 153: /* Adjust markers, and buffer data structure, to put the gap at POS. ! 154: POS is where the loop above stopped, which may be what was specified ! 155: or may be where a quit was detected. */ ! 156: adjust_markers (pos << 1, size1() << 1, gap_size(), data); ! 157: #ifndef OLD_STDIO ! 158: _gap_start = data + pos; ! 159: #else ! 160: if (gap_start_ptr == &gap_start_normal) ! 161: gap_start_normal = data + pos; ! 162: #endif ! 163: __gap_end_pos = to - data; ! 164: /* QUIT;*/ ! 165: } ! 166: ! 167: void edit_buffer::gap_right (int pos) ! 168: { ! 169: register buf_char *to, *from; ! 170: register int i; ! 171: int new_s1; ! 172: ! 173: i = size1(); ! 174: to = gap_start(); ! 175: from = i + gap_end(); ! 176: new_s1 = i; ! 177: ! 178: /* Now copy the characters. To move the gap up, ! 179: copy characters down. */ ! 180: ! 181: while (1) ! 182: { ! 183: /* I gets number of characters left to copy. */ ! 184: i = pos - new_s1; ! 185: if (i == 0) ! 186: break; ! 187: #if 0 ! 188: /* If a quit is requested, stop copying now. ! 189: Change POS to be where we have actually moved the gap to. */ ! 190: if (QUITP) ! 191: { ! 192: pos = new_s1; ! 193: break; ! 194: } ! 195: #endif ! 196: /* Move at most 32000 chars before checking again for a quit. */ ! 197: if (i > 32000) ! 198: i = 32000; ! 199: new_s1 += i; ! 200: while (--i >= 0) ! 201: *to++ = *from++; ! 202: } ! 203: ! 204: adjust_markers ((size1() + gap_size()) << 1, (pos + gap_size()) << 1, ! 205: - gap_size(), data); ! 206: #ifndef OLD_STDIO ! 207: _gap_start = data+pos; ! 208: #else ! 209: if (gap_start_ptr == &gap_start_normal) ! 210: gap_start_normal = data + pos; ! 211: #endif ! 212: __gap_end_pos = from - data; ! 213: /* QUIT;*/ ! 214: } ! 215: ! 216: /* make sure that the gap in the current buffer is at least k ! 217: characters wide */ ! 218: ! 219: void edit_buffer::make_gap(buf_offset k) ! 220: { ! 221: register buf_char *p1, *p2, *lim; ! 222: buf_char *old_data = data; ! 223: int s1 = size1(); ! 224: ! 225: if (gap_size() >= k) ! 226: return; ! 227: ! 228: /* Get more than just enough */ ! 229: if (buf_size > 1000) k += 2000; ! 230: else k += /*200;*/ 20; // for testing! ! 231: ! 232: p1 = (buf_char *) realloc (data, s1 + size2() + k); ! 233: if (p1 == 0) ! 234: abort(); /*memory_full ();*/ ! 235: ! 236: k -= gap_size(); /* Amount of increase. */ ! 237: ! 238: /* Record new location of text */ ! 239: data = p1; ! 240: ! 241: /* Transfer the new free space from the end to the gap ! 242: by shifting the second segment upward */ ! 243: p2 = data + buf_size; ! 244: p1 = p2 + k; ! 245: lim = p2 - size2(); ! 246: while (lim < p2) ! 247: *--p1 = *--p2; ! 248: ! 249: /* Finish updating text location data */ ! 250: __gap_end_pos += k; ! 251: ! 252: #ifndef OLD_STDIO ! 253: _gap_start = data + s1; ! 254: #else ! 255: if (gap_start_ptr == &gap_start_normal) ! 256: gap_start_normal = data + s1; ! 257: #endif ! 258: ! 259: /* adjust markers */ ! 260: adjust_markers (s1 << 1, (buf_size << 1) + 1, k, old_data); ! 261: buf_size += k; ! 262: } ! 263: ! 264: /* Add `amount' to the position of every marker in the current buffer ! 265: whose current position is between `from' (exclusive) and `to' (inclusive). ! 266: Also, any markers past the outside of that interval, in the direction ! 267: of adjustment, are first moved back to the near end of the interval ! 268: and then adjusted by `amount'. */ ! 269: ! 270: void edit_buffer::adjust_markers(register mark_pointer low, ! 271: register mark_pointer high, ! 272: int amount, buf_char *old_data) ! 273: { ! 274: register struct edit_mark *m; ! 275: register mark_pointer mpos; ! 276: /* convert to mark_pointer */ ! 277: amount <<= 1; ! 278: ! 279: if (_writer) ! 280: _writer->disconnect_gap_from_file(this); ! 281: ! 282: for (m = mark_list(); m != NULL; m = m->chain) ! 283: { ! 284: mpos = m->_pos; ! 285: if (amount > 0) ! 286: { ! 287: if (mpos > high && mpos < high + amount) ! 288: mpos = high + amount; ! 289: } ! 290: else ! 291: { ! 292: if (mpos > low + amount && mpos <= low) ! 293: mpos = low + amount; ! 294: } ! 295: if (mpos > low && mpos <= high) ! 296: mpos += amount; ! 297: m->_pos = mpos; ! 298: } ! 299: ! 300: // Now adjust files ! 301: edit_streambuf *file; ! 302: ! 303: for (file = files; file != NULL; file = file->next) { ! 304: mpos = file->current() - old_data; ! 305: if (amount > 0) ! 306: { ! 307: if (mpos > high && mpos < high + amount) ! 308: mpos = high + amount; ! 309: } ! 310: else ! 311: { ! 312: if (mpos > low + amount && mpos <= low) ! 313: mpos = low + amount; ! 314: } ! 315: if (mpos > low && mpos <= high) ! 316: mpos += amount; ! 317: char* new_pos = data + mpos; ! 318: file->set_current(new_pos, file->is_reading()); ! 319: } ! 320: } ! 321: ! 322: #if 0 ! 323: stdio_ ! 324: __off == index at start of buffer (need only be valid after seek ? ) ! 325: __buf == ! 326: ! 327: if read/read_delete/overwrite mode: ! 328: __endp <= min(*gap_start_ptr, edit_string->end->ptr(buffer)) ! 329: ! 330: if inserting: ! 331: must have *gap_start_ptr == __bufp && *gap_start_ptr+gap == __endp ! 332: file->edit_string->end->ptr(buffer) == *gap_start_ptr+end ! 333: if write_mode: ! 334: if before gap ! 335: #endif ! 336: ! 337: int edit_streambuf::underflow() ! 338: { ! 339: if (!(_mode & ios::in)) ! 340: return EOF; ! 341: struct edit_buffer *buffer = str->buffer; ! 342: if (!is_reading()) { // Must switch from put to get mode. ! 343: disconnect_gap_from_file(buffer); ! 344: set_current(pptr(), 1); ! 345: } ! 346: buf_char *str_end = str->end->ptr(buffer); ! 347: retry: ! 348: if (gptr() < egptr()) { ! 349: return *gptr(); ! 350: } ! 351: if ((buf_char*)gptr() == str_end) ! 352: return EOF; ! 353: if (str_end <= buffer->gap_start()) { ! 354: setg(eback(), gptr(), str_end); ! 355: goto retry; ! 356: } ! 357: if (gptr() < buffer->gap_start()) { ! 358: setg(eback(), gptr(), buffer->gap_start()); ! 359: goto retry; ! 360: } ! 361: if (gptr() == buffer->gap_start()) { ! 362: disconnect_gap_from_file(buffer); ! 363: // fp->__offset += fp->__bufp - fp->__buffer; ! 364: setg(buffer->gap_end(), buffer->gap_end(), str_end); ! 365: } ! 366: else ! 367: setg(eback(), gptr(), str_end); ! 368: goto retry; ! 369: } ! 370: ! 371: int edit_streambuf::overflow(int ch) ! 372: { ! 373: if (_mode == ios::in) ! 374: return EOF; ! 375: struct edit_buffer *buffer = str->buffer; ! 376: flush_to_buffer(buffer); ! 377: if (ch == EOF) ! 378: return 0; ! 379: if (is_reading()) { // Must switch from get to put mode. ! 380: set_current(gptr(), 0); ! 381: } ! 382: buf_char *str_end = str->end->ptr(buffer); ! 383: retry: ! 384: if (pptr() < epptr()) { ! 385: *pptr() = ch; ! 386: pbump(1); ! 387: return (unsigned char)ch; ! 388: } ! 389: if ((buf_char*)pptr() == str_end || inserting()) { ! 390: /* insert instead */ ! 391: if (buffer->_writer) ! 392: buffer->_writer->flush_to_buffer(); // Redundant? ! 393: buffer->_writer = NULL; ! 394: if (pptr() >= buffer->gap_end()) ! 395: buffer->move_gap(pptr() - buffer->gap_size()); ! 396: else ! 397: buffer->move_gap(pptr()); ! 398: buffer->make_gap(1); ! 399: setp(buffer->gap_start(), buffer->gap_end()); ! 400: buffer->_writer = this; ! 401: *pptr() = ch; ! 402: pbump(1); ! 403: return (unsigned char)ch; ! 404: } ! 405: if (str_end <= buffer->gap_start()) { ! 406: // Entire string is left of gap. ! 407: setp(pptr(), str_end); ! 408: } ! 409: else if (pptr() < buffer->gap_start()) { ! 410: // Current pos is left of gap. ! 411: setp(pptr(), buffer->gap_start()); ! 412: goto retry; ! 413: } ! 414: else if (pptr() == buffer->gap_start()) { ! 415: // Current pos is at start of gap; move to end of gap. ! 416: // disconnect_gap_from_file(buffer); ! 417: setp(buffer->gap_end(), str_end); ! 418: // __offset += __bufp - __buffer; ! 419: } ! 420: else { ! 421: // Otherwise, current pos is right of gap. ! 422: setp(pptr(), str_end); ! 423: } ! 424: goto retry; ! 425: } ! 426: ! 427: void edit_streambuf::set_current(char *new_pos, int reading) ! 428: { ! 429: if (reading) { ! 430: setg(new_pos, new_pos, new_pos); ! 431: setp(NULL, NULL); ! 432: } ! 433: else { ! 434: setg(NULL, NULL, NULL); ! 435: setp(new_pos, new_pos); ! 436: } ! 437: } ! 438: ! 439: // Called by fseek(fp, pos, whence) if fp is bound to a edit_buffer. ! 440: ! 441: streampos edit_streambuf::seekoff(streamoff offset, _seek_dir dir, ! 442: int mode /* =ios::in|ios::out*/) ! 443: { ! 444: struct edit_buffer *buffer = str->buffer; ! 445: disconnect_gap_from_file(buffer); ! 446: buf_index cur_pos = buffer->tell((buf_char*)current());; ! 447: buf_index start_pos = buffer->tell(str->start); ! 448: buf_index end_pos = buffer->tell(str->end); ! 449: switch (dir) { ! 450: case ios::beg: ! 451: offset += start_pos; ! 452: break; ! 453: case ios::cur: ! 454: offset += cur_pos; ! 455: break; ! 456: case ios::end: ! 457: offset += end_pos; ! 458: break; ! 459: } ! 460: if (offset < start_pos || offset > end_pos) ! 461: return EOF; ! 462: buf_char *new_pos = buffer->data + offset; ! 463: buf_char* gap_start = buffer->gap_start(); ! 464: if (new_pos > gap_start) { ! 465: buf_char* gap_end = buffer->gap_end(); ! 466: new_pos += gap_end - gap_start; ! 467: if (new_pos >= buffer->data + buffer->buf_size) abort(); // Paranoia. ! 468: } ! 469: set_current(new_pos, is_reading()); ! 470: return EOF; ! 471: } ! 472: ! 473: #if 0 ! 474: int buf_seek(void *arg_cookie, fpos_t * pos, int whence) ! 475: { ! 476: struct buf_cookie *cookie = arg_cookie; ! 477: FILE *file = cookie->file; ! 478: struct edit_buffer *buffer = cookie->str->buffer; ! 479: buf_char *str_start = cookie->str->start->ptr(buffer); ! 480: disconnect_gap_from_file(buffer, cookie->file); ! 481: fpos_t cur_pos, new_pos; ! 482: if (file->__bufp <= *buffer->gap_start_ptr ! 483: || str_start >= buffer->__gap_end) ! 484: cur_pos = str_start - file->__bufp; ! 485: else ! 486: cur_pos = ! 487: (*buffer->gap_start_ptr - str_start) + (file->__bufp - __gap_end); ! 488: end_pos = ...; ! 489: switch (whence) { ! 490: case SEEK_SET: ! 491: new_pos = *pos; ! 492: break; ! 493: case SEEK_CUR: ! 494: new_pos = cur_pos + *pos; ! 495: break; ! 496: case SEEK_END: ! 497: new_pos = end_pos + *pos; ! 498: break; ! 499: } ! 500: if (new_pos > end_pos) { ! 501: seek to end_pos; ! 502: insert_nulls(new_pos - end_pos); ! 503: return; ! 504: } ! 505: if (str_start + new_pos <= *gap_start_ptr &* *gap_start_ptr < end) { ! 506: __buffer = str_start; ! 507: __off = 0; ! 508: __bufp = str_start + new_pos; ! 509: file->__get_limit = ! 510: *buffer->gap_start_ptr; /* what if gap_start_ptr == &bufp ??? */ ! 511: } else if () { ! 512: ! 513: } ! 514: *pos = new_pos; ! 515: } ! 516: #endif ! 517: ! 518: /* Delete characters from `from' up to (but not incl) `to' */ ! 519: ! 520: void edit_buffer::delete_range (buf_index from, buf_index to) ! 521: { ! 522: register int numdel; ! 523: ! 524: if ((numdel = to - from) <= 0) ! 525: return; ! 526: ! 527: /* Make sure the gap is somewhere in or next to what we are deleting */ ! 528: if (from > size1()) ! 529: gap_right (from); ! 530: if (to < size1()) ! 531: gap_left (to); ! 532: ! 533: /* Relocate all markers pointing into the new, larger gap ! 534: to point at the end of the text before the gap. */ ! 535: adjust_markers ((to + gap_size()) << 1, (to + gap_size()) << 1, ! 536: - numdel - gap_size(), data); ! 537: ! 538: __gap_end_pos = to + gap_size(); ! 539: _gap_start = data + from; ! 540: } ! 541: ! 542: void edit_buffer::delete_range(struct edit_mark *start, struct edit_mark *end) ! 543: { ! 544: delete_range(tell(start), tell(end)); ! 545: } ! 546: ! 547: void buf_delete_chars(struct edit_buffer *buf, struct edit_mark *mark, size_t count) ! 548: { ! 549: abort(); ! 550: } ! 551: ! 552: edit_streambuf::edit_streambuf(edit_string* bstr, int mode) ! 553: { ! 554: _mode = mode; ! 555: str = bstr; ! 556: edit_buffer* buffer = bstr->buffer; ! 557: next = buffer->files; ! 558: buffer->files = this; ! 559: char* buf_ptr = bstr->start->ptr(buffer); ! 560: _inserting = 0; ! 561: // setb(buf_ptr, buf_ptr, 0); ! 562: set_current(buf_ptr, !(mode & ios::out+ios::trunc+ios::app)); ! 563: if (_mode & ios::trunc) ! 564: truncate(); ! 565: if (_mode & ios::ate) ! 566: seekoff(0, ios::end); ! 567: } ! 568: ! 569: // Called by fclose(fp) if fp is bound to a edit_buffer. ! 570: ! 571: #if 0 ! 572: static int buf_close(void *arg) ! 573: { ! 574: register struct buf_cookie *cookie = arg; ! 575: struct edit_buffer *buffer = cookie->str->buffer; ! 576: struct buf_cookie **ptr; ! 577: for (ptr = &buffer->files; *ptr != cookie; ptr = &(*ptr)->next) ; ! 578: *ptr = cookie->next; ! 579: disconnect_gap_from_file(buffer, cookie->file); ! 580: free (cookie); ! 581: return 0; ! 582: } ! 583: #endif ! 584: ! 585: edit_streambuf::~edit_streambuf() ! 586: { ! 587: if (_mode == ios::out) ! 588: truncate(); ! 589: // Unlink this from list of files associated with bstr->buffer. ! 590: edit_streambuf **ptr = &str->buffer->files; ! 591: for (; *ptr != this; ptr = &(*ptr)->next) { } ! 592: *ptr = next; ! 593: ! 594: disconnect_gap_from_file(str->buffer); ! 595: } ! 596: ! 597: edit_buffer::edit_buffer() ! 598: { ! 599: buf_size = /*200;*/ 15; /* for testing! */ ! 600: data = (buf_char*)malloc(buf_size); ! 601: files = NULL; ! 602: #ifndef OLD_STDIO ! 603: _gap_start = data; ! 604: _writer = NULL; ! 605: #else ! 606: gap_start_normal = data; ! 607: gap_start_ptr = &gap_start_normal; ! 608: #endif ! 609: __gap_end_pos = buf_size; ! 610: start_mark.chain = &end_mark; ! 611: start_mark._pos = 0; ! 612: end_mark.chain = NULL; ! 613: end_mark._pos = 2 * buf_size + 1; ! 614: } ! 615: ! 616: // Allocate a new mark, which is adjusted by 'delta' bytes from 'this'. ! 617: // Restrict new mark to lie within 'str'. ! 618: ! 619: edit_mark::edit_mark(struct edit_string *str, long delta) ! 620: { ! 621: struct edit_buffer *buf = str->buffer; ! 622: chain = buf->start_mark.chain; ! 623: buf->start_mark.chain = this; ! 624: mark_pointer size1 = buf->size1() << 1; ! 625: int gap_size = buf->gap_size() << 1; ! 626: delta <<= 1; ! 627: ! 628: // check if new and old marks are opposite sides of gap ! 629: if (_pos <= size1 && _pos + delta > size1) ! 630: delta += gap_size; ! 631: else if (_pos >= size1 + gap_size && _pos + delta < size1 + gap_size) ! 632: delta -= gap_size; ! 633: ! 634: _pos = _pos + delta; ! 635: if (_pos < str->start->_pos & ~1) ! 636: _pos = (str->start->_pos & ~ 1) + (_pos & 1); ! 637: else if (_pos >= str->end->_pos) ! 638: _pos = (str->end->_pos & ~ 1) + (_pos & 1); ! 639: } ! 640: ! 641: // A (slow) way to find the buffer a mark belongs to. ! 642: ! 643: edit_buffer * edit_mark::buffer() ! 644: { ! 645: struct edit_mark *mark; ! 646: for (mark = this; mark->chain != NULL; mark = mark->chain) ; ! 647: // Assume that the last mark on the chain is the end_mark. ! 648: return (edit_buffer *)((char*)mark - offsetof(edit_buffer, end_mark)); ! 649: } ! 650: ! 651: edit_mark::~edit_mark() ! 652: { ! 653: // Must unlink mark from chain of owning buffer ! 654: struct edit_buffer *buf = buffer(); ! 655: if (this == &buf->start_mark || this == &buf->end_mark) abort(); ! 656: edit_mark **ptr; ! 657: for (ptr = &buf->start_mark.chain; *ptr != this; ptr = &(*ptr)->chain) ; ! 658: *ptr = this->chain; ! 659: } ! 660: ! 661: int edit_string::length() const ! 662: { ! 663: ptrdiff_t delta = end->ptr(buffer) - start->ptr(buffer); ! 664: if (end->ptr(buffer) <= buffer->gap_start() || ! 665: start->ptr(buffer) >= buffer->gap_end()) ! 666: return delta; ! 667: return delta - buffer->gap_size(); ! 668: } ! 669: ! 670: buf_char * edit_string::copy_bytes(int *lenp) const ! 671: { ! 672: char *new_str; ! 673: int len1, len2; ! 674: buf_char *start1, *start2; ! 675: start1 = start->ptr(buffer); ! 676: if (end->ptr(buffer) <= buffer->gap_start() ! 677: || start->ptr(buffer) >= buffer->gap_end()) { ! 678: len1 = end->ptr(buffer) - start1; ! 679: len2 = 0; ! 680: start2 = NULL; // To avoid a warning from g++. ! 681: } ! 682: else { ! 683: len1 = buffer->gap_start() - start1; ! 684: start2 = buffer->gap_end(); ! 685: len2 = end->ptr(buffer) - start2; ! 686: } ! 687: new_str = (char*)malloc(len1 + len2 + 1); ! 688: memcpy(new_str, start1, len1); ! 689: if (len2 > 0) memcpy(new_str + len1, start2, len2); ! 690: new_str[len1+len2] = '\0'; ! 691: *lenp = len1+len2; ! 692: return new_str; ! 693: } ! 694: ! 695: // Replace the buf_chars in 'this' with ones from 'src'. ! 696: // Equivalent to deleting this, then inserting src, except tries ! 697: // to leave marks in place: Marks whose offset from the start ! 698: // of 'this' is less than 'src->length()' will still have the ! 699: // same offset in 'this' when done. ! 700: ! 701: void edit_string::assign(struct edit_string *src) ! 702: { ! 703: edit_streambuf dst_file(this, ios::out); ! 704: if (buffer == src->buffer /*&& ???*/) { /* overly conservative */ ! 705: int src_len; ! 706: buf_char *new_str; ! 707: new_str = src->copy_bytes(&src_len); ! 708: dst_file.sputn(new_str, src_len); ! 709: free (new_str); ! 710: } else { ! 711: edit_streambuf src_file(src, ios::in); ! 712: for ( ; ; ) { ! 713: int ch = src_file.sbumpc(); ! 714: if (ch == EOF) break; ! 715: dst_file.sputc(ch); ! 716: } ! 717: } ! 718: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.