Annotation of GNUtools/libg++/libio/editbuf.cc, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.