diff --git a/db/mork/src/Makefile.in b/db/mork/src/Makefile.in index 42a87d5cd9e0..5851607fa9f6 100644 --- a/db/mork/src/Makefile.in +++ b/db/mork/src/Makefile.in @@ -48,6 +48,7 @@ CPPSRCS = \ morkBuilder.cpp\ morkCell.cpp\ morkCellObject.cpp\ + morkCh.cpp\ morkConfig.cpp\ morkCursor.cpp \ morkDeque.cpp\ diff --git a/db/mork/src/makefile.win b/db/mork/src/makefile.win index eacc44474433..928aafe900d0 100644 --- a/db/mork/src/makefile.win +++ b/db/mork/src/makefile.win @@ -47,6 +47,7 @@ CPPSRCS= orkinCell.cpp\ morkBuilder.cpp\ morkCell.cpp\ morkCellObject.cpp\ + morkCh.cpp\ morkConfig.cpp\ morkCursor.cpp \ morkDeque.cpp\ @@ -97,6 +98,7 @@ CPP_OBJS= .\$(OBJDIR)\orkinCell.obj\ .\$(OBJDIR)\morkBuilder.obj\ .\$(OBJDIR)\morkCell.obj\ .\$(OBJDIR)\morkCellObject.obj\ + .\$(OBJDIR)\morkCh.obj\ .\$(OBJDIR)\morkConfig.obj\ .\$(OBJDIR)\morkCursor.obj\ .\$(OBJDIR)\morkDeque.obj\ diff --git a/db/mork/src/mork.h b/db/mork/src/mork.h index deb90f1de239..a2d7af251901 100644 --- a/db/mork/src/mork.h +++ b/db/mork/src/mork.h @@ -64,6 +64,8 @@ typedef unsigned long mork_u4; // make sure this is four bytes typedef long mork_i4; // make sure this is four bytes typedef long mork_ip; // make sure sizeof(mork_ip) == sizeof(void*) +typedef mork_u1 mork_ch; // small byte-sized character (never wide) + typedef mork_u2 mork_base; // 2-byte magic class signature slot in object typedef mork_u2 mork_derived; // 2-byte magic class signature slot in object typedef mork_u2 mork_uses; // 2-byte strong uses count @@ -109,6 +111,9 @@ typedef mork_u1 mork_load; // dirty or clean (clone IronDoc's fe_load) #define morkChange_kPut 'p' /* put member */ #define morkChange_kSet 's' /* set all members */ #define morkChange_kNil 0 /* no change in this member */ +#define morkChange_kDup 'd' /* duplicate changes have no effect */ +// kDup is intended to replace another change constant in an object as a +// conclusion about change feasibility while staging intended alterations. #define morkLoad_kDirty ((mork_load) 0xDD) /* same as IronDoc constant */ #define morkLoad_kClean ((mork_load) 0x22) /* same as IronDoc constant */ @@ -147,6 +152,7 @@ typedef mdb_order mork_order; // neg:lessthan, zero:equalto, pos:greaterthan // { %%%%% begin class forward defines %%%%% // try to put these in alphabetical order for easier examination: +class morkMid; class morkAtom; class morkAtomSpace; class morkBookAtom; @@ -168,6 +174,7 @@ class morkObject; class morkOidAtom; class morkParser; class morkPool; +class morkPlace; class morkPort; class morkPortTableCursor; class morkRow; @@ -175,6 +182,7 @@ class morkRowCellCursor; class morkRowObject; class morkRowSpace; class morkSpace; +class morkSpan; class morkStore; class morkStream; class morkTable; diff --git a/db/mork/src/morkAtom.h b/db/mork/src/morkAtom.h index c0a3fe8441fc..8d8868993c30 100644 --- a/db/mork/src/morkAtom.h +++ b/db/mork/src/morkAtom.h @@ -305,7 +305,7 @@ class morkMaxBookAtom : public morkBigBookAtom { // // mork_u1 mBigBookAtom_Body[ 1 ]; // 1st byte of immed content vector public: - mork_u1 mBigBookAtom_Body[ morkBookAtom_kMaxBodySize + 3 ]; // max bytes + mork_u1 mMaxBookAtom_Body[ morkBookAtom_kMaxBodySize + 3 ]; // max bytes public: // empty construction does nothing morkMaxBookAtom() { } diff --git a/db/mork/src/morkAtomMap.h b/db/mork/src/morkAtomMap.h index 26e3bdb984fb..f80992b253de 100644 --- a/db/mork/src/morkAtomMap.h +++ b/db/mork/src/morkAtomMap.h @@ -138,11 +138,11 @@ public: // dynamic type identification // { ===== begin morkMap poly interface ===== virtual mork_bool // note: equal(a,b) implies hash(a) == hash(b) Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const; - // implemented using morkBookAtom::HashFormAndBody() + // implemented using morkBookAtom::EqualFormAndBody() virtual mork_u4 // note: equal(a,b) implies hash(a) == hash(b) Hash(morkEnv* ev, const void* inKey) const; - // implemented using morkBookAtom::EqualFormAndBody() + // implemented using morkBookAtom::HashFormAndBody() // } ===== end morkMap poly interface ===== public: // other map methods diff --git a/db/mork/src/morkAtomSpace.cpp b/db/mork/src/morkAtomSpace.cpp index 8196884c0f4a..6e53095ca1f4 100644 --- a/db/mork/src/morkAtomSpace.cpp +++ b/db/mork/src/morkAtomSpace.cpp @@ -153,6 +153,32 @@ morkAtomSpace::CutAllAtoms(morkEnv* ev, morkPool* ioPool) } +morkBookAtom* +morkAtomSpace::MakeBookAtomCopyWithAid(morkEnv* ev, + const morkBigBookAtom& inAtom, mork_aid inAid) +// Make copy of inAtom and put it in both maps, using specified ID. +{ + morkBookAtom* outAtom = 0; + if ( ev->Good() ) + { + morkPool* pool = this->GetSpaceStorePool(); + outAtom = pool->NewBookAtomCopy(ev, inAtom); + if ( outAtom ) + { + outAtom->mBookAtom_Id = inAid; + outAtom->mBookAtom_Space = this; + mAtomSpace_AtomAids.AddAtom(ev, outAtom); + mAtomSpace_AtomBodies.AddAtom(ev, outAtom); + if ( mSpace_Scope == morkAtomSpace_kColumnScope ) + outAtom->MakeCellUseForever(ev); + + if ( mAtomSpace_HighUnderId <= inAid ) + mAtomSpace_HighUnderId = inAid + 1; + } + } + return outAtom; +} + morkBookAtom* morkAtomSpace::MakeBookAtomCopy(morkEnv* ev, const morkBigBookAtom& inAtom) // make copy of inAtom and put it in both maps, using a new ID as needed. @@ -167,9 +193,12 @@ morkAtomSpace::MakeBookAtomCopy(morkEnv* ev, const morkBigBookAtom& inAtom) mork_aid id = this->MakeNewAtomId(ev, atom); if ( id ) { - outAtom = atom; + outAtom = atom; + atom->mBookAtom_Space = this; mAtomSpace_AtomAids.AddAtom(ev, atom); mAtomSpace_AtomBodies.AddAtom(ev, atom); + if ( mSpace_Scope == morkAtomSpace_kColumnScope ) + outAtom->MakeCellUseForever(ev); } } } diff --git a/db/mork/src/morkAtomSpace.h b/db/mork/src/morkAtomSpace.h index 8d03534d144d..4988cab70bd7 100644 --- a/db/mork/src/morkAtomSpace.h +++ b/db/mork/src/morkAtomSpace.h @@ -64,6 +64,8 @@ #define morkDerived_kAtomSpace /*i*/ 0x6153 /* ascii 'aS' */ +#define morkAtomSpace_kColumnScope ((mork_scope) 'c') /* column scope is forever */ + /*| morkAtomSpace: |*/ class morkAtomSpace : public morkSpace { // @@ -132,6 +134,10 @@ public: // other space methods mork_num CutAllAtoms(morkEnv* ev, morkPool* ioPool); // CutAllAtoms() puts all the atoms back in the pool. + morkBookAtom* MakeBookAtomCopyWithAid(morkEnv* ev, + const morkBigBookAtom& inAtom, mork_aid inAid); + // Make copy of inAtom and put it in both maps, using specified ID. + morkBookAtom* MakeBookAtomCopy(morkEnv* ev, const morkBigBookAtom& inAtom); // Make copy of inAtom and put it in both maps, using a new ID as needed. diff --git a/db/mork/src/morkBlob.cpp b/db/mork/src/morkBlob.cpp index 7f56c5f59616..73496613f703 100644 --- a/db/mork/src/morkBlob.cpp +++ b/db/mork/src/morkBlob.cpp @@ -32,31 +32,92 @@ #include "morkEnv.h" #endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 -morkSpool::morkSpool(morkEnv* ev, nsIMdbHeap* ioHeap) +/*static*/ void +morkBuf::NilBufBodyError(morkEnv* ev) +{ + ev->NewError("nil mBuf_Body"); +} + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +/*static*/ void +morkBlob::BlobFillOverSizeError(morkEnv* ev) +{ + ev->NewError("mBuf_Fill > mBlob_Size"); +} + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +mork_bool +morkBlob::GrowBlob(morkEnv* ev, nsIMdbHeap* ioHeap, mork_size inNewSize) +{ + if ( ioHeap ) + { + if ( !mBuf_Body ) // no body? implies zero sized? + mBlob_Size = 0; + + if ( mBuf_Fill > mBlob_Size ) // fill more than size? + { + ev->NewWarning("mBuf_Fill > mBlob_Size"); + mBuf_Fill = mBlob_Size; + } + + if ( inNewSize > mBlob_Size ) // need to allocate larger blob? + { + mork_u1* body = 0; + ioHeap->Alloc(ev->AsMdbEnv(), inNewSize, (void**) &body); + if ( body && ev->Good() ) + { + void* oldBody = mBuf_Body; + if ( mBlob_Size ) // any old content to transfer? + MORK_MEMCPY(body, oldBody, mBlob_Size); + + mBlob_Size = inNewSize; // install new size + mBuf_Body = body; // install new body + + if ( oldBody ) // need to free old buffer body? + ioHeap->Free(ev->AsMdbEnv(), oldBody); + } + } + } + else + ev->NilPointerError(); + + if ( ev->Good() && mBlob_Size < inNewSize ) + ev->NewError("mBlob_Size < inNewSize"); + + return ev->Good(); +} + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +morkCoil::morkCoil(morkEnv* ev, nsIMdbHeap* ioHeap) { mBuf_Body = 0; mBuf_Fill = 0; mBlob_Size = 0; mText_Form = 0; - mSpool_Heap = ioHeap; + mCoil_Heap = ioHeap; if ( !ioHeap ) ev->NilPointerError(); } void -morkSpool::CloseSpool(morkEnv* ev) +morkCoil::CloseCoil(morkEnv* ev) { void* body = mBuf_Body; - nsIMdbHeap* heap = mSpool_Heap; + nsIMdbHeap* heap = mCoil_Heap; + + mBuf_Body = 0; + mCoil_Heap = 0; if ( body && heap ) { heap->Free(ev->AsMdbEnv(), body); } - mBuf_Body = 0; - mSpool_Heap = 0; } //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 diff --git a/db/mork/src/morkBlob.h b/db/mork/src/morkBlob.h index 44f0d8d4ccdb..d70d6ca266e7 100644 --- a/db/mork/src/morkBlob.h +++ b/db/mork/src/morkBlob.h @@ -39,6 +39,10 @@ public: morkBuf(const void* ioBuf, mork_fill inFill) : mBuf_Body((void*) ioBuf), mBuf_Fill(inFill) { } + void ClearBufFill() { mBuf_Fill = 0; } + + static void NilBufBodyError(morkEnv* ev); + private: // copying is not allowed morkBuf(const morkBuf& other); morkBuf& operator=(const morkBuf& other); @@ -61,9 +65,12 @@ public: morkBlob() { } morkBlob(const void* ioBuf, mork_fill inFill, mork_size inSize) : morkBuf(ioBuf, inFill), mBlob_Size(inSize) { } - + + static void BlobFillOverSizeError(morkEnv* ev); + public: - mork_bool Grow(morkEnv* ev, nsIMdbHeap* ioHeap, mork_size inNewSize); + mork_bool GrowBlob(morkEnv* ev, nsIMdbHeap* ioHeap, + mork_size inNewSize); private: // copying is not allowed morkBlob(const morkBlob& other); @@ -94,49 +101,52 @@ private: // copying is not allowed morkText& operator=(const morkText& other); }; -/*| Spool: a text with an associated nsIMdbHeap instance that provides +/*| Coil: a text with an associated nsIMdbHeap instance that provides **| all memory management for the space pointed to by mBuf_Body. (This **| was the hardest type to give a name in this small class hierarchy, **| because it's hard to characterize self-management of one's space.) -**| A spool is a self-contained blob that knows how to grow itself as -**| necessary to hold more content when necessary. Spool descends from +**| A coil is a self-contained blob that knows how to grow itself as +**| necessary to hold more content when necessary. Coil descends from **| morkText to include the mText_Form slot, even though this won't be **| needed always, because we are not as concerned about the overall -**| size of this particular Spool object (if we were concerned about -**| the size of an array of Spool instances, we would not bother with +**| size of this particular Coil object (if we were concerned about +**| the size of an array of Coil instances, we would not bother with **| a separate heap pointer for each of them). **| -**|| A spool makes a good medium in which to stream content as a sink, -**| so we will have a subclass of morkSink called morkSpoolSink that -**| will stream bytes into this self-contained spool object. The name -**| of this morkSpool class derives more from this intended usage than +**|| A coil makes a good medium in which to stream content as a sink, +**| so we will have a subclass of morkSink called morkCoil that +**| will stream bytes into this self-contained coil object. The name +**| of this morkCoil class derives more from this intended usage than **| from anything else. The Mork code to parse db content will use -**| spools with associated sinks to accumulate parsed strings. +**| coils with associated sinks to accumulate parsed strings. **| **|| Heap: this is the heap used for memory allocation. This instance -**| is NOT refcounted, since this spool always assumes the heap is held +**| is NOT refcounted, since this coil always assumes the heap is held **| through a reference elsewhere (for example, through the same object -**| that contains or holds the spool itself. This lack of refcounting -**| is consistent with the fact that morkSpool itself is not refcounted, +**| that contains or holds the coil itself. This lack of refcounting +**| is consistent with the fact that morkCoil itself is not refcounted, **| and is not intended for use as a standalone object. |*/ -class morkSpool : public morkText { // self-managing text blob object +class morkCoil : public morkText { // self-managing text blob object // void* mBuf_Body; // space for holding any binary content // mdb_fill mBuf_Fill; // logical content in Buf in bytes // mdb_size mBlob_Size; // physical size of Buf in bytes // mdb_cscode mText_Form; // charset format encoding public: - nsIMdbHeap* mSpool_Heap; // storage manager for mBuf_Body pointer + nsIMdbHeap* mCoil_Heap; // storage manager for mBuf_Body pointer public: - morkSpool(morkEnv* ev, nsIMdbHeap* ioHeap); + morkCoil(morkEnv* ev, nsIMdbHeap* ioHeap); - void CloseSpool(morkEnv* ev); + void CloseCoil(morkEnv* ev); + + mork_bool GrowCoil(morkEnv* ev, mork_size inNewSize) + { return this->GrowBlob(ev, mCoil_Heap, inNewSize); } private: // copying is not allowed - morkSpool(const morkSpool& other); - morkSpool& operator=(const morkSpool& other); + morkCoil(const morkCoil& other); + morkCoil& operator=(const morkCoil& other); }; //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 diff --git a/db/mork/src/morkBuilder.cpp b/db/mork/src/morkBuilder.cpp index a5a4af6adee7..54f8fa55659d 100644 --- a/db/mork/src/morkBuilder.cpp +++ b/db/mork/src/morkBuilder.cpp @@ -48,6 +48,34 @@ #include "morkCell.h" #endif +#ifndef _MORKSTORE_ +#include "morkStore.h" +#endif + +#ifndef _MORKTABLE_ +#include "morkTable.h" +#endif + +#ifndef _MORKROW_ +#include "morkRow.h" +#endif + +#ifndef _MORKCELL_ +#include "morkCell.h" +#endif + +#ifndef _MORKATOM_ +#include "morkAtom.h" +#endif + +#ifndef _MORKATOMSPACE_ +#include "morkAtomSpace.h" +#endif + +#ifndef _MORKROWSPACE_ +#include "morkRowSpace.h" +#endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 // ````` ````` ````` ````` ````` @@ -67,7 +95,12 @@ morkBuilder::CloseMorkNode(morkEnv* ev) // CloseBuilder() only if open /*public virtual*/ morkBuilder::~morkBuilder() // assert CloseBuilder() executed earlier { + MORK_ASSERT(mBuilder_Store==0); + MORK_ASSERT(mBuilder_Row==0); MORK_ASSERT(mBuilder_Table==0); + MORK_ASSERT(mBuilder_Cell==0); + MORK_ASSERT(mBuilder_RowSpace==0); + MORK_ASSERT(mBuilder_AtomSpace==0); } /*public non-poly*/ @@ -75,11 +108,67 @@ morkBuilder::morkBuilder(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap, morkStream* ioStream, mdb_count inBytesPerParseSegment, nsIMdbHeap* ioSlotHeap, morkStore* ioStore) + : morkParser(ev, inUsage, ioHeap, ioStream, inBytesPerParseSegment, ioSlotHeap) + +, mBuilder_Store( 0 ) + +, mBuilder_Table( 0 ) +, mBuilder_Row( 0 ) +, mBuilder_Cell( 0 ) + +, mBuilder_RowSpace( 0 ) +, mBuilder_AtomSpace( 0 ) + +, mBuilder_OidAtomSpace( 0 ) +, mBuilder_ScopeAtomSpace( 0 ) + +, mBuilder_iso_8859_1( 0 ) +, mBuilder_r( (mork_scope) 'r' ) +, mBuilder_a( (mork_scope) 'a' ) +, mBuilder_t( (mork_scope) 't' ) + +, mBuilder_MorkNoneToken( 0 ) + +, mBuilder_PortForm( 0 ) +, mBuilder_PortRowScope( (mork_scope) 'r' ) +, mBuilder_PortAtomScope( (mork_scope) 'a' ) + +, mBuilder_TableForm( 0 ) +, mBuilder_TableRowScope( (mork_scope) 'r' ) +, mBuilder_TableAtomScope( (mork_scope) 'a' ) +, mBuilder_TableKind( 0 ) + +, mBuilder_RowForm( 0 ) +, mBuilder_RowRowScope( (mork_scope) 'r' ) +, mBuilder_RowAtomScope( (mork_scope) 'a' ) + +, mBuilder_CellForm( 0 ) +, mBuilder_CellAtomScope( (mork_scope) 'a' ) + +, mBuilder_DictForm( 0 ) +, mBuilder_DictAtomScope( (mork_scope) 'a' ) + +, mBuilder_MetaTokenSlot( 0 ) + +, mBuilder_DoCutRow( morkBool_kFalse ) +, mBuilder_DoCutCell( morkBool_kFalse ) +, mBuilder_CellsVecFill( 0 ) { if ( ev->Good() ) - mNode_Derived = morkDerived_kBuilder; + { + if ( ioStore ) + { + mBuilder_MorkNoneToken = ioStore->mStore_MorkNoneToken; + morkStore::SlotWeakStore(ioStore, ev, &mBuilder_Store); + if ( ev->Good() ) + mNode_Derived = morkDerived_kBuilder; + } + else + ev->NilPointerError(); + } + } /*public non-poly*/ void @@ -89,6 +178,24 @@ morkBuilder::CloseBuilder(morkEnv* ev) // called by CloseMorkNode(); { if ( this->IsNode() ) { + mBuilder_Row = 0; + mBuilder_Cell = 0; + mBuilder_MetaTokenSlot = 0; + + morkTable::SlotStrongTable((morkTable*) 0, ev, &mBuilder_Table); + morkStore::SlotWeakStore((morkStore*) 0, ev, &mBuilder_Store); + + morkRowSpace::SlotStrongRowSpace((morkRowSpace*) 0, ev, + &mBuilder_RowSpace); + + morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev, + &mBuilder_AtomSpace); + + morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev, + &mBuilder_OidAtomSpace); + + morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev, + &mBuilder_ScopeAtomSpace); this->CloseParser(ev); this->MarkShut(); } @@ -108,217 +215,655 @@ morkBuilder::NonBuilderTypeError(morkEnv* ev) ev->NewError("non morkBuilder"); } +/*static*/ void +morkBuilder::NilBuilderCellError(morkEnv* ev) +{ + ev->NewError("nil mBuilder_Cell"); +} + +/*static*/ void +morkBuilder::NilBuilderRowError(morkEnv* ev) +{ + ev->NewError("nil mBuilder_Row"); +} + +/*static*/ void +morkBuilder::NilBuilderTableError(morkEnv* ev) +{ + ev->NewError("nil mBuilder_Table"); +} + +/*static*/ void +morkBuilder::NonColumnSpaceScopeError(morkEnv* ev) +{ + ev->NewError("column space != 'c'"); +} + +void +morkBuilder::LogGlitch(morkEnv* ev, const morkGlitch& inGlitch, + const char* inKind) +{ + ev->NewWarning("parsing glitch"); +} + /*virtual*/ void -morkBuilder::AliasToYarn(morkEnv* ev, - const morkAlias& inAlias, // typically an alias to concat with strings +morkBuilder::MidToYarn(morkEnv* ev, + const morkMid& inMid, // typically an alias to concat with strings mdbYarn* outYarn) // The parser might ask that some aliases be turned into yarns, so they // can be concatenated into longer blobs under some circumstances. This // is an alternative to using a long and complex callback for many parts // for a single cell value. { - ev->StubMethodOnlyError(); + mBuilder_Store->MidToYarn(ev, inMid, outYarn); } /*virtual*/ void morkBuilder::OnNewPort(morkEnv* ev, const morkPlace& inPlace) +// mp:Start ::= OnNewPort mp:PortItem* OnPortEnd +// mp:PortItem ::= mp:Content | mp:Group | OnPortGlitch +// mp:Content ::= mp:PortRow | mp:Dict | mp:Table | mp:Row { - ev->StubMethodOnlyError(); + // mParser_InPort = morkBool_kTrue; + mBuilder_PortForm = 0; + mBuilder_PortRowScope = (mork_scope) 'r'; + mBuilder_PortAtomScope = (mork_scope) 'a'; } /*virtual*/ void morkBuilder::OnPortGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "port"); } /*virtual*/ void morkBuilder::OnPortEnd(morkEnv* ev, const morkSpan& inSpan) +// mp:Start ::= OnNewPort mp:PortItem* OnPortEnd { - ev->StubMethodOnlyError(); + // ev->StubMethodOnlyError(); + // nothing to do? + // mParser_InPort = morkBool_kFalse; } /*virtual*/ void morkBuilder::OnNewGroup(morkEnv* ev, const morkPlace& inPlace, mork_gid inGid) { + // mParser_InGroup = morkBool_kTrue; ev->StubMethodOnlyError(); } /*virtual*/ void morkBuilder::OnGroupGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "group"); } /*virtual*/ void morkBuilder::OnGroupCommitEnd(morkEnv* ev, const morkSpan& inSpan) { + // mParser_InGroup = morkBool_kFalse; ev->StubMethodOnlyError(); } /*virtual*/ void morkBuilder::OnGroupAbortEnd(morkEnv* ev, const morkSpan& inSpan) { + // mParser_InGroup = morkBool_kFalse; ev->StubMethodOnlyError(); } /*virtual*/ void morkBuilder::OnNewPortRow(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) + const morkMid& inMid, mork_change inChange) { + // mParser_InPortRow = morkBool_kTrue; ev->StubMethodOnlyError(); } /*virtual*/ void morkBuilder::OnPortRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "port row"); } /*virtual*/ void morkBuilder::OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan) { + // mParser_InPortRow = morkBool_kFalse; ev->StubMethodOnlyError(); } /*virtual*/ void morkBuilder::OnNewTable(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) + const morkMid& inMid, mork_change inChange) +// mp:Table ::= OnNewTable mp:TableItem* OnTableEnd +// mp:TableItem ::= mp:Row | mp:Meta | OnTableGlitch +// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd +// mp:MetaItem ::= mp:Cell | OnMetaGlitch { - ev->StubMethodOnlyError(); + // mParser_InTable = morkBool_kTrue; + mBuilder_TableForm = mBuilder_PortForm; + mBuilder_TableRowScope = mBuilder_PortRowScope; + mBuilder_TableAtomScope = mBuilder_PortAtomScope; + mBuilder_TableKind = mBuilder_MorkNoneToken; + + morkTable* table = mBuilder_Store->MidToTable(ev, inMid); + morkTable::SlotStrongTable(table, ev, &mBuilder_Table); } /*virtual*/ void morkBuilder::OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "table"); } /*virtual*/ void morkBuilder::OnTableEnd(morkEnv* ev, const morkSpan& inSpan) +// mp:Table ::= OnNewTable mp:TableItem* OnTableEnd { - ev->StubMethodOnlyError(); + // mParser_InTable = morkBool_kFalse; + if ( mBuilder_Table ) + { + morkTable::SlotStrongTable((morkTable*) 0, ev, &mBuilder_Table); + } + else + this->NilBuilderTableError(ev); + + mBuilder_Row = 0; + mBuilder_Cell = 0; + + if ( mBuilder_TableKind == mBuilder_MorkNoneToken ) + ev->NewError("missing table kind"); + + mBuilder_CellAtomScope = mBuilder_RowAtomScope = + mBuilder_TableAtomScope = mBuilder_PortAtomScope; } /*virtual*/ void morkBuilder::OnNewMeta(morkEnv* ev, const morkPlace& inPlace) +// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd +// mp:MetaItem ::= mp:Cell | OnMetaGlitch +// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd +// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + // mParser_InMeta = morkBool_kTrue; + } /*virtual*/ void morkBuilder::OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "meta"); } /*virtual*/ void morkBuilder::OnMetaEnd(morkEnv* ev, const morkSpan& inSpan) +// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd { - ev->StubMethodOnlyError(); + // mParser_InMeta = morkBool_kFalse; } /*virtual*/ void morkBuilder::OnNewRow(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) + const morkMid& inMid, mork_change inChange) +// mp:Row ::= OnNewRow mp:RowItem* OnRowEnd +// mp:RowItem ::= mp:Cell | mp:Meta | OnRowGlitch +// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd +// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + // mParser_InRow = morkBool_kTrue; + if ( mBuilder_Table ) + { + mBuilder_CellForm = mBuilder_RowForm = mBuilder_TableForm; + mBuilder_CellAtomScope = mBuilder_RowAtomScope = mBuilder_TableAtomScope; + mBuilder_RowRowScope = mBuilder_TableRowScope; + morkStore* store = mBuilder_Store; + + if ( !inMid.mMid_Buf && !inMid.mMid_Oid.mOid_Scope ) + { + morkMid mid(inMid); + mid.mMid_Oid.mOid_Scope = mBuilder_RowRowScope; + mBuilder_Row = store->MidToRow(ev, mid); + } + else + { + mBuilder_Row = store->MidToRow(ev, inMid); + } + + if ( mBuilder_Row ) + mBuilder_Table->AddRow(ev, mBuilder_Row); + } + else + this->NilBuilderTableError(ev); } /*virtual*/ void morkBuilder::OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "row"); +} + +void +morkBuilder::FlushBuilderCells(morkEnv* ev) +{ + if ( mBuilder_Row ) + { + morkPool* pool = mBuilder_Store->StorePool(); + morkCell* cells = mBuilder_CellsVec; + mork_fill fill = mBuilder_CellsVecFill; + mBuilder_Row->TakeCells(ev, cells, fill, mBuilder_Store); + + morkCell* end = cells + fill; + --cells; // prepare for preincrement + while ( ++cells < end ) + { + if ( cells->mCell_Atom ) + cells->SetAtom(ev, (morkAtom*) 0, pool); + } + mBuilder_CellsVecFill = 0; + } + else + this->NilBuilderRowError(ev); } /*virtual*/ void morkBuilder::OnRowEnd(morkEnv* ev, const morkSpan& inSpan) +// mp:Row ::= OnNewRow mp:RowItem* OnRowEnd { - ev->StubMethodOnlyError(); + // mParser_InRow = morkBool_kFalse; + if ( mBuilder_Row ) + { + this->FlushBuilderCells(ev); + } + else + this->NilBuilderRowError(ev); + + mBuilder_Row = 0; + mBuilder_Cell = 0; } /*virtual*/ void morkBuilder::OnNewDict(morkEnv* ev, const morkPlace& inPlace) +// mp:Dict ::= OnNewDict mp:DictItem* OnDictEnd +// mp:DictItem ::= OnAlias | OnAliasGlitch | mp:Meta | OnDictGlitch { - ev->StubMethodOnlyError(); + // mParser_InDict = morkBool_kTrue; + + mBuilder_CellForm = mBuilder_DictForm = mBuilder_PortForm; + mBuilder_CellAtomScope = mBuilder_DictAtomScope = mBuilder_PortAtomScope; } /*virtual*/ void morkBuilder::OnDictGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "dict"); } /*virtual*/ void morkBuilder::OnDictEnd(morkEnv* ev, const morkSpan& inSpan) +// mp:Dict ::= OnNewDict mp:DictItem* OnDictEnd { - ev->StubMethodOnlyError(); + // mParser_InDict = morkBool_kFalse; + + mBuilder_DictForm = 0; + mBuilder_DictAtomScope = 0; } /*virtual*/ void morkBuilder::OnAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) + const morkMid& inMid) { - ev->StubMethodOnlyError(); + if ( mParser_InDict ) + { + morkMid mid = inMid; // local copy for modification + mid.mMid_Oid.mOid_Scope = mBuilder_DictAtomScope; + mBuilder_Store->AddAlias(ev, mid, mBuilder_DictForm); + } + else + ev->NewError("alias not in dict"); } /*virtual*/ void morkBuilder::OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "alias"); +} + + +morkCell* +morkBuilder::AddBuilderCell(morkEnv* ev, + const morkMid& inMid, mork_change inChange) +{ + morkCell* outCell = 0; + mork_column column = inMid.mMid_Oid.mOid_Id; + + if ( ev->Good() ) + { + if ( mBuilder_CellsVecFill >= morkBuilder_kCellsVecSize ) + this->FlushBuilderCells(ev); + if ( ev->Good() ) + { + if ( mBuilder_CellsVecFill < morkBuilder_kCellsVecSize ) + { + mork_fill index = mBuilder_CellsVecFill++; + outCell = mBuilder_CellsVec + index; + outCell->SetColumnAndChange(column, inChange); + outCell->mCell_Atom = 0; + } + else + ev->NewError("out of builder cells"); + } + } + return outCell; } /*virtual*/ void morkBuilder::OnNewCell(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) + const morkMid* inMid, const morkBuf* inBuf, mork_change inChange) +// Exactly one of inMid and inBuf is nil, and the other is non-nil. +// When hex ID syntax is used for a column, then inMid is not nil, and +// when a naked string names a column, then inBuf is not nil. + + // mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd + // mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch + // mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + // mParser_InCell = morkBool_kTrue; + + mBuilder_CellAtomScope = mBuilder_RowAtomScope; + + mBuilder_Cell = 0; // nil until determined for a row + morkStore* store = mBuilder_Store; + mork_scope scope = morkStore_kColumnSpaceScope; + morkMid tempMid; // space for local and modifiable cell mid + morkMid* cellMid = &tempMid; // default to local if inMid==0 + + if ( inMid ) // mid parameter is actually provided? + { + *cellMid = *inMid; // bitwise copy for modifiable local mid + + if ( !cellMid->mMid_Oid.mOid_Scope ) + { + if ( cellMid->mMid_Buf ) + { + scope = store->BufToToken(ev, cellMid->mMid_Buf); + cellMid->mMid_Buf = 0; // don't do scope lookup again + ev->NewWarning("column mids need column scope"); + } + cellMid->mMid_Oid.mOid_Scope = scope; + } + } + else if ( inBuf ) // buf points to naked column string name? + { + cellMid->ClearMid(); + cellMid->mMid_Oid.mOid_Id = store->BufToToken(ev, inBuf); + cellMid->mMid_Oid.mOid_Scope = scope; // kColumnSpaceScope + } + else + ev->NilPointerError(); // either inMid or inBuf must be non-nil + + mork_column column = cellMid->mMid_Oid.mOid_Id; + + if ( mParser_InMeta && ev->Good() ) // cell is in metainfo structure? + { + if ( scope == morkStore_kColumnSpaceScope ) + { + if ( mParser_InTable ) // metainfo for table? + { + if ( column == store->mStore_TableKindToken ) + mBuilder_MetaTokenSlot = &mBuilder_TableKind; + else if ( column == store->mStore_RowScopeToken ) + mBuilder_MetaTokenSlot = &mBuilder_TableRowScope; + else if ( column == store->mStore_AtomScopeToken ) + mBuilder_MetaTokenSlot = &mBuilder_TableAtomScope; + else if ( column == store->mStore_CharsetToken ) + mBuilder_MetaTokenSlot = &mBuilder_TableForm; + } + else if ( mParser_InDict ) // metainfo for dict? + { + if ( column == store->mStore_AtomScopeToken ) + mBuilder_MetaTokenSlot = &mBuilder_DictAtomScope; + else if ( column == store->mStore_CharsetToken ) + mBuilder_MetaTokenSlot = &mBuilder_DictForm; + } + else if ( mParser_InRow ) // metainfo for row? + { + if ( column == store->mStore_AtomScopeToken ) + mBuilder_MetaTokenSlot = &mBuilder_RowAtomScope; + else if ( column == store->mStore_RowScopeToken ) + mBuilder_MetaTokenSlot = &mBuilder_RowRowScope; + else if ( column == store->mStore_CharsetToken ) + mBuilder_MetaTokenSlot = &mBuilder_RowForm; + } + } + else + ev->NewWarning("expected column scope"); + } + else if ( ev->Good() ) // this cell must be inside a row + { + if ( mBuilder_Row ) + { + // mBuilder_Cell = this->AddBuilderCell(ev, *cellMid, inChange); + + if ( mBuilder_CellsVecFill >= morkBuilder_kCellsVecSize ) + this->FlushBuilderCells(ev); + if ( ev->Good() ) + { + if ( mBuilder_CellsVecFill < morkBuilder_kCellsVecSize ) + { + mork_fill index = mBuilder_CellsVecFill++; + morkCell* cell = mBuilder_CellsVec + index; + cell->SetColumnAndChange(column, inChange); + cell->mCell_Atom = 0; + mBuilder_Cell = cell; + } + else + ev->NewError("out of builder cells"); + } + } + else + this->NilBuilderRowError(ev); + } } /*virtual*/ void morkBuilder::OnCellGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "cell"); } /*virtual*/ void morkBuilder::OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat) { - ev->StubMethodOnlyError(); + morkCell* cell = mBuilder_Cell; + if ( cell ) + { + mBuilder_CellForm = inCharsetFormat; + } + else + this->NilBuilderCellError(ev); } /*virtual*/ void morkBuilder::OnCellEnd(morkEnv* ev, const morkSpan& inSpan) +// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd { - ev->StubMethodOnlyError(); + // mParser_InCell = morkBool_kFalse; + + mBuilder_MetaTokenSlot = 0; + mBuilder_CellAtomScope = mBuilder_RowAtomScope; } /*virtual*/ void morkBuilder::OnValue(morkEnv* ev, const morkSpan& inSpan, const morkBuf& inBuf) +// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + morkStore* store = mBuilder_Store; + morkCell* cell = mBuilder_Cell; + if ( cell ) + { + mdbYarn yarn; + yarn.mYarn_Buf = inBuf.mBuf_Body; + yarn.mYarn_Fill = yarn.mYarn_Size = inBuf.mBuf_Fill; + yarn.mYarn_More = 0; + yarn.mYarn_Form = mBuilder_CellForm; + yarn.mYarn_Grow = 0; + morkAtom* atom = store->YarnToAtom(ev, &yarn); + cell->SetAtom(ev, atom, store->StorePool()); + } + else if ( mParser_InMeta ) + { + mork_token* metaSlot = mBuilder_MetaTokenSlot; + if ( metaSlot ) + { + mork_token token = store->BufToToken(ev, &inBuf); + if ( token ) + { + *metaSlot = token; + if ( metaSlot == &mBuilder_TableKind ) // table kind? + { + if ( mParser_InTable && mBuilder_Table ) + mBuilder_Table->mTable_Kind = token; + } + } + } + } + else + this->NilBuilderCellError(ev); } /*virtual*/ void -morkBuilder::OnValueAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) +morkBuilder::OnValueMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid) +// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + morkStore* store = mBuilder_Store; + morkCell* cell = mBuilder_Cell; + + morkMid valMid; // local mid for modifications + mdbOid* valOid = &valMid.mMid_Oid; // ref to oid inside mid + *valOid = inMid.mMid_Oid; // bitwise copy inMid's oid + + if ( inMid.mMid_Buf ) + { + if ( !valOid->mOid_Scope ) + store->MidToOid(ev, inMid, valOid); + } + else if ( !valOid->mOid_Scope ) + valOid->mOid_Scope = mBuilder_CellAtomScope; + + if ( cell ) + { + morkBookAtom* atom = store->MidToAtom(ev, valMid); + if ( atom ) + cell->SetAtom(ev, atom, store->StorePool()); + else + ev->NewError("undefined cell value alias"); + } + else if ( mParser_InMeta ) + { + mork_token* metaSlot = mBuilder_MetaTokenSlot; + if ( metaSlot ) + { + if ( valOid->mOid_Scope == morkStore_kColumnSpaceScope ) + { + if ( ev->Good() && valMid.HasSomeId() ) + { + *metaSlot = valOid->mOid_Id; + if ( metaSlot == &mBuilder_TableKind ) // table kind? + { + if ( mParser_InTable && mBuilder_Table ) + { + mBuilder_Table->mTable_Kind = valOid->mOid_Id; + } + else + ev->NewWarning("mBuilder_TableKind not in table"); + } + } + } + else + this->NonColumnSpaceScopeError(ev); + } + } + else + this->NilBuilderCellError(ev); } /*virtual*/ void -morkBuilder::OnRowAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) +morkBuilder::OnRowMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid) +// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + morkStore* store = mBuilder_Store; + morkCell* cell = mBuilder_Cell; + if ( cell ) + { + mdbOid rowOid = inMid.mMid_Oid; + if ( inMid.mMid_Buf ) + { + if ( !rowOid.mOid_Scope ) + store->MidToOid(ev, inMid, &rowOid); + } + else if ( !rowOid.mOid_Scope ) + rowOid.mOid_Scope = mBuilder_RowRowScope; + + if ( ev->Good() ) + { + morkPool* pool = store->StorePool(); + morkAtom* atom = pool->NewRowOidAtom(ev, rowOid); + if ( atom ) + { + cell->SetAtom(ev, atom, pool); + morkRow* row = store->OidToRow(ev, &rowOid); + if ( row ) // found or created such a row? + row->AddTableUse(ev); + } + } + } + else + this->NilBuilderCellError(ev); } /*virtual*/ void -morkBuilder::OnTableAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) +morkBuilder::OnTableMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid) +// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + morkStore* store = mBuilder_Store; + morkCell* cell = mBuilder_Cell; + if ( cell ) + { + mdbOid tableOid = inMid.mMid_Oid; + if ( inMid.mMid_Buf ) + { + if ( !tableOid.mOid_Scope ) + store->MidToOid(ev, inMid, &tableOid); + } + else if ( !tableOid.mOid_Scope ) + tableOid.mOid_Scope = mBuilder_RowRowScope; + + if ( ev->Good() ) + { + morkPool* pool = store->StorePool(); + morkAtom* atom = pool->NewTableOidAtom(ev, tableOid); + if ( atom ) + { + cell->SetAtom(ev, atom, pool); + morkTable* table = store->OidToTable(ev, &tableOid); + if ( table ) // found or created such a table? + table->AddCellUse(ev); + } + } + } + else + this->NilBuilderCellError(ev); } diff --git a/db/mork/src/morkBuilder.h b/db/mork/src/morkBuilder.h index e1afa0257415..a41817726298 100644 --- a/db/mork/src/morkBuilder.h +++ b/db/mork/src/morkBuilder.h @@ -65,31 +65,31 @@ class morkBuilder /*d*/ : public morkParser { // after finding ends of group transactions, we can re-seek the start: // mork_pos mParser_GroupContentStartPos; // start of this group + // mdbOid mParser_TableOid; // table oid if inside a table + // mdbOid mParser_RowOid; // row oid if inside a row // mork_gid mParser_GroupId; // group ID if inside a group - // mork_tid mParser_TableId; // table ID if inside a table - // mork_rid mParser_RowId; // row ID if inside a row // mork_bool mParser_InPort; // called OnNewPort but not OnPortEnd? // mork_bool mParser_InDict; // called OnNewDict but not OnDictEnd? // mork_bool mParser_InCell; // called OnNewCell but not OnCellEnd? // mork_bool mParser_InMeta; // called OnNewMeta but not OnMetaEnd? - // morkAlias mParser_Alias; // current alias being parsed - // note that mParser_Alias.mAlias_Buf points at mParser_ScopeSpool below: + // morkMid mParser_Mid; // current alias being parsed + // note that mParser_Mid.mMid_Buf points at mParser_ScopeCoil below: - // blob spools allocated in mParser_Heap - // morkSpool mParser_ScopeSpool; // place to accumulate ID scope blobs - // morkSpool mParser_ValueSpool; // place to accumulate value blobs - // morkSpool mParser_ColumnSpool; // place to accumulate column blobs - // morkSpool mParser_StringSpool; // place to accumulate string blobs + // blob coils allocated in mParser_Heap + // morkCoil mParser_ScopeCoil; // place to accumulate ID scope blobs + // morkCoil mParser_ValueCoil; // place to accumulate value blobs + // morkCoil mParser_ColumnCoil; // place to accumulate column blobs + // morkCoil mParser_StringCoil; // place to accumulate string blobs - // morkSpoolSink mParser_ScopeSink; // writes to mParser_ScopeSpool - // morkSpoolSink mParser_ValueSink; // writes to mParser_ValueSpool - // morkSpoolSink mParser_ColumnSink; // writes to mParser_ColumnSpool - // morkSpoolSink mParser_StringSink; // writes to mParser_StringSpool + // morkSpool mParser_ScopeSpool; // writes to mParser_ScopeCoil + // morkSpool mParser_ValueSpool; // writes to mParser_ValueCoil + // morkSpool mParser_ColumnSpool; // writes to mParser_ColumnCoil + // morkSpool mParser_StringSpool; // writes to mParser_StringCoil // yarns allocated in mParser_Heap - // morkYarn mParser_AliasYarn; // place to receive from AliasToYarn() + // morkYarn mParser_MidYarn; // place to receive from MidToYarn() // span showing current ongoing file position status: // morkSpan mParser_PortSpan; // span of current db port file @@ -118,8 +118,8 @@ protected: // protected morkBuilder members morkRow* mBuilder_Row; // current row being built (or nil) morkCell* mBuilder_Cell; // current cell within CellsVec (or nil) - morkRowSpace* mBuilder_RowSpace; // space for mBuilder_CurrentRowScope - morkAtomSpace* mBuilder_AtomSpace; // space for mBuilder_CurrentAtomScope + morkRowSpace* mBuilder_RowSpace; // space for mBuilder_CellRowScope + morkAtomSpace* mBuilder_AtomSpace; // space for mBuilder_CellAtomScope morkAtomSpace* mBuilder_OidAtomSpace; // ground atom space for oids morkAtomSpace* mBuilder_ScopeAtomSpace; // ground atom space for scopes @@ -134,6 +134,8 @@ protected: // protected morkBuilder members mork_cscode mBuilder_a; // token for "a" mork_cscode mBuilder_t; // token for "t" + mork_token mBuilder_MorkNoneToken; // token for "mork:none" + // tokens that become set as the result of meta cells in port rows: mork_cscode mBuilder_PortForm; // default port charset format mork_scope mBuilder_PortRowScope; // port row scope @@ -151,21 +153,25 @@ protected: // protected morkBuilder members mork_scope mBuilder_RowAtomScope; // row atom scope // meta tokens currently in force, driven by meta info slots above: - mork_cscode mBuilder_CurrentForm; // current charset format - mork_scope mBuilder_CurrentRowScope; // current row scope - mork_scope mBuilder_CurrentAtomScope; // current atom scope + mork_cscode mBuilder_CellForm; // cell charset format + mork_scope mBuilder_CellAtomScope; // cell atom scope + + mork_cscode mBuilder_DictForm; // dict charset format + mork_scope mBuilder_DictAtomScope; // dict atom scope + + mork_token* mBuilder_MetaTokenSlot; // pointer to some slot above // If any of these 'cut' bools are true, it means a minus was seen in the // Mork source text to indicate removal of content from some container. // (Note there is no corresponding 'add' bool, since add is the default.) // CutRow implies the current row should be cut from the table. // CutCell implies the current column should be cut from the row. - mork_bool mBuilder_CutRow; // row with kCut change - mork_bool mBuilder_CutCell; // cell with kCut change + mork_bool mBuilder_DoCutRow; // row with kCut change + mork_bool mBuilder_DoCutCell; // cell with kCut change mork_u1 mBuilder_Pad1; // pad to u4 alignment mork_u1 mBuilder_Pad2; // pad to u4 alignment - morkCell mBuilder_CellsVec[ morkBuilder_kCellsVecSize ]; + morkCell mBuilder_CellsVec[ morkBuilder_kCellsVecSize + 1 ]; mork_fill mBuilder_CellsVecFill; // count used in CellsVec // Note when mBuilder_CellsVecFill equals morkBuilder_kCellsVecSize, and // another cell is added, this means all the cells in the vector above @@ -199,14 +205,28 @@ public: // dynamic type identification { return IsNode() && mNode_Derived == morkDerived_kBuilder; } // } ===== end morkNode methods ===== -public: // typing +public: // errors static void NonBuilderTypeError(morkEnv* ev); + static void NilBuilderCellError(morkEnv* ev); + static void NilBuilderRowError(morkEnv* ev); + static void NilBuilderTableError(morkEnv* ev); + static void NonColumnSpaceScopeError(morkEnv* ev); + + void LogGlitch(morkEnv* ev, const morkGlitch& inGlitch, + const char* inKind); + +public: // other builder methods + + morkCell* AddBuilderCell(morkEnv* ev, + const morkMid& inMid, mork_change inChange); + + void FlushBuilderCells(morkEnv* ev); // ````` ````` ````` ````` ````` ````` ````` ````` public: // in virtual morkParser methods, data flow subclass to parser - virtual void AliasToYarn(morkEnv* ev, - const morkAlias& inAlias, // typically an alias to concat with strings + virtual void MidToYarn(morkEnv* ev, + const morkMid& inMid, // typically an alias to concat with strings mdbYarn* outYarn); // The parser might ask that some aliases be turned into yarns, so they // can be concatenated into longer blobs under some circumstances. This @@ -216,60 +236,64 @@ public: // in virtual morkParser methods, data flow subclass to parser // ````` ````` ````` ````` ````` ````` ````` ````` public: // out virtual morkParser methods, data flow parser to subclass - virtual void OnNewPort(morkEnv* ev, const morkPlace& inPlace); - virtual void OnPortGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnPortEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnNewPort(morkEnv* ev, const morkPlace& inPlace); + virtual void OnPortGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnPortEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnNewGroup(morkEnv* ev, const morkPlace& inPlace, mork_gid inGid); - virtual void OnGroupGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnGroupCommitEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnGroupAbortEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnNewGroup(morkEnv* ev, const morkPlace& inPlace, mork_gid inGid); + virtual void OnGroupGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnGroupCommitEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnGroupAbortEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnNewPortRow(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange); - virtual void OnPortRowGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnNewPortRow(morkEnv* ev, const morkPlace& inPlace, + const morkMid& inMid, mork_change inChange); + virtual void OnPortRowGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange); - virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan); - - virtual void OnNewMeta(morkEnv* ev, const morkPlace& inPlace); - virtual void OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace, + const morkMid& inMid, mork_change inChange); + virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan); + + virtual void OnNewMeta(morkEnv* ev, const morkPlace& inPlace); + virtual void OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange); - virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace, + const morkMid& inMid, mork_change inChange); + virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnNewDict(morkEnv* ev, const morkPlace& inPlace); - virtual void OnDictGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnDictEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnNewDict(morkEnv* ev, const morkPlace& inPlace); + virtual void OnDictGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnDictEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias); + virtual void OnAlias(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid); - virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange); - virtual void OnCellGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat); - virtual void OnCellEnd(morkEnv* ev, const morkSpan& inSpan); - - virtual void OnValue(morkEnv* ev, const morkSpan& inSpan, - const morkBuf& inBuf); + virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace, + const morkMid* inMid, const morkBuf* inBuf, mork_change inChange); + // Exactly one of inMid and inBuf is nil, and the other is non-nil. + // When hex ID syntax is used for a column, then inMid is not nil, and + // when a naked string names a column, then inBuf is not nil. - virtual void OnValueAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias); + virtual void OnCellGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat); + virtual void OnCellEnd(morkEnv* ev, const morkSpan& inSpan); + + virtual void OnValue(morkEnv* ev, const morkSpan& inSpan, + const morkBuf& inBuf); - virtual void OnRowAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias); + virtual void OnValueMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid); - virtual void OnTableAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias); + virtual void OnRowMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid); + + virtual void OnTableMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid); // ````` ````` ````` ````` ````` ````` ````` ````` public: // public non-poly morkBuilder methods diff --git a/db/mork/src/morkCell.cpp b/db/mork/src/morkCell.cpp index f6f547c1c10c..62c0b837b87f 100644 --- a/db/mork/src/morkCell.cpp +++ b/db/mork/src/morkCell.cpp @@ -46,9 +46,6 @@ //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 -// ````` ````` ````` ````` ````` -// { ===== begin morkNode interface ===== - void morkCell::SetYarn(morkEnv* ev, const mdbYarn* inYarn, morkStore* ioStore) { diff --git a/db/mork/src/morkCell.h b/db/mork/src/morkCell.h index b0c3bb580bd7..93f6977823f3 100644 --- a/db/mork/src/morkCell.h +++ b/db/mork/src/morkCell.h @@ -40,6 +40,9 @@ public: public: morkCell() : mCell_Atom( 0 ), mCell_Delta( 0 ) { } + + morkCell(const morkCell& c) + : mCell_Atom( c.mCell_Atom ), mCell_Delta( c.mCell_Delta ) { } // note if ioAtom is non-nil, caller needs to call ioAtom->AddCellUse(): morkCell(mork_column inCol, mork_change inChange, morkAtom* ioAtom) diff --git a/db/mork/src/morkConfig.cpp b/db/mork/src/morkConfig.cpp index d2822b1f9785..d62be2b7a696 100644 --- a/db/mork/src/morkConfig.cpp +++ b/db/mork/src/morkConfig.cpp @@ -30,8 +30,8 @@ //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 -/* ----- ----- ----- ----- MORK_MAC ----- ----- ----- ----- */ -#ifdef MORK_MAC +/* ----- ----- ----- ----- MORK_OBSOLETE ----- ----- ----- ----- */ +#ifdef MORK_OBSOLETE #include @@ -58,14 +58,14 @@ DebugStr(pascalStr); /* call Mac debugger entry point */ } -#endif /*MORK_MAC*/ -/* ----- ----- ----- ----- MORK_MAC ----- ----- ----- ----- */ +#endif /*MORK_OBSOLETE*/ +/* ----- ----- ----- ----- MORK_OBSOLETE ----- ----- ----- ----- */ void mork_assertion_signal(const char* inMessage) { -#ifdef XP_MAC +#ifdef MORK_OBSOLETE mork_mac_break_string(inMessage); -#endif /*XP_MAC*/ +#endif /*MORK_OBSOLETE*/ #ifdef MORK_WIN // asm { int 3 } diff --git a/db/mork/src/morkConfig.h b/db/mork/src/morkConfig.h index 7ba7d0072406..1148a7c91a53 100644 --- a/db/mork/src/morkConfig.h +++ b/db/mork/src/morkConfig.h @@ -32,6 +32,7 @@ // { %%%%% begin platform defs peculiar to Mork %%%%% #ifdef XP_MAC #define MORK_MAC 1 +#define MORK_OBSOLETE 1 #endif #ifdef XP_OS2 @@ -46,9 +47,14 @@ #ifdef XP_UNIX #define MORK_UNIX 1 #endif + +#ifdef MORK_OBSOLETE +#undef MORK_MAC +#endif + // } %%%%% end platform defs peculiar to Mork %%%%% -#if defined (MORK_WIN) || defined(MORK_UNIX) +#if defined(MORK_WIN) || defined(MORK_UNIX) || defined(MORK_MAC) #include "stdio.h" #include "ctype.h" #include "errno.h" @@ -60,12 +66,12 @@ #define MORK_FILETELL(file) ftell(file) #define MORK_FILESEEK(file, where, how) fseek(file, where, how) -#define MORK_FILEREAD(outbuf, insize, file) fread(outbuf, insize, 1, file) +#define MORK_FILEREAD(outbuf, insize, file) fread(outbuf, 1, insize, file) #define MORK_FILEFLUSH(file) fflush(file) #define MORK_FILECLOSE(file) fclose(file) #endif /*MORK_WIN*/ -#ifdef MORK_MAC +#ifdef MORK_OBSOLETE #include "xp_file.h" #include "ctype.h" @@ -76,17 +82,17 @@ #define MORK_FILEREAD(outbuf, insize, file) XP_FileRead(outbuf, insize, file) #define MORK_FILEFLUSH(file) XP_FileFlush(file) #define MORK_FILECLOSE(file) XP_FileClose(file) -#endif /*MORK_MAC*/ +#endif /*MORK_OBSOLETE*/ /* ===== ===== ===== ===== line characters ===== ===== ===== ===== */ -#define mork_kCR '\015' -#define mork_kLF '\012' +#define mork_kCR 0x0D +#define mork_kLF 0x0A #define mork_kVTAB '\013' #define mork_kFF '\014' #define mork_kTAB '\011' #define mork_kCRLF "\015\012" /* A CR LF equivalent string */ -#ifdef MORK_MAC +#if defined(MORK_MAC) || defined(MORK_OBSOLETE) # define mork_kNewline "\015" # define mork_kNewlineSize 1 #else @@ -113,18 +119,14 @@ extern void mork_assertion_signal(const char* inMessage); // { %%%%% begin standard c utility methods %%%%% /*define MORK_USE_XP_STDLIB 1*/ -#ifdef MORK_MAC +#ifdef MORK_OBSOLETE #define MORK_PROVIDE_STDLIB 1 -#endif /*MORK_MAC*/ +#endif /*MORK_OBSOLETE*/ -#ifdef MORK_WIN +#if defined(MORK_WIN) || defined(MORK_UNIX) || defined(MORK_MAC) #define MORK_USE_C_STDLIB 1 #endif /*MORK_WIN*/ -#ifdef MORK_UNIX -#define MORK_USE_NSPR_STDLIB 1 -#endif - #ifdef MORK_USE_C_STDLIB #define MORK_MEMCMP(src1,src2,size) memcmp(src1,src2,size) #define MORK_MEMCPY(dest,src,size) memcpy(dest,src,size) @@ -167,16 +169,6 @@ MORK_LIB(mork_size) mork_strlen(const void* inString); #define MORK_STRLEN(string) XP_STRLEN(string) #endif /*MORK_USE_XP_STDLIB*/ -#ifdef MORK_USE_NSPR_STDLIB -#define MORK_MEMCMP(src1,src2, size) memcmp(src1, src2, size) -#define MORK_MEMCPY(src1,src2, size) memcpy(src1, src2, size) -#define MORK_MEMMOVE(dest, src, size) memmove(src1, src2, size) -#define MORK_MEMSET(dest,byte,size) memset(dest,byte,size) -#define MORK_STRCPY(dest,src) PL_strcpy(dest,src) -#define MORK_STRCMP(one,two) PL_strcmp(one,two) -#define MORK_STRNCMP(one,two,length) PL_strncmp(one,two,length) -#define MORK_STRLEN(string) PL_strlen(string) -#endif // } %%%%% end standard c utility methods %%%%% diff --git a/db/mork/src/morkFile.cpp b/db/mork/src/morkFile.cpp index 5436caa3612d..d521eeb78f6a 100644 --- a/db/mork/src/morkFile.cpp +++ b/db/mork/src/morkFile.cpp @@ -221,7 +221,7 @@ morkFile::NewFileErrnoError(morkEnv* ev) const // ````` ````` ````` ````` newlines ````` ````` ````` ````` -#ifdef MORK_MAC +#if defined(MORK_MAC) || defined(MORK_OBSOLETE) static const char* morkFile_kNewlines = "\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015"; # define morkFile_kNewlinesCount 16 @@ -314,7 +314,7 @@ morkStdioFile::OpenOldStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap, morkStdioFile* outFile = 0; if ( ioHeap && inFilePath ) { - const char* mode = (inFrozen)? "rb" : "wb"; + const char* mode = (inFrozen)? "rb" : "rb+"; outFile = new(*ioHeap, ev) morkStdioFile(ev, morkUsage::kHeap, ioHeap, ioHeap, inFilePath, mode); diff --git a/db/mork/src/morkParser.cpp b/db/mork/src/morkParser.cpp index bfec6374e7ee..077bf2830ce5 100644 --- a/db/mork/src/morkParser.cpp +++ b/db/mork/src/morkParser.cpp @@ -52,13 +52,17 @@ #include "morkSink.h" #endif +#ifndef _MORKCH_ +#include "morkCh.h" +#endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 // ````` ````` ````` ````` ````` // { ===== begin morkNode interface ===== /*public virtual*/ void -morkParser::CloseMorkNode(morkEnv* ev) /*i*/ // CloseParser() only if open +morkParser::CloseMorkNode(morkEnv* ev) // CloseParser() only if open { if ( this->IsOpenNode() ) { @@ -69,14 +73,14 @@ morkParser::CloseMorkNode(morkEnv* ev) /*i*/ // CloseParser() only if open } /*public virtual*/ -morkParser::~morkParser() /*i*/ // assert CloseParser() executed earlier +morkParser::~morkParser() // assert CloseParser() executed earlier { MORK_ASSERT(mParser_Heap==0); MORK_ASSERT(mParser_Stream==0); } /*public non-poly*/ -morkParser::morkParser(morkEnv* ev, /*i*/ +morkParser::morkParser(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap, morkStream* ioStream, mdb_count inBytesPerParseSegment, nsIMdbHeap* ioSlotHeap) @@ -88,8 +92,9 @@ morkParser::morkParser(morkEnv* ev, /*i*/ , mParser_GroupContentStartPos( 0 ) -, mParser_TableId( 0 ) -, mParser_RowId( 0 ) +, mParser_TableMid( ) +, mParser_RowMid( ) +, mParser_CellMid( ) , mParser_InPort( morkBool_kFalse ) , mParser_InDict( morkBool_kFalse ) @@ -97,41 +102,58 @@ morkParser::morkParser(morkEnv* ev, /*i*/ , mParser_InMeta( morkBool_kFalse ) , mParser_InPortRow( morkBool_kFalse ) +, mParser_InRow( morkBool_kFalse ) +, mParser_InTable( morkBool_kFalse ) +, mParser_InGroup( morkBool_kFalse ) + +, mParser_AtomChange( morkChange_kNil ) +, mParser_CellChange( morkChange_kNil ) +, mParser_RowChange( morkChange_kNil ) +, mParser_TableChange( morkChange_kNil ) + +, mParser_Change( morkChange_kNil ) , mParser_IsBroken( morkBool_kFalse ) , mParser_IsDone( morkBool_kFalse ) +, mParser_DoMore( morkBool_kTrue ) -, mParser_Alias() +, mParser_Mid() -, mParser_ScopeSpool(ev, ioHeap) -, mParser_ValueSpool(ev, ioHeap) -, mParser_ColumnSpool(ev, ioHeap) -, mParser_StringSpool(ev, ioHeap) +, mParser_ScopeCoil(ev, ioSlotHeap) +, mParser_ValueCoil(ev, ioSlotHeap) +, mParser_ColumnCoil(ev, ioSlotHeap) +, mParser_StringCoil(ev, ioSlotHeap) -, mParser_ScopeSink(ev, &mParser_ScopeSpool) -, mParser_ValueSink(ev, &mParser_ValueSpool) -, mParser_ColumnSink(ev, &mParser_ColumnSpool) -, mParser_StringSink(ev, &mParser_StringSpool) +, mParser_ScopeSpool(ev, &mParser_ScopeCoil) +, mParser_ValueSpool(ev, &mParser_ValueCoil) +, mParser_ColumnSpool(ev, &mParser_ColumnCoil) +, mParser_StringSpool(ev, &mParser_StringCoil) -, mParser_AliasYarn(ev, morkUsage_kMember, ioHeap) +, mParser_MidYarn(ev, morkUsage_kMember, ioSlotHeap) { - ev->StubMethodOnlyError(); - if ( inBytesPerParseSegment < morkParser_kMinGranularity ) inBytesPerParseSegment = morkParser_kMinGranularity; else if ( inBytesPerParseSegment > morkParser_kMaxGranularity ) inBytesPerParseSegment = morkParser_kMaxGranularity; mParser_MoreGranularity = inBytesPerParseSegment; - - if ( ev->Good() ) + + if ( ioSlotHeap && ioStream ) { - mParser_Tag = morkParser_kTag; - mNode_Derived = morkDerived_kParser; + nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mParser_Heap); + morkStream::SlotStrongStream(ioStream, ev, &mParser_Stream); + + if ( ev->Good() ) + { + mParser_Tag = morkParser_kTag; + mNode_Derived = morkDerived_kParser; + } } + else + ev->NilPointerError(); } /*public non-poly*/ void -morkParser::CloseParser(morkEnv* ev) /*i*/ // called by CloseMorkNode(); +morkParser::CloseParser(morkEnv* ev) // called by CloseMorkNode(); { if ( this ) { @@ -139,10 +161,10 @@ morkParser::CloseParser(morkEnv* ev) /*i*/ // called by CloseMorkNode(); { if ( !this->IsShutNode() ) { - mParser_ScopeSpool.CloseSpool(ev); - mParser_ValueSpool.CloseSpool(ev); - mParser_ColumnSpool.CloseSpool(ev); - mParser_StringSpool.CloseSpool(ev); + mParser_ScopeCoil.CloseCoil(ev); + mParser_ValueCoil.CloseCoil(ev); + mParser_ColumnCoil.CloseCoil(ev); + mParser_StringCoil.CloseCoil(ev); nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mParser_Heap); morkStream::SlotStrongStream((morkStream*) 0, ev, &mParser_Stream); this->MarkShut(); @@ -158,19 +180,6 @@ morkParser::CloseParser(morkEnv* ev) /*i*/ // called by CloseMorkNode(); // } ===== end morkNode methods ===== // ````` ````` ````` ````` ````` -/*public non-poly*/ void -morkParser::SetParserStream(morkEnv* ev, morkStream* ioStream) -{ - morkStream* stream = mParser_Stream; - if ( stream ) - { - mParser_Stream = 0; - stream->CutStrongRef(ev); - } - if ( ioStream && ioStream->AddStrongRef(ev) ) - mParser_Stream = ioStream; -} - /*protected non-poly*/ void morkParser::NonGoodParserError(morkEnv* ev) // when GoodParserTag() is false { @@ -202,114 +211,871 @@ morkParser::NonUsableParserError(morkEnv* ev) // /*protected non-poly*/ void morkParser::StartParse(morkEnv* ev) { + mParser_InCell = morkBool_kFalse; + mParser_InMeta = morkBool_kFalse; + mParser_InDict = morkBool_kFalse; + mParser_InPortRow = morkBool_kFalse; + + mParser_RowMid.ClearMid(); + mParser_TableMid.ClearMid(); + mParser_CellMid.ClearMid(); + + mParser_GroupId = 0; + mParser_InPort = morkBool_kTrue; + + mParser_GroupSpan.ClearSpan(); + mParser_DictSpan.ClearSpan(); + mParser_AliasSpan.ClearSpan(); + mParser_MetaSpan.ClearSpan(); + mParser_TableSpan.ClearSpan(); + mParser_RowSpan.ClearSpan(); + mParser_CellSpan.ClearSpan(); + mParser_ColumnSpan.ClearSpan(); + mParser_SlotSpan.ClearSpan(); + + mParser_PortSpan.ClearSpan(); } /*protected non-poly*/ void morkParser::StopParse(morkEnv* ev) { - if ( mParser_InCell ) - { - mParser_InCell = morkBool_kFalse; - mParser_CellSpan.SetEndWithEnd(mParser_PortSpan); - this->OnCellEnd(ev, mParser_CellSpan); - } - if ( mParser_InMeta ) - { - mParser_InMeta = morkBool_kFalse; - mParser_MetaSpan.SetEndWithEnd(mParser_PortSpan); - this->OnMetaEnd(ev, mParser_MetaSpan); - } - if ( mParser_InPortRow ) - { - mParser_InPortRow = morkBool_kFalse; - mParser_RowSpan.SetEndWithEnd(mParser_PortSpan); - this->OnPortRowEnd(ev, mParser_RowSpan); - } - if ( mParser_RowId ) - { - mParser_RowId = 0; - mParser_RowSpan.SetEndWithEnd(mParser_PortSpan); - this->OnRowEnd(ev, mParser_RowSpan); - } - if ( mParser_TableId ) - { - mParser_TableId = 0; - mParser_TableSpan.SetEndWithEnd(mParser_PortSpan); - this->OnTableEnd(ev, mParser_TableSpan); - } - if ( mParser_GroupId ) - { - mParser_GroupId = 0; - mParser_GroupSpan.SetEndWithEnd(mParser_PortSpan); - this->OnGroupAbortEnd(ev, mParser_GroupSpan); - } - if ( mParser_InPort ) - { - mParser_InPort = morkBool_kFalse; - this->OnPortEnd(ev, mParser_PortSpan); - } + if ( mParser_InCell ) + { + mParser_InCell = morkBool_kFalse; + mParser_CellSpan.SetEndWithEnd(mParser_PortSpan); + this->OnCellEnd(ev, mParser_CellSpan); + } + if ( mParser_InMeta ) + { + mParser_InMeta = morkBool_kFalse; + mParser_MetaSpan.SetEndWithEnd(mParser_PortSpan); + this->OnMetaEnd(ev, mParser_MetaSpan); + } + if ( mParser_InDict ) + { + mParser_InDict = morkBool_kFalse; + mParser_DictSpan.SetEndWithEnd(mParser_PortSpan); + this->OnDictEnd(ev, mParser_DictSpan); + } + if ( mParser_InPortRow ) + { + mParser_InPortRow = morkBool_kFalse; + mParser_RowSpan.SetEndWithEnd(mParser_PortSpan); + this->OnPortRowEnd(ev, mParser_RowSpan); + } + if ( mParser_InRow ) + { + mParser_InRow = morkBool_kFalse; + mParser_RowMid.ClearMid(); + mParser_RowSpan.SetEndWithEnd(mParser_PortSpan); + this->OnRowEnd(ev, mParser_RowSpan); + } + if ( mParser_InTable ) + { + mParser_InTable = morkBool_kFalse; + mParser_TableMid.ClearMid(); + mParser_TableSpan.SetEndWithEnd(mParser_PortSpan); + this->OnTableEnd(ev, mParser_TableSpan); + } + if ( mParser_GroupId ) + { + mParser_GroupId = 0; + mParser_GroupSpan.SetEndWithEnd(mParser_PortSpan); + this->OnGroupAbortEnd(ev, mParser_GroupSpan); + } + if ( mParser_InPort ) + { + mParser_InPort = morkBool_kFalse; + this->OnPortEnd(ev, mParser_PortSpan); + } } -///*protected non-poly*/ int -//morkParser::NextChar(morkEnv* ev) -//{ -//} - -/*protected non-poly*/ int -morkParser::NextChar(morkEnv* ev) // next non-white content +int morkParser::eat_comment(morkEnv* ev) // last char was '/' { - register int c; // the most heavily used character variable - int outChar = -1; // the byte to return from this method - int d; // the byte after c on some occasions morkStream* s = mParser_Stream; - if ( s ) + // Note morkStream::Getc() returns EOF when an error occurs, so + // we don't need to check for both c != EOF and ev->Good() below. + + register int c = s->Getc(ev); + if ( c == '/' ) // C++ style comment? { - while ( outChar == -1 && ev->Good() ) + while ( (c = s->Getc(ev)) != EOF && c != 0xA && c != 0xD ) + /* empty */; + + if ( c == 0xA || c == 0xD ) + c = this->eat_line_break(ev, c); + } + else if ( c == '*' ) /* C style comment? */ + { + int depth = 1; // count depth of comments until depth reaches zero + + while ( depth > 0 && c != EOF ) // still looking for comment end(s)? { - while ( (c = s->Getc(ev)) != EOF && ev->Good() ) + while ( (c = s->Getc(ev)) != EOF && c != '/' && c != '*' ) { - if ( c == 0xA || c == 0xD ) // end of line? + if ( c == 0xA || c == 0xD ) // need to count a line break? { - this->AddLine(); - d = s->Getc(ev); // look for another byte in #xA #xD, or #xD #xA - if (( d == 0xA || d == 0xD ) && c != d ) // eat this one too? - { - } - else if ( d != EOF ) // not trying to push back end of file - s->Ungetc(d); + c = this->eat_line_break(ev, c); + if ( c == '/' || c == '*' ) + break; // end while loop } } - - if ( c == '/' ) // maybe start of comment? + + if ( c == '*' ) // maybe end of a comment, if next char is '/'? { - int depth = 0; + if ( (c = s->Getc(ev)) == '/' ) // end of comment? + --depth; // depth of comments has decreased by one + else if ( c != EOF ) // need to put the char back? + s->Ungetc(c); // especially need to put back '*', 0xA, or 0xD } - else if ( c == '\\' ) // maybe start of line continuation? + else if ( c == '/' ) // maybe nested comemnt, if next char is '*'? { - if ( (c = s->Getc(ev)) == 0xA || c == 0xD ) - ; - } - - if ( c == EOF ) // reached end of file? - { - if ( outChar == -1 ) - outChar = 1; // end while loop - mParser_DoMore = morkBool_kFalse; - mParser_IsDone = morkBool_kTrue; + if ( (c = s->Getc(ev)) == '*' ) // nested comment? + ++depth; // depth of comments has increased by one + else if ( c != EOF ) // need to put the char back? + s->Ungetc(c); // especially need to put back '/', 0xA, or 0xD } + + if ( ev->Bad() ) + c = EOF; } - - this->SetHerePos(s->Tell(ev)); + if ( c == EOF && depth > 0 ) + ev->NewWarning("EOF before end of comment"); } - else // nil stream pointer + else + ev->NewWarning("expected / or *"); + + return c; +} + +int morkParser::eat_line_break(morkEnv* ev, int inLast) +{ + morkStream* s = mParser_Stream; + register int c = s->Getc(ev); // get next char after 0xA or 0xD + this->CountLineBreak(); + if ( c == 0xA || c == 0xD ) // another line break character? + { + if ( c != inLast ) // not the same as the last one? + c = s->Getc(ev); // get next char after two-byte linebreak + } + return c; +} + +int morkParser::eat_line_continue(morkEnv* ev) // last char was '\\' +{ + morkStream* s = mParser_Stream; + register int c = s->Getc(ev); + if ( c == 0xA || c == 0xD ) // linebreak follows \ as expected? + { + c = this->eat_line_break(ev, c); + } + else + ev->NewWarning("expected linebreak"); + + return c; +} + +int morkParser::NextChar(morkEnv* ev) // next non-white content +{ + morkStream* s = mParser_Stream; + register int c = s->Getc(ev); + while ( c > 0 && ev->Good() ) + { + if ( c == '/' ) + c = this->eat_comment(ev); + else if ( c == 0xA || c == 0xD ) + c = this->eat_line_break(ev, c); + else if ( c == '\\' ) + c = this->eat_line_continue(ev); + else if ( morkCh_IsWhite(c) ) + c = s->Getc(ev); + else + break; // end while loop when return c is acceptable + } + if ( ev->Bad() ) { - ev->NilPointerError(); mParser_State = morkParser_kBrokenState; mParser_DoMore = morkBool_kFalse; mParser_IsDone = morkBool_kTrue; mParser_IsBroken = morkBool_kTrue; + c = EOF; } - return outChar; + else if ( c == EOF ) + { + mParser_DoMore = morkBool_kFalse; + mParser_IsDone = morkBool_kTrue; + } + return c; +} + +void +morkParser::OnCellState(morkEnv* ev) +{ + ev->StubMethodOnlyError(); +} + +void +morkParser::OnMetaState(morkEnv* ev) +{ + ev->StubMethodOnlyError(); +} + +void +morkParser::OnRowState(morkEnv* ev) +{ + ev->StubMethodOnlyError(); +} + +void +morkParser::OnTableState(morkEnv* ev) +{ + ev->StubMethodOnlyError(); +} + +void +morkParser::OnDictState(morkEnv* ev) +{ + ev->StubMethodOnlyError(); +} + +morkBuf* morkParser::ReadName(morkEnv* ev, register int c) +{ + morkBuf* outBuf = 0; + + if ( !morkCh_IsName(c) ) + ev->NewError("not a name char"); + + morkCoil* coil = &mParser_ColumnCoil; + coil->ClearBufFill(); + + morkSpool* spool = &mParser_ColumnSpool; + spool->Seek(ev, /*pos*/ 0); + + if ( ev->Good() ) + { + spool->Putc(ev, c); + + morkStream* s = mParser_Stream; + while ( (c = s->Getc(ev)) != EOF && morkCh_IsMore(c) && ev->Good() ) + spool->Putc(ev, c); + + if ( ev->Good() ) + { + if ( c != EOF ) + { + s->Ungetc(c); + spool->FlushSink(ev); // update coil->mBuf_Fill + } + else + this->UnexpectedEofError(ev); + + if ( ev->Good() ) + outBuf = coil; + } + } + return outBuf; +} + +mork_bool +morkParser::ReadMid(morkEnv* ev, morkMid* outMid) +{ + outMid->ClearMid(); + + morkStream* s = mParser_Stream; + int next; + outMid->mMid_Oid.mOid_Id = this->ReadHex(ev, &next); + register int c = next; + if ( c == ':' ) + { + if ( (c = s->Getc(ev)) != EOF && ev->Good() ) + { + if ( c == '^' ) + { + outMid->mMid_Oid.mOid_Scope = this->ReadHex(ev, &next); + if ( ev->Good() ) + s->Ungetc(next); + } + else if ( morkCh_IsName(c) ) + { + outMid->mMid_Buf = this->ReadName(ev, c); + } + else + ev->NewError("expected name or hex after ':' following ID"); + } + + if ( c == EOF && ev->Good() ) + this->UnexpectedEofError(ev); + } + else + s->Ungetc(c); + + return ev->Good(); +} + +void +morkParser::ReadCell(morkEnv* ev) +{ + mParser_CellMid.ClearMid(); + this->StartSpanOnLastByte(ev, &mParser_CellSpan); + morkMid* cellMid = 0; // if mid syntax is used for column + morkBuf* cellBuf = 0; // if naked string is used for column + + morkStream* s = mParser_Stream; + register int c; + if ( (c = s->Getc(ev)) != EOF && ev->Good() ) + { + this->StartSpanOnLastByte(ev, &mParser_ColumnSpan); + if ( c == '^' ) + { + cellMid = &mParser_CellMid; + this->ReadMid(ev, cellMid); + // if ( !mParser_CellMid.mMid_Oid.mOid_Scope ) + // mParser_CellMid.mMid_Oid.mOid_Scope = (mork_scope) 'c'; + } + else + { + cellBuf = this->ReadName(ev, c); + } + if ( ev->Good() ) + { + this->EndSpanOnThisByte(ev, &mParser_ColumnSpan); + + mParser_InCell = morkBool_kTrue; + this->OnNewCell(ev, *mParser_CellSpan.AsPlace(), + cellMid, cellBuf, mParser_CellChange); + + if ( (c = this->NextChar(ev)) != EOF && ev->Good() ) + { + this->StartSpanOnLastByte(ev, &mParser_SlotSpan); + if ( c == '=' ) + { + morkBuf* buf = this->ReadValue(ev); + if ( buf ) + { + this->EndSpanOnThisByte(ev, &mParser_SlotSpan); + this->OnValue(ev, mParser_SlotSpan, *buf); + } + } + else if ( c == '^' ) + { + if ( this->ReadMid(ev, &mParser_Mid) ) + { + this->EndSpanOnThisByte(ev, &mParser_SlotSpan); + if ( (c = this->NextChar(ev)) != EOF && ev->Good() ) + { + if ( c != ')' ) + ev->NewError("expected ')' after cell ^ID value"); + } + else if ( c == EOF ) + this->UnexpectedEofError(ev); + + if ( ev->Good() ) + this->OnValueMid(ev, mParser_SlotSpan, mParser_Mid); + } + } + else if ( c == 'r' || c == 't' || c == '"' || c == '\'' ) + { + ev->NewError("cell syntax not yet supported"); + } + else + { + ev->NewError("unknown cell syntax"); + } + } + + this->EndSpanOnThisByte(ev, &mParser_CellSpan); + mParser_InCell = morkBool_kFalse; + this->OnCellEnd(ev, mParser_CellSpan); + } + } + + if ( c == EOF && ev->Good() ) + this->UnexpectedEofError(ev); +} + +void morkParser::ReadRow(morkEnv* ev, int c) +// zm:Row ::= zm:S? '[' zm:S? zm:Id zm:RowItem* zm:S? ']' +// zm:RowItem ::= zm:MetaRow | zm:Cell +// zm:MetaRow ::= zm:S? '[' zm:S? zm:Cell* zm:S? ']' /* meta attributes */ +// zm:Cell ::= zm:S? '(' zm:Column zm:S? zm:Slot? ')' +{ + if ( ev->Good() ) + { + this->StartSpanOnLastByte(ev, &mParser_RowSpan); + if ( mParser_Change ) + mParser_RowChange = mParser_Change; + + if ( c == '[' ) + { + if ( this->ReadMid(ev, &mParser_RowMid) ) + { + mParser_InRow = morkBool_kTrue; + this->OnNewRow(ev, *mParser_RowSpan.AsPlace(), + mParser_RowMid, mParser_RowChange); + + mParser_Change = mParser_RowChange = morkChange_kNil; + + while ( (c = this->NextChar(ev)) != EOF && ev->Good() && c != ']' ) + { + switch ( c ) + { + case '(': // cell + this->ReadCell(ev); + break; + + case '[': // meta + this->ReadMeta(ev, ']'); + break; + + case '+': // plus + mParser_CellChange = morkChange_kAdd; + break; + + case '-': // minus + mParser_CellChange = morkChange_kCut; + break; + + case '!': // bang + mParser_CellChange = morkChange_kSet; + break; + + default: + ev->NewWarning("unexpected byte in row"); + break; + } // switch + } // while + + this->EndSpanOnThisByte(ev, &mParser_RowSpan); + mParser_InRow = morkBool_kFalse; + this->OnRowEnd(ev, mParser_RowSpan); + + } // if ReadMid + } // if '[' + + else // c != '[' + { + morkStream* s = mParser_Stream; + s->Ungetc(c); + if ( this->ReadMid(ev, &mParser_RowMid) ) + { + mParser_InRow = morkBool_kTrue; + this->OnNewRow(ev, *mParser_RowSpan.AsPlace(), + mParser_RowMid, mParser_RowChange); + + mParser_Change = mParser_RowChange = morkChange_kNil; + + this->EndSpanOnThisByte(ev, &mParser_RowSpan); + mParser_InRow = morkBool_kFalse; + this->OnRowEnd(ev, mParser_RowSpan); + } + } + } + + if ( ev->Bad() ) + mParser_State = morkParser_kBrokenState; + else if ( c == EOF ) + mParser_State = morkParser_kDoneState; +} + +void morkParser::ReadTable(morkEnv* ev) +// zm:Table ::= zm:S? '{' zm:S? zm:Id zm:TableItem* zm:S? '}' +// zm:TableItem ::= zm:MetaTable | zm:RowRef | zm:Row +// zm:MetaTable ::= zm:S? '{' zm:S? zm:Cell* zm:S? '}' /* meta attributes */ +{ + this->StartSpanOnLastByte(ev, &mParser_TableSpan); + + if ( mParser_Change ) + mParser_TableChange = mParser_Change; + + if ( ev->Good() && this->ReadMid(ev, &mParser_TableMid) ) + { + mParser_InTable = morkBool_kTrue; + this->OnNewTable(ev, *mParser_TableSpan.AsPlace(), + mParser_TableMid, mParser_TableChange); + + mParser_Change = mParser_TableChange = morkChange_kNil; + + int c; + while ( (c = this->NextChar(ev)) != EOF && ev->Good() && c != '}' ) + { + if ( morkCh_IsHex(c) ) + { + this->ReadRow(ev, c); + } + else + { + switch ( c ) + { + case '[': // row + this->ReadRow(ev, '['); + break; + + case '{': // meta + this->ReadMeta(ev, '}'); + break; + + case '+': // plus + mParser_RowChange = morkChange_kAdd; + break; + + case '-': // minus + mParser_RowChange = morkChange_kCut; + break; + + case '!': // bang + mParser_RowChange = morkChange_kSet; + break; + + default: + ev->NewWarning("unexpected byte in table"); + break; + } + } + } + + this->EndSpanOnThisByte(ev, &mParser_TableSpan); + mParser_InTable = morkBool_kFalse; + this->OnTableEnd(ev, mParser_TableSpan); + + if ( ev->Bad() ) + mParser_State = morkParser_kBrokenState; + else if ( c == EOF ) + mParser_State = morkParser_kDoneState; + } +} + +mork_id morkParser::ReadHex(morkEnv* ev, int* outNextChar) +// zm:Hex ::= [0-9a-fA-F] /* a single hex digit */ +// zm:Hex+ ::= zm:Hex | zm:Hex zm:Hex+ +{ + mork_id hex = 0; + + morkStream* s = mParser_Stream; + register int c = this->NextChar(ev); + + if ( ev->Good() ) + { + if ( c != EOF ) + { + if ( morkCh_IsHex(c) ) + { + do + { + if ( morkCh_IsDigit(c) ) // '0' through '9'? + c -= '0'; + else if ( morkCh_IsUpper(c) ) // 'A' through 'F'? + c -= ('A' - 10) ; // c = (c - 'A') + 10; + else // 'a' through 'f'? + c -= ('a' - 10) ; // c = (c - 'a') + 10; + + hex = (hex << 4) + c; + } + while ( (c = s->Getc(ev)) != EOF && ev->Good() && morkCh_IsHex(c) ); + } + else + this->ExpectedHexDigitError(ev, c); + } + } + if ( c == EOF ) + this->EofInsteadOfHexError(ev); + + *outNextChar = c; + return hex; +} + +/*static*/ void +morkParser::EofInsteadOfHexError(morkEnv* ev) +{ + ev->NewWarning("eof instead of hex"); +} + +/*static*/ void +morkParser::ExpectedHexDigitError(morkEnv* ev, int c) +{ + ev->NewWarning("expected hex digit"); +} + +/*static*/ void +morkParser::ExpectedEqualError(morkEnv* ev) +{ + ev->NewWarning("expected '='"); +} + +/*static*/ void +morkParser::UnexpectedEofError(morkEnv* ev) +{ + ev->NewWarning("unexpected eof"); +} + +morkBuf* morkParser::ReadValue(morkEnv* ev) +{ + morkBuf* outBuf = 0; + + morkCoil* coil = &mParser_ValueCoil; + coil->ClearBufFill(); + + morkSpool* spool = &mParser_ValueSpool; + spool->Seek(ev, /*pos*/ 0); + + if ( ev->Good() ) + { + morkStream* s = mParser_Stream; + register int c; + while ( (c = s->Getc(ev)) != EOF && c != ')' && ev->Good() ) + { + if ( c == '\\' ) // "\" escapes the next char? + { + if ( (c = s->Getc(ev)) == EOF || ev->Bad() ) + break; // end while loop + } + spool->Putc(ev, c); + } + + if ( ev->Good() ) + { + if ( c != EOF ) + spool->FlushSink(ev); // update coil->mBuf_Fill + else + this->UnexpectedEofError(ev); + + if ( ev->Good() ) + outBuf = coil; + } + } + return outBuf; +} + +void morkParser::ReadAlias(morkEnv* ev) +// zm:Alias ::= zm:S? '(' ('#')? zm:Hex+ zm:S? zm:Value ')' +// zm:Value ::= '=' ([^)$\] | '\' zm:NonCRLF | zm:Continue | zm:Dollar)* +{ + this->StartSpanOnLastByte(ev, &mParser_AliasSpan); + + int nextChar; + mork_id hex = this->ReadHex(ev, &nextChar); + register int c = nextChar; + + mParser_Mid.ClearMid(); + mParser_Mid.mMid_Oid.mOid_Id = hex; + + if ( morkCh_IsWhite(c) && ev->Good() ) + c = this->NextChar(ev); + + if ( ev->Good() ) + { + if ( c == '=' ) + { + mParser_Mid.mMid_Buf = this->ReadValue(ev); + if ( mParser_Mid.mMid_Buf ) + { + this->EndSpanOnThisByte(ev, &mParser_AliasSpan); + this->OnAlias(ev, mParser_AliasSpan, mParser_Mid); + } + } + else + this->ExpectedEqualError(ev); + } +} + +void morkParser::ReadMeta(morkEnv* ev, int inEndMeta) +// zm:MetaDict ::= zm:S? '<' zm:S? zm:Cell* zm:S? '>' /* meta attributes */ +// zm:MetaTable ::= zm:S? '{' zm:S? zm:Cell* zm:S? '}' /* meta attributes */ +// zm:MetaRow ::= zm:S? '[' zm:S? zm:Cell* zm:S? ']' /* meta attributes */ +{ + this->StartSpanOnLastByte(ev, &mParser_MetaSpan); + mParser_InMeta = morkBool_kTrue; + this->OnNewMeta(ev, *mParser_MetaSpan.AsPlace()); + + mork_bool more = morkBool_kTrue; // until end meta + int c; + while ( more && (c = this->NextChar(ev)) != EOF && ev->Good() ) + { + switch ( c ) + { + case '(': // cell + this->ReadCell(ev); + break; + + case '>': // maybe end meta? + if ( inEndMeta == '>' ) + more = morkBool_kFalse; // stop reading meta + else + this->UnexpectedByteInMetaWarning(ev); + break; + + case '}': // maybe end meta? + if ( inEndMeta == '}' ) + more = morkBool_kFalse; // stop reading meta + else + this->UnexpectedByteInMetaWarning(ev); + break; + + case ']': // maybe end meta? + if ( inEndMeta == ']' ) + more = morkBool_kFalse; // stop reading meta + else + this->UnexpectedByteInMetaWarning(ev); + break; + + default: + this->UnexpectedByteInMetaWarning(ev); + break; + } + } + + this->EndSpanOnThisByte(ev, &mParser_MetaSpan); + mParser_InMeta = morkBool_kFalse; + this->OnMetaEnd(ev, mParser_MetaSpan); +} + +/*static*/ void +morkParser::UnexpectedByteInMetaWarning(morkEnv* ev) +{ + ev->NewWarning("unexpected byte in meta"); +} + +/*static*/ void +morkParser::NonParserTypeError(morkEnv* ev) +{ + ev->NewError("non morkParser"); +} + +void morkParser::ReadDict(morkEnv* ev) +// zm:Dict ::= zm:S? '<' zm:DictItem* zm:S? '>' +// zm:DictItem ::= zm:MetaDict | zm:Alias +// zm:MetaDict ::= zm:S? '<' zm:S? zm:Cell* zm:S? '>' /* meta attributes */ +// zm:Alias ::= zm:S? '(' ('#')? zm:Hex+ zm:S? zm:Value ')' +{ + mParser_Change = morkChange_kNil; + mParser_AtomChange = morkChange_kNil; + + this->StartSpanOnLastByte(ev, &mParser_DictSpan); + mParser_InDict = morkBool_kTrue; + this->OnNewDict(ev, *mParser_DictSpan.AsPlace()); + + int c; + while ( (c = this->NextChar(ev)) != EOF && ev->Good() && c != '>' ) + { + switch ( c ) + { + case '(': // alias + this->ReadAlias(ev); + break; + + case '<': // meta + this->ReadMeta(ev, '>'); + break; + + default: + ev->NewWarning("unexpected byte in dict"); + break; + } + } + + this->EndSpanOnThisByte(ev, &mParser_DictSpan); + mParser_InDict = morkBool_kFalse; + this->OnDictEnd(ev, mParser_DictSpan); + + if ( ev->Bad() ) + mParser_State = morkParser_kBrokenState; + else if ( c == EOF ) + mParser_State = morkParser_kDoneState; +} + +void morkParser::EndSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan) +{ + mork_pos here = mParser_Stream->Tell(ev); + if ( ev->Good() ) + { + this->SetHerePos(here); + ioSpan->SetEndWithEnd(mParser_PortSpan); + } +} + +void morkParser::StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan) +{ + mork_pos here = mParser_Stream->Tell(ev); + if ( here > 0 ) // positive? + --here; + else + here = 0; + + if ( ev->Good() ) + { + this->SetHerePos(here); + ioSpan->SetStartWithEnd(mParser_PortSpan); + ioSpan->SetEndWithEnd(mParser_PortSpan); + } +} + +void +morkParser::OnPortState(morkEnv* ev) +{ + mParser_InPort = morkBool_kTrue; + this->OnNewPort(ev, *mParser_PortSpan.AsPlace()); + + int c; + while ( (c = this->NextChar(ev)) != EOF && ev->Good() ) + { + switch ( c ) + { + case '[': // row + this->ReadRow(ev, '['); + break; + + case '{': // table + this->ReadTable(ev); + break; + + case '<': // dict + this->ReadDict(ev); + break; + + case '+': // plus + mParser_Change = morkChange_kAdd; + break; + + case '-': // minus + mParser_Change = morkChange_kCut; + break; + + case '!': // bang + mParser_Change = morkChange_kSet; + break; + + default: + ev->NewWarning("unexpected byte in OnPortState()"); + break; + } + } + + mParser_InPort = morkBool_kFalse; + this->OnPortEnd(ev, mParser_PortSpan); + + if ( ev->Bad() ) + mParser_State = morkParser_kBrokenState; + else if ( c == EOF ) + mParser_State = morkParser_kDoneState; +} + +void +morkParser::OnStartState(morkEnv* ev) +{ + morkStream* s = mParser_Stream; + if ( s && s->IsNode() && s->IsOpenNode() ) + { + s->Seek(ev, 0); + if ( ev->Good() ) + { + this->StartParse(ev); + mParser_State = morkParser_kPortState; + } + } + else + ev->NilPointerError(); + + if ( ev->Bad() ) + mParser_State = morkParser_kBrokenState; } /*protected non-poly*/ void @@ -323,33 +1089,25 @@ morkParser::ParseLoop(morkEnv* ev) switch ( mParser_State ) { case morkParser_kCellState: // 0 - break; + this->OnCellState(ev); break; + case morkParser_kMetaState: // 1 - break; + this->OnMetaState(ev); break; + case morkParser_kRowState: // 2 - break; + this->OnRowState(ev); break; + case morkParser_kTableState: // 3 - break; + this->OnTableState(ev); break; + case morkParser_kDictState: // 4 - break; + this->OnDictState(ev); break; + case morkParser_kPortState: // 5 - break; + this->OnPortState(ev); break; case morkParser_kStartState: // 6 - { - morkStream* s = mParser_Stream; - if ( s && s->IsNode() && s->IsOpenNode() ) - { - this->StartParse(ev); - mParser_State = morkParser_kPortState; - } - else - { - mParser_State = morkParser_kBrokenState; - ev->NilPointerError(); - } - } - break; + this->OnStartState(ev); break; case morkParser_kDoneState: // 7 mParser_DoMore = morkBool_kFalse; diff --git a/db/mork/src/morkParser.h b/db/mork/src/morkParser.h index 50a7d27e67d9..54f04251ed81 100644 --- a/db/mork/src/morkParser.h +++ b/db/mork/src/morkParser.h @@ -23,10 +23,6 @@ #include "mork.h" #endif -#ifndef _MORKPARSER_ -#include "morkParser.h" -#endif - #ifndef _MORKBLOB_ #include "morkBlob.h" #endif @@ -68,6 +64,9 @@ public: morkPlace(mork_pos inPos, mork_line inLine) { mPlace_Pos = inPos; mPlace_Line = inLine; } + + morkPlace(const morkPlace& inPlace) + : mPlace_Pos(inPlace.mPlace_Pos), mPlace_Line(inPlace.mPlace_Line) { } }; /*============================================================================= @@ -80,48 +79,68 @@ public: const char* mGlitch_Comment; // null-terminated ASCII C string morkGlitch() { mGlitch_Comment = 0; } + + morkGlitch(const morkPlace& inPlace, const char* inComment) + : mGlitch_Place(inPlace), mGlitch_Comment(inComment) { } }; /*============================================================================= - * morkAlias: all possible ways needed to express an alias ID in Mork syntax + * morkMid: all possible ways needed to express an alias ID in Mork syntax */ -/*| morkAlias: an abstraction of all the variations we might need to support +/*| morkMid: an abstraction of all the variations we might need to support **| in order to present an ID through the parser interface most cheaply and **| with minimum transformation away from the original text format. **| **|| An ID can have one of four forms: -**| 1) idHex (mAlias_Oid.mOid_Id <- idHex) -**| 2) idHex:^scopeHex (mAlias_Oid.mOid_Id <- idHex, mOid_Scope <- scopeHex) -**| 3) idHex:scopeName (mAlias_Oid.mOid_Id <- idHex, mAlias_Buf <- scopeName) -**| 4) columnName (mAlias_Buf <- columnName, for columns in cells only) +**| 1) idHex (mMid_Oid.mOid_Id <- idHex) +**| 2) idHex:^scopeHex (mMid_Oid.mOid_Id <- idHex, mOid_Scope <- scopeHex) +**| 3) idHex:scopeName (mMid_Oid.mOid_Id <- idHex, mMid_Buf <- scopeName) +**| 4) columnName (mMid_Buf <- columnName, for columns in cells only) **| -**|| Typically, mAlias_Oid.mOid_Id will hold a nonzero integer value for +**|| Typically, mMid_Oid.mOid_Id will hold a nonzero integer value for **| an ID, but we might have an optional scope specified by either an integer **| in hex format, or a string name. (Note that while the first ID can be **| scoped variably, any integer ID for a scope is assumed always located in **| the same scope, so the second ID need not be disambiguated.) **| -**|| The only time mAlias_Oid.mOid_Id is ever zero is when mAlias_Buf alone +**|| The only time mMid_Oid.mOid_Id is ever zero is when mMid_Buf alone **| is nonzero, to indicate an explicit string instead of an alias appeared. **| This case happens to make the representation of columns in cells somewhat **| easier to represent, since columns can just appear as a string name; and **| this unifies those interfaces with row and table APIs expecting IDs. **| -**|| So when the parser passes an instance of morkAlias to a subclass, the -**| mAlias_Oid.mOid_Id slot should usually be nonzero. And the other two -**| slots, mAlias_Oid.mOid_Scope and mAlias_Buf, might both be zero, or at +**|| So when the parser passes an instance of morkMid to a subclass, the +**| mMid_Oid.mOid_Id slot should usually be nonzero. And the other two +**| slots, mMid_Oid.mOid_Scope and mMid_Buf, might both be zero, or at **| most one of them will be nonzero to indicate an explicit scope; the **| parser is responsible for ensuring at most one of these is nonzero. |*/ -class morkAlias { +class morkMid { public: - mdbOid mAlias_Oid; // mOid_Scope is zero when not specified - const morkBuf* mAlias_Buf; // points to some specific buf subclass + mdbOid mMid_Oid; // mOid_Scope is zero when not specified + const morkBuf* mMid_Buf; // points to some specific buf subclass - morkAlias() - { mAlias_Oid.mOid_Scope = 0; mAlias_Oid.mOid_Id = morkId_kMinusOne; - mAlias_Buf = 0; } + morkMid() + { mMid_Oid.mOid_Scope = 0; mMid_Oid.mOid_Id = morkId_kMinusOne; + mMid_Buf = 0; } + + void InitMidWithCoil(morkCoil* ioCoil) + { mMid_Oid.mOid_Scope = 0; mMid_Oid.mOid_Id = morkId_kMinusOne; + mMid_Buf = ioCoil; } + + void ClearMid() + { mMid_Oid.mOid_Scope = 0; mMid_Oid.mOid_Id = morkId_kMinusOne; + mMid_Buf = 0; } + + morkMid(const morkMid& other) + : mMid_Oid(other.mMid_Oid), mMid_Buf(other.mMid_Buf) { } + + mork_bool HasNoId() const // ID is unspecified? + { return ( mMid_Oid.mOid_Id == morkId_kMinusOne ); } + + mork_bool HasSomeId() const // ID is specified? + { return ( mMid_Oid.mOid_Id != morkId_kMinusOne ); } }; /*============================================================================= @@ -138,6 +157,9 @@ public: // methods public: // inlines morkSpan() { } // use inline empty constructor for each place + morkPlace* AsPlace() { return &mSpan_Start; } + const morkPlace* AsConstPlace() const { return &mSpan_Start; } + void SetSpan(mork_pos inFromPos, mork_line inFromLine, mork_pos inToPos, mork_line inToLine) { @@ -208,7 +230,7 @@ class morkParser /*d*/ : public morkNode { // ````` ````` ````` ````` ````` ````` ````` ````` protected: // protected morkParser members - nsIMdbHeap* mParser_Heap; // refcounted heap used for allocation + nsIMdbHeap* mParser_Heap; // refcounted heap used for allocation morkStream* mParser_Stream; // refcounted input stream mork_u4 mParser_Tag; // must equal morkParser_kTag @@ -219,9 +241,10 @@ protected: // protected morkParser members // after finding ends of group transactions, we can re-seek the start: mork_pos mParser_GroupContentStartPos; // start of this group - mork_gid mParser_GroupId; // group ID if inside a group - mork_tid mParser_TableId; // table ID if inside a table - mork_rid mParser_RowId; // row ID if inside a row + morkMid mParser_TableMid; // table mid if inside a table + morkMid mParser_RowMid; // row mid if inside a row + morkMid mParser_CellMid; // cell mid if inside a row + mork_gid mParser_GroupId; // group ID if inside a group mork_bool mParser_InPort; // called OnNewPort but not OnPortEnd? mork_bool mParser_InDict; // called OnNewDict but not OnDictEnd? @@ -229,28 +252,36 @@ protected: // protected morkParser members mork_bool mParser_InMeta; // called OnNewMeta but not OnMetaEnd? mork_bool mParser_InPortRow; // called OnNewPortRow but not OnPortRowEnd? + mork_bool mParser_InRow; // called OnNewRow but not OnNewRowEnd? + mork_bool mParser_InTable; // called OnNewMeta but not OnMetaEnd? + mork_bool mParser_InGroup; // called OnNewGroup but not OnGroupEnd? + + mork_change mParser_AtomChange; // driven by mParser_Change + mork_change mParser_CellChange; // driven by mParser_Change + mork_change mParser_RowChange; // driven by mParser_Change + mork_change mParser_TableChange; // driven by mParser_Change + + mork_change mParser_Change; // driven by modifier in text mork_bool mParser_IsBroken; // has the parse become broken? mork_bool mParser_IsDone; // has the parse finished? mork_bool mParser_DoMore; // mParser_MoreGranularity not exhausted? - mork_change mParser_Change; // driven by modifier in text + morkMid mParser_Mid; // current alias being parsed + // note that mParser_Mid.mMid_Buf points at mParser_ScopeCoil below: - morkAlias mParser_Alias; // current alias being parsed - // note that mParser_Alias.mAlias_Buf points at mParser_ScopeSpool below: + // blob coils allocated in mParser_Heap + morkCoil mParser_ScopeCoil; // place to accumulate ID scope blobs + morkCoil mParser_ValueCoil; // place to accumulate value blobs + morkCoil mParser_ColumnCoil; // place to accumulate column blobs + morkCoil mParser_StringCoil; // place to accumulate string blobs - // blob spools allocated in mParser_Heap - morkSpool mParser_ScopeSpool; // place to accumulate ID scope blobs - morkSpool mParser_ValueSpool; // place to accumulate value blobs - morkSpool mParser_ColumnSpool; // place to accumulate column blobs - morkSpool mParser_StringSpool; // place to accumulate string blobs - - morkSpoolSink mParser_ScopeSink; // writes to mParser_ScopeSpool - morkSpoolSink mParser_ValueSink; // writes to mParser_ValueSpool - morkSpoolSink mParser_ColumnSink; // writes to mParser_ColumnSpool - morkSpoolSink mParser_StringSink; // writes to mParser_StringSpool + morkSpool mParser_ScopeSpool; // writes to mParser_ScopeCoil + morkSpool mParser_ValueSpool; // writes to mParser_ValueCoil + morkSpool mParser_ColumnSpool; // writes to mParser_ColumnCoil + morkSpool mParser_StringSpool; // writes to mParser_StringCoil // yarns allocated in mParser_Heap - morkYarn mParser_AliasYarn; // place to receive from AliasToYarn() + morkYarn mParser_MidYarn; // place to receive from MidToYarn() // span showing current ongoing file position status: morkSpan mParser_PortSpan; // span of current db port file @@ -274,8 +305,8 @@ private: // convenience inlines void SetHerePos(mork_pos inPos) { mParser_PortSpan.mSpan_End.mPlace_Pos = inPos; } - void AddLine() - { ++ mParser_PortSpan.mSpan_End.mPlace_Line; } + void CountLineBreak() + { ++mParser_PortSpan.mSpan_End.mPlace_Line; } // { ===== begin morkNode interface ===== public: // morkNode virtual methods @@ -300,8 +331,13 @@ public: // dynamic type identification // } ===== end morkNode methods ===== -public: // typing - void NonParserTypeError(morkEnv* ev); +public: // errors and warnings + static void UnexpectedEofError(morkEnv* ev); + static void EofInsteadOfHexError(morkEnv* ev); + static void ExpectedEqualError(morkEnv* ev); + static void ExpectedHexDigitError(morkEnv* ev, int c); + static void NonParserTypeError(morkEnv* ev); + static void UnexpectedByteInMetaWarning(morkEnv* ev); public: // other type methods mork_bool GoodParserTag() const { return mParser_Tag == morkParser_kTag; } @@ -312,8 +348,8 @@ public: // other type methods // ````` ````` ````` ````` ````` ````` ````` ````` public: // in virtual morkParser methods, data flow subclass to parser - virtual void AliasToYarn(morkEnv* ev, - const morkAlias& inAlias, // typically an alias to concat with strings + virtual void MidToYarn(morkEnv* ev, + const morkMid& inMid, // typically an alias to concat with strings mdbYarn* outYarn) = 0; // The parser might ask that some aliases be turned into yarns, so they // can be concatenated into longer blobs under some circumstances. This @@ -350,7 +386,7 @@ public: // out virtual morkParser methods, data flow parser to subclass // mp:RowItem ::= mp:Cell | mp:Meta | OnRowGlitch // mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd // mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch -// mp:Slot ::= OnValue | OnValueAlias | OnRowAlias | OnTableAlias +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid // Note that in interfaces below, mork_change parameters kAdd and kNil @@ -367,12 +403,12 @@ public: // out virtual morkParser methods, data flow parser to subclass virtual void OnGroupAbortEnd(morkEnv* ev, const morkSpan& inSpan) = 0; virtual void OnNewPortRow(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) = 0; + const morkMid& inMid, mork_change inChange) = 0; virtual void OnPortRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0; virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan) = 0; virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) = 0; + const morkMid& inMid, mork_change inChange) = 0; virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0; virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan) = 0; @@ -381,7 +417,7 @@ public: // out virtual morkParser methods, data flow parser to subclass virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan) = 0; virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) = 0; + const morkMid& inMid, mork_change inChange) = 0; virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0; virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan) = 0; @@ -390,12 +426,16 @@ public: // out virtual morkParser methods, data flow parser to subclass virtual void OnDictEnd(morkEnv* ev, const morkSpan& inSpan) = 0; virtual void OnAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) = 0; + const morkMid& inMid) = 0; virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0; virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) = 0; + const morkMid* inMid, const morkBuf* inBuf, mork_change inChange) = 0; + // Exactly one of inMid and inBuf is nil, and the other is non-nil. + // When hex ID syntax is used for a column, then inMid is not nil, and + // when a naked string names a column, then inBuf is not nil. + virtual void OnCellGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0; virtual void OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat) = 0; virtual void OnCellEnd(morkEnv* ev, const morkSpan& inSpan) = 0; @@ -403,29 +443,54 @@ public: // out virtual morkParser methods, data flow parser to subclass virtual void OnValue(morkEnv* ev, const morkSpan& inSpan, const morkBuf& inBuf) = 0; - virtual void OnValueAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) = 0; + virtual void OnValueMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid) = 0; - virtual void OnRowAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) = 0; + virtual void OnRowMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid) = 0; - virtual void OnTableAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) = 0; + virtual void OnTableMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid) = 0; // ````` ````` ````` ````` ````` ````` ````` ````` protected: // protected parser helper methods - void ParseLoop(morkEnv* ev); // find parse continuation and resume - - void StartParse(morkEnv* ev); // prepare for parsing - void StopParse(morkEnv* ev); // terminate parsing & call needed methods + void ParseLoop(morkEnv* ev); // find parse continuation and resume + + void StartParse(morkEnv* ev); // prepare for parsing + void StopParse(morkEnv* ev); // terminate parsing & call needed methods + + int NextChar(morkEnv* ev); // next non-white content + + void OnCellState(morkEnv* ev); + void OnMetaState(morkEnv* ev); + void OnRowState(morkEnv* ev); + void OnTableState(morkEnv* ev); + void OnDictState(morkEnv* ev); + void OnPortState(morkEnv* ev); + void OnStartState(morkEnv* ev); - int NextChar(morkEnv* ev); // next non-white content + void ReadCell(morkEnv* ev); + void ReadRow(morkEnv* ev, int c); + void ReadTable(morkEnv* ev); + void ReadTableMeta(morkEnv* ev); + void ReadDict(morkEnv* ev); + void ReadMeta(morkEnv* ev, int inEndMeta); + void ReadAlias(morkEnv* ev); + mork_id ReadHex(morkEnv* ev, int* outNextChar); + morkBuf* ReadValue(morkEnv* ev); + morkBuf* ReadName(morkEnv* ev, int c); + mork_bool ReadMid(morkEnv* ev, morkMid* outMid); + + void EndSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan); + void StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan); + + int eat_line_break(morkEnv* ev, int inLast); + int eat_line_continue(morkEnv* ev); // last char was '\\' + int eat_comment(morkEnv* ev); // last char was '/' // ````` ````` ````` ````` ````` ````` ````` ````` public: // public non-poly morkParser methods - - void SetParserStream(morkEnv* ev, morkStream* ioStream); mdb_count ParseMore( // return count of bytes consumed now morkEnv* ev, // context diff --git a/db/mork/src/morkRow.cpp b/db/mork/src/morkRow.cpp index 496ba0e569dc..382e15a338ac 100644 --- a/db/mork/src/morkRow.cpp +++ b/db/mork/src/morkRow.cpp @@ -199,6 +199,121 @@ morkRow::AcquireCellHandle(morkEnv* ev, morkCell* ioCell, return (nsIMdbCell*) 0; } +mork_count +morkRow::CountOverlap(morkEnv* ev, morkCell* ioVector, mork_fill inFill) + // Count cells in ioVector that change existing cells in this row when + // ioVector is added to the row (as in TakeCells()). This is the set + // of cells with the same columns in ioVector and mRow_Cells, which do + // not have exactly the same value in mCell_Atom, and which do not both + // have change status equal to morkChange_kCut (because cutting a cut + // cell still yields a cell that has been cut). CountOverlap() also + // modifies the change attribute of any cell in ioVector to kDup when + // the change was previously kCut and the same column cell was found + // in this row with change also equal to kCut; this tells callers later + // they need not look for that cell in the row again on a second pass. +{ + mork_count outCount = 0; + mork_pos pos = 0; // needed by GetCell() + morkCell* cells = ioVector; + morkCell* end = cells + inFill; + --cells; // prepare for preincrement + while ( ++cells < end && ev->Good() ) + { + mork_column col = cells->GetColumn(); + + morkCell* old = this->GetCell(ev, col, &pos); + if ( old ) // same column? + { + mork_change newChg = cells->GetChange(); + mork_change oldChg = old->GetChange(); + if ( newChg != morkChange_kCut || oldChg != newChg ) // not cut+cut? + { + if ( cells->mCell_Atom != old->mCell_Atom ) // not same atom? + ++outCount; // cells will replace old significantly when added + } + else + cells->SetColumnAndChange(col, morkChange_kDup); // note dup status + } + } + return outCount; +} + +void +morkRow::MergeCells(morkEnv* ev, morkCell* ioVector, + mork_fill inVecLength, mork_fill inOldRowFill, mork_fill inOverlap) + // MergeCells() is the part of TakeCells() that does the insertion. + // inOldRowFill is the old value of mRow_Length, and inOverlap is the + // number of cells in the intersection that must be updated. +{ + morkCell* newCells = mRow_Cells + inOldRowFill; // 1st new cell in row + morkCell* newEnd = newCells + mRow_Length; // one past last cell + + morkCell* srcCells = ioVector; + morkCell* srcEnd = srcCells + inVecLength; + + --srcCells; // prepare for preincrement + while ( ++srcCells < srcEnd && ev->Good() ) + { + mork_change srcChg = srcCells->GetChange(); + if ( srcChg != morkChange_kDup ) // anything to be done? + { + morkCell* dstCell = 0; + if ( inOverlap ) + { + mork_pos pos = 0; // needed by GetCell() + dstCell = this->GetCell(ev, srcCells->GetColumn(), &pos); + } + if ( dstCell ) + { + --inOverlap; // one fewer intersections to resolve + // swap the atoms in the cells to avoid ref counting here: + morkAtom* dstAtom = dstCell->mCell_Atom; + *dstCell = *srcCells; // bitwise copy, taking src atom + srcCells->mCell_Atom = dstAtom; // forget cell ref, if any + } + else if ( newCells < newEnd ) // another new cell exists? + { + dstCell = newCells++; // alloc another new cell + // take atom from source cell, transferring ref to this row: + *dstCell = *srcCells; // bitwise copy, taking src atom + srcCells->mCell_Atom = 0; // forget cell ref, if any + } + else // oops, we ran out... + ev->NewError("out of new cells"); + } + } +} + +void +morkRow::TakeCells(morkEnv* ev, morkCell* ioVector, mork_fill inVecLength, + morkStore* ioStore) +{ + if ( ioVector && inVecLength && ev->Good() ) + { + ++mRow_Seed; // intend to change structure of mRow_Cells + mork_pos length = (mork_pos) mRow_Length; + + mork_count overlap = this->CountOverlap(ev, ioVector, inVecLength); + + mork_size growth = inVecLength - overlap; // cells to add + mork_size newLength = length + growth; + + if ( growth && ev->Good() ) // need to add any cells? + { + morkPool* pool = ioStore->StorePool(); + if ( !pool->AddRowCells(ev, this, length + growth) ) + ev->NewError("cannot take cells"); + } + if ( ev->Good() ) + { + if ( mRow_Length >= newLength ) + this->MergeCells(ev, ioVector, inVecLength, length, overlap); + else + ev->NewError("not enough new cells"); + } + } +} + morkCell* morkRow::NewCell(morkEnv* ev, mdb_column inColumn, mork_pos* outPos, morkStore* ioStore) @@ -284,8 +399,7 @@ void morkRow::OnZeroTableUse(morkEnv* ev) // OnZeroTableUse() is called when CutTableUse() returns zero. { - // OK, this is a P1 showstopper bug, so I'll comment it out. -// ev->NewWarning("need to implement OnZeroTableUse"); + // ev->NewWarning("need to implement OnZeroTableUse"); } void diff --git a/db/mork/src/morkRow.h b/db/mork/src/morkRow.h index a4399fc4c1ae..8c6c0cc63374 100644 --- a/db/mork/src/morkRow.h +++ b/db/mork/src/morkRow.h @@ -74,6 +74,27 @@ public: // other row methods public: // internal row methods + mork_count CountOverlap(morkEnv* ev, morkCell* ioVector, mork_fill inFill); + // Count cells in ioVector that change existing cells in this row when + // ioVector is added to the row (as in TakeCells()). This is the set + // of cells with the same columns in ioVector and mRow_Cells, which do + // not have exactly the same value in mCell_Atom, and which do not both + // have change status equal to morkChange_kCut (because cutting a cut + // cell still yields a cell that has been cut). CountOverlap() also + // modifies the change attribute of any cell in ioVector to kDup when + // the change was previously kCut and the same column cell was found + // in this row with change also equal to kCut; this tells callers later + // they need not look for that cell in the row again on a second pass. + + void MergeCells(morkEnv* ev, morkCell* ioVector, + mork_fill inVecLength, mork_fill inOldRowFill, mork_fill inOverlap); + // MergeCells() is the part of TakeCells() that does the insertion. + // inOldRowFill is the old value of mRow_Length, and inOverlap is the + // number of cells in the intersection that must be updated. + + void TakeCells(morkEnv* ev, morkCell* ioVector, mork_fill inVecLength, + morkStore* ioStore); + morkCell* NewCell(morkEnv* ev, mdb_column inColumn, mork_pos* outPos, morkStore* ioStore); morkCell* GetCell(morkEnv* ev, mdb_column inColumn, mork_pos* outPos) const; diff --git a/db/mork/src/morkRowSpace.cpp b/db/mork/src/morkRowSpace.cpp index ff7b3bcc32f1..eeab400f276e 100644 --- a/db/mork/src/morkRowSpace.cpp +++ b/db/mork/src/morkRowSpace.cpp @@ -230,6 +230,37 @@ morkRowSpace::FindTableByKind(morkEnv* ev, mork_kind inTableKind) return (morkTable*) 0; } +morkTable* +morkRowSpace::NewTableWithTid(morkEnv* ev, mork_tid inTid, + mork_kind inTableKind) +{ + morkTable* outTable = 0; + + if ( inTableKind ) + { + mdb_bool mustBeUnique = morkBool_kFalse; + nsIMdbHeap* heap = mSpace_Store->mPort_Heap; + morkTable* table = new(*heap, ev) + morkTable(ev, morkUsage::kHeap, heap, mSpace_Store, heap, this, + inTid, inTableKind, mustBeUnique); + if ( table ) + { + if ( mRowSpace_Tables.AddTable(ev, table) ) + { + outTable = table; + if ( mRowSpace_NextTableId <= inTid ) + mRowSpace_NextTableId = inTid + 1; + } + else + table->CutStrongRef(ev); + } + } + else + this->ZeroKindError(ev); + + return outTable; +} + morkTable* morkRowSpace::NewTable(morkEnv* ev, mork_kind inTableKind, mdb_bool inMustBeUnique) @@ -328,7 +359,12 @@ morkRowSpace::NewRowWithOid(morkEnv* ev, const mdbOid* inOid) row->InitRow(ev, inOid, this, /*length*/ 0, pool); if ( ev->Good() && mRowSpace_Rows.AddRow(ev, row) ) + { outRow = row; + mork_rid rid = inOid->mOid_Id; + if ( mRowSpace_NextRowId <= rid ) + mRowSpace_NextRowId = rid + 1; + } else pool->ZapRow(ev, row); } diff --git a/db/mork/src/morkRowSpace.h b/db/mork/src/morkRowSpace.h index c10e421d6852..b4cb10dfd5f5 100644 --- a/db/mork/src/morkRowSpace.h +++ b/db/mork/src/morkRowSpace.h @@ -115,6 +115,9 @@ public: // other space methods morkTable* NewTable(morkEnv* ev, mork_kind inTableKind, mdb_bool inMustBeUnique); + morkTable* NewTableWithTid(morkEnv* ev, mork_tid inTid, + mork_kind inTableKind); + morkTable* FindTableByKind(morkEnv* ev, mork_kind inTableKind); morkTable* FindTableByTid(morkEnv* ev, mork_tid inTid) { return mRowSpace_Tables.GetTable(ev, inTid); } diff --git a/db/mork/src/morkSink.cpp b/db/mork/src/morkSink.cpp index 6d3c6b2cef4e..d293782da10e 100644 --- a/db/mork/src/morkSink.cpp +++ b/db/mork/src/morkSink.cpp @@ -32,6 +32,10 @@ #include "morkEnv.h" #endif +#ifndef _MORKBLOB_ +#include "morkBlob.h" +#endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 /*virtual*/ morkSink::~morkSink() @@ -41,41 +45,134 @@ } /*virtual*/ void -morkSpoolSink::FlushSink(morkEnv* ev) // probably does nothing +morkSpool::FlushSink(morkEnv* ev) // sync mSpool_Coil->mBuf_Fill { - ev->StubMethodOnlyError(); + morkCoil* coil = mSpool_Coil; + if ( coil ) + { + mork_u1* body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + mork_u1* at = mSink_At; + mork_u1* end = mSink_End; + if ( at >= body && at <= end ) // expected cursor order? + { + mork_fill fill = at - body; // current content size + if ( fill <= coil->mBlob_Size ) + coil->mBuf_Fill = fill; + else + { + coil->BlobFillOverSizeError(ev); + coil->mBuf_Fill = coil->mBlob_Size; // make it safe + } + } + else + this->BadSpoolCursorOrderError(ev); + } + else + coil->NilBufBodyError(ev); + } + else + this->NilSpoolCoilError(ev); } /*virtual*/ void -morkSpoolSink::SpillPutc(morkEnv* ev, int c) // grow spool and write byte +morkSpool::SpillPutc(morkEnv* ev, int c) // grow coil and write byte { - ev->StubMethodOnlyError(); + morkCoil* coil = mSpool_Coil; + if ( coil ) + { + mork_u1* body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + mork_u1* at = mSink_At; + mork_u1* end = mSink_End; + if ( at >= body && at <= end ) // expected cursor order? + { + mork_size size = coil->mBlob_Size; + mork_fill fill = at - body; // current content size + if ( fill <= size ) // less content than medium size? + { + coil->mBuf_Fill = fill; + if ( at >= end ) // need to grow the coil? + { + if ( size > 2048 ) // grow slower over 2K? + size += 512; + else + { + mork_size growth = ( size * 4 ) / 3; // grow by 33% + if ( growth < 64 ) // grow faster under (64 * 3)? + growth = 64; + size += growth; + } + if ( coil->GrowCoil(ev, size) ) // made coil bigger? + { + body = (mork_u1*) coil->mBuf_Body; + if ( body ) // have a coil body? + { + mSink_At = at = body + fill; + mSink_End = end = body + coil->mBlob_Size; + } + else + coil->NilBufBodyError(ev); + } + } + if ( ev->Good() ) // seem ready to write byte c? + { + if ( at < end ) // morkSink::Putc() would succeed? + { + *at++ = c; + mSink_At = at; + coil->mBuf_Fill = fill + 1; + } + else + this->BadSpoolCursorOrderError(ev); + } + } + else // fill exceeds size + { + coil->BlobFillOverSizeError(ev); + coil->mBuf_Fill = coil->mBlob_Size; // make it safe + } + } + else + this->BadSpoolCursorOrderError(ev); + } + else + coil->NilBufBodyError(ev); + } + else + this->NilSpoolCoilError(ev); } // ````` ````` ````` ````` ````` ````` ````` ````` // public: // public non-poly morkSink methods /*virtual*/ -morkSpoolSink::~morkSpoolSink() +morkSpool::~morkSpool() // Zero all slots to show this sink is disabled, but destroy no memory. -// Note it is typically unnecessary to flush this spool sink, since all -// content is written directly to the spool without any buffering. +// Note it is typically unnecessary to flush this coil sink, since all +// content is written directly to the coil without any buffering. { + mSink_At = 0; + mSink_End = 0; + mSpool_Coil = 0; } -morkSpoolSink::morkSpoolSink(morkEnv* ev, morkSpool* ioSpool) -// After installing the spool, calls Seek(ev, 0) to prepare for writing. +morkSpool::morkSpool(morkEnv* ev, morkCoil* ioCoil) +// After installing the coil, calls Seek(ev, 0) to prepare for writing. : morkSink() -, mSpoolSink_Spool( 0 ) +, mSpool_Coil( 0 ) { + mSink_At = 0; // set correctly later in Seek() + mSink_End = 0; // set correctly later in Seek() + if ( ev->Good() ) { - if ( ioSpool ) + if ( ioCoil ) { - // ev->StubMethodOnlyError(); - mSink_At = 0; - mSink_End = 0; - mSpoolSink_Spool = ioSpool; + mSpool_Coil = ioCoil; + this->Seek(ev, /*pos*/ 0); } else ev->NilPointerError(); @@ -84,29 +181,124 @@ morkSpoolSink::morkSpoolSink(morkEnv* ev, morkSpool* ioSpool) // ----- All boolean return values below are equal to ev->Good(): ----- -mork_bool -morkSpoolSink::Seek(morkEnv* ev, mork_pos inPos) -// Changed the current write position in spool's buffer to inPos. -// For example, to start writing the spool from scratch, use inPos==0. +/*static*/ void +morkSpool::BadSpoolCursorOrderError(morkEnv* ev) { - ev->StubMethodOnlyError(); + ev->NewError("bad morkSpool cursor order"); +} + +/*static*/ void +morkSpool::NilSpoolCoilError(morkEnv* ev) +{ + ev->NewError("nil mSpool_Coil"); +} + +mork_bool +morkSpool::Seek(morkEnv* ev, mork_pos inPos) +// Changed the current write position in coil's buffer to inPos. +// For example, to start writing the coil from scratch, use inPos==0. +{ + morkCoil* coil = mSpool_Coil; + if ( coil ) + { + mork_size minSize = inPos + 64; + + if ( coil->mBlob_Size < minSize ) + coil->GrowCoil(ev, minSize); + + if ( ev->Good() ) + { + coil->mBuf_Fill = inPos; + mork_u1* body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + mSink_At = body + inPos; + mSink_End = body + coil->mBlob_Size; + } + else + coil->NilBufBodyError(ev); + } + } + else + this->NilSpoolCoilError(ev); + return ev->Good(); } mork_bool -morkSpoolSink::Write(morkEnv* ev, const void* inBuf, mork_size inSize) -// write inSize bytes of inBuf to current position inside spool's buffer +morkSpool::Write(morkEnv* ev, const void* inBuf, mork_size inSize) +// write inSize bytes of inBuf to current position inside coil's buffer { - ev->StubMethodOnlyError(); + // This method is conceptually very similar to morkStream::Write(), + // and this code was written while looking at that method for clues. + + morkCoil* coil = mSpool_Coil; + if ( coil ) + { + mork_u1* body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + if ( inBuf && inSize ) // anything to write? + { + mork_u1* at = mSink_At; + mork_u1* end = mSink_End; + if ( at >= body && at <= end ) // expected cursor order? + { + // note coil->mBuf_Fill can be stale after morkSink::Putc(): + mork_pos fill = at - body; // current content size + mork_num space = end - at; // space left in body + if ( space < inSize ) // not enough to hold write? + { + mork_size minGrowth = space + 16; + mork_size minSize = coil->mBlob_Size + minGrowth; + if ( coil->GrowCoil(ev, minSize) ) + { + body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + mSink_At = at = body + fill; + mSink_End = end = body + coil->mBlob_Size; + space = end - at; // space left in body + } + else + coil->NilBufBodyError(ev); + } + } + if ( ev->Good() ) + { + if ( space >= inSize ) // enough room to hold write? + { + MORK_MEMCPY(at, inBuf, inSize); // into body + mSink_At = at + inSize; // advance past written bytes + coil->mBuf_Fill = fill + inSize; // "flush" to fix fill + } + else + ev->NewError("insufficient morkSpool space"); + } + } + else + this->BadSpoolCursorOrderError(ev); + } + } + else + coil->NilBufBodyError(ev); + } + else + this->NilSpoolCoilError(ev); + return ev->Good(); } mork_bool -morkSpoolSink::PutString(morkEnv* ev, const char* inString) +morkSpool::PutString(morkEnv* ev, const char* inString) // call Write() with inBuf=inString and inSize=strlen(inString), // unless inString is null, in which case we then do nothing at all. { - ev->StubMethodOnlyError(); + if ( inString ) + { + mork_size size = MORK_STRLEN(inString); + this->Write(ev, inString, size); + } return ev->Good(); } diff --git a/db/mork/src/morkSink.h b/db/mork/src/morkSink.h index 10b6eddfb00d..79b349c3c074 100644 --- a/db/mork/src/morkSink.h +++ b/db/mork/src/morkSink.h @@ -114,47 +114,52 @@ public: // public non-poly morkSink methods } }; -/*| morkSpoolSink: an output sink that efficiently writes individual bytes -**| or entire byte sequences to a spool instance, which grows as needed by -**| using the heap instance in the spool to grow the internal buffer. +/*| morkSpool: an output sink that efficiently writes individual bytes +**| or entire byte sequences to a coil instance, which grows as needed by +**| using the heap instance in the coil to grow the internal buffer. **| -**|| Note we do not "own" the spool referenced by mSpoolSink_Spool, and -**| the lifetime of the spool is expected to equal or exceed that of this +**|| Note we do not "own" the coil referenced by mSpool_Coil, and +**| the lifetime of the coil is expected to equal or exceed that of this **| sink by some external means. Typical usage might involve keeping an -**| instance of morkSpool and an instance of morkSpoolSink in the same -**| owning parent object, which uses the sink with the associated spool. +**| instance of morkCoil and an instance of morkSpool in the same +**| owning parent object, which uses the spool with the associated coil. |*/ -class morkSpoolSink : public morkSink { // for buffered i/o to a morkSpool +class morkSpool : public morkSink { // for buffered i/o to a morkCoil // ````` ````` ````` ````` ````` ````` ````` ````` public: // public sink virtual methods - virtual void FlushSink(morkEnv* ev); // probably does nothing - virtual void SpillPutc(morkEnv* ev, int c); // grow spool and write byte + // when morkSink::Putc() moves mSink_At, mSpool_Coil->mBuf_Fill is wrong: + + virtual void FlushSink(morkEnv* ev); // sync mSpool_Coil->mBuf_Fill + virtual void SpillPutc(morkEnv* ev, int c); // grow coil and write byte // ````` ````` ````` ````` ````` ````` ````` ````` public: // member variables - morkSpool* mSpoolSink_Spool; // destination medium for written bytes + morkCoil* mSpool_Coil; // destination medium for written bytes // ````` ````` ````` ````` ````` ````` ````` ````` public: // public non-poly morkSink methods - virtual ~morkSpoolSink(); + static void BadSpoolCursorOrderError(morkEnv* ev); + static void NilSpoolCoilError(morkEnv* ev); + + virtual ~morkSpool(); // Zero all slots to show this sink is disabled, but destroy no memory. - // Note it is typically unnecessary to flush this spool sink, since all - // content is written directly to the spool without any buffering. + // Note it is typically unnecessary to flush this coil sink, since all + // content is written directly to the coil without any buffering. - morkSpoolSink(morkEnv* ev, morkSpool* ioSpool); - // After installing the spool, calls Seek(ev, 0) to prepare for writing. + morkSpool(morkEnv* ev, morkCoil* ioCoil); + // After installing the coil, calls Seek(ev, 0) to prepare for writing. // ----- All boolean return values below are equal to ev->Good(): ----- mork_bool Seek(morkEnv* ev, mork_pos inPos); - // Changed the current write position in spool's buffer to inPos. - // For example, to start writing the spool from scratch, use inPos==0. + // Changed the current write position in coil's buffer to inPos. + // For example, to start writing the coil from scratch, use inPos==0. mork_bool Write(morkEnv* ev, const void* inBuf, mork_size inSize); - // write inSize bytes of inBuf to current position inside spool's buffer + // write inSize bytes of inBuf to current position inside coil's buffer mork_bool PutBuf(morkEnv* ev, const morkBuf& inBuffer) { return this->Write(ev, inBuffer.mBuf_Body, inBuffer.mBuf_Fill); } diff --git a/db/mork/src/morkStore.cpp b/db/mork/src/morkStore.cpp index de6a39710bf8..d7ee71db987d 100644 --- a/db/mork/src/morkStore.cpp +++ b/db/mork/src/morkStore.cpp @@ -92,6 +92,10 @@ #include "morkRowMap.h" #endif +#ifndef _MORKPARSER_ +#include "morkParser.h" +#endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 // ````` ````` ````` ````` ````` @@ -212,6 +216,15 @@ morkStore::morkStore(morkEnv* ev, const morkUsage& inUsage, , mStore_OidAtomSpace( 0 ) , mStore_GroundAtomSpace( 0 ) , mStore_GroundColumnSpace( 0 ) + +, mStore_MorkNoneToken( 0 ) +, mStore_CharsetToken( 0 ) +, mStore_AtomScopeToken( 0 ) +, mStore_RowScopeToken( 0 ) +, mStore_TableScopeToken( 0 ) +, mStore_ColumnScopeToken( 0 ) +, mStore_TableKindToken( 0 ) + , mStore_RowSpaces(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap) , mStore_AtomSpaces(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap) , mStore_Pool(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap) @@ -220,6 +233,9 @@ morkStore::morkStore(morkEnv* ev, const morkUsage& inUsage, { mNode_Derived = morkDerived_kStore; + if ( ev->Good() ) + mStore_MorkNoneToken = this->StringToToken(ev, "mork:none"); + if ( ev->Good() ) mStore_CharsetToken = this->StringToToken(ev, "charset"); @@ -302,6 +318,28 @@ morkStore::AcquireStoreHandle(morkEnv* ev) } +morkMaxBookAtom* +morkStore::StageAliasAsBookAtom(morkEnv* ev, const morkMid* inMid, + morkAtomSpace* ioSpace, mork_cscode inForm) +{ + if ( inMid && inMid->mMid_Buf ) + { + const morkBuf* buf = inMid->mMid_Buf; + mork_size length = buf->mBuf_Fill; + if ( length <= morkBookAtom_kMaxBodySize ) + { + mork_aid dummyAid = 1; + mStore_BookAtom.InitMaxBookAtom(ev, *buf, + inForm, ioSpace, dummyAid); + return &mStore_BookAtom; + } + } + else + ev->NilPointerError(); + + return (morkMaxBookAtom*) 0; +} + morkMaxBookAtom* morkStore::StageYarnAsBookAtom(morkEnv* ev, const mdbYarn* inYarn, morkAtomSpace* ioSpace) @@ -436,6 +474,15 @@ morkStream* morkStore::LazyGetOutStream(morkEnv* ev) return mStore_OutStream; } +void +morkStore::ForgetBuilder(morkEnv* ev) +{ + if ( mStore_Builder ) + morkBuilder::SlotStrongBuilder((morkBuilder*) 0, ev, &mStore_Builder); + if ( mStore_InStream ) + morkStream::SlotStrongStream((morkStream*) 0, ev, &mStore_InStream); +} + morkBuilder* morkStore::LazyGetBuilder(morkEnv* ev) { if ( !mStore_Builder ) @@ -556,7 +603,7 @@ morkStore::CreateStoreFile(morkEnv* ev, } return ev->Good(); } - + morkAtom* morkStore::YarnToAtom(morkEnv* ev, const mdbYarn* inYarn) { @@ -586,10 +633,125 @@ morkStore::YarnToAtom(morkEnv* ev, const mdbYarn* inYarn) return outAtom; } -// mork_bool -// morkStore::CutBookAtom(morkEnv* ev, morkBookAtom* ioAtom) -// { -// } +mork_bool +morkStore::MidToOid(morkEnv* ev, const morkMid& inMid, mdbOid* outOid) +{ + *outOid = inMid.mMid_Oid; + const morkBuf* buf = inMid.mMid_Buf; + if ( buf && !outOid->mOid_Scope ) + { + mdbOid oid = inMid.mMid_Oid; + if ( buf->mBuf_Fill <= morkBookAtom_kMaxBodySize ) + { + if ( buf->mBuf_Fill == 1 ) + { + mork_u1* name = (mork_u1*) buf->mBuf_Body; + if ( name ) + { + outOid->mOid_Scope = (mork_scope) *name; + return ev->Good(); + } + } + morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev); + if ( groundSpace ) + { + mork_cscode form = 0; // default + mork_aid aid = 1; // dummy + mStore_BookAtom.InitMaxBookAtom(ev, *buf, form, groundSpace, aid); + morkMaxBookAtom* keyAtom = &mStore_BookAtom; + morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies; + morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom); + if ( bookAtom ) + outOid->mOid_Scope = bookAtom->mBookAtom_Id; + else + { + bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom); + if ( bookAtom ) + { + outOid->mOid_Scope = bookAtom->mBookAtom_Id; + bookAtom->MakeCellUseForever(ev); + } + } + } + } + } + return ev->Good(); +} + +morkRow* +morkStore::MidToRow(morkEnv* ev, const morkMid& inMid) +{ + mdbOid tempOid; + this->MidToOid(ev, inMid, &tempOid); + return this->OidToRow(ev, &tempOid); +} + +morkTable* +morkStore::MidToTable(morkEnv* ev, const morkMid& inMid) +{ + mdbOid tempOid; + this->MidToOid(ev, inMid, &tempOid); + return this->OidToTable(ev, &tempOid); +} + +mork_bool +morkStore::MidToYarn(morkEnv* ev, const morkMid& inMid, mdbYarn* outYarn) +{ + mdbOid tempOid; + this->MidToOid(ev, inMid, &tempOid); + return this->OidToYarn(ev, tempOid, outYarn); +} + +mork_bool +morkStore::OidToYarn(morkEnv* ev, const mdbOid& inOid, mdbYarn* outYarn) +{ + morkBookAtom* atom = 0; + + morkAtomSpace* atomSpace = mStore_AtomSpaces.GetAtomSpace(ev, inOid.mOid_Scope); + if ( atomSpace ) + { + morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids; + atom = map->GetAid(ev, (mork_aid) inOid.mOid_Id); + } + atom->GetYarn(outYarn); // note this is safe even when atom==nil + + return ev->Good(); +} + +morkBookAtom* +morkStore::MidToAtom(morkEnv* ev, const morkMid& inMid) +{ + morkBookAtom* outAtom = 0; + mdbOid oid; + if ( this->MidToOid(ev, inMid, &oid) ) + { + morkAtomSpace* atomSpace = mStore_AtomSpaces.GetAtomSpace(ev, oid.mOid_Scope); + if ( atomSpace ) + { + morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids; + outAtom = map->GetAid(ev, (mork_aid) oid.mOid_Id); + } + } + return outAtom; +} + +/*static*/ void +morkStore::SmallTokenToOneByteYarn(morkEnv* ev, mdb_token inToken, + mdbYarn* outYarn) +{ + if ( outYarn->mYarn_Buf && outYarn->mYarn_Size ) // any space in yarn at all? + { + mork_u1* buf = (mork_u1*) outYarn->mYarn_Buf; // for byte arithmetic + buf[ 0 ] = (mork_u1) inToken; // write the single byte + outYarn->mYarn_Fill = 1; + outYarn->mYarn_More = 0; + } + else // just record we could not write the single byte + { + outYarn->mYarn_More = 1; + outYarn->mYarn_Fill = 0; + } +} void morkStore::TokenToString(morkEnv* ev, mdb_token inToken, mdbYarn* outTokenName) @@ -604,23 +766,161 @@ morkStore::TokenToString(morkEnv* ev, mdb_token inToken, mdbYarn* outTokenName) atom->GetYarn(outTokenName); // note this is safe even when atom==nil } else // token is an "immediate" single byte string representation? + this->SmallTokenToOneByteYarn(ev, inToken, outTokenName); +} + +void +morkStore::SyncTokenIdChange(morkEnv* ev, const morkBookAtom* inAtom, + const mdbOid* inOid) +{ +// mork_token mStore_MorkNoneToken; // token for "mork:none" // fill=9 +// mork_column mStore_CharsetToken; // token for "charset" // fill=7 +// mork_column mStore_AtomScopeToken; // token for "atomScope" // fill=9 +// mork_column mStore_RowScopeToken; // token for "rowScope" // fill=8 +// mork_column mStore_TableScopeToken; // token for "tableScope" // fill=10 +// mork_column mStore_ColumnScopeToken; // token for "columnScope" // fill=11 +// mork_kind mStore_TableKindToken; // token for "tableKind" // fill=9 +// ---------------------ruler-for-token-length-above---123456789012 + + if ( inOid->mOid_Scope == morkStore_kColumnSpaceScope && inAtom->IsWeeBook() ) { - mdbYarn* y = outTokenName; - if ( y->mYarn_Buf && y->mYarn_Size ) // any space in yarn at all? + const mork_u1* body = ((const morkWeeBookAtom*) inAtom)->mWeeBookAtom_Body; + mork_size size = inAtom->mAtom_Size; + + if ( size >= 7 && size <= 11 ) { - mork_u1* buf = (mork_u1*) y->mYarn_Buf; // for byte arithmetic - buf[ 0 ] = (mork_u1) inToken; // write the single byte - y->mYarn_Fill = 1; - y->mYarn_More = 0; - } - else // just record we could not write the single byte - { - y->mYarn_More = 1; - y->mYarn_Fill = 0; + if ( size == 9 ) + { + if ( *body == 'm' ) + { + if ( MORK_MEMCMP(body, "mork:none", 9) == 0 ) + mStore_MorkNoneToken = inAtom->mBookAtom_Id; + } + else if ( *body == 'a' ) + { + if ( MORK_MEMCMP(body, "atomScope", 9) == 0 ) + mStore_AtomScopeToken = inAtom->mBookAtom_Id; + } + else if ( *body == 't' ) + { + if ( MORK_MEMCMP(body, "tableKind", 9) == 0 ) + mStore_TableKindToken = inAtom->mBookAtom_Id; + } + } + else if ( size == 7 && *body == 'c' ) + { + if ( MORK_MEMCMP(body, "charset", 7) == 0 ) + mStore_CharsetToken = inAtom->mBookAtom_Id; + } + else if ( size == 8 && *body == 'r' ) + { + if ( MORK_MEMCMP(body, "rowScope", 8) == 0 ) + mStore_RowScopeToken = inAtom->mBookAtom_Id; + } + else if ( size == 10 && *body == 't' ) + { + if ( MORK_MEMCMP(body, "tableScope", 10) == 0 ) + mStore_TableScopeToken = inAtom->mBookAtom_Id; + } + else if ( size == 11 && *body == 'c' ) + { + if ( MORK_MEMCMP(body, "columnScope", 11) == 0 ) + mStore_ColumnScopeToken = inAtom->mBookAtom_Id; + } } } } +morkAtom* +morkStore::AddAlias(morkEnv* ev, const morkMid& inMid, mork_cscode inForm) +{ + morkBookAtom* outAtom = 0; + if ( ev->Good() ) + { + const mdbOid* oid = &inMid.mMid_Oid; + morkAtomSpace* atomSpace = this->LazyGetAtomSpace(ev, oid->mOid_Scope); + if ( atomSpace ) + { + morkMaxBookAtom* keyAtom = + this->StageAliasAsBookAtom(ev, &inMid, atomSpace, inForm); + if ( keyAtom ) + { + morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids; + outAtom = map->GetAid(ev, (mork_aid) oid->mOid_Id); + if ( outAtom ) + { + if ( !outAtom->EqualFormAndBody(ev, keyAtom) ) + ev->NewError("duplicate alias ID"); + } + else + { + keyAtom->mBookAtom_Id = oid->mOid_Id; + outAtom = atomSpace->MakeBookAtomCopyWithAid(ev, + *keyAtom, (mork_aid) oid->mOid_Id); + + if ( outAtom && outAtom->IsWeeBook() ) + { + if ( oid->mOid_Scope == morkStore_kColumnSpaceScope ) + { + mork_size size = outAtom->mAtom_Size; + if ( size >= 7 && size <= 11 ) + this->SyncTokenIdChange(ev, outAtom, oid); + } + } + } + } + } + } + return outAtom; +} + +mork_token +morkStore::BufToToken(morkEnv* ev, const morkBuf* inBuf) +{ + mork_token outToken = 0; + if ( ev->Good() ) + { + const mork_u1* s = (const mork_u1*) inBuf->mBuf_Body; + mork_bool nonAscii = ( *s > 0x7F ); + mork_size length = inBuf->mBuf_Fill; + if ( nonAscii || length > 1 ) // more than one byte? + { + mork_cscode form = 0; // default charset + morkAtomSpace* space = this->LazyGetGroundColumnSpace(ev); + if ( space ) + { + morkMaxBookAtom* keyAtom = 0; + if ( length <= morkBookAtom_kMaxBodySize ) + { + mork_aid aid = 1; // dummy + mStore_BookAtom.InitMaxBookAtom(ev, *inBuf, form, space, aid); + keyAtom = &mStore_BookAtom; + } + if ( keyAtom ) + { + morkAtomBodyMap* map = &space->mAtomSpace_AtomBodies; + morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom); + if ( bookAtom ) + outToken = bookAtom->mBookAtom_Id; + else + { + bookAtom = space->MakeBookAtomCopy(ev, *keyAtom); + if ( bookAtom ) + { + outToken = bookAtom->mBookAtom_Id; + bookAtom->MakeCellUseForever(ev); + } + } + } + } + } + else // only a single byte in inTokenName string: + outToken = *s; + } + + return outToken; +} + mork_token morkStore::StringToToken(morkEnv* ev, const char* inTokenName) { @@ -702,6 +1002,8 @@ morkStore::HasTableKind(morkEnv* ev, mdb_scope inRowScope, mdb_kind inTableKind, mdb_count* outTableCount) { mork_bool outBool = morkBool_kFalse; + + ev->StubMethodOnlyError(); return outBool; } @@ -789,6 +1091,19 @@ morkStore::GetPortTableCursor(morkEnv* ev, mdb_scope inRowScope, return outCursor; } +morkRow* +morkStore::NewRow(morkEnv* ev, mdb_scope inRowScope) +{ + morkRow* outRow = 0; + if ( ev->Good() ) + { + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope); + if ( rowSpace ) + outRow = rowSpace->NewRow(ev); + } + return outRow; +} + morkRow* morkStore::NewRowWithOid(morkEnv* ev, const mdbOid* inOid) { @@ -803,16 +1118,42 @@ morkStore::NewRowWithOid(morkEnv* ev, const mdbOid* inOid) } morkRow* -morkStore::NewRow(morkEnv* ev, mdb_scope inRowScope) +morkStore::OidToRow(morkEnv* ev, const mdbOid* inOid) + // OidToRow() finds old row with oid, or makes new one if not found. { morkRow* outRow = 0; if ( ev->Good() ) { - morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope); + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope); if ( rowSpace ) - outRow = rowSpace->NewRow(ev); + { + outRow = rowSpace->mRowSpace_Rows.GetOid(ev, inOid); + if ( !outRow && ev->Good() ) + outRow = rowSpace->NewRowWithOid(ev, inOid); + } } return outRow; } +morkTable* +morkStore::OidToTable(morkEnv* ev, const mdbOid* inOid) + // OidToTable() finds old table with oid, or makes new one if not found. +{ + morkTable* outTable = 0; + if ( ev->Good() ) + { + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope); + if ( rowSpace ) + { + outTable = rowSpace->mRowSpace_Tables.GetTable(ev, inOid->mOid_Id); + if ( !outTable && ev->Good() ) + { + mork_kind tableKind = mStore_MorkNoneToken; + outTable = rowSpace->NewTableWithTid(ev, inOid->mOid_Id, tableKind); + } + } + } + return outTable; +} + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 diff --git a/db/mork/src/morkStore.h b/db/mork/src/morkStore.h index 2edbac96be3c..4c4c4d22610d 100644 --- a/db/mork/src/morkStore.h +++ b/db/mork/src/morkStore.h @@ -115,6 +115,7 @@ public: // typesafe refcounting inlines calling inherited morkNode methods **| all other explicitly tokenized strings. |*/ #define morkStore_kGroundColumnSpace 'c' /* for mStore_GroundColumnSpace*/ +#define morkStore_kColumnSpaceScope ((mork_scope) 'c') /*kGroundColumnSpace*/ #define morkStore_kGroundAtomSpace 'a' /* for mStore_GroundAtomSpace*/ #define morkStore_kStreamBufSize (8 * 1024) /* okay buffer size */ @@ -150,6 +151,7 @@ public: // state is public because the entire Mork system is private morkStream* mStore_OutStream; // stream using file used by the writer + mork_token mStore_MorkNoneToken; // token for "mork:none" mork_column mStore_CharsetToken; // token for "charset" mork_column mStore_AtomScopeToken; // token for "atomScope" mork_column mStore_RowScopeToken; // token for "rowScope" @@ -164,9 +166,17 @@ public: // state is public because the entire Mork system is private // we alloc a max size book atom to reuse space for atom map key searches: morkMaxBookAtom mStore_BookAtom; // staging area for atom map searches + +public: // coping with any changes to store token slots above: + + void SyncTokenIdChange(morkEnv* ev, const morkBookAtom* inAtom, + const mdbOid* inOid); public: // building an atom inside mStore_BookAtom from a char* string + morkMaxBookAtom* StageAliasAsBookAtom(morkEnv* ev, + const morkMid* inMid, morkAtomSpace* ioSpace, mork_cscode inForm); + morkMaxBookAtom* StageYarnAsBookAtom(morkEnv* ev, const mdbYarn* inYarn, morkAtomSpace* ioSpace); @@ -186,6 +196,7 @@ public: // lazy creation of members and nested row or atom spaces morkStream* LazyGetInStream(morkEnv* ev); morkBuilder* LazyGetBuilder(morkEnv* ev); + void ForgetBuilder(morkEnv* ev); morkStream* LazyGetOutStream(morkEnv* ev); @@ -221,6 +232,8 @@ public: // typing public: // store utilties morkAtom* YarnToAtom(morkEnv* ev, const mdbYarn* inYarn); + morkAtom* AddAlias(morkEnv* ev, const morkMid& inMid, + mork_cscode inForm); public: // other store methods @@ -239,11 +252,30 @@ public: // other store methods const char* inFilePath, const mdbOpenPolicy* inOpenPolicy); - // mork_bool CutBookAtom(morkEnv* ev, morkBookAtom* ioAtom); + mork_token BufToToken(morkEnv* ev, const morkBuf* inBuf); mork_token StringToToken(morkEnv* ev, const char* inTokenName); mork_token QueryToken(morkEnv* ev, const char* inTokenName); void TokenToString(morkEnv* ev, mdb_token inToken, mdbYarn* outTokenName); + mork_bool MidToOid(morkEnv* ev, const morkMid& inMid, + mdbOid* outOid); + mork_bool OidToYarn(morkEnv* ev, const mdbOid& inOid, mdbYarn* outYarn); + mork_bool MidToYarn(morkEnv* ev, const morkMid& inMid, + mdbYarn* outYarn); + + morkBookAtom* MidToAtom(morkEnv* ev, const morkMid& inMid); + morkRow* MidToRow(morkEnv* ev, const morkMid& inMid); + morkTable* MidToTable(morkEnv* ev, const morkMid& inMid); + + morkRow* OidToRow(morkEnv* ev, const mdbOid* inOid); + // OidToRow() finds old row with oid, or makes new one if not found. + + morkTable* OidToTable(morkEnv* ev, const mdbOid* inOid); + // OidToTable() finds old table with oid, or makes new one if not found. + + static void SmallTokenToOneByteYarn(morkEnv* ev, mdb_token inToken, + mdbYarn* outYarn); + mork_bool HasTableKind(morkEnv* ev, mdb_scope inRowScope, mdb_kind inTableKind, mdb_count* outTableCount); diff --git a/db/mork/src/morkStream.cpp b/db/mork/src/morkStream.cpp index e7d33fe4239e..6855235ad22e 100644 --- a/db/mork/src/morkStream.cpp +++ b/db/mork/src/morkStream.cpp @@ -75,7 +75,7 @@ morkStream::morkStream(morkEnv* ev, const morkUsage& inUsage, , mStream_ContentFile( 0 ) , mStream_Buf( 0 ) -, mStream_BufSize( 0 ) +, mStream_BufSize( inBufSize ) , mStream_BufPos( 0 ) , mStream_Dirty( morkBool_kFalse ) , mStream_HitEof( morkBool_kFalse ) @@ -329,7 +329,7 @@ morkStream::PutByteThenNewlineThenSpace(morkEnv* ev, int inByte) mork_size morkStream::PutLineBreak(morkEnv* ev) { -#ifdef MORK_MAC +#if defined(MORK_MAC) || defined(MORK_OBSOLETE) this->Putc(ev, mork_kCR); return 1; diff --git a/db/mork/src/morkStream.h b/db/mork/src/morkStream.h index 464383fcef3f..1285f33ad0e3 100644 --- a/db/mork/src/morkStream.h +++ b/db/mork/src/morkStream.h @@ -212,6 +212,7 @@ public: // public non-poly morkStream methods void Ungetc(int c) /*i*/ { if ( mStream_At > mStream_Buf && c > 0 ) *--mStream_At = c; } + // Note Getc() returns EOF consistently after any fill_getc() error occurs. int Getc(morkEnv* ev) /*i*/ { return ( mStream_At < mStream_ReadEnd )? *mStream_At++ : fill_getc(ev); } diff --git a/db/mork/src/morkTable.cpp b/db/mork/src/morkTable.cpp index 8ecc8b9ef9ca..f507d09efc6d 100644 --- a/db/mork/src/morkTable.cpp +++ b/db/mork/src/morkTable.cpp @@ -147,6 +147,35 @@ morkTable::CloseTable(morkEnv* ev) /*i*/ // called by CloseMorkNode(); // } ===== end morkNode methods ===== // ````` ````` ````` ````` ````` +mork_u2 +morkTable::AddCellUse(morkEnv* ev) +{ + if ( mTable_CellUses < morkTable_kMaxCellUses ) // not already maxed out? + ++mTable_CellUses; + + return mTable_CellUses; +} + +mork_u2 +morkTable::CutCellUse(morkEnv* ev) +{ + if ( mTable_CellUses ) // any outstanding uses to cut? + { + if ( mTable_CellUses < morkTable_kMaxCellUses ) // not frozen at max? + --mTable_CellUses; + } + else + this->CellUsesUnderflowWarning(ev); + + return mTable_CellUses; +} + +/*static*/ void +morkTable::CellUsesUnderflowWarning(morkEnv* ev) +{ + ev->NewWarning("mTable_CellUses underflow"); +} + /*static*/ void morkTable::NonTableTypeError(morkEnv* ev) { diff --git a/db/mork/src/morkTable.h b/db/mork/src/morkTable.h index 4a4291e33e4b..492816e89446 100644 --- a/db/mork/src/morkTable.h +++ b/db/mork/src/morkTable.h @@ -51,6 +51,7 @@ class nsIMdbTable; #define morkTable_kStartRowArraySize 11 /* modest starting size for array */ #define morkTable_kStartRowMapSlotCount 128 +#define morkTable_kMaxCellUses 0x0FFFF /* max for 16-bit unsigned int */ class morkTable : public morkObject { @@ -85,7 +86,8 @@ public: // state is public because the entire Mork system is private mork_kind mTable_Kind; mork_bool mTable_MustBeUnique; - mork_u1 mTable_Pad[ 3 ]; // padding to u4 alignment + mork_u1 mTable_Pad; // padding for u4 alignment + mork_u2 mTable_CellUses; // persistent references from cells // { ===== begin morkNode interface ===== public: // morkNode virtual methods @@ -109,12 +111,18 @@ public: // dynamic type identification { return IsNode() && mNode_Derived == morkDerived_kTable; } // } ===== end morkNode methods ===== -public: // typing +public: // errors static void NonTableTypeError(morkEnv* ev); static void NonTableTypeWarning(morkEnv* ev); static void NilRowSpaceError(morkEnv* ev); +public: // warnings + static void CellUsesUnderflowWarning(morkEnv* ev); + public: // other table methods + + mork_u2 AddCellUse(morkEnv* ev); + mork_u2 CutCellUse(morkEnv* ev); // void DirtyAllTableContent(morkEnv* ev); @@ -137,7 +145,7 @@ public: // typesafe refcounting inlines calling inherited morkNode methods morkEnv* ev, morkTable** ioSlot) { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); } - static void SlotStrongTableS(morkTable* me, + static void SlotStrongTable(morkTable* me, morkEnv* ev, morkTable** ioSlot) { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); } }; diff --git a/db/mork/src/morkThumb.cpp b/db/mork/src/morkThumb.cpp index 9044930833f4..d50be5bfadbc 100644 --- a/db/mork/src/morkThumb.cpp +++ b/db/mork/src/morkThumb.cpp @@ -52,6 +52,18 @@ #include "morkWriter.h" #endif +#ifndef _MORKPARSER_ +#include "morkParser.h" +#endif + +#ifndef _MORKBUILDER_ +#include "morkBuilder.h" +#endif + +#ifndef _MORKFILE_ +#include "morkFile.h" +#endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 // ````` ````` ````` ````` ````` @@ -92,6 +104,7 @@ morkThumb::morkThumb(morkEnv* ev, , mThumb_Store( 0 ) , mThumb_File( 0 ) , mThumb_Writer( 0 ) +, mThumb_Builder( 0 ) , mThumb_SourcePort( 0 ) , mThumb_DoCollect( morkBool_kFalse ) @@ -111,9 +124,13 @@ morkThumb::CloseThumb(morkEnv* ev) // called by CloseMorkNode(); if ( this->IsNode() ) { mThumb_Magic = 0; + if ( mThumb_Builder && mThumb_Store ) + mThumb_Store->ForgetBuilder(ev); + morkBuilder::SlotStrongBuilder((morkBuilder*) 0, ev, &mThumb_Builder); + morkWriter::SlotStrongWriter((morkWriter*) 0, ev, &mThumb_Writer); morkFile::SlotStrongFile((morkFile*) 0, ev, &mThumb_File); - morkStore::SlotWeakStore((morkStore*) 0, ev, &mThumb_Store); + morkStore::SlotStrongStore((morkStore*) 0, ev, &mThumb_Store); morkPort::SlotStrongPort((morkPort*) 0, ev, &mThumb_SourcePort); this->MarkShut(); } @@ -152,6 +169,11 @@ morkThumb::CloseThumb(morkEnv* ev) // called by CloseMorkNode(); ev->NewError("nil mThumb_Writer"); } +/*static*/ void morkThumb::NilThumbBuilderError(morkEnv* ev) +{ + ev->NewError("nil mThumb_Builder"); +} + /*static*/ void morkThumb::NilThumbSourcePortError(morkEnv* ev) { ev->NewError("nil mThumb_SourcePort"); @@ -181,14 +203,31 @@ morkThumb::Make_OpenFileStore(morkEnv* ev, nsIMdbHeap* ioHeap, morkThumb* outThumb = 0; if ( ioHeap && ioStore ) { - outThumb = new(*ioHeap, ev) - morkThumb(ev, morkUsage::kHeap, ioHeap, ioHeap, - morkThumb_kMagic_OpenFileStore); - - if ( outThumb ) + morkFile* file = ioStore->mStore_File; + if ( file ) { - morkStore::SlotWeakStore(ioStore, ev, &outThumb->mThumb_Store); + mork_pos fileEof = file->Length(ev); + if ( ev->Good() ) + { + outThumb = new(*ioHeap, ev) + morkThumb(ev, morkUsage::kHeap, ioHeap, ioHeap, + morkThumb_kMagic_OpenFileStore); + + if ( outThumb ) + { + morkBuilder* builder = ioStore->LazyGetBuilder(ev); + if ( builder ) + { + outThumb->mThumb_Total = fileEof; + morkStore::SlotStrongStore(ioStore, ev, &outThumb->mThumb_Store); + morkBuilder::SlotStrongBuilder(builder, ev, + &outThumb->mThumb_Builder); + } + } + } } + else + ioStore->NilStoreFileError(ev); } else ev->NilPointerError(); @@ -219,7 +258,7 @@ morkThumb::Make_CompressCommit(morkEnv* ev, { writer->mWriter_NeedDirtyAll = morkBool_kTrue; outThumb->mThumb_DoCollect = inDoCollect; - morkStore::SlotWeakStore(ioStore, ev, &outThumb->mThumb_Store); + morkStore::SlotStrongStore(ioStore, ev, &outThumb->mThumb_Store); morkFile::SlotStrongFile(file, ev, &outThumb->mThumb_File); morkWriter::SlotStrongWriter(writer, ev, &outThumb->mThumb_Writer); } @@ -330,7 +369,21 @@ void morkThumb::DoMore_OpenFilePort(morkEnv* ev) void morkThumb::DoMore_OpenFileStore(morkEnv* ev) { - this->UnsupportedThumbMagicError(ev); + morkBuilder* builder = mThumb_Builder; + if ( builder ) + { + mork_pos pos = 0; + builder->ParseMore(ev, &pos, &mThumb_Done, &mThumb_Broken); + // mThumb_Total = builder->mBuilder_TotalCount; + // mThumb_Current = builder->mBuilder_DoneCount; + mThumb_Current = pos; + } + else + { + this->NilThumbBuilderError(ev); + mThumb_Broken = morkBool_kTrue; + mThumb_Done = morkBool_kTrue; + } } void morkThumb::DoMore_ExportToFormat(morkEnv* ev) diff --git a/db/mork/src/morkThumb.h b/db/mork/src/morkThumb.h index 39a78515c598..5c034728ff4d 100644 --- a/db/mork/src/morkThumb.h +++ b/db/mork/src/morkThumb.h @@ -84,6 +84,7 @@ public: // state is public because the entire Mork system is private morkStore* mThumb_Store; // weak ref to created store morkFile* mThumb_File; // strong ref to file (store, import, export) morkWriter* mThumb_Writer; // strong ref to writer (for commit) + morkBuilder* mThumb_Builder; // strong ref to builder (for store open) morkPort* mThumb_SourcePort; // strong ref to port for import mork_bool mThumb_DoCollect; // influence whether a collect happens @@ -115,6 +116,7 @@ public: // typing static void NilThumbStoreError(morkEnv* ev); static void NilThumbFileError(morkEnv* ev); static void NilThumbWriterError(morkEnv* ev); + static void NilThumbBuilderError(morkEnv* ev); static void NilThumbSourcePortError(morkEnv* ev); public: // 'do more' methods diff --git a/db/mork/src/morkWriter.cpp b/db/mork/src/morkWriter.cpp index 2fc18064c0a0..082b153848da 100644 --- a/db/mork/src/morkWriter.cpp +++ b/db/mork/src/morkWriter.cpp @@ -84,6 +84,10 @@ #include "morkAtom.h" #endif +#ifndef _MORKCH_ +#include "morkCh.h" +#endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 // ````` ````` ````` ````` ````` @@ -123,6 +127,7 @@ morkWriter::morkWriter(morkEnv* ev, const morkUsage& inUsage, , mWriter_LineSize( 0 ) , mWriter_MaxIndent( morkWriter_kMaxIndent ) +, mWriter_MaxLine( morkWriter_kMaxLine ) , mWriter_TableCharset( 0 ) , mWriter_TableAtomScope( 0 ) @@ -362,15 +367,16 @@ morkWriter::WriteYarn(morkEnv* ev, const mdbYarn* inYarn) while ( b < end ) { c = *b++; // next byte to print - if ( c < 0x080 && MORK_ISPRINT(c) ) + if ( morkCh_IsValue(c) ) { - if ( c == ')' && c == '$' && c == '\\' ) - { - stream->Putc(ev, '\\'); - ++outSize; - } stream->Putc(ev, c); - ++outSize; + ++outSize; // c + } + else if ( c == ')' && c == '$' && c == '\\' ) + { + stream->Putc(ev, '\\'); + stream->Putc(ev, c); + outSize += 2; // '\' c } else { @@ -396,8 +402,13 @@ morkWriter::WriteAtom(morkEnv* ev, const morkAtom* inAtom) mdbYarn yarn; // to ref content inside atom if ( inAtom->AliasYarn(&yarn) ) + { + if ( mWriter_DidStartDict && yarn.mYarn_Form != mWriter_DictCharset ) + this->ChangeDictCharset(ev, yarn.mYarn_Form); + outSize = this->WriteYarn(ev, &yarn); // mWriter_LineSize += stream->Write(ev, inYarn->mYarn_Buf, outSize); + } else inAtom->BadAtomKindError(ev); @@ -424,6 +435,7 @@ morkWriter::WriteAtomSpaceAsDict(morkEnv* ev, morkAtomSpace* ioSpace) if ( ev->Good() ) { + mdbYarn yarn; // to ref content inside atom char buf[ 64 ]; // buffer for staging the dict alias hex ID char* idBuf = buf + 1; // where the id always starts buf[ 0 ] = '('; // we always start with open paren @@ -442,15 +454,23 @@ morkWriter::WriteAtomSpaceAsDict(morkEnv* ev, morkAtomSpace* ioSpace) { atom->mAtom_Change = morkChange_kNil; // neutralize change - this->IndentAsNeeded(ev, morkWriter_kDictAliasDepth); + atom->AliasYarn(&yarn); mork_size size = ev->TokenAsHex(idBuf, atom->mBookAtom_Id); - mWriter_LineSize += stream->Write(ev, buf, size+1); // '(' - this->IndentAsNeeded(ev, morkWriter_kDictAliasValueDepth); - stream->Putc(ev, '='); // end alias + if ( yarn.mYarn_Form != mWriter_DictCharset ) + this->ChangeDictCharset(ev, yarn.mYarn_Form); + + mork_size pending = yarn.mYarn_Fill + size + + morkWriter_kYarnEscapeSlop + 4; + this->IndentOverMaxLine(ev, pending, morkWriter_kDictAliasDepth); + mWriter_LineSize += stream->Write(ev, buf, size+1); // + '(' + + pending -= ( size + 1 ); + this->IndentOverMaxLine(ev, pending, morkWriter_kDictAliasValueDepth); + stream->Putc(ev, '='); // start alias ++mWriter_LineSize; - this->WriteAtom(ev, atom); + this->WriteYarn(ev, &yarn); stream->Putc(ev, ')'); // end alias ++mWriter_LineSize; @@ -1037,22 +1057,40 @@ morkWriter::WriteStringToTokenDictCell(morkEnv* ev, // mWriter_LineSize += stream->Write(ev, yarnBuf, fill + 1); // +1 for ')' } +void +morkWriter::ChangeDictCharset(morkEnv* ev, mork_cscode inNewForm) +{ + if ( inNewForm != mWriter_DictCharset ) + { + morkStream* stream = mWriter_Stream; + if ( mWriter_LineSize ) + stream->PutLineBreak(ev); + mWriter_LineSize = 0; + + stream->Putc(ev, '<'); + this->WriteStringToTokenDictCell(ev, "(charset=", mWriter_DictCharset); + stream->Putc(ev, '>'); + ++mWriter_LineSize; + + mWriter_DictCharset = inNewForm; + } +} + void morkWriter::StartDict(morkEnv* ev) { morkStream* stream = mWriter_Stream; if ( mWriter_DidStartDict ) { - if ( mWriter_LineSize ) - stream->PutLineBreak(ev); - stream->PutStringThenNewline(ev, "> // end dict"); - mWriter_LineSize = 0; + stream->Putc(ev, '>'); // end dict + ++mWriter_LineSize; } mWriter_DidStartDict = morkBool_kTrue; if ( mWriter_LineSize ) stream->PutLineBreak(ev); mWriter_LineSize = 0; + stream->PutLineBreak(ev); if ( mWriter_DictCharset || mWriter_DictAtomScope != 'a' ) { stream->Putc(ev, '<'); @@ -1069,7 +1107,9 @@ morkWriter::StartDict(morkEnv* ev) } else { - stream->PutString(ev, "< // <(charset=iso-8859-1)(atomScope=a)>"); + stream->Putc(ev, '<'); + stream->Putc(ev, ' '); + mWriter_LineSize += 2; } mWriter_LineSize = stream->PutIndent(ev, morkWriter_kDictAliasDepth); } @@ -1080,10 +1120,8 @@ morkWriter::EndDict(morkEnv* ev) morkStream* stream = mWriter_Stream; if ( mWriter_DidStartDict ) { - if ( mWriter_LineSize ) - stream->PutLineBreak(ev); - stream->PutStringThenNewline(ev, "> // end dict"); - mWriter_LineSize = 0; + stream->Putc(ev, '>'); // end dict + ++mWriter_LineSize; } mWriter_DidStartDict = morkBool_kFalse; } @@ -1100,6 +1138,7 @@ morkWriter::StartTable(morkEnv* ev, morkTable* ioTable) if ( mWriter_LineSize ) stream->PutLineBreak(ev); mWriter_LineSize = 0; + stream->PutLineBreak(ev); char buf[ 64 ]; // buffer for staging hex char* p = buf; @@ -1123,9 +1162,8 @@ morkWriter::StartTable(morkEnv* ev, morkTable* ioTable) this->IndentAsNeeded(ev, morkWriter_kTableMetaCellDepth); this->WriteTokenToTokenMetaCell(ev, store->mStore_TableKindToken, tk); } - stream->Putc(ev, '}'); - stream->Putc(ev, ' '); - mWriter_LineSize += 2; + stream->Putc(ev, '}'); // end meta + mWriter_LineSize = stream->PutIndent(ev, morkWriter_kRowCellDepth); } } @@ -1133,10 +1171,8 @@ void morkWriter::EndTable(morkEnv* ev) { morkStream* stream = mWriter_Stream; - if ( mWriter_LineSize ) - stream->PutLineBreak(ev); - stream->PutStringThenNewline(ev, "} // end table"); - mWriter_LineSize = 0; + stream->Putc(ev, '}'); // end table + ++mWriter_LineSize; } mork_bool @@ -1208,9 +1244,9 @@ morkWriter::PutRowCells(morkEnv* ev, morkRow* ioRow) colSize = ev->TokenAsHex(p, col); p += colSize; - this->IndentAsNeeded(ev, morkWriter_kRowCellDepth); if ( atom->IsBook() ) // is it possible to write atom ID? { + this->IndentAsNeeded(ev, morkWriter_kRowCellDepth); *p++ = '^'; morkBookAtom* ba = (morkBookAtom*) atom; mork_size valSize = ev->TokenAsHex(p, ba->mBookAtom_Id); @@ -1227,13 +1263,24 @@ morkWriter::PutRowCells(morkEnv* ev, morkRow* ioRow) } else // must write an anonymous atom { + mdbYarn yarn; // to ref content inside atom + atom->AliasYarn(&yarn); + + if ( yarn.mYarn_Form != mWriter_DictCharset ) + this->ChangeDictCharset(ev, yarn.mYarn_Form); + + mork_size pending = yarn.mYarn_Fill + colSize + + morkWriter_kYarnEscapeSlop + 2; + this->IndentOverMaxLine(ev, pending, morkWriter_kRowCellDepth); + mWriter_LineSize += stream->Write(ev, buf, colSize + 2); - this->IndentAsNeeded(ev, morkWriter_kRowCellValueDepth); + pending -= ( colSize + 2 ); + this->IndentOverMaxLine(ev, pending, morkWriter_kRowCellDepth); stream->Putc(ev, '='); ++mWriter_LineSize; - this->WriteAtom(ev, atom); + this->WriteYarn(ev, &yarn); stream->Putc(ev, ')'); // end alias ++mWriter_LineSize; } @@ -1254,8 +1301,8 @@ morkWriter::PutRow(morkEnv* ev, morkRow* ioRow) this->IndentAsNeeded(ev, morkWriter_kRowDepth); - // if ( ioRow->IsRowDirty() ) - if ( morkBool_kTrue ) + //if ( morkBool_kTrue ) + if ( ioRow->IsRowDirty() ) { ioRow->SetRowClean(); mork_rid rid = roid->mOid_Id; @@ -1271,8 +1318,7 @@ morkWriter::PutRow(morkEnv* ev, morkRow* ioRow) this->PutRowCells(ev, ioRow); stream->Putc(ev, ']'); // end row - stream->Putc(ev, ' '); // end row - mWriter_LineSize += 2; + ++mWriter_LineSize; } else { diff --git a/db/mork/src/morkWriter.h b/db/mork/src/morkWriter.h index 51c79bfd74b5..8b446eec13d7 100644 --- a/db/mork/src/morkWriter.h +++ b/db/mork/src/morkWriter.h @@ -58,7 +58,7 @@ //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 -#define morkWriter_kStreamBufSize /*i*/ (16) /* buffer size for stream */ +#define morkWriter_kStreamBufSize /*i*/ (16 * 1024) /* buffer size for stream */ #define morkDerived_kWriter /*i*/ 0x5772 /* ascii 'Wr' */ @@ -85,7 +85,10 @@ #define morkWriter_kMaxColumnNameSize 128 /* longest writable col name */ -#define morkWriter_kMaxIndent 48 /* default value for mWriter_MaxIndent */ +#define morkWriter_kMaxIndent 56 /* default value for mWriter_MaxIndent */ +#define morkWriter_kMaxLine 78 /* default value for mWriter_MaxLine */ + +#define morkWriter_kYarnEscapeSlop 4 /* guess average yarn escape overhead */ #define morkWriter_kTableMetaCellDepth 4 /* */ #define morkWriter_kTableMetaCellValueDepth 6 /* */ @@ -126,6 +129,7 @@ public: // state is public because the entire Mork system is private mork_size mWriter_LineSize; // length of current line being written mork_size mWriter_MaxIndent; // line size forcing a line break + mork_size mWriter_MaxLine; // line size forcing a value continuation mork_cscode mWriter_TableCharset; // current charset metainfo mork_scope mWriter_TableAtomScope; // current atom scope @@ -195,6 +199,7 @@ public: // typing & errors static void UnsupportedPhaseError(morkEnv* ev); public: // inlines + void ChangeDictCharset(morkEnv* ev, mork_cscode inNewForm); mork_bool DidStartDict() const { return mWriter_DidStartDict; } mork_bool DidEndDict() const { return mWriter_DidEndDict; } @@ -206,6 +211,13 @@ public: // inlines if ( mWriter_LineSize > mWriter_MaxIndent ) mWriter_LineSize = mWriter_Stream->PutIndent(ev, inDepth); } + + void IndentOverMaxLine(morkEnv* ev, + mork_size inPendingSize, mork_size inDepth) + { + if ( mWriter_LineSize + inPendingSize > mWriter_MaxLine ) + mWriter_LineSize = mWriter_Stream->PutIndent(ev, inDepth); + } public: // iterative/asynchronouse writing diff --git a/mailnews/db/mork/src/Makefile.in b/mailnews/db/mork/src/Makefile.in index 42a87d5cd9e0..5851607fa9f6 100644 --- a/mailnews/db/mork/src/Makefile.in +++ b/mailnews/db/mork/src/Makefile.in @@ -48,6 +48,7 @@ CPPSRCS = \ morkBuilder.cpp\ morkCell.cpp\ morkCellObject.cpp\ + morkCh.cpp\ morkConfig.cpp\ morkCursor.cpp \ morkDeque.cpp\ diff --git a/mailnews/db/mork/src/makefile.win b/mailnews/db/mork/src/makefile.win index eacc44474433..928aafe900d0 100644 --- a/mailnews/db/mork/src/makefile.win +++ b/mailnews/db/mork/src/makefile.win @@ -47,6 +47,7 @@ CPPSRCS= orkinCell.cpp\ morkBuilder.cpp\ morkCell.cpp\ morkCellObject.cpp\ + morkCh.cpp\ morkConfig.cpp\ morkCursor.cpp \ morkDeque.cpp\ @@ -97,6 +98,7 @@ CPP_OBJS= .\$(OBJDIR)\orkinCell.obj\ .\$(OBJDIR)\morkBuilder.obj\ .\$(OBJDIR)\morkCell.obj\ .\$(OBJDIR)\morkCellObject.obj\ + .\$(OBJDIR)\morkCh.obj\ .\$(OBJDIR)\morkConfig.obj\ .\$(OBJDIR)\morkCursor.obj\ .\$(OBJDIR)\morkDeque.obj\ diff --git a/mailnews/db/mork/src/mork.h b/mailnews/db/mork/src/mork.h index deb90f1de239..a2d7af251901 100644 --- a/mailnews/db/mork/src/mork.h +++ b/mailnews/db/mork/src/mork.h @@ -64,6 +64,8 @@ typedef unsigned long mork_u4; // make sure this is four bytes typedef long mork_i4; // make sure this is four bytes typedef long mork_ip; // make sure sizeof(mork_ip) == sizeof(void*) +typedef mork_u1 mork_ch; // small byte-sized character (never wide) + typedef mork_u2 mork_base; // 2-byte magic class signature slot in object typedef mork_u2 mork_derived; // 2-byte magic class signature slot in object typedef mork_u2 mork_uses; // 2-byte strong uses count @@ -109,6 +111,9 @@ typedef mork_u1 mork_load; // dirty or clean (clone IronDoc's fe_load) #define morkChange_kPut 'p' /* put member */ #define morkChange_kSet 's' /* set all members */ #define morkChange_kNil 0 /* no change in this member */ +#define morkChange_kDup 'd' /* duplicate changes have no effect */ +// kDup is intended to replace another change constant in an object as a +// conclusion about change feasibility while staging intended alterations. #define morkLoad_kDirty ((mork_load) 0xDD) /* same as IronDoc constant */ #define morkLoad_kClean ((mork_load) 0x22) /* same as IronDoc constant */ @@ -147,6 +152,7 @@ typedef mdb_order mork_order; // neg:lessthan, zero:equalto, pos:greaterthan // { %%%%% begin class forward defines %%%%% // try to put these in alphabetical order for easier examination: +class morkMid; class morkAtom; class morkAtomSpace; class morkBookAtom; @@ -168,6 +174,7 @@ class morkObject; class morkOidAtom; class morkParser; class morkPool; +class morkPlace; class morkPort; class morkPortTableCursor; class morkRow; @@ -175,6 +182,7 @@ class morkRowCellCursor; class morkRowObject; class morkRowSpace; class morkSpace; +class morkSpan; class morkStore; class morkStream; class morkTable; diff --git a/mailnews/db/mork/src/morkAtom.h b/mailnews/db/mork/src/morkAtom.h index c0a3fe8441fc..8d8868993c30 100644 --- a/mailnews/db/mork/src/morkAtom.h +++ b/mailnews/db/mork/src/morkAtom.h @@ -305,7 +305,7 @@ class morkMaxBookAtom : public morkBigBookAtom { // // mork_u1 mBigBookAtom_Body[ 1 ]; // 1st byte of immed content vector public: - mork_u1 mBigBookAtom_Body[ morkBookAtom_kMaxBodySize + 3 ]; // max bytes + mork_u1 mMaxBookAtom_Body[ morkBookAtom_kMaxBodySize + 3 ]; // max bytes public: // empty construction does nothing morkMaxBookAtom() { } diff --git a/mailnews/db/mork/src/morkAtomMap.h b/mailnews/db/mork/src/morkAtomMap.h index 26e3bdb984fb..f80992b253de 100644 --- a/mailnews/db/mork/src/morkAtomMap.h +++ b/mailnews/db/mork/src/morkAtomMap.h @@ -138,11 +138,11 @@ public: // dynamic type identification // { ===== begin morkMap poly interface ===== virtual mork_bool // note: equal(a,b) implies hash(a) == hash(b) Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const; - // implemented using morkBookAtom::HashFormAndBody() + // implemented using morkBookAtom::EqualFormAndBody() virtual mork_u4 // note: equal(a,b) implies hash(a) == hash(b) Hash(morkEnv* ev, const void* inKey) const; - // implemented using morkBookAtom::EqualFormAndBody() + // implemented using morkBookAtom::HashFormAndBody() // } ===== end morkMap poly interface ===== public: // other map methods diff --git a/mailnews/db/mork/src/morkAtomSpace.cpp b/mailnews/db/mork/src/morkAtomSpace.cpp index 8196884c0f4a..6e53095ca1f4 100644 --- a/mailnews/db/mork/src/morkAtomSpace.cpp +++ b/mailnews/db/mork/src/morkAtomSpace.cpp @@ -153,6 +153,32 @@ morkAtomSpace::CutAllAtoms(morkEnv* ev, morkPool* ioPool) } +morkBookAtom* +morkAtomSpace::MakeBookAtomCopyWithAid(morkEnv* ev, + const morkBigBookAtom& inAtom, mork_aid inAid) +// Make copy of inAtom and put it in both maps, using specified ID. +{ + morkBookAtom* outAtom = 0; + if ( ev->Good() ) + { + morkPool* pool = this->GetSpaceStorePool(); + outAtom = pool->NewBookAtomCopy(ev, inAtom); + if ( outAtom ) + { + outAtom->mBookAtom_Id = inAid; + outAtom->mBookAtom_Space = this; + mAtomSpace_AtomAids.AddAtom(ev, outAtom); + mAtomSpace_AtomBodies.AddAtom(ev, outAtom); + if ( mSpace_Scope == morkAtomSpace_kColumnScope ) + outAtom->MakeCellUseForever(ev); + + if ( mAtomSpace_HighUnderId <= inAid ) + mAtomSpace_HighUnderId = inAid + 1; + } + } + return outAtom; +} + morkBookAtom* morkAtomSpace::MakeBookAtomCopy(morkEnv* ev, const morkBigBookAtom& inAtom) // make copy of inAtom and put it in both maps, using a new ID as needed. @@ -167,9 +193,12 @@ morkAtomSpace::MakeBookAtomCopy(morkEnv* ev, const morkBigBookAtom& inAtom) mork_aid id = this->MakeNewAtomId(ev, atom); if ( id ) { - outAtom = atom; + outAtom = atom; + atom->mBookAtom_Space = this; mAtomSpace_AtomAids.AddAtom(ev, atom); mAtomSpace_AtomBodies.AddAtom(ev, atom); + if ( mSpace_Scope == morkAtomSpace_kColumnScope ) + outAtom->MakeCellUseForever(ev); } } } diff --git a/mailnews/db/mork/src/morkAtomSpace.h b/mailnews/db/mork/src/morkAtomSpace.h index 8d03534d144d..4988cab70bd7 100644 --- a/mailnews/db/mork/src/morkAtomSpace.h +++ b/mailnews/db/mork/src/morkAtomSpace.h @@ -64,6 +64,8 @@ #define morkDerived_kAtomSpace /*i*/ 0x6153 /* ascii 'aS' */ +#define morkAtomSpace_kColumnScope ((mork_scope) 'c') /* column scope is forever */ + /*| morkAtomSpace: |*/ class morkAtomSpace : public morkSpace { // @@ -132,6 +134,10 @@ public: // other space methods mork_num CutAllAtoms(morkEnv* ev, morkPool* ioPool); // CutAllAtoms() puts all the atoms back in the pool. + morkBookAtom* MakeBookAtomCopyWithAid(morkEnv* ev, + const morkBigBookAtom& inAtom, mork_aid inAid); + // Make copy of inAtom and put it in both maps, using specified ID. + morkBookAtom* MakeBookAtomCopy(morkEnv* ev, const morkBigBookAtom& inAtom); // Make copy of inAtom and put it in both maps, using a new ID as needed. diff --git a/mailnews/db/mork/src/morkBlob.cpp b/mailnews/db/mork/src/morkBlob.cpp index 7f56c5f59616..73496613f703 100644 --- a/mailnews/db/mork/src/morkBlob.cpp +++ b/mailnews/db/mork/src/morkBlob.cpp @@ -32,31 +32,92 @@ #include "morkEnv.h" #endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 -morkSpool::morkSpool(morkEnv* ev, nsIMdbHeap* ioHeap) +/*static*/ void +morkBuf::NilBufBodyError(morkEnv* ev) +{ + ev->NewError("nil mBuf_Body"); +} + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +/*static*/ void +morkBlob::BlobFillOverSizeError(morkEnv* ev) +{ + ev->NewError("mBuf_Fill > mBlob_Size"); +} + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +mork_bool +morkBlob::GrowBlob(morkEnv* ev, nsIMdbHeap* ioHeap, mork_size inNewSize) +{ + if ( ioHeap ) + { + if ( !mBuf_Body ) // no body? implies zero sized? + mBlob_Size = 0; + + if ( mBuf_Fill > mBlob_Size ) // fill more than size? + { + ev->NewWarning("mBuf_Fill > mBlob_Size"); + mBuf_Fill = mBlob_Size; + } + + if ( inNewSize > mBlob_Size ) // need to allocate larger blob? + { + mork_u1* body = 0; + ioHeap->Alloc(ev->AsMdbEnv(), inNewSize, (void**) &body); + if ( body && ev->Good() ) + { + void* oldBody = mBuf_Body; + if ( mBlob_Size ) // any old content to transfer? + MORK_MEMCPY(body, oldBody, mBlob_Size); + + mBlob_Size = inNewSize; // install new size + mBuf_Body = body; // install new body + + if ( oldBody ) // need to free old buffer body? + ioHeap->Free(ev->AsMdbEnv(), oldBody); + } + } + } + else + ev->NilPointerError(); + + if ( ev->Good() && mBlob_Size < inNewSize ) + ev->NewError("mBlob_Size < inNewSize"); + + return ev->Good(); +} + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +morkCoil::morkCoil(morkEnv* ev, nsIMdbHeap* ioHeap) { mBuf_Body = 0; mBuf_Fill = 0; mBlob_Size = 0; mText_Form = 0; - mSpool_Heap = ioHeap; + mCoil_Heap = ioHeap; if ( !ioHeap ) ev->NilPointerError(); } void -morkSpool::CloseSpool(morkEnv* ev) +morkCoil::CloseCoil(morkEnv* ev) { void* body = mBuf_Body; - nsIMdbHeap* heap = mSpool_Heap; + nsIMdbHeap* heap = mCoil_Heap; + + mBuf_Body = 0; + mCoil_Heap = 0; if ( body && heap ) { heap->Free(ev->AsMdbEnv(), body); } - mBuf_Body = 0; - mSpool_Heap = 0; } //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 diff --git a/mailnews/db/mork/src/morkBlob.h b/mailnews/db/mork/src/morkBlob.h index 44f0d8d4ccdb..d70d6ca266e7 100644 --- a/mailnews/db/mork/src/morkBlob.h +++ b/mailnews/db/mork/src/morkBlob.h @@ -39,6 +39,10 @@ public: morkBuf(const void* ioBuf, mork_fill inFill) : mBuf_Body((void*) ioBuf), mBuf_Fill(inFill) { } + void ClearBufFill() { mBuf_Fill = 0; } + + static void NilBufBodyError(morkEnv* ev); + private: // copying is not allowed morkBuf(const morkBuf& other); morkBuf& operator=(const morkBuf& other); @@ -61,9 +65,12 @@ public: morkBlob() { } morkBlob(const void* ioBuf, mork_fill inFill, mork_size inSize) : morkBuf(ioBuf, inFill), mBlob_Size(inSize) { } - + + static void BlobFillOverSizeError(morkEnv* ev); + public: - mork_bool Grow(morkEnv* ev, nsIMdbHeap* ioHeap, mork_size inNewSize); + mork_bool GrowBlob(morkEnv* ev, nsIMdbHeap* ioHeap, + mork_size inNewSize); private: // copying is not allowed morkBlob(const morkBlob& other); @@ -94,49 +101,52 @@ private: // copying is not allowed morkText& operator=(const morkText& other); }; -/*| Spool: a text with an associated nsIMdbHeap instance that provides +/*| Coil: a text with an associated nsIMdbHeap instance that provides **| all memory management for the space pointed to by mBuf_Body. (This **| was the hardest type to give a name in this small class hierarchy, **| because it's hard to characterize self-management of one's space.) -**| A spool is a self-contained blob that knows how to grow itself as -**| necessary to hold more content when necessary. Spool descends from +**| A coil is a self-contained blob that knows how to grow itself as +**| necessary to hold more content when necessary. Coil descends from **| morkText to include the mText_Form slot, even though this won't be **| needed always, because we are not as concerned about the overall -**| size of this particular Spool object (if we were concerned about -**| the size of an array of Spool instances, we would not bother with +**| size of this particular Coil object (if we were concerned about +**| the size of an array of Coil instances, we would not bother with **| a separate heap pointer for each of them). **| -**|| A spool makes a good medium in which to stream content as a sink, -**| so we will have a subclass of morkSink called morkSpoolSink that -**| will stream bytes into this self-contained spool object. The name -**| of this morkSpool class derives more from this intended usage than +**|| A coil makes a good medium in which to stream content as a sink, +**| so we will have a subclass of morkSink called morkCoil that +**| will stream bytes into this self-contained coil object. The name +**| of this morkCoil class derives more from this intended usage than **| from anything else. The Mork code to parse db content will use -**| spools with associated sinks to accumulate parsed strings. +**| coils with associated sinks to accumulate parsed strings. **| **|| Heap: this is the heap used for memory allocation. This instance -**| is NOT refcounted, since this spool always assumes the heap is held +**| is NOT refcounted, since this coil always assumes the heap is held **| through a reference elsewhere (for example, through the same object -**| that contains or holds the spool itself. This lack of refcounting -**| is consistent with the fact that morkSpool itself is not refcounted, +**| that contains or holds the coil itself. This lack of refcounting +**| is consistent with the fact that morkCoil itself is not refcounted, **| and is not intended for use as a standalone object. |*/ -class morkSpool : public morkText { // self-managing text blob object +class morkCoil : public morkText { // self-managing text blob object // void* mBuf_Body; // space for holding any binary content // mdb_fill mBuf_Fill; // logical content in Buf in bytes // mdb_size mBlob_Size; // physical size of Buf in bytes // mdb_cscode mText_Form; // charset format encoding public: - nsIMdbHeap* mSpool_Heap; // storage manager for mBuf_Body pointer + nsIMdbHeap* mCoil_Heap; // storage manager for mBuf_Body pointer public: - morkSpool(morkEnv* ev, nsIMdbHeap* ioHeap); + morkCoil(morkEnv* ev, nsIMdbHeap* ioHeap); - void CloseSpool(morkEnv* ev); + void CloseCoil(morkEnv* ev); + + mork_bool GrowCoil(morkEnv* ev, mork_size inNewSize) + { return this->GrowBlob(ev, mCoil_Heap, inNewSize); } private: // copying is not allowed - morkSpool(const morkSpool& other); - morkSpool& operator=(const morkSpool& other); + morkCoil(const morkCoil& other); + morkCoil& operator=(const morkCoil& other); }; //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 diff --git a/mailnews/db/mork/src/morkBuilder.cpp b/mailnews/db/mork/src/morkBuilder.cpp index a5a4af6adee7..54f8fa55659d 100644 --- a/mailnews/db/mork/src/morkBuilder.cpp +++ b/mailnews/db/mork/src/morkBuilder.cpp @@ -48,6 +48,34 @@ #include "morkCell.h" #endif +#ifndef _MORKSTORE_ +#include "morkStore.h" +#endif + +#ifndef _MORKTABLE_ +#include "morkTable.h" +#endif + +#ifndef _MORKROW_ +#include "morkRow.h" +#endif + +#ifndef _MORKCELL_ +#include "morkCell.h" +#endif + +#ifndef _MORKATOM_ +#include "morkAtom.h" +#endif + +#ifndef _MORKATOMSPACE_ +#include "morkAtomSpace.h" +#endif + +#ifndef _MORKROWSPACE_ +#include "morkRowSpace.h" +#endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 // ````` ````` ````` ````` ````` @@ -67,7 +95,12 @@ morkBuilder::CloseMorkNode(morkEnv* ev) // CloseBuilder() only if open /*public virtual*/ morkBuilder::~morkBuilder() // assert CloseBuilder() executed earlier { + MORK_ASSERT(mBuilder_Store==0); + MORK_ASSERT(mBuilder_Row==0); MORK_ASSERT(mBuilder_Table==0); + MORK_ASSERT(mBuilder_Cell==0); + MORK_ASSERT(mBuilder_RowSpace==0); + MORK_ASSERT(mBuilder_AtomSpace==0); } /*public non-poly*/ @@ -75,11 +108,67 @@ morkBuilder::morkBuilder(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap, morkStream* ioStream, mdb_count inBytesPerParseSegment, nsIMdbHeap* ioSlotHeap, morkStore* ioStore) + : morkParser(ev, inUsage, ioHeap, ioStream, inBytesPerParseSegment, ioSlotHeap) + +, mBuilder_Store( 0 ) + +, mBuilder_Table( 0 ) +, mBuilder_Row( 0 ) +, mBuilder_Cell( 0 ) + +, mBuilder_RowSpace( 0 ) +, mBuilder_AtomSpace( 0 ) + +, mBuilder_OidAtomSpace( 0 ) +, mBuilder_ScopeAtomSpace( 0 ) + +, mBuilder_iso_8859_1( 0 ) +, mBuilder_r( (mork_scope) 'r' ) +, mBuilder_a( (mork_scope) 'a' ) +, mBuilder_t( (mork_scope) 't' ) + +, mBuilder_MorkNoneToken( 0 ) + +, mBuilder_PortForm( 0 ) +, mBuilder_PortRowScope( (mork_scope) 'r' ) +, mBuilder_PortAtomScope( (mork_scope) 'a' ) + +, mBuilder_TableForm( 0 ) +, mBuilder_TableRowScope( (mork_scope) 'r' ) +, mBuilder_TableAtomScope( (mork_scope) 'a' ) +, mBuilder_TableKind( 0 ) + +, mBuilder_RowForm( 0 ) +, mBuilder_RowRowScope( (mork_scope) 'r' ) +, mBuilder_RowAtomScope( (mork_scope) 'a' ) + +, mBuilder_CellForm( 0 ) +, mBuilder_CellAtomScope( (mork_scope) 'a' ) + +, mBuilder_DictForm( 0 ) +, mBuilder_DictAtomScope( (mork_scope) 'a' ) + +, mBuilder_MetaTokenSlot( 0 ) + +, mBuilder_DoCutRow( morkBool_kFalse ) +, mBuilder_DoCutCell( morkBool_kFalse ) +, mBuilder_CellsVecFill( 0 ) { if ( ev->Good() ) - mNode_Derived = morkDerived_kBuilder; + { + if ( ioStore ) + { + mBuilder_MorkNoneToken = ioStore->mStore_MorkNoneToken; + morkStore::SlotWeakStore(ioStore, ev, &mBuilder_Store); + if ( ev->Good() ) + mNode_Derived = morkDerived_kBuilder; + } + else + ev->NilPointerError(); + } + } /*public non-poly*/ void @@ -89,6 +178,24 @@ morkBuilder::CloseBuilder(morkEnv* ev) // called by CloseMorkNode(); { if ( this->IsNode() ) { + mBuilder_Row = 0; + mBuilder_Cell = 0; + mBuilder_MetaTokenSlot = 0; + + morkTable::SlotStrongTable((morkTable*) 0, ev, &mBuilder_Table); + morkStore::SlotWeakStore((morkStore*) 0, ev, &mBuilder_Store); + + morkRowSpace::SlotStrongRowSpace((morkRowSpace*) 0, ev, + &mBuilder_RowSpace); + + morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev, + &mBuilder_AtomSpace); + + morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev, + &mBuilder_OidAtomSpace); + + morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev, + &mBuilder_ScopeAtomSpace); this->CloseParser(ev); this->MarkShut(); } @@ -108,217 +215,655 @@ morkBuilder::NonBuilderTypeError(morkEnv* ev) ev->NewError("non morkBuilder"); } +/*static*/ void +morkBuilder::NilBuilderCellError(morkEnv* ev) +{ + ev->NewError("nil mBuilder_Cell"); +} + +/*static*/ void +morkBuilder::NilBuilderRowError(morkEnv* ev) +{ + ev->NewError("nil mBuilder_Row"); +} + +/*static*/ void +morkBuilder::NilBuilderTableError(morkEnv* ev) +{ + ev->NewError("nil mBuilder_Table"); +} + +/*static*/ void +morkBuilder::NonColumnSpaceScopeError(morkEnv* ev) +{ + ev->NewError("column space != 'c'"); +} + +void +morkBuilder::LogGlitch(morkEnv* ev, const morkGlitch& inGlitch, + const char* inKind) +{ + ev->NewWarning("parsing glitch"); +} + /*virtual*/ void -morkBuilder::AliasToYarn(morkEnv* ev, - const morkAlias& inAlias, // typically an alias to concat with strings +morkBuilder::MidToYarn(morkEnv* ev, + const morkMid& inMid, // typically an alias to concat with strings mdbYarn* outYarn) // The parser might ask that some aliases be turned into yarns, so they // can be concatenated into longer blobs under some circumstances. This // is an alternative to using a long and complex callback for many parts // for a single cell value. { - ev->StubMethodOnlyError(); + mBuilder_Store->MidToYarn(ev, inMid, outYarn); } /*virtual*/ void morkBuilder::OnNewPort(morkEnv* ev, const morkPlace& inPlace) +// mp:Start ::= OnNewPort mp:PortItem* OnPortEnd +// mp:PortItem ::= mp:Content | mp:Group | OnPortGlitch +// mp:Content ::= mp:PortRow | mp:Dict | mp:Table | mp:Row { - ev->StubMethodOnlyError(); + // mParser_InPort = morkBool_kTrue; + mBuilder_PortForm = 0; + mBuilder_PortRowScope = (mork_scope) 'r'; + mBuilder_PortAtomScope = (mork_scope) 'a'; } /*virtual*/ void morkBuilder::OnPortGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "port"); } /*virtual*/ void morkBuilder::OnPortEnd(morkEnv* ev, const morkSpan& inSpan) +// mp:Start ::= OnNewPort mp:PortItem* OnPortEnd { - ev->StubMethodOnlyError(); + // ev->StubMethodOnlyError(); + // nothing to do? + // mParser_InPort = morkBool_kFalse; } /*virtual*/ void morkBuilder::OnNewGroup(morkEnv* ev, const morkPlace& inPlace, mork_gid inGid) { + // mParser_InGroup = morkBool_kTrue; ev->StubMethodOnlyError(); } /*virtual*/ void morkBuilder::OnGroupGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "group"); } /*virtual*/ void morkBuilder::OnGroupCommitEnd(morkEnv* ev, const morkSpan& inSpan) { + // mParser_InGroup = morkBool_kFalse; ev->StubMethodOnlyError(); } /*virtual*/ void morkBuilder::OnGroupAbortEnd(morkEnv* ev, const morkSpan& inSpan) { + // mParser_InGroup = morkBool_kFalse; ev->StubMethodOnlyError(); } /*virtual*/ void morkBuilder::OnNewPortRow(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) + const morkMid& inMid, mork_change inChange) { + // mParser_InPortRow = morkBool_kTrue; ev->StubMethodOnlyError(); } /*virtual*/ void morkBuilder::OnPortRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "port row"); } /*virtual*/ void morkBuilder::OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan) { + // mParser_InPortRow = morkBool_kFalse; ev->StubMethodOnlyError(); } /*virtual*/ void morkBuilder::OnNewTable(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) + const morkMid& inMid, mork_change inChange) +// mp:Table ::= OnNewTable mp:TableItem* OnTableEnd +// mp:TableItem ::= mp:Row | mp:Meta | OnTableGlitch +// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd +// mp:MetaItem ::= mp:Cell | OnMetaGlitch { - ev->StubMethodOnlyError(); + // mParser_InTable = morkBool_kTrue; + mBuilder_TableForm = mBuilder_PortForm; + mBuilder_TableRowScope = mBuilder_PortRowScope; + mBuilder_TableAtomScope = mBuilder_PortAtomScope; + mBuilder_TableKind = mBuilder_MorkNoneToken; + + morkTable* table = mBuilder_Store->MidToTable(ev, inMid); + morkTable::SlotStrongTable(table, ev, &mBuilder_Table); } /*virtual*/ void morkBuilder::OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "table"); } /*virtual*/ void morkBuilder::OnTableEnd(morkEnv* ev, const morkSpan& inSpan) +// mp:Table ::= OnNewTable mp:TableItem* OnTableEnd { - ev->StubMethodOnlyError(); + // mParser_InTable = morkBool_kFalse; + if ( mBuilder_Table ) + { + morkTable::SlotStrongTable((morkTable*) 0, ev, &mBuilder_Table); + } + else + this->NilBuilderTableError(ev); + + mBuilder_Row = 0; + mBuilder_Cell = 0; + + if ( mBuilder_TableKind == mBuilder_MorkNoneToken ) + ev->NewError("missing table kind"); + + mBuilder_CellAtomScope = mBuilder_RowAtomScope = + mBuilder_TableAtomScope = mBuilder_PortAtomScope; } /*virtual*/ void morkBuilder::OnNewMeta(morkEnv* ev, const morkPlace& inPlace) +// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd +// mp:MetaItem ::= mp:Cell | OnMetaGlitch +// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd +// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + // mParser_InMeta = morkBool_kTrue; + } /*virtual*/ void morkBuilder::OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "meta"); } /*virtual*/ void morkBuilder::OnMetaEnd(morkEnv* ev, const morkSpan& inSpan) +// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd { - ev->StubMethodOnlyError(); + // mParser_InMeta = morkBool_kFalse; } /*virtual*/ void morkBuilder::OnNewRow(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) + const morkMid& inMid, mork_change inChange) +// mp:Row ::= OnNewRow mp:RowItem* OnRowEnd +// mp:RowItem ::= mp:Cell | mp:Meta | OnRowGlitch +// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd +// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + // mParser_InRow = morkBool_kTrue; + if ( mBuilder_Table ) + { + mBuilder_CellForm = mBuilder_RowForm = mBuilder_TableForm; + mBuilder_CellAtomScope = mBuilder_RowAtomScope = mBuilder_TableAtomScope; + mBuilder_RowRowScope = mBuilder_TableRowScope; + morkStore* store = mBuilder_Store; + + if ( !inMid.mMid_Buf && !inMid.mMid_Oid.mOid_Scope ) + { + morkMid mid(inMid); + mid.mMid_Oid.mOid_Scope = mBuilder_RowRowScope; + mBuilder_Row = store->MidToRow(ev, mid); + } + else + { + mBuilder_Row = store->MidToRow(ev, inMid); + } + + if ( mBuilder_Row ) + mBuilder_Table->AddRow(ev, mBuilder_Row); + } + else + this->NilBuilderTableError(ev); } /*virtual*/ void morkBuilder::OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "row"); +} + +void +morkBuilder::FlushBuilderCells(morkEnv* ev) +{ + if ( mBuilder_Row ) + { + morkPool* pool = mBuilder_Store->StorePool(); + morkCell* cells = mBuilder_CellsVec; + mork_fill fill = mBuilder_CellsVecFill; + mBuilder_Row->TakeCells(ev, cells, fill, mBuilder_Store); + + morkCell* end = cells + fill; + --cells; // prepare for preincrement + while ( ++cells < end ) + { + if ( cells->mCell_Atom ) + cells->SetAtom(ev, (morkAtom*) 0, pool); + } + mBuilder_CellsVecFill = 0; + } + else + this->NilBuilderRowError(ev); } /*virtual*/ void morkBuilder::OnRowEnd(morkEnv* ev, const morkSpan& inSpan) +// mp:Row ::= OnNewRow mp:RowItem* OnRowEnd { - ev->StubMethodOnlyError(); + // mParser_InRow = morkBool_kFalse; + if ( mBuilder_Row ) + { + this->FlushBuilderCells(ev); + } + else + this->NilBuilderRowError(ev); + + mBuilder_Row = 0; + mBuilder_Cell = 0; } /*virtual*/ void morkBuilder::OnNewDict(morkEnv* ev, const morkPlace& inPlace) +// mp:Dict ::= OnNewDict mp:DictItem* OnDictEnd +// mp:DictItem ::= OnAlias | OnAliasGlitch | mp:Meta | OnDictGlitch { - ev->StubMethodOnlyError(); + // mParser_InDict = morkBool_kTrue; + + mBuilder_CellForm = mBuilder_DictForm = mBuilder_PortForm; + mBuilder_CellAtomScope = mBuilder_DictAtomScope = mBuilder_PortAtomScope; } /*virtual*/ void morkBuilder::OnDictGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "dict"); } /*virtual*/ void morkBuilder::OnDictEnd(morkEnv* ev, const morkSpan& inSpan) +// mp:Dict ::= OnNewDict mp:DictItem* OnDictEnd { - ev->StubMethodOnlyError(); + // mParser_InDict = morkBool_kFalse; + + mBuilder_DictForm = 0; + mBuilder_DictAtomScope = 0; } /*virtual*/ void morkBuilder::OnAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) + const morkMid& inMid) { - ev->StubMethodOnlyError(); + if ( mParser_InDict ) + { + morkMid mid = inMid; // local copy for modification + mid.mMid_Oid.mOid_Scope = mBuilder_DictAtomScope; + mBuilder_Store->AddAlias(ev, mid, mBuilder_DictForm); + } + else + ev->NewError("alias not in dict"); } /*virtual*/ void morkBuilder::OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "alias"); +} + + +morkCell* +morkBuilder::AddBuilderCell(morkEnv* ev, + const morkMid& inMid, mork_change inChange) +{ + morkCell* outCell = 0; + mork_column column = inMid.mMid_Oid.mOid_Id; + + if ( ev->Good() ) + { + if ( mBuilder_CellsVecFill >= morkBuilder_kCellsVecSize ) + this->FlushBuilderCells(ev); + if ( ev->Good() ) + { + if ( mBuilder_CellsVecFill < morkBuilder_kCellsVecSize ) + { + mork_fill index = mBuilder_CellsVecFill++; + outCell = mBuilder_CellsVec + index; + outCell->SetColumnAndChange(column, inChange); + outCell->mCell_Atom = 0; + } + else + ev->NewError("out of builder cells"); + } + } + return outCell; } /*virtual*/ void morkBuilder::OnNewCell(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) + const morkMid* inMid, const morkBuf* inBuf, mork_change inChange) +// Exactly one of inMid and inBuf is nil, and the other is non-nil. +// When hex ID syntax is used for a column, then inMid is not nil, and +// when a naked string names a column, then inBuf is not nil. + + // mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd + // mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch + // mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + // mParser_InCell = morkBool_kTrue; + + mBuilder_CellAtomScope = mBuilder_RowAtomScope; + + mBuilder_Cell = 0; // nil until determined for a row + morkStore* store = mBuilder_Store; + mork_scope scope = morkStore_kColumnSpaceScope; + morkMid tempMid; // space for local and modifiable cell mid + morkMid* cellMid = &tempMid; // default to local if inMid==0 + + if ( inMid ) // mid parameter is actually provided? + { + *cellMid = *inMid; // bitwise copy for modifiable local mid + + if ( !cellMid->mMid_Oid.mOid_Scope ) + { + if ( cellMid->mMid_Buf ) + { + scope = store->BufToToken(ev, cellMid->mMid_Buf); + cellMid->mMid_Buf = 0; // don't do scope lookup again + ev->NewWarning("column mids need column scope"); + } + cellMid->mMid_Oid.mOid_Scope = scope; + } + } + else if ( inBuf ) // buf points to naked column string name? + { + cellMid->ClearMid(); + cellMid->mMid_Oid.mOid_Id = store->BufToToken(ev, inBuf); + cellMid->mMid_Oid.mOid_Scope = scope; // kColumnSpaceScope + } + else + ev->NilPointerError(); // either inMid or inBuf must be non-nil + + mork_column column = cellMid->mMid_Oid.mOid_Id; + + if ( mParser_InMeta && ev->Good() ) // cell is in metainfo structure? + { + if ( scope == morkStore_kColumnSpaceScope ) + { + if ( mParser_InTable ) // metainfo for table? + { + if ( column == store->mStore_TableKindToken ) + mBuilder_MetaTokenSlot = &mBuilder_TableKind; + else if ( column == store->mStore_RowScopeToken ) + mBuilder_MetaTokenSlot = &mBuilder_TableRowScope; + else if ( column == store->mStore_AtomScopeToken ) + mBuilder_MetaTokenSlot = &mBuilder_TableAtomScope; + else if ( column == store->mStore_CharsetToken ) + mBuilder_MetaTokenSlot = &mBuilder_TableForm; + } + else if ( mParser_InDict ) // metainfo for dict? + { + if ( column == store->mStore_AtomScopeToken ) + mBuilder_MetaTokenSlot = &mBuilder_DictAtomScope; + else if ( column == store->mStore_CharsetToken ) + mBuilder_MetaTokenSlot = &mBuilder_DictForm; + } + else if ( mParser_InRow ) // metainfo for row? + { + if ( column == store->mStore_AtomScopeToken ) + mBuilder_MetaTokenSlot = &mBuilder_RowAtomScope; + else if ( column == store->mStore_RowScopeToken ) + mBuilder_MetaTokenSlot = &mBuilder_RowRowScope; + else if ( column == store->mStore_CharsetToken ) + mBuilder_MetaTokenSlot = &mBuilder_RowForm; + } + } + else + ev->NewWarning("expected column scope"); + } + else if ( ev->Good() ) // this cell must be inside a row + { + if ( mBuilder_Row ) + { + // mBuilder_Cell = this->AddBuilderCell(ev, *cellMid, inChange); + + if ( mBuilder_CellsVecFill >= morkBuilder_kCellsVecSize ) + this->FlushBuilderCells(ev); + if ( ev->Good() ) + { + if ( mBuilder_CellsVecFill < morkBuilder_kCellsVecSize ) + { + mork_fill index = mBuilder_CellsVecFill++; + morkCell* cell = mBuilder_CellsVec + index; + cell->SetColumnAndChange(column, inChange); + cell->mCell_Atom = 0; + mBuilder_Cell = cell; + } + else + ev->NewError("out of builder cells"); + } + } + else + this->NilBuilderRowError(ev); + } } /*virtual*/ void morkBuilder::OnCellGlitch(morkEnv* ev, const morkGlitch& inGlitch) { - ev->StubMethodOnlyError(); + this->LogGlitch(ev, inGlitch, "cell"); } /*virtual*/ void morkBuilder::OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat) { - ev->StubMethodOnlyError(); + morkCell* cell = mBuilder_Cell; + if ( cell ) + { + mBuilder_CellForm = inCharsetFormat; + } + else + this->NilBuilderCellError(ev); } /*virtual*/ void morkBuilder::OnCellEnd(morkEnv* ev, const morkSpan& inSpan) +// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd { - ev->StubMethodOnlyError(); + // mParser_InCell = morkBool_kFalse; + + mBuilder_MetaTokenSlot = 0; + mBuilder_CellAtomScope = mBuilder_RowAtomScope; } /*virtual*/ void morkBuilder::OnValue(morkEnv* ev, const morkSpan& inSpan, const morkBuf& inBuf) +// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + morkStore* store = mBuilder_Store; + morkCell* cell = mBuilder_Cell; + if ( cell ) + { + mdbYarn yarn; + yarn.mYarn_Buf = inBuf.mBuf_Body; + yarn.mYarn_Fill = yarn.mYarn_Size = inBuf.mBuf_Fill; + yarn.mYarn_More = 0; + yarn.mYarn_Form = mBuilder_CellForm; + yarn.mYarn_Grow = 0; + morkAtom* atom = store->YarnToAtom(ev, &yarn); + cell->SetAtom(ev, atom, store->StorePool()); + } + else if ( mParser_InMeta ) + { + mork_token* metaSlot = mBuilder_MetaTokenSlot; + if ( metaSlot ) + { + mork_token token = store->BufToToken(ev, &inBuf); + if ( token ) + { + *metaSlot = token; + if ( metaSlot == &mBuilder_TableKind ) // table kind? + { + if ( mParser_InTable && mBuilder_Table ) + mBuilder_Table->mTable_Kind = token; + } + } + } + } + else + this->NilBuilderCellError(ev); } /*virtual*/ void -morkBuilder::OnValueAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) +morkBuilder::OnValueMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid) +// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + morkStore* store = mBuilder_Store; + morkCell* cell = mBuilder_Cell; + + morkMid valMid; // local mid for modifications + mdbOid* valOid = &valMid.mMid_Oid; // ref to oid inside mid + *valOid = inMid.mMid_Oid; // bitwise copy inMid's oid + + if ( inMid.mMid_Buf ) + { + if ( !valOid->mOid_Scope ) + store->MidToOid(ev, inMid, valOid); + } + else if ( !valOid->mOid_Scope ) + valOid->mOid_Scope = mBuilder_CellAtomScope; + + if ( cell ) + { + morkBookAtom* atom = store->MidToAtom(ev, valMid); + if ( atom ) + cell->SetAtom(ev, atom, store->StorePool()); + else + ev->NewError("undefined cell value alias"); + } + else if ( mParser_InMeta ) + { + mork_token* metaSlot = mBuilder_MetaTokenSlot; + if ( metaSlot ) + { + if ( valOid->mOid_Scope == morkStore_kColumnSpaceScope ) + { + if ( ev->Good() && valMid.HasSomeId() ) + { + *metaSlot = valOid->mOid_Id; + if ( metaSlot == &mBuilder_TableKind ) // table kind? + { + if ( mParser_InTable && mBuilder_Table ) + { + mBuilder_Table->mTable_Kind = valOid->mOid_Id; + } + else + ev->NewWarning("mBuilder_TableKind not in table"); + } + } + } + else + this->NonColumnSpaceScopeError(ev); + } + } + else + this->NilBuilderCellError(ev); } /*virtual*/ void -morkBuilder::OnRowAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) +morkBuilder::OnRowMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid) +// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + morkStore* store = mBuilder_Store; + morkCell* cell = mBuilder_Cell; + if ( cell ) + { + mdbOid rowOid = inMid.mMid_Oid; + if ( inMid.mMid_Buf ) + { + if ( !rowOid.mOid_Scope ) + store->MidToOid(ev, inMid, &rowOid); + } + else if ( !rowOid.mOid_Scope ) + rowOid.mOid_Scope = mBuilder_RowRowScope; + + if ( ev->Good() ) + { + morkPool* pool = store->StorePool(); + morkAtom* atom = pool->NewRowOidAtom(ev, rowOid); + if ( atom ) + { + cell->SetAtom(ev, atom, pool); + morkRow* row = store->OidToRow(ev, &rowOid); + if ( row ) // found or created such a row? + row->AddTableUse(ev); + } + } + } + else + this->NilBuilderCellError(ev); } /*virtual*/ void -morkBuilder::OnTableAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) +morkBuilder::OnTableMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid) +// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid { - ev->StubMethodOnlyError(); + morkStore* store = mBuilder_Store; + morkCell* cell = mBuilder_Cell; + if ( cell ) + { + mdbOid tableOid = inMid.mMid_Oid; + if ( inMid.mMid_Buf ) + { + if ( !tableOid.mOid_Scope ) + store->MidToOid(ev, inMid, &tableOid); + } + else if ( !tableOid.mOid_Scope ) + tableOid.mOid_Scope = mBuilder_RowRowScope; + + if ( ev->Good() ) + { + morkPool* pool = store->StorePool(); + morkAtom* atom = pool->NewTableOidAtom(ev, tableOid); + if ( atom ) + { + cell->SetAtom(ev, atom, pool); + morkTable* table = store->OidToTable(ev, &tableOid); + if ( table ) // found or created such a table? + table->AddCellUse(ev); + } + } + } + else + this->NilBuilderCellError(ev); } diff --git a/mailnews/db/mork/src/morkBuilder.h b/mailnews/db/mork/src/morkBuilder.h index e1afa0257415..a41817726298 100644 --- a/mailnews/db/mork/src/morkBuilder.h +++ b/mailnews/db/mork/src/morkBuilder.h @@ -65,31 +65,31 @@ class morkBuilder /*d*/ : public morkParser { // after finding ends of group transactions, we can re-seek the start: // mork_pos mParser_GroupContentStartPos; // start of this group + // mdbOid mParser_TableOid; // table oid if inside a table + // mdbOid mParser_RowOid; // row oid if inside a row // mork_gid mParser_GroupId; // group ID if inside a group - // mork_tid mParser_TableId; // table ID if inside a table - // mork_rid mParser_RowId; // row ID if inside a row // mork_bool mParser_InPort; // called OnNewPort but not OnPortEnd? // mork_bool mParser_InDict; // called OnNewDict but not OnDictEnd? // mork_bool mParser_InCell; // called OnNewCell but not OnCellEnd? // mork_bool mParser_InMeta; // called OnNewMeta but not OnMetaEnd? - // morkAlias mParser_Alias; // current alias being parsed - // note that mParser_Alias.mAlias_Buf points at mParser_ScopeSpool below: + // morkMid mParser_Mid; // current alias being parsed + // note that mParser_Mid.mMid_Buf points at mParser_ScopeCoil below: - // blob spools allocated in mParser_Heap - // morkSpool mParser_ScopeSpool; // place to accumulate ID scope blobs - // morkSpool mParser_ValueSpool; // place to accumulate value blobs - // morkSpool mParser_ColumnSpool; // place to accumulate column blobs - // morkSpool mParser_StringSpool; // place to accumulate string blobs + // blob coils allocated in mParser_Heap + // morkCoil mParser_ScopeCoil; // place to accumulate ID scope blobs + // morkCoil mParser_ValueCoil; // place to accumulate value blobs + // morkCoil mParser_ColumnCoil; // place to accumulate column blobs + // morkCoil mParser_StringCoil; // place to accumulate string blobs - // morkSpoolSink mParser_ScopeSink; // writes to mParser_ScopeSpool - // morkSpoolSink mParser_ValueSink; // writes to mParser_ValueSpool - // morkSpoolSink mParser_ColumnSink; // writes to mParser_ColumnSpool - // morkSpoolSink mParser_StringSink; // writes to mParser_StringSpool + // morkSpool mParser_ScopeSpool; // writes to mParser_ScopeCoil + // morkSpool mParser_ValueSpool; // writes to mParser_ValueCoil + // morkSpool mParser_ColumnSpool; // writes to mParser_ColumnCoil + // morkSpool mParser_StringSpool; // writes to mParser_StringCoil // yarns allocated in mParser_Heap - // morkYarn mParser_AliasYarn; // place to receive from AliasToYarn() + // morkYarn mParser_MidYarn; // place to receive from MidToYarn() // span showing current ongoing file position status: // morkSpan mParser_PortSpan; // span of current db port file @@ -118,8 +118,8 @@ protected: // protected morkBuilder members morkRow* mBuilder_Row; // current row being built (or nil) morkCell* mBuilder_Cell; // current cell within CellsVec (or nil) - morkRowSpace* mBuilder_RowSpace; // space for mBuilder_CurrentRowScope - morkAtomSpace* mBuilder_AtomSpace; // space for mBuilder_CurrentAtomScope + morkRowSpace* mBuilder_RowSpace; // space for mBuilder_CellRowScope + morkAtomSpace* mBuilder_AtomSpace; // space for mBuilder_CellAtomScope morkAtomSpace* mBuilder_OidAtomSpace; // ground atom space for oids morkAtomSpace* mBuilder_ScopeAtomSpace; // ground atom space for scopes @@ -134,6 +134,8 @@ protected: // protected morkBuilder members mork_cscode mBuilder_a; // token for "a" mork_cscode mBuilder_t; // token for "t" + mork_token mBuilder_MorkNoneToken; // token for "mork:none" + // tokens that become set as the result of meta cells in port rows: mork_cscode mBuilder_PortForm; // default port charset format mork_scope mBuilder_PortRowScope; // port row scope @@ -151,21 +153,25 @@ protected: // protected morkBuilder members mork_scope mBuilder_RowAtomScope; // row atom scope // meta tokens currently in force, driven by meta info slots above: - mork_cscode mBuilder_CurrentForm; // current charset format - mork_scope mBuilder_CurrentRowScope; // current row scope - mork_scope mBuilder_CurrentAtomScope; // current atom scope + mork_cscode mBuilder_CellForm; // cell charset format + mork_scope mBuilder_CellAtomScope; // cell atom scope + + mork_cscode mBuilder_DictForm; // dict charset format + mork_scope mBuilder_DictAtomScope; // dict atom scope + + mork_token* mBuilder_MetaTokenSlot; // pointer to some slot above // If any of these 'cut' bools are true, it means a minus was seen in the // Mork source text to indicate removal of content from some container. // (Note there is no corresponding 'add' bool, since add is the default.) // CutRow implies the current row should be cut from the table. // CutCell implies the current column should be cut from the row. - mork_bool mBuilder_CutRow; // row with kCut change - mork_bool mBuilder_CutCell; // cell with kCut change + mork_bool mBuilder_DoCutRow; // row with kCut change + mork_bool mBuilder_DoCutCell; // cell with kCut change mork_u1 mBuilder_Pad1; // pad to u4 alignment mork_u1 mBuilder_Pad2; // pad to u4 alignment - morkCell mBuilder_CellsVec[ morkBuilder_kCellsVecSize ]; + morkCell mBuilder_CellsVec[ morkBuilder_kCellsVecSize + 1 ]; mork_fill mBuilder_CellsVecFill; // count used in CellsVec // Note when mBuilder_CellsVecFill equals morkBuilder_kCellsVecSize, and // another cell is added, this means all the cells in the vector above @@ -199,14 +205,28 @@ public: // dynamic type identification { return IsNode() && mNode_Derived == morkDerived_kBuilder; } // } ===== end morkNode methods ===== -public: // typing +public: // errors static void NonBuilderTypeError(morkEnv* ev); + static void NilBuilderCellError(morkEnv* ev); + static void NilBuilderRowError(morkEnv* ev); + static void NilBuilderTableError(morkEnv* ev); + static void NonColumnSpaceScopeError(morkEnv* ev); + + void LogGlitch(morkEnv* ev, const morkGlitch& inGlitch, + const char* inKind); + +public: // other builder methods + + morkCell* AddBuilderCell(morkEnv* ev, + const morkMid& inMid, mork_change inChange); + + void FlushBuilderCells(morkEnv* ev); // ````` ````` ````` ````` ````` ````` ````` ````` public: // in virtual morkParser methods, data flow subclass to parser - virtual void AliasToYarn(morkEnv* ev, - const morkAlias& inAlias, // typically an alias to concat with strings + virtual void MidToYarn(morkEnv* ev, + const morkMid& inMid, // typically an alias to concat with strings mdbYarn* outYarn); // The parser might ask that some aliases be turned into yarns, so they // can be concatenated into longer blobs under some circumstances. This @@ -216,60 +236,64 @@ public: // in virtual morkParser methods, data flow subclass to parser // ````` ````` ````` ````` ````` ````` ````` ````` public: // out virtual morkParser methods, data flow parser to subclass - virtual void OnNewPort(morkEnv* ev, const morkPlace& inPlace); - virtual void OnPortGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnPortEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnNewPort(morkEnv* ev, const morkPlace& inPlace); + virtual void OnPortGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnPortEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnNewGroup(morkEnv* ev, const morkPlace& inPlace, mork_gid inGid); - virtual void OnGroupGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnGroupCommitEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnGroupAbortEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnNewGroup(morkEnv* ev, const morkPlace& inPlace, mork_gid inGid); + virtual void OnGroupGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnGroupCommitEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnGroupAbortEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnNewPortRow(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange); - virtual void OnPortRowGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnNewPortRow(morkEnv* ev, const morkPlace& inPlace, + const morkMid& inMid, mork_change inChange); + virtual void OnPortRowGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange); - virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan); - - virtual void OnNewMeta(morkEnv* ev, const morkPlace& inPlace); - virtual void OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace, + const morkMid& inMid, mork_change inChange); + virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan); + + virtual void OnNewMeta(morkEnv* ev, const morkPlace& inPlace); + virtual void OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange); - virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace, + const morkMid& inMid, mork_change inChange); + virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnNewDict(morkEnv* ev, const morkPlace& inPlace); - virtual void OnDictGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnDictEnd(morkEnv* ev, const morkSpan& inSpan); + virtual void OnNewDict(morkEnv* ev, const morkPlace& inPlace); + virtual void OnDictGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnDictEnd(morkEnv* ev, const morkSpan& inSpan); - virtual void OnAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias); + virtual void OnAlias(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid); - virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange); - virtual void OnCellGlitch(morkEnv* ev, const morkGlitch& inGlitch); - virtual void OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat); - virtual void OnCellEnd(morkEnv* ev, const morkSpan& inSpan); - - virtual void OnValue(morkEnv* ev, const morkSpan& inSpan, - const morkBuf& inBuf); + virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace, + const morkMid* inMid, const morkBuf* inBuf, mork_change inChange); + // Exactly one of inMid and inBuf is nil, and the other is non-nil. + // When hex ID syntax is used for a column, then inMid is not nil, and + // when a naked string names a column, then inBuf is not nil. - virtual void OnValueAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias); + virtual void OnCellGlitch(morkEnv* ev, const morkGlitch& inGlitch); + virtual void OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat); + virtual void OnCellEnd(morkEnv* ev, const morkSpan& inSpan); + + virtual void OnValue(morkEnv* ev, const morkSpan& inSpan, + const morkBuf& inBuf); - virtual void OnRowAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias); + virtual void OnValueMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid); - virtual void OnTableAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias); + virtual void OnRowMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid); + + virtual void OnTableMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid); // ````` ````` ````` ````` ````` ````` ````` ````` public: // public non-poly morkBuilder methods diff --git a/mailnews/db/mork/src/morkCell.cpp b/mailnews/db/mork/src/morkCell.cpp index f6f547c1c10c..62c0b837b87f 100644 --- a/mailnews/db/mork/src/morkCell.cpp +++ b/mailnews/db/mork/src/morkCell.cpp @@ -46,9 +46,6 @@ //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 -// ````` ````` ````` ````` ````` -// { ===== begin morkNode interface ===== - void morkCell::SetYarn(morkEnv* ev, const mdbYarn* inYarn, morkStore* ioStore) { diff --git a/mailnews/db/mork/src/morkCell.h b/mailnews/db/mork/src/morkCell.h index b0c3bb580bd7..93f6977823f3 100644 --- a/mailnews/db/mork/src/morkCell.h +++ b/mailnews/db/mork/src/morkCell.h @@ -40,6 +40,9 @@ public: public: morkCell() : mCell_Atom( 0 ), mCell_Delta( 0 ) { } + + morkCell(const morkCell& c) + : mCell_Atom( c.mCell_Atom ), mCell_Delta( c.mCell_Delta ) { } // note if ioAtom is non-nil, caller needs to call ioAtom->AddCellUse(): morkCell(mork_column inCol, mork_change inChange, morkAtom* ioAtom) diff --git a/mailnews/db/mork/src/morkConfig.cpp b/mailnews/db/mork/src/morkConfig.cpp index d2822b1f9785..d62be2b7a696 100644 --- a/mailnews/db/mork/src/morkConfig.cpp +++ b/mailnews/db/mork/src/morkConfig.cpp @@ -30,8 +30,8 @@ //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 -/* ----- ----- ----- ----- MORK_MAC ----- ----- ----- ----- */ -#ifdef MORK_MAC +/* ----- ----- ----- ----- MORK_OBSOLETE ----- ----- ----- ----- */ +#ifdef MORK_OBSOLETE #include @@ -58,14 +58,14 @@ DebugStr(pascalStr); /* call Mac debugger entry point */ } -#endif /*MORK_MAC*/ -/* ----- ----- ----- ----- MORK_MAC ----- ----- ----- ----- */ +#endif /*MORK_OBSOLETE*/ +/* ----- ----- ----- ----- MORK_OBSOLETE ----- ----- ----- ----- */ void mork_assertion_signal(const char* inMessage) { -#ifdef XP_MAC +#ifdef MORK_OBSOLETE mork_mac_break_string(inMessage); -#endif /*XP_MAC*/ +#endif /*MORK_OBSOLETE*/ #ifdef MORK_WIN // asm { int 3 } diff --git a/mailnews/db/mork/src/morkConfig.h b/mailnews/db/mork/src/morkConfig.h index 7ba7d0072406..1148a7c91a53 100644 --- a/mailnews/db/mork/src/morkConfig.h +++ b/mailnews/db/mork/src/morkConfig.h @@ -32,6 +32,7 @@ // { %%%%% begin platform defs peculiar to Mork %%%%% #ifdef XP_MAC #define MORK_MAC 1 +#define MORK_OBSOLETE 1 #endif #ifdef XP_OS2 @@ -46,9 +47,14 @@ #ifdef XP_UNIX #define MORK_UNIX 1 #endif + +#ifdef MORK_OBSOLETE +#undef MORK_MAC +#endif + // } %%%%% end platform defs peculiar to Mork %%%%% -#if defined (MORK_WIN) || defined(MORK_UNIX) +#if defined(MORK_WIN) || defined(MORK_UNIX) || defined(MORK_MAC) #include "stdio.h" #include "ctype.h" #include "errno.h" @@ -60,12 +66,12 @@ #define MORK_FILETELL(file) ftell(file) #define MORK_FILESEEK(file, where, how) fseek(file, where, how) -#define MORK_FILEREAD(outbuf, insize, file) fread(outbuf, insize, 1, file) +#define MORK_FILEREAD(outbuf, insize, file) fread(outbuf, 1, insize, file) #define MORK_FILEFLUSH(file) fflush(file) #define MORK_FILECLOSE(file) fclose(file) #endif /*MORK_WIN*/ -#ifdef MORK_MAC +#ifdef MORK_OBSOLETE #include "xp_file.h" #include "ctype.h" @@ -76,17 +82,17 @@ #define MORK_FILEREAD(outbuf, insize, file) XP_FileRead(outbuf, insize, file) #define MORK_FILEFLUSH(file) XP_FileFlush(file) #define MORK_FILECLOSE(file) XP_FileClose(file) -#endif /*MORK_MAC*/ +#endif /*MORK_OBSOLETE*/ /* ===== ===== ===== ===== line characters ===== ===== ===== ===== */ -#define mork_kCR '\015' -#define mork_kLF '\012' +#define mork_kCR 0x0D +#define mork_kLF 0x0A #define mork_kVTAB '\013' #define mork_kFF '\014' #define mork_kTAB '\011' #define mork_kCRLF "\015\012" /* A CR LF equivalent string */ -#ifdef MORK_MAC +#if defined(MORK_MAC) || defined(MORK_OBSOLETE) # define mork_kNewline "\015" # define mork_kNewlineSize 1 #else @@ -113,18 +119,14 @@ extern void mork_assertion_signal(const char* inMessage); // { %%%%% begin standard c utility methods %%%%% /*define MORK_USE_XP_STDLIB 1*/ -#ifdef MORK_MAC +#ifdef MORK_OBSOLETE #define MORK_PROVIDE_STDLIB 1 -#endif /*MORK_MAC*/ +#endif /*MORK_OBSOLETE*/ -#ifdef MORK_WIN +#if defined(MORK_WIN) || defined(MORK_UNIX) || defined(MORK_MAC) #define MORK_USE_C_STDLIB 1 #endif /*MORK_WIN*/ -#ifdef MORK_UNIX -#define MORK_USE_NSPR_STDLIB 1 -#endif - #ifdef MORK_USE_C_STDLIB #define MORK_MEMCMP(src1,src2,size) memcmp(src1,src2,size) #define MORK_MEMCPY(dest,src,size) memcpy(dest,src,size) @@ -167,16 +169,6 @@ MORK_LIB(mork_size) mork_strlen(const void* inString); #define MORK_STRLEN(string) XP_STRLEN(string) #endif /*MORK_USE_XP_STDLIB*/ -#ifdef MORK_USE_NSPR_STDLIB -#define MORK_MEMCMP(src1,src2, size) memcmp(src1, src2, size) -#define MORK_MEMCPY(src1,src2, size) memcpy(src1, src2, size) -#define MORK_MEMMOVE(dest, src, size) memmove(src1, src2, size) -#define MORK_MEMSET(dest,byte,size) memset(dest,byte,size) -#define MORK_STRCPY(dest,src) PL_strcpy(dest,src) -#define MORK_STRCMP(one,two) PL_strcmp(one,two) -#define MORK_STRNCMP(one,two,length) PL_strncmp(one,two,length) -#define MORK_STRLEN(string) PL_strlen(string) -#endif // } %%%%% end standard c utility methods %%%%% diff --git a/mailnews/db/mork/src/morkFile.cpp b/mailnews/db/mork/src/morkFile.cpp index 5436caa3612d..d521eeb78f6a 100644 --- a/mailnews/db/mork/src/morkFile.cpp +++ b/mailnews/db/mork/src/morkFile.cpp @@ -221,7 +221,7 @@ morkFile::NewFileErrnoError(morkEnv* ev) const // ````` ````` ````` ````` newlines ````` ````` ````` ````` -#ifdef MORK_MAC +#if defined(MORK_MAC) || defined(MORK_OBSOLETE) static const char* morkFile_kNewlines = "\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015"; # define morkFile_kNewlinesCount 16 @@ -314,7 +314,7 @@ morkStdioFile::OpenOldStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap, morkStdioFile* outFile = 0; if ( ioHeap && inFilePath ) { - const char* mode = (inFrozen)? "rb" : "wb"; + const char* mode = (inFrozen)? "rb" : "rb+"; outFile = new(*ioHeap, ev) morkStdioFile(ev, morkUsage::kHeap, ioHeap, ioHeap, inFilePath, mode); diff --git a/mailnews/db/mork/src/morkParser.cpp b/mailnews/db/mork/src/morkParser.cpp index bfec6374e7ee..077bf2830ce5 100644 --- a/mailnews/db/mork/src/morkParser.cpp +++ b/mailnews/db/mork/src/morkParser.cpp @@ -52,13 +52,17 @@ #include "morkSink.h" #endif +#ifndef _MORKCH_ +#include "morkCh.h" +#endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 // ````` ````` ````` ````` ````` // { ===== begin morkNode interface ===== /*public virtual*/ void -morkParser::CloseMorkNode(morkEnv* ev) /*i*/ // CloseParser() only if open +morkParser::CloseMorkNode(morkEnv* ev) // CloseParser() only if open { if ( this->IsOpenNode() ) { @@ -69,14 +73,14 @@ morkParser::CloseMorkNode(morkEnv* ev) /*i*/ // CloseParser() only if open } /*public virtual*/ -morkParser::~morkParser() /*i*/ // assert CloseParser() executed earlier +morkParser::~morkParser() // assert CloseParser() executed earlier { MORK_ASSERT(mParser_Heap==0); MORK_ASSERT(mParser_Stream==0); } /*public non-poly*/ -morkParser::morkParser(morkEnv* ev, /*i*/ +morkParser::morkParser(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap, morkStream* ioStream, mdb_count inBytesPerParseSegment, nsIMdbHeap* ioSlotHeap) @@ -88,8 +92,9 @@ morkParser::morkParser(morkEnv* ev, /*i*/ , mParser_GroupContentStartPos( 0 ) -, mParser_TableId( 0 ) -, mParser_RowId( 0 ) +, mParser_TableMid( ) +, mParser_RowMid( ) +, mParser_CellMid( ) , mParser_InPort( morkBool_kFalse ) , mParser_InDict( morkBool_kFalse ) @@ -97,41 +102,58 @@ morkParser::morkParser(morkEnv* ev, /*i*/ , mParser_InMeta( morkBool_kFalse ) , mParser_InPortRow( morkBool_kFalse ) +, mParser_InRow( morkBool_kFalse ) +, mParser_InTable( morkBool_kFalse ) +, mParser_InGroup( morkBool_kFalse ) + +, mParser_AtomChange( morkChange_kNil ) +, mParser_CellChange( morkChange_kNil ) +, mParser_RowChange( morkChange_kNil ) +, mParser_TableChange( morkChange_kNil ) + +, mParser_Change( morkChange_kNil ) , mParser_IsBroken( morkBool_kFalse ) , mParser_IsDone( morkBool_kFalse ) +, mParser_DoMore( morkBool_kTrue ) -, mParser_Alias() +, mParser_Mid() -, mParser_ScopeSpool(ev, ioHeap) -, mParser_ValueSpool(ev, ioHeap) -, mParser_ColumnSpool(ev, ioHeap) -, mParser_StringSpool(ev, ioHeap) +, mParser_ScopeCoil(ev, ioSlotHeap) +, mParser_ValueCoil(ev, ioSlotHeap) +, mParser_ColumnCoil(ev, ioSlotHeap) +, mParser_StringCoil(ev, ioSlotHeap) -, mParser_ScopeSink(ev, &mParser_ScopeSpool) -, mParser_ValueSink(ev, &mParser_ValueSpool) -, mParser_ColumnSink(ev, &mParser_ColumnSpool) -, mParser_StringSink(ev, &mParser_StringSpool) +, mParser_ScopeSpool(ev, &mParser_ScopeCoil) +, mParser_ValueSpool(ev, &mParser_ValueCoil) +, mParser_ColumnSpool(ev, &mParser_ColumnCoil) +, mParser_StringSpool(ev, &mParser_StringCoil) -, mParser_AliasYarn(ev, morkUsage_kMember, ioHeap) +, mParser_MidYarn(ev, morkUsage_kMember, ioSlotHeap) { - ev->StubMethodOnlyError(); - if ( inBytesPerParseSegment < morkParser_kMinGranularity ) inBytesPerParseSegment = morkParser_kMinGranularity; else if ( inBytesPerParseSegment > morkParser_kMaxGranularity ) inBytesPerParseSegment = morkParser_kMaxGranularity; mParser_MoreGranularity = inBytesPerParseSegment; - - if ( ev->Good() ) + + if ( ioSlotHeap && ioStream ) { - mParser_Tag = morkParser_kTag; - mNode_Derived = morkDerived_kParser; + nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mParser_Heap); + morkStream::SlotStrongStream(ioStream, ev, &mParser_Stream); + + if ( ev->Good() ) + { + mParser_Tag = morkParser_kTag; + mNode_Derived = morkDerived_kParser; + } } + else + ev->NilPointerError(); } /*public non-poly*/ void -morkParser::CloseParser(morkEnv* ev) /*i*/ // called by CloseMorkNode(); +morkParser::CloseParser(morkEnv* ev) // called by CloseMorkNode(); { if ( this ) { @@ -139,10 +161,10 @@ morkParser::CloseParser(morkEnv* ev) /*i*/ // called by CloseMorkNode(); { if ( !this->IsShutNode() ) { - mParser_ScopeSpool.CloseSpool(ev); - mParser_ValueSpool.CloseSpool(ev); - mParser_ColumnSpool.CloseSpool(ev); - mParser_StringSpool.CloseSpool(ev); + mParser_ScopeCoil.CloseCoil(ev); + mParser_ValueCoil.CloseCoil(ev); + mParser_ColumnCoil.CloseCoil(ev); + mParser_StringCoil.CloseCoil(ev); nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mParser_Heap); morkStream::SlotStrongStream((morkStream*) 0, ev, &mParser_Stream); this->MarkShut(); @@ -158,19 +180,6 @@ morkParser::CloseParser(morkEnv* ev) /*i*/ // called by CloseMorkNode(); // } ===== end morkNode methods ===== // ````` ````` ````` ````` ````` -/*public non-poly*/ void -morkParser::SetParserStream(morkEnv* ev, morkStream* ioStream) -{ - morkStream* stream = mParser_Stream; - if ( stream ) - { - mParser_Stream = 0; - stream->CutStrongRef(ev); - } - if ( ioStream && ioStream->AddStrongRef(ev) ) - mParser_Stream = ioStream; -} - /*protected non-poly*/ void morkParser::NonGoodParserError(morkEnv* ev) // when GoodParserTag() is false { @@ -202,114 +211,871 @@ morkParser::NonUsableParserError(morkEnv* ev) // /*protected non-poly*/ void morkParser::StartParse(morkEnv* ev) { + mParser_InCell = morkBool_kFalse; + mParser_InMeta = morkBool_kFalse; + mParser_InDict = morkBool_kFalse; + mParser_InPortRow = morkBool_kFalse; + + mParser_RowMid.ClearMid(); + mParser_TableMid.ClearMid(); + mParser_CellMid.ClearMid(); + + mParser_GroupId = 0; + mParser_InPort = morkBool_kTrue; + + mParser_GroupSpan.ClearSpan(); + mParser_DictSpan.ClearSpan(); + mParser_AliasSpan.ClearSpan(); + mParser_MetaSpan.ClearSpan(); + mParser_TableSpan.ClearSpan(); + mParser_RowSpan.ClearSpan(); + mParser_CellSpan.ClearSpan(); + mParser_ColumnSpan.ClearSpan(); + mParser_SlotSpan.ClearSpan(); + + mParser_PortSpan.ClearSpan(); } /*protected non-poly*/ void morkParser::StopParse(morkEnv* ev) { - if ( mParser_InCell ) - { - mParser_InCell = morkBool_kFalse; - mParser_CellSpan.SetEndWithEnd(mParser_PortSpan); - this->OnCellEnd(ev, mParser_CellSpan); - } - if ( mParser_InMeta ) - { - mParser_InMeta = morkBool_kFalse; - mParser_MetaSpan.SetEndWithEnd(mParser_PortSpan); - this->OnMetaEnd(ev, mParser_MetaSpan); - } - if ( mParser_InPortRow ) - { - mParser_InPortRow = morkBool_kFalse; - mParser_RowSpan.SetEndWithEnd(mParser_PortSpan); - this->OnPortRowEnd(ev, mParser_RowSpan); - } - if ( mParser_RowId ) - { - mParser_RowId = 0; - mParser_RowSpan.SetEndWithEnd(mParser_PortSpan); - this->OnRowEnd(ev, mParser_RowSpan); - } - if ( mParser_TableId ) - { - mParser_TableId = 0; - mParser_TableSpan.SetEndWithEnd(mParser_PortSpan); - this->OnTableEnd(ev, mParser_TableSpan); - } - if ( mParser_GroupId ) - { - mParser_GroupId = 0; - mParser_GroupSpan.SetEndWithEnd(mParser_PortSpan); - this->OnGroupAbortEnd(ev, mParser_GroupSpan); - } - if ( mParser_InPort ) - { - mParser_InPort = morkBool_kFalse; - this->OnPortEnd(ev, mParser_PortSpan); - } + if ( mParser_InCell ) + { + mParser_InCell = morkBool_kFalse; + mParser_CellSpan.SetEndWithEnd(mParser_PortSpan); + this->OnCellEnd(ev, mParser_CellSpan); + } + if ( mParser_InMeta ) + { + mParser_InMeta = morkBool_kFalse; + mParser_MetaSpan.SetEndWithEnd(mParser_PortSpan); + this->OnMetaEnd(ev, mParser_MetaSpan); + } + if ( mParser_InDict ) + { + mParser_InDict = morkBool_kFalse; + mParser_DictSpan.SetEndWithEnd(mParser_PortSpan); + this->OnDictEnd(ev, mParser_DictSpan); + } + if ( mParser_InPortRow ) + { + mParser_InPortRow = morkBool_kFalse; + mParser_RowSpan.SetEndWithEnd(mParser_PortSpan); + this->OnPortRowEnd(ev, mParser_RowSpan); + } + if ( mParser_InRow ) + { + mParser_InRow = morkBool_kFalse; + mParser_RowMid.ClearMid(); + mParser_RowSpan.SetEndWithEnd(mParser_PortSpan); + this->OnRowEnd(ev, mParser_RowSpan); + } + if ( mParser_InTable ) + { + mParser_InTable = morkBool_kFalse; + mParser_TableMid.ClearMid(); + mParser_TableSpan.SetEndWithEnd(mParser_PortSpan); + this->OnTableEnd(ev, mParser_TableSpan); + } + if ( mParser_GroupId ) + { + mParser_GroupId = 0; + mParser_GroupSpan.SetEndWithEnd(mParser_PortSpan); + this->OnGroupAbortEnd(ev, mParser_GroupSpan); + } + if ( mParser_InPort ) + { + mParser_InPort = morkBool_kFalse; + this->OnPortEnd(ev, mParser_PortSpan); + } } -///*protected non-poly*/ int -//morkParser::NextChar(morkEnv* ev) -//{ -//} - -/*protected non-poly*/ int -morkParser::NextChar(morkEnv* ev) // next non-white content +int morkParser::eat_comment(morkEnv* ev) // last char was '/' { - register int c; // the most heavily used character variable - int outChar = -1; // the byte to return from this method - int d; // the byte after c on some occasions morkStream* s = mParser_Stream; - if ( s ) + // Note morkStream::Getc() returns EOF when an error occurs, so + // we don't need to check for both c != EOF and ev->Good() below. + + register int c = s->Getc(ev); + if ( c == '/' ) // C++ style comment? { - while ( outChar == -1 && ev->Good() ) + while ( (c = s->Getc(ev)) != EOF && c != 0xA && c != 0xD ) + /* empty */; + + if ( c == 0xA || c == 0xD ) + c = this->eat_line_break(ev, c); + } + else if ( c == '*' ) /* C style comment? */ + { + int depth = 1; // count depth of comments until depth reaches zero + + while ( depth > 0 && c != EOF ) // still looking for comment end(s)? { - while ( (c = s->Getc(ev)) != EOF && ev->Good() ) + while ( (c = s->Getc(ev)) != EOF && c != '/' && c != '*' ) { - if ( c == 0xA || c == 0xD ) // end of line? + if ( c == 0xA || c == 0xD ) // need to count a line break? { - this->AddLine(); - d = s->Getc(ev); // look for another byte in #xA #xD, or #xD #xA - if (( d == 0xA || d == 0xD ) && c != d ) // eat this one too? - { - } - else if ( d != EOF ) // not trying to push back end of file - s->Ungetc(d); + c = this->eat_line_break(ev, c); + if ( c == '/' || c == '*' ) + break; // end while loop } } - - if ( c == '/' ) // maybe start of comment? + + if ( c == '*' ) // maybe end of a comment, if next char is '/'? { - int depth = 0; + if ( (c = s->Getc(ev)) == '/' ) // end of comment? + --depth; // depth of comments has decreased by one + else if ( c != EOF ) // need to put the char back? + s->Ungetc(c); // especially need to put back '*', 0xA, or 0xD } - else if ( c == '\\' ) // maybe start of line continuation? + else if ( c == '/' ) // maybe nested comemnt, if next char is '*'? { - if ( (c = s->Getc(ev)) == 0xA || c == 0xD ) - ; - } - - if ( c == EOF ) // reached end of file? - { - if ( outChar == -1 ) - outChar = 1; // end while loop - mParser_DoMore = morkBool_kFalse; - mParser_IsDone = morkBool_kTrue; + if ( (c = s->Getc(ev)) == '*' ) // nested comment? + ++depth; // depth of comments has increased by one + else if ( c != EOF ) // need to put the char back? + s->Ungetc(c); // especially need to put back '/', 0xA, or 0xD } + + if ( ev->Bad() ) + c = EOF; } - - this->SetHerePos(s->Tell(ev)); + if ( c == EOF && depth > 0 ) + ev->NewWarning("EOF before end of comment"); } - else // nil stream pointer + else + ev->NewWarning("expected / or *"); + + return c; +} + +int morkParser::eat_line_break(morkEnv* ev, int inLast) +{ + morkStream* s = mParser_Stream; + register int c = s->Getc(ev); // get next char after 0xA or 0xD + this->CountLineBreak(); + if ( c == 0xA || c == 0xD ) // another line break character? + { + if ( c != inLast ) // not the same as the last one? + c = s->Getc(ev); // get next char after two-byte linebreak + } + return c; +} + +int morkParser::eat_line_continue(morkEnv* ev) // last char was '\\' +{ + morkStream* s = mParser_Stream; + register int c = s->Getc(ev); + if ( c == 0xA || c == 0xD ) // linebreak follows \ as expected? + { + c = this->eat_line_break(ev, c); + } + else + ev->NewWarning("expected linebreak"); + + return c; +} + +int morkParser::NextChar(morkEnv* ev) // next non-white content +{ + morkStream* s = mParser_Stream; + register int c = s->Getc(ev); + while ( c > 0 && ev->Good() ) + { + if ( c == '/' ) + c = this->eat_comment(ev); + else if ( c == 0xA || c == 0xD ) + c = this->eat_line_break(ev, c); + else if ( c == '\\' ) + c = this->eat_line_continue(ev); + else if ( morkCh_IsWhite(c) ) + c = s->Getc(ev); + else + break; // end while loop when return c is acceptable + } + if ( ev->Bad() ) { - ev->NilPointerError(); mParser_State = morkParser_kBrokenState; mParser_DoMore = morkBool_kFalse; mParser_IsDone = morkBool_kTrue; mParser_IsBroken = morkBool_kTrue; + c = EOF; } - return outChar; + else if ( c == EOF ) + { + mParser_DoMore = morkBool_kFalse; + mParser_IsDone = morkBool_kTrue; + } + return c; +} + +void +morkParser::OnCellState(morkEnv* ev) +{ + ev->StubMethodOnlyError(); +} + +void +morkParser::OnMetaState(morkEnv* ev) +{ + ev->StubMethodOnlyError(); +} + +void +morkParser::OnRowState(morkEnv* ev) +{ + ev->StubMethodOnlyError(); +} + +void +morkParser::OnTableState(morkEnv* ev) +{ + ev->StubMethodOnlyError(); +} + +void +morkParser::OnDictState(morkEnv* ev) +{ + ev->StubMethodOnlyError(); +} + +morkBuf* morkParser::ReadName(morkEnv* ev, register int c) +{ + morkBuf* outBuf = 0; + + if ( !morkCh_IsName(c) ) + ev->NewError("not a name char"); + + morkCoil* coil = &mParser_ColumnCoil; + coil->ClearBufFill(); + + morkSpool* spool = &mParser_ColumnSpool; + spool->Seek(ev, /*pos*/ 0); + + if ( ev->Good() ) + { + spool->Putc(ev, c); + + morkStream* s = mParser_Stream; + while ( (c = s->Getc(ev)) != EOF && morkCh_IsMore(c) && ev->Good() ) + spool->Putc(ev, c); + + if ( ev->Good() ) + { + if ( c != EOF ) + { + s->Ungetc(c); + spool->FlushSink(ev); // update coil->mBuf_Fill + } + else + this->UnexpectedEofError(ev); + + if ( ev->Good() ) + outBuf = coil; + } + } + return outBuf; +} + +mork_bool +morkParser::ReadMid(morkEnv* ev, morkMid* outMid) +{ + outMid->ClearMid(); + + morkStream* s = mParser_Stream; + int next; + outMid->mMid_Oid.mOid_Id = this->ReadHex(ev, &next); + register int c = next; + if ( c == ':' ) + { + if ( (c = s->Getc(ev)) != EOF && ev->Good() ) + { + if ( c == '^' ) + { + outMid->mMid_Oid.mOid_Scope = this->ReadHex(ev, &next); + if ( ev->Good() ) + s->Ungetc(next); + } + else if ( morkCh_IsName(c) ) + { + outMid->mMid_Buf = this->ReadName(ev, c); + } + else + ev->NewError("expected name or hex after ':' following ID"); + } + + if ( c == EOF && ev->Good() ) + this->UnexpectedEofError(ev); + } + else + s->Ungetc(c); + + return ev->Good(); +} + +void +morkParser::ReadCell(morkEnv* ev) +{ + mParser_CellMid.ClearMid(); + this->StartSpanOnLastByte(ev, &mParser_CellSpan); + morkMid* cellMid = 0; // if mid syntax is used for column + morkBuf* cellBuf = 0; // if naked string is used for column + + morkStream* s = mParser_Stream; + register int c; + if ( (c = s->Getc(ev)) != EOF && ev->Good() ) + { + this->StartSpanOnLastByte(ev, &mParser_ColumnSpan); + if ( c == '^' ) + { + cellMid = &mParser_CellMid; + this->ReadMid(ev, cellMid); + // if ( !mParser_CellMid.mMid_Oid.mOid_Scope ) + // mParser_CellMid.mMid_Oid.mOid_Scope = (mork_scope) 'c'; + } + else + { + cellBuf = this->ReadName(ev, c); + } + if ( ev->Good() ) + { + this->EndSpanOnThisByte(ev, &mParser_ColumnSpan); + + mParser_InCell = morkBool_kTrue; + this->OnNewCell(ev, *mParser_CellSpan.AsPlace(), + cellMid, cellBuf, mParser_CellChange); + + if ( (c = this->NextChar(ev)) != EOF && ev->Good() ) + { + this->StartSpanOnLastByte(ev, &mParser_SlotSpan); + if ( c == '=' ) + { + morkBuf* buf = this->ReadValue(ev); + if ( buf ) + { + this->EndSpanOnThisByte(ev, &mParser_SlotSpan); + this->OnValue(ev, mParser_SlotSpan, *buf); + } + } + else if ( c == '^' ) + { + if ( this->ReadMid(ev, &mParser_Mid) ) + { + this->EndSpanOnThisByte(ev, &mParser_SlotSpan); + if ( (c = this->NextChar(ev)) != EOF && ev->Good() ) + { + if ( c != ')' ) + ev->NewError("expected ')' after cell ^ID value"); + } + else if ( c == EOF ) + this->UnexpectedEofError(ev); + + if ( ev->Good() ) + this->OnValueMid(ev, mParser_SlotSpan, mParser_Mid); + } + } + else if ( c == 'r' || c == 't' || c == '"' || c == '\'' ) + { + ev->NewError("cell syntax not yet supported"); + } + else + { + ev->NewError("unknown cell syntax"); + } + } + + this->EndSpanOnThisByte(ev, &mParser_CellSpan); + mParser_InCell = morkBool_kFalse; + this->OnCellEnd(ev, mParser_CellSpan); + } + } + + if ( c == EOF && ev->Good() ) + this->UnexpectedEofError(ev); +} + +void morkParser::ReadRow(morkEnv* ev, int c) +// zm:Row ::= zm:S? '[' zm:S? zm:Id zm:RowItem* zm:S? ']' +// zm:RowItem ::= zm:MetaRow | zm:Cell +// zm:MetaRow ::= zm:S? '[' zm:S? zm:Cell* zm:S? ']' /* meta attributes */ +// zm:Cell ::= zm:S? '(' zm:Column zm:S? zm:Slot? ')' +{ + if ( ev->Good() ) + { + this->StartSpanOnLastByte(ev, &mParser_RowSpan); + if ( mParser_Change ) + mParser_RowChange = mParser_Change; + + if ( c == '[' ) + { + if ( this->ReadMid(ev, &mParser_RowMid) ) + { + mParser_InRow = morkBool_kTrue; + this->OnNewRow(ev, *mParser_RowSpan.AsPlace(), + mParser_RowMid, mParser_RowChange); + + mParser_Change = mParser_RowChange = morkChange_kNil; + + while ( (c = this->NextChar(ev)) != EOF && ev->Good() && c != ']' ) + { + switch ( c ) + { + case '(': // cell + this->ReadCell(ev); + break; + + case '[': // meta + this->ReadMeta(ev, ']'); + break; + + case '+': // plus + mParser_CellChange = morkChange_kAdd; + break; + + case '-': // minus + mParser_CellChange = morkChange_kCut; + break; + + case '!': // bang + mParser_CellChange = morkChange_kSet; + break; + + default: + ev->NewWarning("unexpected byte in row"); + break; + } // switch + } // while + + this->EndSpanOnThisByte(ev, &mParser_RowSpan); + mParser_InRow = morkBool_kFalse; + this->OnRowEnd(ev, mParser_RowSpan); + + } // if ReadMid + } // if '[' + + else // c != '[' + { + morkStream* s = mParser_Stream; + s->Ungetc(c); + if ( this->ReadMid(ev, &mParser_RowMid) ) + { + mParser_InRow = morkBool_kTrue; + this->OnNewRow(ev, *mParser_RowSpan.AsPlace(), + mParser_RowMid, mParser_RowChange); + + mParser_Change = mParser_RowChange = morkChange_kNil; + + this->EndSpanOnThisByte(ev, &mParser_RowSpan); + mParser_InRow = morkBool_kFalse; + this->OnRowEnd(ev, mParser_RowSpan); + } + } + } + + if ( ev->Bad() ) + mParser_State = morkParser_kBrokenState; + else if ( c == EOF ) + mParser_State = morkParser_kDoneState; +} + +void morkParser::ReadTable(morkEnv* ev) +// zm:Table ::= zm:S? '{' zm:S? zm:Id zm:TableItem* zm:S? '}' +// zm:TableItem ::= zm:MetaTable | zm:RowRef | zm:Row +// zm:MetaTable ::= zm:S? '{' zm:S? zm:Cell* zm:S? '}' /* meta attributes */ +{ + this->StartSpanOnLastByte(ev, &mParser_TableSpan); + + if ( mParser_Change ) + mParser_TableChange = mParser_Change; + + if ( ev->Good() && this->ReadMid(ev, &mParser_TableMid) ) + { + mParser_InTable = morkBool_kTrue; + this->OnNewTable(ev, *mParser_TableSpan.AsPlace(), + mParser_TableMid, mParser_TableChange); + + mParser_Change = mParser_TableChange = morkChange_kNil; + + int c; + while ( (c = this->NextChar(ev)) != EOF && ev->Good() && c != '}' ) + { + if ( morkCh_IsHex(c) ) + { + this->ReadRow(ev, c); + } + else + { + switch ( c ) + { + case '[': // row + this->ReadRow(ev, '['); + break; + + case '{': // meta + this->ReadMeta(ev, '}'); + break; + + case '+': // plus + mParser_RowChange = morkChange_kAdd; + break; + + case '-': // minus + mParser_RowChange = morkChange_kCut; + break; + + case '!': // bang + mParser_RowChange = morkChange_kSet; + break; + + default: + ev->NewWarning("unexpected byte in table"); + break; + } + } + } + + this->EndSpanOnThisByte(ev, &mParser_TableSpan); + mParser_InTable = morkBool_kFalse; + this->OnTableEnd(ev, mParser_TableSpan); + + if ( ev->Bad() ) + mParser_State = morkParser_kBrokenState; + else if ( c == EOF ) + mParser_State = morkParser_kDoneState; + } +} + +mork_id morkParser::ReadHex(morkEnv* ev, int* outNextChar) +// zm:Hex ::= [0-9a-fA-F] /* a single hex digit */ +// zm:Hex+ ::= zm:Hex | zm:Hex zm:Hex+ +{ + mork_id hex = 0; + + morkStream* s = mParser_Stream; + register int c = this->NextChar(ev); + + if ( ev->Good() ) + { + if ( c != EOF ) + { + if ( morkCh_IsHex(c) ) + { + do + { + if ( morkCh_IsDigit(c) ) // '0' through '9'? + c -= '0'; + else if ( morkCh_IsUpper(c) ) // 'A' through 'F'? + c -= ('A' - 10) ; // c = (c - 'A') + 10; + else // 'a' through 'f'? + c -= ('a' - 10) ; // c = (c - 'a') + 10; + + hex = (hex << 4) + c; + } + while ( (c = s->Getc(ev)) != EOF && ev->Good() && morkCh_IsHex(c) ); + } + else + this->ExpectedHexDigitError(ev, c); + } + } + if ( c == EOF ) + this->EofInsteadOfHexError(ev); + + *outNextChar = c; + return hex; +} + +/*static*/ void +morkParser::EofInsteadOfHexError(morkEnv* ev) +{ + ev->NewWarning("eof instead of hex"); +} + +/*static*/ void +morkParser::ExpectedHexDigitError(morkEnv* ev, int c) +{ + ev->NewWarning("expected hex digit"); +} + +/*static*/ void +morkParser::ExpectedEqualError(morkEnv* ev) +{ + ev->NewWarning("expected '='"); +} + +/*static*/ void +morkParser::UnexpectedEofError(morkEnv* ev) +{ + ev->NewWarning("unexpected eof"); +} + +morkBuf* morkParser::ReadValue(morkEnv* ev) +{ + morkBuf* outBuf = 0; + + morkCoil* coil = &mParser_ValueCoil; + coil->ClearBufFill(); + + morkSpool* spool = &mParser_ValueSpool; + spool->Seek(ev, /*pos*/ 0); + + if ( ev->Good() ) + { + morkStream* s = mParser_Stream; + register int c; + while ( (c = s->Getc(ev)) != EOF && c != ')' && ev->Good() ) + { + if ( c == '\\' ) // "\" escapes the next char? + { + if ( (c = s->Getc(ev)) == EOF || ev->Bad() ) + break; // end while loop + } + spool->Putc(ev, c); + } + + if ( ev->Good() ) + { + if ( c != EOF ) + spool->FlushSink(ev); // update coil->mBuf_Fill + else + this->UnexpectedEofError(ev); + + if ( ev->Good() ) + outBuf = coil; + } + } + return outBuf; +} + +void morkParser::ReadAlias(morkEnv* ev) +// zm:Alias ::= zm:S? '(' ('#')? zm:Hex+ zm:S? zm:Value ')' +// zm:Value ::= '=' ([^)$\] | '\' zm:NonCRLF | zm:Continue | zm:Dollar)* +{ + this->StartSpanOnLastByte(ev, &mParser_AliasSpan); + + int nextChar; + mork_id hex = this->ReadHex(ev, &nextChar); + register int c = nextChar; + + mParser_Mid.ClearMid(); + mParser_Mid.mMid_Oid.mOid_Id = hex; + + if ( morkCh_IsWhite(c) && ev->Good() ) + c = this->NextChar(ev); + + if ( ev->Good() ) + { + if ( c == '=' ) + { + mParser_Mid.mMid_Buf = this->ReadValue(ev); + if ( mParser_Mid.mMid_Buf ) + { + this->EndSpanOnThisByte(ev, &mParser_AliasSpan); + this->OnAlias(ev, mParser_AliasSpan, mParser_Mid); + } + } + else + this->ExpectedEqualError(ev); + } +} + +void morkParser::ReadMeta(morkEnv* ev, int inEndMeta) +// zm:MetaDict ::= zm:S? '<' zm:S? zm:Cell* zm:S? '>' /* meta attributes */ +// zm:MetaTable ::= zm:S? '{' zm:S? zm:Cell* zm:S? '}' /* meta attributes */ +// zm:MetaRow ::= zm:S? '[' zm:S? zm:Cell* zm:S? ']' /* meta attributes */ +{ + this->StartSpanOnLastByte(ev, &mParser_MetaSpan); + mParser_InMeta = morkBool_kTrue; + this->OnNewMeta(ev, *mParser_MetaSpan.AsPlace()); + + mork_bool more = morkBool_kTrue; // until end meta + int c; + while ( more && (c = this->NextChar(ev)) != EOF && ev->Good() ) + { + switch ( c ) + { + case '(': // cell + this->ReadCell(ev); + break; + + case '>': // maybe end meta? + if ( inEndMeta == '>' ) + more = morkBool_kFalse; // stop reading meta + else + this->UnexpectedByteInMetaWarning(ev); + break; + + case '}': // maybe end meta? + if ( inEndMeta == '}' ) + more = morkBool_kFalse; // stop reading meta + else + this->UnexpectedByteInMetaWarning(ev); + break; + + case ']': // maybe end meta? + if ( inEndMeta == ']' ) + more = morkBool_kFalse; // stop reading meta + else + this->UnexpectedByteInMetaWarning(ev); + break; + + default: + this->UnexpectedByteInMetaWarning(ev); + break; + } + } + + this->EndSpanOnThisByte(ev, &mParser_MetaSpan); + mParser_InMeta = morkBool_kFalse; + this->OnMetaEnd(ev, mParser_MetaSpan); +} + +/*static*/ void +morkParser::UnexpectedByteInMetaWarning(morkEnv* ev) +{ + ev->NewWarning("unexpected byte in meta"); +} + +/*static*/ void +morkParser::NonParserTypeError(morkEnv* ev) +{ + ev->NewError("non morkParser"); +} + +void morkParser::ReadDict(morkEnv* ev) +// zm:Dict ::= zm:S? '<' zm:DictItem* zm:S? '>' +// zm:DictItem ::= zm:MetaDict | zm:Alias +// zm:MetaDict ::= zm:S? '<' zm:S? zm:Cell* zm:S? '>' /* meta attributes */ +// zm:Alias ::= zm:S? '(' ('#')? zm:Hex+ zm:S? zm:Value ')' +{ + mParser_Change = morkChange_kNil; + mParser_AtomChange = morkChange_kNil; + + this->StartSpanOnLastByte(ev, &mParser_DictSpan); + mParser_InDict = morkBool_kTrue; + this->OnNewDict(ev, *mParser_DictSpan.AsPlace()); + + int c; + while ( (c = this->NextChar(ev)) != EOF && ev->Good() && c != '>' ) + { + switch ( c ) + { + case '(': // alias + this->ReadAlias(ev); + break; + + case '<': // meta + this->ReadMeta(ev, '>'); + break; + + default: + ev->NewWarning("unexpected byte in dict"); + break; + } + } + + this->EndSpanOnThisByte(ev, &mParser_DictSpan); + mParser_InDict = morkBool_kFalse; + this->OnDictEnd(ev, mParser_DictSpan); + + if ( ev->Bad() ) + mParser_State = morkParser_kBrokenState; + else if ( c == EOF ) + mParser_State = morkParser_kDoneState; +} + +void morkParser::EndSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan) +{ + mork_pos here = mParser_Stream->Tell(ev); + if ( ev->Good() ) + { + this->SetHerePos(here); + ioSpan->SetEndWithEnd(mParser_PortSpan); + } +} + +void morkParser::StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan) +{ + mork_pos here = mParser_Stream->Tell(ev); + if ( here > 0 ) // positive? + --here; + else + here = 0; + + if ( ev->Good() ) + { + this->SetHerePos(here); + ioSpan->SetStartWithEnd(mParser_PortSpan); + ioSpan->SetEndWithEnd(mParser_PortSpan); + } +} + +void +morkParser::OnPortState(morkEnv* ev) +{ + mParser_InPort = morkBool_kTrue; + this->OnNewPort(ev, *mParser_PortSpan.AsPlace()); + + int c; + while ( (c = this->NextChar(ev)) != EOF && ev->Good() ) + { + switch ( c ) + { + case '[': // row + this->ReadRow(ev, '['); + break; + + case '{': // table + this->ReadTable(ev); + break; + + case '<': // dict + this->ReadDict(ev); + break; + + case '+': // plus + mParser_Change = morkChange_kAdd; + break; + + case '-': // minus + mParser_Change = morkChange_kCut; + break; + + case '!': // bang + mParser_Change = morkChange_kSet; + break; + + default: + ev->NewWarning("unexpected byte in OnPortState()"); + break; + } + } + + mParser_InPort = morkBool_kFalse; + this->OnPortEnd(ev, mParser_PortSpan); + + if ( ev->Bad() ) + mParser_State = morkParser_kBrokenState; + else if ( c == EOF ) + mParser_State = morkParser_kDoneState; +} + +void +morkParser::OnStartState(morkEnv* ev) +{ + morkStream* s = mParser_Stream; + if ( s && s->IsNode() && s->IsOpenNode() ) + { + s->Seek(ev, 0); + if ( ev->Good() ) + { + this->StartParse(ev); + mParser_State = morkParser_kPortState; + } + } + else + ev->NilPointerError(); + + if ( ev->Bad() ) + mParser_State = morkParser_kBrokenState; } /*protected non-poly*/ void @@ -323,33 +1089,25 @@ morkParser::ParseLoop(morkEnv* ev) switch ( mParser_State ) { case morkParser_kCellState: // 0 - break; + this->OnCellState(ev); break; + case morkParser_kMetaState: // 1 - break; + this->OnMetaState(ev); break; + case morkParser_kRowState: // 2 - break; + this->OnRowState(ev); break; + case morkParser_kTableState: // 3 - break; + this->OnTableState(ev); break; + case morkParser_kDictState: // 4 - break; + this->OnDictState(ev); break; + case morkParser_kPortState: // 5 - break; + this->OnPortState(ev); break; case morkParser_kStartState: // 6 - { - morkStream* s = mParser_Stream; - if ( s && s->IsNode() && s->IsOpenNode() ) - { - this->StartParse(ev); - mParser_State = morkParser_kPortState; - } - else - { - mParser_State = morkParser_kBrokenState; - ev->NilPointerError(); - } - } - break; + this->OnStartState(ev); break; case morkParser_kDoneState: // 7 mParser_DoMore = morkBool_kFalse; diff --git a/mailnews/db/mork/src/morkParser.h b/mailnews/db/mork/src/morkParser.h index 50a7d27e67d9..54f04251ed81 100644 --- a/mailnews/db/mork/src/morkParser.h +++ b/mailnews/db/mork/src/morkParser.h @@ -23,10 +23,6 @@ #include "mork.h" #endif -#ifndef _MORKPARSER_ -#include "morkParser.h" -#endif - #ifndef _MORKBLOB_ #include "morkBlob.h" #endif @@ -68,6 +64,9 @@ public: morkPlace(mork_pos inPos, mork_line inLine) { mPlace_Pos = inPos; mPlace_Line = inLine; } + + morkPlace(const morkPlace& inPlace) + : mPlace_Pos(inPlace.mPlace_Pos), mPlace_Line(inPlace.mPlace_Line) { } }; /*============================================================================= @@ -80,48 +79,68 @@ public: const char* mGlitch_Comment; // null-terminated ASCII C string morkGlitch() { mGlitch_Comment = 0; } + + morkGlitch(const morkPlace& inPlace, const char* inComment) + : mGlitch_Place(inPlace), mGlitch_Comment(inComment) { } }; /*============================================================================= - * morkAlias: all possible ways needed to express an alias ID in Mork syntax + * morkMid: all possible ways needed to express an alias ID in Mork syntax */ -/*| morkAlias: an abstraction of all the variations we might need to support +/*| morkMid: an abstraction of all the variations we might need to support **| in order to present an ID through the parser interface most cheaply and **| with minimum transformation away from the original text format. **| **|| An ID can have one of four forms: -**| 1) idHex (mAlias_Oid.mOid_Id <- idHex) -**| 2) idHex:^scopeHex (mAlias_Oid.mOid_Id <- idHex, mOid_Scope <- scopeHex) -**| 3) idHex:scopeName (mAlias_Oid.mOid_Id <- idHex, mAlias_Buf <- scopeName) -**| 4) columnName (mAlias_Buf <- columnName, for columns in cells only) +**| 1) idHex (mMid_Oid.mOid_Id <- idHex) +**| 2) idHex:^scopeHex (mMid_Oid.mOid_Id <- idHex, mOid_Scope <- scopeHex) +**| 3) idHex:scopeName (mMid_Oid.mOid_Id <- idHex, mMid_Buf <- scopeName) +**| 4) columnName (mMid_Buf <- columnName, for columns in cells only) **| -**|| Typically, mAlias_Oid.mOid_Id will hold a nonzero integer value for +**|| Typically, mMid_Oid.mOid_Id will hold a nonzero integer value for **| an ID, but we might have an optional scope specified by either an integer **| in hex format, or a string name. (Note that while the first ID can be **| scoped variably, any integer ID for a scope is assumed always located in **| the same scope, so the second ID need not be disambiguated.) **| -**|| The only time mAlias_Oid.mOid_Id is ever zero is when mAlias_Buf alone +**|| The only time mMid_Oid.mOid_Id is ever zero is when mMid_Buf alone **| is nonzero, to indicate an explicit string instead of an alias appeared. **| This case happens to make the representation of columns in cells somewhat **| easier to represent, since columns can just appear as a string name; and **| this unifies those interfaces with row and table APIs expecting IDs. **| -**|| So when the parser passes an instance of morkAlias to a subclass, the -**| mAlias_Oid.mOid_Id slot should usually be nonzero. And the other two -**| slots, mAlias_Oid.mOid_Scope and mAlias_Buf, might both be zero, or at +**|| So when the parser passes an instance of morkMid to a subclass, the +**| mMid_Oid.mOid_Id slot should usually be nonzero. And the other two +**| slots, mMid_Oid.mOid_Scope and mMid_Buf, might both be zero, or at **| most one of them will be nonzero to indicate an explicit scope; the **| parser is responsible for ensuring at most one of these is nonzero. |*/ -class morkAlias { +class morkMid { public: - mdbOid mAlias_Oid; // mOid_Scope is zero when not specified - const morkBuf* mAlias_Buf; // points to some specific buf subclass + mdbOid mMid_Oid; // mOid_Scope is zero when not specified + const morkBuf* mMid_Buf; // points to some specific buf subclass - morkAlias() - { mAlias_Oid.mOid_Scope = 0; mAlias_Oid.mOid_Id = morkId_kMinusOne; - mAlias_Buf = 0; } + morkMid() + { mMid_Oid.mOid_Scope = 0; mMid_Oid.mOid_Id = morkId_kMinusOne; + mMid_Buf = 0; } + + void InitMidWithCoil(morkCoil* ioCoil) + { mMid_Oid.mOid_Scope = 0; mMid_Oid.mOid_Id = morkId_kMinusOne; + mMid_Buf = ioCoil; } + + void ClearMid() + { mMid_Oid.mOid_Scope = 0; mMid_Oid.mOid_Id = morkId_kMinusOne; + mMid_Buf = 0; } + + morkMid(const morkMid& other) + : mMid_Oid(other.mMid_Oid), mMid_Buf(other.mMid_Buf) { } + + mork_bool HasNoId() const // ID is unspecified? + { return ( mMid_Oid.mOid_Id == morkId_kMinusOne ); } + + mork_bool HasSomeId() const // ID is specified? + { return ( mMid_Oid.mOid_Id != morkId_kMinusOne ); } }; /*============================================================================= @@ -138,6 +157,9 @@ public: // methods public: // inlines morkSpan() { } // use inline empty constructor for each place + morkPlace* AsPlace() { return &mSpan_Start; } + const morkPlace* AsConstPlace() const { return &mSpan_Start; } + void SetSpan(mork_pos inFromPos, mork_line inFromLine, mork_pos inToPos, mork_line inToLine) { @@ -208,7 +230,7 @@ class morkParser /*d*/ : public morkNode { // ````` ````` ````` ````` ````` ````` ````` ````` protected: // protected morkParser members - nsIMdbHeap* mParser_Heap; // refcounted heap used for allocation + nsIMdbHeap* mParser_Heap; // refcounted heap used for allocation morkStream* mParser_Stream; // refcounted input stream mork_u4 mParser_Tag; // must equal morkParser_kTag @@ -219,9 +241,10 @@ protected: // protected morkParser members // after finding ends of group transactions, we can re-seek the start: mork_pos mParser_GroupContentStartPos; // start of this group - mork_gid mParser_GroupId; // group ID if inside a group - mork_tid mParser_TableId; // table ID if inside a table - mork_rid mParser_RowId; // row ID if inside a row + morkMid mParser_TableMid; // table mid if inside a table + morkMid mParser_RowMid; // row mid if inside a row + morkMid mParser_CellMid; // cell mid if inside a row + mork_gid mParser_GroupId; // group ID if inside a group mork_bool mParser_InPort; // called OnNewPort but not OnPortEnd? mork_bool mParser_InDict; // called OnNewDict but not OnDictEnd? @@ -229,28 +252,36 @@ protected: // protected morkParser members mork_bool mParser_InMeta; // called OnNewMeta but not OnMetaEnd? mork_bool mParser_InPortRow; // called OnNewPortRow but not OnPortRowEnd? + mork_bool mParser_InRow; // called OnNewRow but not OnNewRowEnd? + mork_bool mParser_InTable; // called OnNewMeta but not OnMetaEnd? + mork_bool mParser_InGroup; // called OnNewGroup but not OnGroupEnd? + + mork_change mParser_AtomChange; // driven by mParser_Change + mork_change mParser_CellChange; // driven by mParser_Change + mork_change mParser_RowChange; // driven by mParser_Change + mork_change mParser_TableChange; // driven by mParser_Change + + mork_change mParser_Change; // driven by modifier in text mork_bool mParser_IsBroken; // has the parse become broken? mork_bool mParser_IsDone; // has the parse finished? mork_bool mParser_DoMore; // mParser_MoreGranularity not exhausted? - mork_change mParser_Change; // driven by modifier in text + morkMid mParser_Mid; // current alias being parsed + // note that mParser_Mid.mMid_Buf points at mParser_ScopeCoil below: - morkAlias mParser_Alias; // current alias being parsed - // note that mParser_Alias.mAlias_Buf points at mParser_ScopeSpool below: + // blob coils allocated in mParser_Heap + morkCoil mParser_ScopeCoil; // place to accumulate ID scope blobs + morkCoil mParser_ValueCoil; // place to accumulate value blobs + morkCoil mParser_ColumnCoil; // place to accumulate column blobs + morkCoil mParser_StringCoil; // place to accumulate string blobs - // blob spools allocated in mParser_Heap - morkSpool mParser_ScopeSpool; // place to accumulate ID scope blobs - morkSpool mParser_ValueSpool; // place to accumulate value blobs - morkSpool mParser_ColumnSpool; // place to accumulate column blobs - morkSpool mParser_StringSpool; // place to accumulate string blobs - - morkSpoolSink mParser_ScopeSink; // writes to mParser_ScopeSpool - morkSpoolSink mParser_ValueSink; // writes to mParser_ValueSpool - morkSpoolSink mParser_ColumnSink; // writes to mParser_ColumnSpool - morkSpoolSink mParser_StringSink; // writes to mParser_StringSpool + morkSpool mParser_ScopeSpool; // writes to mParser_ScopeCoil + morkSpool mParser_ValueSpool; // writes to mParser_ValueCoil + morkSpool mParser_ColumnSpool; // writes to mParser_ColumnCoil + morkSpool mParser_StringSpool; // writes to mParser_StringCoil // yarns allocated in mParser_Heap - morkYarn mParser_AliasYarn; // place to receive from AliasToYarn() + morkYarn mParser_MidYarn; // place to receive from MidToYarn() // span showing current ongoing file position status: morkSpan mParser_PortSpan; // span of current db port file @@ -274,8 +305,8 @@ private: // convenience inlines void SetHerePos(mork_pos inPos) { mParser_PortSpan.mSpan_End.mPlace_Pos = inPos; } - void AddLine() - { ++ mParser_PortSpan.mSpan_End.mPlace_Line; } + void CountLineBreak() + { ++mParser_PortSpan.mSpan_End.mPlace_Line; } // { ===== begin morkNode interface ===== public: // morkNode virtual methods @@ -300,8 +331,13 @@ public: // dynamic type identification // } ===== end morkNode methods ===== -public: // typing - void NonParserTypeError(morkEnv* ev); +public: // errors and warnings + static void UnexpectedEofError(morkEnv* ev); + static void EofInsteadOfHexError(morkEnv* ev); + static void ExpectedEqualError(morkEnv* ev); + static void ExpectedHexDigitError(morkEnv* ev, int c); + static void NonParserTypeError(morkEnv* ev); + static void UnexpectedByteInMetaWarning(morkEnv* ev); public: // other type methods mork_bool GoodParserTag() const { return mParser_Tag == morkParser_kTag; } @@ -312,8 +348,8 @@ public: // other type methods // ````` ````` ````` ````` ````` ````` ````` ````` public: // in virtual morkParser methods, data flow subclass to parser - virtual void AliasToYarn(morkEnv* ev, - const morkAlias& inAlias, // typically an alias to concat with strings + virtual void MidToYarn(morkEnv* ev, + const morkMid& inMid, // typically an alias to concat with strings mdbYarn* outYarn) = 0; // The parser might ask that some aliases be turned into yarns, so they // can be concatenated into longer blobs under some circumstances. This @@ -350,7 +386,7 @@ public: // out virtual morkParser methods, data flow parser to subclass // mp:RowItem ::= mp:Cell | mp:Meta | OnRowGlitch // mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd // mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch -// mp:Slot ::= OnValue | OnValueAlias | OnRowAlias | OnTableAlias +// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid // Note that in interfaces below, mork_change parameters kAdd and kNil @@ -367,12 +403,12 @@ public: // out virtual morkParser methods, data flow parser to subclass virtual void OnGroupAbortEnd(morkEnv* ev, const morkSpan& inSpan) = 0; virtual void OnNewPortRow(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) = 0; + const morkMid& inMid, mork_change inChange) = 0; virtual void OnPortRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0; virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan) = 0; virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) = 0; + const morkMid& inMid, mork_change inChange) = 0; virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0; virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan) = 0; @@ -381,7 +417,7 @@ public: // out virtual morkParser methods, data flow parser to subclass virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan) = 0; virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) = 0; + const morkMid& inMid, mork_change inChange) = 0; virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0; virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan) = 0; @@ -390,12 +426,16 @@ public: // out virtual morkParser methods, data flow parser to subclass virtual void OnDictEnd(morkEnv* ev, const morkSpan& inSpan) = 0; virtual void OnAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) = 0; + const morkMid& inMid) = 0; virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0; virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace, - const morkAlias& inAlias, mork_change inChange) = 0; + const morkMid* inMid, const morkBuf* inBuf, mork_change inChange) = 0; + // Exactly one of inMid and inBuf is nil, and the other is non-nil. + // When hex ID syntax is used for a column, then inMid is not nil, and + // when a naked string names a column, then inBuf is not nil. + virtual void OnCellGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0; virtual void OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat) = 0; virtual void OnCellEnd(morkEnv* ev, const morkSpan& inSpan) = 0; @@ -403,29 +443,54 @@ public: // out virtual morkParser methods, data flow parser to subclass virtual void OnValue(morkEnv* ev, const morkSpan& inSpan, const morkBuf& inBuf) = 0; - virtual void OnValueAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) = 0; + virtual void OnValueMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid) = 0; - virtual void OnRowAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) = 0; + virtual void OnRowMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid) = 0; - virtual void OnTableAlias(morkEnv* ev, const morkSpan& inSpan, - const morkAlias& inAlias) = 0; + virtual void OnTableMid(morkEnv* ev, const morkSpan& inSpan, + const morkMid& inMid) = 0; // ````` ````` ````` ````` ````` ````` ````` ````` protected: // protected parser helper methods - void ParseLoop(morkEnv* ev); // find parse continuation and resume - - void StartParse(morkEnv* ev); // prepare for parsing - void StopParse(morkEnv* ev); // terminate parsing & call needed methods + void ParseLoop(morkEnv* ev); // find parse continuation and resume + + void StartParse(morkEnv* ev); // prepare for parsing + void StopParse(morkEnv* ev); // terminate parsing & call needed methods + + int NextChar(morkEnv* ev); // next non-white content + + void OnCellState(morkEnv* ev); + void OnMetaState(morkEnv* ev); + void OnRowState(morkEnv* ev); + void OnTableState(morkEnv* ev); + void OnDictState(morkEnv* ev); + void OnPortState(morkEnv* ev); + void OnStartState(morkEnv* ev); - int NextChar(morkEnv* ev); // next non-white content + void ReadCell(morkEnv* ev); + void ReadRow(morkEnv* ev, int c); + void ReadTable(morkEnv* ev); + void ReadTableMeta(morkEnv* ev); + void ReadDict(morkEnv* ev); + void ReadMeta(morkEnv* ev, int inEndMeta); + void ReadAlias(morkEnv* ev); + mork_id ReadHex(morkEnv* ev, int* outNextChar); + morkBuf* ReadValue(morkEnv* ev); + morkBuf* ReadName(morkEnv* ev, int c); + mork_bool ReadMid(morkEnv* ev, morkMid* outMid); + + void EndSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan); + void StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan); + + int eat_line_break(morkEnv* ev, int inLast); + int eat_line_continue(morkEnv* ev); // last char was '\\' + int eat_comment(morkEnv* ev); // last char was '/' // ````` ````` ````` ````` ````` ````` ````` ````` public: // public non-poly morkParser methods - - void SetParserStream(morkEnv* ev, morkStream* ioStream); mdb_count ParseMore( // return count of bytes consumed now morkEnv* ev, // context diff --git a/mailnews/db/mork/src/morkRow.cpp b/mailnews/db/mork/src/morkRow.cpp index 496ba0e569dc..382e15a338ac 100644 --- a/mailnews/db/mork/src/morkRow.cpp +++ b/mailnews/db/mork/src/morkRow.cpp @@ -199,6 +199,121 @@ morkRow::AcquireCellHandle(morkEnv* ev, morkCell* ioCell, return (nsIMdbCell*) 0; } +mork_count +morkRow::CountOverlap(morkEnv* ev, morkCell* ioVector, mork_fill inFill) + // Count cells in ioVector that change existing cells in this row when + // ioVector is added to the row (as in TakeCells()). This is the set + // of cells with the same columns in ioVector and mRow_Cells, which do + // not have exactly the same value in mCell_Atom, and which do not both + // have change status equal to morkChange_kCut (because cutting a cut + // cell still yields a cell that has been cut). CountOverlap() also + // modifies the change attribute of any cell in ioVector to kDup when + // the change was previously kCut and the same column cell was found + // in this row with change also equal to kCut; this tells callers later + // they need not look for that cell in the row again on a second pass. +{ + mork_count outCount = 0; + mork_pos pos = 0; // needed by GetCell() + morkCell* cells = ioVector; + morkCell* end = cells + inFill; + --cells; // prepare for preincrement + while ( ++cells < end && ev->Good() ) + { + mork_column col = cells->GetColumn(); + + morkCell* old = this->GetCell(ev, col, &pos); + if ( old ) // same column? + { + mork_change newChg = cells->GetChange(); + mork_change oldChg = old->GetChange(); + if ( newChg != morkChange_kCut || oldChg != newChg ) // not cut+cut? + { + if ( cells->mCell_Atom != old->mCell_Atom ) // not same atom? + ++outCount; // cells will replace old significantly when added + } + else + cells->SetColumnAndChange(col, morkChange_kDup); // note dup status + } + } + return outCount; +} + +void +morkRow::MergeCells(morkEnv* ev, morkCell* ioVector, + mork_fill inVecLength, mork_fill inOldRowFill, mork_fill inOverlap) + // MergeCells() is the part of TakeCells() that does the insertion. + // inOldRowFill is the old value of mRow_Length, and inOverlap is the + // number of cells in the intersection that must be updated. +{ + morkCell* newCells = mRow_Cells + inOldRowFill; // 1st new cell in row + morkCell* newEnd = newCells + mRow_Length; // one past last cell + + morkCell* srcCells = ioVector; + morkCell* srcEnd = srcCells + inVecLength; + + --srcCells; // prepare for preincrement + while ( ++srcCells < srcEnd && ev->Good() ) + { + mork_change srcChg = srcCells->GetChange(); + if ( srcChg != morkChange_kDup ) // anything to be done? + { + morkCell* dstCell = 0; + if ( inOverlap ) + { + mork_pos pos = 0; // needed by GetCell() + dstCell = this->GetCell(ev, srcCells->GetColumn(), &pos); + } + if ( dstCell ) + { + --inOverlap; // one fewer intersections to resolve + // swap the atoms in the cells to avoid ref counting here: + morkAtom* dstAtom = dstCell->mCell_Atom; + *dstCell = *srcCells; // bitwise copy, taking src atom + srcCells->mCell_Atom = dstAtom; // forget cell ref, if any + } + else if ( newCells < newEnd ) // another new cell exists? + { + dstCell = newCells++; // alloc another new cell + // take atom from source cell, transferring ref to this row: + *dstCell = *srcCells; // bitwise copy, taking src atom + srcCells->mCell_Atom = 0; // forget cell ref, if any + } + else // oops, we ran out... + ev->NewError("out of new cells"); + } + } +} + +void +morkRow::TakeCells(morkEnv* ev, morkCell* ioVector, mork_fill inVecLength, + morkStore* ioStore) +{ + if ( ioVector && inVecLength && ev->Good() ) + { + ++mRow_Seed; // intend to change structure of mRow_Cells + mork_pos length = (mork_pos) mRow_Length; + + mork_count overlap = this->CountOverlap(ev, ioVector, inVecLength); + + mork_size growth = inVecLength - overlap; // cells to add + mork_size newLength = length + growth; + + if ( growth && ev->Good() ) // need to add any cells? + { + morkPool* pool = ioStore->StorePool(); + if ( !pool->AddRowCells(ev, this, length + growth) ) + ev->NewError("cannot take cells"); + } + if ( ev->Good() ) + { + if ( mRow_Length >= newLength ) + this->MergeCells(ev, ioVector, inVecLength, length, overlap); + else + ev->NewError("not enough new cells"); + } + } +} + morkCell* morkRow::NewCell(morkEnv* ev, mdb_column inColumn, mork_pos* outPos, morkStore* ioStore) @@ -284,8 +399,7 @@ void morkRow::OnZeroTableUse(morkEnv* ev) // OnZeroTableUse() is called when CutTableUse() returns zero. { - // OK, this is a P1 showstopper bug, so I'll comment it out. -// ev->NewWarning("need to implement OnZeroTableUse"); + // ev->NewWarning("need to implement OnZeroTableUse"); } void diff --git a/mailnews/db/mork/src/morkRow.h b/mailnews/db/mork/src/morkRow.h index a4399fc4c1ae..8c6c0cc63374 100644 --- a/mailnews/db/mork/src/morkRow.h +++ b/mailnews/db/mork/src/morkRow.h @@ -74,6 +74,27 @@ public: // other row methods public: // internal row methods + mork_count CountOverlap(morkEnv* ev, morkCell* ioVector, mork_fill inFill); + // Count cells in ioVector that change existing cells in this row when + // ioVector is added to the row (as in TakeCells()). This is the set + // of cells with the same columns in ioVector and mRow_Cells, which do + // not have exactly the same value in mCell_Atom, and which do not both + // have change status equal to morkChange_kCut (because cutting a cut + // cell still yields a cell that has been cut). CountOverlap() also + // modifies the change attribute of any cell in ioVector to kDup when + // the change was previously kCut and the same column cell was found + // in this row with change also equal to kCut; this tells callers later + // they need not look for that cell in the row again on a second pass. + + void MergeCells(morkEnv* ev, morkCell* ioVector, + mork_fill inVecLength, mork_fill inOldRowFill, mork_fill inOverlap); + // MergeCells() is the part of TakeCells() that does the insertion. + // inOldRowFill is the old value of mRow_Length, and inOverlap is the + // number of cells in the intersection that must be updated. + + void TakeCells(morkEnv* ev, morkCell* ioVector, mork_fill inVecLength, + morkStore* ioStore); + morkCell* NewCell(morkEnv* ev, mdb_column inColumn, mork_pos* outPos, morkStore* ioStore); morkCell* GetCell(morkEnv* ev, mdb_column inColumn, mork_pos* outPos) const; diff --git a/mailnews/db/mork/src/morkRowSpace.cpp b/mailnews/db/mork/src/morkRowSpace.cpp index ff7b3bcc32f1..eeab400f276e 100644 --- a/mailnews/db/mork/src/morkRowSpace.cpp +++ b/mailnews/db/mork/src/morkRowSpace.cpp @@ -230,6 +230,37 @@ morkRowSpace::FindTableByKind(morkEnv* ev, mork_kind inTableKind) return (morkTable*) 0; } +morkTable* +morkRowSpace::NewTableWithTid(morkEnv* ev, mork_tid inTid, + mork_kind inTableKind) +{ + morkTable* outTable = 0; + + if ( inTableKind ) + { + mdb_bool mustBeUnique = morkBool_kFalse; + nsIMdbHeap* heap = mSpace_Store->mPort_Heap; + morkTable* table = new(*heap, ev) + morkTable(ev, morkUsage::kHeap, heap, mSpace_Store, heap, this, + inTid, inTableKind, mustBeUnique); + if ( table ) + { + if ( mRowSpace_Tables.AddTable(ev, table) ) + { + outTable = table; + if ( mRowSpace_NextTableId <= inTid ) + mRowSpace_NextTableId = inTid + 1; + } + else + table->CutStrongRef(ev); + } + } + else + this->ZeroKindError(ev); + + return outTable; +} + morkTable* morkRowSpace::NewTable(morkEnv* ev, mork_kind inTableKind, mdb_bool inMustBeUnique) @@ -328,7 +359,12 @@ morkRowSpace::NewRowWithOid(morkEnv* ev, const mdbOid* inOid) row->InitRow(ev, inOid, this, /*length*/ 0, pool); if ( ev->Good() && mRowSpace_Rows.AddRow(ev, row) ) + { outRow = row; + mork_rid rid = inOid->mOid_Id; + if ( mRowSpace_NextRowId <= rid ) + mRowSpace_NextRowId = rid + 1; + } else pool->ZapRow(ev, row); } diff --git a/mailnews/db/mork/src/morkRowSpace.h b/mailnews/db/mork/src/morkRowSpace.h index c10e421d6852..b4cb10dfd5f5 100644 --- a/mailnews/db/mork/src/morkRowSpace.h +++ b/mailnews/db/mork/src/morkRowSpace.h @@ -115,6 +115,9 @@ public: // other space methods morkTable* NewTable(morkEnv* ev, mork_kind inTableKind, mdb_bool inMustBeUnique); + morkTable* NewTableWithTid(morkEnv* ev, mork_tid inTid, + mork_kind inTableKind); + morkTable* FindTableByKind(morkEnv* ev, mork_kind inTableKind); morkTable* FindTableByTid(morkEnv* ev, mork_tid inTid) { return mRowSpace_Tables.GetTable(ev, inTid); } diff --git a/mailnews/db/mork/src/morkSink.cpp b/mailnews/db/mork/src/morkSink.cpp index 6d3c6b2cef4e..d293782da10e 100644 --- a/mailnews/db/mork/src/morkSink.cpp +++ b/mailnews/db/mork/src/morkSink.cpp @@ -32,6 +32,10 @@ #include "morkEnv.h" #endif +#ifndef _MORKBLOB_ +#include "morkBlob.h" +#endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 /*virtual*/ morkSink::~morkSink() @@ -41,41 +45,134 @@ } /*virtual*/ void -morkSpoolSink::FlushSink(morkEnv* ev) // probably does nothing +morkSpool::FlushSink(morkEnv* ev) // sync mSpool_Coil->mBuf_Fill { - ev->StubMethodOnlyError(); + morkCoil* coil = mSpool_Coil; + if ( coil ) + { + mork_u1* body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + mork_u1* at = mSink_At; + mork_u1* end = mSink_End; + if ( at >= body && at <= end ) // expected cursor order? + { + mork_fill fill = at - body; // current content size + if ( fill <= coil->mBlob_Size ) + coil->mBuf_Fill = fill; + else + { + coil->BlobFillOverSizeError(ev); + coil->mBuf_Fill = coil->mBlob_Size; // make it safe + } + } + else + this->BadSpoolCursorOrderError(ev); + } + else + coil->NilBufBodyError(ev); + } + else + this->NilSpoolCoilError(ev); } /*virtual*/ void -morkSpoolSink::SpillPutc(morkEnv* ev, int c) // grow spool and write byte +morkSpool::SpillPutc(morkEnv* ev, int c) // grow coil and write byte { - ev->StubMethodOnlyError(); + morkCoil* coil = mSpool_Coil; + if ( coil ) + { + mork_u1* body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + mork_u1* at = mSink_At; + mork_u1* end = mSink_End; + if ( at >= body && at <= end ) // expected cursor order? + { + mork_size size = coil->mBlob_Size; + mork_fill fill = at - body; // current content size + if ( fill <= size ) // less content than medium size? + { + coil->mBuf_Fill = fill; + if ( at >= end ) // need to grow the coil? + { + if ( size > 2048 ) // grow slower over 2K? + size += 512; + else + { + mork_size growth = ( size * 4 ) / 3; // grow by 33% + if ( growth < 64 ) // grow faster under (64 * 3)? + growth = 64; + size += growth; + } + if ( coil->GrowCoil(ev, size) ) // made coil bigger? + { + body = (mork_u1*) coil->mBuf_Body; + if ( body ) // have a coil body? + { + mSink_At = at = body + fill; + mSink_End = end = body + coil->mBlob_Size; + } + else + coil->NilBufBodyError(ev); + } + } + if ( ev->Good() ) // seem ready to write byte c? + { + if ( at < end ) // morkSink::Putc() would succeed? + { + *at++ = c; + mSink_At = at; + coil->mBuf_Fill = fill + 1; + } + else + this->BadSpoolCursorOrderError(ev); + } + } + else // fill exceeds size + { + coil->BlobFillOverSizeError(ev); + coil->mBuf_Fill = coil->mBlob_Size; // make it safe + } + } + else + this->BadSpoolCursorOrderError(ev); + } + else + coil->NilBufBodyError(ev); + } + else + this->NilSpoolCoilError(ev); } // ````` ````` ````` ````` ````` ````` ````` ````` // public: // public non-poly morkSink methods /*virtual*/ -morkSpoolSink::~morkSpoolSink() +morkSpool::~morkSpool() // Zero all slots to show this sink is disabled, but destroy no memory. -// Note it is typically unnecessary to flush this spool sink, since all -// content is written directly to the spool without any buffering. +// Note it is typically unnecessary to flush this coil sink, since all +// content is written directly to the coil without any buffering. { + mSink_At = 0; + mSink_End = 0; + mSpool_Coil = 0; } -morkSpoolSink::morkSpoolSink(morkEnv* ev, morkSpool* ioSpool) -// After installing the spool, calls Seek(ev, 0) to prepare for writing. +morkSpool::morkSpool(morkEnv* ev, morkCoil* ioCoil) +// After installing the coil, calls Seek(ev, 0) to prepare for writing. : morkSink() -, mSpoolSink_Spool( 0 ) +, mSpool_Coil( 0 ) { + mSink_At = 0; // set correctly later in Seek() + mSink_End = 0; // set correctly later in Seek() + if ( ev->Good() ) { - if ( ioSpool ) + if ( ioCoil ) { - // ev->StubMethodOnlyError(); - mSink_At = 0; - mSink_End = 0; - mSpoolSink_Spool = ioSpool; + mSpool_Coil = ioCoil; + this->Seek(ev, /*pos*/ 0); } else ev->NilPointerError(); @@ -84,29 +181,124 @@ morkSpoolSink::morkSpoolSink(morkEnv* ev, morkSpool* ioSpool) // ----- All boolean return values below are equal to ev->Good(): ----- -mork_bool -morkSpoolSink::Seek(morkEnv* ev, mork_pos inPos) -// Changed the current write position in spool's buffer to inPos. -// For example, to start writing the spool from scratch, use inPos==0. +/*static*/ void +morkSpool::BadSpoolCursorOrderError(morkEnv* ev) { - ev->StubMethodOnlyError(); + ev->NewError("bad morkSpool cursor order"); +} + +/*static*/ void +morkSpool::NilSpoolCoilError(morkEnv* ev) +{ + ev->NewError("nil mSpool_Coil"); +} + +mork_bool +morkSpool::Seek(morkEnv* ev, mork_pos inPos) +// Changed the current write position in coil's buffer to inPos. +// For example, to start writing the coil from scratch, use inPos==0. +{ + morkCoil* coil = mSpool_Coil; + if ( coil ) + { + mork_size minSize = inPos + 64; + + if ( coil->mBlob_Size < minSize ) + coil->GrowCoil(ev, minSize); + + if ( ev->Good() ) + { + coil->mBuf_Fill = inPos; + mork_u1* body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + mSink_At = body + inPos; + mSink_End = body + coil->mBlob_Size; + } + else + coil->NilBufBodyError(ev); + } + } + else + this->NilSpoolCoilError(ev); + return ev->Good(); } mork_bool -morkSpoolSink::Write(morkEnv* ev, const void* inBuf, mork_size inSize) -// write inSize bytes of inBuf to current position inside spool's buffer +morkSpool::Write(morkEnv* ev, const void* inBuf, mork_size inSize) +// write inSize bytes of inBuf to current position inside coil's buffer { - ev->StubMethodOnlyError(); + // This method is conceptually very similar to morkStream::Write(), + // and this code was written while looking at that method for clues. + + morkCoil* coil = mSpool_Coil; + if ( coil ) + { + mork_u1* body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + if ( inBuf && inSize ) // anything to write? + { + mork_u1* at = mSink_At; + mork_u1* end = mSink_End; + if ( at >= body && at <= end ) // expected cursor order? + { + // note coil->mBuf_Fill can be stale after morkSink::Putc(): + mork_pos fill = at - body; // current content size + mork_num space = end - at; // space left in body + if ( space < inSize ) // not enough to hold write? + { + mork_size minGrowth = space + 16; + mork_size minSize = coil->mBlob_Size + minGrowth; + if ( coil->GrowCoil(ev, minSize) ) + { + body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + mSink_At = at = body + fill; + mSink_End = end = body + coil->mBlob_Size; + space = end - at; // space left in body + } + else + coil->NilBufBodyError(ev); + } + } + if ( ev->Good() ) + { + if ( space >= inSize ) // enough room to hold write? + { + MORK_MEMCPY(at, inBuf, inSize); // into body + mSink_At = at + inSize; // advance past written bytes + coil->mBuf_Fill = fill + inSize; // "flush" to fix fill + } + else + ev->NewError("insufficient morkSpool space"); + } + } + else + this->BadSpoolCursorOrderError(ev); + } + } + else + coil->NilBufBodyError(ev); + } + else + this->NilSpoolCoilError(ev); + return ev->Good(); } mork_bool -morkSpoolSink::PutString(morkEnv* ev, const char* inString) +morkSpool::PutString(morkEnv* ev, const char* inString) // call Write() with inBuf=inString and inSize=strlen(inString), // unless inString is null, in which case we then do nothing at all. { - ev->StubMethodOnlyError(); + if ( inString ) + { + mork_size size = MORK_STRLEN(inString); + this->Write(ev, inString, size); + } return ev->Good(); } diff --git a/mailnews/db/mork/src/morkSink.h b/mailnews/db/mork/src/morkSink.h index 10b6eddfb00d..79b349c3c074 100644 --- a/mailnews/db/mork/src/morkSink.h +++ b/mailnews/db/mork/src/morkSink.h @@ -114,47 +114,52 @@ public: // public non-poly morkSink methods } }; -/*| morkSpoolSink: an output sink that efficiently writes individual bytes -**| or entire byte sequences to a spool instance, which grows as needed by -**| using the heap instance in the spool to grow the internal buffer. +/*| morkSpool: an output sink that efficiently writes individual bytes +**| or entire byte sequences to a coil instance, which grows as needed by +**| using the heap instance in the coil to grow the internal buffer. **| -**|| Note we do not "own" the spool referenced by mSpoolSink_Spool, and -**| the lifetime of the spool is expected to equal or exceed that of this +**|| Note we do not "own" the coil referenced by mSpool_Coil, and +**| the lifetime of the coil is expected to equal or exceed that of this **| sink by some external means. Typical usage might involve keeping an -**| instance of morkSpool and an instance of morkSpoolSink in the same -**| owning parent object, which uses the sink with the associated spool. +**| instance of morkCoil and an instance of morkSpool in the same +**| owning parent object, which uses the spool with the associated coil. |*/ -class morkSpoolSink : public morkSink { // for buffered i/o to a morkSpool +class morkSpool : public morkSink { // for buffered i/o to a morkCoil // ````` ````` ````` ````` ````` ````` ````` ````` public: // public sink virtual methods - virtual void FlushSink(morkEnv* ev); // probably does nothing - virtual void SpillPutc(morkEnv* ev, int c); // grow spool and write byte + // when morkSink::Putc() moves mSink_At, mSpool_Coil->mBuf_Fill is wrong: + + virtual void FlushSink(morkEnv* ev); // sync mSpool_Coil->mBuf_Fill + virtual void SpillPutc(morkEnv* ev, int c); // grow coil and write byte // ````` ````` ````` ````` ````` ````` ````` ````` public: // member variables - morkSpool* mSpoolSink_Spool; // destination medium for written bytes + morkCoil* mSpool_Coil; // destination medium for written bytes // ````` ````` ````` ````` ````` ````` ````` ````` public: // public non-poly morkSink methods - virtual ~morkSpoolSink(); + static void BadSpoolCursorOrderError(morkEnv* ev); + static void NilSpoolCoilError(morkEnv* ev); + + virtual ~morkSpool(); // Zero all slots to show this sink is disabled, but destroy no memory. - // Note it is typically unnecessary to flush this spool sink, since all - // content is written directly to the spool without any buffering. + // Note it is typically unnecessary to flush this coil sink, since all + // content is written directly to the coil without any buffering. - morkSpoolSink(morkEnv* ev, morkSpool* ioSpool); - // After installing the spool, calls Seek(ev, 0) to prepare for writing. + morkSpool(morkEnv* ev, morkCoil* ioCoil); + // After installing the coil, calls Seek(ev, 0) to prepare for writing. // ----- All boolean return values below are equal to ev->Good(): ----- mork_bool Seek(morkEnv* ev, mork_pos inPos); - // Changed the current write position in spool's buffer to inPos. - // For example, to start writing the spool from scratch, use inPos==0. + // Changed the current write position in coil's buffer to inPos. + // For example, to start writing the coil from scratch, use inPos==0. mork_bool Write(morkEnv* ev, const void* inBuf, mork_size inSize); - // write inSize bytes of inBuf to current position inside spool's buffer + // write inSize bytes of inBuf to current position inside coil's buffer mork_bool PutBuf(morkEnv* ev, const morkBuf& inBuffer) { return this->Write(ev, inBuffer.mBuf_Body, inBuffer.mBuf_Fill); } diff --git a/mailnews/db/mork/src/morkStore.cpp b/mailnews/db/mork/src/morkStore.cpp index de6a39710bf8..d7ee71db987d 100644 --- a/mailnews/db/mork/src/morkStore.cpp +++ b/mailnews/db/mork/src/morkStore.cpp @@ -92,6 +92,10 @@ #include "morkRowMap.h" #endif +#ifndef _MORKPARSER_ +#include "morkParser.h" +#endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 // ````` ````` ````` ````` ````` @@ -212,6 +216,15 @@ morkStore::morkStore(morkEnv* ev, const morkUsage& inUsage, , mStore_OidAtomSpace( 0 ) , mStore_GroundAtomSpace( 0 ) , mStore_GroundColumnSpace( 0 ) + +, mStore_MorkNoneToken( 0 ) +, mStore_CharsetToken( 0 ) +, mStore_AtomScopeToken( 0 ) +, mStore_RowScopeToken( 0 ) +, mStore_TableScopeToken( 0 ) +, mStore_ColumnScopeToken( 0 ) +, mStore_TableKindToken( 0 ) + , mStore_RowSpaces(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap) , mStore_AtomSpaces(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap) , mStore_Pool(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap) @@ -220,6 +233,9 @@ morkStore::morkStore(morkEnv* ev, const morkUsage& inUsage, { mNode_Derived = morkDerived_kStore; + if ( ev->Good() ) + mStore_MorkNoneToken = this->StringToToken(ev, "mork:none"); + if ( ev->Good() ) mStore_CharsetToken = this->StringToToken(ev, "charset"); @@ -302,6 +318,28 @@ morkStore::AcquireStoreHandle(morkEnv* ev) } +morkMaxBookAtom* +morkStore::StageAliasAsBookAtom(morkEnv* ev, const morkMid* inMid, + morkAtomSpace* ioSpace, mork_cscode inForm) +{ + if ( inMid && inMid->mMid_Buf ) + { + const morkBuf* buf = inMid->mMid_Buf; + mork_size length = buf->mBuf_Fill; + if ( length <= morkBookAtom_kMaxBodySize ) + { + mork_aid dummyAid = 1; + mStore_BookAtom.InitMaxBookAtom(ev, *buf, + inForm, ioSpace, dummyAid); + return &mStore_BookAtom; + } + } + else + ev->NilPointerError(); + + return (morkMaxBookAtom*) 0; +} + morkMaxBookAtom* morkStore::StageYarnAsBookAtom(morkEnv* ev, const mdbYarn* inYarn, morkAtomSpace* ioSpace) @@ -436,6 +474,15 @@ morkStream* morkStore::LazyGetOutStream(morkEnv* ev) return mStore_OutStream; } +void +morkStore::ForgetBuilder(morkEnv* ev) +{ + if ( mStore_Builder ) + morkBuilder::SlotStrongBuilder((morkBuilder*) 0, ev, &mStore_Builder); + if ( mStore_InStream ) + morkStream::SlotStrongStream((morkStream*) 0, ev, &mStore_InStream); +} + morkBuilder* morkStore::LazyGetBuilder(morkEnv* ev) { if ( !mStore_Builder ) @@ -556,7 +603,7 @@ morkStore::CreateStoreFile(morkEnv* ev, } return ev->Good(); } - + morkAtom* morkStore::YarnToAtom(morkEnv* ev, const mdbYarn* inYarn) { @@ -586,10 +633,125 @@ morkStore::YarnToAtom(morkEnv* ev, const mdbYarn* inYarn) return outAtom; } -// mork_bool -// morkStore::CutBookAtom(morkEnv* ev, morkBookAtom* ioAtom) -// { -// } +mork_bool +morkStore::MidToOid(morkEnv* ev, const morkMid& inMid, mdbOid* outOid) +{ + *outOid = inMid.mMid_Oid; + const morkBuf* buf = inMid.mMid_Buf; + if ( buf && !outOid->mOid_Scope ) + { + mdbOid oid = inMid.mMid_Oid; + if ( buf->mBuf_Fill <= morkBookAtom_kMaxBodySize ) + { + if ( buf->mBuf_Fill == 1 ) + { + mork_u1* name = (mork_u1*) buf->mBuf_Body; + if ( name ) + { + outOid->mOid_Scope = (mork_scope) *name; + return ev->Good(); + } + } + morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev); + if ( groundSpace ) + { + mork_cscode form = 0; // default + mork_aid aid = 1; // dummy + mStore_BookAtom.InitMaxBookAtom(ev, *buf, form, groundSpace, aid); + morkMaxBookAtom* keyAtom = &mStore_BookAtom; + morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies; + morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom); + if ( bookAtom ) + outOid->mOid_Scope = bookAtom->mBookAtom_Id; + else + { + bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom); + if ( bookAtom ) + { + outOid->mOid_Scope = bookAtom->mBookAtom_Id; + bookAtom->MakeCellUseForever(ev); + } + } + } + } + } + return ev->Good(); +} + +morkRow* +morkStore::MidToRow(morkEnv* ev, const morkMid& inMid) +{ + mdbOid tempOid; + this->MidToOid(ev, inMid, &tempOid); + return this->OidToRow(ev, &tempOid); +} + +morkTable* +morkStore::MidToTable(morkEnv* ev, const morkMid& inMid) +{ + mdbOid tempOid; + this->MidToOid(ev, inMid, &tempOid); + return this->OidToTable(ev, &tempOid); +} + +mork_bool +morkStore::MidToYarn(morkEnv* ev, const morkMid& inMid, mdbYarn* outYarn) +{ + mdbOid tempOid; + this->MidToOid(ev, inMid, &tempOid); + return this->OidToYarn(ev, tempOid, outYarn); +} + +mork_bool +morkStore::OidToYarn(morkEnv* ev, const mdbOid& inOid, mdbYarn* outYarn) +{ + morkBookAtom* atom = 0; + + morkAtomSpace* atomSpace = mStore_AtomSpaces.GetAtomSpace(ev, inOid.mOid_Scope); + if ( atomSpace ) + { + morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids; + atom = map->GetAid(ev, (mork_aid) inOid.mOid_Id); + } + atom->GetYarn(outYarn); // note this is safe even when atom==nil + + return ev->Good(); +} + +morkBookAtom* +morkStore::MidToAtom(morkEnv* ev, const morkMid& inMid) +{ + morkBookAtom* outAtom = 0; + mdbOid oid; + if ( this->MidToOid(ev, inMid, &oid) ) + { + morkAtomSpace* atomSpace = mStore_AtomSpaces.GetAtomSpace(ev, oid.mOid_Scope); + if ( atomSpace ) + { + morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids; + outAtom = map->GetAid(ev, (mork_aid) oid.mOid_Id); + } + } + return outAtom; +} + +/*static*/ void +morkStore::SmallTokenToOneByteYarn(morkEnv* ev, mdb_token inToken, + mdbYarn* outYarn) +{ + if ( outYarn->mYarn_Buf && outYarn->mYarn_Size ) // any space in yarn at all? + { + mork_u1* buf = (mork_u1*) outYarn->mYarn_Buf; // for byte arithmetic + buf[ 0 ] = (mork_u1) inToken; // write the single byte + outYarn->mYarn_Fill = 1; + outYarn->mYarn_More = 0; + } + else // just record we could not write the single byte + { + outYarn->mYarn_More = 1; + outYarn->mYarn_Fill = 0; + } +} void morkStore::TokenToString(morkEnv* ev, mdb_token inToken, mdbYarn* outTokenName) @@ -604,23 +766,161 @@ morkStore::TokenToString(morkEnv* ev, mdb_token inToken, mdbYarn* outTokenName) atom->GetYarn(outTokenName); // note this is safe even when atom==nil } else // token is an "immediate" single byte string representation? + this->SmallTokenToOneByteYarn(ev, inToken, outTokenName); +} + +void +morkStore::SyncTokenIdChange(morkEnv* ev, const morkBookAtom* inAtom, + const mdbOid* inOid) +{ +// mork_token mStore_MorkNoneToken; // token for "mork:none" // fill=9 +// mork_column mStore_CharsetToken; // token for "charset" // fill=7 +// mork_column mStore_AtomScopeToken; // token for "atomScope" // fill=9 +// mork_column mStore_RowScopeToken; // token for "rowScope" // fill=8 +// mork_column mStore_TableScopeToken; // token for "tableScope" // fill=10 +// mork_column mStore_ColumnScopeToken; // token for "columnScope" // fill=11 +// mork_kind mStore_TableKindToken; // token for "tableKind" // fill=9 +// ---------------------ruler-for-token-length-above---123456789012 + + if ( inOid->mOid_Scope == morkStore_kColumnSpaceScope && inAtom->IsWeeBook() ) { - mdbYarn* y = outTokenName; - if ( y->mYarn_Buf && y->mYarn_Size ) // any space in yarn at all? + const mork_u1* body = ((const morkWeeBookAtom*) inAtom)->mWeeBookAtom_Body; + mork_size size = inAtom->mAtom_Size; + + if ( size >= 7 && size <= 11 ) { - mork_u1* buf = (mork_u1*) y->mYarn_Buf; // for byte arithmetic - buf[ 0 ] = (mork_u1) inToken; // write the single byte - y->mYarn_Fill = 1; - y->mYarn_More = 0; - } - else // just record we could not write the single byte - { - y->mYarn_More = 1; - y->mYarn_Fill = 0; + if ( size == 9 ) + { + if ( *body == 'm' ) + { + if ( MORK_MEMCMP(body, "mork:none", 9) == 0 ) + mStore_MorkNoneToken = inAtom->mBookAtom_Id; + } + else if ( *body == 'a' ) + { + if ( MORK_MEMCMP(body, "atomScope", 9) == 0 ) + mStore_AtomScopeToken = inAtom->mBookAtom_Id; + } + else if ( *body == 't' ) + { + if ( MORK_MEMCMP(body, "tableKind", 9) == 0 ) + mStore_TableKindToken = inAtom->mBookAtom_Id; + } + } + else if ( size == 7 && *body == 'c' ) + { + if ( MORK_MEMCMP(body, "charset", 7) == 0 ) + mStore_CharsetToken = inAtom->mBookAtom_Id; + } + else if ( size == 8 && *body == 'r' ) + { + if ( MORK_MEMCMP(body, "rowScope", 8) == 0 ) + mStore_RowScopeToken = inAtom->mBookAtom_Id; + } + else if ( size == 10 && *body == 't' ) + { + if ( MORK_MEMCMP(body, "tableScope", 10) == 0 ) + mStore_TableScopeToken = inAtom->mBookAtom_Id; + } + else if ( size == 11 && *body == 'c' ) + { + if ( MORK_MEMCMP(body, "columnScope", 11) == 0 ) + mStore_ColumnScopeToken = inAtom->mBookAtom_Id; + } } } } +morkAtom* +morkStore::AddAlias(morkEnv* ev, const morkMid& inMid, mork_cscode inForm) +{ + morkBookAtom* outAtom = 0; + if ( ev->Good() ) + { + const mdbOid* oid = &inMid.mMid_Oid; + morkAtomSpace* atomSpace = this->LazyGetAtomSpace(ev, oid->mOid_Scope); + if ( atomSpace ) + { + morkMaxBookAtom* keyAtom = + this->StageAliasAsBookAtom(ev, &inMid, atomSpace, inForm); + if ( keyAtom ) + { + morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids; + outAtom = map->GetAid(ev, (mork_aid) oid->mOid_Id); + if ( outAtom ) + { + if ( !outAtom->EqualFormAndBody(ev, keyAtom) ) + ev->NewError("duplicate alias ID"); + } + else + { + keyAtom->mBookAtom_Id = oid->mOid_Id; + outAtom = atomSpace->MakeBookAtomCopyWithAid(ev, + *keyAtom, (mork_aid) oid->mOid_Id); + + if ( outAtom && outAtom->IsWeeBook() ) + { + if ( oid->mOid_Scope == morkStore_kColumnSpaceScope ) + { + mork_size size = outAtom->mAtom_Size; + if ( size >= 7 && size <= 11 ) + this->SyncTokenIdChange(ev, outAtom, oid); + } + } + } + } + } + } + return outAtom; +} + +mork_token +morkStore::BufToToken(morkEnv* ev, const morkBuf* inBuf) +{ + mork_token outToken = 0; + if ( ev->Good() ) + { + const mork_u1* s = (const mork_u1*) inBuf->mBuf_Body; + mork_bool nonAscii = ( *s > 0x7F ); + mork_size length = inBuf->mBuf_Fill; + if ( nonAscii || length > 1 ) // more than one byte? + { + mork_cscode form = 0; // default charset + morkAtomSpace* space = this->LazyGetGroundColumnSpace(ev); + if ( space ) + { + morkMaxBookAtom* keyAtom = 0; + if ( length <= morkBookAtom_kMaxBodySize ) + { + mork_aid aid = 1; // dummy + mStore_BookAtom.InitMaxBookAtom(ev, *inBuf, form, space, aid); + keyAtom = &mStore_BookAtom; + } + if ( keyAtom ) + { + morkAtomBodyMap* map = &space->mAtomSpace_AtomBodies; + morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom); + if ( bookAtom ) + outToken = bookAtom->mBookAtom_Id; + else + { + bookAtom = space->MakeBookAtomCopy(ev, *keyAtom); + if ( bookAtom ) + { + outToken = bookAtom->mBookAtom_Id; + bookAtom->MakeCellUseForever(ev); + } + } + } + } + } + else // only a single byte in inTokenName string: + outToken = *s; + } + + return outToken; +} + mork_token morkStore::StringToToken(morkEnv* ev, const char* inTokenName) { @@ -702,6 +1002,8 @@ morkStore::HasTableKind(morkEnv* ev, mdb_scope inRowScope, mdb_kind inTableKind, mdb_count* outTableCount) { mork_bool outBool = morkBool_kFalse; + + ev->StubMethodOnlyError(); return outBool; } @@ -789,6 +1091,19 @@ morkStore::GetPortTableCursor(morkEnv* ev, mdb_scope inRowScope, return outCursor; } +morkRow* +morkStore::NewRow(morkEnv* ev, mdb_scope inRowScope) +{ + morkRow* outRow = 0; + if ( ev->Good() ) + { + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope); + if ( rowSpace ) + outRow = rowSpace->NewRow(ev); + } + return outRow; +} + morkRow* morkStore::NewRowWithOid(morkEnv* ev, const mdbOid* inOid) { @@ -803,16 +1118,42 @@ morkStore::NewRowWithOid(morkEnv* ev, const mdbOid* inOid) } morkRow* -morkStore::NewRow(morkEnv* ev, mdb_scope inRowScope) +morkStore::OidToRow(morkEnv* ev, const mdbOid* inOid) + // OidToRow() finds old row with oid, or makes new one if not found. { morkRow* outRow = 0; if ( ev->Good() ) { - morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope); + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope); if ( rowSpace ) - outRow = rowSpace->NewRow(ev); + { + outRow = rowSpace->mRowSpace_Rows.GetOid(ev, inOid); + if ( !outRow && ev->Good() ) + outRow = rowSpace->NewRowWithOid(ev, inOid); + } } return outRow; } +morkTable* +morkStore::OidToTable(morkEnv* ev, const mdbOid* inOid) + // OidToTable() finds old table with oid, or makes new one if not found. +{ + morkTable* outTable = 0; + if ( ev->Good() ) + { + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope); + if ( rowSpace ) + { + outTable = rowSpace->mRowSpace_Tables.GetTable(ev, inOid->mOid_Id); + if ( !outTable && ev->Good() ) + { + mork_kind tableKind = mStore_MorkNoneToken; + outTable = rowSpace->NewTableWithTid(ev, inOid->mOid_Id, tableKind); + } + } + } + return outTable; +} + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 diff --git a/mailnews/db/mork/src/morkStore.h b/mailnews/db/mork/src/morkStore.h index 2edbac96be3c..4c4c4d22610d 100644 --- a/mailnews/db/mork/src/morkStore.h +++ b/mailnews/db/mork/src/morkStore.h @@ -115,6 +115,7 @@ public: // typesafe refcounting inlines calling inherited morkNode methods **| all other explicitly tokenized strings. |*/ #define morkStore_kGroundColumnSpace 'c' /* for mStore_GroundColumnSpace*/ +#define morkStore_kColumnSpaceScope ((mork_scope) 'c') /*kGroundColumnSpace*/ #define morkStore_kGroundAtomSpace 'a' /* for mStore_GroundAtomSpace*/ #define morkStore_kStreamBufSize (8 * 1024) /* okay buffer size */ @@ -150,6 +151,7 @@ public: // state is public because the entire Mork system is private morkStream* mStore_OutStream; // stream using file used by the writer + mork_token mStore_MorkNoneToken; // token for "mork:none" mork_column mStore_CharsetToken; // token for "charset" mork_column mStore_AtomScopeToken; // token for "atomScope" mork_column mStore_RowScopeToken; // token for "rowScope" @@ -164,9 +166,17 @@ public: // state is public because the entire Mork system is private // we alloc a max size book atom to reuse space for atom map key searches: morkMaxBookAtom mStore_BookAtom; // staging area for atom map searches + +public: // coping with any changes to store token slots above: + + void SyncTokenIdChange(morkEnv* ev, const morkBookAtom* inAtom, + const mdbOid* inOid); public: // building an atom inside mStore_BookAtom from a char* string + morkMaxBookAtom* StageAliasAsBookAtom(morkEnv* ev, + const morkMid* inMid, morkAtomSpace* ioSpace, mork_cscode inForm); + morkMaxBookAtom* StageYarnAsBookAtom(morkEnv* ev, const mdbYarn* inYarn, morkAtomSpace* ioSpace); @@ -186,6 +196,7 @@ public: // lazy creation of members and nested row or atom spaces morkStream* LazyGetInStream(morkEnv* ev); morkBuilder* LazyGetBuilder(morkEnv* ev); + void ForgetBuilder(morkEnv* ev); morkStream* LazyGetOutStream(morkEnv* ev); @@ -221,6 +232,8 @@ public: // typing public: // store utilties morkAtom* YarnToAtom(morkEnv* ev, const mdbYarn* inYarn); + morkAtom* AddAlias(morkEnv* ev, const morkMid& inMid, + mork_cscode inForm); public: // other store methods @@ -239,11 +252,30 @@ public: // other store methods const char* inFilePath, const mdbOpenPolicy* inOpenPolicy); - // mork_bool CutBookAtom(morkEnv* ev, morkBookAtom* ioAtom); + mork_token BufToToken(morkEnv* ev, const morkBuf* inBuf); mork_token StringToToken(morkEnv* ev, const char* inTokenName); mork_token QueryToken(morkEnv* ev, const char* inTokenName); void TokenToString(morkEnv* ev, mdb_token inToken, mdbYarn* outTokenName); + mork_bool MidToOid(morkEnv* ev, const morkMid& inMid, + mdbOid* outOid); + mork_bool OidToYarn(morkEnv* ev, const mdbOid& inOid, mdbYarn* outYarn); + mork_bool MidToYarn(morkEnv* ev, const morkMid& inMid, + mdbYarn* outYarn); + + morkBookAtom* MidToAtom(morkEnv* ev, const morkMid& inMid); + morkRow* MidToRow(morkEnv* ev, const morkMid& inMid); + morkTable* MidToTable(morkEnv* ev, const morkMid& inMid); + + morkRow* OidToRow(morkEnv* ev, const mdbOid* inOid); + // OidToRow() finds old row with oid, or makes new one if not found. + + morkTable* OidToTable(morkEnv* ev, const mdbOid* inOid); + // OidToTable() finds old table with oid, or makes new one if not found. + + static void SmallTokenToOneByteYarn(morkEnv* ev, mdb_token inToken, + mdbYarn* outYarn); + mork_bool HasTableKind(morkEnv* ev, mdb_scope inRowScope, mdb_kind inTableKind, mdb_count* outTableCount); diff --git a/mailnews/db/mork/src/morkStream.cpp b/mailnews/db/mork/src/morkStream.cpp index e7d33fe4239e..6855235ad22e 100644 --- a/mailnews/db/mork/src/morkStream.cpp +++ b/mailnews/db/mork/src/morkStream.cpp @@ -75,7 +75,7 @@ morkStream::morkStream(morkEnv* ev, const morkUsage& inUsage, , mStream_ContentFile( 0 ) , mStream_Buf( 0 ) -, mStream_BufSize( 0 ) +, mStream_BufSize( inBufSize ) , mStream_BufPos( 0 ) , mStream_Dirty( morkBool_kFalse ) , mStream_HitEof( morkBool_kFalse ) @@ -329,7 +329,7 @@ morkStream::PutByteThenNewlineThenSpace(morkEnv* ev, int inByte) mork_size morkStream::PutLineBreak(morkEnv* ev) { -#ifdef MORK_MAC +#if defined(MORK_MAC) || defined(MORK_OBSOLETE) this->Putc(ev, mork_kCR); return 1; diff --git a/mailnews/db/mork/src/morkStream.h b/mailnews/db/mork/src/morkStream.h index 464383fcef3f..1285f33ad0e3 100644 --- a/mailnews/db/mork/src/morkStream.h +++ b/mailnews/db/mork/src/morkStream.h @@ -212,6 +212,7 @@ public: // public non-poly morkStream methods void Ungetc(int c) /*i*/ { if ( mStream_At > mStream_Buf && c > 0 ) *--mStream_At = c; } + // Note Getc() returns EOF consistently after any fill_getc() error occurs. int Getc(morkEnv* ev) /*i*/ { return ( mStream_At < mStream_ReadEnd )? *mStream_At++ : fill_getc(ev); } diff --git a/mailnews/db/mork/src/morkTable.cpp b/mailnews/db/mork/src/morkTable.cpp index 8ecc8b9ef9ca..f507d09efc6d 100644 --- a/mailnews/db/mork/src/morkTable.cpp +++ b/mailnews/db/mork/src/morkTable.cpp @@ -147,6 +147,35 @@ morkTable::CloseTable(morkEnv* ev) /*i*/ // called by CloseMorkNode(); // } ===== end morkNode methods ===== // ````` ````` ````` ````` ````` +mork_u2 +morkTable::AddCellUse(morkEnv* ev) +{ + if ( mTable_CellUses < morkTable_kMaxCellUses ) // not already maxed out? + ++mTable_CellUses; + + return mTable_CellUses; +} + +mork_u2 +morkTable::CutCellUse(morkEnv* ev) +{ + if ( mTable_CellUses ) // any outstanding uses to cut? + { + if ( mTable_CellUses < morkTable_kMaxCellUses ) // not frozen at max? + --mTable_CellUses; + } + else + this->CellUsesUnderflowWarning(ev); + + return mTable_CellUses; +} + +/*static*/ void +morkTable::CellUsesUnderflowWarning(morkEnv* ev) +{ + ev->NewWarning("mTable_CellUses underflow"); +} + /*static*/ void morkTable::NonTableTypeError(morkEnv* ev) { diff --git a/mailnews/db/mork/src/morkTable.h b/mailnews/db/mork/src/morkTable.h index 4a4291e33e4b..492816e89446 100644 --- a/mailnews/db/mork/src/morkTable.h +++ b/mailnews/db/mork/src/morkTable.h @@ -51,6 +51,7 @@ class nsIMdbTable; #define morkTable_kStartRowArraySize 11 /* modest starting size for array */ #define morkTable_kStartRowMapSlotCount 128 +#define morkTable_kMaxCellUses 0x0FFFF /* max for 16-bit unsigned int */ class morkTable : public morkObject { @@ -85,7 +86,8 @@ public: // state is public because the entire Mork system is private mork_kind mTable_Kind; mork_bool mTable_MustBeUnique; - mork_u1 mTable_Pad[ 3 ]; // padding to u4 alignment + mork_u1 mTable_Pad; // padding for u4 alignment + mork_u2 mTable_CellUses; // persistent references from cells // { ===== begin morkNode interface ===== public: // morkNode virtual methods @@ -109,12 +111,18 @@ public: // dynamic type identification { return IsNode() && mNode_Derived == morkDerived_kTable; } // } ===== end morkNode methods ===== -public: // typing +public: // errors static void NonTableTypeError(morkEnv* ev); static void NonTableTypeWarning(morkEnv* ev); static void NilRowSpaceError(morkEnv* ev); +public: // warnings + static void CellUsesUnderflowWarning(morkEnv* ev); + public: // other table methods + + mork_u2 AddCellUse(morkEnv* ev); + mork_u2 CutCellUse(morkEnv* ev); // void DirtyAllTableContent(morkEnv* ev); @@ -137,7 +145,7 @@ public: // typesafe refcounting inlines calling inherited morkNode methods morkEnv* ev, morkTable** ioSlot) { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); } - static void SlotStrongTableS(morkTable* me, + static void SlotStrongTable(morkTable* me, morkEnv* ev, morkTable** ioSlot) { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); } }; diff --git a/mailnews/db/mork/src/morkThumb.cpp b/mailnews/db/mork/src/morkThumb.cpp index 9044930833f4..d50be5bfadbc 100644 --- a/mailnews/db/mork/src/morkThumb.cpp +++ b/mailnews/db/mork/src/morkThumb.cpp @@ -52,6 +52,18 @@ #include "morkWriter.h" #endif +#ifndef _MORKPARSER_ +#include "morkParser.h" +#endif + +#ifndef _MORKBUILDER_ +#include "morkBuilder.h" +#endif + +#ifndef _MORKFILE_ +#include "morkFile.h" +#endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 // ````` ````` ````` ````` ````` @@ -92,6 +104,7 @@ morkThumb::morkThumb(morkEnv* ev, , mThumb_Store( 0 ) , mThumb_File( 0 ) , mThumb_Writer( 0 ) +, mThumb_Builder( 0 ) , mThumb_SourcePort( 0 ) , mThumb_DoCollect( morkBool_kFalse ) @@ -111,9 +124,13 @@ morkThumb::CloseThumb(morkEnv* ev) // called by CloseMorkNode(); if ( this->IsNode() ) { mThumb_Magic = 0; + if ( mThumb_Builder && mThumb_Store ) + mThumb_Store->ForgetBuilder(ev); + morkBuilder::SlotStrongBuilder((morkBuilder*) 0, ev, &mThumb_Builder); + morkWriter::SlotStrongWriter((morkWriter*) 0, ev, &mThumb_Writer); morkFile::SlotStrongFile((morkFile*) 0, ev, &mThumb_File); - morkStore::SlotWeakStore((morkStore*) 0, ev, &mThumb_Store); + morkStore::SlotStrongStore((morkStore*) 0, ev, &mThumb_Store); morkPort::SlotStrongPort((morkPort*) 0, ev, &mThumb_SourcePort); this->MarkShut(); } @@ -152,6 +169,11 @@ morkThumb::CloseThumb(morkEnv* ev) // called by CloseMorkNode(); ev->NewError("nil mThumb_Writer"); } +/*static*/ void morkThumb::NilThumbBuilderError(morkEnv* ev) +{ + ev->NewError("nil mThumb_Builder"); +} + /*static*/ void morkThumb::NilThumbSourcePortError(morkEnv* ev) { ev->NewError("nil mThumb_SourcePort"); @@ -181,14 +203,31 @@ morkThumb::Make_OpenFileStore(morkEnv* ev, nsIMdbHeap* ioHeap, morkThumb* outThumb = 0; if ( ioHeap && ioStore ) { - outThumb = new(*ioHeap, ev) - morkThumb(ev, morkUsage::kHeap, ioHeap, ioHeap, - morkThumb_kMagic_OpenFileStore); - - if ( outThumb ) + morkFile* file = ioStore->mStore_File; + if ( file ) { - morkStore::SlotWeakStore(ioStore, ev, &outThumb->mThumb_Store); + mork_pos fileEof = file->Length(ev); + if ( ev->Good() ) + { + outThumb = new(*ioHeap, ev) + morkThumb(ev, morkUsage::kHeap, ioHeap, ioHeap, + morkThumb_kMagic_OpenFileStore); + + if ( outThumb ) + { + morkBuilder* builder = ioStore->LazyGetBuilder(ev); + if ( builder ) + { + outThumb->mThumb_Total = fileEof; + morkStore::SlotStrongStore(ioStore, ev, &outThumb->mThumb_Store); + morkBuilder::SlotStrongBuilder(builder, ev, + &outThumb->mThumb_Builder); + } + } + } } + else + ioStore->NilStoreFileError(ev); } else ev->NilPointerError(); @@ -219,7 +258,7 @@ morkThumb::Make_CompressCommit(morkEnv* ev, { writer->mWriter_NeedDirtyAll = morkBool_kTrue; outThumb->mThumb_DoCollect = inDoCollect; - morkStore::SlotWeakStore(ioStore, ev, &outThumb->mThumb_Store); + morkStore::SlotStrongStore(ioStore, ev, &outThumb->mThumb_Store); morkFile::SlotStrongFile(file, ev, &outThumb->mThumb_File); morkWriter::SlotStrongWriter(writer, ev, &outThumb->mThumb_Writer); } @@ -330,7 +369,21 @@ void morkThumb::DoMore_OpenFilePort(morkEnv* ev) void morkThumb::DoMore_OpenFileStore(morkEnv* ev) { - this->UnsupportedThumbMagicError(ev); + morkBuilder* builder = mThumb_Builder; + if ( builder ) + { + mork_pos pos = 0; + builder->ParseMore(ev, &pos, &mThumb_Done, &mThumb_Broken); + // mThumb_Total = builder->mBuilder_TotalCount; + // mThumb_Current = builder->mBuilder_DoneCount; + mThumb_Current = pos; + } + else + { + this->NilThumbBuilderError(ev); + mThumb_Broken = morkBool_kTrue; + mThumb_Done = morkBool_kTrue; + } } void morkThumb::DoMore_ExportToFormat(morkEnv* ev) diff --git a/mailnews/db/mork/src/morkThumb.h b/mailnews/db/mork/src/morkThumb.h index 39a78515c598..5c034728ff4d 100644 --- a/mailnews/db/mork/src/morkThumb.h +++ b/mailnews/db/mork/src/morkThumb.h @@ -84,6 +84,7 @@ public: // state is public because the entire Mork system is private morkStore* mThumb_Store; // weak ref to created store morkFile* mThumb_File; // strong ref to file (store, import, export) morkWriter* mThumb_Writer; // strong ref to writer (for commit) + morkBuilder* mThumb_Builder; // strong ref to builder (for store open) morkPort* mThumb_SourcePort; // strong ref to port for import mork_bool mThumb_DoCollect; // influence whether a collect happens @@ -115,6 +116,7 @@ public: // typing static void NilThumbStoreError(morkEnv* ev); static void NilThumbFileError(morkEnv* ev); static void NilThumbWriterError(morkEnv* ev); + static void NilThumbBuilderError(morkEnv* ev); static void NilThumbSourcePortError(morkEnv* ev); public: // 'do more' methods diff --git a/mailnews/db/mork/src/morkWriter.cpp b/mailnews/db/mork/src/morkWriter.cpp index 2fc18064c0a0..082b153848da 100644 --- a/mailnews/db/mork/src/morkWriter.cpp +++ b/mailnews/db/mork/src/morkWriter.cpp @@ -84,6 +84,10 @@ #include "morkAtom.h" #endif +#ifndef _MORKCH_ +#include "morkCh.h" +#endif + //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 // ````` ````` ````` ````` ````` @@ -123,6 +127,7 @@ morkWriter::morkWriter(morkEnv* ev, const morkUsage& inUsage, , mWriter_LineSize( 0 ) , mWriter_MaxIndent( morkWriter_kMaxIndent ) +, mWriter_MaxLine( morkWriter_kMaxLine ) , mWriter_TableCharset( 0 ) , mWriter_TableAtomScope( 0 ) @@ -362,15 +367,16 @@ morkWriter::WriteYarn(morkEnv* ev, const mdbYarn* inYarn) while ( b < end ) { c = *b++; // next byte to print - if ( c < 0x080 && MORK_ISPRINT(c) ) + if ( morkCh_IsValue(c) ) { - if ( c == ')' && c == '$' && c == '\\' ) - { - stream->Putc(ev, '\\'); - ++outSize; - } stream->Putc(ev, c); - ++outSize; + ++outSize; // c + } + else if ( c == ')' && c == '$' && c == '\\' ) + { + stream->Putc(ev, '\\'); + stream->Putc(ev, c); + outSize += 2; // '\' c } else { @@ -396,8 +402,13 @@ morkWriter::WriteAtom(morkEnv* ev, const morkAtom* inAtom) mdbYarn yarn; // to ref content inside atom if ( inAtom->AliasYarn(&yarn) ) + { + if ( mWriter_DidStartDict && yarn.mYarn_Form != mWriter_DictCharset ) + this->ChangeDictCharset(ev, yarn.mYarn_Form); + outSize = this->WriteYarn(ev, &yarn); // mWriter_LineSize += stream->Write(ev, inYarn->mYarn_Buf, outSize); + } else inAtom->BadAtomKindError(ev); @@ -424,6 +435,7 @@ morkWriter::WriteAtomSpaceAsDict(morkEnv* ev, morkAtomSpace* ioSpace) if ( ev->Good() ) { + mdbYarn yarn; // to ref content inside atom char buf[ 64 ]; // buffer for staging the dict alias hex ID char* idBuf = buf + 1; // where the id always starts buf[ 0 ] = '('; // we always start with open paren @@ -442,15 +454,23 @@ morkWriter::WriteAtomSpaceAsDict(morkEnv* ev, morkAtomSpace* ioSpace) { atom->mAtom_Change = morkChange_kNil; // neutralize change - this->IndentAsNeeded(ev, morkWriter_kDictAliasDepth); + atom->AliasYarn(&yarn); mork_size size = ev->TokenAsHex(idBuf, atom->mBookAtom_Id); - mWriter_LineSize += stream->Write(ev, buf, size+1); // '(' - this->IndentAsNeeded(ev, morkWriter_kDictAliasValueDepth); - stream->Putc(ev, '='); // end alias + if ( yarn.mYarn_Form != mWriter_DictCharset ) + this->ChangeDictCharset(ev, yarn.mYarn_Form); + + mork_size pending = yarn.mYarn_Fill + size + + morkWriter_kYarnEscapeSlop + 4; + this->IndentOverMaxLine(ev, pending, morkWriter_kDictAliasDepth); + mWriter_LineSize += stream->Write(ev, buf, size+1); // + '(' + + pending -= ( size + 1 ); + this->IndentOverMaxLine(ev, pending, morkWriter_kDictAliasValueDepth); + stream->Putc(ev, '='); // start alias ++mWriter_LineSize; - this->WriteAtom(ev, atom); + this->WriteYarn(ev, &yarn); stream->Putc(ev, ')'); // end alias ++mWriter_LineSize; @@ -1037,22 +1057,40 @@ morkWriter::WriteStringToTokenDictCell(morkEnv* ev, // mWriter_LineSize += stream->Write(ev, yarnBuf, fill + 1); // +1 for ')' } +void +morkWriter::ChangeDictCharset(morkEnv* ev, mork_cscode inNewForm) +{ + if ( inNewForm != mWriter_DictCharset ) + { + morkStream* stream = mWriter_Stream; + if ( mWriter_LineSize ) + stream->PutLineBreak(ev); + mWriter_LineSize = 0; + + stream->Putc(ev, '<'); + this->WriteStringToTokenDictCell(ev, "(charset=", mWriter_DictCharset); + stream->Putc(ev, '>'); + ++mWriter_LineSize; + + mWriter_DictCharset = inNewForm; + } +} + void morkWriter::StartDict(morkEnv* ev) { morkStream* stream = mWriter_Stream; if ( mWriter_DidStartDict ) { - if ( mWriter_LineSize ) - stream->PutLineBreak(ev); - stream->PutStringThenNewline(ev, "> // end dict"); - mWriter_LineSize = 0; + stream->Putc(ev, '>'); // end dict + ++mWriter_LineSize; } mWriter_DidStartDict = morkBool_kTrue; if ( mWriter_LineSize ) stream->PutLineBreak(ev); mWriter_LineSize = 0; + stream->PutLineBreak(ev); if ( mWriter_DictCharset || mWriter_DictAtomScope != 'a' ) { stream->Putc(ev, '<'); @@ -1069,7 +1107,9 @@ morkWriter::StartDict(morkEnv* ev) } else { - stream->PutString(ev, "< // <(charset=iso-8859-1)(atomScope=a)>"); + stream->Putc(ev, '<'); + stream->Putc(ev, ' '); + mWriter_LineSize += 2; } mWriter_LineSize = stream->PutIndent(ev, morkWriter_kDictAliasDepth); } @@ -1080,10 +1120,8 @@ morkWriter::EndDict(morkEnv* ev) morkStream* stream = mWriter_Stream; if ( mWriter_DidStartDict ) { - if ( mWriter_LineSize ) - stream->PutLineBreak(ev); - stream->PutStringThenNewline(ev, "> // end dict"); - mWriter_LineSize = 0; + stream->Putc(ev, '>'); // end dict + ++mWriter_LineSize; } mWriter_DidStartDict = morkBool_kFalse; } @@ -1100,6 +1138,7 @@ morkWriter::StartTable(morkEnv* ev, morkTable* ioTable) if ( mWriter_LineSize ) stream->PutLineBreak(ev); mWriter_LineSize = 0; + stream->PutLineBreak(ev); char buf[ 64 ]; // buffer for staging hex char* p = buf; @@ -1123,9 +1162,8 @@ morkWriter::StartTable(morkEnv* ev, morkTable* ioTable) this->IndentAsNeeded(ev, morkWriter_kTableMetaCellDepth); this->WriteTokenToTokenMetaCell(ev, store->mStore_TableKindToken, tk); } - stream->Putc(ev, '}'); - stream->Putc(ev, ' '); - mWriter_LineSize += 2; + stream->Putc(ev, '}'); // end meta + mWriter_LineSize = stream->PutIndent(ev, morkWriter_kRowCellDepth); } } @@ -1133,10 +1171,8 @@ void morkWriter::EndTable(morkEnv* ev) { morkStream* stream = mWriter_Stream; - if ( mWriter_LineSize ) - stream->PutLineBreak(ev); - stream->PutStringThenNewline(ev, "} // end table"); - mWriter_LineSize = 0; + stream->Putc(ev, '}'); // end table + ++mWriter_LineSize; } mork_bool @@ -1208,9 +1244,9 @@ morkWriter::PutRowCells(morkEnv* ev, morkRow* ioRow) colSize = ev->TokenAsHex(p, col); p += colSize; - this->IndentAsNeeded(ev, morkWriter_kRowCellDepth); if ( atom->IsBook() ) // is it possible to write atom ID? { + this->IndentAsNeeded(ev, morkWriter_kRowCellDepth); *p++ = '^'; morkBookAtom* ba = (morkBookAtom*) atom; mork_size valSize = ev->TokenAsHex(p, ba->mBookAtom_Id); @@ -1227,13 +1263,24 @@ morkWriter::PutRowCells(morkEnv* ev, morkRow* ioRow) } else // must write an anonymous atom { + mdbYarn yarn; // to ref content inside atom + atom->AliasYarn(&yarn); + + if ( yarn.mYarn_Form != mWriter_DictCharset ) + this->ChangeDictCharset(ev, yarn.mYarn_Form); + + mork_size pending = yarn.mYarn_Fill + colSize + + morkWriter_kYarnEscapeSlop + 2; + this->IndentOverMaxLine(ev, pending, morkWriter_kRowCellDepth); + mWriter_LineSize += stream->Write(ev, buf, colSize + 2); - this->IndentAsNeeded(ev, morkWriter_kRowCellValueDepth); + pending -= ( colSize + 2 ); + this->IndentOverMaxLine(ev, pending, morkWriter_kRowCellDepth); stream->Putc(ev, '='); ++mWriter_LineSize; - this->WriteAtom(ev, atom); + this->WriteYarn(ev, &yarn); stream->Putc(ev, ')'); // end alias ++mWriter_LineSize; } @@ -1254,8 +1301,8 @@ morkWriter::PutRow(morkEnv* ev, morkRow* ioRow) this->IndentAsNeeded(ev, morkWriter_kRowDepth); - // if ( ioRow->IsRowDirty() ) - if ( morkBool_kTrue ) + //if ( morkBool_kTrue ) + if ( ioRow->IsRowDirty() ) { ioRow->SetRowClean(); mork_rid rid = roid->mOid_Id; @@ -1271,8 +1318,7 @@ morkWriter::PutRow(morkEnv* ev, morkRow* ioRow) this->PutRowCells(ev, ioRow); stream->Putc(ev, ']'); // end row - stream->Putc(ev, ' '); // end row - mWriter_LineSize += 2; + ++mWriter_LineSize; } else { diff --git a/mailnews/db/mork/src/morkWriter.h b/mailnews/db/mork/src/morkWriter.h index 51c79bfd74b5..8b446eec13d7 100644 --- a/mailnews/db/mork/src/morkWriter.h +++ b/mailnews/db/mork/src/morkWriter.h @@ -58,7 +58,7 @@ //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 -#define morkWriter_kStreamBufSize /*i*/ (16) /* buffer size for stream */ +#define morkWriter_kStreamBufSize /*i*/ (16 * 1024) /* buffer size for stream */ #define morkDerived_kWriter /*i*/ 0x5772 /* ascii 'Wr' */ @@ -85,7 +85,10 @@ #define morkWriter_kMaxColumnNameSize 128 /* longest writable col name */ -#define morkWriter_kMaxIndent 48 /* default value for mWriter_MaxIndent */ +#define morkWriter_kMaxIndent 56 /* default value for mWriter_MaxIndent */ +#define morkWriter_kMaxLine 78 /* default value for mWriter_MaxLine */ + +#define morkWriter_kYarnEscapeSlop 4 /* guess average yarn escape overhead */ #define morkWriter_kTableMetaCellDepth 4 /* */ #define morkWriter_kTableMetaCellValueDepth 6 /* */ @@ -126,6 +129,7 @@ public: // state is public because the entire Mork system is private mork_size mWriter_LineSize; // length of current line being written mork_size mWriter_MaxIndent; // line size forcing a line break + mork_size mWriter_MaxLine; // line size forcing a value continuation mork_cscode mWriter_TableCharset; // current charset metainfo mork_scope mWriter_TableAtomScope; // current atom scope @@ -195,6 +199,7 @@ public: // typing & errors static void UnsupportedPhaseError(morkEnv* ev); public: // inlines + void ChangeDictCharset(morkEnv* ev, mork_cscode inNewForm); mork_bool DidStartDict() const { return mWriter_DidStartDict; } mork_bool DidEndDict() const { return mWriter_DidEndDict; } @@ -206,6 +211,13 @@ public: // inlines if ( mWriter_LineSize > mWriter_MaxIndent ) mWriter_LineSize = mWriter_Stream->PutIndent(ev, inDepth); } + + void IndentOverMaxLine(morkEnv* ev, + mork_size inPendingSize, mork_size inDepth) + { + if ( mWriter_LineSize + inPendingSize > mWriter_MaxLine ) + mWriter_LineSize = mWriter_Stream->PutIndent(ev, inDepth); + } public: // iterative/asynchronouse writing