Back to index

lightning-sunbird  0.9+nobinonly
morkParser.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifndef _MDB_
00039 #include "mdb.h"
00040 #endif
00041 
00042 #ifndef _MORK_
00043 #include "mork.h"
00044 #endif
00045 
00046 #ifndef _MORKNODE_
00047 #include "morkNode.h"
00048 #endif
00049 
00050 #ifndef _MORKMAP_
00051 #include "morkMap.h"
00052 #endif
00053 
00054 #ifndef _MORKENV_
00055 #include "morkEnv.h"
00056 #endif
00057 
00058 #ifndef _MORKPARSER_
00059 #include "morkParser.h"
00060 #endif
00061 
00062 #ifndef _MORKSTREAM_
00063 #include "morkStream.h"
00064 #endif
00065 
00066 #ifndef _MORKBLOB_
00067 #include "morkBlob.h"
00068 #endif
00069 
00070 #ifndef _MORKSINK_
00071 #include "morkSink.h"
00072 #endif
00073 
00074 #ifndef _MORKCH_
00075 #include "morkCh.h"
00076 #endif
00077 
00078 #ifndef _MORKSTORE_
00079 #include "morkStore.h"
00080 #endif
00081 
00082 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00083 
00084 // ````` ````` ````` ````` ````` 
00085 // { ===== begin morkNode interface =====
00086 
00087 /*public virtual*/ void
00088 morkParser::CloseMorkNode(morkEnv* ev) // CloseParser() only if open
00089 {
00090   if ( this->IsOpenNode() )
00091   {
00092     this->MarkClosing();
00093     this->CloseParser(ev);
00094     this->MarkShut();
00095   }
00096 }
00097 
00098 /*public virtual*/
00099 morkParser::~morkParser() // assert CloseParser() executed earlier
00100 {
00101   MORK_ASSERT(mParser_Heap==0);
00102   MORK_ASSERT(mParser_Stream==0);
00103 }
00104 
00105 /*public non-poly*/
00106 morkParser::morkParser(morkEnv* ev,
00107   const morkUsage& inUsage, nsIMdbHeap* ioHeap, 
00108   morkStream* ioStream, mdb_count inBytesPerParseSegment,
00109   nsIMdbHeap* ioSlotHeap)
00110 : morkNode(ev, inUsage, ioHeap)
00111 , mParser_Heap( 0 )
00112 , mParser_Stream( 0 )
00113 , mParser_MoreGranularity( inBytesPerParseSegment )
00114 , mParser_State( morkParser_kStartState )
00115 
00116 , mParser_GroupContentStartPos( 0 )
00117 
00118 , mParser_TableMid(  )
00119 , mParser_RowMid(  )
00120 , mParser_CellMid(  )
00121     
00122 , mParser_InPort( morkBool_kFalse )
00123 , mParser_InDict( morkBool_kFalse )
00124 , mParser_InCell( morkBool_kFalse )
00125 , mParser_InMeta( morkBool_kFalse )
00126     
00127 , mParser_InPortRow( morkBool_kFalse )
00128 , mParser_InRow( morkBool_kFalse )
00129 , mParser_InTable( morkBool_kFalse )
00130 , mParser_InGroup( morkBool_kFalse )
00131 
00132 , mParser_AtomChange( morkChange_kNil )
00133 , mParser_CellChange( morkChange_kNil )
00134 , mParser_RowChange( morkChange_kNil )
00135 , mParser_TableChange( morkChange_kNil )
00136 
00137 , mParser_Change( morkChange_kNil )
00138 , mParser_IsBroken( morkBool_kFalse )
00139 , mParser_IsDone( morkBool_kFalse )
00140 , mParser_DoMore( morkBool_kTrue )
00141     
00142 , mParser_Mid()
00143 
00144 , mParser_ScopeCoil(ev, ioSlotHeap)
00145 , mParser_ValueCoil(ev, ioSlotHeap)
00146 , mParser_ColumnCoil(ev, ioSlotHeap)
00147 , mParser_StringCoil(ev, ioSlotHeap)
00148 
00149 , mParser_ScopeSpool(ev, &mParser_ScopeCoil)
00150 , mParser_ValueSpool(ev, &mParser_ValueCoil)
00151 , mParser_ColumnSpool(ev, &mParser_ColumnCoil)
00152 , mParser_StringSpool(ev, &mParser_StringCoil)
00153 
00154 , mParser_MidYarn(ev, morkUsage_kMember, ioSlotHeap)
00155 {
00156   if ( inBytesPerParseSegment < morkParser_kMinGranularity )
00157     inBytesPerParseSegment = morkParser_kMinGranularity;
00158   else if ( inBytesPerParseSegment > morkParser_kMaxGranularity )
00159     inBytesPerParseSegment = morkParser_kMaxGranularity;
00160     
00161   mParser_MoreGranularity = inBytesPerParseSegment;
00162 
00163   if ( ioSlotHeap && ioStream )
00164   {
00165     nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mParser_Heap);
00166     morkStream::SlotStrongStream(ioStream, ev, &mParser_Stream);
00167     
00168     if ( ev->Good() )
00169     {
00170       mParser_Tag = morkParser_kTag;
00171       mNode_Derived = morkDerived_kParser;
00172     }
00173   }
00174   else
00175     ev->NilPointerError();
00176 }
00177 
00178 /*public non-poly*/ void
00179 morkParser::CloseParser(morkEnv* ev) // called by CloseMorkNode();
00180 {
00181   if ( this )
00182   {
00183     if ( this->IsNode() )
00184     {
00185       if ( !this->IsShutNode() )
00186       {
00187         mParser_ScopeCoil.CloseCoil(ev);
00188         mParser_ValueCoil.CloseCoil(ev);
00189         mParser_ColumnCoil.CloseCoil(ev);
00190         mParser_StringCoil.CloseCoil(ev);
00191         nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mParser_Heap);
00192         morkStream::SlotStrongStream((morkStream*) 0, ev, &mParser_Stream);
00193         this->MarkShut();
00194       }
00195     }
00196     else
00197       this->NonNodeError(ev);
00198   }
00199   else
00200     ev->NilPointerError();
00201 }
00202 
00203 // } ===== end morkNode methods =====
00204 // ````` ````` ````` ````` ````` 
00205 
00206 /*protected non-poly*/ void
00207 morkParser::NonGoodParserError(morkEnv* ev) // when GoodParserTag() is false
00208 {
00209   ev->NewError("non-morkNode");
00210 }
00211 
00212 /*protected non-poly*/ void
00213 morkParser::NonUsableParserError(morkEnv* ev) //
00214 {
00215   if ( this->IsNode() )
00216   {
00217     if ( this->IsOpenNode() )
00218     {
00219       if (  this->GoodParserTag() )
00220       {
00221          // okay
00222       }
00223       else
00224         this->NonGoodParserError(ev);
00225     }
00226     else
00227       this->NonOpenNodeError(ev);
00228   }
00229   else
00230     this->NonNodeError(ev);
00231 }
00232 
00233 
00234 /*protected non-poly*/ void
00235 morkParser::StartParse(morkEnv* ev)
00236 {
00237   MORK_USED_1(ev);
00238   mParser_InCell = morkBool_kFalse;
00239   mParser_InMeta = morkBool_kFalse;
00240   mParser_InDict = morkBool_kFalse;
00241   mParser_InPortRow = morkBool_kFalse;
00242   
00243   mParser_RowMid.ClearMid();
00244   mParser_TableMid.ClearMid();
00245   mParser_CellMid.ClearMid();
00246   
00247   mParser_GroupId = 0;
00248   mParser_InPort = morkBool_kTrue;
00249 
00250   mParser_GroupSpan.ClearSpan();
00251   mParser_DictSpan.ClearSpan();
00252   mParser_AliasSpan.ClearSpan();
00253   mParser_MetaSpan.ClearSpan();
00254   mParser_TableSpan.ClearSpan();
00255   mParser_RowSpan.ClearSpan();
00256   mParser_CellSpan.ClearSpan();
00257   mParser_ColumnSpan.ClearSpan();
00258   mParser_SlotSpan.ClearSpan();
00259 
00260    mParser_PortSpan.ClearSpan();
00261 }
00262 
00263 /*protected non-poly*/ void
00264 morkParser::StopParse(morkEnv* ev)
00265 {
00266   if ( mParser_InCell )
00267   {
00268     mParser_InCell = morkBool_kFalse;
00269     mParser_CellSpan.SetEndWithEnd(mParser_PortSpan);
00270     this->OnCellEnd(ev, mParser_CellSpan);
00271   }
00272   if ( mParser_InMeta )
00273   {
00274     mParser_InMeta = morkBool_kFalse;
00275     mParser_MetaSpan.SetEndWithEnd(mParser_PortSpan);
00276     this->OnMetaEnd(ev, mParser_MetaSpan);
00277   }
00278   if ( mParser_InDict )
00279   {
00280     mParser_InDict = morkBool_kFalse;
00281     mParser_DictSpan.SetEndWithEnd(mParser_PortSpan);
00282     this->OnDictEnd(ev, mParser_DictSpan);
00283   }
00284   if ( mParser_InPortRow )
00285   {
00286     mParser_InPortRow = morkBool_kFalse;
00287     mParser_RowSpan.SetEndWithEnd(mParser_PortSpan);
00288     this->OnPortRowEnd(ev, mParser_RowSpan);
00289   }
00290   if ( mParser_InRow )
00291   {
00292     mParser_InRow = morkBool_kFalse;
00293     mParser_RowMid.ClearMid();
00294     mParser_RowSpan.SetEndWithEnd(mParser_PortSpan);
00295     this->OnRowEnd(ev, mParser_RowSpan);
00296   }
00297   if ( mParser_InTable )
00298   {
00299     mParser_InTable = morkBool_kFalse;
00300     mParser_TableMid.ClearMid();
00301     mParser_TableSpan.SetEndWithEnd(mParser_PortSpan);
00302     this->OnTableEnd(ev, mParser_TableSpan);
00303   }
00304   if ( mParser_GroupId )
00305   {
00306     mParser_GroupId = 0;
00307     mParser_GroupSpan.SetEndWithEnd(mParser_PortSpan);
00308     this->OnGroupAbortEnd(ev, mParser_GroupSpan);
00309   }
00310   if ( mParser_InPort )
00311   {
00312     mParser_InPort = morkBool_kFalse;
00313     this->OnPortEnd(ev, mParser_PortSpan);
00314   }
00315 }
00316 
00317 int morkParser::eat_comment(morkEnv* ev) // last char was '/'
00318 {
00319   morkStream* s = mParser_Stream;
00320   // Note morkStream::Getc() returns EOF when an error occurs, so
00321   // we don't need to check for both c != EOF and ev->Good() below.
00322   
00323   register int c = s->Getc(ev);
00324   if ( c == '/' ) // C++ style comment?
00325   {
00326     while ( (c = s->Getc(ev)) != EOF && c != 0xA && c != 0xD )
00327       /* empty */;
00328       
00329     if ( c == 0xA || c == 0xD )
00330       c = this->eat_line_break(ev, c);
00331   }
00332   else if ( c == '*' ) /* C style comment? */
00333   {
00334     int depth = 1; // count depth of comments until depth reaches zero
00335     
00336     while ( depth > 0 && c != EOF ) // still looking for comment end(s)?
00337     {
00338       while ( (c = s->Getc(ev)) != EOF && c != '/' && c != '*' )
00339       {
00340         if ( c == 0xA || c == 0xD ) // need to count a line break?
00341         {
00342           c = this->eat_line_break(ev, c);
00343           if ( c == '/' || c == '*' )
00344             break; // end while loop
00345         }
00346       }
00347         
00348       if ( c == '*' ) // maybe end of a comment, if next char is '/'?
00349       {
00350         if ( (c = s->Getc(ev)) == '/' ) // end of comment?
00351         {
00352           --depth; // depth of comments has decreased by one
00353           if ( !depth ) // comments all done?
00354             c = s->Getc(ev); // return the byte after end of comment
00355         }
00356         else if ( c != EOF ) // need to put the char back?
00357           s->Ungetc(c); // especially need to put back '*', 0xA, or 0xD
00358       }
00359       else if ( c == '/' ) // maybe nested comemnt, if next char is '*'?
00360       {
00361         if ( (c = s->Getc(ev)) == '*' ) // nested comment?
00362           ++depth; // depth of comments has increased by one
00363         else if ( c != EOF ) // need to put the char back?
00364           s->Ungetc(c); // especially need to put back '/', 0xA, or 0xD
00365       }
00366         
00367       if ( ev->Bad() )
00368         c = EOF;
00369     }
00370     if ( c == EOF && depth > 0 )
00371       ev->NewWarning("EOF before end of comment");
00372   }
00373   else
00374     ev->NewWarning("expected / or *");
00375   
00376   return c;
00377 }
00378 
00379 int morkParser::eat_line_break(morkEnv* ev, int inLast)
00380 {
00381   morkStream* s = mParser_Stream;
00382   register int c = s->Getc(ev); // get next char after 0xA or 0xD
00383   this->CountLineBreak();
00384   if ( c == 0xA || c == 0xD ) // another line break character?
00385   {
00386     if ( c != inLast ) // not the same as the last one?
00387       c = s->Getc(ev); // get next char after two-byte linebreak
00388   }
00389   return c;
00390 }
00391 
00392 int morkParser::eat_line_continue(morkEnv* ev) // last char was '\'
00393 {
00394   morkStream* s = mParser_Stream;
00395   register int c = s->Getc(ev);
00396   if ( c == 0xA || c == 0xD ) // linebreak follows \ as expected?
00397   {
00398     c = this->eat_line_break(ev, c);
00399   }
00400   else
00401     ev->NewWarning("expected linebreak");
00402   
00403   return c;
00404 }
00405 
00406 int morkParser::NextChar(morkEnv* ev) // next non-white content
00407 {
00408   morkStream* s = mParser_Stream;
00409   register int c = s->Getc(ev);
00410   while ( c > 0 && ev->Good() )
00411   {
00412     if ( c == '/' )
00413       c = this->eat_comment(ev);
00414     else if ( c == 0xA || c == 0xD )
00415       c = this->eat_line_break(ev, c);
00416     else if ( c == '\\' )
00417       c = this->eat_line_continue(ev);
00418     else if ( morkCh_IsWhite(c) )
00419       c = s->Getc(ev);
00420     else  
00421       break; // end while loop when return c is acceptable
00422   }
00423   if ( ev->Bad() )
00424   {
00425     mParser_State = morkParser_kBrokenState;
00426     mParser_DoMore = morkBool_kFalse;
00427     mParser_IsDone = morkBool_kTrue;
00428     mParser_IsBroken = morkBool_kTrue;
00429     c = EOF;
00430   }
00431   else if ( c == EOF )
00432   {
00433     mParser_DoMore = morkBool_kFalse;
00434     mParser_IsDone = morkBool_kTrue;
00435   }
00436   return c;
00437 }
00438 
00439 void
00440 morkParser::OnCellState(morkEnv* ev)
00441 {
00442   ev->StubMethodOnlyError();
00443 }
00444 
00445 void
00446 morkParser::OnMetaState(morkEnv* ev)
00447 {
00448   ev->StubMethodOnlyError();
00449 }
00450 
00451 void
00452 morkParser::OnRowState(morkEnv* ev)
00453 {
00454   ev->StubMethodOnlyError();
00455 }
00456 
00457 void
00458 morkParser::OnTableState(morkEnv* ev)
00459 {
00460   ev->StubMethodOnlyError();
00461 }
00462 
00463 void
00464 morkParser::OnDictState(morkEnv* ev)
00465 {
00466   ev->StubMethodOnlyError();
00467 }
00468 
00469 morkBuf* morkParser::ReadName(morkEnv* ev, register int c)
00470 {
00471   morkBuf* outBuf = 0;
00472   
00473   if ( !morkCh_IsName(c) )
00474     ev->NewError("not a name char");
00475 
00476   morkCoil* coil = &mParser_ColumnCoil;
00477   coil->ClearBufFill();
00478 
00479   morkSpool* spool = &mParser_ColumnSpool;
00480   spool->Seek(ev, /*pos*/ 0);
00481   
00482   if ( ev->Good() )
00483   {
00484     spool->Putc(ev, c);
00485     
00486     morkStream* s = mParser_Stream;
00487     while ( (c = s->Getc(ev)) != EOF && morkCh_IsMore(c) && ev->Good() )
00488       spool->Putc(ev, c);
00489       
00490     if ( ev->Good() )
00491     {
00492       if ( c != EOF )
00493       {
00494         s->Ungetc(c);
00495         spool->FlushSink(ev); // update coil->mBuf_Fill
00496       }
00497       else
00498         this->UnexpectedEofError(ev);
00499         
00500       if ( ev->Good() )
00501         outBuf = coil;
00502     }
00503   }  
00504   return outBuf;
00505 }
00506 
00507 mork_bool
00508 morkParser::ReadMid(morkEnv* ev, morkMid* outMid)
00509 {
00510   outMid->ClearMid();
00511   
00512   morkStream* s = mParser_Stream;
00513   int next;
00514   outMid->mMid_Oid.mOid_Id = this->ReadHex(ev, &next);
00515   register int c = next;
00516   if ( c == ':' )
00517   {
00518     if ( (c = s->Getc(ev)) != EOF && ev->Good() )
00519     {
00520       if ( c == '^' )
00521       {
00522         outMid->mMid_Oid.mOid_Scope = this->ReadHex(ev, &next);
00523         if ( ev->Good() )
00524           s->Ungetc(next);
00525       }
00526       else if ( morkCh_IsName(c) )
00527       {
00528         outMid->mMid_Buf = this->ReadName(ev, c); 
00529       }
00530       else
00531         ev->NewError("expected name or hex after ':' following ID");
00532     }
00533     
00534     if ( c == EOF && ev->Good() )
00535       this->UnexpectedEofError(ev);
00536   }
00537   else
00538     s->Ungetc(c);
00539   
00540   return ev->Good();
00541 }
00542 
00543 void
00544 morkParser::ReadCell(morkEnv* ev)
00545 {
00546   mParser_CellMid.ClearMid();
00547   // this->StartSpanOnLastByte(ev, &mParser_CellSpan);
00548   morkMid* cellMid = 0; // if mid syntax is used for column
00549   morkBuf* cellBuf = 0; // if naked string is used for column
00550 
00551   morkStream* s = mParser_Stream;
00552   register int c;
00553   if ( (c = s->Getc(ev)) != EOF && ev->Good() )
00554   {
00555     // this->StartSpanOnLastByte(ev, &mParser_ColumnSpan);
00556     if ( c == '^' )
00557     {
00558       cellMid = &mParser_CellMid;
00559       this->ReadMid(ev, cellMid);
00560       // if ( !mParser_CellMid.mMid_Oid.mOid_Scope )
00561       //  mParser_CellMid.mMid_Oid.mOid_Scope = (mork_scope) 'c';
00562     }
00563     else
00564     {
00565       if (mParser_InMeta && c == morkStore_kFormColumn)
00566       {
00567         ReadCellForm(ev, c);
00568         return;
00569       }
00570       else
00571         cellBuf = this->ReadName(ev, c); 
00572     }
00573     if ( ev->Good() )
00574     {
00575       // this->EndSpanOnThisByte(ev, &mParser_ColumnSpan);
00576 
00577       mParser_InCell = morkBool_kTrue;
00578       this->OnNewCell(ev, *mParser_CellSpan.AsPlace(),
00579         cellMid, cellBuf); // , mParser_CellChange
00580 
00581       mParser_CellChange = morkChange_kNil;
00582       if ( (c = this->NextChar(ev)) != EOF && ev->Good() )
00583       {
00584         // this->StartSpanOnLastByte(ev, &mParser_SlotSpan);
00585         if ( c == '=' )
00586         {
00587           morkBuf* buf = this->ReadValue(ev);
00588           if ( buf )
00589           {
00590             // this->EndSpanOnThisByte(ev, &mParser_SlotSpan);
00591             this->OnValue(ev, mParser_SlotSpan, *buf);
00592           }
00593         }
00594         else if ( c == '^' )
00595         {
00596           if ( this->ReadMid(ev, &mParser_Mid) )
00597           {
00598             // this->EndSpanOnThisByte(ev, &mParser_SlotSpan);
00599             if ( (c = this->NextChar(ev)) != EOF && ev->Good() )
00600             {
00601               if ( c != ')' )
00602                 ev->NewError("expected ')' after cell ^ID value");
00603             }
00604             else if ( c == EOF )
00605               this->UnexpectedEofError(ev);
00606             
00607             if ( ev->Good() )
00608               this->OnValueMid(ev, mParser_SlotSpan, mParser_Mid);
00609           }
00610         }
00611         else if ( c == 'r' || c == 't' || c == '"' || c == '\'' )
00612         {
00613           ev->NewError("cell syntax not yet supported");
00614         }
00615         else
00616         {
00617           ev->NewError("unknown cell syntax");
00618         }
00619       }
00620       
00621       // this->EndSpanOnThisByte(ev, &mParser_CellSpan);
00622       mParser_InCell = morkBool_kFalse;
00623       this->OnCellEnd(ev, mParser_CellSpan);
00624     }
00625   }
00626   mParser_CellChange = morkChange_kNil;
00627   
00628   if ( c == EOF && ev->Good() )
00629     this->UnexpectedEofError(ev);
00630 }
00631 
00632 void morkParser::ReadRowPos(morkEnv* ev)
00633 {
00634   int c; // next character
00635   mork_pos rowPos = this->ReadHex(ev, &c);
00636   
00637   if ( ev->Good() && c != EOF ) // should put back byte after hex?
00638     mParser_Stream->Ungetc(c);
00639 
00640   this->OnRowPos(ev, rowPos);
00641 }
00642 
00643 void morkParser::ReadRow(morkEnv* ev, int c)
00644 // zm:Row       ::= zm:S? '[' zm:S? zm:Id zm:RowItem* zm:S? ']'
00645 // zm:RowItem   ::= zm:MetaRow | zm:Cell
00646 // zm:MetaRow   ::= zm:S? '[' zm:S? zm:Cell* zm:S? ']' /* meta attributes */
00647 // zm:Cell      ::= zm:S? '(' zm:Column zm:S? zm:Slot? ')'
00648 {
00649   if ( ev->Good() )
00650   {
00651     // this->StartSpanOnLastByte(ev, &mParser_RowSpan);
00652     if ( mParser_Change )
00653       mParser_RowChange = mParser_Change;
00654 
00655     mork_bool cutAllRowCols = morkBool_kFalse;
00656 
00657     if ( c == '[' )
00658     {
00659       if ( ( c = this->NextChar(ev) ) == '-' )
00660         cutAllRowCols = morkBool_kTrue;
00661       else if ( ev->Good() && c != EOF )
00662         mParser_Stream->Ungetc(c);
00663 
00664       if ( this->ReadMid(ev, &mParser_RowMid) )
00665       {
00666         mParser_InRow = morkBool_kTrue;
00667         this->OnNewRow(ev, *mParser_RowSpan.AsPlace(),
00668           mParser_RowMid, cutAllRowCols);
00669 
00670         mParser_Change = mParser_RowChange = morkChange_kNil;
00671 
00672         while ( (c = this->NextChar(ev)) != EOF && ev->Good() && c != ']' )
00673         {
00674           switch ( c )
00675           {
00676             case '(': // cell
00677               this->ReadCell(ev);
00678               break;
00679               
00680             case '[': // meta
00681               this->ReadMeta(ev, ']');
00682               break;
00683             
00684             // case '+': // plus
00685             //   mParser_CellChange = morkChange_kAdd;
00686             //   break;
00687               
00688             case '-': // minus
00689               // mParser_CellChange = morkChange_kCut;
00690               this->OnMinusCell(ev);
00691               break;
00692               
00693             // case '!': // bang
00694             //   mParser_CellChange = morkChange_kSet;
00695             //  break;
00696               
00697             default:
00698               ev->NewWarning("unexpected byte in row");
00699               break;
00700           } // switch
00701         } // while
00702         
00703         if ( ev->Good() )
00704         {
00705           if ( (c = this->NextChar(ev)) == '!' )
00706             this->ReadRowPos(ev);
00707           else if ( c != EOF && ev->Good() )
00708             mParser_Stream->Ungetc(c);
00709         }
00710         
00711         // this->EndSpanOnThisByte(ev, &mParser_RowSpan);
00712         mParser_InRow = morkBool_kFalse;
00713         this->OnRowEnd(ev, mParser_RowSpan);
00714 
00715       } // if ReadMid
00716     } // if '['
00717     
00718     else // c != '['
00719     {
00720       morkStream* s = mParser_Stream;
00721       s->Ungetc(c);
00722       if ( this->ReadMid(ev, &mParser_RowMid) )
00723       {
00724         mParser_InRow = morkBool_kTrue;
00725         this->OnNewRow(ev, *mParser_RowSpan.AsPlace(),
00726           mParser_RowMid, cutAllRowCols);
00727 
00728         mParser_Change = mParser_RowChange = morkChange_kNil;
00729         
00730         if ( ev->Good() )
00731         {
00732           if ( (c = this->NextChar(ev)) == '!' )
00733             this->ReadRowPos(ev);
00734           else if ( c != EOF && ev->Good() )
00735             s->Ungetc(c);
00736         }
00737 
00738         // this->EndSpanOnThisByte(ev, &mParser_RowSpan);
00739         mParser_InRow = morkBool_kFalse;
00740         this->OnRowEnd(ev, mParser_RowSpan);
00741       }
00742     }
00743   }
00744   
00745   if ( ev->Bad() )
00746     mParser_State = morkParser_kBrokenState;
00747   else if ( c == EOF )
00748     mParser_State = morkParser_kDoneState;
00749 }
00750 
00751 void morkParser::ReadTable(morkEnv* ev)
00752 // zm:Table     ::= zm:S? '{' zm:S? zm:Id zm:TableItem* zm:S? '}'
00753 // zm:TableItem ::= zm:MetaTable | zm:RowRef | zm:Row
00754 // zm:MetaTable ::= zm:S? '{' zm:S? zm:Cell* zm:S? '}' /* meta attributes */
00755 {
00756   // this->StartSpanOnLastByte(ev, &mParser_TableSpan);
00757 
00758   if ( mParser_Change )
00759     mParser_TableChange = mParser_Change;
00760 
00761   mork_bool cutAllTableRows = morkBool_kFalse;
00762   
00763   int c = this->NextChar(ev);
00764   if ( c == '-' )
00765     cutAllTableRows = morkBool_kTrue;
00766   else if ( ev->Good() && c != EOF )
00767     mParser_Stream->Ungetc(c);
00768   
00769   if ( ev->Good() && this->ReadMid(ev, &mParser_TableMid) )
00770   {
00771     mParser_InTable = morkBool_kTrue;
00772     this->OnNewTable(ev, *mParser_TableSpan.AsPlace(),  
00773       mParser_TableMid, cutAllTableRows);
00774 
00775     mParser_Change = mParser_TableChange = morkChange_kNil;
00776 
00777     while ( (c = this->NextChar(ev)) != EOF && ev->Good() && c != '}' )
00778     {
00779       if ( morkCh_IsHex(c) )
00780       {
00781         this->ReadRow(ev, c);
00782       }
00783       else
00784       {
00785         switch ( c )
00786         {
00787           case '[': // row
00788             this->ReadRow(ev, '[');
00789             break;
00790             
00791           case '{': // meta
00792             this->ReadMeta(ev, '}');
00793             break;
00794           
00795           // case '+': // plus
00796           //   mParser_RowChange = morkChange_kAdd;
00797           //   break;
00798             
00799           case '-': // minus
00800             // mParser_RowChange = morkChange_kCut;
00801             this->OnMinusRow(ev);
00802             break;
00803             
00804           // case '!': // bang
00805           //   mParser_RowChange = morkChange_kSet;
00806           //   break;
00807             
00808           default:
00809             ev->NewWarning("unexpected byte in table");
00810             break;
00811         }
00812       }
00813     }
00814 
00815     // this->EndSpanOnThisByte(ev, &mParser_TableSpan);
00816     mParser_InTable = morkBool_kFalse;
00817     this->OnTableEnd(ev, mParser_TableSpan);
00818 
00819     if ( ev->Bad() )
00820       mParser_State = morkParser_kBrokenState;
00821     else if ( c == EOF )
00822       mParser_State = morkParser_kDoneState;
00823   }
00824 }
00825 
00826 mork_id morkParser::ReadHex(morkEnv* ev, int* outNextChar)
00827 // zm:Hex   ::= [0-9a-fA-F] /* a single hex digit */
00828 // zm:Hex+  ::= zm:Hex | zm:Hex zm:Hex+
00829 {
00830   mork_id hex = 0;
00831 
00832   morkStream* s = mParser_Stream;
00833   register int c = this->NextChar(ev);
00834     
00835   if ( ev->Good() )
00836   {
00837     if ( c != EOF )
00838     {
00839       if ( morkCh_IsHex(c) )
00840       {
00841         do
00842         {
00843           if ( morkCh_IsDigit(c) ) // '0' through '9'?
00844             c -= '0';
00845           else if ( morkCh_IsUpper(c) ) // 'A' through 'F'?
00846             c -= ('A' - 10) ; // c = (c - 'A') + 10;
00847           else // 'a' through 'f'?
00848             c -= ('a' - 10) ; // c = (c - 'a') + 10;
00849 
00850           hex = (hex << 4) + c;
00851         }
00852         while ( (c = s->Getc(ev)) != EOF && ev->Good() && morkCh_IsHex(c) );
00853       }
00854       else
00855         this->ExpectedHexDigitError(ev, c);
00856     }
00857   }
00858   if ( c == EOF )
00859     this->EofInsteadOfHexError(ev);
00860     
00861   *outNextChar = c;
00862   return hex;
00863 }
00864 
00865 /*static*/ void
00866 morkParser::EofInsteadOfHexError(morkEnv* ev)
00867 {
00868   ev->NewWarning("eof instead of hex");
00869 }
00870 
00871 /*static*/ void
00872 morkParser::ExpectedHexDigitError(morkEnv* ev, int c)
00873 {
00874   MORK_USED_1(c);
00875   ev->NewWarning("expected hex digit");
00876 }
00877 
00878 /*static*/ void
00879 morkParser::ExpectedEqualError(morkEnv* ev)
00880 {
00881   ev->NewWarning("expected '='");
00882 }
00883 
00884 /*static*/ void
00885 morkParser::UnexpectedEofError(morkEnv* ev)
00886 {
00887   ev->NewWarning("unexpected eof");
00888 }
00889 
00890 
00891 morkBuf* morkParser::ReadValue(morkEnv* ev)
00892 {
00893   morkBuf* outBuf = 0;
00894 
00895   morkCoil* coil = &mParser_ValueCoil;
00896   coil->ClearBufFill();
00897 
00898   morkSpool* spool = &mParser_ValueSpool;
00899   spool->Seek(ev, /*pos*/ 0);
00900   
00901   if ( ev->Good() )
00902   {
00903     morkStream* s = mParser_Stream;
00904     register int c;
00905     while ( (c = s->Getc(ev)) != EOF && c != ')' && ev->Good() )
00906     {
00907       if ( c == '\\' ) // next char is escaped by '\'? 
00908       {
00909         if ( (c = s->Getc(ev)) == 0xA || c == 0xD ) // linebreak after \?
00910         {
00911           c = this->eat_line_break(ev, c);
00912           if ( c == ')' || c == '\\' || c == '$' )
00913           {
00914             s->Ungetc(c); // just let while loop test read this again
00915             continue; // goto next iteration of while loop
00916           }
00917         }
00918         if ( c == EOF || ev->Bad() )
00919           break; // end while loop
00920       }
00921       else if ( c == '$' ) // "$" escapes next two hex digits?
00922       {
00923         if ( (c = s->Getc(ev)) != EOF && ev->Good() )
00924         {
00925           mork_ch first = (mork_ch) c; // first hex digit
00926           if ( (c = s->Getc(ev)) != EOF && ev->Good() )
00927           {
00928             mork_ch second = (mork_ch) c; // second hex digit
00929             c = ev->HexToByte(first, second);
00930           }
00931           else
00932             break; // end while loop
00933         }
00934         else
00935           break; // end while loop
00936       }
00937       spool->Putc(ev, c);
00938     }
00939       
00940     if ( ev->Good() )
00941     {
00942       if ( c != EOF )
00943         spool->FlushSink(ev); // update coil->mBuf_Fill
00944       else
00945         this->UnexpectedEofError(ev);
00946         
00947       if ( ev->Good() )
00948         outBuf = coil;
00949     }
00950   }
00951   return outBuf; 
00952 }
00953 
00954 void morkParser::ReadDictForm(morkEnv *ev)
00955 {
00956   int nextChar;
00957   nextChar = this->NextChar(ev);
00958   if (nextChar == '(')
00959   {
00960     nextChar = this->NextChar(ev);
00961     if (nextChar == morkStore_kFormColumn)
00962     {
00963       int dictForm;
00964 
00965       nextChar = this->NextChar(ev);
00966       if (nextChar == '=')
00967       {
00968         dictForm = this->NextChar(ev);
00969         nextChar = this->NextChar(ev);
00970       }
00971       else if (nextChar == '^')
00972       {
00973         dictForm = this->ReadHex(ev, &nextChar);
00974       }
00975       else
00976       {
00977         ev->NewWarning("unexpected byte in dict form");
00978         return;
00979       }
00980       mParser_ValueCoil.mText_Form = dictForm;
00981       if (nextChar == ')')
00982       {
00983         nextChar = this->NextChar(ev);
00984         if (nextChar == '>')
00985           return;
00986       }
00987     }
00988   }
00989   ev->NewWarning("unexpected byte in dict form");
00990 }
00991 
00992 void morkParser::ReadCellForm(morkEnv *ev, int c)
00993 {
00994   MORK_ASSERT (c == morkStore_kFormColumn);
00995   int nextChar;
00996   nextChar = this->NextChar(ev);
00997   int cellForm;
00998 
00999   if (nextChar == '=')
01000   {
01001     cellForm = this->NextChar(ev);
01002     nextChar = this->NextChar(ev);
01003   }
01004   else if (nextChar == '^')
01005   {
01006     cellForm = this->ReadHex(ev, &nextChar);
01007   }
01008   else
01009   {
01010     ev->NewWarning("unexpected byte in cell form");
01011     return;
01012   }
01013   // ### not sure about this. Which form should we set?
01014   //    mBuilder_CellForm = mBuilder_RowForm = cellForm;
01015   if (nextChar == ')')
01016   {
01017     OnCellForm(ev, cellForm);
01018     return;
01019   }
01020   ev->NewWarning("unexpected byte in cell form");
01021 }
01022 
01023 void morkParser::ReadAlias(morkEnv* ev)
01024 // zm:Alias     ::= zm:S? '(' ('#')? zm:Hex+ zm:S? zm:Value ')'
01025 // zm:Value   ::= '=' ([^)$\] | '\' zm:NonCRLF | zm:Continue | zm:Dollar)*
01026 {
01027   // this->StartSpanOnLastByte(ev, &mParser_AliasSpan);
01028 
01029   int nextChar;
01030   mork_id hex = this->ReadHex(ev, &nextChar);
01031   register int c = nextChar;
01032 
01033   mParser_Mid.ClearMid();
01034   mParser_Mid.mMid_Oid.mOid_Id = hex;
01035 
01036   if ( morkCh_IsWhite(c) && ev->Good() )
01037     c = this->NextChar(ev);
01038 
01039   if ( ev->Good() )
01040   {
01041     if ( c == '<')
01042     {
01043       ReadDictForm(ev);
01044       if (ev->Good())
01045         c = this->NextChar(ev);
01046     }
01047     if ( c == '=' )
01048     {
01049       mParser_Mid.mMid_Buf = this->ReadValue(ev);
01050       if ( mParser_Mid.mMid_Buf )
01051       {
01052         // this->EndSpanOnThisByte(ev, &mParser_AliasSpan);
01053         this->OnAlias(ev, mParser_AliasSpan, mParser_Mid);
01054         // need to reset this somewhere.
01055         mParser_ValueCoil.mText_Form = 0;
01056 
01057       }
01058     }
01059     else
01060       this->ExpectedEqualError(ev);
01061   }
01062 }
01063 
01064 void morkParser::ReadMeta(morkEnv* ev, int inEndMeta)
01065 // zm:MetaDict  ::= zm:S? '<' zm:S? zm:Cell* zm:S? '>' /* meta attributes */
01066 // zm:MetaTable ::= zm:S? '{' zm:S? zm:Cell* zm:S? '}' /* meta attributes */
01067 // zm:MetaRow   ::= zm:S? '[' zm:S? zm:Cell* zm:S? ']' /* meta attributes */
01068 {
01069   // this->StartSpanOnLastByte(ev, &mParser_MetaSpan);
01070   mParser_InMeta = morkBool_kTrue;
01071   this->OnNewMeta(ev, *mParser_MetaSpan.AsPlace());
01072 
01073   mork_bool more = morkBool_kTrue; // until end meta
01074   int c;
01075   while ( more && (c = this->NextChar(ev)) != EOF && ev->Good() )
01076   {
01077     switch ( c )
01078     {
01079       case '(': // cell
01080         this->ReadCell(ev);
01081         break;
01082         
01083       case '>': // maybe end meta?
01084         if ( inEndMeta == '>' )
01085           more = morkBool_kFalse; // stop reading meta
01086         else
01087           this->UnexpectedByteInMetaWarning(ev);
01088         break;
01089         
01090       case '}': // maybe end meta?
01091         if ( inEndMeta == '}' )
01092           more = morkBool_kFalse; // stop reading meta
01093         else
01094           this->UnexpectedByteInMetaWarning(ev);
01095         break;
01096         
01097       case ']': // maybe end meta?
01098         if ( inEndMeta == ']' )
01099           more = morkBool_kFalse; // stop reading meta
01100         else
01101           this->UnexpectedByteInMetaWarning(ev);
01102         break;
01103         
01104       case '[': // maybe table meta row?
01105         if ( mParser_InTable )
01106           this->ReadRow(ev, '['); 
01107         else
01108           this->UnexpectedByteInMetaWarning(ev);
01109         break;
01110         
01111       default:
01112         if ( mParser_InTable && morkCh_IsHex(c) )
01113           this->ReadRow(ev, c);
01114         else
01115           this->UnexpectedByteInMetaWarning(ev);
01116         break;
01117     }
01118   }
01119 
01120   // this->EndSpanOnThisByte(ev, &mParser_MetaSpan);
01121   mParser_InMeta = morkBool_kFalse;
01122   this->OnMetaEnd(ev, mParser_MetaSpan);
01123 }
01124 
01125 /*static*/ void
01126 morkParser::UnexpectedByteInMetaWarning(morkEnv* ev)
01127 {
01128   ev->NewWarning("unexpected byte in meta");
01129 }
01130 
01131 /*static*/ void
01132 morkParser::NonParserTypeError(morkEnv* ev)
01133 {
01134   ev->NewError("non morkParser");
01135 }
01136 
01137 mork_bool morkParser::MatchPattern(morkEnv* ev, const char* inPattern)
01138 {
01139   // if an error occurs, we want original inPattern in the debugger:
01140   const char* pattern = inPattern; // mutable copy of pointer
01141   morkStream* s = mParser_Stream;
01142   register int c;
01143   while ( *pattern && ev->Good() )
01144   {
01145     char byte = *pattern++;
01146     if ( (c = s->Getc(ev)) != byte )
01147     {
01148       ev->NewError("byte not in expected pattern");
01149     }
01150   }
01151   return ev->Good();
01152 }
01153 
01154 mork_bool morkParser::FindGroupEnd(morkEnv* ev)
01155 {
01156   mork_bool foundEnd = morkBool_kFalse;
01157   
01158   // char gidBuf[ 64 ]; // to hold hex pattern we want
01159   // (void) ev->TokenAsHex(gidBuf, mParser_GroupId);
01160   
01161   morkStream* s = mParser_Stream;
01162   register int c;
01163   
01164   while ( (c = s->Getc(ev)) != EOF && ev->Good() && !foundEnd )
01165   {
01166     if ( c == '@' ) // maybe start of group ending?
01167     {
01168       // this->EndSpanOnThisByte(ev, &mParser_GroupSpan);
01169       if ( (c = s->Getc(ev)) == '$' ) // '$' follows '@' ?
01170       {
01171         if ( (c = s->Getc(ev)) == '$' ) // '$' follows "@$" ?
01172         {
01173           if ( (c = s->Getc(ev)) == '}' )
01174           {
01175             foundEnd = this->ReadEndGroupId(ev);
01176             // this->EndSpanOnThisByte(ev, &mParser_GroupSpan);
01177 
01178           }
01179           else
01180             ev->NewError("expected '}' after @$$");
01181         }
01182       }
01183       if ( !foundEnd && c == '@' )
01184         s->Ungetc(c);
01185     }
01186   }
01187 
01188   return foundEnd && ev->Good();
01189 }
01190 
01191 void morkParser::ReadGroup(morkEnv* mev)
01192 {
01193   nsIMdbEnv *ev = mev->AsMdbEnv();
01194   int next = 0;
01195   mParser_GroupId = this->ReadHex(mev, &next);
01196   if ( next == '{' )
01197   {
01198     morkStream* s = mParser_Stream;
01199      register int c;
01200     if ( (c = s->Getc(mev)) == '@' )
01201     {
01202        // we really need the following span inside morkBuilder::OnNewGroup():
01203       this->StartSpanOnThisByte(mev, &mParser_GroupSpan);
01204       mork_pos startPos = mParser_GroupSpan.mSpan_Start.mPlace_Pos;
01205 
01206       // if ( !store->mStore_FirstCommitGroupPos )
01207       //   store->mStore_FirstCommitGroupPos = startPos;
01208       // else if ( !store->mStore_SecondCommitGroupPos )
01209       //   store->mStore_SecondCommitGroupPos = startPos;
01210       
01211       if ( this->FindGroupEnd(mev) )
01212       {
01213         mork_pos outPos;
01214         s->Seek(ev, startPos, &outPos);
01215         if ( mev->Good() )
01216         {
01217           this->OnNewGroup(mev, mParser_GroupSpan.mSpan_Start,
01218             mParser_GroupId);
01219           
01220           this->ReadContent(mev, /*inInsideGroup*/ morkBool_kTrue);
01221 
01222           this->OnGroupCommitEnd(mev, mParser_GroupSpan);
01223         }
01224       }
01225     }
01226     else
01227       mev->NewError("expected '@' after @$${id{");
01228   }
01229   else
01230     mev->NewError("expected '{' after @$$id");
01231     
01232 }
01233 
01234 mork_bool morkParser::ReadAt(morkEnv* ev, mork_bool inInsideGroup)
01235 /* groups must be ignored until properly terminated */
01236 // zm:Group       ::= zm:GroupStart zm:Content zm:GroupEnd /* transaction */
01237 // zm:GroupStart  ::= zm:S? '@$${' zm:Hex+ '{@' /* xaction id has own space */
01238 // zm:GroupEnd    ::= zm:GroupCommit | zm:GroupAbort
01239 // zm:GroupCommit ::= zm:S? '@$$}' zm:Hex+ '}@'  /* id matches start id */
01240 // zm:GroupAbort  ::= zm:S? '@$$}~~}@' /* id matches start id */
01241 /* We must allow started transactions to be aborted in summary files. */
01242 /* Note '$$' will never occur unescaped in values we will see in Mork. */
01243 {
01244   if ( this->MatchPattern(ev, "$$") )
01245   {
01246     morkStream* s = mParser_Stream;
01247      register int c;
01248     if ( ((c = s->Getc(ev)) == '{' || c == '}') && ev->Good() )
01249      {
01250        if ( c == '{' ) // start of new group?
01251        {
01252          if ( !inInsideGroup )
01253            this->ReadGroup(ev);
01254          else
01255            ev->NewError("nested @$${ inside another group");
01256        }
01257        else // c == '}' // end of old group?
01258        {
01259          if ( inInsideGroup )
01260          {
01261           this->ReadEndGroupId(ev);
01262           mParser_GroupId = 0;
01263          }
01264          else
01265            ev->NewError("unmatched @$$} outside any group");
01266        }
01267      }
01268      else
01269        ev->NewError("expected '{' or '}' after @$$");
01270   }
01271   return ev->Good();
01272 }
01273 
01274 mork_bool morkParser::ReadEndGroupId(morkEnv* ev)
01275 {
01276   mork_bool outSawGroupId = morkBool_kFalse;
01277   morkStream* s = mParser_Stream;
01278   register int c;
01279   if ( (c = s->Getc(ev)) != EOF && ev->Good() )
01280   {
01281     if ( c == '~' ) // transaction is aborted?
01282     {
01283       this->MatchPattern(ev, "~}@"); // finish rest of pattern
01284     }
01285     else // push back byte and read expected trailing hex id
01286     {
01287       s->Ungetc(c);
01288       int next = 0;
01289       mork_gid endGroupId = this->ReadHex(ev, &next);
01290       if ( ev->Good() )
01291       {
01292         if ( endGroupId == mParser_GroupId ) // matches start?
01293         {
01294           if ( next == '}' ) // '}' after @$$}id ?
01295           {
01296             if ( (c = s->Getc(ev)) == '@' ) // '@' after @$$}id} ?
01297             {
01298               // looks good, so return with no error
01299               outSawGroupId = morkBool_kTrue;
01300             }
01301             else
01302               ev->NewError("expected '@' after @$$}id}");
01303           }
01304           else
01305             ev->NewError("expected '}' after @$$}id");
01306         }
01307         else
01308           ev->NewError("end group id mismatch");
01309       }
01310     }
01311   }
01312   return ( outSawGroupId && ev->Good() );
01313 }
01314 
01315 
01316 void morkParser::ReadDict(morkEnv* ev)
01317 // zm:Dict      ::= zm:S? '<' zm:DictItem* zm:S? '>'
01318 // zm:DictItem  ::= zm:MetaDict | zm:Alias
01319 // zm:MetaDict  ::= zm:S? '<' zm:S? zm:Cell* zm:S? '>' /* meta attributes */
01320 // zm:Alias     ::= zm:S? '(' ('#')? zm:Hex+ zm:S? zm:Value ')'
01321 {
01322   mParser_Change = morkChange_kNil;
01323   mParser_AtomChange = morkChange_kNil;
01324   
01325   // this->StartSpanOnLastByte(ev, &mParser_DictSpan);
01326   mParser_InDict = morkBool_kTrue;
01327   this->OnNewDict(ev, *mParser_DictSpan.AsPlace());
01328   
01329   int c;
01330   while ( (c = this->NextChar(ev)) != EOF && ev->Good() && c != '>' )
01331   {
01332     switch ( c )
01333     {
01334       case '(': // alias
01335         this->ReadAlias(ev);
01336         break;
01337         
01338       case '<': // meta
01339         this->ReadMeta(ev, '>');
01340         break;
01341         
01342       default:
01343         ev->NewWarning("unexpected byte in dict");
01344         break;
01345     }
01346   }
01347 
01348   // this->EndSpanOnThisByte(ev, &mParser_DictSpan);
01349   mParser_InDict = morkBool_kFalse;
01350   this->OnDictEnd(ev, mParser_DictSpan);
01351   
01352   if ( ev->Bad() )
01353     mParser_State = morkParser_kBrokenState;
01354   else if ( c == EOF )
01355     mParser_State = morkParser_kDoneState;
01356 }
01357 
01358 void morkParser::EndSpanOnThisByte(morkEnv* mev, morkSpan* ioSpan)
01359 {
01360   mork_pos here;
01361   nsIMdbEnv *ev = mev->AsMdbEnv();
01362   nsresult rv = mParser_Stream->Tell(ev, &here);
01363   if (NS_SUCCEEDED(rv) && mev->Good() )
01364   {
01365     this->SetHerePos(here);
01366     ioSpan->SetEndWithEnd(mParser_PortSpan);
01367   }
01368 }
01369 
01370 void morkParser::EndSpanOnLastByte(morkEnv* mev, morkSpan* ioSpan)
01371 {
01372   mork_pos here;
01373   nsIMdbEnv *ev = mev->AsMdbEnv();
01374   nsresult rv= mParser_Stream->Tell(ev, &here);
01375   if ( NS_SUCCEEDED(rv) && mev->Good() )
01376   {
01377     if ( here > 0 )
01378       --here;
01379     else
01380       here = 0;
01381 
01382     this->SetHerePos(here);
01383     ioSpan->SetEndWithEnd(mParser_PortSpan);
01384   }
01385 }
01386 
01387 void morkParser::StartSpanOnLastByte(morkEnv* mev, morkSpan* ioSpan)
01388 {
01389   mork_pos here;
01390   nsIMdbEnv *ev = mev->AsMdbEnv();
01391   nsresult rv = mParser_Stream->Tell(ev, &here);
01392   if ( NS_SUCCEEDED(rv) && mev->Good() )
01393   {
01394     if ( here > 0 )
01395       --here;
01396     else
01397       here = 0;
01398 
01399     this->SetHerePos(here);
01400     ioSpan->SetStartWithEnd(mParser_PortSpan);
01401     ioSpan->SetEndWithEnd(mParser_PortSpan);
01402   }
01403 }
01404 
01405 void morkParser::StartSpanOnThisByte(morkEnv* mev, morkSpan* ioSpan)
01406 {
01407   mork_pos here;
01408   nsIMdbEnv *ev = mev->AsMdbEnv();
01409   nsresult rv = mParser_Stream->Tell(ev, &here);
01410   if ( NS_SUCCEEDED(rv) && mev->Good() )
01411   {
01412     this->SetHerePos(here);
01413     ioSpan->SetStartWithEnd(mParser_PortSpan);
01414     ioSpan->SetEndWithEnd(mParser_PortSpan);
01415   }
01416 }
01417 
01418 mork_bool
01419 morkParser::ReadContent(morkEnv* ev, mork_bool inInsideGroup)
01420 {
01421   int c;
01422   while ( (c = this->NextChar(ev)) != EOF && ev->Good() )
01423   {
01424     switch ( c )
01425     {
01426       case '[': // row
01427         this->ReadRow(ev, '[');
01428         break;
01429         
01430       case '{': // table
01431         this->ReadTable(ev);
01432         break;
01433         
01434       case '<': // dict
01435         this->ReadDict(ev);
01436         break;
01437         
01438       case '@': // group
01439         return this->ReadAt(ev, inInsideGroup);
01440         // break;
01441         
01442       // case '+': // plus
01443       //   mParser_Change = morkChange_kAdd;
01444       //   break;
01445         
01446       // case '-': // minus
01447       //   mParser_Change = morkChange_kCut;
01448       //   break;
01449         
01450       // case '!': // bang
01451       //   mParser_Change = morkChange_kSet;
01452       //   break;
01453         
01454       default:
01455         ev->NewWarning("unexpected byte in ReadContent()");
01456         break;
01457     }
01458   }
01459   if ( ev->Bad() )
01460     mParser_State = morkParser_kBrokenState;
01461   else if ( c == EOF )
01462     mParser_State = morkParser_kDoneState;
01463     
01464   return ( ev->Good() && c != EOF );
01465 }
01466 
01467 void
01468 morkParser::OnPortState(morkEnv* ev)
01469 {
01470   mParser_InPort = morkBool_kTrue;
01471   this->OnNewPort(ev, *mParser_PortSpan.AsPlace());
01472 
01473   while ( this->ReadContent(ev, /*inInsideGroup*/ morkBool_kFalse) )
01474     /* empty */;
01475   
01476   mParser_InPort = morkBool_kFalse;
01477   this->OnPortEnd(ev, mParser_PortSpan);
01478   
01479   if ( ev->Bad() )
01480     mParser_State = morkParser_kBrokenState;
01481 }
01482 
01483 void
01484 morkParser::OnStartState(morkEnv* mev)
01485 {
01486   morkStream* s = mParser_Stream;
01487   nsIMdbEnv *ev = mev->AsMdbEnv();
01488   if ( s && s->IsNode() && s->IsOpenNode() )
01489   {
01490     mork_pos outPos;
01491     nsresult rv = s->Seek(ev, 0, &outPos);
01492     if (NS_SUCCEEDED(rv) && mev->Good() )
01493     {
01494       this->StartParse(mev);
01495       mParser_State = morkParser_kPortState;
01496     }
01497   }
01498   else
01499     mev->NilPointerError();
01500 
01501   if ( mev->Bad() )
01502     mParser_State = morkParser_kBrokenState;
01503 }
01504 
01505 /*protected non-poly*/ void
01506 morkParser::ParseLoop(morkEnv* ev)
01507 {
01508   mParser_Change = morkChange_kNil;
01509   mParser_DoMore = morkBool_kTrue;
01510             
01511   while ( mParser_DoMore )
01512   {
01513     switch ( mParser_State )
01514     {
01515       case morkParser_kCellState: // 0
01516         this->OnCellState(ev); break;
01517         
01518       case morkParser_kMetaState: // 1
01519         this->OnMetaState(ev); break;
01520         
01521       case morkParser_kRowState: // 2
01522         this->OnRowState(ev); break;
01523         
01524       case morkParser_kTableState: // 3
01525         this->OnTableState(ev); break;
01526         
01527       case morkParser_kDictState: // 4
01528         this->OnDictState(ev); break;
01529         
01530       case morkParser_kPortState: // 5
01531         this->OnPortState(ev); break;
01532         
01533       case morkParser_kStartState: // 6
01534         this->OnStartState(ev); break;
01535        
01536       case morkParser_kDoneState: // 7
01537         mParser_DoMore = morkBool_kFalse;
01538         mParser_IsDone = morkBool_kTrue;
01539         this->StopParse(ev);
01540         break;
01541       case morkParser_kBrokenState: // 8
01542         mParser_DoMore = morkBool_kFalse;
01543         mParser_IsBroken = morkBool_kTrue;
01544         this->StopParse(ev);
01545         break;
01546       default: // ?
01547         MORK_ASSERT(morkBool_kFalse);
01548         mParser_State = morkParser_kBrokenState;
01549         break;
01550     }
01551   }
01552 }
01553     
01554 /*public non-poly*/ mdb_count
01555 morkParser::ParseMore( // return count of bytes consumed now
01556     morkEnv* ev,          // context
01557     mork_pos* outPos,     // current byte pos in the stream afterwards
01558     mork_bool* outDone,   // is parsing finished?
01559     mork_bool* outBroken  // is parsing irreparably dead and broken?
01560   )
01561 {
01562   mdb_count outCount = 0;
01563   if ( this->IsNode() && this->GoodParserTag() && this->IsOpenNode() )
01564   {
01565     mork_pos startPos = this->HerePos();
01566 
01567     if ( !mParser_IsDone && !mParser_IsBroken )
01568       this->ParseLoop(ev);
01569   
01570     mork_pos endPos = this->HerePos();
01571     if ( outDone )
01572       *outDone = mParser_IsDone;
01573     if ( outBroken )
01574       *outBroken = mParser_IsBroken;
01575     if ( outPos )
01576       *outPos = endPos;
01577       
01578     if ( endPos > startPos )
01579       outCount = (mdb_count) (endPos - startPos);
01580   }
01581   else
01582   {
01583     this->NonUsableParserError(ev);
01584     if ( outDone )
01585       *outDone = morkBool_kTrue;
01586     if ( outBroken )
01587       *outBroken = morkBool_kTrue;
01588     if ( outPos )
01589       *outPos = 0;
01590   }
01591   return outCount;
01592 }
01593 
01594 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
01595