Back to index

lightning-sunbird  0.9+nobinonly
morkFile.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 _MORKENV_
00051 #include "morkEnv.h"
00052 #endif
00053 
00054 #ifndef _MORKFILE_
00055 #include "morkFile.h"
00056 #endif
00057 
00058 #ifdef MORK_WIN
00059 #include "io.h"
00060 #include <windows.h>
00061 #endif
00062 
00063 // #define MORK_CONFIG_USE_ORKINFILE 1
00064  
00065 #ifdef MORK_CONFIG_USE_ORKINFILE
00066 #ifndef _ORKINFILE_
00067 #include "orkinFile.h"
00068 #endif
00069 #endif /*MORK_CONFIG_USE_ORKINFILE*/
00070 
00071 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00072 
00073 
00074 // ````` ````` ````` ````` ````` 
00075 // { ===== begin morkNode interface =====
00076 
00077 /*public virtual*/ void
00078 morkFile::CloseMorkNode(morkEnv* ev) // CloseFile() only if open
00079 {
00080   if ( this->IsOpenNode() )
00081   {
00082     this->MarkClosing();
00083     this->CloseFile(ev);
00084     this->MarkShut();
00085   }
00086 }
00087 
00088 /*public virtual*/
00089 morkFile::~morkFile() // assert CloseFile() executed earlier
00090 {
00091   MORK_ASSERT(mFile_Frozen==0);
00092   MORK_ASSERT(mFile_DoTrace==0);
00093   MORK_ASSERT(mFile_IoOpen==0);
00094   MORK_ASSERT(mFile_Active==0);
00095 }
00096 
00097 /*public non-poly*/
00098 morkFile::morkFile(morkEnv* ev, const morkUsage& inUsage, 
00099   nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
00100 : morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*) 0)
00101 , mFile_Frozen( 0 )
00102 , mFile_DoTrace( 0 )
00103 , mFile_IoOpen( 0 )
00104 , mFile_Active( 0 )
00105 
00106 , mFile_SlotHeap( 0 )
00107 , mFile_Name( 0 )
00108 , mFile_Thief( 0 )
00109 {
00110   if ( ev->Good() )
00111   {
00112     if ( ioSlotHeap )
00113     {
00114       nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mFile_SlotHeap);
00115       if ( ev->Good() )
00116         mNode_Derived = morkDerived_kFile;
00117     }
00118     else
00119       ev->NilPointerError();
00120   }
00121 }
00122 
00123 NS_IMPL_ISUPPORTS_INHERITED1(morkFile, morkObject, nsIMdbFile)
00124 /*public non-poly*/ void
00125 morkFile::CloseFile(morkEnv* ev) // called by CloseMorkNode();
00126 {
00127   if ( this )
00128   {
00129     if ( this->IsNode() )
00130     {
00131       mFile_Frozen = 0;
00132       mFile_DoTrace = 0;
00133       mFile_IoOpen = 0;
00134       mFile_Active = 0;
00135       
00136       if ( mFile_Name )
00137         this->SetFileName(ev, (const char*) 0);
00138 
00139       nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mFile_SlotHeap);
00140       nsIMdbFile_SlotStrongFile((nsIMdbFile*) 0, ev, &mFile_Thief);
00141 
00142       this->MarkShut();
00143     }
00144     else
00145       this->NonNodeError(ev);
00146   }
00147   else
00148     ev->NilPointerError();
00149 }
00150 
00151 // } ===== end morkNode methods =====
00152 // ````` ````` ````` ````` ````` 
00153 
00154 nsIMdbFile*
00155 morkFile::AcquireFileHandle(morkEnv* ev)
00156 {
00157   nsIMdbFile* outFile = 0;
00158 
00159 #ifdef MORK_CONFIG_USE_ORKINFILE
00160   return this;
00161 #endif /*MORK_CONFIG_USE_ORKINFILE*/
00162   MORK_USED_1(ev);
00163     
00164   return outFile;
00165 }
00166 
00167 /*static*/ morkFile*
00168 morkFile::OpenOldFile(morkEnv* ev, nsIMdbHeap* ioHeap,
00169   const char* inFilePath, mork_bool inFrozen)
00170   // Choose some subclass of morkFile to instantiate, in order to read
00171   // (and write if not frozen) the file known by inFilePath.  The file
00172   // returned should be open and ready for use, and presumably positioned
00173   // at the first byte position of the file.  The exact manner in which
00174   // files must be opened is considered a subclass specific detail, and
00175   // other portions or Mork source code don't want to know how it's done.
00176 {
00177   return morkStdioFile::OpenOldStdioFile(ev, ioHeap, inFilePath, inFrozen);
00178 }
00179 
00180 /*static*/ morkFile*
00181 morkFile::CreateNewFile(morkEnv* ev, nsIMdbHeap* ioHeap,
00182   const char* inFilePath)
00183   // Choose some subclass of morkFile to instantiate, in order to read
00184   // (and write if not frozen) the file known by inFilePath.  The file
00185   // returned should be created and ready for use, and presumably positioned
00186   // at the first byte position of the file.  The exact manner in which
00187   // files must be opened is considered a subclass specific detail, and
00188   // other portions or Mork source code don't want to know how it's done.
00189 {
00190   return morkStdioFile::CreateNewStdioFile(ev, ioHeap, inFilePath);
00191 }
00192 
00193 void
00194 morkFile::NewMissingIoError(morkEnv* ev) const
00195 {
00196   ev->NewError("file missing io");
00197 }
00198 
00199 /*static*/ void
00200 morkFile::NonFileTypeError(morkEnv* ev)
00201 {
00202   ev->NewError("non morkFile");
00203 }
00204 
00205 /*static*/ void
00206 morkFile::NilSlotHeapError(morkEnv* ev)
00207 {
00208   ev->NewError("nil mFile_SlotHeap");
00209 }
00210 
00211 /*static*/ void
00212 morkFile::NilFileNameError(morkEnv* ev)
00213 {
00214   ev->NewError("nil mFile_Name");
00215 }
00216 
00217 void
00218 morkFile::SetThief(morkEnv* ev, nsIMdbFile* ioThief)
00219 {
00220   nsIMdbFile_SlotStrongFile(ioThief, ev, &mFile_Thief);
00221 }
00222 
00223 void
00224 morkFile::SetFileName(morkEnv* ev, const char* inName) // inName can be nil
00225 {
00226   nsIMdbHeap* heap = mFile_SlotHeap;
00227   if ( heap )
00228   {
00229     char* name = mFile_Name;
00230     if ( name )
00231     {
00232       mFile_Name = 0;
00233       ev->FreeString(heap, name);
00234     }
00235     if ( ev->Good() && inName )
00236       mFile_Name = ev->CopyString(heap, inName);
00237   }
00238   else
00239     this->NilSlotHeapError(ev);
00240 }
00241 
00242 void
00243 morkFile::NewFileDownError(morkEnv* ev) const
00244 // call NewFileDownError() when either IsOpenAndActiveFile()
00245 // is false, or when IsOpenActiveAndMutableFile() is false.
00246 {
00247   if ( this->IsOpenNode() )
00248   {
00249     if ( this->FileActive() )
00250     {
00251       if ( this->FileFrozen() )
00252       {
00253         ev->NewError("file frozen");
00254       }
00255       else
00256         ev->NewError("unknown file problem");
00257     }
00258     else
00259       ev->NewError("file not active");
00260   }
00261   else
00262     ev->NewError("file not open");
00263 }
00264 
00265 void
00266 morkFile::NewFileErrnoError(morkEnv* ev) const
00267 // call NewFileErrnoError() to convert std C errno into AB fault
00268 {
00269   const char* errnoString = strerror(errno);
00270   ev->NewError(errnoString); // maybe pass value of strerror() instead
00271 }
00272 
00273 // ````` ````` ````` ````` newlines ````` ````` ````` `````  
00274 
00275 #if defined(MORK_MAC)
00276        static const char morkFile_kNewlines[] = 
00277        "\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015";
00278 #      define morkFile_kNewlinesCount 16
00279 #else
00280 #  if defined(MORK_WIN) || defined(MORK_OS2)
00281        static const char morkFile_kNewlines[] = 
00282        "\015\012\015\012\015\012\015\012\015\012\015\012\015\012\015\012";
00283 #    define morkFile_kNewlinesCount 8
00284 #  else
00285 #    if defined(MORK_UNIX) || defined(MORK_BEOS)
00286        static const char morkFile_kNewlines[] = 
00287        "\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012";
00288 #      define morkFile_kNewlinesCount 16
00289 #    endif /* MORK_UNIX || MORK_BEOS */
00290 #  endif /* MORK_WIN */
00291 #endif /* MORK_MAC */
00292 
00293 mork_size
00294 morkFile::WriteNewlines(morkEnv* ev, mork_count inNewlines)
00295   // WriteNewlines() returns the number of bytes written.
00296 {
00297   mork_size outSize = 0;
00298   while ( inNewlines && ev->Good() ) // more newlines to write?
00299   {
00300     mork_u4 quantum = inNewlines;
00301     if ( quantum > morkFile_kNewlinesCount )
00302       quantum = morkFile_kNewlinesCount;
00303 
00304     mork_size quantumSize = quantum * mork_kNewlineSize;
00305     mdb_size bytesWritten;
00306     this->Write(ev->AsMdbEnv(), morkFile_kNewlines, quantumSize, &bytesWritten);
00307     outSize += quantumSize;
00308     inNewlines -= quantum;
00309   }
00310   return outSize;
00311 }
00312 
00313 NS_IMETHODIMP
00314 morkFile::Eof(nsIMdbEnv* mev, mdb_pos* outPos)
00315 {
00316   mdb_err outErr = 0;
00317   mdb_pos pos = -1;
00318   morkEnv *ev = morkEnv::FromMdbEnv(mev);
00319   pos = Length(ev);
00320   outErr = ev->AsErr();
00321   if ( outPos )
00322     *outPos = pos;
00323   return outErr;
00324 }
00325 
00326 NS_IMETHODIMP
00327 morkFile::Get(nsIMdbEnv* mev, void* outBuf, mdb_size inSize,
00328   mdb_pos inPos, mdb_size* outActualSize)
00329 {
00330   nsresult rv = NS_OK;
00331   morkEnv *ev = morkEnv::FromMdbEnv(mev);
00332   if ( ev )
00333   {
00334     mdb_pos outPos;
00335     Seek(mev, inPos, &outPos);
00336     if ( ev->Good() )
00337       rv = Read(mev, outBuf, inSize, outActualSize);
00338   }
00339   return rv;
00340 }
00341 
00342 NS_IMETHODIMP
00343 morkFile::Put(nsIMdbEnv* mev, const void* inBuf, mdb_size inSize,
00344   mdb_pos inPos, mdb_size* outActualSize)
00345 {
00346   mdb_err outErr = 0;
00347   *outActualSize = 0;
00348   morkEnv *ev = morkEnv::FromMdbEnv(mev);
00349   if ( ev )
00350   {
00351     mdb_pos outPos;
00352 
00353     Seek(mev, inPos, &outPos);
00354     if ( ev->Good() )
00355       Write(mev, inBuf, inSize, outActualSize);
00356     outErr = ev->AsErr();
00357   }
00358   return outErr;
00359 }
00360 
00361 // { ----- begin path methods -----
00362 NS_IMETHODIMP
00363 morkFile::Path(nsIMdbEnv* mev, mdbYarn* outFilePath)
00364 {
00365   mdb_err outErr = 0;
00366   if ( outFilePath )
00367     outFilePath->mYarn_Fill = 0;
00368   morkEnv *ev = morkEnv::FromMdbEnv(mev);
00369   if ( ev )
00370   {
00371     ev->StringToYarn(GetFileNameString(), outFilePath);
00372     outErr = ev->AsErr();
00373   }
00374   return outErr;
00375 }
00376 
00377 // } ----- end path methods -----
00378   
00379 // { ----- begin replacement methods -----
00380 
00381 
00382 NS_IMETHODIMP
00383 morkFile::Thief(nsIMdbEnv* mev, nsIMdbFile** acqThief)
00384 {
00385   mdb_err outErr = 0;
00386   nsIMdbFile* outThief = 0;
00387   morkEnv *ev = morkEnv::FromMdbEnv(mev);
00388   if ( ev )
00389   {
00390     outThief = GetThief();
00391     NS_IF_ADDREF(outThief);
00392     outErr = ev->AsErr();
00393   }
00394   if ( acqThief )
00395     *acqThief = outThief;
00396   return outErr;
00397 }
00398 
00399 // } ----- end replacement methods -----
00400 
00401 // { ----- begin versioning methods -----
00402 
00403 // ````` ````` ````` ````` ````` 
00404 // { ===== begin morkNode interface =====
00405 
00406 /*public virtual*/ void
00407 morkStdioFile::CloseMorkNode(morkEnv* ev) // CloseStdioFile() only if open
00408 {
00409   if ( this->IsOpenNode() )
00410   {
00411     this->MarkClosing();
00412     this->CloseStdioFile(ev);
00413     this->MarkShut();
00414   }
00415 }
00416 
00417 /*public virtual*/
00418 morkStdioFile::~morkStdioFile() // assert CloseStdioFile() executed earlier
00419 {
00420   if (mStdioFile_File)
00421     CloseStdioFile(mMorkEnv);
00422   MORK_ASSERT(mStdioFile_File==0);
00423 }
00424 
00425 /*public non-poly*/ void
00426 morkStdioFile::CloseStdioFile(morkEnv* ev) // called by CloseMorkNode();
00427 {
00428   if ( this )
00429   {
00430     if ( this->IsNode() )
00431     {
00432       if ( mStdioFile_File && this->FileActive() && this->FileIoOpen() )
00433       {
00434         this->CloseStdio(ev);
00435       }
00436       
00437       mStdioFile_File = 0;
00438       
00439       this->CloseFile(ev);
00440       this->MarkShut();
00441     }
00442     else
00443       this->NonNodeError(ev);
00444   }
00445   else
00446     ev->NilPointerError();
00447 }
00448 
00449 // } ===== end morkNode methods =====
00450 // ````` ````` ````` ````` ````` 
00451 
00452 // compatible with the morkFile::MakeFile() entry point
00453 
00454 /*static*/ morkStdioFile* 
00455 morkStdioFile::OpenOldStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
00456   const char* inFilePath, mork_bool inFrozen)
00457 {
00458   morkStdioFile* outFile = 0;
00459   if ( ioHeap && inFilePath )
00460   {
00461     const char* mode = (inFrozen)? "rb" : "rb+";
00462     outFile = new(*ioHeap, ev)
00463       morkStdioFile(ev, morkUsage::kHeap, ioHeap, ioHeap, inFilePath, mode); 
00464       
00465     if ( outFile )
00466     {
00467       outFile->SetFileFrozen(inFrozen);
00468     }
00469   }
00470   else
00471     ev->NilPointerError();
00472   
00473   return outFile;
00474 }
00475 
00476 /*static*/ morkStdioFile* 
00477 morkStdioFile::CreateNewStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
00478   const char* inFilePath)
00479 {
00480   morkStdioFile* outFile = 0;
00481   if ( ioHeap && inFilePath )
00482   {
00483     const char* mode = "wb+";
00484     outFile = new(*ioHeap, ev)
00485       morkStdioFile(ev, morkUsage::kHeap, ioHeap, ioHeap, inFilePath, mode); 
00486   }
00487   else
00488     ev->NilPointerError();
00489 
00490   return outFile;
00491 }
00492 
00493 
00494 
00495 NS_IMETHODIMP
00496 morkStdioFile::BecomeTrunk(nsIMdbEnv* ev)
00497   // If this file is a file version branch created by calling AcquireBud(),
00498   // BecomeTrunk() causes this file's content to replace the original
00499   // file's content, typically by assuming the original file's identity.
00500 {
00501   return Flush(ev);
00502 }
00503 
00504 NS_IMETHODIMP 
00505 morkStdioFile::AcquireBud(nsIMdbEnv * mdbev, nsIMdbHeap* ioHeap, nsIMdbFile **acquiredFile)
00506   // AcquireBud() starts a new "branch" version of the file, empty of content,
00507   // so that a new version of the file can be written.  This new file
00508   // can later be told to BecomeTrunk() the original file, so the branch
00509   // created by budding the file will replace the original file.  Some
00510   // file subclasses might initially take the unsafe but expedient
00511   // approach of simply truncating this file down to zero length, and
00512   // then returning the same morkFile pointer as this, with an extra
00513   // reference count increment.  Note that the caller of AcquireBud() is
00514   // expected to eventually call CutStrongRef() on the returned file
00515   // in order to release the strong reference.  High quality versions
00516   // of morkFile subclasses will create entirely new files which later
00517   // are renamed to become the old file, so that better transactional
00518   // behavior is exhibited by the file, so crashes protect old files.
00519   // Note that AcquireBud() is an illegal operation on readonly files.
00520 {
00521   NS_ENSURE_ARG(acquiredFile);
00522   MORK_USED_1(ioHeap);
00523   nsresult rv = NS_OK;
00524   morkFile* outFile = 0;
00525   morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
00526 
00527   if ( this->IsOpenAndActiveFile() )
00528   {
00529     FILE* file = (FILE*) mStdioFile_File;
00530     if ( file )
00531     {
00532 //#ifdef MORK_WIN
00533 //      truncate(file, /*eof*/ 0);
00534 //#else /*MORK_WIN*/
00535       char* name = mFile_Name;
00536       if ( name )
00537       {
00538         if ( MORK_FILECLOSE(file) >= 0 )
00539         {
00540           this->SetFileActive(morkBool_kFalse);
00541           this->SetFileIoOpen(morkBool_kFalse);
00542           mStdioFile_File = 0;
00543           
00544           file = MORK_FILEOPEN(name, "wb+"); // open for write, discarding old content
00545           if ( file )
00546           {
00547             mStdioFile_File = file;
00548             this->SetFileActive(morkBool_kTrue);
00549             this->SetFileIoOpen(morkBool_kTrue);
00550             this->SetFileFrozen(morkBool_kFalse);
00551           }
00552           else
00553             this->new_stdio_file_fault(ev);
00554         }
00555         else
00556           this->new_stdio_file_fault(ev);
00557       }
00558       else
00559         this->NilFileNameError(ev);
00560       
00561 //#endif /*MORK_WIN*/
00562 
00563       if ( ev->Good() && this->AddStrongRef(ev->AsMdbEnv()) )
00564       {
00565         outFile = this;
00566         AddRef();
00567       }
00568     }
00569     else if ( mFile_Thief )
00570     {
00571       rv = mFile_Thief->AcquireBud(ev->AsMdbEnv(), ioHeap, acquiredFile);
00572     }
00573     else
00574       this->NewMissingIoError(ev);
00575   }
00576   else this->NewFileDownError(ev);
00577   
00578   *acquiredFile = outFile;
00579   return rv;
00580 }
00581 
00582 mork_pos 
00583 morkStdioFile::Length(morkEnv * ev) const
00584 {
00585   mork_pos outPos = 0;
00586   
00587   if ( this->IsOpenAndActiveFile() )
00588   {
00589     FILE* file = (FILE*) mStdioFile_File;
00590     if ( file )
00591     {
00592       long start = MORK_FILETELL(file);
00593       if ( start >= 0 )
00594       {
00595         long fore = MORK_FILESEEK(file, 0, SEEK_END);
00596         if ( fore >= 0 )
00597         {
00598           long eof = MORK_FILETELL(file);
00599           if ( eof >= 0 )
00600           {
00601             long back = MORK_FILESEEK(file, start, SEEK_SET);
00602             if ( back >= 0 )
00603               outPos = eof;
00604             else
00605               this->new_stdio_file_fault(ev);
00606           }
00607           else this->new_stdio_file_fault(ev);
00608         }
00609         else this->new_stdio_file_fault(ev);
00610       }
00611       else this->new_stdio_file_fault(ev);
00612     }
00613     else if ( mFile_Thief )
00614       mFile_Thief->Eof(ev->AsMdbEnv(), &outPos);
00615     else
00616       this->NewMissingIoError(ev);
00617   }
00618   else this->NewFileDownError(ev);
00619 
00620   return outPos;
00621 }
00622 
00623 NS_IMETHODIMP
00624 morkStdioFile::Tell(nsIMdbEnv* ev, mork_pos *outPos) const
00625 {
00626   nsresult rv = NS_OK;
00627   NS_ENSURE_ARG(outPos);  
00628   morkEnv* mev = morkEnv::FromMdbEnv(ev);
00629   if ( this->IsOpenAndActiveFile() )
00630   {
00631     FILE* file = (FILE*) mStdioFile_File;
00632     if ( file )
00633     {
00634       long where = MORK_FILETELL(file);
00635       if ( where >= 0 )
00636         *outPos = where;
00637       else
00638         this->new_stdio_file_fault(mev);
00639     }
00640     else if ( mFile_Thief )
00641       mFile_Thief->Tell(ev, outPos);
00642     else
00643       this->NewMissingIoError(mev);
00644   }
00645   else this->NewFileDownError(mev);
00646 
00647   return rv;
00648 }
00649 
00650 NS_IMETHODIMP
00651 morkStdioFile::Read(nsIMdbEnv* ev, void* outBuf, mork_size inSize,  mork_num *outCount)
00652 {
00653   nsresult rv = NS_OK;
00654   morkEnv* mev = morkEnv::FromMdbEnv(ev);
00655   if ( this->IsOpenAndActiveFile() )
00656   {
00657     FILE* file = (FILE*) mStdioFile_File;
00658     if ( file )
00659     {
00660       long count = (long) MORK_FILEREAD(outBuf, inSize, file);
00661       if ( count >= 0 )
00662       {
00663         *outCount = (mork_num) count;
00664       }
00665       else this->new_stdio_file_fault(mev);
00666     }
00667     else if ( mFile_Thief )
00668       mFile_Thief->Read(ev, outBuf, inSize, outCount);
00669     else
00670       this->NewMissingIoError(mev);
00671   }
00672   else this->NewFileDownError(mev);
00673 
00674   return rv;
00675 }
00676 
00677 NS_IMETHODIMP 
00678 morkStdioFile::Seek(nsIMdbEnv* mdbev, mork_pos inPos, mork_pos *aOutPos)
00679 {
00680   mork_pos outPos = 0;
00681   nsresult rv = NS_OK;
00682   morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
00683 
00684   if ( this->IsOpenOrClosingNode() && this->FileActive() )
00685   {
00686     FILE* file = (FILE*) mStdioFile_File;
00687     if ( file )
00688     {
00689       long where = MORK_FILESEEK(file, inPos, SEEK_SET);
00690       if ( where >= 0 )
00691         outPos = inPos;
00692       else
00693         this->new_stdio_file_fault(ev);
00694     }
00695     else if ( mFile_Thief )
00696       mFile_Thief->Seek(mdbev, inPos, aOutPos);
00697     else
00698       this->NewMissingIoError(ev);
00699   }
00700   else this->NewFileDownError(ev);
00701 
00702   *aOutPos = outPos;
00703   return rv;
00704 }
00705 
00706 NS_IMETHODIMP 
00707 morkStdioFile::Write(nsIMdbEnv* mdbev, const void* inBuf, mork_size inSize, mork_size *aOutSize)
00708 {
00709   mork_num outCount = 0;
00710   nsresult rv = NS_OK;
00711   morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
00712   if ( this->IsOpenActiveAndMutableFile() )
00713   {
00714     FILE* file = (FILE*) mStdioFile_File;
00715     if ( file )
00716     {
00717       fwrite(inBuf, 1, inSize, file);
00718       if ( !ferror(file) )
00719         outCount = inSize;
00720       else
00721         this->new_stdio_file_fault(ev);
00722     }
00723     else if ( mFile_Thief )
00724       mFile_Thief->Write(mdbev, inBuf, inSize, &outCount);
00725     else
00726       this->NewMissingIoError(ev);
00727   }
00728   else this->NewFileDownError(ev);
00729 
00730   *aOutSize = outCount;
00731   return rv;
00732 }
00733 
00734 NS_IMETHODIMP
00735 morkStdioFile::Flush(nsIMdbEnv* mdbev)
00736 {
00737   morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
00738   if ( this->IsOpenOrClosingNode() && this->FileActive() )
00739   {
00740     FILE* file = (FILE*) mStdioFile_File;
00741     if ( file )
00742     {
00743       MORK_FILEFLUSH(file);
00744 
00745     }
00746     else if ( mFile_Thief )
00747       mFile_Thief->Flush(mdbev);
00748     else
00749       this->NewMissingIoError(ev);
00750   }
00751   else this->NewFileDownError(ev);
00752   return NS_OK;
00753 }
00754 
00755 // ````` ````` ````` `````   ````` ````` ````` `````  
00756 //protected: // protected non-poly morkStdioFile methods
00757 
00758 void
00759 morkStdioFile::new_stdio_file_fault(morkEnv* ev) const
00760 {
00761   FILE* file = (FILE*) mStdioFile_File;
00762 
00763   int copyErrno = errno; // facilitate seeing error in debugger
00764   
00765   //  bunch of stuff not ported here
00766   if ( !copyErrno && file )
00767   {
00768     copyErrno = ferror(file);
00769     errno = copyErrno;
00770   }
00771 
00772   this->NewFileErrnoError(ev);
00773 }
00774 
00775 // ````` ````` ````` `````   ````` ````` ````` `````  
00776 //public: // public non-poly morkStdioFile methods
00777 
00778 
00779 /*public non-poly*/
00780 morkStdioFile::morkStdioFile(morkEnv* ev,
00781   const morkUsage& inUsage, nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
00782 : morkFile(ev, inUsage, ioHeap, ioSlotHeap)
00783 , mStdioFile_File( 0 )
00784 {
00785   if ( ev->Good() )
00786     mNode_Derived = morkDerived_kStdioFile;
00787 }
00788 
00789 morkStdioFile::morkStdioFile(morkEnv* ev, const morkUsage& inUsage,
00790   nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap,
00791   const char* inName, const char* inMode)
00792   // calls OpenStdio() after construction
00793 : morkFile(ev, inUsage, ioHeap, ioSlotHeap)
00794 , mStdioFile_File( 0 )
00795 {
00796   if ( ev->Good() )
00797     this->OpenStdio(ev, inName, inMode);
00798 }
00799 
00800 morkStdioFile::morkStdioFile(morkEnv* ev, const morkUsage& inUsage,
00801    nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap,
00802    void* ioFile, const char* inName, mork_bool inFrozen)
00803   // calls UseStdio() after construction
00804 : morkFile(ev, inUsage, ioHeap, ioSlotHeap)
00805 , mStdioFile_File( 0 )
00806 {
00807   if ( ev->Good() )
00808     this->UseStdio(ev, ioFile, inName, inFrozen);
00809 }
00810 
00811 void
00812 morkStdioFile::OpenStdio(morkEnv* ev, const char* inName, const char* inMode)
00813   // Open a new FILE with name inName, using mode flags from inMode.
00814 {
00815   if ( ev->Good() )
00816   {
00817     if ( !inMode )
00818       inMode = "";
00819     
00820     mork_bool frozen = (*inMode == 'r'); // cursory attempt to note readonly
00821     
00822     if ( this->IsOpenNode() )
00823     {
00824       if ( !this->FileActive() )
00825       {
00826         this->SetFileIoOpen(morkBool_kFalse);
00827         if ( inName && *inName )
00828         {
00829           this->SetFileName(ev, inName);
00830           if ( ev->Good() )
00831           {
00832             FILE* file = MORK_FILEOPEN(inName, inMode);
00833             if ( file )
00834             {
00835               mStdioFile_File = file;
00836               this->SetFileActive(morkBool_kTrue);
00837               this->SetFileIoOpen(morkBool_kTrue);
00838               this->SetFileFrozen(frozen);
00839             }
00840             else
00841               this->new_stdio_file_fault(ev);
00842           }
00843         }
00844         else ev->NewError("no file name");
00845       }
00846       else ev->NewError("file already active");
00847     }
00848     else this->NewFileDownError(ev);
00849   }
00850 }
00851 
00852 void
00853 morkStdioFile::UseStdio(morkEnv* ev, void* ioFile, const char* inName,
00854   mork_bool inFrozen)
00855   // Use an existing file, like stdin/stdout/stderr, which should not
00856   // have the io stream closed when the file is closed.  The ioFile
00857   // parameter must actually be of type FILE (but we don't want to make
00858   // this header file include the stdio.h header file).
00859 {
00860   if ( ev->Good() )
00861   {
00862     if ( this->IsOpenNode() )
00863     {
00864       if ( !this->FileActive() )
00865       {
00866         if ( ioFile )
00867         {
00868           this->SetFileIoOpen(morkBool_kFalse);
00869           this->SetFileName(ev, inName);
00870           if ( ev->Good() )
00871           {
00872             mStdioFile_File = ioFile;
00873             this->SetFileActive(morkBool_kTrue);
00874             this->SetFileFrozen(inFrozen);
00875           }
00876         }
00877         else
00878           ev->NilPointerError();
00879       }
00880       else ev->NewError("file already active");
00881     }
00882     else this->NewFileDownError(ev);
00883   }
00884 }
00885 
00886 void
00887 morkStdioFile::CloseStdio(morkEnv* ev)
00888   // Close the stream io if both and FileActive() and FileIoOpen(), but
00889   // this does not close this instances (like CloseStdioFile() does).
00890   // If stream io was made active by means of calling UseStdio(),
00891   // then this method does little beyond marking the stream inactive
00892   // because FileIoOpen() is false.
00893 {
00894   if ( mStdioFile_File && this->FileActive() && this->FileIoOpen() )
00895   {
00896     FILE* file = (FILE*) mStdioFile_File;
00897     if ( MORK_FILECLOSE(file) < 0 )
00898       this->new_stdio_file_fault(ev);
00899     
00900     mStdioFile_File = 0;
00901     this->SetFileActive(morkBool_kFalse);
00902     this->SetFileIoOpen(morkBool_kFalse);
00903   }
00904 }
00905 
00906 
00907 NS_IMETHODIMP
00908 morkStdioFile::Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief)
00909   // If this file is a file version branch created by calling AcquireBud(),
00910   // BecomeTrunk() causes this file's content to replace the original
00911   // file's content, typically by assuming the original file's identity.
00912 {
00913   morkEnv *mev = morkEnv::FromMdbEnv(ev);
00914   if ( mStdioFile_File && FileActive() && FileIoOpen() )
00915   {
00916     FILE* file = (FILE*) mStdioFile_File;
00917     if ( MORK_FILECLOSE(file) < 0 )
00918       new_stdio_file_fault(mev);
00919     
00920     mStdioFile_File = 0;
00921   }
00922   SetThief(mev, ioThief);
00923   return NS_OK;
00924 }
00925 
00926 
00927 #if defined(MORK_WIN)
00928 
00929 void mork_fileflush(FILE * file)
00930 {
00931   fflush(file);
00932 #ifndef WINCE
00933   OSVERSIONINFOA vi = { sizeof(OSVERSIONINFOA) };
00934   if ((GetVersionExA(&vi) && vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS))
00935   {
00936     // Win9x/ME
00937     int fd = fileno(file);
00938     HANDLE fh = (HANDLE)_get_osfhandle(fd);
00939     FlushFileBuffers(fh);
00940   }
00941 #endif
00942 }
00943 
00944 #endif /*MORK_WIN*/
00945 
00946 
00947 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789