c4_String c4_String::Mid(int nFirst, int nCount)const { if (nFirst >= GetLength()) return c4_String(); if (nFirst + nCount > GetLength()) nCount = GetLength() - nFirst; if (nFirst == 0 && nCount == GetLength()) return *this; return c4_String(Data() + nFirst, nCount); }
void c4_HandlerSeq::Prepare(const t4_byte **ptr_, bool selfDesc_) { if (ptr_ != 0) { d4_dbgdef(t4_i32 sias =)c4_Column::PullValue(*ptr_); d4_assert(sias == 0); // not yet if (selfDesc_) { t4_i32 n = c4_Column::PullValue(*ptr_); if (n > 0) { c4_String s = "[" + c4_String((const char *) * ptr_, n) + "]"; const char *desc = s; c4_Field *f = d4_new c4_Field(desc); d4_assert(! *desc); Restructure(*f, false); *ptr_ += n; } } int rows = (int)c4_Column::PullValue(*ptr_); if (rows > 0) { SetNumRows(rows); for (int i = 0; i < NumFields(); ++i) { NthHandler(i).Define(rows, ptr_); } } }
c4_String c4_String::Right(int nCount) const { if (nCount >= GetLength()) return *this; return c4_String (Data() + GetLength() - nCount, nCount); }
void c4_Persist::LoadAll() { c4_Column walk(this); if (!LoadIt(walk)) return ; if (_strategy._rootLen < 0) { _oldSeek = _strategy._rootPos; _oldBuf = d4_new t4_byte[512]; _oldCurr = _oldLimit = _oldBuf; t4_i32 n = FetchOldValue(); d4_assert(n == 0); n = FetchOldValue(); d4_assert(n > 0); c4_Bytes temp; t4_byte *buf = temp.SetBuffer(n); d4_dbgdef(int n2 = )OldRead(buf, n); d4_assert(n2 == n); c4_String s = "[" + c4_String((const char*)buf, n) + "]"; const char *desc = s; c4_Field *f = d4_new c4_Field(desc); d4_assert(! *desc); //?_root->DefineRoot(); _root->Restructure(*f, false); _root->OldPrepare(); // don't touch data inside while converting the file if (_strategy.FileSize() >= 0) OccupySpace(1, _strategy.FileSize()); } else {
c4_String c4_String::Left(int nCount) const { if (nCount >= GetLength()) return *this; return c4_String (Data(), nCount); }
c4_Field::c4_Field(const char * &description_, c4_Field *parent_): _type(0) { _indirect = this; size_t n = strcspn(description_, ",[]"); const char *p = strchr(description_, ':'); if (p != 0 && p < description_ + n) { _name = c4_String(description_, p - description_); _type = p[1] &~0x20; // force to upper case } else { _name = c4_String(description_, n); _type = 'S'; } description_ += n; if (*description_ == '[') { ++description_; _type = 'V'; if (*description_ == '^') { ++description_; _indirect = parent_; d4_assert(*description_ == ']'); } if (*description_ == ']') ++description_; else do { // 2004-01-20 ignore duplicate property names // (since there is no good way to report errors at this point) c4_Field *sf = d4_new c4_Field(description_, this); for (int i = 0; i < NumSubFields(); ++i) if (SubField(i).Name().CompareNoCase(sf->Name()) == 0) { delete sf; sf = 0; break; } if (sf != 0) _subFields.Add(sf); } while (*description_++ == ','); } }
/// Define the complete view structure of the storage void c4_Storage::SetStructure(const char *description_) { d4_assert(description_ != 0); if (description_ != Description()) { c4_String s = "[" + c4_String(description_) + "]"; description_ = s; c4_Field *field = d4_new c4_Field(description_); d4_assert(! *description_); d4_assert(field != 0); Persist()->Root().Restructure(*field, false); } }
c4_Field::c4_Field (const char*& description_, c4_Field* parent_) : _type (0) { _indirect = this; size_t n = strcspn(description_, ",[]"); const char* p = strchr(description_, ':'); if (p != 0 && p < description_ + n) { _name = c4_String (description_, p - description_); _type = p[1] & ~0x20; // force to upper case } else { _name = c4_String (description_, n); _type = 'S'; } description_ += n; if (*description_ == '[') { ++description_; _type = 'V'; if (*description_ == '^') { ++description_; _indirect = parent_; d4_assert(*description_ == ']'); } if (*description_ == ']') ++description_; else do _subFields.Add(d4_new c4_Field (description_, this)); while (*description_++ == ','); } }
void TestResize() { B(r00, Simple insert, 0)W(r00a); { CResizer r1("r00a"); int n = r1.Ins(0, 250); A(n == 250); } D(r00a); R(r00a); E; B(r01, Simple removes, 0)W(r01a); { CResizer r1("r01a"); int n; n = r1.Ins(0, 500); A(n == 500); n = r1.Del(0, 50); A(n == 450); n = r1.Del(350, 100); A(n == 350); n = r1.Del(25, 150); A(n == 200); n = r1.Del(0, 200); A(n == 0); n = r1.Ins(0, 15); A(n == 15); } D(r01a); R(r01a); E; B(r02, Large inserts and removes, 0)W(r02a); { int big = sizeof(int) == sizeof(short) ? 1000 : 4000; CResizer r1("r02a"); int n; n = r1.Ins(0, 2000); A(n == 2000); n = r1.Ins(0, 3000); A(n == 5000); n = r1.Ins(5000, 1000+big); A(n == 6000+big); n = r1.Ins(100, 10); A(n == 6010+big); n = r1.Ins(4000, 100); A(n == 6110+big); n = r1.Ins(0, 1001); A(n == 7111+big); n = r1.Del(7111, big); A(n == 7111); n = r1.Del(0, 4111); A(n == 3000); n = r1.Del(10, 10); A(n == 2990); n = r1.Del(10, 10); A(n == 2980); n = r1.Del(5, 10); A(n == 2970); n = r1.Del(0, 990); A(n == 1980); n = r1.Del(3, 1975); A(n == 5); } D(r02a); R(r02a); E; B(r03, Binary property insertions, 0)W(r03a); { c4_BytesProp p1("p1"); c4_Storage s1("r03a", 1); s1.SetStructure("a[p1:B]"); c4_View v1 = s1.View("a"); char buf[1024]; memset(buf, 0x11, sizeof buf); v1.Add(p1[c4_Bytes(buf, sizeof buf)]); memset(buf, 0x22, sizeof buf); v1.Add(p1[c4_Bytes(buf, sizeof buf / 2)]); s1.Commit(); memset(buf, 0x33, sizeof buf); p1(v1[1]) = c4_Bytes(buf, sizeof buf); // fix c4_Column::CopyData memset(buf, 0x44, sizeof buf); v1.Add(p1[c4_Bytes(buf, sizeof buf / 3)]); s1.Commit(); memset(buf, 0x55, sizeof buf); v1.InsertAt(1, p1[c4_Bytes(buf, sizeof buf)]); memset(buf, 0x66, sizeof buf); v1.InsertAt(1, p1[c4_Bytes(buf, sizeof buf / 4)]); s1.Commit(); } D(r03a); R(r03a); E; B(r04, Scripted string property tests, 0)W(r04a); { c4_StringProp p1("p1"); c4_Storage s1("r04a", 1); s1.SetStructure("a[p1:S]"); // This code implements a tiny language to specify tests in: // // "<X>,<Y>A" add X partial buffers of size Y // "<X>a" add X full buffers at end // "<X>,<Y>C" change entry X to a partial buffer of size Y // "<X>c" change entry at position X to a full buffer // "<X>,<Y>I" insert partial buffer of size Y at position X // "<X>i" insert a full buffer at position X // "<X>,<Y>R" remove Y entries at position X // "<X>r" remove one entry at position X // // ">" commit changes // "<" rollback changes // // " " ignore spaces // "<X>," for additional args // "<X>=" verify number of rows is X const char *scripts[] = { // A B C D E F G H I J "5a 5a 5a 1r 5r 10r 6r 2r > 10=", "5a 5a 5a 1,200C 5,200C 10,200C 6,200C 2,200C > 15=", "5a 5a 5a 1,300C 5,300C 10,300C 6,300C 2,300C > 15=", // A B C D E F G H I J "50a 50a 50a 10r 50r 100r 60r 20r > 145=", "50a 50a 50a 10,200C 50,200C 100,200C 60,200C 20,200C > 150=", "50a 50a 50a 10,300C 50,300C 100,300C 60,300C 20,300C > 150=", // A B C D E F G H I J "50,0A 50,0A 50,0A 10c 50c 100c 60c 20c > 150=", // asserts in 1.7b1 // A B C D E "3,3A 1,10C 1,1C > 3=", // asserts in 1.7 - June 6 build "", 0 }; for (int i = 0; scripts[i]; ++i) { c4_View v1 = s1.View("a"); v1.RemoveAll(); s1.Commit(); A(v1.GetSize() == 0); // start with a clean slate each time const char *p = scripts[i]; char fill = '@'; int save = 0; c4_Row row; while (*p) { // default is a string of 255 chars (with additional null byte) p1(row) = c4_String(++fill, 255); int arg = (int)strtol(p, (char **) &p, 10); // loses const switch (*p++) { case 'A': p1(row) = c4_String(fill, arg); arg = save; case 'a': while (--arg >= 0) v1.Add(row); break; case 'C': p1(row) = c4_String(fill, arg); arg = save; case 'c': v1.SetAt(arg, row); break; case 'I': p1(row) = c4_String(fill, arg); arg = save; case 'i': v1.InsertAt(arg, row); break; case 'R': v1.RemoveAt(save, arg); break; case 'r': v1.RemoveAt(arg); break; case '>': s1.Commit(); break; case '<': s1.Rollback(); v1 = s1.View("a"); break; case ' ': break; case ',': save = arg; break; case '=': A(v1.GetSize() == arg); break; } } } s1.Commit(); } D(r04a); R(r04a); E; }
void TestStores4() { B(s30, Memo storage, 0)W(s30a); { c4_Bytes hi("hi", 2); c4_Bytes gday("gday", 4); c4_Bytes hello("hello", 5); c4_MemoProp p1("p1"); c4_Storage s1("s30a", 1); s1.SetStructure("a[p1:B]"); c4_View v1 = s1.View("a"); v1.Add(p1[hi]); A(p1(v1[0]) == hi); v1.Add(p1[hello]); A(p1(v1[0]) == hi); A(p1(v1[1]) == hello); v1.InsertAt(1, p1[gday]); A(p1(v1[0]) == hi); A(p1(v1[1]) == gday); A(p1(v1[2]) == hello); s1.Commit(); A(p1(v1[0]) == hi); A(p1(v1[1]) == gday); A(p1(v1[2]) == hello); } D(s30a); R(s30a); E; // this failed in the unbuffered 1.8.5a interim release in Mk4tcl 1.0.5 B(s31, Check sort buffer use, 0)W(s31a); { c4_IntProp p1("p1"); c4_Storage s1("s31a", 1); s1.SetStructure("a[p1:I]"); c4_View v1 = s1.View("a"); v1.Add(p1[3]); v1.Add(p1[1]); v1.Add(p1[2]); s1.Commit(); c4_View v2 = v1.SortOn(p1); A(v2.GetSize() == 3); A(p1(v2[0]) == 1); A(p1(v2[1]) == 2); A(p1(v2[2]) == 3); } D(s31a); R(s31a); E; // this failed in 1.8.6, fixed 19990828 B(s32, Set memo empty or same size, 0)W(s32a); { c4_Bytes empty; c4_Bytes full("full", 4); c4_Bytes more("more", 4); c4_MemoProp p1("p1"); c4_Storage s1("s32a", 1); s1.SetStructure("a[p1:B]"); c4_View v1 = s1.View("a"); v1.Add(p1[full]); A(p1(v1[0]) == full); s1.Commit(); A(p1(v1[0]) == full); p1(v1[0]) = empty; A(p1(v1[0]) == empty); s1.Commit(); A(p1(v1[0]) == empty); p1(v1[0]) = more; A(p1(v1[0]) == more); s1.Commit(); A(p1(v1[0]) == more); p1(v1[0]) = full; A(p1(v1[0]) == full); s1.Commit(); A(p1(v1[0]) == full); } D(s32a); R(s32a); E; // this failed in 1.8.6, fixed 19990828 B(s33, Serialize memo fields, 0)W(s33a); W(s33b); W(s33c); { c4_Bytes hi("hi", 2); c4_Bytes gday("gday", 4); c4_Bytes hello("hello", 5); c4_MemoProp p1("p1"); c4_Storage s1("s33a", 1); s1.SetStructure("a[p1:B]"); c4_View v1 = s1.View("a"); v1.Add(p1[hi]); v1.Add(p1[gday]); v1.Add(p1[hello]); A(p1(v1[0]) == hi); A(p1(v1[1]) == gday); A(p1(v1[2]) == hello); s1.Commit(); A(p1(v1[0]) == hi); A(p1(v1[1]) == gday); A(p1(v1[2]) == hello); { c4_FileStream fs1(fopen("s33b", "wb"), true); s1.SaveTo(fs1); } c4_Storage s2("s33c", 1); c4_FileStream fs2(fopen("s33b", "rb"), true); s2.LoadFrom(fs2); c4_View v2 = s2.View("a"); A(p1(v2[0]) == hi); A(p1(v2[1]) == gday); A(p1(v2[2]) == hello); s2.Commit(); A(p1(v2[0]) == hi); A(p1(v2[1]) == gday); A(p1(v2[2]) == hello); s2.Commit(); A(p1(v2[0]) == hi); A(p1(v2[1]) == gday); A(p1(v2[2]) == hello); } D(s33a); D(s33b); D(s33c); R(s33a); R(s33b); R(s33c); E; // check smarter commit and commit failure on r/o B(s34, Smart and failed commits, 0)W(s34a); { c4_IntProp p1("p1"); { c4_Storage s1("s34a", 1); s1.SetStructure("a[p1:I]"); c4_View v1 = s1.View("a"); v1.Add(p1[111]); A(v1.GetSize() == 1); A(p1(v1[0]) == 111); bool f1 = s1.Commit(); A(f1); A(v1.GetSize() == 1); A(p1(v1[0]) == 111); bool f2 = s1.Commit(); A(f2); // succeeds, but should not write anything A(v1.GetSize() == 1); A(p1(v1[0]) == 111); } { c4_Storage s1("s34a", 0); c4_View v1 = s1.View("a"); v1.Add(p1[222]); A(v1.GetSize() == 2); A(p1(v1[0]) == 111); A(p1(v1[1]) == 222); bool f1 = s1.Commit(); A(!f1); A(v1.GetSize() == 2); A(p1(v1[0]) == 111); A(p1(v1[1]) == 222); } } D(s34a); R(s34a); E; B(s35, Datafile with preamble, 0)W(s35a); { { c4_FileStream fs1(fopen("s35a", "wb"), true); fs1.Write("abc", 3); } c4_IntProp p1("p1"); { c4_Storage s1("s35a", 1); s1.SetStructure("a[p1:I]"); c4_View v1 = s1.View("a"); v1.Add(p1[111]); A(v1.GetSize() == 1); A(p1(v1[0]) == 111); bool f1 = s1.Commit(); A(f1); A(v1.GetSize() == 1); A(p1(v1[0]) == 111); bool f2 = s1.Commit(); A(f2); // succeeds, but should not write anything A(v1.GetSize() == 1); A(p1(v1[0]) == 111); } { c4_FileStream fs1(fopen("s35a", "rb"), true); char buffer[10]; int n1 = fs1.Read(buffer, 3); A(n1 == 3); A(c4_String(buffer, 3) == "abc"); } { c4_Storage s1("s35a", 0); c4_View v1 = s1.View("a"); A(v1.GetSize() == 1); A(p1(v1[0]) == 111); v1.Add(p1[222]); A(v1.GetSize() == 2); A(p1(v1[0]) == 111); A(p1(v1[1]) == 222); bool f1 = s1.Commit(); A(!f1); A(v1.GetSize() == 2); A(p1(v1[0]) == 111); A(p1(v1[1]) == 222); } } D(s35a); R(s35a); E; B(s36, Commit after load, 0)W(s36a); W(s36b); { c4_IntProp p1("p1"); c4_Storage s1("s36a", 1); s1.SetStructure("a[p1:I]"); c4_View v1 = s1.View("a"); v1.Add(p1[111]); A(v1.GetSize() == 1); A(p1(v1[0]) == 111); { c4_FileStream fs1(fopen("s36b", "wb"), true); s1.SaveTo(fs1); } p1(v1[0]) = 222; v1.Add(p1[333]); bool f1 = s1.Commit(); A(f1); A(v1.GetSize() == 2); A(p1(v1[0]) == 222); A(p1(v1[1]) == 333); c4_FileStream fs2(fopen("s36b", "rb"), true); s1.LoadFrom(fs2); //A(v1.GetSize() == 0); // should be detached, but it's still 2 c4_View v2 = s1.View("a"); A(v2.GetSize() == 1); A(p1(v2[0]) == 111); // this fails in 2.4.0, reported by James Lupo, August 2001 bool f2 = s1.Commit(); A(f2); } D(s36a); D(s36b); R(s36a); R(s36b); E; // fails in 2.4.1, reported Oct 31. 2001 by Steve Baxter B(s37, Change short partial fields, 0)W(s37a); { c4_BytesProp p1("p1"); c4_Storage s1("s37a", true); c4_View v1 = s1.GetAs("v1[key:I,p1:B]"); v1.Add(p1[c4_Bytes("12345", 6)]); A(v1.GetSize() == 1); s1.Commit(); c4_Bytes buf = p1(v1[0]); A(buf.Size() == 6); A(buf == c4_Bytes("12345", 6)); buf = p1(v1[0]).Access(1, 3); A(buf == c4_Bytes("234", 3)); p1(v1[0]).Modify(c4_Bytes("ab", 2), 2, 0); s1.Commit(); buf = p1(v1[0]); A(buf == c4_Bytes("12ab5", 6)); } D(s37a); R(s37a); E; // Gross memory use (but no leaks), January 2002, Murat Berk B(s38, Lots of empty subviews, 0)W(s38a); { c4_BytesProp p1("p1"); { c4_Storage s1("s38a", true); c4_View v = s1.GetAs("v[v1[p1:S]]"); v.SetSize(100000); s1.Commit(); } { c4_Storage s2("s38a", true); c4_View v2 = s2.View("v"); // this should not materialize all the empty subviews v2.SetSize(v2.GetSize() + 1); // nor should this s2.Commit(); } { c4_Storage s3("s38a", true); c4_View v3 = s3.View("v"); v3.RemoveAt(1, v3.GetSize() - 2); A(v3.GetSize() == 2); s3.Commit(); } } D(s38a); R(s38a); E; // Fix bug introduced on 7-2-2002, as reported by M. Berk B(s39, Do not detach empty top-level views, 0)W(s39a); { c4_IntProp p1("p1"); c4_Storage s1("s39a", true); c4_View v1 = s1.GetAs("v1[p1:I]"); s1.Commit(); A(v1.GetSize() == 0); v1.Add(p1[123]); A(v1.GetSize() == 1); s1.Commit(); c4_View v2 = s1.View("v1"); A(v2.GetSize() == 1); // fails with 0 due to recent bug } D(s39a); R(s39a); E; }
//--------------------------------------------------------------------------- void __fastcall TMainForm::DataGridDrawCell(TObject *Sender, int Col, int Row, TRect &Rect, TGridDrawState State) { char buf [100]; const char* s = buf; if (Col > 0) { int c = _colNum >= 0 ? _colNum : Col - 1; if (c >= _data.NumProperties()) return; // empty storage c4_Property prop (_data.NthProperty(c)); char type = prop.Type(); if (Row > 0) { c4_RowRef r = _data[Row-1]; switch (type) { case 'I': wsprintf(buf, "%ld", (long) ((c4_IntProp&) prop)(r)); break; case 'F': gcvt(((c4_FloatProp&) prop)(r), 6, buf); break; case 'D': gcvt(((c4_DoubleProp&) prop)(r), 12, buf); break; case 'S': s = ((c4_StringProp&) prop)(r); //{ static c4_String t; t = s; s = t; } //wsprintf(buf, "%ld", strlen(s)); s = buf; break; case 'B': case 'M': wsprintf(buf, "(%db)", prop(r).GetSize()); break; case 'V': wsprintf(buf, "[#%d]", ((c4_View) ((c4_ViewProp&) prop)(r)).GetSize()); break; } } else { strcpy(buf, (c4_String) prop.Name() + ":" + (c4_String) type); } } else if (Row > 0) { wsprintf(buf, "%ld", Row - 1); // "poor man's right alignment" int n = strlen(s); if (n < 5) // tricky, because two spaces is the width of one digit strcpy(buf, c4_String (' ', 10 - 2 * n) + s); } else { s = ""; } AnsiString as (s); if (as.Length() > 1000) // TextRect seems to crash with huge strings as.SetLength(1000); DataGrid->Canvas->TextRect(Rect, Rect.Left + 3, Rect.Top, as); }