/* * Copyright (c) 1987, 1988, 1989 Stanford University * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Stanford not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Stanford makes no representations about * the suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * TextBuffer - editable text buffer */ #include #include #include #include #include static const char NEWLINE = '\012'; TextBuffer::TextBuffer (char* t, int l, int s) { text = t; length = l; size = s; memset(text + length, 0, size - length); linecount = 1 + LinesBetween(0, length); lastline = 0; lastindex = 0; } TextBuffer::~TextBuffer () { Text(); } char TextBuffer::Char (int i) { return (i<0) ? text[0] : (i>length) ? text[length] : text[i]; } const char* TextBuffer::Text () { return text; } const char* TextBuffer::Text (int i) { return text + ((i<0) ? 0 : (i>length) ? length : i); } const char* TextBuffer::Text (int i, int) { return text + ((i<0) ? 0 : (i>length) ? length : i); } int TextBuffer::PreviousCharacter (int i) { return (i<=0) ? 0 : i-1; } int TextBuffer::NextCharacter (int i) { return (i>=length) ? length : i+1; } bool TextBuffer::IsBeginningOfText (int i) { return i <= 0; } int TextBuffer::BeginningOfText () { return 0; } bool TextBuffer::IsEndOfText (int i) { return i >= length; } int TextBuffer::EndOfText () { return length; } int TextBuffer::Height () { return linecount; } int TextBuffer::Length () { return length; } int TextBuffer::Search (Regexp* regexp, int index, int range, int stop) { int s = limit(0, stop, length); int i = limit(0, index, s); return regexp->Search(text, s, i, range); } int TextBuffer::BackwardSearch (Regexp* regexp, int index) { int i = limit(0, index, length); int r = regexp->Search(text, length, i, -i); if (r >= 0) { return regexp->BeginningOfMatch(); } else { return r; } } int TextBuffer::ForwardSearch (Regexp* regexp, int index) { int i = limit(0, index, length); int r = regexp->Search(text, length, i, length - i); if (r >= 0) { return regexp->EndOfMatch(); } else { return r; } } int TextBuffer::Match (Regexp* regexp, int index, int stop) { int s = limit(0, stop, length); int i = limit(0, index, s); return regexp->Match(text, length, i); } bool TextBuffer::BackwardMatch (Regexp* regexp, int index) { int i = limit(0, index, length); for (int j = i; j >= 0; --j) { if (regexp->Match(text, length, j) == i - j) { return true; } } return false; } bool TextBuffer::ForwardMatch (Regexp* regexp, int index) { int i = limit(0, index, length); return regexp->Match(text, length, i) >= 0; } int TextBuffer::Insert (int index, const char* string, int count) { if (index < 0 || index > length) { return 0; } else if (count < 0) { return Insert(index + count, string, -count); } else { count = min(count, size - length); memmove(text + index + count, text + index, length - index); memmove(text + index, string, count); length += count; int newlines = (count == 1) ? (*string == NEWLINE) : LinesBetween(index, index + count); linecount += newlines; if (lastindex > index) { lastindex += count; lastline += newlines; } return count; } } int TextBuffer::Delete (int index, int count) { if (index < 0 || index > length) { return 0; } else if (count < 0) { return -Delete(index + count, -count); } else { count = min(count, length - index); int oldlines = (count == 1) ? (text[index] == NEWLINE) : LinesBetween(index, index + count); if (lastindex > index + count) { lastindex -= count; lastline -= oldlines; } else if (lastindex >= index) { (void)LineNumber(index); } memmove(text + index, text + index + count, length - (index+count)); length -= count; memset(text + length, 0, count); linecount -= oldlines; return count; } } int TextBuffer::Copy (int index, char* buffer, int count) { if (index < 0 || index > length) { return 0; } else if (count < 0) { return Copy(index + count, buffer, -count); } else { count = min(count, length - index); memmove(buffer, text + index, count); return count; } } int TextBuffer::Width () { int width = 0; int i = 0; while (i != length) { width = max(width, EndOfLine(i) - i); i = BeginningOfNextLine(i); } return width; } int TextBuffer::LineIndex(int line) { int l = (line<0) ? 0 : (line>=linecount) ? linecount-1 : line; while (lastline > l) { --lastline; lastindex = BeginningOfLine(EndOfPreviousLine(lastindex)); } while (lastline < l) { ++lastline; lastindex = BeginningOfNextLine(lastindex); } if (line >= linecount) { return EndOfText(); } else { return lastindex; } } int TextBuffer::LinesBetween (int index1, int index2) { if (index1 == index2) { return 0; } else if (index1 > index2) { return -LinesBetween(index2, index1); } else { const char* start = Text(index1); const char* finish = Text(index2); const char* tt; int l = 0; while (start < finish) { tt = (const char*) memchr(start, NEWLINE, finish - start); if (tt == nil) { break; } start = tt + 1; ++l; } return l; } } int TextBuffer::LineNumber (int index) { int l = LinesBetween(lastindex, index); lastline += l; lastindex = BeginningOfLine(index); return lastline; } int TextBuffer::LineOffset (int index) { return (index<0) ? 0 : (index>length) ? 0 : index-BeginningOfLine(index); } bool TextBuffer::IsBeginningOfLine (int index) { const char* t = Text(index); return t <= text || *(t-1) == NEWLINE; } int TextBuffer::BeginningOfLine (int index) { const char* t = Text(index); while (t > text && *(t-1) != NEWLINE) { --t; } return t - text; } int TextBuffer::BeginningOfNextLine (int index) { const char* t = Text(index); const char* e = text + length; t = (const char*) memchr(t, NEWLINE, e - t); if (t == nil) { return length; } else { return t - text + 1; } } bool TextBuffer::IsEndOfLine (int index) { const char* t = Text(index); return t >= text + length || *t == NEWLINE; } int TextBuffer::EndOfLine (int index) { const char* t = Text(index); const char* e = text + length; t = (const char*) memchr(t, NEWLINE, e - t); if (t == nil) { return length; } else { return t - text; } } int TextBuffer::EndOfPreviousLine (int index) { const char* t = Text(index-1); while (t > text && *t != NEWLINE) { --t; } return t - text; } bool TextBuffer::IsBeginningOfWord (int index) { const char* t = Text(index); return t <= text || !isalnum(*(t-1)) && isalnum(*t); } int TextBuffer::BeginningOfWord (int index) { const char* t = Text(index); while (t > text && !(!isalnum(*(t-1)) && isalnum(*t))) { --t; } return t - text; } int TextBuffer::BeginningOfNextWord (int index) { const char* t = Text(index+1); while (t < text+length && !(!isalnum(*(t-1)) && isalnum(*t))) { ++t; } return t - text; } bool TextBuffer::IsEndOfWord (int index) { const char* t = Text(index); return t >= text+length || isalnum(*(t-1)) && !isalnum(*t); } int TextBuffer::EndOfWord (int index) { const char* t = Text(index); while (t < text+length && !(isalnum(*(t-1)) && !isalnum(*t))) { ++t; } return t - text; } int TextBuffer::EndOfPreviousWord (int index) { const char* t = Text(index-1); while (t > text && !(isalnum(*(t-1)) && !isalnum(*t))) { --t; } return t - text; }