summaryrefslogtreecommitdiffstats
path: root/db/mork/src/morkFile.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2019-11-03 00:17:46 -0400
committerMatt A. Tobin <email@mattatobin.com>2019-11-03 00:17:46 -0400
commit302bf1b523012e11b60425d6eee1221ebc2724eb (patch)
treeb191a895f8716efcbe42f454f37597a545a6f421 /db/mork/src/morkFile.cpp
parent21b3f6247403c06f85e1f45d219f87549862198f (diff)
downloadUXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar.gz
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar.lz
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar.xz
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.zip
Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1
Diffstat (limited to 'db/mork/src/morkFile.cpp')
-rw-r--r--db/mork/src/morkFile.cpp874
1 files changed, 874 insertions, 0 deletions
diff --git a/db/mork/src/morkFile.cpp b/db/mork/src/morkFile.cpp
new file mode 100644
index 000000000..040d1a8dc
--- /dev/null
+++ b/db/mork/src/morkFile.cpp
@@ -0,0 +1,874 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _MDB_
+#include "mdb.h"
+#endif
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKNODE_
+#include "morkNode.h"
+#endif
+
+#ifndef _MORKENV_
+#include "morkEnv.h"
+#endif
+
+#ifndef _MORKFILE_
+#include "morkFile.h"
+#endif
+
+#ifdef MORK_WIN
+#include "io.h"
+#include <windows.h>
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void
+morkFile::CloseMorkNode(morkEnv* ev) // CloseFile() only if open
+{
+ if ( this->IsOpenNode() )
+ {
+ this->MarkClosing();
+ this->CloseFile(ev);
+ this->MarkShut();
+ }
+}
+
+/*public virtual*/
+morkFile::~morkFile() // assert CloseFile() executed earlier
+{
+ MORK_ASSERT(mFile_Frozen==0);
+ MORK_ASSERT(mFile_DoTrace==0);
+ MORK_ASSERT(mFile_IoOpen==0);
+ MORK_ASSERT(mFile_Active==0);
+}
+
+/*public non-poly*/
+morkFile::morkFile(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
+: morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*) 0)
+, mFile_Frozen( 0 )
+, mFile_DoTrace( 0 )
+, mFile_IoOpen( 0 )
+, mFile_Active( 0 )
+
+, mFile_SlotHeap( 0 )
+, mFile_Name( 0 )
+, mFile_Thief( 0 )
+{
+ if ( ev->Good() )
+ {
+ if ( ioSlotHeap )
+ {
+ nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mFile_SlotHeap);
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kFile;
+ }
+ else
+ ev->NilPointerError();
+ }
+}
+
+NS_IMPL_ISUPPORTS_INHERITED(morkFile, morkObject, nsIMdbFile)
+/*public non-poly*/ void
+morkFile::CloseFile(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this->IsNode() )
+ {
+ mFile_Frozen = 0;
+ mFile_DoTrace = 0;
+ mFile_IoOpen = 0;
+ mFile_Active = 0;
+
+ if ( mFile_Name )
+ this->SetFileName(ev, (const char*) 0);
+
+ nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mFile_SlotHeap);
+ nsIMdbFile_SlotStrongFile((nsIMdbFile*) 0, ev, &mFile_Thief);
+
+ this->MarkShut();
+ }
+ else
+ this->NonNodeError(ev);
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+
+/*static*/ morkFile*
+morkFile::OpenOldFile(morkEnv* ev, nsIMdbHeap* ioHeap,
+ const char* inFilePath, mork_bool inFrozen)
+ // Choose some subclass of morkFile to instantiate, in order to read
+ // (and write if not frozen) the file known by inFilePath. The file
+ // returned should be open and ready for use, and presumably positioned
+ // at the first byte position of the file. The exact manner in which
+ // files must be opened is considered a subclass specific detail, and
+ // other portions or Mork source code don't want to know how it's done.
+{
+ return morkStdioFile::OpenOldStdioFile(ev, ioHeap, inFilePath, inFrozen);
+}
+
+/*static*/ morkFile*
+morkFile::CreateNewFile(morkEnv* ev, nsIMdbHeap* ioHeap,
+ const char* inFilePath)
+ // Choose some subclass of morkFile to instantiate, in order to read
+ // (and write if not frozen) the file known by inFilePath. The file
+ // returned should be created and ready for use, and presumably positioned
+ // at the first byte position of the file. The exact manner in which
+ // files must be opened is considered a subclass specific detail, and
+ // other portions or Mork source code don't want to know how it's done.
+{
+ return morkStdioFile::CreateNewStdioFile(ev, ioHeap, inFilePath);
+}
+
+void
+morkFile::NewMissingIoError(morkEnv* ev) const
+{
+ ev->NewError("file missing io");
+}
+
+/*static*/ void
+morkFile::NonFileTypeError(morkEnv* ev)
+{
+ ev->NewError("non morkFile");
+}
+
+/*static*/ void
+morkFile::NilSlotHeapError(morkEnv* ev)
+{
+ ev->NewError("nil mFile_SlotHeap");
+}
+
+/*static*/ void
+morkFile::NilFileNameError(morkEnv* ev)
+{
+ ev->NewError("nil mFile_Name");
+}
+
+void
+morkFile::SetThief(morkEnv* ev, nsIMdbFile* ioThief)
+{
+ nsIMdbFile_SlotStrongFile(ioThief, ev, &mFile_Thief);
+}
+
+void
+morkFile::SetFileName(morkEnv* ev, const char* inName) // inName can be nil
+{
+ nsIMdbHeap* heap = mFile_SlotHeap;
+ if ( heap )
+ {
+ char* name = mFile_Name;
+ if ( name )
+ {
+ mFile_Name = 0;
+ ev->FreeString(heap, name);
+ }
+ if ( ev->Good() && inName )
+ mFile_Name = ev->CopyString(heap, inName);
+ }
+ else
+ this->NilSlotHeapError(ev);
+}
+
+void
+morkFile::NewFileDownError(morkEnv* ev) const
+// call NewFileDownError() when either IsOpenAndActiveFile()
+// is false, or when IsOpenActiveAndMutableFile() is false.
+{
+ if ( this->IsOpenNode() )
+ {
+ if ( this->FileActive() )
+ {
+ if ( this->FileFrozen() )
+ {
+ ev->NewError("file frozen");
+ }
+ else
+ ev->NewError("unknown file problem");
+ }
+ else
+ ev->NewError("file not active");
+ }
+ else
+ ev->NewError("file not open");
+}
+
+void
+morkFile::NewFileErrnoError(morkEnv* ev) const
+// call NewFileErrnoError() to convert std C errno into AB fault
+{
+ const char* errnoString = strerror(errno);
+ ev->NewError(errnoString); // maybe pass value of strerror() instead
+}
+
+// ````` ````` ````` ````` newlines ````` ````` ````` `````
+
+#if defined(MORK_MAC)
+ 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
+#else
+# if defined(MORK_WIN)
+ static const char morkFile_kNewlines[] =
+ "\015\012\015\012\015\012\015\012\015\012\015\012\015\012\015\012";
+# define morkFile_kNewlinesCount 8
+# else
+# ifdef MORK_UNIX
+ static const char morkFile_kNewlines[] =
+ "\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012";
+# define morkFile_kNewlinesCount 16
+# endif /* MORK_UNIX */
+# endif /* MORK_WIN */
+#endif /* MORK_MAC */
+
+mork_size
+morkFile::WriteNewlines(morkEnv* ev, mork_count inNewlines)
+ // WriteNewlines() returns the number of bytes written.
+{
+ mork_size outSize = 0;
+ while ( inNewlines && ev->Good() ) // more newlines to write?
+ {
+ mork_u4 quantum = inNewlines;
+ if ( quantum > morkFile_kNewlinesCount )
+ quantum = morkFile_kNewlinesCount;
+
+ mork_size quantumSize = quantum * mork_kNewlineSize;
+ mdb_size bytesWritten;
+ this->Write(ev->AsMdbEnv(), morkFile_kNewlines, quantumSize, &bytesWritten);
+ outSize += quantumSize;
+ inNewlines -= quantum;
+ }
+ return outSize;
+}
+
+NS_IMETHODIMP
+morkFile::Eof(nsIMdbEnv* mev, mdb_pos* outPos)
+{
+ nsresult outErr = NS_OK;
+ mdb_pos pos = -1;
+ morkEnv *ev = morkEnv::FromMdbEnv(mev);
+ pos = Length(ev);
+ outErr = ev->AsErr();
+ if ( outPos )
+ *outPos = pos;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkFile::Get(nsIMdbEnv* mev, void* outBuf, mdb_size inSize,
+ mdb_pos inPos, mdb_size* outActualSize)
+{
+ nsresult rv = NS_OK;
+ morkEnv *ev = morkEnv::FromMdbEnv(mev);
+ if ( ev )
+ {
+ mdb_pos outPos;
+ Seek(mev, inPos, &outPos);
+ if ( ev->Good() )
+ rv = Read(mev, outBuf, inSize, outActualSize);
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+morkFile::Put(nsIMdbEnv* mev, const void* inBuf, mdb_size inSize,
+ mdb_pos inPos, mdb_size* outActualSize)
+{
+ nsresult outErr = NS_OK;
+ *outActualSize = 0;
+ morkEnv *ev = morkEnv::FromMdbEnv(mev);
+ if ( ev )
+ {
+ mdb_pos outPos;
+
+ Seek(mev, inPos, &outPos);
+ if ( ev->Good() )
+ Write(mev, inBuf, inSize, outActualSize);
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+// { ----- begin path methods -----
+NS_IMETHODIMP
+morkFile::Path(nsIMdbEnv* mev, mdbYarn* outFilePath)
+{
+ nsresult outErr = NS_OK;
+ if ( outFilePath )
+ outFilePath->mYarn_Fill = 0;
+ morkEnv *ev = morkEnv::FromMdbEnv(mev);
+ if ( ev )
+ {
+ ev->StringToYarn(GetFileNameString(), outFilePath);
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+// } ----- end path methods -----
+
+// { ----- begin replacement methods -----
+
+
+NS_IMETHODIMP
+morkFile::Thief(nsIMdbEnv* mev, nsIMdbFile** acqThief)
+{
+ nsresult outErr = NS_OK;
+ nsIMdbFile* outThief = 0;
+ morkEnv *ev = morkEnv::FromMdbEnv(mev);
+ if ( ev )
+ {
+ outThief = GetThief();
+ NS_IF_ADDREF(outThief);
+ outErr = ev->AsErr();
+ }
+ if ( acqThief )
+ *acqThief = outThief;
+ return outErr;
+}
+
+// } ----- end replacement methods -----
+
+// { ----- begin versioning methods -----
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void
+morkStdioFile::CloseMorkNode(morkEnv* ev) // CloseStdioFile() only if open
+{
+ if ( this->IsOpenNode() )
+ {
+ this->MarkClosing();
+ this->CloseStdioFile(ev);
+ this->MarkShut();
+ }
+}
+
+/*public virtual*/
+morkStdioFile::~morkStdioFile() // assert CloseStdioFile() executed earlier
+{
+ if (mStdioFile_File)
+ CloseStdioFile(mMorkEnv);
+ MORK_ASSERT(mStdioFile_File==0);
+}
+
+/*public non-poly*/ void
+morkStdioFile::CloseStdioFile(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this->IsNode() )
+ {
+ if ( mStdioFile_File && this->FileActive() && this->FileIoOpen() )
+ {
+ this->CloseStdio(ev);
+ }
+
+ mStdioFile_File = 0;
+
+ this->CloseFile(ev);
+ this->MarkShut();
+ }
+ else
+ this->NonNodeError(ev);
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+
+// compatible with the morkFile::MakeFile() entry point
+
+/*static*/ morkStdioFile*
+morkStdioFile::OpenOldStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
+ const char* inFilePath, mork_bool inFrozen)
+{
+ morkStdioFile* outFile = 0;
+ if ( ioHeap && inFilePath )
+ {
+ const char* mode = (inFrozen)? "rb" : "rb+";
+ outFile = new(*ioHeap, ev)
+ morkStdioFile(ev, morkUsage::kHeap, ioHeap, ioHeap, inFilePath, mode);
+
+ if ( outFile )
+ {
+ outFile->SetFileFrozen(inFrozen);
+ }
+ }
+ else
+ ev->NilPointerError();
+
+ return outFile;
+}
+
+/*static*/ morkStdioFile*
+morkStdioFile::CreateNewStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
+ const char* inFilePath)
+{
+ morkStdioFile* outFile = 0;
+ if ( ioHeap && inFilePath )
+ {
+ const char* mode = "wb+";
+ outFile = new(*ioHeap, ev)
+ morkStdioFile(ev, morkUsage::kHeap, ioHeap, ioHeap, inFilePath, mode);
+ }
+ else
+ ev->NilPointerError();
+
+ return outFile;
+}
+
+
+
+NS_IMETHODIMP
+morkStdioFile::BecomeTrunk(nsIMdbEnv* ev)
+ // If this file is a file version branch created by calling AcquireBud(),
+ // BecomeTrunk() causes this file's content to replace the original
+ // file's content, typically by assuming the original file's identity.
+{
+ return Flush(ev);
+}
+
+NS_IMETHODIMP
+morkStdioFile::AcquireBud(nsIMdbEnv * mdbev, nsIMdbHeap* ioHeap, nsIMdbFile **acquiredFile)
+ // AcquireBud() starts a new "branch" version of the file, empty of content,
+ // so that a new version of the file can be written. This new file
+ // can later be told to BecomeTrunk() the original file, so the branch
+ // created by budding the file will replace the original file. Some
+ // file subclasses might initially take the unsafe but expedient
+ // approach of simply truncating this file down to zero length, and
+ // then returning the same morkFile pointer as this, with an extra
+ // reference count increment. Note that the caller of AcquireBud() is
+ // expected to eventually call CutStrongRef() on the returned file
+ // in order to release the strong reference. High quality versions
+ // of morkFile subclasses will create entirely new files which later
+ // are renamed to become the old file, so that better transactional
+ // behavior is exhibited by the file, so crashes protect old files.
+ // Note that AcquireBud() is an illegal operation on readonly files.
+{
+ NS_ENSURE_ARG(acquiredFile);
+ MORK_USED_1(ioHeap);
+ nsresult rv = NS_OK;
+ morkFile* outFile = 0;
+ morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
+
+ if ( this->IsOpenAndActiveFile() )
+ {
+ FILE* file = (FILE*) mStdioFile_File;
+ if ( file )
+ {
+//#ifdef MORK_WIN
+// truncate(file, /*eof*/ 0);
+//#else /*MORK_WIN*/
+ char* name = mFile_Name;
+ if ( name )
+ {
+ if ( MORK_FILECLOSE(file) >= 0 )
+ {
+ this->SetFileActive(morkBool_kFalse);
+ this->SetFileIoOpen(morkBool_kFalse);
+ mStdioFile_File = 0;
+
+ file = MORK_FILEOPEN(name, "wb+"); // open for write, discarding old content
+ if ( file )
+ {
+ mStdioFile_File = file;
+ this->SetFileActive(morkBool_kTrue);
+ this->SetFileIoOpen(morkBool_kTrue);
+ this->SetFileFrozen(morkBool_kFalse);
+ }
+ else
+ this->new_stdio_file_fault(ev);
+ }
+ else
+ this->new_stdio_file_fault(ev);
+ }
+ else
+ this->NilFileNameError(ev);
+
+//#endif /*MORK_WIN*/
+
+ if ( ev->Good() && this->AddStrongRef(ev->AsMdbEnv()) )
+ {
+ outFile = this;
+ AddRef();
+ }
+ }
+ else if ( mFile_Thief )
+ {
+ rv = mFile_Thief->AcquireBud(ev->AsMdbEnv(), ioHeap, acquiredFile);
+ }
+ else
+ this->NewMissingIoError(ev);
+ }
+ else this->NewFileDownError(ev);
+
+ *acquiredFile = outFile;
+ return rv;
+}
+
+mork_pos
+morkStdioFile::Length(morkEnv * ev) const
+{
+ mork_pos outPos = 0;
+
+ if ( this->IsOpenAndActiveFile() )
+ {
+ FILE* file = (FILE*) mStdioFile_File;
+ if ( file )
+ {
+ long start = MORK_FILETELL(file);
+ if ( start >= 0 )
+ {
+ long fore = MORK_FILESEEK(file, 0, SEEK_END);
+ if ( fore >= 0 )
+ {
+ long eof = MORK_FILETELL(file);
+ if ( eof >= 0 )
+ {
+ long back = MORK_FILESEEK(file, start, SEEK_SET);
+ if ( back >= 0 )
+ outPos = eof;
+ else
+ this->new_stdio_file_fault(ev);
+ }
+ else this->new_stdio_file_fault(ev);
+ }
+ else this->new_stdio_file_fault(ev);
+ }
+ else this->new_stdio_file_fault(ev);
+ }
+ else if ( mFile_Thief )
+ mFile_Thief->Eof(ev->AsMdbEnv(), &outPos);
+ else
+ this->NewMissingIoError(ev);
+ }
+ else this->NewFileDownError(ev);
+
+ return outPos;
+}
+
+NS_IMETHODIMP
+morkStdioFile::Tell(nsIMdbEnv* ev, mork_pos *outPos) const
+{
+ nsresult rv = NS_OK;
+ NS_ENSURE_ARG(outPos);
+ morkEnv* mev = morkEnv::FromMdbEnv(ev);
+ if ( this->IsOpenAndActiveFile() )
+ {
+ FILE* file = (FILE*) mStdioFile_File;
+ if ( file )
+ {
+ long where = MORK_FILETELL(file);
+ if ( where >= 0 )
+ *outPos = where;
+ else
+ this->new_stdio_file_fault(mev);
+ }
+ else if ( mFile_Thief )
+ mFile_Thief->Tell(ev, outPos);
+ else
+ this->NewMissingIoError(mev);
+ }
+ else this->NewFileDownError(mev);
+
+ return rv;
+}
+
+NS_IMETHODIMP
+morkStdioFile::Read(nsIMdbEnv* ev, void* outBuf, mork_size inSize, mork_num *outCount)
+{
+ nsresult rv = NS_OK;
+ morkEnv* mev = morkEnv::FromMdbEnv(ev);
+ if ( this->IsOpenAndActiveFile() )
+ {
+ FILE* file = (FILE*) mStdioFile_File;
+ if ( file )
+ {
+ long count = (long) MORK_FILEREAD(outBuf, inSize, file);
+ if ( count >= 0 )
+ {
+ *outCount = (mork_num) count;
+ }
+ else this->new_stdio_file_fault(mev);
+ }
+ else if ( mFile_Thief )
+ mFile_Thief->Read(ev, outBuf, inSize, outCount);
+ else
+ this->NewMissingIoError(mev);
+ }
+ else this->NewFileDownError(mev);
+
+ return rv;
+}
+
+NS_IMETHODIMP
+morkStdioFile::Seek(nsIMdbEnv* mdbev, mork_pos inPos, mork_pos *aOutPos)
+{
+ mork_pos outPos = 0;
+ nsresult rv = NS_OK;
+ morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
+
+ if ( this->IsOpenOrClosingNode() && this->FileActive() )
+ {
+ FILE* file = (FILE*) mStdioFile_File;
+ if ( file )
+ {
+ long where = MORK_FILESEEK(file, inPos, SEEK_SET);
+ if ( where >= 0 )
+ outPos = inPos;
+ else
+ this->new_stdio_file_fault(ev);
+ }
+ else if ( mFile_Thief )
+ mFile_Thief->Seek(mdbev, inPos, aOutPos);
+ else
+ this->NewMissingIoError(ev);
+ }
+ else this->NewFileDownError(ev);
+
+ *aOutPos = outPos;
+ return rv;
+}
+
+NS_IMETHODIMP
+morkStdioFile::Write(nsIMdbEnv* mdbev, const void* inBuf, mork_size inSize, mork_size *aOutSize)
+{
+ mork_num outCount = 0;
+ nsresult rv = NS_OK;
+ morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
+ if ( this->IsOpenActiveAndMutableFile() )
+ {
+ FILE* file = (FILE*) mStdioFile_File;
+ if ( file )
+ {
+ fwrite(inBuf, 1, inSize, file);
+ if ( !ferror(file) )
+ outCount = inSize;
+ else
+ this->new_stdio_file_fault(ev);
+ }
+ else if ( mFile_Thief )
+ mFile_Thief->Write(mdbev, inBuf, inSize, &outCount);
+ else
+ this->NewMissingIoError(ev);
+ }
+ else this->NewFileDownError(ev);
+
+ *aOutSize = outCount;
+ return rv;
+}
+
+NS_IMETHODIMP
+morkStdioFile::Flush(nsIMdbEnv* mdbev)
+{
+ morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
+ if ( this->IsOpenOrClosingNode() && this->FileActive() )
+ {
+ FILE* file = (FILE*) mStdioFile_File;
+ if ( file )
+ {
+ MORK_FILEFLUSH(file);
+
+ }
+ else if ( mFile_Thief )
+ mFile_Thief->Flush(mdbev);
+ else
+ this->NewMissingIoError(ev);
+ }
+ else this->NewFileDownError(ev);
+ return NS_OK;
+}
+
+// ````` ````` ````` ````` ````` ````` ````` `````
+//protected: // protected non-poly morkStdioFile methods
+
+void
+morkStdioFile::new_stdio_file_fault(morkEnv* ev) const
+{
+ FILE* file = (FILE*) mStdioFile_File;
+
+ int copyErrno = errno; // facilitate seeing error in debugger
+
+ // bunch of stuff not ported here
+ if ( !copyErrno && file )
+ {
+ copyErrno = ferror(file);
+ errno = copyErrno;
+ }
+
+ this->NewFileErrnoError(ev);
+}
+
+// ````` ````` ````` ````` ````` ````` ````` `````
+//public: // public non-poly morkStdioFile methods
+
+
+/*public non-poly*/
+morkStdioFile::morkStdioFile(morkEnv* ev,
+ const morkUsage& inUsage, nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
+: morkFile(ev, inUsage, ioHeap, ioSlotHeap)
+, mStdioFile_File( 0 )
+{
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kStdioFile;
+}
+
+morkStdioFile::morkStdioFile(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap,
+ const char* inName, const char* inMode)
+ // calls OpenStdio() after construction
+: morkFile(ev, inUsage, ioHeap, ioSlotHeap)
+, mStdioFile_File( 0 )
+{
+ if ( ev->Good() )
+ this->OpenStdio(ev, inName, inMode);
+}
+
+morkStdioFile::morkStdioFile(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap,
+ void* ioFile, const char* inName, mork_bool inFrozen)
+ // calls UseStdio() after construction
+: morkFile(ev, inUsage, ioHeap, ioSlotHeap)
+, mStdioFile_File( 0 )
+{
+ if ( ev->Good() )
+ this->UseStdio(ev, ioFile, inName, inFrozen);
+}
+
+void
+morkStdioFile::OpenStdio(morkEnv* ev, const char* inName, const char* inMode)
+ // Open a new FILE with name inName, using mode flags from inMode.
+{
+ if ( ev->Good() )
+ {
+ if ( !inMode )
+ inMode = "";
+
+ mork_bool frozen = (*inMode == 'r'); // cursory attempt to note readonly
+
+ if ( this->IsOpenNode() )
+ {
+ if ( !this->FileActive() )
+ {
+ this->SetFileIoOpen(morkBool_kFalse);
+ if ( inName && *inName )
+ {
+ this->SetFileName(ev, inName);
+ if ( ev->Good() )
+ {
+ FILE* file = MORK_FILEOPEN(inName, inMode);
+ if ( file )
+ {
+ mStdioFile_File = file;
+ this->SetFileActive(morkBool_kTrue);
+ this->SetFileIoOpen(morkBool_kTrue);
+ this->SetFileFrozen(frozen);
+ }
+ else
+ this->new_stdio_file_fault(ev);
+ }
+ }
+ else ev->NewError("no file name");
+ }
+ else ev->NewError("file already active");
+ }
+ else this->NewFileDownError(ev);
+ }
+}
+
+void
+morkStdioFile::UseStdio(morkEnv* ev, void* ioFile, const char* inName,
+ mork_bool inFrozen)
+ // Use an existing file, like stdin/stdout/stderr, which should not
+ // have the io stream closed when the file is closed. The ioFile
+ // parameter must actually be of type FILE (but we don't want to make
+ // this header file include the stdio.h header file).
+{
+ if ( ev->Good() )
+ {
+ if ( this->IsOpenNode() )
+ {
+ if ( !this->FileActive() )
+ {
+ if ( ioFile )
+ {
+ this->SetFileIoOpen(morkBool_kFalse);
+ this->SetFileName(ev, inName);
+ if ( ev->Good() )
+ {
+ mStdioFile_File = ioFile;
+ this->SetFileActive(morkBool_kTrue);
+ this->SetFileFrozen(inFrozen);
+ }
+ }
+ else
+ ev->NilPointerError();
+ }
+ else ev->NewError("file already active");
+ }
+ else this->NewFileDownError(ev);
+ }
+}
+
+void
+morkStdioFile::CloseStdio(morkEnv* ev)
+ // Close the stream io if both and FileActive() and FileIoOpen(), but
+ // this does not close this instances (like CloseStdioFile() does).
+ // If stream io was made active by means of calling UseStdio(),
+ // then this method does little beyond marking the stream inactive
+ // because FileIoOpen() is false.
+{
+ if ( mStdioFile_File && this->FileActive() && this->FileIoOpen() )
+ {
+ FILE* file = (FILE*) mStdioFile_File;
+ if ( MORK_FILECLOSE(file) < 0 )
+ this->new_stdio_file_fault(ev);
+
+ mStdioFile_File = 0;
+ this->SetFileActive(morkBool_kFalse);
+ this->SetFileIoOpen(morkBool_kFalse);
+ }
+}
+
+
+NS_IMETHODIMP
+morkStdioFile::Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief)
+ // If this file is a file version branch created by calling AcquireBud(),
+ // BecomeTrunk() causes this file's content to replace the original
+ // file's content, typically by assuming the original file's identity.
+{
+ morkEnv *mev = morkEnv::FromMdbEnv(ev);
+ if ( mStdioFile_File && FileActive() && FileIoOpen() )
+ {
+ FILE* file = (FILE*) mStdioFile_File;
+ if ( MORK_FILECLOSE(file) < 0 )
+ new_stdio_file_fault(mev);
+
+ mStdioFile_File = 0;
+ }
+ SetThief(mev, ioThief);
+ return NS_OK;
+}
+
+
+#if defined(MORK_WIN)
+
+void mork_fileflush(FILE * file)
+{
+ fflush(file);
+}
+
+#endif /*MORK_WIN*/
+
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789