#include "ET++.ph" #ifdef __GNUG__ #pragma implementation #endif #include "CheapText.h" #include "Class.h" #include "RegularExp.h" #include "Port.h" #include "Error.h" #include "Math.h" #include "String.h" #include "TextFormatter.h" //---- CheapText --------------------------------------------------------------- NewMetaImpl(CheapText,Text, (T(capacity), TV(cont,size))); CheapText::CheapText(int s, Font *fd) { Init(s, fd, 0, 0); } CheapText::CheapText(const byte *t, int len, Font *fd) { Init(0, fd, t, len); } CheapText::CheapText(const char *t, int len, Font *fd) { Init(0, fd, (const byte*)t, len); } void CheapText::Init(int cap, Font *fd, const byte *t, int l) { if (l == -1) l= strlen((char*)t); if (cap == 0) cap= (l/5 + 1) * 6; capacity= Math::Max(cTextInitCap, cap); cont= new byte[capacity]; if (l > 0 && t) MemCpy(cont, t, l); size= l; SetFont(fd); SetDefTab(fd->Width(' ')*8); Terminate(); } void CheapText::InitNew() { Text::InitNew(); Init(0, gSysFont); } CheapText::~CheapText() { SafeDelete(cont); } void CheapText::Terminate() { if (IsTerminated()) return; byte null= '\0'; InsertBytes(&null, 1, Size(), Size()); } void CheapText::ReplaceRange(int from, int to, Text *src, int sfrom, int sto) { CheapText *ct; byte *buf= 0; if (!CheckRange(End(), from, to)) Error("PasteText", "out of range"); if (!src->IsKindOf(CheapText)) { // convert int s= sto-sfrom; buf= new byte[s+1]; src->CopyInStr(buf, s+1, sfrom, sto); sto= sto-sfrom; sfrom= 0; ct= new CheapText(buf, s); } else ct= (CheapText*)src; InsertBytes(ct->cont+sfrom, sto-sfrom, from, to); if (buf) { delete buf; delete ct; } } Text *CheapText::MakeScratchText(byte *buf, int len) { if (buf) return new CheapText(buf, len); return new CheapText(len); } void CheapText::CopyInStr(byte *str, int sz, int from, int to) { if (!CheckRange(size, from, to) || str == 0) return; register int l= Math::Min(to, from+sz-1) - from; MemCpy(str, &cont[from], l); str[l]= '\0'; } void CheapText::AddChar(int at, byte b) { InsertBytes(&b, 1, at, at); } byte *CheapText::GetLineAccess(byte**, int from, int to) { if (!CheckRange(size, from, to)) return 0; return &cont[from]; } int CheapText::Search(RegularExp *rex, int *nMatched, int start, int range, bool dir) { if (dir == cSearchForward) return rex->SearchForward((char*)cont, nMatched, start, End(), range, 0); return rex->SearchBackward((char*)cont, nMatched, start, End(), range, 0); } void CheapText::InsertBytes(byte *c, int n, int from, int to) { int shift= n - (to - from); if (HighWaterMark(shift)) Expand(GrowSize(capacity+shift)); if (shift < 0) MemCpy(&cont[to+shift], &cont[to], size-to); else if (shift > 0) MemCpy(&cont[from+shift], &cont[from], size-from); //---- insert pasted text MemCpy(&cont[from], c, n); size += shift; if (LowWaterMark()) Expand(capacity/2); } byte& CheapText::operator[](int i) { if (!CheckRange(size, i, i)) i= capacity-1; return cont[i]; } int CheapText::Size() { return size; } void CheapText::Expand(int newSize) { if (newSize < Size()) // texts never shrinks return; cont= (byte*) Storage::ReAlloc(cont, newSize); size= Math::Min(newSize, size); capacity= newSize; } TextIter *CheapText::MakeIterator(int from, int to, void *placement) { return new(placement) CheapTextIter(this, from, to); } const char *CheapText::AsString() { return (char*) cont; } OStream& CheapText::PrintOn(OStream &s) { Text::PrintOn(s); return s.PrintString(cont, size); } IStream& CheapText::ReadFrom(IStream &s) { SafeDelete(cont); Text::ReadFrom(s); s.ReadString(&cont, &capacity); size= capacity; return s; } OStream &CheapText::PrintOnAsPureText(OStream &s) { s.write(cont, End()); return s; } IStream &CheapText::ReadFromAsPureText(IStream &s, long sizeHint) { char ch; if (sizeHint > 0) { int delta= (int)(sizeHint - capacity); // !!! if (delta > 0) Expand(delta + 50); } size= 0; while (s.get(ch)) { if (HighWaterMark(1)) Expand(GrowSize(capacity+1)); cont[size++]= ch; } if (!s.eof()) Error("ReadFromAsPureText", "something strange happened"); Terminate(); return s; } //----- CheapTextIter ---------------------------------------------------------- CheapTextIter::CheapTextIter(Text *s, int from, int to) : TextIter(s, from, to) { if (!s->IsKindOf(CheapText)) Error("CheapTextIter::CheapTextIter", "CheapText expected"); font= s->GetFont(); } int CheapTextIter::operator()(int *w, LineDesc* ld) { CheapText *ctp= (CheapText*)ct; if (ld) ld->FromFont(font); unget= ce; if (ce == upto) return cEOT; int ch= ctp->cont[ce++]; if (w) *w= font->Width(ch); return ch; } int CheapTextIter::Token(int *w, LineDesc* ld) { CheapText *ctp= (CheapText*)ct; unget= ce; *w= 0; if (ld) ld->FromFont(font); if (ce >= upto) return cEOT; register int ch= ctp->CharAt(ce); if (Iswordwrap(ch)) { *w= font->Width(ch); ce++; return (ch); } while (ce < upto && !Iswordwrap(ctp->CharAt(ce))) { ch= ctp->CharAt(ce++); *w+= font->Width(ch); } return (ch); }