new file mode 100644
--- /dev/null
+++ b/db/Makefile.in
@@ -0,0 +1,51 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+ifndef NSS_DISABLE_DBM
+ifdef MOZ_MORK
+PARALLEL_DIRS = mork
+endif
+endif
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/db/mork/Makefile.in
@@ -0,0 +1,48 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = src build public
+
+include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/db/mork/build/Makefile.in
@@ -0,0 +1,63 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+VPATH = @srcdir@
+srcdir = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = mork
+LIBRARY_NAME = mork
+EXPORT_LIBRARY = 1
+IS_COMPONENT = 1
+MODULE_NAME = nsMorkModule
+LIBXUL_LIBRARY = 1
+
+
+CPPSRCS = nsMorkFactory.cpp
+
+EXPORTS = \
+ nsMorkCID.h \
+ nsIMdbFactoryFactory.h \
+ $(NULL)
+
+SHARED_LIBRARY_LIBS = ../src/$(LIB_PREFIX)msgmork_s.$(LIB_SUFFIX)
+
+include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/db/mork/build/nsIMdbFactoryFactory.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsIMdbFactoryFactory_h__
+#define nsIMdbFactoryFactory_h__
+
+#include "nsISupports.h"
+#include "nsIFactory.h"
+#include "nsIComponentManager.h"
+
+class nsIMdbFactory;
+
+// 2794D0B7-E740-47a4-91C0-3E4FCB95B806
+#define NS_IMDBFACTORYFACTORY_IID \
+{ 0x2794d0b7, 0xe740, 0x47a4, { 0x91, 0xc0, 0x3e, 0x4f, 0xcb, 0x95, 0xb8, 0x6 } }
+
+// because Mork doesn't support XPCOM, we have to wrap the mdb factory interface
+// with an interface that gives you an mdb factory.
+class nsIMdbFactoryService : public nsISupports
+{
+public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBFACTORYFACTORY_IID)
+ NS_IMETHOD GetMdbFactory(nsIMdbFactory **aFactory) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbFactoryService, NS_IMDBFACTORYFACTORY_IID)
+
+#endif
new file mode 100644
--- /dev/null
+++ b/db/mork/build/nsMorkCID.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsMorkCID_h__
+#define nsMorkCID_h__
+
+#include "nsISupports.h"
+#include "nsIFactory.h"
+#include "nsIComponentManager.h"
+
+#define NS_MORK_CONTRACTID \
+ "@mozilla.org/db/mork;1"
+
+// 36d90300-27f5-11d3-8d74-00805f8a6617
+#define NS_MORK_CID \
+{ 0x36d90300, 0x27f5, 0x11d3, \
+ { 0x8d, 0x74, 0x00, 0x80, 0x5f, 0x8a, 0x66, 0x17 } }
+
+#endif
new file mode 100644
--- /dev/null
+++ b/db/mork/build/nsMorkFactory.cpp
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Pierre Phaneuf <pp@ludusdesign.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mozilla/ModuleUtils.h"
+#include "nsCOMPtr.h"
+#include "nsMorkCID.h"
+#include "nsIMdbFactoryFactory.h"
+#include "mdb.h"
+
+class nsMorkFactoryService : public nsIMdbFactoryService
+{
+public:
+ nsMorkFactoryService() {};
+ // nsISupports methods
+ NS_DECL_ISUPPORTS
+
+ NS_IMETHOD GetMdbFactory(nsIMdbFactory **aFactory);
+
+protected:
+ nsCOMPtr<nsIMdbFactory> mMdbFactory;
+};
+
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsMorkFactoryService)
+
+NS_DEFINE_NAMED_CID(NS_MORK_CID);
+
+const mozilla::Module::CIDEntry kMorkCIDs[] = {
+ { &kNS_MORK_CID, false, NULL, nsMorkFactoryServiceConstructor },
+ { NULL }
+};
+
+const mozilla::Module::ContractIDEntry kMorkContracts[] = {
+ { NS_MORK_CONTRACTID, &kNS_MORK_CID },
+ { NULL }
+};
+
+static const mozilla::Module kMorkModule = {
+ mozilla::Module::kVersion,
+ kMorkCIDs,
+ kMorkContracts
+};
+
+NSMODULE_DEFN(nsMorkModule) = &kMorkModule;
+
+NS_IMPL_ISUPPORTS1(nsMorkFactoryService, nsIMdbFactoryService)
+
+NS_IMETHODIMP nsMorkFactoryService::GetMdbFactory(nsIMdbFactory **aFactory)
+{
+ if (!mMdbFactory)
+ mMdbFactory = MakeMdbFactory();
+ NS_IF_ADDREF(*aFactory = mMdbFactory);
+ return *aFactory ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
new file mode 100644
--- /dev/null
+++ b/db/mork/public/Makefile.in
@@ -0,0 +1,51 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1999
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = mork
+XPIDL_MODULE = msgmdb
+
+EXPORTS = mdb.h
+
+include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/db/mork/public/mdb.h
@@ -0,0 +1,2569 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Blake Ross (blake@blakeross.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MDB_
+#define _MDB_ 1
+
+#include "nscore.h"
+#include "nsISupports.h"
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// { %%%%% begin scalar typedefs %%%%%
+typedef unsigned char mdb_u1; // make sure this is one byte
+typedef unsigned short mdb_u2; // make sure this is two bytes
+typedef short mdb_i2; // make sure this is two bytes
+typedef PRUint32 mdb_u4; // make sure this is four bytes
+typedef PRInt32 mdb_i4; // make sure this is four bytes
+typedef PRWord mdb_ip; // make sure sizeof(mdb_ip) == sizeof(void*)
+
+typedef mdb_u1 mdb_bool; // unsigned byte with zero=false, nonzero=true
+
+/* canonical boolean constants provided only for code clarity: */
+#define mdbBool_kTrue ((mdb_bool) 1) /* actually any nonzero means true */
+#define mdbBool_kFalse ((mdb_bool) 0) /* only zero means false */
+
+typedef mdb_u4 mdb_id; // unsigned object identity in a scope
+typedef mdb_id mdb_rid; // unsigned row identity inside scope
+typedef mdb_id mdb_tid; // unsigned table identity inside scope
+typedef mdb_u4 mdb_token; // unsigned token for atomized string
+typedef mdb_token mdb_scope; // token used to id scope for rows
+typedef mdb_token mdb_kind; // token used to id kind for tables
+typedef mdb_token mdb_column; // token used to id columns for rows
+typedef mdb_token mdb_cscode; // token used to id charset names
+typedef mdb_u4 mdb_seed; // unsigned collection change counter
+typedef mdb_u4 mdb_count; // unsigned collection member count
+typedef mdb_u4 mdb_size; // unsigned physical media size
+typedef mdb_u4 mdb_fill; // unsigned logical content size
+typedef mdb_u4 mdb_more; // more available bytes for larger buffer
+
+#define mdbId_kNone ((mdb_id) -1) /* never a valid Mork object ID */
+
+typedef mdb_u4 mdb_percent; // 0..100, with values >100 same as 100
+
+typedef mdb_u1 mdb_priority; // 0..9, for a total of ten different values
+
+// temporary substitute for NS_RESULT, for mdb.h standalone compilation:
+typedef nsresult mdb_err; // equivalent to NS_RESULT
+
+// sequence position is signed; negative is useful to mean "before first":
+typedef mdb_i4 mdb_pos; // signed zero-based ordinal collection position
+
+#define mdbPos_kBeforeFirst ((mdb_pos) -1) /* any negative is before zero */
+
+// order is also signed, so we can use three states for comparison order:
+typedef mdb_i4 mdb_order; // neg:lessthan, zero:equalto, pos:greaterthan
+
+typedef mdb_order (* mdbAny_Order)(const void* inA, const void* inB,
+ const void* inClosure);
+
+// } %%%%% end scalar typedefs %%%%%
+
+// { %%%%% begin C structs %%%%%
+
+#ifndef mdbScopeStringSet_typedef
+typedef struct mdbScopeStringSet mdbScopeStringSet;
+#define mdbScopeStringSet_typedef 1
+#endif
+
+/*| mdbScopeStringSet: a set of null-terminated C strings that enumerate some
+**| names of row scopes, so that row scopes intended for use by an application
+**| can be declared by an app when trying to open or create a database file.
+**| (We use strings and not tokens because we cannot know the tokens for any
+**| particular db without having first opened the db.) The goal is to inform
+**| a db runtime that scopes not appearing in this list can be given relatively
+**| short shrift in runtime representation, with the expectation that other
+**| scopes will not actually be used. However, a db should still be prepared
+**| to handle accessing row scopes not in this list, rather than raising errors.
+**| But it could be quite expensive to access a row scope not on the list.
+**| Note a zero count for the string set means no such string set is being
+**| specified, and that a db should handle all row scopes efficiently.
+**| (It does NOT mean an app plans to use no content whatsoever.)
+|*/
+#ifndef mdbScopeStringSet_struct
+#define mdbScopeStringSet_struct 1
+struct mdbScopeStringSet { // vector of scopes for use in db opening policy
+ // when mScopeStringSet_Count is zero, this means no scope constraints
+ mdb_count mScopeStringSet_Count; // number of strings in vector below
+ const char** mScopeStringSet_Strings; // null-ended ascii scope strings
+};
+#endif /*mdbScopeStringSet_struct*/
+
+#ifndef mdbOpenPolicy_typedef
+typedef struct mdbOpenPolicy mdbOpenPolicy;
+#define mdbOpenPolicy_typedef 1
+#endif
+
+#ifndef mdbOpenPolicy_struct
+#define mdbOpenPolicy_struct 1
+struct mdbOpenPolicy { // policies affecting db usage for ports and stores
+ mdbScopeStringSet mOpenPolicy_ScopePlan; // predeclare scope usage plan
+ mdb_bool mOpenPolicy_MaxLazy; // nonzero: do least work
+ mdb_bool mOpenPolicy_MinMemory; // nonzero: use least memory
+};
+#endif /*mdbOpenPolicy_struct*/
+
+#ifndef mdbTokenSet_typedef
+typedef struct mdbTokenSet mdbTokenSet;
+#define mdbTokenSet_typedef 1
+#endif
+
+#ifndef mdbTokenSet_struct
+#define mdbTokenSet_struct 1
+struct mdbTokenSet { // array for a set of tokens, and actual slots used
+ mdb_count mTokenSet_Count; // number of token slots in the array
+ mdb_fill mTokenSet_Fill; // the subset of count slots actually used
+ mdb_more mTokenSet_More; // more tokens available for bigger array
+ mdb_token* mTokenSet_Tokens; // array of count mdb_token instances
+};
+#endif /*mdbTokenSet_struct*/
+
+#ifndef mdbUsagePolicy_typedef
+typedef struct mdbUsagePolicy mdbUsagePolicy;
+#define mdbUsagePolicy_typedef 1
+#endif
+
+/*| mdbUsagePolicy: another version of mdbOpenPolicy which uses tokens instead
+**| of scope strings, because usage policies can be constructed for use with a
+**| db that is already open, while an open policy must be constructed before a
+**| db has yet been opened.
+|*/
+#ifndef mdbUsagePolicy_struct
+#define mdbUsagePolicy_struct 1
+struct mdbUsagePolicy { // policies affecting db usage for ports and stores
+ mdbTokenSet mUsagePolicy_ScopePlan; // current scope usage plan
+ mdb_bool mUsagePolicy_MaxLazy; // nonzero: do least work
+ mdb_bool mUsagePolicy_MinMemory; // nonzero: use least memory
+};
+#endif /*mdbUsagePolicy_struct*/
+
+#ifndef mdbOid_typedef
+typedef struct mdbOid mdbOid;
+#define mdbOid_typedef 1
+#endif
+
+#ifndef mdbOid_struct
+#define mdbOid_struct 1
+struct mdbOid { // identity of some row or table inside a database
+ mdb_scope mOid_Scope; // scope token for an id's namespace
+ mdb_id mOid_Id; // identity of object inside scope namespace
+};
+#endif /*mdbOid_struct*/
+
+#ifndef mdbRange_typedef
+typedef struct mdbRange mdbRange;
+#define mdbRange_typedef 1
+#endif
+
+#ifndef mdbRange_struct
+#define mdbRange_struct 1
+struct mdbRange { // range of row positions in a table
+ mdb_pos mRange_FirstPos; // position of first row
+ mdb_pos mRange_LastPos; // position of last row
+};
+#endif /*mdbRange_struct*/
+
+#ifndef mdbColumnSet_typedef
+typedef struct mdbColumnSet mdbColumnSet;
+#define mdbColumnSet_typedef 1
+#endif
+
+#ifndef mdbColumnSet_struct
+#define mdbColumnSet_struct 1
+struct mdbColumnSet { // array of column tokens (just the same as mdbTokenSet)
+ mdb_count mColumnSet_Count; // number of columns
+ mdb_column* mColumnSet_Columns; // count mdb_column instances
+};
+#endif /*mdbColumnSet_struct*/
+
+#ifndef mdbYarn_typedef
+typedef struct mdbYarn mdbYarn;
+#define mdbYarn_typedef 1
+#endif
+
+#ifdef MDB_BEGIN_C_LINKAGE_define
+#define MDB_BEGIN_C_LINKAGE_define 1
+#define MDB_BEGIN_C_LINKAGE extern "C" {
+#define MDB_END_C_LINKAGE }
+#endif /*MDB_BEGIN_C_LINKAGE_define*/
+
+/*| mdbYarn_mGrow: an abstract API for growing the size of a mdbYarn
+**| instance. With respect to a specific API that requires a caller
+**| to supply a string (mdbYarn) that a callee fills with content
+**| that might exceed the specified size, mdbYarn_mGrow is a caller-
+**| supplied means of letting a callee attempt to increase the string
+**| size to become large enough to receive all content available.
+**|
+**|| Grow(): a method for requesting that a yarn instance be made
+**| larger in size. Note that such requests need not be honored, and
+**| need not be honored in full if only partial size growth is desired.
+**| (Note that no nsIMdbEnv instance is passed as argument, although one
+**| might be needed in some circumstances. So if an nsIMdbEnv is needed,
+**| a reference to one might be held inside a mdbYarn member slot.)
+**|
+**|| self: a yarn instance to be grown. Presumably this yarn is
+**| the instance which holds the mYarn_Grow method pointer. Yarn
+**| instancesshould only be passed to grow methods which they were
+**| specifically designed to fit, as indicated by the mYarn_Grow slot.
+**|
+**|| inNewSize: the new desired value for slot mYarn_Size in self.
+**| If mYarn_Size is already this big, then nothing should be done.
+**| If inNewSize is larger than seems feasible or desirable to honor,
+**| then any size restriction policy can be used to grow to some size
+**| greater than mYarn_Size. (Grow() might even grow to a size
+**| greater than inNewSize in order to make the increase in size seem
+**| worthwhile, rather than growing in many smaller steps over time.)
+|*/
+typedef void (* mdbYarn_mGrow)(mdbYarn* self, mdb_size inNewSize);
+// mdbYarn_mGrow methods must be declared with C linkage in C++
+
+/*| mdbYarn: a variable length "string" of arbitrary binary bytes,
+**| whose length is mYarn_Fill, inside a buffer mYarn_Buf that has
+**| at most mYarn_Size byte of physical space.
+**|
+**|| mYarn_Buf: a pointer to space containing content. This slot
+**| might never be nil when mYarn_Size is nonzero, but checks for nil
+**| are recommended anyway.
+**| (Implementations of mdbYarn_mGrow methods should take care to
+**| ensure the existence of a replacement before dropping old Bufs.)
+**| Content in Buf can be anything in any format, but the mYarn_Form
+**| implies the actual format by some caller-to-callee convention.
+**| mYarn_Form==0 implies US-ASCII iso-8859-1 Latin1 string content.
+**|
+**|| mYarn_Size: the physical size of Buf in bytes. Note that if one
+**| intends to terminate a string with a null byte, that it must not
+**| be written at or after mYarn_Buf[mYarn_Size] because this is after
+**| the last byte in the physical buffer space. Size can be zero,
+**| which means the string has no content whatsoever; note that when
+**| Size is zero, this is a suitable reason for Buf==nil as well.
+**|
+**|| mYarn_Fill: the logical content in Buf in bytes, where Fill must
+**| never exceed mYarn_Size. Note that yarn strings might not have a
+**| terminating null byte (since they might not even be C strings), but
+**| when they do, such terminating nulls are considered part of content
+**| and therefore Fill will count such null bytes. So an "empty" C
+**| string will have Fill==1, because content includes one null byte.
+**| Fill does not mean "length" when applied to C strings for this
+**| reason. However, clients using yarns to hold C strings can infer
+**| that length is equal to Fill-1 (but should take care to handle the
+**| case where Fill==0). To be paranoid, one can always copy to a
+**| destination with size exceeding Fill, and place a redundant null
+**| byte in the Fill position when this simplifies matters.
+**|
+**|| mYarn_Form: a designation of content format within mYarn_Buf.
+**| The semantics of this slot are the least well defined, since the
+**| actual meaning is context dependent, to the extent that callers
+**| and callees must agree on format encoding conventions when such
+**| are not standardized in many computing contexts. However, in the
+**| context of a specific mdb database, mYarn_Form is a token for an
+**| atomized string in that database that typically names a preferred
+**| mime type charset designation. If and when mdbYarn is used for
+**| other purposes away from the mdb interface, folks can use another
+**| convention system for encoding content formats. However, in all
+**| contexts is it useful to maintain the convention that Form==0
+**| implies Buf contains US-ASCII iso-8859-1 Latin1 string content.
+**|
+**|| mYarn_Grow: either a mdbYarn_mGrow method, or else nil. When
+**| a mdbYarn_mGrow method is provided, this method can be used to
+**| request a yarn buf size increase. A caller who constructs the
+**| original mdbYarn instance decides whether a grow method is necessary
+**| or desirable, and uses only grow methods suitable for the buffering
+**| nature of a specific mdbYarn instance. (For example, Buf might be a
+**| staticly allocated string space which switches to something heap-based
+**| when grown, and subsequent calls to grow the yarn must distinguish the
+**| original static string from heap allocated space, etc.) Note that the
+**| method stored in mYarn_Grow can change, and this might be a common way
+**| to track memory managent changes in policy for mYarn_Buf.
+|*/
+#ifndef mdbYarn_struct
+#define mdbYarn_struct 1
+struct mdbYarn { // buffer with caller space allocation semantics
+ void* mYarn_Buf; // space for holding any binary content
+ mdb_fill mYarn_Fill; // logical content in Buf in bytes
+ mdb_size mYarn_Size; // physical size of Buf in bytes
+ mdb_more mYarn_More; // more available bytes if Buf is bigger
+ mdb_cscode mYarn_Form; // charset format encoding
+ mdbYarn_mGrow mYarn_Grow; // optional method to grow mYarn_Buf
+
+ // Subclasses might add further slots after mYarn_Grow in order to
+ // maintain bookkeeping needs, such as state info about mYarn_Buf.
+};
+#endif /*mdbYarn_struct*/
+
+// } %%%%% end C structs %%%%%
+
+// { %%%%% begin class forward defines %%%%%
+class nsIMdbEnv;
+class nsIMdbObject;
+class nsIMdbErrorHook;
+class nsIMdbCompare;
+class nsIMdbThumb;
+class nsIMdbFactory;
+class nsIMdbFile;
+class nsIMdbPort;
+class nsIMdbStore;
+class nsIMdbCursor;
+class nsIMdbPortTableCursor;
+class nsIMdbCollection;
+class nsIMdbTable;
+class nsIMdbTableRowCursor;
+class nsIMdbRow;
+class nsIMdbRowCellCursor;
+class nsIMdbBlob;
+class nsIMdbCell;
+class nsIMdbSorting;
+// } %%%%% end class forward defines %%%%%
+
+
+// { %%%%% begin C++ abstract class interfaces %%%%%
+
+/*| nsIMdbObject: base class for all message db class interfaces
+**|
+**|| factory: all nsIMdbObjects from the same code suite have the same factory
+**|
+**|| refcounting: both strong and weak references, to ensure strong refs are
+**| acyclic, while weak refs can cause cycles. CloseMdbObject() is
+**| called when (strong) use counts hit zero, but clients can call this close
+**| method early for some reason, if absolutely necessary even though it will
+**| thwart the other uses of the same object. Note that implementations must
+**| cope with close methods being called arbitrary numbers of times. The COM
+**| calls to AddRef() and release ref map directly to strong use ref calls,
+**| but the total ref count for COM objects is the sum of weak & strong refs.
+|*/
+
+#define NS_IMDBOBJECT_IID_STR "5533ea4b-14c3-4bef-ac60-22f9e9a49084"
+
+#define NS_IMDBOBJECT_IID \
+{0x5533ea4b, 0x14c3, 0x4bef, \
+{ 0xac, 0x60, 0x22, 0xf9, 0xe9, 0xa4, 0x90, 0x84}}
+
+class nsIMdbObject : public nsISupports { // msg db base class
+public:
+
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBOBJECT_IID)
+// { ===== begin nsIMdbObject methods =====
+
+ // { ----- begin attribute methods -----
+ NS_IMETHOD IsFrozenMdbObject(nsIMdbEnv* ev, mdb_bool* outIsReadonly) = 0;
+ // same as nsIMdbPort::GetIsPortReadonly() when this object is inside a port.
+ // } ----- end attribute methods -----
+
+ // { ----- begin factory methods -----
+ NS_IMETHOD GetMdbFactory(nsIMdbEnv* ev, nsIMdbFactory** acqFactory) = 0;
+ // } ----- end factory methods -----
+
+ // { ----- begin ref counting for well-behaved cyclic graphs -----
+ NS_IMETHOD GetWeakRefCount(nsIMdbEnv* ev, // weak refs
+ mdb_count* outCount) = 0;
+ NS_IMETHOD GetStrongRefCount(nsIMdbEnv* ev, // strong refs
+ mdb_count* outCount) = 0;
+
+ NS_IMETHOD AddWeakRef(nsIMdbEnv* ev) = 0;
+ NS_IMETHOD AddStrongRef(nsIMdbEnv* ev) = 0;
+
+ NS_IMETHOD CutWeakRef(nsIMdbEnv* ev) = 0;
+ NS_IMETHOD CutStrongRef(nsIMdbEnv* ev) = 0;
+
+ NS_IMETHOD CloseMdbObject(nsIMdbEnv* ev) = 0; // called at strong refs zero
+ NS_IMETHOD IsOpenMdbObject(nsIMdbEnv* ev, mdb_bool* outOpen) = 0;
+ // } ----- end ref counting -----
+
+// } ===== end nsIMdbObject methods =====
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbObject, NS_IMDBOBJECT_IID)
+
+/*| nsIMdbErrorHook: a base class for clients of this API to subclass, in order
+**| to provide a callback installable in nsIMdbEnv for error notifications. If
+**| apps that subclass nsIMdbErrorHook wish to maintain a reference to the env
+**| that contains the hook, then this should be a weak ref to avoid cycles.
+**|
+**|| OnError: when nsIMdbEnv has an error condition that causes the total count
+**| of errors to increase, then nsIMdbEnv should call OnError() to report the
+**| error in some fashion when an instance of nsIMdbErrorHook is installed. The
+**| variety of string flavors is currently due to the uncertainty here in the
+**| nsIMdbBlob and nsIMdbCell interfaces. (Note that overloading by using the
+**| same method name is not necessary here, and potentially less clear.)
+|*/
+class nsIMdbErrorHook : public nsISupports{ // env callback handler to report errors
+public:
+
+// { ===== begin error methods =====
+ NS_IMETHOD OnErrorString(nsIMdbEnv* ev, const char* inAscii) = 0;
+ NS_IMETHOD OnErrorYarn(nsIMdbEnv* ev, const mdbYarn* inYarn) = 0;
+// } ===== end error methods =====
+
+// { ===== begin warning methods =====
+ NS_IMETHOD OnWarningString(nsIMdbEnv* ev, const char* inAscii) = 0;
+ NS_IMETHOD OnWarningYarn(nsIMdbEnv* ev, const mdbYarn* inYarn) = 0;
+// } ===== end warning methods =====
+
+// { ===== begin abort hint methods =====
+ NS_IMETHOD OnAbortHintString(nsIMdbEnv* ev, const char* inAscii) = 0;
+ NS_IMETHOD OnAbortHintYarn(nsIMdbEnv* ev, const mdbYarn* inYarn) = 0;
+// } ===== end abort hint methods =====
+};
+
+/*| nsIMdbCompare: a caller-supplied yarn comparison interface. When two yarns
+**| are compared to each other with Order(), this method should return a signed
+**| long integer denoting relation R between the 1st and 2nd yarn instances
+**| such that (First R Second), where negative is less than, zero is equal to,
+**| and positive is greater than. Note that both yarns are readonly, and the
+**| Order() method should make no attempt to modify the yarn content.
+|*/
+class nsIMdbCompare { // caller-supplied yarn comparison
+public:
+
+// { ===== begin nsIMdbCompare methods =====
+ NS_IMETHOD Order(nsIMdbEnv* ev, // compare first to second yarn
+ const mdbYarn* inFirst, // first yarn in comparison
+ const mdbYarn* inSecond, // second yarn in comparison
+ mdb_order* outOrder) = 0; // negative="<", zero="=", positive=">"
+
+ NS_IMETHOD AddStrongRef(nsIMdbEnv* ev) = 0; // does nothing
+ NS_IMETHOD CutStrongRef(nsIMdbEnv* ev) = 0; // does nothing
+// } ===== end nsIMdbCompare methods =====
+
+};
+
+/*| nsIMdbHeap: abstract memory allocation interface.
+**|
+**|| Alloc: return a block at least inSize bytes in size with alignment
+**| suitable for any native type (such as long integers). When no such
+**| block can be allocated, failure is indicated by a null address in
+**| addition to reporting an error in the environment.
+**|
+**|| Free: deallocate a block allocated or resized earlier by the same
+**| heap instance. If the inBlock parameter is nil, the heap should do
+**| nothing (and crashing is strongly discouraged).
+|*/
+class nsIMdbHeap { // caller-supplied memory management interface
+public:
+// { ===== begin nsIMdbHeap methods =====
+ NS_IMETHOD Alloc(nsIMdbEnv* ev, // allocate a piece of memory
+ mdb_size inSize, // requested byte size of new memory block
+ void** outBlock) = 0; // memory block of inSize bytes, or nil
+
+ NS_IMETHOD Free(nsIMdbEnv* ev, // free block from Alloc or Resize()
+ void* ioBlock) = 0; // block to be destroyed/deallocated
+
+ NS_IMETHOD HeapAddStrongRef(nsIMdbEnv* ev) = 0;
+ NS_IMETHOD HeapCutStrongRef(nsIMdbEnv* ev) = 0;
+
+// } ===== end nsIMdbHeap methods =====
+};
+
+/*| nsIMdbCPlusHeap: Alloc() with global ::new(), Free() with global ::delete().
+**| Resize() is done by ::new() followed by ::delete().
+|*/
+class nsIMdbCPlusHeap { // caller-supplied memory management interface
+public:
+// { ===== begin nsIMdbHeap methods =====
+ NS_IMETHOD Alloc(nsIMdbEnv* ev, // allocate a piece of memory
+ mdb_size inSize, // requested size of new memory block
+ void** outBlock); // memory block of inSize bytes, or nil
+
+ NS_IMETHOD Free(nsIMdbEnv* ev, // free block allocated earlier by Alloc()
+ void* inBlock);
+
+ NS_IMETHOD HeapAddStrongRef(nsIMdbEnv* ev);
+ NS_IMETHOD HeapCutStrongRef(nsIMdbEnv* ev);
+// } ===== end nsIMdbHeap methods =====
+};
+
+/*| nsIMdbThumb:
+|*/
+
+
+#define NS_IMDBTHUMB_IID_STR "6d3ad7c1-a809-4e74-8577-49fa9a4562fa"
+
+#define NS_IMDBTHUMB_IID \
+{0x6d3ad7c1, 0xa809, 0x4e74, \
+{ 0x85, 0x77, 0x49, 0xfa, 0x9a, 0x45, 0x62, 0xfa}}
+
+
+class nsIMdbThumb : public nsISupports { // closure for repeating incremental method
+public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBTHUMB_IID)
+
+// { ===== begin nsIMdbThumb methods =====
+ NS_IMETHOD GetProgress(nsIMdbEnv* ev,
+ mdb_count* outTotal, // total somethings to do in operation
+ mdb_count* outCurrent, // subportion of total completed so far
+ mdb_bool* outDone, // is operation finished?
+ mdb_bool* outBroken // is operation irreparably dead and broken?
+ ) = 0;
+
+ NS_IMETHOD DoMore(nsIMdbEnv* ev,
+ mdb_count* outTotal, // total somethings to do in operation
+ mdb_count* outCurrent, // subportion of total completed so far
+ mdb_bool* outDone, // is operation finished?
+ mdb_bool* outBroken // is operation irreparably dead and broken?
+ ) = 0;
+
+ NS_IMETHOD CancelAndBreakThumb( // cancel pending operation
+ nsIMdbEnv* ev) = 0;
+// } ===== end nsIMdbThumb methods =====
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbThumb, NS_IMDBTHUMB_IID)
+
+/*| nsIMdbEnv: a context parameter used when calling most abstract db methods.
+**| The main purpose of such an object is to permit a database implementation
+**| to avoid the use of globals to share information between various parts of
+**| the implementation behind the abstract db interface. An environment acts
+**| like a session object for a given calling thread, and callers should use
+**| at least one different nsIMdbEnv instance for each thread calling the API.
+**| While the database implementation might not be threaded, it is highly
+**| desirable that the db be thread-safe if calling threads use distinct
+**| instances of nsIMdbEnv. Callers can stop at one nsIMdbEnv per thread, or they
+**| might decide to make on nsIMdbEnv instance for every nsIMdbPort opened, so that
+**| error information is segregated by database instance. Callers create
+**| instances of nsIMdbEnv by calling the MakeEnv() method in nsIMdbFactory.
+**|
+**|| tracing: an environment might support some kind of tracing, and this
+**| boolean attribute permits such activity to be enabled or disabled.
+**|
+**|| errors: when a call to the abstract db interface returns, a caller might
+**| check the number of outstanding errors to see whether the operation did
+**| actually succeed. Each nsIMdbEnv should have all its errors cleared by a
+**| call to ClearErrors() before making each call to the abstract db API,
+**| because outstanding errors might disable further database actions. (This
+**| is not done inside the db interface, because the db cannot in general know
+**| when a call originates from inside or outside -- only the app knows this.)
+**|
+**|| error hook: callers can install an instance of nsIMdbErrorHook to receive
+**| error notifications whenever the error count increases. The hook can
+**| be uninstalled by passing a null pointer.
+**|
+|*/
+
+#define NS_IMDBENV_IID_STR "a765e46b-efb6-41e6-b75b-c5d6bd710594"
+
+#define NS_IMDBENV_IID \
+{0xa765e46b, 0xefb6, 0x41e6, \
+{ 0xb7, 0x5b, 0xc5, 0xd6, 0xbd, 0x71, 0x05, 0x94}}
+
+class nsIMdbEnv : public nsISupports { // db specific context parameter
+public:
+
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBENV_IID)
+// { ===== begin nsIMdbEnv methods =====
+
+ // { ----- begin attribute methods -----
+ NS_IMETHOD GetErrorCount(mdb_count* outCount,
+ mdb_bool* outShouldAbort) = 0;
+ NS_IMETHOD GetWarningCount(mdb_count* outCount,
+ mdb_bool* outShouldAbort) = 0;
+
+ NS_IMETHOD GetEnvBeVerbose(mdb_bool* outBeVerbose) = 0;
+ NS_IMETHOD SetEnvBeVerbose(mdb_bool inBeVerbose) = 0;
+
+ NS_IMETHOD GetDoTrace(mdb_bool* outDoTrace) = 0;
+ NS_IMETHOD SetDoTrace(mdb_bool inDoTrace) = 0;
+
+ NS_IMETHOD GetAutoClear(mdb_bool* outAutoClear) = 0;
+ NS_IMETHOD SetAutoClear(mdb_bool inAutoClear) = 0;
+
+ NS_IMETHOD GetErrorHook(nsIMdbErrorHook** acqErrorHook) = 0;
+ NS_IMETHOD SetErrorHook(
+ nsIMdbErrorHook* ioErrorHook) = 0; // becomes referenced
+
+ NS_IMETHOD GetHeap(nsIMdbHeap** acqHeap) = 0;
+ NS_IMETHOD SetHeap(
+ nsIMdbHeap* ioHeap) = 0; // becomes referenced
+ // } ----- end attribute methods -----
+
+ NS_IMETHOD ClearErrors() = 0; // clear errors beore re-entering db API
+ NS_IMETHOD ClearWarnings() = 0; // clear warnings
+ NS_IMETHOD ClearErrorsAndWarnings() = 0; // clear both errors & warnings
+// } ===== end nsIMdbEnv methods =====
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbEnv, NS_IMDBENV_IID)
+
+/*| nsIMdbFactory: the main entry points to the abstract db interface. A DLL
+**| that supports this mdb interface need only have a single exported method
+**| that will return an instance of nsIMdbFactory, so that further methods in
+**| the suite can be accessed from objects returned by nsIMdbFactory methods.
+**|
+**|| mdbYarn: note all nsIMdbFactory subclasses must guarantee null
+**| termination of all strings written into mdbYarn instances, as long as
+**| mYarn_Size and mYarn_Buf are nonzero. Even truncated string values must
+**| be null terminated. This is more strict behavior than mdbYarn requires,
+**| but it is part of the nsIMdbFactory interface.
+**|
+**|| envs: an environment instance is required as per-thread context for
+**| most of the db method calls, so nsIMdbFactory creates such instances.
+**|
+**|| rows: callers must be able to create row instances that are independent
+**| of storage space that is part of the db content graph. Many interfaces
+**| for data exchange have strictly copy semantics, so that a row instance
+**| has no specific identity inside the db content model, and the text in
+**| cells are an independenty copy of unexposed content inside the db model.
+**| Callers are expected to maintain one or more row instances as a buffer
+**| for staging cell content copied into or out of a table inside the db.
+**| Callers are urged to use an instance of nsIMdbRow created by the nsIMdbFactory
+**| code suite, because reading and writing might be much more efficient than
+**| when using a hand-rolled nsIMdbRow subclass with no relation to the suite.
+**|
+**|| ports: a port is a readonly interface to a specific database file. Most
+**| of the methods to access a db file are suitable for a readonly interface,
+**| so a port is the basic minimum for accessing content. This makes it
+**| possible to read other external formats for import purposes, without
+**| needing the code or competence necessary to write every such format. So
+**| we can write generic import code just once, as long as every format can
+**| show a face based on nsIMdbPort. (However, same suite import can be faster.)
+**| Given a file name and the first 512 bytes of a file, a factory can say if
+**| a port can be opened by this factory. Presumably an app maintains chains
+**| of factories for different suites, and asks each in turn about opening a
+**| a prospective file for reading (as a port) or writing (as a store). I'm
+**| not ready to tackle issues of format fidelity and factory chain ordering.
+**|
+**|| stores: a store is a mutable interface to a specific database file, and
+**| includes the port interface plus any methods particular to writing, which
+**| are few in number. Presumably the set of files that can be opened as
+**| stores is a subset of the set of files that can be opened as ports. A
+**| new store can be created with CreateNewFileStore() by supplying a new
+**| file name which does not yet exist (callers are always responsible for
+**| destroying any existing files before calling this method).
+|*/
+
+#define NS_IMDBFACTORY_IID_STR "2b80395c-b91e-4990-b1a7-023e99ab14e9"
+
+#define NS_IMDBFACTORY_IID \
+{0xf04aa4ab, 0x1fe, 0x4115, \
+{ 0xa4, 0xa5, 0x68, 0x19, 0xdf, 0xf1, 0x10, 0x3d}}
+
+
+class nsIMdbFactory : public nsISupports { // suite entry points
+public:
+
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBFACTORY_IID)
+// { ===== begin nsIMdbFactory methods =====
+
+ // { ----- begin file methods -----
+ NS_IMETHOD OpenOldFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
+ const char* inFilePath,
+ mdb_bool inFrozen, nsIMdbFile** acqFile) = 0;
+ // Choose some subclass of nsIMdbFile 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.
+
+ NS_IMETHOD CreateNewFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
+ const char* inFilePath,
+ nsIMdbFile** acqFile) = 0;
+ // Choose some subclass of nsIMdbFile 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.
+ // } ----- end file methods -----
+
+ // { ----- begin env methods -----
+ NS_IMETHOD MakeEnv(nsIMdbHeap* ioHeap, nsIMdbEnv** acqEnv) = 0; // acquire new env
+ // ioHeap can be nil, causing a MakeHeap() style heap instance to be used
+ // } ----- end env methods -----
+
+ // { ----- begin heap methods -----
+ NS_IMETHOD MakeHeap(nsIMdbEnv* ev, nsIMdbHeap** acqHeap) = 0; // acquire new heap
+ // } ----- end heap methods -----
+
+ // { ----- begin compare methods -----
+ NS_IMETHOD MakeCompare(nsIMdbEnv* ev, nsIMdbCompare** acqCompare) = 0; // ASCII
+ // } ----- end compare methods -----
+
+ // { ----- begin row methods -----
+ NS_IMETHOD MakeRow(nsIMdbEnv* ev, nsIMdbHeap* ioHeap, nsIMdbRow** acqRow) = 0; // new row
+ // ioHeap can be nil, causing the heap associated with ev to be used
+ // } ----- end row methods -----
+
+ // { ----- begin port methods -----
+ NS_IMETHOD CanOpenFilePort(
+ nsIMdbEnv* ev, // context
+ // const char* inFilePath, // the file to investigate
+ // const mdbYarn* inFirst512Bytes,
+ nsIMdbFile* ioFile, // db abstract file interface
+ mdb_bool* outCanOpen, // whether OpenFilePort() might succeed
+ mdbYarn* outFormatVersion) = 0; // informal file format description
+
+ NS_IMETHOD OpenFilePort(
+ nsIMdbEnv* ev, // context
+ nsIMdbHeap* ioHeap, // can be nil to cause ev's heap attribute to be used
+ // const char* inFilePath, // the file to open for readonly import
+ nsIMdbFile* ioFile, // db abstract file interface
+ const mdbOpenPolicy* inOpenPolicy, // runtime policies for using db
+ nsIMdbThumb** acqThumb) = 0; // acquire thumb for incremental port open
+ // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+ // then call nsIMdbFactory::ThumbToOpenPort() to get the port instance.
+
+ NS_IMETHOD ThumbToOpenPort( // redeeming a completed thumb from OpenFilePort()
+ nsIMdbEnv* ev, // context
+ nsIMdbThumb* ioThumb, // thumb from OpenFilePort() with done status
+ nsIMdbPort** acqPort) = 0; // acquire new port object
+ // } ----- end port methods -----
+
+ // { ----- begin store methods -----
+ NS_IMETHOD CanOpenFileStore(
+ nsIMdbEnv* ev, // context
+ // const char* inFilePath, // the file to investigate
+ // const mdbYarn* inFirst512Bytes,
+ nsIMdbFile* ioFile, // db abstract file interface
+ mdb_bool* outCanOpenAsStore, // whether OpenFileStore() might succeed
+ mdb_bool* outCanOpenAsPort, // whether OpenFilePort() might succeed
+ mdbYarn* outFormatVersion) = 0; // informal file format description
+
+ NS_IMETHOD OpenFileStore( // open an existing database
+ nsIMdbEnv* ev, // context
+ nsIMdbHeap* ioHeap, // can be nil to cause ev's heap attribute to be used
+ // const char* inFilePath, // the file to open for general db usage
+ nsIMdbFile* ioFile, // db abstract file interface
+ const mdbOpenPolicy* inOpenPolicy, // runtime policies for using db
+ nsIMdbThumb** acqThumb) = 0; // acquire thumb for incremental store open
+ // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+ // then call nsIMdbFactory::ThumbToOpenStore() to get the store instance.
+
+ NS_IMETHOD
+ ThumbToOpenStore( // redeem completed thumb from OpenFileStore()
+ nsIMdbEnv* ev, // context
+ nsIMdbThumb* ioThumb, // thumb from OpenFileStore() with done status
+ nsIMdbStore** acqStore) = 0; // acquire new db store object
+
+ NS_IMETHOD CreateNewFileStore( // create a new db with minimal content
+ nsIMdbEnv* ev, // context
+ nsIMdbHeap* ioHeap, // can be nil to cause ev's heap attribute to be used
+ // const char* inFilePath, // name of file which should not yet exist
+ nsIMdbFile* ioFile, // db abstract file interface
+ const mdbOpenPolicy* inOpenPolicy, // runtime policies for using db
+ nsIMdbStore** acqStore) = 0; // acquire new db store object
+ // } ----- end store methods -----
+
+// } ===== end nsIMdbFactory methods =====
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbFactory, NS_IMDBFACTORY_IID)
+
+extern "C" nsIMdbFactory* MakeMdbFactory();
+
+/*| nsIMdbFile: abstract file interface resembling the original morkFile
+**| abstract interface (which was in turn modeled on the file interface
+**| from public domain IronDoc). The design of this file interface is
+**| complicated by the fact that some DB's will not find this interface
+**| adequate for all runtime requirements (even though this file API is
+**| enough to implement text-based DB's like Mork). For this reason,
+**| more methods have been added to let a DB library force the file to
+**| become closed so the DB can reopen the file in some other manner.
+**| Folks are encouraged to suggest ways to tune this interface to suit
+**| DB's that cannot manage to pull their maneuvers even given this API.
+**|
+**|| Tell: get the current i/o position in file
+**|
+**|| Seek: change the current i/o position in file
+**|
+**|| Eof: return file's total length in bytes
+**|
+**|| Read: input inSize bytes into outBuf, returning actual transfer size
+**|
+**|| Get: read starting at specific file offset (e.g. Seek(); Read();)
+**|
+**|| Write: output inSize bytes from inBuf, returning actual transfer size
+**|
+**|| Put: write starting at specific file offset (e.g. Seek(); Write();)
+**|
+**|| Flush: if written bytes are buffered, push them to final destination
+**|
+**|| Path: get file path in some string representation. This is intended
+**| either to support the display of file name in a user presentation, or
+**| to support the closing and reopening of the file when the DB needs more
+**| exotic file access than is presented by the nsIMdbFile interface.
+**|
+**|| Steal: tell this file to close any associated i/o stream in the file
+**| system, because the file ioThief intends to reopen the file in order
+**| to provide the MDB implementation with more exotic file access than is
+**| offered by the nsIMdbFile alone. Presumably the thief knows enough
+**| from Path() in order to know which file to reopen. If Steal() is
+**| successful, this file should probably delegate all future calls to
+**| the nsIMdbFile interface down to the thief files, so that even after
+**| the file has been stolen, it can still be read, written, or forcibly
+**| closed (by a call to CloseMdbObject()).
+**|
+**|| Thief: acquire and return thief passed to an earlier call to Steal().
+|*/
+
+#define NS_IMDBFILE_IID_STR "f04aa4ab-1fe7-4115-a4a5-6819dff1103d"
+
+#define NS_IMDBFILE_IID \
+{0xf04aa4ab, 0x1fe, 0x4115, \
+{ 0xa4, 0xa5, 0x68, 0x19, 0xdf, 0xf1, 0x10, 0x3d}}
+
+class nsIMdbFile : public nsISupports { // minimal file interface
+public:
+
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBFILE_IID)
+// { ===== begin nsIMdbFile methods =====
+
+ // { ----- begin pos methods -----
+ NS_IMETHOD Tell(nsIMdbEnv* ev, mdb_pos* outPos) const = 0;
+ NS_IMETHOD Seek(nsIMdbEnv* ev, mdb_pos inPos, mdb_pos *outPos) = 0;
+ NS_IMETHOD Eof(nsIMdbEnv* ev, mdb_pos* outPos) = 0;
+ // } ----- end pos methods -----
+
+ // { ----- begin read methods -----
+ NS_IMETHOD Read(nsIMdbEnv* ev, void* outBuf, mdb_size inSize,
+ mdb_size* outActualSize) = 0;
+ NS_IMETHOD Get(nsIMdbEnv* ev, void* outBuf, mdb_size inSize,
+ mdb_pos inPos, mdb_size* outActualSize) = 0;
+ // } ----- end read methods -----
+
+ // { ----- begin write methods -----
+ NS_IMETHOD Write(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
+ mdb_size* outActualSize) = 0;
+ NS_IMETHOD Put(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
+ mdb_pos inPos, mdb_size* outActualSize) = 0;
+ NS_IMETHOD Flush(nsIMdbEnv* ev) = 0;
+ // } ----- end attribute methods -----
+
+ // { ----- begin path methods -----
+ NS_IMETHOD Path(nsIMdbEnv* ev, mdbYarn* outFilePath) = 0;
+ // } ----- end path methods -----
+
+ // { ----- begin replacement methods -----
+ NS_IMETHOD Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief) = 0;
+ NS_IMETHOD Thief(nsIMdbEnv* ev, nsIMdbFile** acqThief) = 0;
+ // } ----- end replacement methods -----
+
+ // { ----- begin versioning methods -----
+ NS_IMETHOD BecomeTrunk(nsIMdbEnv* ev) = 0;
+ // 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.
+ // This default implementation of BecomeTrunk() does nothing, and this
+ // is appropriate behavior for files which are not branches, and is
+ // also the right behavior for files returned from AcquireBud() which are
+ // in fact the original file that has been truncated down to zero length.
+
+ NS_IMETHOD AcquireBud(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
+ nsIMdbFile** acqBud) = 0; // acquired file for new version of content
+ // 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.
+ // } ----- end versioning methods -----
+
+// } ===== end nsIMdbFile methods =====
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbFile, NS_IMDBFILE_IID)
+
+/*| nsIMdbPort: a readonly interface to a specific database file. The mutable
+**| nsIMdbStore interface is a subclass that includes writing behavior, but
+**| most of the needed db methods appear in the readonly nsIMdbPort interface.
+**|
+**|| mdbYarn: note all nsIMdbPort and nsIMdbStore subclasses must guarantee null
+**| termination of all strings written into mdbYarn instances, as long as
+**| mYarn_Size and mYarn_Buf are nonzero. Even truncated string values must
+**| be null terminated. This is more strict behavior than mdbYarn requires,
+**| but it is part of the nsIMdbPort and nsIMdbStore interface.
+**|
+**|| attributes: methods are provided to distinguish a readonly port from a
+**| mutable store, and whether a mutable store actually has any dirty content.
+**|
+**|| filepath: the file path used to open the port from the nsIMdbFactory can be
+**| queried and discovered by GetPortFilePath(), which includes format info.
+**|
+**|| export: a port can write itself in other formats, with perhaps a typical
+**| emphasis on text interchange formats used by other systems. A port can be
+**| queried to determine its preferred export interchange format, and a port
+**| can be queried to see whether a specific export format is supported. And
+**| actually exporting a port requires a new destination file name and format.
+**|
+**|| tokens: a port supports queries about atomized strings to map tokens to
+**| strings or strings to token integers. (All atomized strings must be in
+**| US-ASCII iso-8859-1 Latin1 charset encoding.) When a port is actually a
+**| mutable store and a string has not yet been atomized, then StringToToken()
+**| will actually do so and modify the store. The QueryToken() method will not
+**| atomize a string if it has not already been atomized yet, even in stores.
+**|
+**|| tables: other than string tokens, all port content is presented through
+**| tables, which are ordered collections of rows. Tables are identified by
+**| row scope and table kind, which might or might not be unique in a port,
+**| depending on app convention. When tables are effectively unique, then
+**| queries for specific scope and kind pairs will find those tables. To see
+**| all tables that match specific row scope and table kind patterns, even in
+**| the presence of duplicates, every port supports a GetPortTableCursor()
+**| method that returns an iterator over all matching tables. Table kind is
+**| considered scoped inside row scope, so passing a zero for table kind will
+**| find all table kinds for some nonzero row scope. Passing a zero for row
+**| scope will iterate over all tables in the port, in some undefined order.
+**| (A new table can be added to a port using nsIMdbStore::NewTable(), even when
+**| the requested scope and kind combination is already used by other tables.)
+**|
+**|| memory: callers can request that a database use less memory footprint in
+**| several flavors, from an inconsequential idle flavor to a rather drastic
+**| panic flavor. Callers might perform an idle purge very frequently if desired
+**| with very little cost, since only normally scheduled memory management will
+**| be conducted, such as freeing resources for objects scheduled to be dropped.
+**| Callers should perform session memory purges infrequently because they might
+**| involve costly scanning of data structures to removed cached content, and
+**| session purges are recommended only when a caller experiences memory crunch.
+**| Callers should only rarely perform a panic purge, in response to dire memory
+**| straits, since this is likely to make db operations much more expensive
+**| than they would be otherwise. A panic purge asks a database to free as much
+**| memory as possible while staying effective and operational, because a caller
+**| thinks application failure might otherwise occur. (Apps might better close
+**| an open db, so panic purges only make sense when a db is urgently needed.)
+|*/
+class nsIMdbPort : public nsISupports {
+public:
+
+// { ===== begin nsIMdbPort methods =====
+
+ // { ----- begin attribute methods -----
+ NS_IMETHOD GetIsPortReadonly(nsIMdbEnv* ev, mdb_bool* outBool) = 0;
+ NS_IMETHOD GetIsStore(nsIMdbEnv* ev, mdb_bool* outBool) = 0;
+ NS_IMETHOD GetIsStoreAndDirty(nsIMdbEnv* ev, mdb_bool* outBool) = 0;
+
+ NS_IMETHOD GetUsagePolicy(nsIMdbEnv* ev,
+ mdbUsagePolicy* ioUsagePolicy) = 0;
+
+ NS_IMETHOD SetUsagePolicy(nsIMdbEnv* ev,
+ const mdbUsagePolicy* inUsagePolicy) = 0;
+ // } ----- end attribute methods -----
+
+ // { ----- begin memory policy methods -----
+ NS_IMETHOD IdleMemoryPurge( // do memory management already scheduled
+ nsIMdbEnv* ev, // context
+ mdb_size* outEstimatedBytesFreed) = 0; // approximate bytes actually freed
+
+ NS_IMETHOD SessionMemoryPurge( // request specific footprint decrease
+ nsIMdbEnv* ev, // context
+ mdb_size inDesiredBytesFreed, // approximate number of bytes wanted
+ mdb_size* outEstimatedBytesFreed) = 0; // approximate bytes actually freed
+
+ NS_IMETHOD PanicMemoryPurge( // desperately free all possible memory
+ nsIMdbEnv* ev, // context
+ mdb_size* outEstimatedBytesFreed) = 0; // approximate bytes actually freed
+ // } ----- end memory policy methods -----
+
+ // { ----- begin filepath methods -----
+ NS_IMETHOD GetPortFilePath(
+ nsIMdbEnv* ev, // context
+ mdbYarn* outFilePath, // name of file holding port content
+ mdbYarn* outFormatVersion) = 0; // file format description
+
+ NS_IMETHOD GetPortFile(
+ nsIMdbEnv* ev, // context
+ nsIMdbFile** acqFile) = 0; // acquire file used by port or store
+ // } ----- end filepath methods -----
+
+ // { ----- begin export methods -----
+ NS_IMETHOD BestExportFormat( // determine preferred export format
+ nsIMdbEnv* ev, // context
+ mdbYarn* outFormatVersion) = 0; // file format description
+
+ // some tentative suggested import/export formats
+ // "ns:msg:db:port:format:ldif:ns4.0:passthrough" // necessary
+ // "ns:msg:db:port:format:ldif:ns4.5:utf8" // necessary
+ // "ns:msg:db:port:format:ldif:ns4.5:tabbed"
+ // "ns:msg:db:port:format:ldif:ns4.5:binary" // necessary
+ // "ns:msg:db:port:format:html:ns3.0:addressbook" // necessary
+ // "ns:msg:db:port:format:html:display:verbose"
+ // "ns:msg:db:port:format:html:display:concise"
+ // "ns:msg:db:port:format:mork:zany:verbose" // necessary
+ // "ns:msg:db:port:format:mork:zany:atomized" // necessary
+ // "ns:msg:db:port:format:rdf:xml"
+ // "ns:msg:db:port:format:xml:mork"
+ // "ns:msg:db:port:format:xml:display:verbose"
+ // "ns:msg:db:port:format:xml:display:concise"
+ // "ns:msg:db:port:format:xml:print:verbose" // recommended
+ // "ns:msg:db:port:format:xml:print:concise"
+
+ NS_IMETHOD
+ CanExportToFormat( // can export content in given specific format?
+ nsIMdbEnv* ev, // context
+ const char* inFormatVersion, // file format description
+ mdb_bool* outCanExport) = 0; // whether ExportSource() might succeed
+
+ NS_IMETHOD ExportToFormat( // export content in given specific format
+ nsIMdbEnv* ev, // context
+ // const char* inFilePath, // the file to receive exported content
+ nsIMdbFile* ioFile, // destination abstract file interface
+ const char* inFormatVersion, // file format description
+ nsIMdbThumb** acqThumb) = 0; // acquire thumb for incremental export
+ // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+ // then the export will be finished.
+
+ // } ----- end export methods -----
+
+ // { ----- begin token methods -----
+ NS_IMETHOD TokenToString( // return a string name for an integer token
+ nsIMdbEnv* ev, // context
+ mdb_token inToken, // token for inTokenName inside this port
+ mdbYarn* outTokenName) = 0; // the type of table to access
+
+ NS_IMETHOD StringToToken( // return an integer token for scope name
+ nsIMdbEnv* ev, // context
+ const char* inTokenName, // Latin1 string to tokenize if possible
+ mdb_token* outToken) = 0; // token for inTokenName inside this port
+
+ // String token zero is never used and never supported. If the port
+ // is a mutable store, then StringToToken() to create a new
+ // association of inTokenName with a new integer token if possible.
+ // But a readonly port will return zero for an unknown scope name.
+
+ NS_IMETHOD QueryToken( // like StringToToken(), but without adding
+ nsIMdbEnv* ev, // context
+ const char* inTokenName, // Latin1 string to tokenize if possible
+ mdb_token* outToken) = 0; // token for inTokenName inside this port
+
+ // QueryToken() will return a string token if one already exists,
+ // but unlike StringToToken(), will not assign a new token if not
+ // already in use.
+
+ // } ----- end token methods -----
+
+ // { ----- begin row methods -----
+ NS_IMETHOD HasRow( // contains a row with the specified oid?
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid, // hypothetical row oid
+ mdb_bool* outHasRow) = 0; // whether GetRow() might succeed
+
+ NS_IMETHOD GetRowRefCount( // get number of tables that contain a row
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid, // hypothetical row oid
+ mdb_count* outRefCount) = 0; // number of tables containing inRowKey
+
+ NS_IMETHOD GetRow( // access one row with specific oid
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid, // hypothetical row oid
+ nsIMdbRow** acqRow) = 0; // acquire specific row (or null)
+
+ // NS_IMETHOD
+ // GetPortRowCursor( // get cursor for all rows in specific scope
+ // nsIMdbEnv* ev, // context
+ // mdb_scope inRowScope, // row scope for row ids
+ // nsIMdbPortRowCursor** acqCursor) = 0; // all such rows in the port
+
+ NS_IMETHOD FindRow(nsIMdbEnv* ev, // search for row with matching cell
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_column inColumn, // the column to search (and maintain an index)
+ const mdbYarn* inTargetCellValue, // cell value for which to search
+ mdbOid* outRowOid, // out row oid on match (or {0,-1} for no match)
+ nsIMdbRow** acqRow) = 0; // acquire matching row (or nil for no match)
+ // can be null if you only want the oid
+ // FindRow() searches for one row that has a cell in column inColumn with
+ // a contained value with the same form (i.e. charset) and is byte-wise
+ // identical to the blob described by yarn inTargetCellValue. Both content
+ // and form of the yarn must be an exact match to find a matching row.
+ //
+ // (In other words, both a yarn's blob bytes and form are significant. The
+ // form is not expected to vary in columns used for identity anyway. This
+ // is intended to make the cost of FindRow() cheaper for MDB implementors,
+ // since any cell value atomization performed internally must necessarily
+ // make yarn form significant in order to avoid data loss in atomization.)
+ //
+ // FindRow() can lazily create an index on attribute inColumn for all rows
+ // with that attribute in row space scope inRowScope, so that subsequent
+ // calls to FindRow() will perform faster. Such an index might or might
+ // not be persistent (but this seems desirable if it is cheap to do so).
+ // Note that lazy index creation in readonly DBs is not very feasible.
+ //
+ // This FindRow() interface assumes that attribute inColumn is effectively
+ // an alternative means of unique identification for a row in a rowspace,
+ // so correct behavior is only guaranteed when no duplicates for this col
+ // appear in the given set of rows. (If more than one row has the same cell
+ // value in this column, no more than one will be found; and cutting one of
+ // two duplicate rows can cause the index to assume no other such row lives
+ // in the row space, so future calls return nil for negative search results
+ // even though some duplicate row might still live within the rowspace.)
+ //
+ // In other words, the FindRow() implementation is allowed to assume simple
+ // hash tables mapping unqiue column keys to associated row values will be
+ // sufficient, where any duplication is not recorded because only one copy
+ // of a given key need be remembered. Implementors are not required to sort
+ // all rows by the specified column.
+ // } ----- end row methods -----
+
+ // { ----- begin table methods -----
+ NS_IMETHOD HasTable( // supports a table with the specified oid?
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid, // hypothetical table oid
+ mdb_bool* outHasTable) = 0; // whether GetTable() might succeed
+
+ NS_IMETHOD GetTable( // access one table with specific oid
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid, // hypothetical table oid
+ nsIMdbTable** acqTable) = 0; // acquire specific table (or null)
+
+ NS_IMETHOD HasTableKind( // supports a table of the specified type?
+ nsIMdbEnv* ev, // context
+ mdb_scope inRowScope, // rid scope for row ids
+ mdb_kind inTableKind, // the type of table to access
+ mdb_count* outTableCount, // current number of such tables
+ mdb_bool* outSupportsTable) = 0; // whether GetTableKind() might succeed
+
+ // row scopes to be supported include the following suggestions:
+ // "ns:msg:db:row:scope:address:cards:all"
+ // "ns:msg:db:row:scope:mail:messages:all"
+ // "ns:msg:db:row:scope:news:articles:all"
+
+ // table kinds to be supported include the following suggestions:
+ // "ns:msg:db:table:kind:address:cards:main"
+ // "ns:msg:db:table:kind:address:lists:all"
+ // "ns:msg:db:table:kind:address:list"
+ // "ns:msg:db:table:kind:news:threads:all"
+ // "ns:msg:db:table:kind:news:thread"
+ // "ns:msg:db:table:kind:mail:threads:all"
+ // "ns:msg:db:table:kind:mail:thread"
+
+ NS_IMETHOD GetTableKind( // access one (random) table of specific type
+ nsIMdbEnv* ev, // context
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_kind inTableKind, // the type of table to access
+ mdb_count* outTableCount, // current number of such tables
+ mdb_bool* outMustBeUnique, // whether port can hold only one of these
+ nsIMdbTable** acqTable) = 0; // acquire scoped collection of rows
+
+ NS_IMETHOD
+ GetPortTableCursor( // get cursor for all tables of specific type
+ nsIMdbEnv* ev, // context
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_kind inTableKind, // the type of table to access
+ nsIMdbPortTableCursor** acqCursor) = 0; // all such tables in the port
+ // } ----- end table methods -----
+
+
+ // { ----- begin commit methods -----
+
+ NS_IMETHOD ShouldCompress( // store wastes at least inPercentWaste?
+ nsIMdbEnv* ev, // context
+ mdb_percent inPercentWaste, // 0..100 percent file size waste threshold
+ mdb_percent* outActualWaste, // 0..100 percent of file actually wasted
+ mdb_bool* outShould) = 0; // true when about inPercentWaste% is wasted
+ // ShouldCompress() returns true if the store can determine that the file
+ // will shrink by an estimated percentage of inPercentWaste% (or more) if
+ // CompressCommit() is called, because that percentage of the file seems
+ // to be recoverable free space. The granularity is only in terms of
+ // percentage points, and any value over 100 is considered equal to 100.
+ //
+ // If a store only has an approximate idea how much space might be saved
+ // during a compress, then a best guess should be made. For example, the
+ // Mork implementation might keep track of how much file space began with
+ // text content before the first updating transaction, and then consider
+ // all content following the start of the first transaction as potentially
+ // wasted space if it is all updates and not just new content. (This is
+ // a safe assumption in the sense that behavior will stabilize on a low
+ // estimate of wastage after a commit removes all transaction updates.)
+ //
+ // Some db formats might attempt to keep a very accurate reckoning of free
+ // space size, so a very accurate determination can be made. But other db
+ // formats might have difficulty determining size of free space, and might
+ // require some lengthy calculation to answer. This is the reason for
+ // passing in the percentage threshold of interest, so that such lengthy
+ // computations can terminate early as soon as at least inPercentWaste is
+ // found, so that the entire file need not be groveled when unnecessary.
+ // However, we hope implementations will always favor fast but imprecise
+ // heuristic answers instead of extremely slow but very precise answers.
+ //
+ // If the outActualWaste parameter is non-nil, it will be used to return
+ // the actual estimated space wasted as a percentage of file size. (This
+ // parameter is provided so callers need not call repeatedly with altered
+ // inPercentWaste values to isolate the actual wastage figure.) Note the
+ // actual wastage figure returned can exactly equal inPercentWaste even
+ // when this grossly underestimates the real figure involved, if the db
+ // finds it very expensive to determine the extent of wastage after it is
+ // known to at least exceed inPercentWaste. Note we expect that whenever
+ // outShould returns true, that outActualWaste returns >= inPercentWaste.
+ //
+ // The effect of different inPercentWaste values is not very uniform over
+ // the permitted range. For example, 50 represents 50% wastage, or a file
+ // that is about double what it should be ideally. But 99 represents 99%
+ // wastage, or a file that is about ninety-nine times as big as it should
+ // be ideally. In the smaller direction, 25 represents 25% wastage, or
+ // a file that is only 33% larger than it should be ideally.
+ //
+ // Callers can determine what policy they want to use for considering when
+ // a file holds too much wasted space, and express this as a percentage
+ // of total file size to pass as in the inPercentWaste parameter. A zero
+ // likely returns always trivially true, and 100 always trivially false.
+ // The great majority of callers are expected to use values from 25 to 75,
+ // since most plausible thresholds for compressing might fall between the
+ // extremes of 133% of ideal size and 400% of ideal size. (Presumably the
+ // larger a file gets, the more important the percentage waste involved, so
+ // a sliding scale for compress thresholds might use smaller numbers for
+ // much bigger file sizes.)
+
+ // } ----- end commit methods -----
+
+// } ===== end nsIMdbPort methods =====
+};
+
+/*| nsIMdbStore: a mutable interface to a specific database file.
+**|
+**|| tables: one can force a new table to exist in a store with NewTable()
+**| and nonzero values for both row scope and table kind. (If one wishes only
+**| one table of a certain kind, then one might look for it first using the
+**| GetTableKind() method). One can pass inMustBeUnique to force future
+**| users of this store to be unable to create other tables with the same pair
+**| of scope and kind attributes. When inMustBeUnique is true, and the table
+**| with the given scope and kind pair already exists, then the existing one
+**| is returned instead of making a new table. Similarly, if one passes false
+**| for inMustBeUnique, but the table kind has already been marked unique by a
+**| previous user of the store, then the existing unique table is returned.
+**|
+**|| import: all or some of another port's content can be imported by calling
+**| AddPortContent() with a row scope identifying the extent of content to
+**| be imported. A zero row scope will import everything. A nonzero row
+**| scope will only import tables with a matching row scope. Note that one
+**| must somehow find a way to negotiate possible conflicts between existing
+**| row content and imported row content, and this involves a specific kind of
+**| definition for row identity involving either row IDs or unique attributes,
+**| or some combination of these two. At the moment I am just going to wave
+**| my hands, and say the default behavior is to assign all new row identities
+**| to all imported content, which will result in no merging of content; this
+**| must change later because it is unacceptable in some contexts.
+**|
+**|| commits: to manage modifications in a mutable store, very few methods are
+**| really needed to indicate global policy choices that are independent of
+**| the actual modifications that happen in objects at the level of tables,
+**| rows, and cells, etc. The most important policy to specify is which sets
+**| of changes are considered associated in a manner such that they should be
+**| applied together atomically to a given store. We call each such group of
+**| changes a transaction. We handle three different grades of transaction,
+**| but they differ only in semantic significance to the application, and are
+**| not intended to nest. (If small transactions were nested inside large
+**| transactions, that would imply that a single large transaction must be
+**| atomic over all the contained small transactions; but actually we intend
+**| smalls transaction never be undone once commited due to, say, aborting a
+**| transaction of greater significance.) The small, large, and session level
+**| commits have equal granularity, and differ only in risk of loss from the
+**| perspective of an application. Small commits characterize changes that
+**| can be lost with relatively small risk, so small transactions can delay
+**| until later if they are expensive or impractical to commit. Large commits
+**| involve changes that would probably inconvenience users if lost, so the
+**| need to pay costs of writing is rather greater than with small commits.
+**| Session commits are last ditch attempts to save outstanding changes before
+**| stopping the use of a particular database, so there will be no later point
+**| in time to save changes that have been delayed due to possible high cost.
+**| If large commits are never delayed, then a session commit has about the
+**| same performance effect as another large commit; but if small and large
+**| commits are always delayed, then a session commit is likely to be rather
+**| expensive as a runtime cost compared to any earlier database usage.
+**|
+**|| aborts: the only way to abort changes to a store is by closing the store.
+**| So there is no specific method for causing any abort. Stores must discard
+**| all changes made that are uncommited when a store is closed. This design
+**| choice makes the implementations of tables, rows, and cells much less
+**| complex because they need not maintain a record of undobable changes. When
+**| a store is closed, presumably this precipitates the closure of all tables,
+**| rows, and cells in the store as well. So an application can revert the
+**| state of a store in the user interface by quietly closing and reopening a
+**| store, because this will discard uncommited changes and show old content.
+**| This implies an app that closes a store will need to send a "scramble"
+**| event notification to any views that depend on old discarded content.
+|*/
+
+#define NS_IMDBSTORE_IID_STR "726618d3-f15b-49b9-9f4a-efcc9db53d0d"
+
+#define NS_IMDBSTORE_IID \
+{0x726618d3, 0xf15b, 0x49b9, \
+{0x9f, 0x4a, 0xef, 0xcc, 0x9d, 0xb5, 0x3d, 0x0d}}
+
+class nsIMdbStore : public nsIMdbPort {
+public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBSTORE_IID)
+
+// { ===== begin nsIMdbStore methods =====
+
+ // { ----- begin table methods -----
+ NS_IMETHOD NewTable( // make one new table of specific type
+ nsIMdbEnv* ev, // context
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_kind inTableKind, // the type of table to access
+ mdb_bool inMustBeUnique, // whether store can hold only one of these
+ const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
+ nsIMdbTable** acqTable) = 0; // acquire scoped collection of rows
+
+ NS_IMETHOD NewTableWithOid( // make one new table of specific type
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid, // caller assigned oid
+ mdb_kind inTableKind, // the type of table to access
+ mdb_bool inMustBeUnique, // whether store can hold only one of these
+ const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
+ nsIMdbTable** acqTable) = 0; // acquire scoped collection of rows
+ // } ----- end table methods -----
+
+ // { ----- begin row scope methods -----
+ NS_IMETHOD RowScopeHasAssignedIds(nsIMdbEnv* ev,
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
+ mdb_bool* outStoreAssigned) = 0; // nonzero if store db assigned specified
+
+ NS_IMETHOD SetCallerAssignedIds(nsIMdbEnv* ev,
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
+ mdb_bool* outStoreAssigned) = 0; // nonzero if store db assigned specified
+
+ NS_IMETHOD SetStoreAssignedIds(nsIMdbEnv* ev,
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
+ mdb_bool* outStoreAssigned) = 0; // nonzero if store db assigned specified
+ // } ----- end row scope methods -----
+
+ // { ----- begin row methods -----
+ NS_IMETHOD NewRowWithOid(nsIMdbEnv* ev, // new row w/ caller assigned oid
+ const mdbOid* inOid, // caller assigned oid
+ nsIMdbRow** acqRow) = 0; // create new row
+
+ NS_IMETHOD NewRow(nsIMdbEnv* ev, // new row with db assigned oid
+ mdb_scope inRowScope, // row scope for row ids
+ nsIMdbRow** acqRow) = 0; // create new row
+ // Note this row must be added to some table or cell child before the
+ // store is closed in order to make this row persist across sesssions.
+
+ // } ----- end row methods -----
+
+ // { ----- begin inport/export methods -----
+ NS_IMETHOD ImportContent( // import content from port
+ nsIMdbEnv* ev, // context
+ mdb_scope inRowScope, // scope for rows (or zero for all?)
+ nsIMdbPort* ioPort, // the port with content to add to store
+ nsIMdbThumb** acqThumb) = 0; // acquire thumb for incremental import
+ // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+ // then the import will be finished.
+
+ NS_IMETHOD ImportFile( // import content from port
+ nsIMdbEnv* ev, // context
+ nsIMdbFile* ioFile, // the file with content to add to store
+ nsIMdbThumb** acqThumb) = 0; // acquire thumb for incremental import
+ // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+ // then the import will be finished.
+ // } ----- end inport/export methods -----
+
+ // { ----- begin hinting methods -----
+ NS_IMETHOD
+ ShareAtomColumnsHint( // advise re shared column content atomizing
+ nsIMdbEnv* ev, // context
+ mdb_scope inScopeHint, // zero, or suggested shared namespace
+ const mdbColumnSet* inColumnSet) = 0; // cols desired tokenized together
+
+ NS_IMETHOD
+ AvoidAtomColumnsHint( // advise column with poor atomizing prospects
+ nsIMdbEnv* ev, // context
+ const mdbColumnSet* inColumnSet) = 0; // cols with poor atomizing prospects
+ // } ----- end hinting methods -----
+
+ // { ----- begin commit methods -----
+ NS_IMETHOD SmallCommit( // save minor changes if convenient and uncostly
+ nsIMdbEnv* ev) = 0; // context
+
+ NS_IMETHOD LargeCommit( // save important changes if at all possible
+ nsIMdbEnv* ev, // context
+ nsIMdbThumb** acqThumb) = 0; // acquire thumb for incremental commit
+ // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+ // then the commit will be finished. Note the store is effectively write
+ // locked until commit is finished or canceled through the thumb instance.
+ // Until the commit is done, the store will report it has readonly status.
+
+ NS_IMETHOD SessionCommit( // save all changes if large commits delayed
+ nsIMdbEnv* ev, // context
+ nsIMdbThumb** acqThumb) = 0; // acquire thumb for incremental commit
+ // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+ // then the commit will be finished. Note the store is effectively write
+ // locked until commit is finished or canceled through the thumb instance.
+ // Until the commit is done, the store will report it has readonly status.
+
+ NS_IMETHOD
+ CompressCommit( // commit and make db physically smaller if possible
+ nsIMdbEnv* ev, // context
+ nsIMdbThumb** acqThumb) = 0; // acquire thumb for incremental commit
+ // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+ // then the commit will be finished. Note the store is effectively write
+ // locked until commit is finished or canceled through the thumb instance.
+ // Until the commit is done, the store will report it has readonly status.
+
+ // } ----- end commit methods -----
+
+// } ===== end nsIMdbStore methods =====
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbStore, NS_IMDBSTORE_IID)
+
+/*| nsIMdbCursor: base cursor class for iterating row cells and table rows
+**|
+**|| count: the number of elements in the collection (table or row)
+**|
+**|| seed: the change count in the underlying collection, which is synced
+**| with the collection when the iteration position is set, and henceforth
+**| acts to show whether the iter has lost collection synchronization, in
+**| case it matters to clients whether any change happens during iteration.
+**|
+**|| pos: the position of the current element in the collection. Negative
+**| means a position logically before the first element. A positive value
+**| equal to count (or larger) implies a position after the last element.
+**| To iterate over all elements, set the position to negative, so subsequent
+**| calls to any 'next' method will access the first collection element.
+**|
+**|| doFailOnSeedOutOfSync: whether a cursor should return an error if the
+**| cursor's snapshot of a table's seed becomes stale with respect the table's
+**| current seed value (which implies the iteration is less than total) in
+**| between to cursor calls that actually access collection content. By
+**| default, a cursor should assume this attribute is false until specified,
+**| so that iterations quietly try to re-sync when they lose coherence.
+|*/
+
+#define NS_IMDBCURSOR_IID_STR "a0c37337-6ebc-474c-90db-e65ea0b850aa"
+
+#define NS_IMDBCURSOR_IID \
+{0xa0c37337, 0x6ebc, 0x474c, \
+{0x90, 0xdb, 0xe6, 0x5e, 0xa0, 0xb8, 0x50, 0xaa}}
+
+class nsIMdbCursor : public nsISupports { // collection iterator
+public:
+
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBCURSOR_IID)
+// { ===== begin nsIMdbCursor methods =====
+
+ // { ----- begin attribute methods -----
+ NS_IMETHOD GetCount(nsIMdbEnv* ev, mdb_count* outCount) = 0; // readonly
+ NS_IMETHOD GetSeed(nsIMdbEnv* ev, mdb_seed* outSeed) = 0; // readonly
+
+ NS_IMETHOD SetPos(nsIMdbEnv* ev, mdb_pos inPos) = 0; // mutable
+ NS_IMETHOD GetPos(nsIMdbEnv* ev, mdb_pos* outPos) = 0;
+
+ NS_IMETHOD SetDoFailOnSeedOutOfSync(nsIMdbEnv* ev, mdb_bool inFail) = 0;
+ NS_IMETHOD GetDoFailOnSeedOutOfSync(nsIMdbEnv* ev, mdb_bool* outFail) = 0;
+ // } ----- end attribute methods -----
+
+// } ===== end nsIMdbCursor methods =====
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbCursor, NS_IMDBCURSOR_IID)
+
+#define NS_IMDBPORTTABLECURSOR_IID_STR = "f181a41e-933d-49b3-af93-20d3634b8b78"
+
+#define NS_IMDBPORTTABLECURSOR_IID \
+{0xf181a41e, 0x933d, 0x49b3, \
+{0xaf, 0x93, 0x20, 0xd3, 0x63, 0x4b, 0x8b, 0x78}}
+
+/*| nsIMdbPortTableCursor: cursor class for iterating port tables
+**|
+**|| port: the cursor is associated with a specific port, which can be
+**| set to a different port (which resets the position to -1 so the
+**| next table acquired is the first in the port.
+**|
+|*/
+class nsIMdbPortTableCursor : public nsISupports { // table collection iterator
+public:
+
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBPORTTABLECURSOR_IID)
+// { ===== begin nsIMdbPortTableCursor methods =====
+
+ // { ----- begin attribute methods -----
+ NS_IMETHOD SetPort(nsIMdbEnv* ev, nsIMdbPort* ioPort) = 0; // sets pos to -1
+ NS_IMETHOD GetPort(nsIMdbEnv* ev, nsIMdbPort** acqPort) = 0;
+
+ NS_IMETHOD SetRowScope(nsIMdbEnv* ev, // sets pos to -1
+ mdb_scope inRowScope) = 0;
+ NS_IMETHOD GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope) = 0;
+ // setting row scope to zero iterates over all row scopes in port
+
+ NS_IMETHOD SetTableKind(nsIMdbEnv* ev, // sets pos to -1
+ mdb_kind inTableKind) = 0;
+ NS_IMETHOD GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind) = 0;
+ // setting table kind to zero iterates over all table kinds in row scope
+ // } ----- end attribute methods -----
+
+ // { ----- begin table iteration methods -----
+ NS_IMETHOD NextTable( // get table at next position in the db
+ nsIMdbEnv* ev, // context
+ nsIMdbTable** acqTable) = 0; // the next table in the iteration
+ // } ----- end table iteration methods -----
+
+// } ===== end nsIMdbPortTableCursor methods =====
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbPortTableCursor,
+ NS_IMDBPORTTABLECURSOR_IID)
+
+/*| nsIMdbCollection: an object that collects a set of other objects as members.
+**| The main purpose of this base class is to unify the perceived semantics
+**| of tables and rows where their collection behavior is similar. This helps
+**| isolate the mechanics of collection behavior from the other semantics that
+**| are more characteristic of rows and tables.
+**|
+**|| count: the number of objects in a collection is the member count. (Some
+**| collection interfaces call this attribute the 'size', but that can be a
+**| little ambiguous, and counting actual members is harder to confuse.)
+**|
+**|| seed: the seed of a collection is a counter for changes in membership in
+**| a specific collection. This seed should change when members are added to
+**| or removed from a collection, but not when a member changes internal state.
+**| The seed should also change whenever the internal collection of members has
+**| a complex state change that reorders member positions (say by sorting) that
+**| would affect the nature of an iteration over that collection of members.
+**| The purpose of a seed is to inform any outstanding collection cursors that
+**| they might be stale, without incurring the cost of broadcasting an event
+**| notification to such cursors, which would need more data structure support.
+**| Presumably a cursor in a particular mdb code suite has much more direct
+**| access to a collection seed member slot that this abstract COM interface,
+**| so this information is intended more for clients outside mdb that want to
+**| make inferences similar to those made by the collection cursors. The seed
+**| value as an integer magnitude is not very important, and callers should not
+**| assume meaningful information can be derived from an integer value beyond
+**| whether it is equal or different from a previous inspection. A seed uses
+**| integers of many bits in order to make the odds of wrapping and becoming
+**| equal to an earlier seed value have probability that is vanishingly small.
+**|
+**|| port: every collection is associated with a specific database instance.
+**|
+**|| cursor: a subclass of nsIMdbCursor suitable for this specific collection
+**| subclass. The ability to GetCursor() from the base nsIMdbCollection class
+**| is not really as useful as getting a more specifically typed cursor more
+**| directly from the base class without any casting involved. So including
+**| this method here is more for conceptual illustration.
+**|
+**|| oid: every collection has an identity that persists from session to
+**| session. Implementations are probably able to distinguish row IDs from
+**| table IDs, but we don't specify anything official in this regard. A
+**| collection has the same identity for the lifetime of the collection,
+**| unless identity is swapped with another collection by means of a call to
+**| BecomeContent(), which is considered a way to swap a new representation
+**| for an old well-known object. (Even so, only content appears to change,
+**| while the identity seems to stay the same.)
+**|
+**|| become: developers can effectively cause two objects to swap identities,
+**| in order to effect a complete swap between what persistent content is
+**| represented by two oids. The caller should consider this a content swap,
+**| and not identity wap, because identities will seem to stay the same while
+**| only content changes. However, implementations will likely do this
+**| internally by swapping identities. Callers must swap content only
+**| between objects of similar type, such as a row with another row, and a
+**| table with another table, because implementations need not support
+**| cross-object swapping because it might break object name spaces.
+**|
+**|| dropping: when a caller expects a row or table will no longer be used, the
+**| caller can tell the collection to 'drop activity', which means the runtime
+**| object can have its internal representation purged to save memory or any
+**| other resource that is being consumed by the collection's representation.
+**| This has no effect on the collection's persistent content or semantics,
+**| and is only considered a runtime effect. After a collection drops
+**| activity, the object should still be as usable as before (because it has
+**| NOT been closed), but further usage can be expensive to re-instate because
+**| it might involve reallocating space and/or re-reading disk space. But
+**| since this future usage is not expected, the caller does not expect to
+**| pay the extra expense. An implementation can choose to implement
+**| 'dropping activity' in different ways, or even not at all if this
+**| operation is not really feasible. Callers cannot ask objects whether they
+**| are 'dropped' or not, so this should be transparent. (Note that
+**| implementors might fear callers do not really know whether future
+**| usage will occur, and therefore might delay the act of dropping until
+**| the near future, until seeing whether the object is used again
+**| immediately elsewhere. Such use soon after the drop request might cause
+**| the drop to be cancelled.)
+|*/
+class nsIMdbCollection : public nsISupports { // sequence of objects
+public:
+
+// { ===== begin nsIMdbCollection methods =====
+
+ // { ----- begin attribute methods -----
+ NS_IMETHOD GetSeed(nsIMdbEnv* ev,
+ mdb_seed* outSeed) = 0; // member change count
+ NS_IMETHOD GetCount(nsIMdbEnv* ev,
+ mdb_count* outCount) = 0; // member count
+
+ NS_IMETHOD GetPort(nsIMdbEnv* ev,
+ nsIMdbPort** acqPort) = 0; // collection container
+ // } ----- end attribute methods -----
+
+ // { ----- begin cursor methods -----
+ NS_IMETHOD GetCursor( // make a cursor starting iter at inMemberPos
+ nsIMdbEnv* ev, // context
+ mdb_pos inMemberPos, // zero-based ordinal pos of member in collection
+ nsIMdbCursor** acqCursor) = 0; // acquire new cursor instance
+ // } ----- end cursor methods -----
+
+ // { ----- begin ID methods -----
+ NS_IMETHOD GetOid(nsIMdbEnv* ev,
+ mdbOid* outOid) = 0; // read object identity
+ NS_IMETHOD BecomeContent(nsIMdbEnv* ev,
+ const mdbOid* inOid) = 0; // exchange content
+ // } ----- end ID methods -----
+
+ // { ----- begin activity dropping methods -----
+ NS_IMETHOD DropActivity( // tell collection usage no longer expected
+ nsIMdbEnv* ev) = 0;
+ // } ----- end activity dropping methods -----
+
+// } ===== end nsIMdbCollection methods =====
+};
+
+/*| nsIMdbTable: an ordered collection of rows
+**|
+**|| row scope: an integer token for an atomized string in this database
+**| that names a space for row IDs. This attribute of a table is intended
+**| as guidance metainformation that helps with searching a database for
+**| tables that operate on collections of rows of the specific type. By
+**| convention, a table with a specific row scope is expected to focus on
+**| containing rows that belong to that scope, however exceptions are easily
+**| allowed because all rows in a table are known by both row ID and scope.
+**| (A table with zero row scope is never allowed because this would make it
+**| ambiguous to use a zero row scope when iterating over tables in a port to
+**| indicate that all row scopes should be seen by a cursor.)
+**|
+**|| table kind: an integer token for an atomized string in this database
+**| that names a kind of table as a subset of the associated row scope. This
+**| attribute is intended as guidance metainformation to clarify the role of
+**| this table with respect to other tables in the same row scope, and this
+**| also helps search for such tables in a database. By convention, a table
+**| with a specific table kind has a consistent role for containing rows with
+**| respect to other collections of such rows in the same row scope. Also by
+**| convention, at least one table in a row scope has a table kind purporting
+**| to contain ALL the rows that belong in that row scope, so that at least
+**| one table exists that allows all rows in a scope to be interated over.
+**| (A table with zero table kind is never allowed because this would make it
+**| ambiguous to use a zero table kind when iterating over tables in a port to
+**| indicate that all table kinds in a row scope should be seen by a cursor.)
+**|
+**|| port: every table is considered part of some port that contains the
+**| table, so that closing the containing port will cause the table to be
+**| indirectly closed as well. We make it easy to get the containing port for
+**| a table, because the port supports important semantic interfaces that will
+**| affect how content in table is presented; the most important port context
+**| that affects a table is specified by the set of token to string mappings
+**| that affect all tokens used throughout the database, and which drive the
+**| meanings of row scope, table kind, cell columns, etc.
+**|
+**|| cursor: a cursor that iterates over the rows in this table, where rows
+**| have zero-based index positions from zero to count-1. Making a cursor
+**| with negative position will next iterate over the first row in the table.
+**|
+**|| position: given any position from zero to count-1, a table will return
+**| the row ID and row scope for the row at that position. (One can use the
+**| GetRowAllCells() method to read that row, or else use a row cursor to both
+**| get the row at some position and read its content at the same time.) The
+**| position depends on whether a table is sorted, and upon the actual sort.
+**| Note that moving a row's position is only possible in unsorted tables.
+**|
+**|| row set: every table contains a collection of rows, where a member row is
+**| referenced by the table using the row ID and row scope for the row. No
+**| single table owns a given row instance, because rows are effectively ref-
+**| counted and destroyed only when the last table removes a reference to that
+**| particular row. (But a row can be emptied of all content no matter how
+**| many refs exist, and this might be the next best thing to destruction.)
+**| Once a row exists in a least one table (after NewRow() is called), then it
+**| can be added to any other table by calling AddRow(), or removed from any
+**| table by calling CutRow(), or queried as a member by calling HasRow(). A
+**| row can only be added to a table once, and further additions do nothing and
+**| complain not at all. Cutting a row from a table only does something when
+**| the row was actually a member, and otherwise does nothing silently.
+**|
+**|| row ref count: one can query the number of tables (and/or cells)
+**| containing a row as a member or a child.
+**|
+**|| row content: one can access or modify the cell content in a table's row
+**| by moving content to or from an instance of nsIMdbRow. Note that nsIMdbRow
+**| never represents the actual row inside a table, and this is the reason
+**| why nsIMdbRow instances do not have row IDs or row scopes. So an instance
+**| of nsIMdbRow always and only contains a snapshot of some or all content in
+**| past, present, or future persistent row inside a table. This means that
+**| reading and writing rows in tables has strictly copy semantics, and we
+**| currently do not plan any exceptions for specific performance reasons.
+**|
+**|| sorting: note all rows are assumed sorted by row ID as a secondary
+**| sort following the primary column sort, when table rows are sorted.
+**|
+**|| indexes:
+|*/
+
+
+#define NS_IMDBTABLE_IID_STR = "fe11bc98-d02b-4128-9fac-87042fdf9639"
+
+#define NS_IMDBTABLE_IID \
+{0xfe11bc98, 0xd02b, 0x4128, \
+{0x9f, 0xac, 0x87, 0x04, 0x2f, 0xdf, 0x96, 0x39}}
+
+class nsIMdbTable : public nsIMdbCollection { // a collection of rows
+public:
+
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBTABLE_IID)
+// { ===== begin nsIMdbTable methods =====
+
+ // { ----- begin meta attribute methods -----
+ NS_IMETHOD SetTablePriority(nsIMdbEnv* ev, mdb_priority inPrio) = 0;
+ NS_IMETHOD GetTablePriority(nsIMdbEnv* ev, mdb_priority* outPrio) = 0;
+
+ NS_IMETHOD GetTableBeVerbose(nsIMdbEnv* ev, mdb_bool* outBeVerbose) = 0;
+ NS_IMETHOD SetTableBeVerbose(nsIMdbEnv* ev, mdb_bool inBeVerbose) = 0;
+
+ NS_IMETHOD GetTableIsUnique(nsIMdbEnv* ev, mdb_bool* outIsUnique) = 0;
+
+ NS_IMETHOD GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind) = 0;
+ NS_IMETHOD GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope) = 0;
+
+ NS_IMETHOD GetMetaRow(
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
+ mdbOid* outOid, // output meta row oid, can be nil to suppress output
+ nsIMdbRow** acqRow) = 0; // acquire table's unique singleton meta row
+ // The purpose of a meta row is to support the persistent recording of
+ // meta info about a table as cells put into the distinguished meta row.
+ // Each table has exactly one meta row, which is not considered a member
+ // of the collection of rows inside the table. The only way to tell
+ // whether a row is a meta row is by the fact that it is returned by this
+ // GetMetaRow() method from some table. Otherwise nothing distinguishes
+ // a meta row from any other row. A meta row can be used anyplace that
+ // any other row can be used, and can even be put into other tables (or
+ // the same table) as a table member, if this is useful for some reason.
+ // The first attempt to access a table's meta row using GetMetaRow() will
+ // cause the meta row to be created if it did not already exist. When the
+ // meta row is created, it will have the row oid that was previously
+ // requested for this table's meta row; or if no oid was ever explicitly
+ // specified for this meta row, then a unique oid will be generated in
+ // the row scope named "m" (so obviously MDB clients should not
+ // manually allocate any row IDs from that special meta scope namespace).
+ // The meta row oid can be specified either when the table is created, or
+ // else the first time that GetMetaRow() is called, by passing a non-nil
+ // pointer to an oid for parameter inOptionalMetaRowOid. The meta row's
+ // actual oid is returned in outOid (if this is a non-nil pointer), and
+ // it will be different from inOptionalMetaRowOid when the meta row was
+ // already given a different oid earlier.
+ // } ----- end meta attribute methods -----
+
+
+ // { ----- begin cursor methods -----
+ NS_IMETHOD GetTableRowCursor( // make a cursor, starting iteration at inRowPos
+ nsIMdbEnv* ev, // context
+ mdb_pos inRowPos, // zero-based ordinal position of row in table
+ nsIMdbTableRowCursor** acqCursor) = 0; // acquire new cursor instance
+ // } ----- end row position methods -----
+
+ // { ----- begin row position methods -----
+ NS_IMETHOD PosToOid( // get row member for a table position
+ nsIMdbEnv* ev, // context
+ mdb_pos inRowPos, // zero-based ordinal position of row in table
+ mdbOid* outOid) = 0; // row oid at the specified position
+
+ NS_IMETHOD OidToPos( // test for the table position of a row member
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid, // row to find in table
+ mdb_pos* outPos) = 0; // zero-based ordinal position of row in table
+
+ NS_IMETHOD PosToRow( // test for the table position of a row member
+ nsIMdbEnv* ev, // context
+ mdb_pos inRowPos, // zero-based ordinal position of row in table
+ nsIMdbRow** acqRow) = 0; // acquire row at table position inRowPos
+
+ NS_IMETHOD RowToPos( // test for the table position of a row member
+ nsIMdbEnv* ev, // context
+ nsIMdbRow* ioRow, // row to find in table
+ mdb_pos* outPos) = 0; // zero-based ordinal position of row in table
+ // } ----- end row position methods -----
+
+ // { ----- begin oid set methods -----
+ NS_IMETHOD AddOid( // make sure the row with inOid is a table member
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid) = 0; // row to ensure membership in table
+
+ NS_IMETHOD HasOid( // test for the table position of a row member
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid, // row to find in table
+ mdb_bool* outHasOid) = 0; // whether inOid is a member row
+
+ NS_IMETHOD CutOid( // make sure the row with inOid is not a member
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid) = 0; // row to remove from table
+ // } ----- end oid set methods -----
+
+ // { ----- begin row set methods -----
+ NS_IMETHOD NewRow( // create a new row instance in table
+ nsIMdbEnv* ev, // context
+ mdbOid* ioOid, // please use minus one (unbound) rowId for db-assigned IDs
+ nsIMdbRow** acqRow) = 0; // create new row
+
+ NS_IMETHOD AddRow( // make sure the row with inOid is a table member
+ nsIMdbEnv* ev, // context
+ nsIMdbRow* ioRow) = 0; // row to ensure membership in table
+
+ NS_IMETHOD HasRow( // test for the table position of a row member
+ nsIMdbEnv* ev, // context
+ nsIMdbRow* ioRow, // row to find in table
+ mdb_bool* outHasRow) = 0; // whether row is a table member
+
+ NS_IMETHOD CutRow( // make sure the row with inOid is not a member
+ nsIMdbEnv* ev, // context
+ nsIMdbRow* ioRow) = 0; // row to remove from table
+
+ NS_IMETHOD CutAllRows( // remove all rows from the table
+ nsIMdbEnv* ev) = 0; // context
+ // } ----- end row set methods -----
+
+ // { ----- begin hinting methods -----
+ NS_IMETHOD SearchColumnsHint( // advise re future expected search cols
+ nsIMdbEnv* ev, // context
+ const mdbColumnSet* inColumnSet) = 0; // columns likely to be searched
+
+ NS_IMETHOD SortColumnsHint( // advise re future expected sort columns
+ nsIMdbEnv* ev, // context
+ const mdbColumnSet* inColumnSet) = 0; // columns for likely sort requests
+
+ NS_IMETHOD StartBatchChangeHint( // advise before many adds and cuts
+ nsIMdbEnv* ev, // context
+ const void* inLabel) = 0; // intend unique address to match end call
+ // If batch starts nest by virtue of nesting calls in the stack, then
+ // the address of a local variable makes a good batch start label that
+ // can be used at batch end time, and such addresses remain unique.
+
+ NS_IMETHOD EndBatchChangeHint( // advise before many adds and cuts
+ nsIMdbEnv* ev, // context
+ const void* inLabel) = 0; // label matching start label
+ // Suppose a table is maintaining one or many sort orders for a table,
+ // so that every row added to the table must be inserted in each sort,
+ // and every row cut must be removed from each sort. If a db client
+ // intends to make many such changes before needing any information
+ // about the order or positions of rows inside a table, then a client
+ // might tell the table to start batch changes in order to disable
+ // sorting of rows for the interim. Presumably a table will then do
+ // a full sort of all rows at need when the batch changes end, or when
+ // a surprise request occurs for row position during batch changes.
+ // } ----- end hinting methods -----
+
+ // { ----- begin searching methods -----
+ NS_IMETHOD FindRowMatches( // search variable number of sorted cols
+ nsIMdbEnv* ev, // context
+ const mdbYarn* inPrefix, // content to find as prefix in row's column cell
+ nsIMdbTableRowCursor** acqCursor) = 0; // set of matching rows
+
+ NS_IMETHOD GetSearchColumns( // query columns used by FindRowMatches()
+ nsIMdbEnv* ev, // context
+ mdb_count* outCount, // context
+ mdbColumnSet* outColSet) = 0; // caller supplied space to put columns
+ // GetSearchColumns() returns the columns actually searched when the
+ // FindRowMatches() method is called. No more than mColumnSet_Count
+ // slots of mColumnSet_Columns will be written, since mColumnSet_Count
+ // indicates how many slots are present in the column array. The
+ // actual number of search column used by the table is returned in
+ // the outCount parameter; if this number exceeds mColumnSet_Count,
+ // then a caller needs a bigger array to read the entire column set.
+ // The minimum of mColumnSet_Count and outCount is the number slots
+ // in mColumnSet_Columns that were actually written by this method.
+ //
+ // Callers are expected to change this set of columns by calls to
+ // nsIMdbTable::SearchColumnsHint() or SetSearchSorting(), or both.
+ // } ----- end searching methods -----
+
+ // { ----- begin sorting methods -----
+ // sorting: note all rows are assumed sorted by row ID as a secondary
+ // sort following the primary column sort, when table rows are sorted.
+
+ NS_IMETHOD
+ CanSortColumn( // query which column is currently used for sorting
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // column to query sorting potential
+ mdb_bool* outCanSort) = 0; // whether the column can be sorted
+
+ NS_IMETHOD GetSorting( // view same table in particular sorting
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // requested new column for sorting table
+ nsIMdbSorting** acqSorting) = 0; // acquire sorting for column
+
+ NS_IMETHOD SetSearchSorting( // use this sorting in FindRowMatches()
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // often same as nsIMdbSorting::GetSortColumn()
+ nsIMdbSorting* ioSorting) = 0; // requested sorting for some column
+ // SetSearchSorting() attempts to inform the table that ioSorting
+ // should be used during calls to FindRowMatches() for searching
+ // the column which is actually sorted by ioSorting. This method
+ // is most useful in conjunction with nsIMdbSorting::SetCompare(),
+ // because otherwise a caller would not be able to override the
+ // comparison ordering method used during searchs. Note that some
+ // database implementations might be unable to use an arbitrarily
+ // specified sort order, either due to schema or runtime interface
+ // constraints, in which case ioSorting might not actually be used.
+ // Presumably ioSorting is an instance that was returned from some
+ // earlier call to nsIMdbTable::GetSorting(). A caller can also
+ // use nsIMdbTable::SearchColumnsHint() to specify desired change
+ // in which columns are sorted and searched by FindRowMatches().
+ //
+ // A caller can pass a nil pointer for ioSorting to request that
+ // column inColumn no longer be used at all by FindRowMatches().
+ // But when ioSorting is non-nil, then inColumn should match the
+ // column actually sorted by ioSorting; when these do not agree,
+ // implementations are instructed to give precedence to the column
+ // specified by ioSorting (so this means callers might just pass
+ // zero for inColumn when ioSorting is also provided, since then
+ // inColumn is both redundant and ignored).
+ // } ----- end sorting methods -----
+
+ // { ----- begin moving methods -----
+ // moving a row does nothing unless a table is currently unsorted
+
+ NS_IMETHOD MoveOid( // change position of row in unsorted table
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid, // row oid to find in table
+ mdb_pos inHintFromPos, // suggested hint regarding start position
+ mdb_pos inToPos, // desired new position for row inRowId
+ mdb_pos* outActualPos) = 0; // actual new position of row in table
+
+ NS_IMETHOD MoveRow( // change position of row in unsorted table
+ nsIMdbEnv* ev, // context
+ nsIMdbRow* ioRow, // row oid to find in table
+ mdb_pos inHintFromPos, // suggested hint regarding start position
+ mdb_pos inToPos, // desired new position for row inRowId
+ mdb_pos* outActualPos) = 0; // actual new position of row in table
+ // } ----- end moving methods -----
+
+ // { ----- begin index methods -----
+ NS_IMETHOD AddIndex( // create a sorting index for column if possible
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // the column to sort by index
+ nsIMdbThumb** acqThumb) = 0; // acquire thumb for incremental index building
+ // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+ // then the index addition will be finished.
+
+ NS_IMETHOD CutIndex( // stop supporting a specific column index
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // the column with index to be removed
+ nsIMdbThumb** acqThumb) = 0; // acquire thumb for incremental index destroy
+ // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+ // then the index removal will be finished.
+
+ NS_IMETHOD HasIndex( // query for current presence of a column index
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // the column to investigate
+ mdb_bool* outHasIndex) = 0; // whether column has index for this column
+
+
+ NS_IMETHOD EnableIndexOnSort( // create an index for col on first sort
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn) = 0; // the column to index if ever sorted
+
+ NS_IMETHOD QueryIndexOnSort( // check whether index on sort is enabled
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // the column to investigate
+ mdb_bool* outIndexOnSort) = 0; // whether column has index-on-sort enabled
+
+ NS_IMETHOD DisableIndexOnSort( // prevent future index creation on sort
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn) = 0; // the column to index if ever sorted
+ // } ----- end index methods -----
+
+// } ===== end nsIMdbTable methods =====
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbTable, NS_IMDBTABLE_IID)
+
+/*| nsIMdbSorting: a view of a table in some particular sort order. This
+**| row order closely resembles a readonly array of rows with the same row
+**| membership as the underlying table, but in a different order than the
+**| table's explicit row order. But the sorting's row membership changes
+**| whenever the table's membership changes (without any notification, so
+**| keep this in mind when modifying the table).
+**|
+**|| table: every sorting is associated with a particular table. You
+**| cannot change which table is used by a sorting (just ask some new
+**| table for a suitable sorting instance instead).
+**|
+**|| compare: the ordering method used by a sorting, wrapped up in a
+**| abstract plug-in interface. When this was never installed by an
+**| explicit call to SetNewCompare(), a compare object is still returned,
+**| and it might match the compare instance returned by the factory method
+**| nsIMdbFactory::MakeCompare(), which represents a default sort order
+**| (which we fervently hope is consistently ASCII byte ordering).
+**|
+**|| cursor: in case callers are more comfortable with a cursor style
+**| of accessing row members, each sorting will happily return a cursor
+**| instance with behavior very similar to a cursor returned from a call
+**| to nsIMdbTable::GetTableRowCursor(), but with different row order.
+**| A cursor should show exactly the same information as the pos methods.
+**|
+**|| pos: the PosToOid() and PosToRow() methods are just like the table
+**| methods of the same name, except they show rows in the sort order of
+**| the sorting, rather than that of the table. These methods are like
+**| readonly array position accessor's, or like a C++ operator[].
+|*/
+class nsIMdbSorting : public nsIMdbObject { // sorting of some table
+public:
+// { ===== begin nsIMdbSorting methods =====
+
+ // { ----- begin attribute methods -----
+ // sorting: note all rows are assumed sorted by row ID as a secondary
+ // sort following the primary column sort, when table rows are sorted.
+
+ NS_IMETHOD GetTable(nsIMdbEnv* ev, nsIMdbTable** acqTable) = 0;
+ NS_IMETHOD GetSortColumn( // query which col is currently sorted
+ nsIMdbEnv* ev, // context
+ mdb_column* outColumn) = 0; // col the table uses for sorting (or zero)
+
+ NS_IMETHOD SetNewCompare(nsIMdbEnv* ev,
+ nsIMdbCompare* ioNewCompare) = 0;
+ // Setting the sorting's compare object will typically cause the rows
+ // to be resorted, presumably in a lazy fashion when the sorting is
+ // next required to be in a valid row ordering state, such as when a
+ // call to PosToOid() happens. ioNewCompare can be nil, in which case
+ // implementations should revert to the default sort order, which must
+ // be equivalent to whatever is used by nsIMdbFactory::MakeCompare().
+
+ NS_IMETHOD GetOldCompare(nsIMdbEnv* ev,
+ nsIMdbCompare** acqOldCompare) = 0;
+ // Get this sorting instance's compare object, which handles the
+ // ordering of rows in the sorting, by comparing yarns from the cells
+ // in the column being sorted. Since nsIMdbCompare has no interface
+ // to query the state of the compare object, it is not clear what you
+ // would do with this object when returned, except maybe compare it
+ // as a pointer address to some other instance, to check identities.
+
+ // } ----- end attribute methods -----
+
+ // { ----- begin cursor methods -----
+ NS_IMETHOD GetSortingRowCursor( // make a cursor, starting at inRowPos
+ nsIMdbEnv* ev, // context
+ mdb_pos inRowPos, // zero-based ordinal position of row in table
+ nsIMdbTableRowCursor** acqCursor) = 0; // acquire new cursor instance
+ // A cursor interface turning same info as PosToOid() or PosToRow().
+ // } ----- end row position methods -----
+
+ // { ----- begin row position methods -----
+ NS_IMETHOD PosToOid( // get row member for a table position
+ nsIMdbEnv* ev, // context
+ mdb_pos inRowPos, // zero-based ordinal position of row in table
+ mdbOid* outOid) = 0; // row oid at the specified position
+
+ NS_IMETHOD PosToRow( // test for the table position of a row member
+ nsIMdbEnv* ev, // context
+ mdb_pos inRowPos, // zero-based ordinal position of row in table
+ nsIMdbRow** acqRow) = 0; // acquire row at table position inRowPos
+ // } ----- end row position methods -----
+
+// } ===== end nsIMdbSorting methods =====
+};
+
+/*| nsIMdbTableRowCursor: cursor class for iterating table rows
+**|
+**|| table: the cursor is associated with a specific table, which can be
+**| set to a different table (which resets the position to -1 so the
+**| next row acquired is the first in the table.
+**|
+**|| NextRowId: the rows in the table can be iterated by identity alone,
+**| without actually reading the cells of any row with this method.
+**|
+**|| NextRowCells: read the next row in the table, but only read cells
+**| from the table which are already present in the row (so no new cells
+**| are added to the row, even if they are present in the table). All the
+**| cells will have content specified, even it is the empty string. No
+**| columns will be removed, even if missing from the row (because missing
+**| and empty are semantically equivalent).
+**|
+**|| NextRowAllCells: read the next row in the table, and access all the
+**| cells for this row in the table, adding any missing columns to the row
+**| as needed until all cells are represented. All the
+**| cells will have content specified, even it is the empty string. No
+**| columns will be removed, even if missing from the row (because missing
+**| and empty are semantically equivalent).
+**|
+|*/
+
+#define NS_IMDBTABLEROWCURSOR_IID_STR = "4f325dad-0385-4b62-a992-c914ab93587e"
+
+#define NS_IMDBTABLEROWCURSOR_IID \
+{0x4f325dad, 0x0385, 0x4b62, \
+{0xa9, 0x92, 0xc9, 0x14, 0xab, 0x93, 0x58, 0x7e}}
+
+
+
+class nsIMdbTableRowCursor : public nsISupports { // table row iterator
+public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBTABLEROWCURSOR_IID)
+
+// { ===== begin nsIMdbTableRowCursor methods =====
+
+ // { ----- begin attribute methods -----
+ // NS_IMETHOD SetTable(nsIMdbEnv* ev, nsIMdbTable* ioTable) = 0; // sets pos to -1
+ // Method SetTable() cut and made obsolete in keeping with new sorting methods.
+
+ NS_IMETHOD GetTable(nsIMdbEnv* ev, nsIMdbTable** acqTable) = 0;
+ // } ----- end attribute methods -----
+
+ // { ----- begin duplicate row removal methods -----
+ NS_IMETHOD CanHaveDupRowMembers(nsIMdbEnv* ev, // cursor might hold dups?
+ mdb_bool* outCanHaveDups) = 0;
+
+ NS_IMETHOD MakeUniqueCursor( // clone cursor, removing duplicate rows
+ nsIMdbEnv* ev, // context
+ nsIMdbTableRowCursor** acqCursor) = 0; // acquire clone with no dups
+ // Note that MakeUniqueCursor() is never necessary for a cursor which was
+ // created by table method nsIMdbTable::GetTableRowCursor(), because a table
+ // never contains the same row as a member more than once. However, a cursor
+ // created by table method nsIMdbTable::FindRowMatches() might contain the
+ // same row more than once, because the same row can generate a hit by more
+ // than one column with a matching string prefix. Note this method can
+ // return the very same cursor instance with just an incremented refcount,
+ // when the original cursor could not contain any duplicate rows (calling
+ // CanHaveDupRowMembers() shows this case on a false return). Otherwise
+ // this method returns a different cursor instance. Callers should not use
+ // this MakeUniqueCursor() method lightly, because it tends to defeat the
+ // purpose of lazy programming techniques, since it can force creation of
+ // an explicit row collection in a new cursor's representation, in order to
+ // inspect the row membership and remove any duplicates; this can have big
+ // impact if a collection holds tens of thousands of rows or more, when
+ // the original cursor with dups simply referenced rows indirectly by row
+ // position ranges, without using an explicit row set representation.
+ // Callers are encouraged to use nsIMdbCursor::GetCount() to determine
+ // whether the row collection is very large (tens of thousands), and to
+ // delay calling MakeUniqueCursor() when possible, until a user interface
+ // element actually demands the creation of an explicit set representation.
+ // } ----- end duplicate row removal methods -----
+
+ // { ----- begin oid iteration methods -----
+ NS_IMETHOD NextRowOid( // get row id of next row in the table
+ nsIMdbEnv* ev, // context
+ mdbOid* outOid, // out row oid
+ mdb_pos* outRowPos) = 0; // zero-based position of the row in table
+ // } ----- end oid iteration methods -----
+
+ // { ----- begin row iteration methods -----
+ NS_IMETHOD NextRow( // get row cells from table for cells already in row
+ nsIMdbEnv* ev, // context
+ nsIMdbRow** acqRow, // acquire next row in table
+ mdb_pos* outRowPos) = 0; // zero-based position of the row in table
+
+ NS_IMETHOD PrevRowOid( // get row id of previous row in the table
+ nsIMdbEnv* ev, // context
+ mdbOid* outOid, // out row oid
+ mdb_pos* outRowPos) = 0; // zero-based position of the row in table
+ // } ----- end oid iteration methods -----
+
+ // { ----- begin row iteration methods -----
+ NS_IMETHOD PrevRow( // get row cells from table for cells already in row
+ nsIMdbEnv* ev, // context
+ nsIMdbRow** acqRow, // acquire previous row in table
+ mdb_pos* outRowPos) = 0; // zero-based position of the row in table
+
+ // } ----- end row iteration methods -----
+
+ // { ----- begin copy iteration methods -----
+ // NS_IMETHOD NextRowCopy( // put row cells into sink only when already in sink
+ // nsIMdbEnv* ev, // context
+ // nsIMdbRow* ioSinkRow, // sink for row cells read from next row
+ // mdbOid* outOid, // out row oid
+ // mdb_pos* outRowPos) = 0; // zero-based position of the row in table
+ //
+ // NS_IMETHOD NextRowCopyAll( // put all row cells into sink, adding to sink
+ // nsIMdbEnv* ev, // context
+ // nsIMdbRow* ioSinkRow, // sink for row cells read from next row
+ // mdbOid* outOid, // out row oid
+ // mdb_pos* outRowPos) = 0; // zero-based position of the row in table
+ // } ----- end copy iteration methods -----
+
+// } ===== end nsIMdbTableRowCursor methods =====
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbTableRowCursor, NS_IMDBTABLEROWCURSOR_IID)
+
+/*| nsIMdbRow: a collection of cells
+**|
+|*/
+
+#define NS_IMDBROW_IID_STR "271e8d6e-183a-40e3-9f18-36913b4c7853"
+
+
+#define NS_IMDBROW_IID \
+{0x271e8d6e, 0x183a, 0x40e3, \
+{0x9f, 0x18, 0x36, 0x91, 0x3b, 0x4c, 0x78, 0x53}}
+
+
+class nsIMdbRow : public nsIMdbCollection { // cell tuple
+public:
+
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBROW_IID)
+// { ===== begin nsIMdbRow methods =====
+
+ // { ----- begin cursor methods -----
+ NS_IMETHOD GetRowCellCursor( // make a cursor starting iteration at inCellPos
+ nsIMdbEnv* ev, // context
+ mdb_pos inCellPos, // zero-based ordinal position of cell in row
+ nsIMdbRowCellCursor** acqCursor) = 0; // acquire new cursor instance
+ // } ----- end cursor methods -----
+
+ // { ----- begin column methods -----
+ NS_IMETHOD AddColumn( // make sure a particular column is inside row
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // column to add
+ const mdbYarn* inYarn) = 0; // cell value to install
+
+ NS_IMETHOD CutColumn( // make sure a column is absent from the row
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn) = 0; // column to ensure absent from row
+
+ NS_IMETHOD CutAllColumns( // remove all columns from the row
+ nsIMdbEnv* ev) = 0; // context
+ // } ----- end column methods -----
+
+ // { ----- begin cell methods -----
+ NS_IMETHOD NewCell( // get cell for specified column, or add new one
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // column to add
+ nsIMdbCell** acqCell) = 0; // cell column and value
+
+ NS_IMETHOD AddCell( // copy a cell from another row to this row
+ nsIMdbEnv* ev, // context
+ const nsIMdbCell* inCell) = 0; // cell column and value
+
+ NS_IMETHOD GetCell( // find a cell in this row
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // column to find
+ nsIMdbCell** acqCell) = 0; // cell for specified column, or null
+
+ NS_IMETHOD EmptyAllCells( // make all cells in row empty of content
+ nsIMdbEnv* ev) = 0; // context
+ // } ----- end cell methods -----
+
+ // { ----- begin row methods -----
+ NS_IMETHOD AddRow( // add all cells in another row to this one
+ nsIMdbEnv* ev, // context
+ nsIMdbRow* ioSourceRow) = 0; // row to union with
+
+ NS_IMETHOD SetRow( // make exact duplicate of another row
+ nsIMdbEnv* ev, // context
+ nsIMdbRow* ioSourceRow) = 0; // row to duplicate
+ // } ----- end row methods -----
+
+ // { ----- begin blob methods -----
+ NS_IMETHOD SetCellYarn(nsIMdbEnv* ev, // synonym for AddColumn()
+ mdb_column inColumn, // column to write
+ const mdbYarn* inYarn) = 0; // reads from yarn slots
+ // make this text object contain content from the yarn's buffer
+
+ NS_IMETHOD GetCellYarn(nsIMdbEnv* ev,
+ mdb_column inColumn, // column to read
+ mdbYarn* outYarn) = 0; // writes some yarn slots
+ // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
+
+ NS_IMETHOD AliasCellYarn(nsIMdbEnv* ev,
+ mdb_column inColumn, // column to alias
+ mdbYarn* outYarn) = 0; // writes ALL yarn slots
+
+ NS_IMETHOD NextCellYarn(nsIMdbEnv* ev, // iterative version of GetCellYarn()
+ mdb_column* ioColumn, // next column to read
+ mdbYarn* outYarn) = 0; // writes some yarn slots
+ // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
+ //
+ // The ioColumn argument is an inout parameter which initially contains the
+ // last column accessed and returns the next column corresponding to the
+ // content read into the yarn. Callers should start with a zero column
+ // value to say 'no previous column', which causes the first column to be
+ // read. Then the value returned in ioColumn is perfect for the next call
+ // to NextCellYarn(), since it will then be the previous column accessed.
+ // Callers need only examine the column token returned to see which cell
+ // in the row is being read into the yarn. When no more columns remain,
+ // and the iteration has ended, ioColumn will return a zero token again.
+ // So iterating over cells starts and ends with a zero column token.
+
+ NS_IMETHOD SeekCellYarn( // resembles nsIMdbRowCellCursor::SeekCell()
+ nsIMdbEnv* ev, // context
+ mdb_pos inPos, // position of cell in row sequence
+ mdb_column* outColumn, // column for this particular cell
+ mdbYarn* outYarn) = 0; // writes some yarn slots
+ // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
+ // Callers can pass nil for outYarn to indicate no interest in content, so
+ // only the outColumn value is returned. NOTE to subclasses: you must be
+ // able to ignore outYarn when the pointer is nil; please do not crash.
+
+ // } ----- end blob methods -----
+
+// } ===== end nsIMdbRow methods =====
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbRow, NS_IMDBROW_IID)
+
+/*| nsIMdbRowCellCursor: cursor class for iterating row cells
+**|
+**|| row: the cursor is associated with a specific row, which can be
+**| set to a different row (which resets the position to -1 so the
+**| next cell acquired is the first in the row.
+**|
+**|| NextCell: get the next cell in the row and return its position and
+**| a new instance of a nsIMdbCell to represent this next cell.
+|*/
+
+#define NS_IMDBROWCELLCURSOR_IID_STR "b33371a7-5d63-4d10-85a8-e44dffe75c28"
+
+
+#define NS_IMDBROWCELLCURSOR_IID \
+{0x271e8d6e, 0x5d63, 0x4d10 , \
+{0x85, 0xa8, 0xe4, 0x4d, 0xff, 0xe7, 0x5c, 0x28}}
+
+
+class nsIMdbRowCellCursor : public nsISupports{ // cell collection iterator
+public:
+
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBROWCELLCURSOR_IID)
+// { ===== begin nsIMdbRowCellCursor methods =====
+
+ // { ----- begin attribute methods -----
+ NS_IMETHOD SetRow(nsIMdbEnv* ev, nsIMdbRow* ioRow) = 0; // sets pos to -1
+ NS_IMETHOD GetRow(nsIMdbEnv* ev, nsIMdbRow** acqRow) = 0;
+ // } ----- end attribute methods -----
+
+ // { ----- begin cell creation methods -----
+ NS_IMETHOD MakeCell( // get cell at current pos in the row
+ nsIMdbEnv* ev, // context
+ mdb_column* outColumn, // column for this particular cell
+ mdb_pos* outPos, // position of cell in row sequence
+ nsIMdbCell** acqCell) = 0; // the cell at inPos
+ // } ----- end cell creation methods -----
+
+ // { ----- begin cell seeking methods -----
+ NS_IMETHOD SeekCell( // same as SetRow() followed by MakeCell()
+ nsIMdbEnv* ev, // context
+ mdb_pos inPos, // position of cell in row sequence
+ mdb_column* outColumn, // column for this particular cell
+ nsIMdbCell** acqCell) = 0; // the cell at inPos
+ // } ----- end cell seeking methods -----
+
+ // { ----- begin cell iteration methods -----
+ NS_IMETHOD NextCell( // get next cell in the row
+ nsIMdbEnv* ev, // context
+ nsIMdbCell** acqCell, // changes to the next cell in the iteration
+ mdb_column* outColumn, // column for this particular cell
+ mdb_pos* outPos) = 0; // position of cell in row sequence
+
+ NS_IMETHOD PickNextCell( // get next cell in row within filter set
+ nsIMdbEnv* ev, // context
+ nsIMdbCell* ioCell, // changes to the next cell in the iteration
+ const mdbColumnSet* inFilterSet, // col set of actual caller interest
+ mdb_column* outColumn, // column for this particular cell
+ mdb_pos* outPos) = 0; // position of cell in row sequence
+
+ // Note that inFilterSet should not have too many (many more than 10?)
+ // cols, since this might imply a potential excessive consumption of time
+ // over many cursor calls when looking for column and filter intersection.
+ // } ----- end cell iteration methods -----
+
+// } ===== end nsIMdbRowCellCursor methods =====
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbRowCellCursor, NS_IMDBROWCELLCURSOR_IID)
+
+/*| nsIMdbBlob: a base class for objects composed mainly of byte sequence state.
+**| (This provides a base class for nsIMdbCell, so that cells themselves can
+**| be used to set state in another cell, without extracting a buffer.)
+|*/
+class nsIMdbBlob : public nsISupports { // a string with associated charset
+public:
+
+// { ===== begin nsIMdbBlob methods =====
+
+ // { ----- begin attribute methods -----
+ NS_IMETHOD SetBlob(nsIMdbEnv* ev,
+ nsIMdbBlob* ioBlob) = 0; // reads inBlob slots
+ // when inBlob is in the same suite, this might be fastest cell-to-cell
+
+ NS_IMETHOD ClearBlob( // make empty (so content has zero length)
+ nsIMdbEnv* ev) = 0;
+ // clearing a yarn is like SetYarn() with empty yarn instance content
+
+ NS_IMETHOD GetBlobFill(nsIMdbEnv* ev,
+ mdb_fill* outFill) = 0; // size of blob
+ // Same value that would be put into mYarn_Fill, if one called GetYarn()
+ // with a yarn instance that had mYarn_Buf==nil and mYarn_Size==0.
+
+ NS_IMETHOD SetYarn(nsIMdbEnv* ev,
+ const mdbYarn* inYarn) = 0; // reads from yarn slots
+ // make this text object contain content from the yarn's buffer
+
+ NS_IMETHOD GetYarn(nsIMdbEnv* ev,
+ mdbYarn* outYarn) = 0; // writes some yarn slots
+ // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
+
+ NS_IMETHOD AliasYarn(nsIMdbEnv* ev,
+ mdbYarn* outYarn) = 0; // writes ALL yarn slots
+ // AliasYarn() reveals sensitive internal text buffer state to the caller
+ // by setting mYarn_Buf to point into the guts of this text implementation.
+ //
+ // The caller must take great care to avoid writing on this space, and to
+ // avoid calling any method that would cause the state of this text object
+ // to change (say by directly or indirectly setting the text to hold more
+ // content that might grow the size of the buffer and free the old buffer).
+ // In particular, callers should scrupulously avoid making calls into the
+ // mdb interface to write any content while using the buffer pointer found
+ // in the returned yarn instance. Best safe usage involves copying content
+ // into some other kind of external content representation beyond mdb.
+ //
+ // (The original design of this method a week earlier included the concept
+ // of very fast and efficient cooperative locking via a pointer to some lock
+ // member slot. But let's ignore that complexity in the current design.)
+ //
+ // AliasYarn() is specifically intended as the first step in transferring
+ // content from nsIMdbBlob to a nsString representation, without forcing extra
+ // allocations and/or memory copies. (A standard nsIMdbBlob_AsString() utility
+ // will use AliasYarn() as the first step in setting a nsString instance.)
+ //
+ // This is an alternative to the GetYarn() method, which has copy semantics
+ // only; AliasYarn() relaxes a robust safety principle only for performance
+ // reasons, to accomodate the need for callers to transform text content to
+ // some other canonical representation that would necessitate an additional
+ // copy and transformation when such is incompatible with the mdbYarn format.
+ //
+ // The implementation of AliasYarn() should have extremely little overhead
+ // besides the virtual dispatch to the method implementation, and the code
+ // necessary to populate all the mdbYarn member slots with internal buffer
+ // address and metainformation that describes the buffer content. Note that
+ // mYarn_Grow must always be set to nil to indicate no resizing is allowed.
+
+ // } ----- end attribute methods -----
+
+// } ===== end nsIMdbBlob methods =====
+};
+
+/*| nsIMdbCell: the text in a single column of a row. The base nsIMdbBlob
+**| class provides all the interface related to accessing cell text.
+**|
+**|| column: each cell in a row appears in a specific column, where this
+**| column is identified by the an integer mdb_scope value (generated by
+**| the StringToScopeToken() method in the containing nsIMdbPort instance).
+**| Because a row cannot have more than one cell with the same column,
+**| something must give if one calls SetColumn() with an existing column
+**| in the same row. When this happens, the other cell is replaced with
+**| this cell (and the old cell is closed if it has outstanding refs).
+**|
+**|| row: every cell instance is a part of some row, and every cell knows
+**| which row is the parent row. (Note this should be represented by a
+**| weak backpointer, so that outstanding cell references cannot keep a
+**| row open that should be closed. Otherwise we'd have ref graph cycles.)
+**|
+**|| text: a cell can either be text, or it can have a child row or table,
+**| but not both at once. If text is read from a cell with a child, the text
+**| content should be empty (for AliasYarn()) or a description of the type
+**| of child (perhaps "mdb:cell:child:row" or "mdb:cell:child:table").
+**|
+**|| child: a cell might reference another row or a table, rather than text.
+**| The interface for putting and getting children rows and tables was first
+**| defined in the nsIMdbTable interface, but then this was moved to this cell
+**| interface as more natural.
+|*/
+
+
+
+#define NS_IMDBCELL_IID \
+{0xa3b62f71, 0xa181, 0x4a91, \
+{0xb6, 0x6b, 0x27, 0x10, 0x9b, 0x88, 0x98, 0x35}}
+
+#define NS_IMDBCELL_IID_STR = "a3b62f71-a181-4a91-b66b-27109b889835"
+
+class nsIMdbCell : public nsIMdbBlob { // text attribute in row with column scope
+public:
+
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBTABLEROWCURSOR_IID)
+// { ===== begin nsIMdbCell methods =====
+
+ // { ----- begin attribute methods -----
+ NS_IMETHOD SetColumn(nsIMdbEnv* ev, mdb_column inColumn) = 0;
+ NS_IMETHOD GetColumn(nsIMdbEnv* ev, mdb_column* outColumn) = 0;
+
+ NS_IMETHOD GetCellInfo( // all cell metainfo except actual content
+ nsIMdbEnv* ev,
+ mdb_column* outColumn, // the column in the containing row
+ mdb_fill* outBlobFill, // the size of text content in bytes
+ mdbOid* outChildOid, // oid of possible row or table child
+ mdb_bool* outIsRowChild) = 0; // nonzero if child, and a row child
+
+ // Checking all cell metainfo is a good way to avoid forcing a large cell
+ // in to memory when you don't actually want to use the content.
+
+ NS_IMETHOD GetRow(nsIMdbEnv* ev, // parent row for this cell
+ nsIMdbRow** acqRow) = 0;
+ NS_IMETHOD GetPort(nsIMdbEnv* ev, // port containing cell
+ nsIMdbPort** acqPort) = 0;
+ // } ----- end attribute methods -----
+
+ // { ----- begin children methods -----
+ NS_IMETHOD HasAnyChild( // does cell have a child instead of text?
+ nsIMdbEnv* ev,
+ mdbOid* outOid, // out id of row or table (or unbound if no child)
+ mdb_bool* outIsRow) = 0; // nonzero if child is a row (rather than a table)
+
+ NS_IMETHOD GetAnyChild( // access table of specific attribute
+ nsIMdbEnv* ev, // context
+ nsIMdbRow** acqRow, // child row (or null)
+ nsIMdbTable** acqTable) = 0; // child table (or null)
+
+
+ NS_IMETHOD SetChildRow( // access table of specific attribute
+ nsIMdbEnv* ev, // context
+ nsIMdbRow* ioRow) = 0; // inRow must be bound inside this same db port
+
+ NS_IMETHOD GetChildRow( // access row of specific attribute
+ nsIMdbEnv* ev, // context
+ nsIMdbRow** acqRow) = 0; // acquire child row (or nil if no child)
+
+
+ NS_IMETHOD SetChildTable( // access table of specific attribute
+ nsIMdbEnv* ev, // context
+ nsIMdbTable* inTable) = 0; // table must be bound inside this same db port
+
+ NS_IMETHOD GetChildTable( // access table of specific attribute
+ nsIMdbEnv* ev, // context
+ nsIMdbTable** acqTable) = 0; // acquire child table (or nil if no child)
+ // } ----- end children methods -----
+
+// } ===== end nsIMdbCell methods =====
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbCell, NS_IMDBTABLEROWCURSOR_IID)
+
+// } %%%%% end C++ abstract class interfaces %%%%%
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#endif /* _MDB_ */
+
new file mode 100644
--- /dev/null
+++ b/db/mork/src/Makefile.in
@@ -0,0 +1,100 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = mork
+LIBRARY_NAME = msgmork_s
+FORCE_STATIC_LIB=1
+LIBXUL_LIBRARY = 1
+
+CPPSRCS = \
+ orkinHeap.cpp \
+ morkArray.cpp \
+ morkAtom.cpp \
+ morkAtomMap.cpp \
+ morkAtomSpace.cpp \
+ morkBlob.cpp \
+ morkBuilder.cpp \
+ morkCell.cpp \
+ morkCellObject.cpp \
+ morkCh.cpp \
+ morkConfig.cpp \
+ morkCursor.cpp \
+ morkDeque.cpp \
+ morkEnv.cpp \
+ morkFactory.cpp \
+ morkFile.cpp \
+ morkHandle.cpp \
+ morkIntMap.cpp \
+ morkMap.cpp \
+ morkNode.cpp \
+ morkNodeMap.cpp \
+ morkObject.cpp \
+ morkParser.cpp \
+ morkPool.cpp \
+ morkRow.cpp \
+ morkRowCellCursor.cpp \
+ morkRowMap.cpp \
+ morkRowObject.cpp \
+ morkRowSpace.cpp \
+ morkSink.cpp \
+ morkSpace.cpp \
+ morkStore.cpp \
+ morkStream.cpp \
+ morkTable.cpp \
+ morkPortTableCursor.cpp \
+ morkTableRowCursor.cpp \
+ morkThumb.cpp \
+ morkWriter.cpp \
+ morkYarn.cpp \
+ morkBead.cpp \
+ morkProbeMap.cpp \
+ morkZone.cpp \
+ $(NULL)
+
+ifeq ($(OS_ARCH),WINNT)
+CPPSRCS += morkSearchRowCursor.cpp
+endif
+
+include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/db/mork/src/mork.h
@@ -0,0 +1,249 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MORK_
+#define _MORK_ 1
+
+#ifndef _MDB_
+#include "mdb.h"
+#endif
+
+#include "nscore.h"
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+
+// { %%%%% begin disable unused param warnings %%%%%
+#define MORK_USED_1(x) (void)(&x)
+#define MORK_USED_2(x,y) (void)(&x);(void)(&y);
+#define MORK_USED_3(x,y,z) (void)(&x);(void)(&y);(void)(&z);
+#define MORK_USED_4(w,x,y,z) (void)(&w);(void)(&x);(void)(&y);(void)(&z);
+
+// } %%%%% end disable unused param warnings %%%%%
+
+// { %%%%% begin macro for finding class member offset %%%%%
+
+/*| OffsetOf: the unsigned integer offset of a class or struct
+**| field from the beginning of that class or struct. This is
+**| the same as the similarly named public domain IronDoc macro,
+**| and is also the same as another macro appearing in stdlib.h.
+**| We want these offsets so we can correctly convert pointers
+**| to member slots back into pointers to enclosing objects, and
+**| have this exactly match what the compiler thinks is true.
+**|
+**|| Bascially we are asking the compiler to determine the offset at
+**| compile time, and we use the definition of address artithmetic
+**| to do this. By casting integer zero to a pointer of type obj*,
+**| we can reference the address of a slot in such an object that
+**| is hypothetically physically placed at address zero, but without
+**| actually dereferencing a memory location. The absolute address
+**| of slot is the same as offset of that slot, when the object is
+**| placed at address zero.
+|*/
+#define mork_OffsetOf(obj,slot) ((unsigned int)&((obj*) 0)->slot)
+
+// } %%%%% end macro for finding class member offset %%%%%
+
+// { %%%%% begin specific-size integer scalar typedefs %%%%%
+typedef unsigned char mork_u1; // make sure this is one byte
+typedef unsigned short mork_u2; // make sure this is two bytes
+typedef short mork_i2; // make sure this is two bytes
+typedef PRUint32 mork_u4; // make sure this is four bytes
+typedef PRInt32 mork_i4; // make sure this is four bytes
+typedef PRWord mork_ip; // make sure sizeof(mork_ip) == sizeof(void*)
+
+typedef mork_u1 mork_ch; // small byte-sized character (never wide)
+typedef mork_u1 mork_flags; // one byte's worth of predicate bit flags
+
+typedef mork_u2 mork_base; // 2-byte magic class signature slot in object
+typedef mork_u2 mork_derived; // 2-byte magic class signature slot in object
+typedef mork_u2 mork_uses; // 2-byte strong uses count
+typedef mork_u2 mork_refs; // 2-byte actual reference count
+
+typedef mork_u4 mork_token; // unsigned token for atomized string
+typedef mork_token mork_scope; // token used to id scope for rows
+typedef mork_token mork_kind; // token used to id kind for tables
+typedef mork_token mork_cscode; // token used to id charset names
+typedef mork_token mork_aid; // token used to id atomize cell values
+
+typedef mork_token mork_column; // token used to id columns for rows
+typedef mork_column mork_delta; // mork_column plus mork_change
+
+typedef mork_token mork_color; // bead ID
+#define morkColor_kNone ((mork_color) 0)
+
+typedef mork_u4 mork_magic; // unsigned magic signature
+
+typedef mork_u4 mork_seed; // unsigned collection change counter
+typedef mork_u4 mork_count; // unsigned collection member count
+typedef mork_count mork_num; // synonym for count
+typedef mork_u4 mork_size; // unsigned physical media size
+typedef mork_u4 mork_fill; // unsigned logical content size
+typedef mork_u4 mork_more; // more available bytes for larger buffer
+
+typedef mdb_u4 mork_percent; // 0..100, with values >100 same as 100
+
+typedef mork_i4 mork_pos; // negative means "before first" (at zero pos)
+typedef mork_i4 mork_line; // negative means "before first line in file"
+
+typedef mork_u1 mork_usage; // 1-byte magic usage signature slot in object
+typedef mork_u1 mork_access; // 1-byte magic access signature slot in object
+
+typedef mork_u1 mork_change; // add, cut, put, set, nil
+typedef mork_u1 mork_priority; // 0..9, for a total of ten different values
+
+typedef mork_u1 mork_able; // on, off, asleep (clone IronDoc's fe_able)
+typedef mork_u1 mork_load; // dirty or clean (clone IronDoc's fe_load)
+// } %%%%% end specific-size integer scalar typedefs %%%%%
+
+// 'test' is a public domain Mithril for key equality tests in probe maps
+typedef mork_i2 mork_test; /* neg=>kVoid, zero=>kHit, pos=>kMiss */
+
+#define morkTest_kVoid ((mork_test) -1) /* -1: nil key slot, no key order */
+#define morkTest_kHit ((mork_test) 0) /* 0: keys are equal, a map hit */
+#define morkTest_kMiss ((mork_test) 1) /* 1: keys not equal, a map miss */
+
+// { %%%%% begin constants for Mork scalar types %%%%%
+#define morkPriority_kHi ((mork_priority) 0) /* best priority */
+#define morkPriority_kMin ((mork_priority) 0) /* best priority is smallest */
+
+#define morkPriority_kLo ((mork_priority) 9) /* worst priority */
+#define morkPriority_kMax ((mork_priority) 9) /* worst priority is biggest */
+
+#define morkPriority_kCount 10 /* number of distinct priority values */
+
+#define morkAble_kEnabled ((mork_able) 0x55) /* same as IronDoc constant */
+#define morkAble_kDisabled ((mork_able) 0xAA) /* same as IronDoc constant */
+#define morkAble_kAsleep ((mork_able) 0x5A) /* same as IronDoc constant */
+
+#define morkChange_kAdd 'a' /* add member */
+#define morkChange_kCut 'c' /* cut member */
+#define morkChange_kPut 'p' /* put member */
+#define morkChange_kSet 's' /* set all members */
+#define morkChange_kNil 0 /* no change in this member */
+#define morkChange_kDup 'd' /* duplicate changes have no effect */
+// kDup is intended to replace another change constant in an object as a
+// conclusion about change feasibility while staging intended alterations.
+
+#define morkLoad_kDirty ((mork_load) 0xDD) /* same as IronDoc constant */
+#define morkLoad_kClean ((mork_load) 0x22) /* same as IronDoc constant */
+
+#define morkAccess_kOpen 'o'
+#define morkAccess_kClosing 'c'
+#define morkAccess_kShut 's'
+#define morkAccess_kDead 'd'
+// } %%%%% end constants for Mork scalar types %%%%%
+
+// { %%%%% begin non-specific-size integer scalar typedefs %%%%%
+typedef int mork_char; // nominal type for ints used to hold input byte
+#define morkChar_IsWhite(c) \
+ ((c) == 0xA || (c) == 0x9 || (c) == 0xD || (c) == ' ')
+// } %%%%% end non-specific-size integer scalar typedefs %%%%%
+
+// { %%%%% begin mdb-driven scalar typedefs %%%%%
+// easier to define bool exactly the same as mdb:
+typedef mdb_bool mork_bool; // unsigned byte with zero=false, nonzero=true
+
+/* canonical boolean constants provided only for code clarity: */
+#define morkBool_kTrue ((mork_bool) 1) /* actually any nonzero means true */
+#define morkBool_kFalse ((mork_bool) 0) /* only zero means false */
+
+// mdb clients can assign these, so we cannot pick maximum size:
+typedef mdb_id mork_id; // unsigned object identity in a scope
+typedef mork_id mork_rid; // unsigned row identity inside scope
+typedef mork_id mork_tid; // unsigned table identity inside scope
+typedef mork_id mork_gid; // unsigned group identity without any scope
+
+// we only care about neg, zero, pos -- so we don't care about size:
+typedef mdb_order mork_order; // neg:lessthan, zero:equalto, pos:greaterthan
+// } %%%%% end mdb-driven scalar typedefs %%%%%
+
+#define morkId_kMinusOne ((mdb_id) -1)
+
+// { %%%%% begin class forward defines %%%%%
+// try to put these in alphabetical order for easier examination:
+class morkMid;
+class morkAtom;
+class morkAtomSpace;
+class morkBookAtom;
+class morkBuf;
+class morkBuilder;
+class morkCell;
+class morkCellObject;
+class morkCursor;
+class morkEnv;
+class morkFactory;
+class morkFile;
+class morkHandle;
+class morkHandleFace; // just an opaque cookie type
+class morkHandleFrame;
+class morkHashArrays;
+class morkMap;
+class morkNode;
+class morkObject;
+class morkOidAtom;
+class morkParser;
+class morkPool;
+class morkPlace;
+class morkPort;
+class morkPortTableCursor;
+class morkProbeMap;
+class morkRow;
+class morkRowCellCursor;
+class morkRowObject;
+class morkRowSpace;
+class morkSorting;
+class morkSortingRowCursor;
+class morkSpace;
+class morkSpan;
+class morkStore;
+class morkStream;
+class morkTable;
+class morkTableChange;
+class morkTableRowCursor;
+class morkThumb;
+class morkWriter;
+class morkZone;
+// } %%%%% end class forward defines %%%%%
+
+// include this config file last for platform & environment specific stuff:
+#ifndef _MORKCONFIG_
+#include "morkConfig.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#endif /* _MORK_ */
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkArray.cpp
@@ -0,0 +1,334 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nscore.h"
+
+#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 _MORKARRAY_
+#include "morkArray.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void
+morkArray::CloseMorkNode(morkEnv* ev) // CloseTable() only if open
+{
+ if ( this->IsOpenNode() )
+ {
+ this->MarkClosing();
+ this->CloseArray(ev);
+ this->MarkShut();
+ }
+}
+
+/*public virtual*/
+morkArray::~morkArray() // assert CloseTable() executed earlier
+{
+ MORK_ASSERT(this->IsShutNode());
+ MORK_ASSERT(mArray_Slots==0);
+}
+
+/*public non-poly*/
+morkArray::morkArray(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, mork_size inSize, nsIMdbHeap* ioSlotHeap)
+: morkNode(ev, inUsage, ioHeap)
+, mArray_Slots( 0 )
+, mArray_Heap( 0 )
+, mArray_Fill( 0 )
+, mArray_Size( 0 )
+, mArray_Seed( (mork_u4)NS_PTR_TO_INT32(this) ) // "random" integer assignment
+{
+ if ( ev->Good() )
+ {
+ if ( ioSlotHeap )
+ {
+ nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mArray_Heap);
+ if ( ev->Good() )
+ {
+ if ( inSize < 3 )
+ inSize = 3;
+ mdb_size byteSize = inSize * sizeof(void*);
+ void** block = 0;
+ ioSlotHeap->Alloc(ev->AsMdbEnv(), byteSize, (void**) &block);
+ if ( block && ev->Good() )
+ {
+ mArray_Slots = block;
+ mArray_Size = inSize;
+ MORK_MEMSET(mArray_Slots, 0, byteSize);
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kArray;
+ }
+ }
+ }
+ else
+ ev->NilPointerError();
+ }
+}
+
+/*public non-poly*/ void
+morkArray::CloseArray(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this )
+ {
+ if ( this->IsNode() )
+ {
+ if ( mArray_Heap && mArray_Slots )
+ mArray_Heap->Free(ev->AsMdbEnv(), mArray_Slots);
+
+ mArray_Slots = 0;
+ mArray_Size = 0;
+ mArray_Fill = 0;
+ ++mArray_Seed;
+ nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mArray_Heap);
+ this->MarkShut();
+ }
+ else
+ this->NonNodeError(ev);
+ }
+ else
+ ev->NilPointerError();
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+
+/*static*/ void
+morkArray::NonArrayTypeError(morkEnv* ev)
+{
+ ev->NewError("non morkArray");
+}
+
+/*static*/ void
+morkArray::IndexBeyondEndError(morkEnv* ev)
+{
+ ev->NewError("array index beyond end");
+}
+
+/*static*/ void
+morkArray::NilSlotsAddressError(morkEnv* ev)
+{
+ ev->NewError("nil mArray_Slots");
+}
+
+/*static*/ void
+morkArray::FillBeyondSizeError(morkEnv* ev)
+{
+ ev->NewError("mArray_Fill > mArray_Size");
+}
+
+mork_bool
+morkArray::Grow(morkEnv* ev, mork_size inNewSize)
+// Grow() returns true if capacity becomes >= inNewSize and ev->Good()
+{
+ if ( ev->Good() && inNewSize > mArray_Size ) // make array larger?
+ {
+ if ( mArray_Fill <= mArray_Size ) // fill and size fit the invariant?
+ {
+ if (mArray_Size <= 3)
+ inNewSize = mArray_Size + 3;
+ else
+ inNewSize = mArray_Size * 2;// + 3; // try doubling size here - used to grow by 3
+
+ mdb_size newByteSize = inNewSize * sizeof(void*);
+ void** newBlock = 0;
+ mArray_Heap->Alloc(ev->AsMdbEnv(), newByteSize, (void**) &newBlock);
+ if ( newBlock && ev->Good() ) // okay new block?
+ {
+ void** oldSlots = mArray_Slots;
+ void** oldEnd = oldSlots + mArray_Fill;
+
+ void** newSlots = newBlock;
+ void** newEnd = newBlock + inNewSize;
+
+ while ( oldSlots < oldEnd )
+ *newSlots++ = *oldSlots++;
+
+ while ( newSlots < newEnd )
+ *newSlots++ = (void*) 0;
+
+ oldSlots = mArray_Slots;
+ mArray_Size = inNewSize;
+ mArray_Slots = newBlock;
+ mArray_Heap->Free(ev->AsMdbEnv(), oldSlots);
+ }
+ }
+ else
+ this->FillBeyondSizeError(ev);
+ }
+ ++mArray_Seed; // always modify seed, since caller intends to add slots
+ return ( ev->Good() && mArray_Size >= inNewSize );
+}
+
+void*
+morkArray::SafeAt(morkEnv* ev, mork_pos inPos)
+{
+ if ( mArray_Slots )
+ {
+ if ( inPos >= 0 && inPos < (mork_pos) mArray_Fill )
+ return mArray_Slots[ inPos ];
+ else
+ this->IndexBeyondEndError(ev);
+ }
+ else
+ this->NilSlotsAddressError(ev);
+
+ return (void*) 0;
+}
+
+void
+morkArray::SafeAtPut(morkEnv* ev, mork_pos inPos, void* ioSlot)
+{
+ if ( mArray_Slots )
+ {
+ if ( inPos >= 0 && inPos < (mork_pos) mArray_Fill )
+ {
+ mArray_Slots[ inPos ] = ioSlot;
+ ++mArray_Seed;
+ }
+ else
+ this->IndexBeyondEndError(ev);
+ }
+ else
+ this->NilSlotsAddressError(ev);
+}
+
+mork_pos
+morkArray::AppendSlot(morkEnv* ev, void* ioSlot)
+{
+ mork_pos outPos = -1;
+ if ( mArray_Slots )
+ {
+ mork_fill fill = mArray_Fill;
+ if ( this->Grow(ev, fill+1) )
+ {
+ outPos = (mork_pos) fill;
+ mArray_Slots[ fill ] = ioSlot;
+ mArray_Fill = fill + 1;
+ // note Grow() increments mArray_Seed
+ }
+ }
+ else
+ this->NilSlotsAddressError(ev);
+
+ return outPos;
+}
+
+void
+morkArray::AddSlot(morkEnv* ev, mork_pos inPos, void* ioSlot)
+{
+ if ( mArray_Slots )
+ {
+ mork_fill fill = mArray_Fill;
+ if ( this->Grow(ev, fill+1) )
+ {
+ void** slot = mArray_Slots; // the slot vector
+ void** end = slot + fill; // one past the last used array slot
+ slot += inPos; // the slot to be added
+
+ while ( --end >= slot ) // another slot to move upward?
+ end[ 1 ] = *end;
+
+ *slot = ioSlot;
+ mArray_Fill = fill + 1;
+ // note Grow() increments mArray_Seed
+ }
+ }
+ else
+ this->NilSlotsAddressError(ev);
+}
+
+void
+morkArray::CutSlot(morkEnv* ev, mork_pos inPos)
+{
+ MORK_USED_1(ev);
+ mork_fill fill = mArray_Fill;
+ if ( inPos >= 0 && inPos < (mork_pos) fill ) // cutting slot in used array portion?
+ {
+ void** slot = mArray_Slots; // the slot vector
+ void** end = slot + fill; // one past the last used array slot
+ slot += inPos; // the slot to be cut
+
+ while ( ++slot < end ) // another slot to move downward?
+ slot[ -1 ] = *slot;
+
+ slot[ -1 ] = 0; // clear the last used slot which is now unused
+
+ // note inPos<fill implies fill>0, so fill-1 must be nonnegative:
+ mArray_Fill = fill - 1;
+ ++mArray_Seed;
+ }
+}
+
+void
+morkArray::CutAllSlots(morkEnv* ev)
+{
+ if ( mArray_Slots )
+ {
+ if ( mArray_Fill <= mArray_Size )
+ {
+ mdb_size oldByteSize = mArray_Fill * sizeof(void*);
+ MORK_MEMSET(mArray_Slots, 0, oldByteSize);
+ }
+ else
+ this->FillBeyondSizeError(ev);
+ }
+ else
+ this->NilSlotsAddressError(ev);
+
+ ++mArray_Seed;
+ mArray_Fill = 0;
+}
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkArray.h
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MORKARRAY_
+#define _MORKARRAY_ 1
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKNODE_
+#include "morkNode.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#define morkDerived_kArray /*i*/ 0x4179 /* ascii 'Ay' */
+
+class morkArray : public morkNode { // row iterator
+
+// public: // slots inherited from morkObject (meant to inform only)
+ // nsIMdbHeap* mNode_Heap;
+ // mork_able mNode_Mutable; // can this node be modified?
+ // mork_load mNode_Load; // is this node clean or dirty?
+ // mork_base mNode_Base; // must equal morkBase_kNode
+ // mork_derived mNode_Derived; // depends on specific node subclass
+ // mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
+ // mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
+ // mork_uses mNode_Uses; // refcount for strong refs
+ // mork_refs mNode_Refs; // refcount for strong refs + weak refs
+
+public: // state is public because the entire Mork system is private
+ void** mArray_Slots; // array of pointers
+ nsIMdbHeap* mArray_Heap; // required heap for allocating mArray_Slots
+ mork_fill mArray_Fill; // logical count of used slots in mArray_Slots
+ mork_size mArray_Size; // physical count of mArray_Slots ( >= Fill)
+ mork_seed mArray_Seed; // change counter for syncing with iterators
+
+// { ===== begin morkNode interface =====
+public: // morkNode virtual methods
+ virtual void CloseMorkNode(morkEnv* ev); // CloseArray()
+ virtual ~morkArray(); // assert that close executed earlier
+
+public: // morkArray construction & destruction
+ morkArray(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, mork_size inSize, nsIMdbHeap* ioSlotHeap);
+ void CloseArray(morkEnv* ev); // called by CloseMorkNode();
+
+private: // copying is not allowed
+ morkArray(const morkArray& other);
+ morkArray& operator=(const morkArray& other);
+
+public: // dynamic type identification
+ mork_bool IsArray() const
+ { return IsNode() && mNode_Derived == morkDerived_kArray; }
+// } ===== end morkNode methods =====
+
+public: // typing & errors
+ static void NonArrayTypeError(morkEnv* ev);
+ static void IndexBeyondEndError(morkEnv* ev);
+ static void NilSlotsAddressError(morkEnv* ev);
+ static void FillBeyondSizeError(morkEnv* ev);
+
+public: // other table row cursor methods
+
+ mork_fill Length() const { return mArray_Fill; }
+ mork_size Capacity() const { return mArray_Size; }
+
+ mork_bool Grow(morkEnv* ev, mork_size inNewSize);
+ // Grow() returns true if capacity becomes >= inNewSize and ev->Good()
+
+ void* At(mork_pos inPos) const { return mArray_Slots[ inPos ]; }
+ void AtPut(mork_pos inPos, void* ioSlot)
+ { mArray_Slots[ inPos ] = ioSlot; }
+
+ void* SafeAt(morkEnv* ev, mork_pos inPos);
+ void SafeAtPut(morkEnv* ev, mork_pos inPos, void* ioSlot);
+
+ mork_pos AppendSlot(morkEnv* ev, void* ioSlot);
+ void AddSlot(morkEnv* ev, mork_pos inPos, void* ioSlot);
+ void CutSlot(morkEnv* ev, mork_pos inPos);
+ void CutAllSlots(morkEnv* ev);
+
+public: // typesafe refcounting inlines calling inherited morkNode methods
+ static void SlotWeakArray(morkArray* me,
+ morkEnv* ev, morkArray** ioSlot)
+ { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+
+ static void SlotStrongArray(morkArray* me,
+ morkEnv* ev, morkArray** ioSlot)
+ { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#endif /* _MORKTABLEROWCURSOR_ */
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkAtom.cpp
@@ -0,0 +1,604 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MDB_
+#include "mdb.h"
+#endif
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKBLOB_
+#include "morkBlob.h"
+#endif
+
+#ifndef _MORKATOM_
+#include "morkAtom.h"
+#endif
+
+#ifndef _MORKENV_
+#include "morkEnv.h"
+#endif
+
+#ifndef _MORKATOMSPACE_
+#include "morkAtomSpace.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+mork_bool
+morkAtom::GetYarn(mdbYarn* outYarn) const
+{
+ const void* source = 0;
+ mdb_fill fill = 0;
+ mdb_cscode form = 0;
+ outYarn->mYarn_More = 0;
+
+ if ( this )
+ {
+ if ( this->IsWeeBook() )
+ {
+ morkWeeBookAtom* weeBook = (morkWeeBookAtom*) this;
+ source = weeBook->mWeeBookAtom_Body;
+ fill = weeBook->mAtom_Size;
+ }
+ else if ( this->IsBigBook() )
+ {
+ morkBigBookAtom* bigBook = (morkBigBookAtom*) this;
+ source = bigBook->mBigBookAtom_Body;
+ fill = bigBook->mBigBookAtom_Size;
+ form = bigBook->mBigBookAtom_Form;
+ }
+ else if ( this->IsWeeAnon() )
+ {
+ morkWeeAnonAtom* weeAnon = (morkWeeAnonAtom*) this;
+ source = weeAnon->mWeeAnonAtom_Body;
+ fill = weeAnon->mAtom_Size;
+ }
+ else if ( this->IsBigAnon() )
+ {
+ morkBigAnonAtom* bigAnon = (morkBigAnonAtom*) this;
+ source = bigAnon->mBigAnonAtom_Body;
+ fill = bigAnon->mBigAnonAtom_Size;
+ form = bigAnon->mBigAnonAtom_Form;
+ }
+ }
+ if ( source && fill ) // have an atom with nonempty content?
+ {
+ // if we have too many bytes, and yarn seems growable:
+ if ( fill > outYarn->mYarn_Size && outYarn->mYarn_Grow ) // try grow?
+ (*outYarn->mYarn_Grow)(outYarn, (mdb_size) fill); // request bigger
+
+ mdb_size size = outYarn->mYarn_Size; // max dest size
+ if ( fill > size ) // too much atom content?
+ {
+ outYarn->mYarn_More = fill - size; // extra atom bytes omitted
+ fill = size; // copy no more bytes than size of yarn buffer
+ }
+ void* dest = outYarn->mYarn_Buf; // where bytes are going
+ if ( !dest ) // nil destination address buffer?
+ fill = 0; // we can't write any content at all
+
+ if ( fill ) // anything to copy?
+ MORK_MEMCPY(dest, source, fill); // copy fill bytes to yarn
+
+ outYarn->mYarn_Fill = fill; // tell yarn size of copied content
+ }
+ else // no content to put into the yarn
+ {
+ outYarn->mYarn_Fill = 0; // tell yarn that atom has no bytes
+ }
+ outYarn->mYarn_Form = form; // always update the form slot
+
+ return ( source != 0 );
+}
+
+mork_bool
+morkAtom::AsBuf(morkBuf& outBuf) const
+{
+ const morkAtom* atom = this;
+ if ( atom )
+ {
+ if ( atom->IsWeeBook() )
+ {
+ morkWeeBookAtom* weeBook = (morkWeeBookAtom*) atom;
+ outBuf.mBuf_Body = weeBook->mWeeBookAtom_Body;
+ outBuf.mBuf_Fill = weeBook->mAtom_Size;
+ }
+ else if ( atom->IsBigBook() )
+ {
+ morkBigBookAtom* bigBook = (morkBigBookAtom*) atom;
+ outBuf.mBuf_Body = bigBook->mBigBookAtom_Body;
+ outBuf.mBuf_Fill = bigBook->mBigBookAtom_Size;
+ }
+ else if ( atom->IsWeeAnon() )
+ {
+ morkWeeAnonAtom* weeAnon = (morkWeeAnonAtom*) atom;
+ outBuf.mBuf_Body = weeAnon->mWeeAnonAtom_Body;
+ outBuf.mBuf_Fill = weeAnon->mAtom_Size;
+ }
+ else if ( atom->IsBigAnon() )
+ {
+ morkBigAnonAtom* bigAnon = (morkBigAnonAtom*) atom;
+ outBuf.mBuf_Body = bigAnon->mBigAnonAtom_Body;
+ outBuf.mBuf_Fill = bigAnon->mBigAnonAtom_Size;
+ }
+ else
+ atom = 0; // show desire to put empty content in yarn
+ }
+
+ if ( !atom ) // empty content for yarn?
+ {
+ outBuf.mBuf_Body = 0;
+ outBuf.mBuf_Fill = 0;
+ }
+ return ( atom != 0 );
+}
+
+mork_bool
+morkAtom::AliasYarn(mdbYarn* outYarn) const
+{
+ outYarn->mYarn_More = 0;
+ outYarn->mYarn_Form = 0;
+ const morkAtom* atom = this;
+
+ if ( atom )
+ {
+ if ( atom->IsWeeBook() )
+ {
+ morkWeeBookAtom* weeBook = (morkWeeBookAtom*) atom;
+ outYarn->mYarn_Buf = weeBook->mWeeBookAtom_Body;
+ outYarn->mYarn_Fill = weeBook->mAtom_Size;
+ outYarn->mYarn_Size = weeBook->mAtom_Size;
+ }
+ else if ( atom->IsBigBook() )
+ {
+ morkBigBookAtom* bigBook = (morkBigBookAtom*) atom;
+ outYarn->mYarn_Buf = bigBook->mBigBookAtom_Body;
+ outYarn->mYarn_Fill = bigBook->mBigBookAtom_Size;
+ outYarn->mYarn_Size = bigBook->mBigBookAtom_Size;
+ outYarn->mYarn_Form = bigBook->mBigBookAtom_Form;
+ }
+ else if ( atom->IsWeeAnon() )
+ {
+ morkWeeAnonAtom* weeAnon = (morkWeeAnonAtom*) atom;
+ outYarn->mYarn_Buf = weeAnon->mWeeAnonAtom_Body;
+ outYarn->mYarn_Fill = weeAnon->mAtom_Size;
+ outYarn->mYarn_Size = weeAnon->mAtom_Size;
+ }
+ else if ( atom->IsBigAnon() )
+ {
+ morkBigAnonAtom* bigAnon = (morkBigAnonAtom*) atom;
+ outYarn->mYarn_Buf = bigAnon->mBigAnonAtom_Body;
+ outYarn->mYarn_Fill = bigAnon->mBigAnonAtom_Size;
+ outYarn->mYarn_Size = bigAnon->mBigAnonAtom_Size;
+ outYarn->mYarn_Form = bigAnon->mBigAnonAtom_Form;
+ }
+ else
+ atom = 0; // show desire to put empty content in yarn
+ }
+
+ if ( !atom ) // empty content for yarn?
+ {
+ outYarn->mYarn_Buf = 0;
+ outYarn->mYarn_Fill = 0;
+ outYarn->mYarn_Size = 0;
+ // outYarn->mYarn_Grow = 0; // please don't modify the Grow slot
+ }
+ return ( atom != 0 );
+}
+
+mork_aid
+morkAtom::GetBookAtomAid() const // zero or book atom's ID
+{
+ return ( this->IsBook() )? ((morkBookAtom*) this)->mBookAtom_Id : 0;
+}
+
+mork_scope
+morkAtom::GetBookAtomSpaceScope(morkEnv* ev) const // zero or book's space's scope
+{
+ mork_scope outScope = 0;
+ if ( this->IsBook() )
+ {
+ const morkBookAtom* bookAtom = (const morkBookAtom*) this;
+ morkAtomSpace* space = bookAtom->mBookAtom_Space;
+ if ( space->IsAtomSpace() )
+ outScope = space->SpaceScope();
+ else
+ space->NonAtomSpaceTypeError(ev);
+ }
+
+ return outScope;
+}
+
+void
+morkAtom::MakeCellUseForever(morkEnv* ev)
+{
+ MORK_USED_1(ev);
+ mAtom_CellUses = morkAtom_kForeverCellUses;
+}
+
+mork_u1
+morkAtom::AddCellUse(morkEnv* ev)
+{
+ MORK_USED_1(ev);
+ if ( mAtom_CellUses < morkAtom_kMaxCellUses ) // not already maxed out?
+ ++mAtom_CellUses;
+
+ return mAtom_CellUses;
+}
+
+mork_u1
+morkAtom::CutCellUse(morkEnv* ev)
+{
+ if ( mAtom_CellUses ) // any outstanding uses to cut?
+ {
+ if ( mAtom_CellUses < morkAtom_kMaxCellUses ) // not frozen at max?
+ --mAtom_CellUses;
+ }
+ else
+ this->CellUsesUnderflowWarning(ev);
+
+ return mAtom_CellUses;
+}
+
+/*static*/ void
+morkAtom::CellUsesUnderflowWarning(morkEnv* ev)
+{
+ ev->NewWarning("mAtom_CellUses underflow");
+}
+
+/*static*/ void
+morkAtom::BadAtomKindError(morkEnv* ev)
+{
+ ev->NewError("bad mAtom_Kind");
+}
+
+/*static*/ void
+morkAtom::ZeroAidError(morkEnv* ev)
+{
+ ev->NewError("zero atom ID");
+}
+
+/*static*/ void
+morkAtom::AtomSizeOverflowError(morkEnv* ev)
+{
+ ev->NewError("atom mAtom_Size overflow");
+}
+
+void
+morkOidAtom::InitRowOidAtom(morkEnv* ev, const mdbOid& inOid)
+{
+ MORK_USED_1(ev);
+ mAtom_CellUses = 0;
+ mAtom_Kind = morkAtom_kKindRowOid;
+ mAtom_Change = morkChange_kNil;
+ mAtom_Size = 0;
+ mOidAtom_Oid = inOid; // bitwise copy
+}
+
+void
+morkOidAtom::InitTableOidAtom(morkEnv* ev, const mdbOid& inOid)
+{
+ MORK_USED_1(ev);
+ mAtom_CellUses = 0;
+ mAtom_Kind = morkAtom_kKindTableOid;
+ mAtom_Change = morkChange_kNil;
+ mAtom_Size = 0;
+ mOidAtom_Oid = inOid; // bitwise copy
+}
+
+void
+morkWeeAnonAtom::InitWeeAnonAtom(morkEnv* ev, const morkBuf& inBuf)
+{
+ mAtom_Kind = 0;
+ mAtom_Change = morkChange_kNil;
+ if ( inBuf.mBuf_Fill <= morkAtom_kMaxByteSize )
+ {
+ mAtom_CellUses = 0;
+ mAtom_Kind = morkAtom_kKindWeeAnon;
+ mork_size size = inBuf.mBuf_Fill;
+ mAtom_Size = (mork_u1) size;
+ if ( size && inBuf.mBuf_Body )
+ MORK_MEMCPY(mWeeAnonAtom_Body, inBuf.mBuf_Body, size);
+
+ mWeeAnonAtom_Body[ size ] = 0;
+ }
+ else
+ this->AtomSizeOverflowError(ev);
+}
+
+void
+morkBigAnonAtom::InitBigAnonAtom(morkEnv* ev, const morkBuf& inBuf,
+ mork_cscode inForm)
+{
+ MORK_USED_1(ev);
+ mAtom_CellUses = 0;
+ mAtom_Kind = morkAtom_kKindBigAnon;
+ mAtom_Change = morkChange_kNil;
+ mAtom_Size = 0;
+ mBigAnonAtom_Form = inForm;
+ mork_size size = inBuf.mBuf_Fill;
+ mBigAnonAtom_Size = size;
+ if ( size && inBuf.mBuf_Body )
+ MORK_MEMCPY(mBigAnonAtom_Body, inBuf.mBuf_Body, size);
+
+ mBigAnonAtom_Body[ size ] = 0;
+}
+
+/*static*/ void
+morkBookAtom::NonBookAtomTypeError(morkEnv* ev)
+{
+ ev->NewError("non morkBookAtom");
+}
+
+mork_u4
+morkBookAtom::HashFormAndBody(morkEnv* ev) const
+{
+ // This hash is obviously a variation of the dragon book string hash.
+ // (I won't bother to explain or rationalize this usage for you.)
+
+ register mork_u4 outHash = 0; // hash value returned
+ register unsigned char c; // next character
+ register const mork_u1* body; // body of bytes to hash
+ mork_size size = 0; // the number of bytes to hash
+
+ if ( this->IsWeeBook() )
+ {
+ size = mAtom_Size;
+ body = ((const morkWeeBookAtom*) this)->mWeeBookAtom_Body;
+ }
+ else if ( this->IsBigBook() )
+ {
+ size = ((const morkBigBookAtom*) this)->mBigBookAtom_Size;
+ body = ((const morkBigBookAtom*) this)->mBigBookAtom_Body;
+ }
+ else if ( this->IsFarBook() )
+ {
+ size = ((const morkFarBookAtom*) this)->mFarBookAtom_Size;
+ body = ((const morkFarBookAtom*) this)->mFarBookAtom_Body;
+ }
+ else
+ {
+ this->NonBookAtomTypeError(ev);
+ return 0;
+ }
+
+ const mork_u1* end = body + size;
+ while ( body < end )
+ {
+ c = *body++;
+ outHash <<= 4;
+ outHash += c;
+ mork_u4 top = outHash & 0xF0000000L; // top four bits
+ if ( top ) // any of high four bits equal to one?
+ {
+ outHash ^= (top >> 24); // fold down high bits
+ outHash ^= top; // zero top four bits
+ }
+ }
+
+ return outHash;
+}
+
+mork_bool
+morkBookAtom::EqualFormAndBody(morkEnv* ev, const morkBookAtom* inAtom) const
+{
+ mork_bool outEqual = morkBool_kFalse;
+
+ const mork_u1* body = 0; // body of inAtom bytes to compare
+ mork_size size; // the number of inAtom bytes to compare
+ mork_cscode form; // nominal charset for ioAtom
+
+ if ( inAtom->IsWeeBook() )
+ {
+ size = inAtom->mAtom_Size;
+ body = ((const morkWeeBookAtom*) inAtom)->mWeeBookAtom_Body;
+ form = 0;
+ }
+ else if ( inAtom->IsBigBook() )
+ {
+ size = ((const morkBigBookAtom*) inAtom)->mBigBookAtom_Size;
+ body = ((const morkBigBookAtom*) inAtom)->mBigBookAtom_Body;
+ form = ((const morkBigBookAtom*) inAtom)->mBigBookAtom_Form;
+ }
+ else if ( inAtom->IsFarBook() )
+ {
+ size = ((const morkFarBookAtom*) inAtom)->mFarBookAtom_Size;
+ body = ((const morkFarBookAtom*) inAtom)->mFarBookAtom_Body;
+ form = ((const morkFarBookAtom*) inAtom)->mFarBookAtom_Form;
+ }
+ else
+ {
+ inAtom->NonBookAtomTypeError(ev);
+ return morkBool_kFalse;
+ }
+
+ const mork_u1* thisBody = 0; // body of bytes in this to compare
+ mork_size thisSize; // the number of bytes in this to compare
+ mork_cscode thisForm; // nominal charset for this atom
+
+ if ( this->IsWeeBook() )
+ {
+ thisSize = mAtom_Size;
+ thisBody = ((const morkWeeBookAtom*) this)->mWeeBookAtom_Body;
+ thisForm = 0;
+ }
+ else if ( this->IsBigBook() )
+ {
+ thisSize = ((const morkBigBookAtom*) this)->mBigBookAtom_Size;
+ thisBody = ((const morkBigBookAtom*) this)->mBigBookAtom_Body;
+ thisForm = ((const morkBigBookAtom*) this)->mBigBookAtom_Form;
+ }
+ else if ( this->IsFarBook() )
+ {
+ thisSize = ((const morkFarBookAtom*) this)->mFarBookAtom_Size;
+ thisBody = ((const morkFarBookAtom*) this)->mFarBookAtom_Body;
+ thisForm = ((const morkFarBookAtom*) this)->mFarBookAtom_Form;
+ }
+ else
+ {
+ this->NonBookAtomTypeError(ev);
+ return morkBool_kFalse;
+ }
+
+ // if atoms are empty, form is irrelevant
+ if ( body && thisBody && size == thisSize && (!size || form == thisForm ))
+ outEqual = (MORK_MEMCMP(body, thisBody, size) == 0);
+
+ return outEqual;
+}
+
+
+void
+morkBookAtom::CutBookAtomFromSpace(morkEnv* ev)
+{
+ morkAtomSpace* space = mBookAtom_Space;
+ if ( space )
+ {
+ mBookAtom_Space = 0;
+ space->mAtomSpace_AtomBodies.CutAtom(ev, this);
+ space->mAtomSpace_AtomAids.CutAtom(ev, this);
+ }
+ else
+ ev->NilPointerError();
+}
+
+morkWeeBookAtom::morkWeeBookAtom(mork_aid inAid)
+{
+ mAtom_Kind = morkAtom_kKindWeeBook;
+ mAtom_CellUses = 0;
+ mAtom_Change = morkChange_kNil;
+ mAtom_Size = 0;
+
+ mBookAtom_Space = 0;
+ mBookAtom_Id = inAid;
+
+ mWeeBookAtom_Body[ 0 ] = 0;
+}
+
+void
+morkWeeBookAtom::InitWeeBookAtom(morkEnv* ev, const morkBuf& inBuf,
+ morkAtomSpace* ioSpace, mork_aid inAid)
+{
+ mAtom_Kind = 0;
+ mAtom_Change = morkChange_kNil;
+ if ( ioSpace )
+ {
+ if ( inAid )
+ {
+ if ( inBuf.mBuf_Fill <= morkAtom_kMaxByteSize )
+ {
+ mAtom_CellUses = 0;
+ mAtom_Kind = morkAtom_kKindWeeBook;
+ mBookAtom_Space = ioSpace;
+ mBookAtom_Id = inAid;
+ mork_size size = inBuf.mBuf_Fill;
+ mAtom_Size = (mork_u1) size;
+ if ( size && inBuf.mBuf_Body )
+ MORK_MEMCPY(mWeeBookAtom_Body, inBuf.mBuf_Body, size);
+
+ mWeeBookAtom_Body[ size ] = 0;
+ }
+ else
+ this->AtomSizeOverflowError(ev);
+ }
+ else
+ this->ZeroAidError(ev);
+ }
+ else
+ ev->NilPointerError();
+}
+
+void
+morkBigBookAtom::InitBigBookAtom(morkEnv* ev, const morkBuf& inBuf,
+ mork_cscode inForm, morkAtomSpace* ioSpace, mork_aid inAid)
+{
+ mAtom_Kind = 0;
+ mAtom_Change = morkChange_kNil;
+ if ( ioSpace )
+ {
+ if ( inAid )
+ {
+ mAtom_CellUses = 0;
+ mAtom_Kind = morkAtom_kKindBigBook;
+ mAtom_Size = 0;
+ mBookAtom_Space = ioSpace;
+ mBookAtom_Id = inAid;
+ mBigBookAtom_Form = inForm;
+ mork_size size = inBuf.mBuf_Fill;
+ mBigBookAtom_Size = size;
+ if ( size && inBuf.mBuf_Body )
+ MORK_MEMCPY(mBigBookAtom_Body, inBuf.mBuf_Body, size);
+
+ mBigBookAtom_Body[ size ] = 0;
+ }
+ else
+ this->ZeroAidError(ev);
+ }
+ else
+ ev->NilPointerError();
+}
+
+void morkFarBookAtom::InitFarBookAtom(morkEnv* ev, const morkBuf& inBuf,
+ mork_cscode inForm, morkAtomSpace* ioSpace, mork_aid inAid)
+{
+ mAtom_Kind = 0;
+ mAtom_Change = morkChange_kNil;
+ if ( ioSpace )
+ {
+ if ( inAid )
+ {
+ mAtom_CellUses = 0;
+ mAtom_Kind = morkAtom_kKindFarBook;
+ mAtom_Size = 0;
+ mBookAtom_Space = ioSpace;
+ mBookAtom_Id = inAid;
+ mFarBookAtom_Form = inForm;
+ mFarBookAtom_Size = inBuf.mBuf_Fill;
+ mFarBookAtom_Body = (mork_u1*) inBuf.mBuf_Body;
+ }
+ else
+ this->ZeroAidError(ev);
+ }
+ else
+ ev->NilPointerError();
+}
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkAtom.h
@@ -0,0 +1,398 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MORKATOM_
+#define _MORKATOM_ 1
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+
+#define morkAtom_kMaxByteSize 255 /* max for 8-bit integer */
+#define morkAtom_kForeverCellUses 0x0FF /* max for 8-bit integer */
+#define morkAtom_kMaxCellUses 0x07F /* max for 7-bit integer */
+
+#define morkAtom_kKindWeeAnon 'a' /* means morkWeeAnonAtom subclass */
+#define morkAtom_kKindBigAnon 'A' /* means morkBigAnonAtom subclass */
+#define morkAtom_kKindWeeBook 'b' /* means morkWeeBookAtom subclass */
+#define morkAtom_kKindBigBook 'B' /* means morkBigBookAtom subclass */
+#define morkAtom_kKindFarBook 'f' /* means morkFarBookAtom subclass */
+#define morkAtom_kKindRowOid 'r' /* means morkOidAtom subclass */
+#define morkAtom_kKindTableOid 't' /* means morkOidAtom subclass */
+
+/*| Atom: .
+|*/
+class morkAtom { //
+
+public:
+
+ mork_u1 mAtom_Kind; // identifies a specific atom subclass
+ mork_u1 mAtom_CellUses; // number of persistent uses in a cell
+ mork_change mAtom_Change; // how has this atom been changed?
+ mork_u1 mAtom_Size; // only for atoms smaller than 256 bytes
+
+public:
+ morkAtom(mork_aid inAid, mork_u1 inKind);
+
+ mork_bool IsWeeAnon() const { return mAtom_Kind == morkAtom_kKindWeeAnon; }
+ mork_bool IsBigAnon() const { return mAtom_Kind == morkAtom_kKindBigAnon; }
+ mork_bool IsWeeBook() const { return mAtom_Kind == morkAtom_kKindWeeBook; }
+ mork_bool IsBigBook() const { return mAtom_Kind == morkAtom_kKindBigBook; }
+ mork_bool IsFarBook() const { return mAtom_Kind == morkAtom_kKindFarBook; }
+ mork_bool IsRowOid() const { return mAtom_Kind == morkAtom_kKindRowOid; }
+ mork_bool IsTableOid() const { return mAtom_Kind == morkAtom_kKindTableOid; }
+
+ mork_bool IsBook() const { return this->IsWeeBook() || this->IsBigBook(); }
+
+public: // clean vs dirty
+
+ void SetAtomClean() { mAtom_Change = morkChange_kNil; }
+ void SetAtomDirty() { mAtom_Change = morkChange_kAdd; }
+
+ mork_bool IsAtomClean() const { return mAtom_Change == morkChange_kNil; }
+ mork_bool IsAtomDirty() const { return mAtom_Change == morkChange_kAdd; }
+
+public: // atom space scope if IsBook() is true, or else zero:
+
+ mork_scope GetBookAtomSpaceScope(morkEnv* ev) const;
+ // zero or book's space's scope
+
+ mork_aid GetBookAtomAid() const;
+ // zero or book atom's ID
+
+public: // empty construction does nothing
+ morkAtom() { }
+
+public: // one-byte refcounting, freezing at maximum
+ void MakeCellUseForever(morkEnv* ev);
+ mork_u1 AddCellUse(morkEnv* ev);
+ mork_u1 CutCellUse(morkEnv* ev);
+
+ mork_bool IsCellUseForever() const
+ { return mAtom_CellUses == morkAtom_kForeverCellUses; }
+
+private: // warnings
+
+ static void CellUsesUnderflowWarning(morkEnv* ev);
+
+public: // errors
+
+ static void BadAtomKindError(morkEnv* ev);
+ static void ZeroAidError(morkEnv* ev);
+ static void AtomSizeOverflowError(morkEnv* ev);
+
+public: // yarns
+
+ mork_bool AsBuf(morkBuf& outBuf) const;
+ mork_bool AliasYarn(mdbYarn* outYarn) const;
+ mork_bool GetYarn(mdbYarn* outYarn) const;
+
+private: // copying is not allowed
+ morkAtom(const morkAtom& other);
+ morkAtom& operator=(const morkAtom& other);
+};
+
+/*| OidAtom: an atom that references a row or table by identity.
+|*/
+class morkOidAtom : public morkAtom { //
+
+ // mork_u1 mAtom_Kind; // identifies a specific atom subclass
+ // mork_u1 mAtom_CellUses; // number of persistent uses in a cell
+ // mork_change mAtom_Change; // how has this atom been changed?
+ // mork_u1 mAtom_Size; // NOT USED IN "BIG" format atoms
+
+public:
+ mdbOid mOidAtom_Oid; // identity of referenced object
+
+public: // empty construction does nothing
+ morkOidAtom() { }
+ void InitRowOidAtom(morkEnv* ev, const mdbOid& inOid);
+ void InitTableOidAtom(morkEnv* ev, const mdbOid& inOid);
+
+private: // copying is not allowed
+ morkOidAtom(const morkOidAtom& other);
+ morkOidAtom& operator=(const morkOidAtom& other);
+};
+
+/*| WeeAnonAtom: an atom whose content immediately follows morkAtom slots
+**| in an inline fashion, so that morkWeeAnonAtom contains both leading
+**| atom slots and then the content bytes without further overhead. Note
+**| that charset encoding is not indicated, so zero is implied for Latin1.
+**| (Non-Latin1 content must be stored in a morkBigAnonAtom with a charset.)
+**|
+**|| An anon (anonymous) atom has no identity, with no associated bookkeeping
+**| for lookup needed for sharing like a book atom.
+**|
+**|| A wee anon atom is immediate but not shared with any other users of this
+**| atom, so no bookkeeping for sharing is needed. This means the atom has
+**| no ID, because the atom has no identity other than this immediate content,
+**| and no hash table is needed to look up this particular atom. This also
+**| applies to the larger format morkBigAnonAtom, which has more slots.
+|*/
+class morkWeeAnonAtom : public morkAtom { //
+
+ // mork_u1 mAtom_Kind; // identifies a specific atom subclass
+ // mork_u1 mAtom_CellUses; // number of persistent uses in a cell
+ // mork_change mAtom_Change; // how has this atom been changed?
+ // mork_u1 mAtom_Size; // only for atoms smaller than 256 bytes
+
+public:
+ mork_u1 mWeeAnonAtom_Body[ 1 ]; // 1st byte of immediate content vector
+
+public: // empty construction does nothing
+ morkWeeAnonAtom() { }
+ void InitWeeAnonAtom(morkEnv* ev, const morkBuf& inBuf);
+
+ // allow extra trailing byte for a null byte:
+ static mork_size SizeForFill(mork_fill inFill)
+ { return sizeof(morkWeeAnonAtom) + inFill; }
+
+private: // copying is not allowed
+ morkWeeAnonAtom(const morkWeeAnonAtom& other);
+ morkWeeAnonAtom& operator=(const morkWeeAnonAtom& other);
+};
+
+/*| BigAnonAtom: another immediate atom that cannot be encoded as the smaller
+**| morkWeeAnonAtom format because either the size is too great, and/or the
+**| charset is not the default zero for Latin1 and must be explicitly noted.
+**|
+**|| An anon (anonymous) atom has no identity, with no associated bookkeeping
+**| for lookup needed for sharing like a book atom.
+|*/
+class morkBigAnonAtom : public morkAtom { //
+
+ // mork_u1 mAtom_Kind; // identifies a specific atom subclass
+ // mork_u1 mAtom_CellUses; // number of persistent uses in a cell
+ // mork_change mAtom_Change; // how has this atom been changed?
+ // mork_u1 mAtom_Size; // NOT USED IN "BIG" format atoms
+
+public:
+ mork_cscode mBigAnonAtom_Form; // charset format encoding
+ mork_size mBigAnonAtom_Size; // size of content vector
+ mork_u1 mBigAnonAtom_Body[ 1 ]; // 1st byte of immed content vector
+
+public: // empty construction does nothing
+ morkBigAnonAtom() { }
+ void InitBigAnonAtom(morkEnv* ev, const morkBuf& inBuf, mork_cscode inForm);
+
+ // allow extra trailing byte for a null byte:
+ static mork_size SizeForFill(mork_fill inFill)
+ { return sizeof(morkBigAnonAtom) + inFill; }
+
+private: // copying is not allowed
+ morkBigAnonAtom(const morkBigAnonAtom& other);
+ morkBigAnonAtom& operator=(const morkBigAnonAtom& other);
+};
+
+#define morkBookAtom_kMaxBodySize 1024 /* if larger, cannot be shared */
+
+/*| BookAtom: the common subportion of wee book atoms and big book atoms that
+**| includes the atom ID and the pointer to the space referencing this atom
+**| through a hash table.
+|*/
+class morkBookAtom : public morkAtom { //
+ // mork_u1 mAtom_Kind; // identifies a specific atom subclass
+ // mork_u1 mAtom_CellUses; // number of persistent uses in a cell
+ // mork_change mAtom_Change; // how has this atom been changed?
+ // mork_u1 mAtom_Size; // only for atoms smaller than 256 bytes
+
+public:
+ morkAtomSpace* mBookAtom_Space; // mBookAtom_Space->SpaceScope() is atom scope
+ mork_aid mBookAtom_Id; // identity token for this shared atom
+
+public: // empty construction does nothing
+ morkBookAtom() { }
+
+ static void NonBookAtomTypeError(morkEnv* ev);
+
+public: // Hash() and Equal() for atom ID maps are same for all subclasses:
+
+ mork_u4 HashAid() const { return mBookAtom_Id; }
+ mork_bool EqualAid(const morkBookAtom* inAtom) const
+ { return ( mBookAtom_Id == inAtom->mBookAtom_Id); }
+
+public: // Hash() and Equal() for atom body maps know about subclasses:
+
+ // YOU CANNOT SUBCLASS morkBookAtom WITHOUT FIXING Hash and Equal METHODS:
+
+ mork_u4 HashFormAndBody(morkEnv* ev) const;
+ mork_bool EqualFormAndBody(morkEnv* ev, const morkBookAtom* inAtom) const;
+
+public: // separation from containing space
+
+ void CutBookAtomFromSpace(morkEnv* ev);
+
+private: // copying is not allowed
+ morkBookAtom(const morkBookAtom& other);
+ morkBookAtom& operator=(const morkBookAtom& other);
+};
+
+/*| FarBookAtom: this alternative format for book atoms was introduced
+**| in May 2000 in order to support finding atoms in hash tables without
+**| first copying the strings from original parsing buffers into a new
+**| atom format. This was consuming too much time. However, we can
+**| use morkFarBookAtom to stage a hash table query, as long as we then
+**| fix HashFormAndBody() and EqualFormAndBody() to use morkFarBookAtom
+**| correctly.
+**|
+**|| Note we do NOT intend that instances of morkFarBookAtom will ever
+**| be installed in hash tables, because this is not space efficient.
+**| We only expect to create temp instances for table lookups.
+|*/
+class morkFarBookAtom : public morkBookAtom { //
+
+ // mork_u1 mAtom_Kind; // identifies a specific atom subclass
+ // mork_u1 mAtom_CellUses; // number of persistent uses in a cell
+ // mork_change mAtom_Change; // how has this atom been changed?
+ // mork_u1 mAtom_Size; // NOT USED IN "BIG" format atoms
+
+ // morkAtomSpace* mBookAtom_Space; // mBookAtom_Space->SpaceScope() is scope
+ // mork_aid mBookAtom_Id; // identity token for this shared atom
+
+public:
+ mork_cscode mFarBookAtom_Form; // charset format encoding
+ mork_size mFarBookAtom_Size; // size of content vector
+ mork_u1* mFarBookAtom_Body; // bytes are elsewere, out of line
+
+public: // empty construction does nothing
+ morkFarBookAtom() { }
+ void InitFarBookAtom(morkEnv* ev, const morkBuf& inBuf,
+ mork_cscode inForm, morkAtomSpace* ioSpace, mork_aid inAid);
+
+private: // copying is not allowed
+ morkFarBookAtom(const morkFarBookAtom& other);
+ morkFarBookAtom& operator=(const morkFarBookAtom& other);
+};
+
+/*| WeeBookAtom: .
+|*/
+class morkWeeBookAtom : public morkBookAtom { //
+ // mork_u1 mAtom_Kind; // identifies a specific atom subclass
+ // mork_u1 mAtom_CellUses; // number of persistent uses in a cell
+ // mork_change mAtom_Change; // how has this atom been changed?
+ // mork_u1 mAtom_Size; // only for atoms smaller than 256 bytes
+
+ // morkAtomSpace* mBookAtom_Space; // mBookAtom_Space->SpaceScope() is scope
+ // mork_aid mBookAtom_Id; // identity token for this shared atom
+
+public:
+ mork_u1 mWeeBookAtom_Body[ 1 ]; // 1st byte of immed content vector
+
+public: // empty construction does nothing
+ morkWeeBookAtom() { }
+ morkWeeBookAtom(mork_aid inAid);
+
+ void InitWeeBookAtom(morkEnv* ev, const morkBuf& inBuf,
+ morkAtomSpace* ioSpace, mork_aid inAid);
+
+ // allow extra trailing byte for a null byte:
+ static mork_size SizeForFill(mork_fill inFill)
+ { return sizeof(morkWeeBookAtom) + inFill; }
+
+private: // copying is not allowed
+ morkWeeBookAtom(const morkWeeBookAtom& other);
+ morkWeeBookAtom& operator=(const morkWeeBookAtom& other);
+};
+
+/*| BigBookAtom: .
+|*/
+class morkBigBookAtom : public morkBookAtom { //
+
+ // mork_u1 mAtom_Kind; // identifies a specific atom subclass
+ // mork_u1 mAtom_CellUses; // number of persistent uses in a cell
+ // mork_change mAtom_Change; // how has this atom been changed?
+ // mork_u1 mAtom_Size; // NOT USED IN "BIG" format atoms
+
+ // morkAtomSpace* mBookAtom_Space; // mBookAtom_Space->SpaceScope() is scope
+ // mork_aid mBookAtom_Id; // identity token for this shared atom
+
+public:
+ mork_cscode mBigBookAtom_Form; // charset format encoding
+ mork_size mBigBookAtom_Size; // size of content vector
+ mork_u1 mBigBookAtom_Body[ 1 ]; // 1st byte of immed content vector
+
+public: // empty construction does nothing
+ morkBigBookAtom() { }
+ void InitBigBookAtom(morkEnv* ev, const morkBuf& inBuf,
+ mork_cscode inForm, morkAtomSpace* ioSpace, mork_aid inAid);
+
+ // allow extra trailing byte for a null byte:
+ static mork_size SizeForFill(mork_fill inFill)
+ { return sizeof(morkBigBookAtom) + inFill; }
+
+private: // copying is not allowed
+ morkBigBookAtom(const morkBigBookAtom& other);
+ morkBigBookAtom& operator=(const morkBigBookAtom& other);
+};
+
+/*| MaxBookAtom: .
+|*/
+class morkMaxBookAtom : public morkBigBookAtom { //
+
+ // mork_u1 mAtom_Kind; // identifies a specific atom subclass
+ // mork_u1 mAtom_CellUses; // number of persistent uses in a cell
+ // mork_change mAtom_Change; // how has this atom been changed?
+ // mork_u1 mAtom_Size; // NOT USED IN "BIG" format atoms
+
+ // morkAtomSpace* mBookAtom_Space; // mBookAtom_Space->SpaceScope() is scope
+ // mork_aid mBookAtom_Id; // identity token for this shared atom
+
+ // mork_cscode mBigBookAtom_Form; // charset format encoding
+ // mork_size mBigBookAtom_Size; // size of content vector
+ // mork_u1 mBigBookAtom_Body[ 1 ]; // 1st byte of immed content vector
+
+public:
+ mork_u1 mMaxBookAtom_Body[ morkBookAtom_kMaxBodySize + 3 ]; // max bytes
+
+public: // empty construction does nothing
+ morkMaxBookAtom() { }
+ void InitMaxBookAtom(morkEnv* ev, const morkBuf& inBuf,
+ mork_cscode inForm, morkAtomSpace* ioSpace, mork_aid inAid)
+ { this->InitBigBookAtom(ev, inBuf, inForm, ioSpace, inAid); }
+
+private: // copying is not allowed
+ morkMaxBookAtom(const morkMaxBookAtom& other);
+ morkMaxBookAtom& operator=(const morkMaxBookAtom& other);
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#endif /* _MORKATOM_ */
+
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkAtomMap.cpp
@@ -0,0 +1,469 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#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 _MORKMAP_
+#include "morkMap.h"
+#endif
+
+#ifndef _MORKATOMMAP_
+#include "morkAtomMap.h"
+#endif
+
+#ifndef _MORKATOM_
+#include "morkAtom.h"
+#endif
+
+#ifndef _MORKINTMAP_
+#include "morkIntMap.h"
+#endif
+
+#ifndef _MORKROW_
+#include "morkRow.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void
+morkAtomAidMap::CloseMorkNode(morkEnv* ev) // CloseAtomAidMap() only if open
+{
+ if ( this->IsOpenNode() )
+ {
+ this->MarkClosing();
+ this->CloseAtomAidMap(ev);
+ this->MarkShut();
+ }
+}
+
+/*public virtual*/
+morkAtomAidMap::~morkAtomAidMap() // assert CloseAtomAidMap() executed earlier
+{
+ MORK_ASSERT(this->IsShutNode());
+}
+
+
+/*public non-poly*/
+morkAtomAidMap::morkAtomAidMap(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
+#ifdef MORK_ENABLE_PROBE_MAPS
+: morkProbeMap(ev, inUsage, ioHeap,
+ /*inKeySize*/ sizeof(morkBookAtom*), /*inValSize*/ 0,
+ ioSlotHeap, morkAtomAidMap_kStartSlotCount,
+ /*inZeroIsClearKey*/ morkBool_kTrue)
+#else /*MORK_ENABLE_PROBE_MAPS*/
+: morkMap(ev, inUsage, ioHeap,
+ /*inKeySize*/ sizeof(morkBookAtom*), /*inValSize*/ 0,
+ morkAtomAidMap_kStartSlotCount, ioSlotHeap,
+ /*inHoldChanges*/ morkBool_kFalse)
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+{
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kAtomAidMap;
+}
+
+/*public non-poly*/ void
+morkAtomAidMap::CloseAtomAidMap(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this )
+ {
+ if ( this->IsNode() )
+ {
+#ifdef MORK_ENABLE_PROBE_MAPS
+ this->CloseProbeMap(ev);
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ this->CloseMap(ev);
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+ this->MarkShut();
+ }
+ else
+ this->NonNodeError(ev);
+ }
+ else
+ ev->NilPointerError();
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+
+#ifdef MORK_ENABLE_PROBE_MAPS
+
+ /*virtual*/ mork_test // hit(a,b) implies hash(a) == hash(b)
+ morkAtomAidMap::MapTest(morkEnv* ev, const void* inMapKey,
+ const void* inAppKey) const
+ {
+ MORK_USED_1(ev);
+ const morkBookAtom* key = *(const morkBookAtom**) inMapKey;
+ if ( key )
+ {
+ mork_bool hit = key->EqualAid(*(const morkBookAtom**) inAppKey);
+ return ( hit ) ? morkTest_kHit : morkTest_kMiss;
+ }
+ else
+ return morkTest_kVoid;
+ }
+
+ /*virtual*/ mork_u4 // hit(a,b) implies hash(a) == hash(b)
+ morkAtomAidMap::MapHash(morkEnv* ev, const void* inAppKey) const
+ {
+ const morkBookAtom* key = *(const morkBookAtom**) inAppKey;
+ if ( key )
+ return key->HashAid();
+ else
+ {
+ ev->NilPointerWarning();
+ return 0;
+ }
+ }
+
+ /*virtual*/ mork_u4
+ morkAtomAidMap::ProbeMapHashMapKey(morkEnv* ev,
+ const void* inMapKey) const
+ {
+ const morkBookAtom* key = *(const morkBookAtom**) inMapKey;
+ if ( key )
+ return key->HashAid();
+ else
+ {
+ ev->NilPointerWarning();
+ return 0;
+ }
+ }
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ // { ===== begin morkMap poly interface =====
+ /*virtual*/ mork_bool //
+ morkAtomAidMap::Equal(morkEnv* ev, const void* inKeyA,
+ const void* inKeyB) const
+ {
+ MORK_USED_1(ev);
+ return (*(const morkBookAtom**) inKeyA)->EqualAid(
+ *(const morkBookAtom**) inKeyB);
+ }
+
+ /*virtual*/ mork_u4 //
+ morkAtomAidMap::Hash(morkEnv* ev, const void* inKey) const
+ {
+ MORK_USED_1(ev);
+ return (*(const morkBookAtom**) inKey)->HashAid();
+ }
+ // } ===== end morkMap poly interface =====
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+
+mork_bool
+morkAtomAidMap::AddAtom(morkEnv* ev, morkBookAtom* ioAtom)
+{
+ if ( ev->Good() )
+ {
+#ifdef MORK_ENABLE_PROBE_MAPS
+ this->MapAtPut(ev, &ioAtom, /*val*/ (void*) 0,
+ /*key*/ (void*) 0, /*val*/ (void*) 0);
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ this->Put(ev, &ioAtom, /*val*/ (void*) 0,
+ /*key*/ (void*) 0, /*val*/ (void*) 0, (mork_change**) 0);
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+ }
+ return ev->Good();
+}
+
+morkBookAtom*
+morkAtomAidMap::CutAtom(morkEnv* ev, const morkBookAtom* inAtom)
+{
+ morkBookAtom* oldKey = 0;
+
+#ifdef MORK_ENABLE_PROBE_MAPS
+ MORK_USED_1(inAtom);
+ morkProbeMap::ProbeMapCutError(ev);
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ this->Cut(ev, &inAtom, &oldKey, /*val*/ (void*) 0,
+ (mork_change**) 0);
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+ return oldKey;
+}
+
+morkBookAtom*
+morkAtomAidMap::GetAtom(morkEnv* ev, const morkBookAtom* inAtom)
+{
+ morkBookAtom* key = 0; // old val in the map
+
+#ifdef MORK_ENABLE_PROBE_MAPS
+ this->MapAt(ev, &inAtom, &key, /*val*/ (void*) 0);
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ this->Get(ev, &inAtom, &key, /*val*/ (void*) 0, (mork_change**) 0);
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+ return key;
+}
+
+morkBookAtom*
+morkAtomAidMap::GetAid(morkEnv* ev, mork_aid inAid)
+{
+ morkWeeBookAtom weeAtom(inAid);
+ morkBookAtom* key = &weeAtom; // we need a pointer
+ morkBookAtom* oldKey = 0; // old key in the map
+
+#ifdef MORK_ENABLE_PROBE_MAPS
+ this->MapAt(ev, &key, &oldKey, /*val*/ (void*) 0);
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ this->Get(ev, &key, &oldKey, /*val*/ (void*) 0, (mork_change**) 0);
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+ return oldKey;
+}
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void
+morkAtomBodyMap::CloseMorkNode(morkEnv* ev) // CloseAtomBodyMap() only if open
+{
+ if ( this->IsOpenNode() )
+ {
+ this->MarkClosing();
+ this->CloseAtomBodyMap(ev);
+ this->MarkShut();
+ }
+}
+
+/*public virtual*/
+morkAtomBodyMap::~morkAtomBodyMap() // assert CloseAtomBodyMap() executed earlier
+{
+ MORK_ASSERT(this->IsShutNode());
+}
+
+
+/*public non-poly*/
+morkAtomBodyMap::morkAtomBodyMap(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
+#ifdef MORK_ENABLE_PROBE_MAPS
+: morkProbeMap(ev, inUsage, ioHeap,
+ /*inKeySize*/ sizeof(morkBookAtom*), /*inValSize*/ 0,
+ ioSlotHeap, morkAtomBodyMap_kStartSlotCount,
+ /*inZeroIsClearKey*/ morkBool_kTrue)
+#else /*MORK_ENABLE_PROBE_MAPS*/
+: morkMap(ev, inUsage, ioHeap,
+ /*inKeySize*/ sizeof(morkBookAtom*), /*inValSize*/ 0,
+ morkAtomBodyMap_kStartSlotCount, ioSlotHeap,
+ /*inHoldChanges*/ morkBool_kFalse)
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+{
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kAtomBodyMap;
+}
+
+/*public non-poly*/ void
+morkAtomBodyMap::CloseAtomBodyMap(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this )
+ {
+ if ( this->IsNode() )
+ {
+#ifdef MORK_ENABLE_PROBE_MAPS
+ this->CloseProbeMap(ev);
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ this->CloseMap(ev);
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+ this->MarkShut();
+ }
+ else
+ this->NonNodeError(ev);
+ }
+ else
+ ev->NilPointerError();
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+#ifdef MORK_ENABLE_PROBE_MAPS
+
+ /*virtual*/ mork_test // hit(a,b) implies hash(a) == hash(b)
+ morkAtomBodyMap::MapTest(morkEnv* ev, const void* inMapKey,
+ const void* inAppKey) const
+ {
+ const morkBookAtom* key = *(const morkBookAtom**) inMapKey;
+ if ( key )
+ {
+ return ( key->EqualFormAndBody(ev, *(const morkBookAtom**) inAppKey) ) ?
+ morkTest_kHit : morkTest_kMiss;
+ }
+ else
+ return morkTest_kVoid;
+ }
+
+ /*virtual*/ mork_u4 // hit(a,b) implies hash(a) == hash(b)
+ morkAtomBodyMap::MapHash(morkEnv* ev, const void* inAppKey) const
+ {
+ const morkBookAtom* key = *(const morkBookAtom**) inAppKey;
+ if ( key )
+ return key->HashFormAndBody(ev);
+ else
+ return 0;
+ }
+
+ /*virtual*/ mork_u4
+ morkAtomBodyMap::ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const
+ {
+ const morkBookAtom* key = *(const morkBookAtom**) inMapKey;
+ if ( key )
+ return key->HashFormAndBody(ev);
+ else
+ return 0;
+ }
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ // { ===== begin morkMap poly interface =====
+ /*virtual*/ mork_bool //
+ morkAtomBodyMap::Equal(morkEnv* ev, const void* inKeyA,
+ const void* inKeyB) const
+ {
+ return (*(const morkBookAtom**) inKeyA)->EqualFormAndBody(ev,
+ *(const morkBookAtom**) inKeyB);
+ }
+
+ /*virtual*/ mork_u4 //
+ morkAtomBodyMap::Hash(morkEnv* ev, const void* inKey) const
+ {
+ return (*(const morkBookAtom**) inKey)->HashFormAndBody(ev);
+ }
+ // } ===== end morkMap poly interface =====
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+
+mork_bool
+morkAtomBodyMap::AddAtom(morkEnv* ev, morkBookAtom* ioAtom)
+{
+ if ( ev->Good() )
+ {
+#ifdef MORK_ENABLE_PROBE_MAPS
+ this->MapAtPut(ev, &ioAtom, /*val*/ (void*) 0,
+ /*key*/ (void*) 0, /*val*/ (void*) 0);
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ this->Put(ev, &ioAtom, /*val*/ (void*) 0,
+ /*key*/ (void*) 0, /*val*/ (void*) 0, (mork_change**) 0);
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+ }
+ return ev->Good();
+}
+
+morkBookAtom*
+morkAtomBodyMap::CutAtom(morkEnv* ev, const morkBookAtom* inAtom)
+{
+ morkBookAtom* oldKey = 0;
+
+#ifdef MORK_ENABLE_PROBE_MAPS
+ MORK_USED_1(inAtom);
+ morkProbeMap::ProbeMapCutError(ev);
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ this->Cut(ev, &inAtom, &oldKey, /*val*/ (void*) 0,
+ (mork_change**) 0);
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+ return oldKey;
+}
+
+morkBookAtom*
+morkAtomBodyMap::GetAtom(morkEnv* ev, const morkBookAtom* inAtom)
+{
+ morkBookAtom* key = 0; // old val in the map
+#ifdef MORK_ENABLE_PROBE_MAPS
+ this->MapAt(ev, &inAtom, &key, /*val*/ (void*) 0);
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ this->Get(ev, &inAtom, &key, /*val*/ (void*) 0, (mork_change**) 0);
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+ return key;
+}
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+morkAtomRowMap::~morkAtomRowMap()
+{
+}
+
+// I changed to sizeof(mork_ip) from sizeof(mork_aid) to fix a crash on
+// 64 bit machines. I am not sure it was the right way to fix the problem,
+// but it does stop the crash. Perhaps we should be using the
+// morkPointerMap instead?
+morkAtomRowMap::morkAtomRowMap(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap, mork_column inIndexColumn)
+ : morkIntMap(ev, inUsage, sizeof(mork_ip), ioHeap, ioSlotHeap,
+ /*inHoldChanges*/ morkBool_kFalse)
+, mAtomRowMap_IndexColumn( inIndexColumn )
+{
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kAtomRowMap;
+}
+
+void morkAtomRowMap::AddRow(morkEnv* ev, morkRow* ioRow)
+// add ioRow only if it contains a cell in mAtomRowMap_IndexColumn.
+{
+ mork_aid aid = ioRow->GetCellAtomAid(ev, mAtomRowMap_IndexColumn);
+ if ( aid )
+ this->AddAid(ev, aid, ioRow);
+}
+
+void morkAtomRowMap::CutRow(morkEnv* ev, morkRow* ioRow)
+// cut ioRow only if it contains a cell in mAtomRowMap_IndexColumn.
+{
+ mork_aid aid = ioRow->GetCellAtomAid(ev, mAtomRowMap_IndexColumn);
+ if ( aid )
+ this->CutAid(ev, aid);
+}
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkAtomMap.h
@@ -0,0 +1,397 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MORKATOMMAP_
+#define _MORKATOMMAP_ 1
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKNODE_
+#include "morkNode.h"
+#endif
+
+#ifndef _MORKMAP_
+#include "morkMap.h"
+#endif
+
+#ifndef _MORKPROBEMAP_
+#include "morkProbeMap.h"
+#endif
+
+#ifndef _MORKINTMAP_
+#include "morkIntMap.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#define morkDerived_kAtomAidMap /*i*/ 0x6141 /* ascii 'aA' */
+
+#define morkAtomAidMap_kStartSlotCount 23
+
+/*| morkAtomAidMap: keys of morkBookAtom organized by atom ID
+|*/
+#ifdef MORK_ENABLE_PROBE_MAPS
+class morkAtomAidMap : public morkProbeMap { // for mapping tokens to maps
+#else /*MORK_ENABLE_PROBE_MAPS*/
+class morkAtomAidMap : public morkMap { // for mapping tokens to maps
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+// { ===== begin morkNode interface =====
+public: // morkNode virtual methods
+ virtual void CloseMorkNode(morkEnv* ev); // CloseAtomAidMap() only if open
+ virtual ~morkAtomAidMap(); // assert that CloseAtomAidMap() executed earlier
+
+public: // morkMap construction & destruction
+ morkAtomAidMap(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
+ void CloseAtomAidMap(morkEnv* ev); // called by CloseMorkNode();
+
+public: // dynamic type identification
+ mork_bool IsAtomAidMap() const
+ { return IsNode() && mNode_Derived == morkDerived_kAtomAidMap; }
+// } ===== end morkNode methods =====
+
+public:
+#ifdef MORK_ENABLE_PROBE_MAPS
+ // { ===== begin morkProbeMap methods =====
+ virtual mork_test // hit(a,b) implies hash(a) == hash(b)
+ MapTest(morkEnv* ev, const void* inMapKey, const void* inAppKey) const;
+
+ virtual mork_u4 // hit(a,b) implies hash(a) == hash(b)
+ MapHash(morkEnv* ev, const void* inAppKey) const;
+
+ virtual mork_u4 ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const;
+
+ // virtual mork_bool ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey);
+
+ // virtual void ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
+ // void* ioMapKey, mork_count inKeyCount); // array of keys inside map
+
+ // virtual void ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
+ // const void* inAppKey, const void* inAppVal, // (key,val) outside map
+ // void* outMapKey, void* outMapVal); // (key,val) inside map
+
+ // virtual void ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
+ // const void* inMapKey, const void* inMapVal, // (key,val) inside map
+ // void* outAppKey, void* outAppVal) const; // (key,val) outside map
+ // } ===== end morkProbeMap methods =====
+#else /*MORK_ENABLE_PROBE_MAPS*/
+// { ===== begin morkMap poly interface =====
+ virtual mork_bool // note: equal(a,b) implies hash(a) == hash(b)
+ Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const;
+ // implemented using morkBookAtom::HashAid()
+
+ virtual mork_u4 // note: equal(a,b) implies hash(a) == hash(b)
+ Hash(morkEnv* ev, const void* inKey) const;
+ // implemented using morkBookAtom::EqualAid()
+// } ===== end morkMap poly interface =====
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+public: // other map methods
+
+ mork_bool AddAtom(morkEnv* ev, morkBookAtom* ioAtom);
+ // AddAtom() returns ev->Good()
+
+ morkBookAtom* CutAtom(morkEnv* ev, const morkBookAtom* inAtom);
+ // CutAtom() returns the atom removed equal to inAtom, if there was one
+
+ morkBookAtom* GetAtom(morkEnv* ev, const morkBookAtom* inAtom);
+ // GetAtom() returns the atom equal to inAtom, or else nil
+
+ morkBookAtom* GetAid(morkEnv* ev, mork_aid inAid);
+ // GetAid() returns the atom equal to inAid, or else nil
+
+ // note the atoms are owned elsewhere, usuall by morkAtomSpace
+
+public: // typesafe refcounting inlines calling inherited morkNode methods
+ static void SlotWeakAtomAidMap(morkAtomAidMap* me,
+ morkEnv* ev, morkAtomAidMap** ioSlot)
+ { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+
+ static void SlotStrongAtomAidMap(morkAtomAidMap* me,
+ morkEnv* ev, morkAtomAidMap** ioSlot)
+ { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+};
+
+#ifdef MORK_ENABLE_PROBE_MAPS
+class morkAtomAidMapIter: public morkProbeMapIter { // typesafe wrapper class
+#else /*MORK_ENABLE_PROBE_MAPS*/
+class morkAtomAidMapIter: public morkMapIter { // typesafe wrapper class
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+public:
+#ifdef MORK_ENABLE_PROBE_MAPS
+ morkAtomAidMapIter(morkEnv* ev, morkAtomAidMap* ioMap)
+ : morkProbeMapIter(ev, ioMap) { }
+
+ morkAtomAidMapIter( ) : morkProbeMapIter() { }
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ morkAtomAidMapIter(morkEnv* ev, morkAtomAidMap* ioMap)
+ : morkMapIter(ev, ioMap) { }
+
+ morkAtomAidMapIter( ) : morkMapIter() { }
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+ void InitAtomAidMapIter(morkEnv* ev, morkAtomAidMap* ioMap)
+ { this->InitMapIter(ev, ioMap); }
+
+ mork_change* FirstAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
+ { return this->First(ev, outAtomPtr, /*val*/ (void*) 0); }
+
+ mork_change* NextAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
+ { return this->Next(ev, outAtomPtr, /*val*/ (void*) 0); }
+
+ mork_change* HereAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
+ { return this->Here(ev, outAtomPtr, /*val*/ (void*) 0); }
+
+ mork_change* CutHereAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
+ { return this->CutHere(ev, outAtomPtr, /*val*/ (void*) 0); }
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#define morkDerived_kAtomBodyMap /*i*/ 0x6142 /* ascii 'aB' */
+
+#define morkAtomBodyMap_kStartSlotCount 23
+
+/*| morkAtomBodyMap: keys of morkBookAtom organized by body bytes
+|*/
+#ifdef MORK_ENABLE_PROBE_MAPS
+class morkAtomBodyMap : public morkProbeMap { // for mapping tokens to maps
+#else /*MORK_ENABLE_PROBE_MAPS*/
+class morkAtomBodyMap : public morkMap { // for mapping tokens to maps
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+// { ===== begin morkNode interface =====
+public: // morkNode virtual methods
+ virtual void CloseMorkNode(morkEnv* ev); // CloseAtomBodyMap() only if open
+ virtual ~morkAtomBodyMap(); // assert CloseAtomBodyMap() executed earlier
+
+public: // morkMap construction & destruction
+ morkAtomBodyMap(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
+ void CloseAtomBodyMap(morkEnv* ev); // called by CloseMorkNode();
+
+public: // dynamic type identification
+ mork_bool IsAtomBodyMap() const
+ { return IsNode() && mNode_Derived == morkDerived_kAtomBodyMap; }
+// } ===== end morkNode methods =====
+
+public:
+#ifdef MORK_ENABLE_PROBE_MAPS
+ // { ===== begin morkProbeMap methods =====
+ virtual mork_test // hit(a,b) implies hash(a) == hash(b)
+ MapTest(morkEnv* ev, const void* inMapKey, const void* inAppKey) const;
+
+ virtual mork_u4 // hit(a,b) implies hash(a) == hash(b)
+ MapHash(morkEnv* ev, const void* inAppKey) const;
+
+ virtual mork_u4 ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const;
+
+ // virtual mork_bool ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey);
+
+ // virtual void ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
+ // void* ioMapKey, mork_count inKeyCount); // array of keys inside map
+
+ // virtual void ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
+ // const void* inAppKey, const void* inAppVal, // (key,val) outside map
+ // void* outMapKey, void* outMapVal); // (key,val) inside map
+
+ // virtual void ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
+ // const void* inMapKey, const void* inMapVal, // (key,val) inside map
+ // void* outAppKey, void* outAppVal) const; // (key,val) outside map
+ // } ===== end morkProbeMap methods =====
+#else /*MORK_ENABLE_PROBE_MAPS*/
+// { ===== begin morkMap poly interface =====
+ virtual mork_bool // note: equal(a,b) implies hash(a) == hash(b)
+ Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const;
+ // implemented using morkBookAtom::EqualFormAndBody()
+
+ virtual mork_u4 // note: equal(a,b) implies hash(a) == hash(b)
+ Hash(morkEnv* ev, const void* inKey) const;
+ // implemented using morkBookAtom::HashFormAndBody()
+// } ===== end morkMap poly interface =====
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+public: // other map methods
+
+ mork_bool AddAtom(morkEnv* ev, morkBookAtom* ioAtom);
+ // AddAtom() returns ev->Good()
+
+ morkBookAtom* CutAtom(morkEnv* ev, const morkBookAtom* inAtom);
+ // CutAtom() returns the atom removed equal to inAtom, if there was one
+
+ morkBookAtom* GetAtom(morkEnv* ev, const morkBookAtom* inAtom);
+ // GetAtom() returns the atom equal to inAtom, or else nil
+
+ // note the atoms are owned elsewhere, usuall by morkAtomSpace
+
+public: // typesafe refcounting inlines calling inherited morkNode methods
+ static void SlotWeakAtomBodyMap(morkAtomBodyMap* me,
+ morkEnv* ev, morkAtomBodyMap** ioSlot)
+ { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+
+ static void SlotStrongAtomBodyMap(morkAtomBodyMap* me,
+ morkEnv* ev, morkAtomBodyMap** ioSlot)
+ { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+};
+
+#ifdef MORK_ENABLE_PROBE_MAPS
+class morkAtomBodyMapIter: public morkProbeMapIter{ // typesafe wrapper class
+#else /*MORK_ENABLE_PROBE_MAPS*/
+class morkAtomBodyMapIter: public morkMapIter{ // typesafe wrapper class
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+public:
+#ifdef MORK_ENABLE_PROBE_MAPS
+ morkAtomBodyMapIter(morkEnv* ev, morkAtomBodyMap* ioMap)
+ : morkProbeMapIter(ev, ioMap) { }
+
+ morkAtomBodyMapIter( ) : morkProbeMapIter() { }
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ morkAtomBodyMapIter(morkEnv* ev, morkAtomBodyMap* ioMap)
+ : morkMapIter(ev, ioMap) { }
+
+ morkAtomBodyMapIter( ) : morkMapIter() { }
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+
+ void InitAtomBodyMapIter(morkEnv* ev, morkAtomBodyMap* ioMap)
+ { this->InitMapIter(ev, ioMap); }
+
+ mork_change* FirstAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
+ { return this->First(ev, outAtomPtr, /*val*/ (void*) 0); }
+
+ mork_change* NextAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
+ { return this->Next(ev, outAtomPtr, /*val*/ (void*) 0); }
+
+ mork_change* HereAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
+ { return this->Here(ev, outAtomPtr, /*val*/ (void*) 0); }
+
+ mork_change* CutHereAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
+ { return this->CutHere(ev, outAtomPtr, /*val*/ (void*) 0); }
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#define morkDerived_kAtomRowMap /*i*/ 0x6152 /* ascii 'aR' */
+
+/*| morkAtomRowMap: maps morkAtom* -> morkRow*
+|*/
+class morkAtomRowMap : public morkIntMap { // for mapping atoms to rows
+
+public:
+ mork_column mAtomRowMap_IndexColumn; // row column being indexed
+
+public:
+
+ virtual ~morkAtomRowMap();
+ morkAtomRowMap(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap, mork_column inIndexColumn);
+
+public: // adding and cutting from morkRow instance candidate
+
+ void AddRow(morkEnv* ev, morkRow* ioRow);
+ // add ioRow only if it contains a cell in mAtomRowMap_IndexColumn.
+
+ void CutRow(morkEnv* ev, morkRow* ioRow);
+ // cut ioRow only if it contains a cell in mAtomRowMap_IndexColumn.
+
+public: // other map methods
+
+ mork_bool AddAid(morkEnv* ev, mork_aid inAid, morkRow* ioRow)
+ { return this->AddInt(ev, inAid, ioRow); }
+ // the AddAid() boolean return equals ev->Good().
+
+ mork_bool CutAid(morkEnv* ev, mork_aid inAid)
+ { return this->CutInt(ev, inAid); }
+ // The CutAid() boolean return indicates whether removal happened.
+
+ morkRow* GetAid(morkEnv* ev, mork_aid inAid)
+ { return (morkRow*) this->GetInt(ev, inAid); }
+ // Note the returned space does NOT have an increase in refcount for this.
+
+public: // dynamic type identification
+ mork_bool IsAtomRowMap() const
+ { return IsNode() && mNode_Derived == morkDerived_kAtomRowMap; }
+
+public: // typesafe refcounting inlines calling inherited morkNode methods
+ static void SlotWeakAtomRowMap(morkAtomRowMap* me,
+ morkEnv* ev, morkAtomRowMap** ioSlot)
+ { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+
+ static void SlotStrongAtomRowMap(morkAtomRowMap* me,
+ morkEnv* ev, morkAtomRowMap** ioSlot)
+ { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+
+};
+
+class morkAtomRowMapIter: public morkMapIter{ // typesafe wrapper class
+
+public:
+ morkAtomRowMapIter(morkEnv* ev, morkAtomRowMap* ioMap)
+ : morkMapIter(ev, ioMap) { }
+
+ morkAtomRowMapIter( ) : morkMapIter() { }
+ void InitAtomRowMapIter(morkEnv* ev, morkAtomRowMap* ioMap)
+ { this->InitMapIter(ev, ioMap); }
+
+ mork_change*
+ FirstAtomAndRow(morkEnv* ev, morkAtom** outAtom, morkRow** outRow)
+ { return this->First(ev, outAtom, outRow); }
+
+ mork_change*
+ NextAtomAndRow(morkEnv* ev, morkAtom** outAtom, morkRow** outRow)
+ { return this->Next(ev, outAtom, outRow); }
+
+ mork_change*
+ HereAtomAndRow(morkEnv* ev, morkAtom** outAtom, morkRow** outRow)
+ { return this->Here(ev, outAtom, outRow); }
+
+ mork_change*
+ CutHereAtomAndRow(morkEnv* ev, morkAtom** outAtom, morkRow** outRow)
+ { return this->CutHere(ev, outAtom, outRow); }
+};
+
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#endif /* _MORKATOMMAP_ */
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkAtomSpace.cpp
@@ -0,0 +1,307 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MDB_
+#include "mdb.h"
+#endif
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKNODE_
+#include "morkNode.h"
+#endif
+
+#ifndef _MORKMAP_
+#include "morkMap.h"
+#endif
+
+#ifndef _MORKSPACE_
+#include "morkSpace.h"
+#endif
+
+#ifndef _MORKENV_
+#include "morkEnv.h"
+#endif
+
+#ifndef _MORKSPACE_
+#include "morkSpace.h"
+#endif
+
+#ifndef _MORKATOMSPACE_
+#include "morkAtomSpace.h"
+#endif
+
+#ifndef _MORKPOOL_
+#include "morkPool.h"
+#endif
+
+#ifndef _MORKSTORE_
+#include "morkStore.h"
+#endif
+
+#ifndef _MORKATOM_
+#include "morkAtom.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void
+morkAtomSpace::CloseMorkNode(morkEnv* ev) // CloseAtomSpace() only if open
+{
+ if ( this->IsOpenNode() )
+ {
+ this->MarkClosing();
+ this->CloseAtomSpace(ev);
+ this->MarkShut();
+ }
+}
+
+/*public virtual*/
+morkAtomSpace::~morkAtomSpace() // assert CloseAtomSpace() executed earlier
+{
+ MORK_ASSERT(mAtomSpace_HighUnderId==0);
+ MORK_ASSERT(mAtomSpace_HighOverId==0);
+ MORK_ASSERT(this->IsShutNode());
+ MORK_ASSERT(mAtomSpace_AtomAids.IsShutNode());
+ MORK_ASSERT(mAtomSpace_AtomBodies.IsShutNode());
+}
+
+/*public non-poly*/
+morkAtomSpace::morkAtomSpace(morkEnv* ev, const morkUsage& inUsage,
+ mork_scope inScope, morkStore* ioStore,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
+: morkSpace(ev, inUsage, inScope, ioStore, ioHeap, ioSlotHeap)
+, mAtomSpace_HighUnderId( morkAtomSpace_kMinUnderId )
+, mAtomSpace_HighOverId( morkAtomSpace_kMinOverId )
+, mAtomSpace_AtomAids(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap)
+, mAtomSpace_AtomBodies(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap)
+{
+ // the morkSpace base constructor handles any dirty propagation
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kAtomSpace;
+}
+
+/*public non-poly*/ void
+morkAtomSpace::CloseAtomSpace(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this )
+ {
+ if ( this->IsNode() )
+ {
+ mAtomSpace_AtomBodies.CloseMorkNode(ev);
+ morkStore* store = mSpace_Store;
+ if ( store )
+ this->CutAllAtoms(ev, &store->mStore_Pool);
+
+ mAtomSpace_AtomAids.CloseMorkNode(ev);
+ this->CloseSpace(ev);
+ mAtomSpace_HighUnderId = 0;
+ mAtomSpace_HighOverId = 0;
+ this->MarkShut();
+ }
+ else
+ this->NonNodeError(ev);
+ }
+ else
+ ev->NilPointerError();
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+
+/*static*/ void
+morkAtomSpace::NonAtomSpaceTypeError(morkEnv* ev)
+{
+ ev->NewError("non morkAtomSpace");
+}
+
+mork_num
+morkAtomSpace::CutAllAtoms(morkEnv* ev, morkPool* ioPool)
+{
+#ifdef MORK_ENABLE_ZONE_ARENAS
+ MORK_USED_2(ev, ioPool);
+ return 0;
+#else /*MORK_ENABLE_ZONE_ARENAS*/
+ if ( this->IsAtomSpaceClean() )
+ this->MaybeDirtyStoreAndSpace();
+
+ mork_num outSlots = mAtomSpace_AtomAids.MapFill();
+ morkBookAtom* a = 0; // old key atom in the map
+
+ morkStore* store = mSpace_Store;
+ mork_change* c = 0;
+ morkAtomAidMapIter i(ev, &mAtomSpace_AtomAids);
+ for ( c = i.FirstAtom(ev, &a); c ; c = i.NextAtom(ev, &a) )
+ {
+ if ( a )
+ ioPool->ZapAtom(ev, a, &store->mStore_Zone);
+
+#ifdef MORK_ENABLE_PROBE_MAPS
+ // do not cut anything from the map
+#else /*MORK_ENABLE_PROBE_MAPS*/
+ i.CutHereAtom(ev, /*key*/ (morkBookAtom**) 0);
+#endif /*MORK_ENABLE_PROBE_MAPS*/
+ }
+
+ return outSlots;
+#endif /*MORK_ENABLE_ZONE_ARENAS*/
+}
+
+
+morkBookAtom*
+morkAtomSpace::MakeBookAtomCopyWithAid(morkEnv* ev,
+ const morkFarBookAtom& inAtom, mork_aid inAid)
+// Make copy of inAtom and put it in both maps, using specified ID.
+{
+ morkBookAtom* outAtom = 0;
+ morkStore* store = mSpace_Store;
+ if ( ev->Good() && store )
+ {
+ morkPool* pool = this->GetSpaceStorePool();
+ outAtom = pool->NewFarBookAtomCopy(ev, inAtom, &store->mStore_Zone);
+ if ( outAtom )
+ {
+ if ( store->mStore_CanDirty )
+ {
+ outAtom->SetAtomDirty();
+ if ( this->IsAtomSpaceClean() )
+ this->MaybeDirtyStoreAndSpace();
+ }
+
+ outAtom->mBookAtom_Id = inAid;
+ outAtom->mBookAtom_Space = this;
+ mAtomSpace_AtomAids.AddAtom(ev, outAtom);
+ mAtomSpace_AtomBodies.AddAtom(ev, outAtom);
+ if ( this->SpaceScope() == morkAtomSpace_kColumnScope )
+ outAtom->MakeCellUseForever(ev);
+
+ if ( mAtomSpace_HighUnderId <= inAid )
+ mAtomSpace_HighUnderId = inAid + 1;
+ }
+ }
+ return outAtom;
+}
+
+morkBookAtom*
+morkAtomSpace::MakeBookAtomCopy(morkEnv* ev, const morkFarBookAtom& inAtom)
+// make copy of inAtom and put it in both maps, using a new ID as needed.
+{
+ morkBookAtom* outAtom = 0;
+ morkStore* store = mSpace_Store;
+ if ( ev->Good() && store )
+ {
+ if ( store->mStore_CanAutoAssignAtomIdentity )
+ {
+ morkPool* pool = this->GetSpaceStorePool();
+ morkBookAtom* atom = pool->NewFarBookAtomCopy(ev, inAtom, &mSpace_Store->mStore_Zone);
+ if ( atom )
+ {
+ mork_aid id = this->MakeNewAtomId(ev, atom);
+ if ( id )
+ {
+ if ( store->mStore_CanDirty )
+ {
+ atom->SetAtomDirty();
+ if ( this->IsAtomSpaceClean() )
+ this->MaybeDirtyStoreAndSpace();
+ }
+
+ outAtom = atom;
+ atom->mBookAtom_Space = this;
+ mAtomSpace_AtomAids.AddAtom(ev, atom);
+ mAtomSpace_AtomBodies.AddAtom(ev, atom);
+ if ( this->SpaceScope() == morkAtomSpace_kColumnScope )
+ outAtom->MakeCellUseForever(ev);
+ }
+ else
+ pool->ZapAtom(ev, atom, &mSpace_Store->mStore_Zone);
+ }
+ }
+ else
+ mSpace_Store->CannotAutoAssignAtomIdentityError(ev);
+ }
+ return outAtom;
+}
+
+
+mork_aid
+morkAtomSpace::MakeNewAtomId(morkEnv* ev, morkBookAtom* ioAtom)
+{
+ mork_aid outAid = 0;
+ mork_tid id = mAtomSpace_HighUnderId;
+ mork_num count = 8; // try up to eight times
+
+ while ( !outAid && count ) // still trying to find an unused table ID?
+ {
+ --count;
+ ioAtom->mBookAtom_Id = id;
+ if ( !mAtomSpace_AtomAids.GetAtom(ev, ioAtom) )
+ outAid = id;
+ else
+ {
+ MORK_ASSERT(morkBool_kFalse); // alert developer about ID problems
+ ++id;
+ }
+ }
+
+ mAtomSpace_HighUnderId = id + 1;
+ return outAid;
+}
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+
+morkAtomSpaceMap::~morkAtomSpaceMap()
+{
+}
+
+morkAtomSpaceMap::morkAtomSpaceMap(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
+ : morkNodeMap(ev, inUsage, ioHeap, ioSlotHeap)
+{
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kAtomSpaceMap;
+}
+
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkAtomSpace.h
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MORKATOMSPACE_
+#define _MORKATOMSPACE_ 1
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKNODE_
+#include "morkNode.h"
+#endif
+
+#ifndef _MORKSPACE_
+#include "morkSpace.h"
+#endif
+
+#ifndef _MORKATOMMAP_
+#include "morkAtomMap.h"
+#endif
+
+#ifndef _MORKNODEMAP_
+#include "morkNodeMap.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+/*| kMinUnderId: the smallest ID we auto-assign to the 'under' namespace
+**| reserved for tokens expected to occur very frequently, such as the names
+**| of columns. We reserve single byte ids in the ASCII range to correspond
+**| one-to-one to those tokens consisting single ASCII characters (so that
+**| this assignment is always known and constant). So we start at 0x80, and
+**| then reserve the upper half of two hex digit ids and all the three hex
+**| digit IDs for the 'under' namespace for common tokens.
+|*/
+#define morkAtomSpace_kMinUnderId 0x80 /* low 7 bits mean byte tokens */
+
+#define morkAtomSpace_kMaxSevenBitAid 0x7F /* low seven bit integer ID */
+
+/*| kMinOverId: the smallest ID we auto-assign to the 'over' namespace that
+**| might include very large numbers of tokens that are used infrequently,
+**| so that we care less whether the shortest hex representation is used.
+**| So we start all IDs for 'over' category tokens at a value range that
+**| needs at least four hex digits, so we can reserve three hex digits and
+**| shorter for more commonly occuring tokens in the 'under' category.
+|*/
+#define morkAtomSpace_kMinOverId 0x1000 /* using at least four hex bytes */
+
+#define morkDerived_kAtomSpace /*i*/ 0x6153 /* ascii 'aS' */
+
+#define morkAtomSpace_kColumnScope ((mork_scope) 'c') /* column scope is forever */
+
+/*| morkAtomSpace:
+|*/
+class morkAtomSpace : public morkSpace { //
+
+// public: // slots inherited from morkSpace (meant to inform only)
+ // nsIMdbHeap* mNode_Heap;
+
+ // mork_base mNode_Base; // must equal morkBase_kNode
+ // mork_derived mNode_Derived; // depends on specific node subclass
+
+ // mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
+ // mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
+ // mork_able mNode_Mutable; // can this node be modified?
+ // mork_load mNode_Load; // is this node clean or dirty?
+
+ // mork_uses mNode_Uses; // refcount for strong refs
+ // mork_refs mNode_Refs; // refcount for strong refs + weak refs
+
+ // morkStore* mSpace_Store; // weak ref to containing store
+
+ // mork_bool mSpace_DoAutoIDs; // whether db should assign member IDs
+ // mork_bool mSpace_HaveDoneAutoIDs; // whether actually auto assigned IDs
+ // mork_u1 mSpace_Pad[ 2 ]; // pad to u4 alignment
+
+public: // state is public because the entire Mork system is private
+
+ mork_aid mAtomSpace_HighUnderId; // high ID in 'under' range
+ mork_aid mAtomSpace_HighOverId; // high ID in 'over' range
+
+ morkAtomAidMap mAtomSpace_AtomAids; // all atoms in space by ID
+ morkAtomBodyMap mAtomSpace_AtomBodies; // all atoms in space by body
+
+public: // more specific dirty methods for atom space:
+ void SetAtomSpaceDirty() { this->SetNodeDirty(); }
+ void SetAtomSpaceClean() { this->SetNodeClean(); }
+
+ mork_bool IsAtomSpaceClean() const { return this->IsNodeClean(); }
+ mork_bool IsAtomSpaceDirty() const { return this->IsNodeDirty(); }
+
+// { ===== begin morkNode interface =====
+public: // morkNode virtual methods
+ virtual void CloseMorkNode(morkEnv* ev); // CloseAtomSpace() only if open
+ virtual ~morkAtomSpace(); // assert that CloseAtomSpace() executed earlier
+
+public: // morkMap construction & destruction
+ morkAtomSpace(morkEnv* ev, const morkUsage& inUsage, mork_scope inScope,
+ morkStore* ioStore, nsIMdbHeap* ioNodeHeap, nsIMdbHeap* ioSlotHeap);
+ void CloseAtomSpace(morkEnv* ev); // called by CloseMorkNode();
+
+public: // dynamic type identification
+ mork_bool IsAtomSpace() const
+ { return IsNode() && mNode_Derived == morkDerived_kAtomSpace; }
+// } ===== end morkNode methods =====
+
+public: // typing
+ void NonAtomSpaceTypeError(morkEnv* ev);
+
+public: // setup
+
+ mork_bool MarkAllAtomSpaceContentDirty(morkEnv* ev);
+ // MarkAllAtomSpaceContentDirty() visits every space object and marks
+ // them dirty, including every table, row, cell, and atom. The return
+ // equals ev->Good(), to show whether any error happened. This method is
+ // intended for use in the beginning of a "compress commit" which writes
+ // all store content, whether dirty or not. We dirty everything first so
+ // that later iterations over content can mark things clean as they are
+ // written, and organize the process of serialization so that objects are
+ // written only at need (because of being dirty).
+
+public: // other space methods
+
+ // void ReserveColumnAidCount(mork_count inCount)
+ // {
+ // mAtomSpace_HighUnderId = morkAtomSpace_kMinUnderId + inCount;
+ // mAtomSpace_HighOverId = morkAtomSpace_kMinOverId + inCount;
+ // }
+
+ mork_num CutAllAtoms(morkEnv* ev, morkPool* ioPool);
+ // CutAllAtoms() puts all the atoms back in the pool.
+
+ morkBookAtom* MakeBookAtomCopyWithAid(morkEnv* ev,
+ const morkFarBookAtom& inAtom, mork_aid inAid);
+ // Make copy of inAtom and put it in both maps, using specified ID.
+
+ morkBookAtom* MakeBookAtomCopy(morkEnv* ev, const morkFarBookAtom& inAtom);
+ // Make copy of inAtom and put it in both maps, using a new ID as needed.
+
+ mork_aid MakeNewAtomId(morkEnv* ev, morkBookAtom* ioAtom);
+ // generate an unused atom id.
+
+public: // typesafe refcounting inlines calling inherited morkNode methods
+ static void SlotWeakAtomSpace(morkAtomSpace* me,
+ morkEnv* ev, morkAtomSpace** ioSlot)
+ { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+
+ static void SlotStrongAtomSpace(morkAtomSpace* me,
+ morkEnv* ev, morkAtomSpace** ioSlot)
+ { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#define morkDerived_kAtomSpaceMap /*i*/ 0x615A /* ascii 'aZ' */
+
+/*| morkAtomSpaceMap: maps mork_scope -> morkAtomSpace
+|*/
+class morkAtomSpaceMap : public morkNodeMap { // for mapping tokens to tables
+
+public:
+
+ virtual ~morkAtomSpaceMap();
+ morkAtomSpaceMap(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
+
+public: // other map methods
+
+ mork_bool AddAtomSpace(morkEnv* ev, morkAtomSpace* ioAtomSpace)
+ { return this->AddNode(ev, ioAtomSpace->SpaceScope(), ioAtomSpace); }
+ // the AddAtomSpace() boolean return equals ev->Good().
+
+ mork_bool CutAtomSpace(morkEnv* ev, mork_scope inScope)
+ { return this->CutNode(ev, inScope); }
+ // The CutAtomSpace() boolean return indicates whether removal happened.
+
+ morkAtomSpace* GetAtomSpace(morkEnv* ev, mork_scope inScope)
+ { return (morkAtomSpace*) this->GetNode(ev, inScope); }
+ // Note the returned space does NOT have an increase in refcount for this.
+
+ mork_num CutAllAtomSpaces(morkEnv* ev)
+ { return this->CutAllNodes(ev); }
+ // CutAllAtomSpaces() releases all the referenced table values.
+};
+
+class morkAtomSpaceMapIter: public morkMapIter{ // typesafe wrapper class
+
+public:
+ morkAtomSpaceMapIter(morkEnv* ev, morkAtomSpaceMap* ioMap)
+ : morkMapIter(ev, ioMap) { }
+
+ morkAtomSpaceMapIter( ) : morkMapIter() { }
+ void InitAtomSpaceMapIter(morkEnv* ev, morkAtomSpaceMap* ioMap)
+ { this->InitMapIter(ev, ioMap); }
+
+ mork_change*
+ FirstAtomSpace(morkEnv* ev, mork_scope* outScope, morkAtomSpace** outAtomSpace)
+ { return this->First(ev, outScope, outAtomSpace); }
+
+ mork_change*
+ NextAtomSpace(morkEnv* ev, mork_scope* outScope, morkAtomSpace** outAtomSpace)
+ { return this->Next(ev, outScope, outAtomSpace); }
+
+ mork_change*
+ HereAtomSpace(morkEnv* ev, mork_scope* outScope, morkAtomSpace** outAtomSpace)
+ { return this->Here(ev, outScope, outAtomSpace); }
+
+ mork_change*
+ CutHereAtomSpace(morkEnv* ev, mork_scope* outScope, morkAtomSpace** outAtomSpace)
+ { return this->CutHere(ev, outScope, outAtomSpace); }
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#endif /* _MORKATOMSPACE_ */
+
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkBead.cpp
@@ -0,0 +1,472 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#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 _MORKBEAD_
+#include "morkBead.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void
+morkBead::CloseMorkNode(morkEnv* ev) // CloseBead() only if open
+{
+ if ( this->IsOpenNode() )
+ {
+ this->MarkClosing();
+ this->CloseBead(ev);
+ this->MarkShut();
+ }
+}
+
+/*public virtual*/
+morkBead::~morkBead() // assert CloseBead() executed earlier
+{
+ MORK_ASSERT(mBead_Color==0 || mNode_Usage == morkUsage_kStack );
+}
+
+/*public non-poly*/
+morkBead::morkBead(mork_color inBeadColor)
+: morkNode( morkUsage_kStack )
+, mBead_Color( inBeadColor )
+{
+}
+
+/*public non-poly*/
+morkBead::morkBead(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
+ mork_color inBeadColor)
+: morkNode( inUsage, ioHeap )
+, mBead_Color( inBeadColor )
+{
+}
+
+/*public non-poly*/
+morkBead::morkBead(morkEnv* ev,
+ const morkUsage& inUsage, nsIMdbHeap* ioHeap, mork_color inBeadColor)
+: morkNode(ev, inUsage, ioHeap)
+, mBead_Color( inBeadColor )
+{
+ if ( ev->Good() )
+ {
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kBead;
+ }
+}
+
+/*public non-poly*/ void
+morkBead::CloseBead(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this )
+ {
+ if ( this->IsNode() )
+ {
+ if ( !this->IsShutNode() )
+ {
+ mBead_Color = 0;
+ this->MarkShut();
+ }
+ }
+ else
+ this->NonNodeError(ev);
+ }
+ else
+ ev->NilPointerError();
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void
+morkBeadMap::CloseMorkNode(morkEnv* ev) // CloseBeadMap() only if open
+{
+ if ( this->IsOpenNode() )
+ {
+ this->MarkClosing();
+ this->CloseBeadMap(ev);
+ this->MarkShut();
+ }
+}
+
+/*public virtual*/
+morkBeadMap::~morkBeadMap() // assert CloseBeadMap() executed earlier
+{
+ MORK_ASSERT(this->IsShutNode());
+}
+
+/*public non-poly*/
+morkBeadMap::morkBeadMap(morkEnv* ev,
+ const morkUsage& inUsage, nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
+: morkMap(ev, inUsage, ioHeap, sizeof(morkBead*), /*inValSize*/ 0,
+ /*slotCount*/ 11, ioSlotHeap, /*holdChanges*/ morkBool_kFalse)
+{
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kBeadMap;
+}
+
+/*public non-poly*/ void
+morkBeadMap::CloseBeadMap(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this )
+ {
+ if ( this->IsNode() )
+ {
+ this->CutAllBeads(ev);
+ this->CloseMap(ev);
+ this->MarkShut();
+ }
+ else
+ this->NonNodeError(ev);
+ }
+ else
+ ev->NilPointerError();
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+
+mork_bool
+morkBeadMap::AddBead(morkEnv* ev, morkBead* ioBead)
+ // the AddBead() boolean return equals ev->Good().
+{
+ if ( ioBead && ev->Good() )
+ {
+ morkBead* oldBead = 0; // old key in the map
+
+ mork_bool put = this->Put(ev, &ioBead, /*val*/ (void*) 0,
+ /*key*/ &oldBead, /*val*/ (void*) 0, (mork_change**) 0);
+
+ if ( put ) // replaced an existing key?
+ {
+ if ( oldBead != ioBead ) // new bead was not already in table?
+ ioBead->AddStrongRef(ev); // now there's another ref
+
+ if ( oldBead && oldBead != ioBead ) // need to release old node?
+ oldBead->CutStrongRef(ev);
+ }
+ else
+ ioBead->AddStrongRef(ev); // another ref if not already in table
+ }
+ else if ( !ioBead )
+ ev->NilPointerError();
+
+ return ev->Good();
+}
+
+mork_bool
+morkBeadMap::CutBead(morkEnv* ev, mork_color inColor)
+{
+ morkBead* oldBead = 0; // old key in the map
+ morkBead bead(inColor);
+ morkBead* key = &bead;
+
+ mork_bool outCutNode = this->Cut(ev, &key,
+ /*key*/ &oldBead, /*val*/ (void*) 0, (mork_change**) 0);
+
+ if ( oldBead )
+ oldBead->CutStrongRef(ev);
+
+ bead.CloseBead(ev);
+ return outCutNode;
+}
+
+morkBead*
+morkBeadMap::GetBead(morkEnv* ev, mork_color inColor)
+ // Note the returned bead does NOT have an increase in refcount for this.
+{
+ morkBead* oldBead = 0; // old key in the map
+ morkBead bead(inColor);
+ morkBead* key = &bead;
+
+ this->Get(ev, &key, /*key*/ &oldBead, /*val*/ (void*) 0, (mork_change**) 0);
+
+ bead.CloseBead(ev);
+ return oldBead;
+}
+
+mork_num
+morkBeadMap::CutAllBeads(morkEnv* ev)
+ // CutAllBeads() releases all the referenced beads.
+{
+ mork_num outSlots = mMap_Slots;
+
+ morkBeadMapIter i(ev, this);
+ morkBead* b = i.FirstBead(ev);
+
+ while ( b )
+ {
+ b->CutStrongRef(ev);
+ i.CutHereBead(ev);
+ b = i.NextBead(ev);
+ }
+
+ return outSlots;
+}
+
+
+// { ===== begin morkMap poly interface =====
+/*virtual*/ mork_bool
+morkBeadMap::Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const
+{
+ MORK_USED_1(ev);
+ return (*(const morkBead**) inKeyA)->BeadEqual(
+ *(const morkBead**) inKeyB);
+}
+
+/*virtual*/ mork_u4
+morkBeadMap::Hash(morkEnv* ev, const void* inKey) const
+{
+ MORK_USED_1(ev);
+ return (*(const morkBead**) inKey)->BeadHash();
+}
+// } ===== end morkMap poly interface =====
+
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+
+morkBead* morkBeadMapIter::FirstBead(morkEnv* ev)
+{
+ morkBead* bead = 0;
+ this->First(ev, &bead, /*val*/ (void*) 0);
+ return bead;
+}
+
+morkBead* morkBeadMapIter::NextBead(morkEnv* ev)
+{
+ morkBead* bead = 0;
+ this->Next(ev, &bead, /*val*/ (void*) 0);
+ return bead;
+}
+
+morkBead* morkBeadMapIter::HereBead(morkEnv* ev)
+{
+ morkBead* bead = 0;
+ this->Here(ev, &bead, /*val*/ (void*) 0);
+ return bead;
+}
+
+void morkBeadMapIter::CutHereBead(morkEnv* ev)
+{
+ this->CutHere(ev, /*key*/ (void*) 0, /*val*/ (void*) 0);
+}
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void
+morkBeadProbeMap::CloseMorkNode(morkEnv* ev) // CloseBeadProbeMap() if open
+{
+ if ( this->IsOpenNode() )
+ {
+ this->MarkClosing();
+ this->CloseBeadProbeMap(ev);
+ this->MarkShut();
+ }
+}
+
+/*public virtual*/
+morkBeadProbeMap::~morkBeadProbeMap() // assert CloseBeadProbeMap() earlier
+{
+ MORK_ASSERT(this->IsShutNode());
+}
+
+
+/*public non-poly*/
+morkBeadProbeMap::morkBeadProbeMap(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
+: morkProbeMap(ev, inUsage, ioHeap,
+ /*inKeySize*/ sizeof(morkBead*), /*inValSize*/ 0,
+ ioSlotHeap, /*startSlotCount*/ 11,
+ /*inZeroIsClearKey*/ morkBool_kTrue)
+{
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kBeadProbeMap;
+}
+
+/*public non-poly*/ void
+morkBeadProbeMap::CloseBeadProbeMap(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this )
+ {
+ if ( this->IsNode() )
+ {
+ this->CutAllBeads(ev);
+ this->CloseProbeMap(ev);
+ this->MarkShut();
+ }
+ else
+ this->NonNodeError(ev);
+ }
+ else
+ ev->NilPointerError();
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+
+/*virtual*/ mork_test // hit(a,b) implies hash(a) == hash(b)
+morkBeadProbeMap::MapTest(morkEnv* ev, const void* inMapKey,
+ const void* inAppKey) const
+{
+ MORK_USED_1(ev);
+ const morkBead* key = *(const morkBead**) inMapKey;
+ if ( key )
+ {
+ mork_bool hit = key->BeadEqual(*(const morkBead**) inAppKey);
+ return ( hit ) ? morkTest_kHit : morkTest_kMiss;
+ }
+ else
+ return morkTest_kVoid;
+}
+
+/*virtual*/ mork_u4 // hit(a,b) implies hash(a) == hash(b)
+morkBeadProbeMap::MapHash(morkEnv* ev, const void* inAppKey) const
+{
+ const morkBead* key = *(const morkBead**) inAppKey;
+ if ( key )
+ return key->BeadHash();
+ else
+ {
+ ev->NilPointerWarning();
+ return 0;
+ }
+}
+
+/*virtual*/ mork_u4
+morkBeadProbeMap::ProbeMapHashMapKey(morkEnv* ev,
+ const void* inMapKey) const
+{
+ const morkBead* key = *(const morkBead**) inMapKey;
+ if ( key )
+ return key->BeadHash();
+ else
+ {
+ ev->NilPointerWarning();
+ return 0;
+ }
+}
+
+mork_bool
+morkBeadProbeMap::AddBead(morkEnv* ev, morkBead* ioBead)
+{
+ if ( ioBead && ev->Good() )
+ {
+ morkBead* bead = 0; // old key in the map
+
+ mork_bool put = this->MapAtPut(ev, &ioBead, /*val*/ (void*) 0,
+ /*key*/ &bead, /*val*/ (void*) 0);
+
+ if ( put ) // replaced an existing key?
+ {
+ if ( bead != ioBead ) // new bead was not already in table?
+ ioBead->AddStrongRef(ev); // now there's another ref
+
+ if ( bead && bead != ioBead ) // need to release old node?
+ bead->CutStrongRef(ev);
+ }
+ else
+ ioBead->AddStrongRef(ev); // now there's another ref
+ }
+ else if ( !ioBead )
+ ev->NilPointerError();
+
+ return ev->Good();
+}
+
+morkBead*
+morkBeadProbeMap::GetBead(morkEnv* ev, mork_color inColor)
+{
+ morkBead* oldBead = 0; // old key in the map
+ morkBead bead(inColor);
+ morkBead* key = &bead;
+
+ this->MapAt(ev, &key, &oldBead, /*val*/ (void*) 0);
+
+ bead.CloseBead(ev);
+ return oldBead;
+}
+
+mork_num
+morkBeadProbeMap::CutAllBeads(morkEnv* ev)
+ // CutAllBeads() releases all the referenced bead values.
+{
+ mork_num outSlots = sMap_Slots;
+
+ morkBeadProbeMapIter i(ev, this);
+ morkBead* b = i.FirstBead(ev);
+
+ while ( b )
+ {
+ b->CutStrongRef(ev);
+ b = i.NextBead(ev);
+ }
+ this->MapCutAll(ev);
+
+ return outSlots;
+}
+
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkBead.h
@@ -0,0 +1,277 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MORKBEAD_
+#define _MORKBEAD_ 1
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKNODE_
+#include "morkNode.h"
+#endif
+
+#ifndef _MORKMAP_
+#include "morkMap.h"
+#endif
+
+#ifndef _MORKPROBEMAP_
+#include "morkProbeMap.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#define morkDerived_kBead /*i*/ 0x426F /* ascii 'Bo' */
+
+/*| morkBead: subclass of morkNode that adds knowledge of db suite factory
+**| and containing port to those objects that are exposed as instances of
+**| nsIMdbBead in the public interface.
+|*/
+class morkBead : public morkNode {
+
+// public: // slots inherited from morkNode (meant to inform only)
+ // nsIMdbHeap* mNode_Heap;
+
+ // mork_base mNode_Base; // must equal morkBase_kNode
+ // mork_derived mNode_Derived; // depends on specific node subclass
+
+ // mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
+ // mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
+ // mork_able mNode_Mutable; // can this node be modified?
+ // mork_load mNode_Load; // is this node clean or dirty?
+
+ // mork_uses mNode_Uses; // refcount for strong refs
+ // mork_refs mNode_Refs; // refcount for strong refs + weak refs
+
+public: // state is public because the entire Mork system is private
+
+ mork_color mBead_Color; // ID for this bead
+
+public: // Hash() and Equal() for bead maps are same for all subclasses:
+
+ mork_u4 BeadHash() const { return (mork_u4) mBead_Color; }
+ mork_bool BeadEqual(const morkBead* inBead) const
+ { return ( mBead_Color == inBead->mBead_Color); }
+
+// { ===== begin morkNode interface =====
+public: // morkNode virtual methods
+ virtual void CloseMorkNode(morkEnv* ev); // CloseBead() only if open
+ virtual ~morkBead(); // assert that CloseBead() executed earlier
+
+public: // special case for stack construction for map usage:
+ morkBead(mork_color inBeadColor); // stack-based bead instance
+
+protected: // special case for morkObject:
+ morkBead(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
+ mork_color inBeadColor);
+
+public: // morkEnv construction & destruction
+ morkBead(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
+ mork_color inBeadColor);
+ void CloseBead(morkEnv* ev); // called by CloseMorkNode();
+
+private: // copying is not allowed
+ morkBead(const morkBead& other);
+ morkBead& operator=(const morkBead& other);
+
+public: // dynamic type identification
+ mork_bool IsBead() const
+ { return IsNode() && mNode_Derived == morkDerived_kBead; }
+// } ===== end morkNode methods =====
+
+ // void NewNilHandleError(morkEnv* ev); // mBead_Handle is nil
+
+public: // typesafe refcounting inlines calling inherited morkNode methods
+ static void SlotWeakBead(morkBead* me,
+ morkEnv* ev, morkBead** ioSlot)
+ { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+
+ static void SlotStrongBead(morkBead* me,
+ morkEnv* ev, morkBead** ioSlot)
+ { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#define morkDerived_kBeadMap /*i*/ 0x744D /* ascii 'bM' */
+
+/*| morkBeadMap: maps bead -> bead (key only using mBead_Color)
+|*/
+class morkBeadMap : public morkMap {
+
+
+// { ===== begin morkNode interface =====
+public: // morkNode virtual methods
+ virtual void CloseMorkNode(morkEnv* ev); // CloseBeadMap() only if open
+ virtual ~morkBeadMap(); // assert that CloseBeadMap() executed earlier
+
+public: // morkMap construction & destruction
+ morkBeadMap(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
+ void CloseBeadMap(morkEnv* ev); // called by CloseMorkNode();
+
+public: // dynamic type identification
+ mork_bool IsBeadMap() const
+ { return IsNode() && mNode_Derived == morkDerived_kBeadMap; }
+// } ===== end morkNode methods =====
+
+// { ===== begin morkMap poly interface =====
+public:
+ virtual mork_bool // *((mork_u4*) inKeyA) == *((mork_u4*) inKeyB)
+ Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const;
+
+ virtual mork_u4 // some integer function of *((mork_u4*) inKey)
+ Hash(morkEnv* ev, const void* inKey) const;
+// } ===== end morkMap poly interface =====
+
+public: // other map methods
+
+ mork_bool AddBead(morkEnv* ev, morkBead* ioBead);
+ // the AddBead() boolean return equals ev->Good().
+
+ mork_bool CutBead(morkEnv* ev, mork_color inColor);
+ // The CutBead() boolean return indicates whether removal happened.
+
+ morkBead* GetBead(morkEnv* ev, mork_color inColor);
+ // Note the returned bead does NOT have an increase in refcount for this.
+
+ mork_num CutAllBeads(morkEnv* ev);
+ // CutAllBeads() releases all the referenced beads.
+};
+
+class morkBeadMapIter: public morkMapIter{ // typesafe wrapper class
+
+public:
+ morkBeadMapIter(morkEnv* ev, morkBeadMap* ioMap)
+ : morkMapIter(ev, ioMap) { }
+
+ morkBeadMapIter( ) : morkMapIter() { }
+ void InitBeadMapIter(morkEnv* ev, morkBeadMap* ioMap)
+ { this->InitMapIter(ev, ioMap); }
+
+ morkBead* FirstBead(morkEnv* ev);
+ morkBead* NextBead(morkEnv* ev);
+ morkBead* HereBead(morkEnv* ev);
+ void CutHereBead(morkEnv* ev);
+
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#define morkDerived_kBeadProbeMap /*i*/ 0x6D74 /* ascii 'mb' */
+
+/*| morkBeadProbeMap: maps bead -> bead (key only using mBead_Color)
+|*/
+class morkBeadProbeMap : public morkProbeMap {
+
+
+// { ===== begin morkNode interface =====
+public: // morkNode virtual methods
+ virtual void CloseMorkNode(morkEnv* ev); // CloseBeadProbeMap() only if open
+ virtual ~morkBeadProbeMap(); // assert that CloseBeadProbeMap() executed earlier
+
+public: // morkMap construction & destruction
+ morkBeadProbeMap(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
+ void CloseBeadProbeMap(morkEnv* ev); // called by CloseMorkNode();
+
+public: // dynamic type identification
+ mork_bool IsBeadProbeMap() const
+ { return IsNode() && mNode_Derived == morkDerived_kBeadProbeMap; }
+// } ===== end morkNode methods =====
+
+ // { ===== begin morkProbeMap methods =====
+public:
+ virtual mork_test // hit(a,b) implies hash(a) == hash(b)
+ MapTest(morkEnv* ev, const void* inMapKey, const void* inAppKey) const;
+
+ virtual mork_u4 // hit(a,b) implies hash(a) == hash(b)
+ MapHash(morkEnv* ev, const void* inAppKey) const;
+
+ virtual mork_u4 ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const;
+
+ // virtual mork_bool ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey);
+
+ // virtual void ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
+ // void* ioMapKey, mork_count inKeyCount); // array of keys inside map
+
+ // virtual void ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
+ // const void* inAppKey, const void* inAppVal, // (key,val) outside map
+ // void* outMapKey, void* outMapVal); // (key,val) inside map
+
+ // virtual void ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
+ // const void* inMapKey, const void* inMapVal, // (key,val) inside map
+ // void* outAppKey, void* outAppVal) const; // (key,val) outside map
+ // } ===== end morkProbeMap methods =====
+
+public: // other map methods
+
+ mork_bool AddBead(morkEnv* ev, morkBead* ioBead);
+ // the AddBead() boolean return equals ev->Good().
+
+ morkBead* GetBead(morkEnv* ev, mork_color inColor);
+ // Note the returned bead does NOT have an increase in refcount for this.
+
+ mork_num CutAllBeads(morkEnv* ev);
+ // CutAllBeads() releases all the referenced bead values.
+};
+
+class morkBeadProbeMapIter: public morkProbeMapIter { // typesafe wrapper class
+
+public:
+ morkBeadProbeMapIter(morkEnv* ev, morkBeadProbeMap* ioMap)
+ : morkProbeMapIter(ev, ioMap) { }
+
+ morkBeadProbeMapIter( ) : morkProbeMapIter() { }
+ void InitBeadProbeMapIter(morkEnv* ev, morkBeadProbeMap* ioMap)
+ { this->InitProbeMapIter(ev, ioMap); }
+
+ morkBead* FirstBead(morkEnv* ev)
+ { return (morkBead*) this->IterFirstKey(ev); }
+
+ morkBead* NextBead(morkEnv* ev)
+ { return (morkBead*) this->IterNextKey(ev); }
+
+ morkBead* HereBead(morkEnv* ev)
+ { return (morkBead*) this->IterHereKey(ev); }
+
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#endif /* _MORKBEAD_ */
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkBlob.cpp
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MDB_
+#include "mdb.h"
+#endif
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKBLOB_
+#include "morkBlob.h"
+#endif
+
+#ifndef _MORKENV_
+#include "morkEnv.h"
+#endif
+
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+/*static*/ void
+morkBuf::NilBufBodyError(morkEnv* ev)
+{
+ ev->NewError("nil mBuf_Body");
+}
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+/*static*/ void
+morkBlob::BlobFillOverSizeError(morkEnv* ev)
+{
+ ev->NewError("mBuf_Fill > mBlob_Size");
+}
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+mork_bool
+morkBlob::GrowBlob(morkEnv* ev, nsIMdbHeap* ioHeap, mork_size inNewSize)
+{
+ if ( ioHeap )
+ {
+ if ( !mBuf_Body ) // no body? implies zero sized?
+ mBlob_Size = 0;
+
+ if ( mBuf_Fill > mBlob_Size ) // fill more than size?
+ {
+ ev->NewWarning("mBuf_Fill > mBlob_Size");
+ mBuf_Fill = mBlob_Size;
+ }
+
+ if ( inNewSize > mBlob_Size ) // need to allocate larger blob?
+ {
+ mork_u1* body = 0;
+ ioHeap->Alloc(ev->AsMdbEnv(), inNewSize, (void**) &body);
+ if ( body && ev->Good() )
+ {
+ void* oldBody = mBuf_Body;
+ if ( mBlob_Size ) // any old content to transfer?
+ MORK_MEMCPY(body, oldBody, mBlob_Size);
+
+ mBlob_Size = inNewSize; // install new size
+ mBuf_Body = body; // install new body
+
+ if ( oldBody ) // need to free old buffer body?
+ ioHeap->Free(ev->AsMdbEnv(), oldBody);
+ }
+ }
+ }
+ else
+ ev->NilPointerError();
+
+ if ( ev->Good() && mBlob_Size < inNewSize )
+ ev->NewError("mBlob_Size < inNewSize");
+
+ return ev->Good();
+}
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+morkCoil::morkCoil(morkEnv* ev, nsIMdbHeap* ioHeap)
+{
+ mBuf_Body = 0;
+ mBuf_Fill = 0;
+ mBlob_Size = 0;
+ mText_Form = 0;
+ mCoil_Heap = ioHeap;
+ if ( !ioHeap )
+ ev->NilPointerError();
+}
+
+void
+morkCoil::CloseCoil(morkEnv* ev)
+{
+ void* body = mBuf_Body;
+ nsIMdbHeap* heap = mCoil_Heap;
+
+ mBuf_Body = 0;
+ mCoil_Heap = 0;
+
+ if ( body && heap )
+ {
+ heap->Free(ev->AsMdbEnv(), body);
+ }
+}
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkBlob.h
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MORKBLOB_
+#define _MORKBLOB_ 1
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+/*| Buf: the minimum needed to describe location and content length.
+**| This is typically only enough to read from this buffer, since
+**| one cannot write effectively without knowing the size of a buf.
+|*/
+class morkBuf { // subset of nsIMdbYarn slots
+public:
+ void* mBuf_Body; // space for holding any binary content
+ mork_fill mBuf_Fill; // logical content in Buf in bytes
+
+public:
+ morkBuf() { }
+ morkBuf(const void* ioBuf, mork_fill inFill)
+ : mBuf_Body((void*) ioBuf), mBuf_Fill(inFill) { }
+
+ void ClearBufFill() { mBuf_Fill = 0; }
+
+ static void NilBufBodyError(morkEnv* ev);
+
+private: // copying is not allowed
+ morkBuf(const morkBuf& other);
+ morkBuf& operator=(const morkBuf& other);
+};
+
+/*| Blob: a buffer with an associated size, to increase known buf info
+**| to include max capacity in addition to buf location and content.
+**| This form factor allows us to allocate a vector of such blobs,
+**| which can share the same managing heap stored elsewhere, and that
+**| is why we don't include a pointer to a heap in this blob class.
+|*/
+class morkBlob : public morkBuf { // greater subset of nsIMdbYarn slots
+
+ // void* mBuf_Body; // space for holding any binary content
+ // mdb_fill mBuf_Fill; // logical content in Buf in bytes
+public:
+ mork_size mBlob_Size; // physical size of Buf in bytes
+
+public:
+ morkBlob() { }
+ morkBlob(const void* ioBuf, mork_fill inFill, mork_size inSize)
+ : morkBuf(ioBuf, inFill), mBlob_Size(inSize) { }
+
+ static void BlobFillOverSizeError(morkEnv* ev);
+
+public:
+ mork_bool GrowBlob(morkEnv* ev, nsIMdbHeap* ioHeap,
+ mork_size inNewSize);
+
+private: // copying is not allowed
+ morkBlob(const morkBlob& other);
+ morkBlob& operator=(const morkBlob& other);
+
+};
+
+/*| Text: a blob with an associated charset annotation, where the
+**| charset actually includes the general notion of typing, and not
+**| just a specification of character set alone; we want to permit
+**| arbitrary charset annotations for ad hoc binary types as well.
+**| (We avoid including a nsIMdbHeap pointer in morkText for the same
+**| reason morkBlob does: we want minimal size vectors of morkText.)
+|*/
+class morkText : public morkBlob { // greater subset of nsIMdbYarn slots
+
+ // void* mBuf_Body; // space for holding any binary content
+ // mdb_fill mBuf_Fill; // logical content in Buf in bytes
+ // mdb_size mBlob_Size; // physical size of Buf in bytes
+
+public:
+ mork_cscode mText_Form; // charset format encoding
+
+ morkText() { }
+
+private: // copying is not allowed
+ morkText(const morkText& other);
+ morkText& operator=(const morkText& other);
+};
+
+/*| Coil: a text with an associated nsIMdbHeap instance that provides
+**| all memory management for the space pointed to by mBuf_Body. (This
+**| was the hardest type to give a name in this small class hierarchy,
+**| because it's hard to characterize self-management of one's space.)
+**| A coil is a self-contained blob that knows how to grow itself as
+**| necessary to hold more content when necessary. Coil descends from
+**| morkText to include the mText_Form slot, even though this won't be
+**| needed always, because we are not as concerned about the overall
+**| size of this particular Coil object (if we were concerned about
+**| the size of an array of Coil instances, we would not bother with
+**| a separate heap pointer for each of them).
+**|
+**|| A coil makes a good medium in which to stream content as a sink,
+**| so we will have a subclass of morkSink called morkCoil that
+**| will stream bytes into this self-contained coil object. The name
+**| of this morkCoil class derives more from this intended usage than
+**| from anything else. The Mork code to parse db content will use
+**| coils with associated sinks to accumulate parsed strings.
+**|
+**|| Heap: this is the heap used for memory allocation. This instance
+**| is NOT refcounted, since this coil always assumes the heap is held
+**| through a reference elsewhere (for example, through the same object
+**| that contains or holds the coil itself. This lack of refcounting
+**| is consistent with the fact that morkCoil itself is not refcounted,
+**| and is not intended for use as a standalone object.
+|*/
+class morkCoil : public morkText { // self-managing text blob object
+
+ // void* mBuf_Body; // space for holding any binary content
+ // mdb_fill mBuf_Fill; // logical content in Buf in bytes
+ // mdb_size mBlob_Size; // physical size of Buf in bytes
+ // mdb_cscode mText_Form; // charset format encoding
+public:
+ nsIMdbHeap* mCoil_Heap; // storage manager for mBuf_Body pointer
+
+public:
+ morkCoil(morkEnv* ev, nsIMdbHeap* ioHeap);
+
+ void CloseCoil(morkEnv* ev);
+
+ mork_bool GrowCoil(morkEnv* ev, mork_size inNewSize)
+ { return this->GrowBlob(ev, mCoil_Heap, inNewSize); }
+
+private: // copying is not allowed
+ morkCoil(const morkCoil& other);
+ morkCoil& operator=(const morkCoil& other);
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#endif /* _MORKBLOB_ */
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkBuilder.cpp
@@ -0,0 +1,1068 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MDB_
+#include "mdb.h"
+#endif
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKNODE_
+#include "morkNode.h"
+#endif
+
+#ifndef _MORKMAP_
+#include "morkMap.h"
+#endif
+
+#ifndef _MORKENV_
+#include "morkEnv.h"
+#endif
+
+#ifndef _MORKPARSER_
+#include "morkParser.h"
+#endif
+
+#ifndef _MORKBUILDER_
+#include "morkBuilder.h"
+#endif
+
+#ifndef _MORKCELL_
+#include "morkCell.h"
+#endif
+
+#ifndef _MORKSTORE_
+#include "morkStore.h"
+#endif
+
+#ifndef _MORKTABLE_
+#include "morkTable.h"
+#endif
+
+#ifndef _MORKROW_
+#include "morkRow.h"
+#endif
+
+#ifndef _MORKCELL_
+#include "morkCell.h"
+#endif
+
+#ifndef _MORKATOM_
+#include "morkAtom.h"
+#endif
+
+#ifndef _MORKATOMSPACE_
+#include "morkAtomSpace.h"
+#endif
+
+#ifndef _MORKROWSPACE_
+#include "morkRowSpace.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void
+morkBuilder::CloseMorkNode(morkEnv* ev) // CloseBuilder() only if open
+{
+ if ( this->IsOpenNode() )
+ {
+ this->MarkClosing();
+ this->CloseBuilder(ev);
+ this->MarkShut();
+ }
+}
+
+/*public virtual*/
+morkBuilder::~morkBuilder() // assert CloseBuilder() executed earlier
+{
+ MORK_ASSERT(mBuilder_Store==0);
+ MORK_ASSERT(mBuilder_Row==0);
+ MORK_ASSERT(mBuilder_Table==0);
+ MORK_ASSERT(mBuilder_Cell==0);
+ MORK_ASSERT(mBuilder_RowSpace==0);
+ MORK_ASSERT(mBuilder_AtomSpace==0);
+}
+
+/*public non-poly*/
+morkBuilder::morkBuilder(morkEnv* ev,
+ const morkUsage& inUsage, nsIMdbHeap* ioHeap,
+ morkStream* ioStream, mdb_count inBytesPerParseSegment,
+ nsIMdbHeap* ioSlotHeap, morkStore* ioStore)
+
+: morkParser(ev, inUsage, ioHeap, ioStream,
+ inBytesPerParseSegment, ioSlotHeap)
+
+, mBuilder_Store( 0 )
+
+, mBuilder_Table( 0 )
+, mBuilder_Row( 0 )
+, mBuilder_Cell( 0 )
+
+, mBuilder_RowSpace( 0 )
+, mBuilder_AtomSpace( 0 )
+
+, mBuilder_OidAtomSpace( 0 )
+, mBuilder_ScopeAtomSpace( 0 )
+
+, mBuilder_PortForm( 0 )
+, mBuilder_PortRowScope( (mork_scope) 'r' )
+, mBuilder_PortAtomScope( (mork_scope) 'v' )
+
+, mBuilder_TableForm( 0 )
+, mBuilder_TableRowScope( (mork_scope) 'r' )
+, mBuilder_TableAtomScope( (mork_scope) 'v' )
+, mBuilder_TableKind( 0 )
+
+, mBuilder_TablePriority( morkPriority_kLo )
+, mBuilder_TableIsUnique( morkBool_kFalse )
+, mBuilder_TableIsVerbose( morkBool_kFalse )
+, mBuilder_TablePadByte( 0 )
+
+, mBuilder_RowForm( 0 )
+, mBuilder_RowRowScope( (mork_scope) 'r' )
+, mBuilder_RowAtomScope( (mork_scope) 'v' )
+
+, mBuilder_CellForm( 0 )
+, mBuilder_CellAtomScope( (mork_scope) 'v' )
+
+, mBuilder_DictForm( 0 )
+, mBuilder_DictAtomScope( (mork_scope) 'v' )
+
+, mBuilder_MetaTokenSlot( 0 )
+
+, mBuilder_DoCutRow( morkBool_kFalse )
+, mBuilder_DoCutCell( morkBool_kFalse )
+, mBuilder_CellsVecFill( 0 )
+{
+ if ( ev->Good() )
+ {
+ if ( ioStore )
+ {
+ morkStore::SlotWeakStore(ioStore, ev, &mBuilder_Store);
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kBuilder;
+ }
+ else
+ ev->NilPointerError();
+ }
+
+}
+
+/*public non-poly*/ void
+morkBuilder::CloseBuilder(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this )
+ {
+ if ( this->IsNode() )
+ {
+ mBuilder_Row = 0;
+ mBuilder_Cell = 0;
+ mBuilder_MetaTokenSlot = 0;
+
+ morkTable::SlotStrongTable((morkTable*) 0, ev, &mBuilder_Table);
+ morkStore::SlotWeakStore((morkStore*) 0, ev, &mBuilder_Store);
+
+ morkRowSpace::SlotStrongRowSpace((morkRowSpace*) 0, ev,
+ &mBuilder_RowSpace);
+
+ morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev,
+ &mBuilder_AtomSpace);
+
+ morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev,
+ &mBuilder_OidAtomSpace);
+
+ morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev,
+ &mBuilder_ScopeAtomSpace);
+ this->CloseParser(ev);
+ this->MarkShut();
+ }
+ else
+ this->NonNodeError(ev);
+ }
+ else
+ ev->NilPointerError();
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+
+/*static*/ void
+morkBuilder::NonBuilderTypeError(morkEnv* ev)
+{
+ ev->NewError("non morkBuilder");
+}
+
+/*static*/ void
+morkBuilder::NilBuilderCellError(morkEnv* ev)
+{
+ ev->NewError("nil mBuilder_Cell");
+}
+
+/*static*/ void
+morkBuilder::NilBuilderRowError(morkEnv* ev)
+{
+ ev->NewError("nil mBuilder_Row");
+}
+
+/*static*/ void
+morkBuilder::NilBuilderTableError(morkEnv* ev)
+{
+ ev->NewError("nil mBuilder_Table");
+}
+
+/*static*/ void
+morkBuilder::NonColumnSpaceScopeError(morkEnv* ev)
+{
+ ev->NewError("column space != 'c'");
+}
+
+void
+morkBuilder::LogGlitch(morkEnv* ev, const morkGlitch& inGlitch,
+ const char* inKind)
+{
+ MORK_USED_2(inGlitch,inKind);
+ ev->NewWarning("parsing glitch");
+}
+
+/*virtual*/ void
+morkBuilder::MidToYarn(morkEnv* ev,
+ const morkMid& inMid, // typically an alias to concat with strings
+ mdbYarn* outYarn)
+// The parser might ask that some aliases be turned into yarns, so they
+// can be concatenated into longer blobs under some circumstances. This
+// is an alternative to using a long and complex callback for many parts
+// for a single cell value.
+{
+ mBuilder_Store->MidToYarn(ev, inMid, outYarn);
+}
+
+/*virtual*/ void
+morkBuilder::OnNewPort(morkEnv* ev, const morkPlace& inPlace)
+// mp:Start ::= OnNewPort mp:PortItem* OnPortEnd
+// mp:PortItem ::= mp:Content | mp:Group | OnPortGlitch
+// mp:Content ::= mp:PortRow | mp:Dict | mp:Table | mp:Row
+{
+ MORK_USED_2(ev,inPlace);
+ // mParser_InPort = morkBool_kTrue;
+ mBuilder_PortForm = 0;
+ mBuilder_PortRowScope = (mork_scope) 'r';
+ mBuilder_PortAtomScope = (mork_scope) 'v';
+}
+
+/*virtual*/ void
+morkBuilder::OnPortGlitch(morkEnv* ev, const morkGlitch& inGlitch)
+{
+ this->LogGlitch(ev, inGlitch, "port");
+}
+
+/*virtual*/ void
+morkBuilder::OnPortEnd(morkEnv* ev, const morkSpan& inSpan)
+// mp:Start ::= OnNewPort mp:PortItem* OnPortEnd
+{
+ MORK_USED_2(ev,inSpan);
+ // ev->StubMethodOnlyError();
+ // nothing to do?
+ // mParser_InPort = morkBool_kFalse;
+}
+
+/*virtual*/ void
+morkBuilder::OnNewGroup(morkEnv* ev, const morkPlace& inPlace, mork_gid inGid)
+{
+ MORK_USED_1(inPlace);
+ mParser_InGroup = morkBool_kTrue;
+ mork_pos startPos = inPlace.mPlace_Pos;
+
+ morkStore* store = mBuilder_Store;
+ if ( store )
+ {
+ if ( inGid >= store->mStore_CommitGroupIdentity )
+ store->mStore_CommitGroupIdentity = inGid + 1;
+
+ if ( !store->mStore_FirstCommitGroupPos )
+ store->mStore_FirstCommitGroupPos = startPos;
+ else if ( !store->mStore_SecondCommitGroupPos )
+ store->mStore_SecondCommitGroupPos = startPos;
+ }
+}
+
+/*virtual*/ void
+morkBuilder::OnGroupGlitch(morkEnv* ev, const morkGlitch& inGlitch)
+{
+ this->LogGlitch(ev, inGlitch, "group");
+}
+
+/*virtual*/ void
+morkBuilder::OnGroupCommitEnd(morkEnv* ev, const morkSpan& inSpan)
+{
+ MORK_USED_2(ev,inSpan);
+ // mParser_InGroup = morkBool_kFalse;
+ // ev->StubMethodOnlyError();
+}
+
+/*virtual*/ void
+morkBuilder::OnGroupAbortEnd(morkEnv* ev, const morkSpan& inSpan)
+{
+ MORK_USED_1(inSpan);
+ // mParser_InGroup = morkBool_kFalse;
+ ev->StubMethodOnlyError();
+}
+
+/*virtual*/ void
+morkBuilder::OnNewPortRow(morkEnv* ev, const morkPlace& inPlace,
+ const morkMid& inMid, mork_change inChange)
+{
+ MORK_USED_3(inMid,inPlace,inChange);
+ // mParser_InPortRow = morkBool_kTrue;
+ ev->StubMethodOnlyError();
+}
+
+/*virtual*/ void
+morkBuilder::OnPortRowGlitch(morkEnv* ev, const morkGlitch& inGlitch)
+{
+ this->LogGlitch(ev, inGlitch, "port row");
+}
+
+/*virtual*/ void
+morkBuilder::OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan)
+{
+ MORK_USED_1(inSpan);
+ // mParser_InPortRow = morkBool_kFalse;
+ ev->StubMethodOnlyError();
+}
+
+/*virtual*/ void
+morkBuilder::OnNewTable(morkEnv* ev, const morkPlace& inPlace,
+ const morkMid& inMid, mork_bool inCutAllRows)
+// mp:Table ::= OnNewTable mp:TableItem* OnTableEnd
+// mp:TableItem ::= mp:Row | mp:MetaTable | OnTableGlitch
+// mp:MetaTable ::= OnNewMeta mp:MetaItem* mp:Row OnMetaEnd
+// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd
+// mp:MetaItem ::= mp:Cell | OnMetaGlitch
+{
+ MORK_USED_1(inPlace);
+ // mParser_InTable = morkBool_kTrue;
+ mBuilder_TableForm = mBuilder_PortForm;
+ mBuilder_TableRowScope = mBuilder_PortRowScope;
+ mBuilder_TableAtomScope = mBuilder_PortAtomScope;
+ mBuilder_TableKind = morkStore_kNoneToken;
+
+ mBuilder_TablePriority = morkPriority_kLo;
+ mBuilder_TableIsUnique = morkBool_kFalse;
+ mBuilder_TableIsVerbose = morkBool_kFalse;
+
+ morkTable* table = mBuilder_Store->MidToTable(ev, inMid);
+ morkTable::SlotStrongTable(table, ev, &mBuilder_Table);
+ if ( table )
+ {
+ if ( table->mTable_RowSpace )
+ mBuilder_TableRowScope = table->mTable_RowSpace->SpaceScope();
+
+ if ( inCutAllRows )
+ table->CutAllRows(ev);
+ }
+}
+
+/*virtual*/ void
+morkBuilder::OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch)
+{
+ this->LogGlitch(ev, inGlitch, "table");
+}
+
+/*virtual*/ void
+morkBuilder::OnTableEnd(morkEnv* ev, const morkSpan& inSpan)
+// mp:Table ::= OnNewTable mp:TableItem* OnTableEnd
+{
+ MORK_USED_1(inSpan);
+ // mParser_InTable = morkBool_kFalse;
+ if ( mBuilder_Table )
+ {
+ mBuilder_Table->mTable_Priority = mBuilder_TablePriority;
+
+ if ( mBuilder_TableIsUnique )
+ mBuilder_Table->SetTableUnique();
+
+ if ( mBuilder_TableIsVerbose )
+ mBuilder_Table->SetTableVerbose();
+
+ morkTable::SlotStrongTable((morkTable*) 0, ev, &mBuilder_Table);
+ }
+ else
+ this->NilBuilderTableError(ev);
+
+ mBuilder_Row = 0;
+ mBuilder_Cell = 0;
+
+
+ mBuilder_TablePriority = morkPriority_kLo;
+ mBuilder_TableIsUnique = morkBool_kFalse;
+ mBuilder_TableIsVerbose = morkBool_kFalse;
+
+ if ( mBuilder_TableKind == morkStore_kNoneToken )
+ ev->NewError("missing table kind");
+
+ mBuilder_CellAtomScope = mBuilder_RowAtomScope =
+ mBuilder_TableAtomScope = mBuilder_PortAtomScope;
+
+ mBuilder_DoCutCell = morkBool_kFalse;
+ mBuilder_DoCutRow = morkBool_kFalse;
+}
+
+/*virtual*/ void
+morkBuilder::OnNewMeta(morkEnv* ev, const morkPlace& inPlace)
+// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd
+// mp:MetaItem ::= mp:Cell | OnMetaGlitch
+// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
+// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
+// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
+{
+ MORK_USED_2(ev,inPlace);
+ // mParser_InMeta = morkBool_kTrue;
+
+}
+
+/*virtual*/ void
+morkBuilder::OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch)
+{
+ this->LogGlitch(ev, inGlitch, "meta");
+}
+
+/*virtual*/ void
+morkBuilder::OnMetaEnd(morkEnv* ev, const morkSpan& inSpan)
+// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd
+{
+ MORK_USED_2(ev,inSpan);
+ // mParser_InMeta = morkBool_kFalse;
+}
+
+/*virtual*/ void
+morkBuilder::OnMinusRow(morkEnv* ev)
+{
+ MORK_USED_1(ev);
+ mBuilder_DoCutRow = morkBool_kTrue;
+}
+
+/*virtual*/ void
+morkBuilder::OnNewRow(morkEnv* ev, const morkPlace& inPlace,
+ const morkMid& inMid, mork_bool inCutAllCols)
+// mp:Table ::= OnNewTable mp:TableItem* OnTableEnd
+// mp:TableItem ::= mp:Row | mp:MetaTable | OnTableGlitch
+// mp:MetaTable ::= OnNewMeta mp:MetaItem* mp:Row OnMetaEnd
+// mp:Row ::= OnMinusRow? OnNewRow mp:RowItem* OnRowEnd
+// mp:RowItem ::= mp:Cell | mp:Meta | OnRowGlitch
+// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
+// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
+// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
+{
+ MORK_USED_1(inPlace);
+ // mParser_InRow = morkBool_kTrue;
+
+ mBuilder_CellForm = mBuilder_RowForm = mBuilder_TableForm;
+ mBuilder_CellAtomScope = mBuilder_RowAtomScope = mBuilder_TableAtomScope;
+ mBuilder_RowRowScope = mBuilder_TableRowScope;
+ morkStore* store = mBuilder_Store;
+
+ if ( !inMid.mMid_Buf && !inMid.mMid_Oid.mOid_Scope )
+ {
+ morkMid mid(inMid);
+ mid.mMid_Oid.mOid_Scope = mBuilder_RowRowScope;
+ mBuilder_Row = store->MidToRow(ev, mid);
+ }
+ else
+ {
+ mBuilder_Row = store->MidToRow(ev, inMid);
+ }
+ morkRow* row = mBuilder_Row;
+ if ( row && inCutAllCols )
+ {
+ row->CutAllColumns(ev);
+ }
+
+ morkTable* table = mBuilder_Table;
+ if ( table )
+ {
+ if ( row )
+ {
+ if ( mParser_InMeta )
+ {
+ morkRow* metaRow = table->mTable_MetaRow;
+ if ( !metaRow )
+ {
+ table->mTable_MetaRow = row;
+ table->mTable_MetaRowOid = row->mRow_Oid;
+ row->AddRowGcUse(ev);
+ }
+ else if ( metaRow != row ) // not identical?
+ ev->NewError("duplicate table meta row");
+ }
+ else
+ {
+ if ( mBuilder_DoCutRow )
+ table->CutRow(ev, row);
+ else
+ table->AddRow(ev, row);
+ }
+ }
+ }
+ // else // it is now okay to have rows outside a table:
+ // this->NilBuilderTableError(ev);
+
+ mBuilder_DoCutRow = morkBool_kFalse;
+}
+
+/*virtual*/ void
+morkBuilder::OnRowPos(morkEnv* ev, mork_pos inRowPos)
+{
+ if ( mBuilder_Row && mBuilder_Table && !mParser_InMeta )
+ {
+ mork_pos hintFromPos = 0; // best hint when we don't know position
+ mBuilder_Table->MoveRow(ev, mBuilder_Row, hintFromPos, inRowPos);
+ }
+}
+
+/*virtual*/ void
+morkBuilder::OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch)
+{
+ this->LogGlitch(ev, inGlitch, "row");
+}
+
+void
+morkBuilder::FlushBuilderCells(morkEnv* ev)
+{
+ if ( mBuilder_Row )
+ {
+ morkPool* pool = mBuilder_Store->StorePool();
+ morkCell* cells = mBuilder_CellsVec;
+ mork_fill fill = mBuilder_CellsVecFill;
+ mBuilder_Row->TakeCells(ev, cells, fill, mBuilder_Store);
+
+ morkCell* end = cells + fill;
+ --cells; // prepare for preincrement
+ while ( ++cells < end )
+ {
+ if ( cells->mCell_Atom )
+ cells->SetAtom(ev, (morkAtom*) 0, pool);
+ }
+ mBuilder_CellsVecFill = 0;
+ }
+ else
+ this->NilBuilderRowError(ev);
+}
+
+/*virtual*/ void
+morkBuilder::OnRowEnd(morkEnv* ev, const morkSpan& inSpan)
+// mp:Row ::= OnMinusRow? OnNewRow mp:RowItem* OnRowEnd
+{
+ MORK_USED_1(inSpan);
+ // mParser_InRow = morkBool_kFalse;
+ if ( mBuilder_Row )
+ {
+ this->FlushBuilderCells(ev);
+ }
+ else
+ this->NilBuilderRowError(ev);
+
+ mBuilder_Row = 0;
+ mBuilder_Cell = 0;
+
+ mBuilder_DoCutCell = morkBool_kFalse;
+ mBuilder_DoCutRow = morkBool_kFalse;
+}
+
+/*virtual*/ void
+morkBuilder::OnNewDict(morkEnv* ev, const morkPlace& inPlace)
+// mp:Dict ::= OnNewDict mp:DictItem* OnDictEnd
+// mp:DictItem ::= OnAlias | OnAliasGlitch | mp:Meta | OnDictGlitch
+{
+ MORK_USED_2(ev,inPlace);
+ // mParser_InDict = morkBool_kTrue;
+
+ mBuilder_CellForm = mBuilder_DictForm = mBuilder_PortForm;
+ mBuilder_CellAtomScope = mBuilder_DictAtomScope = mBuilder_PortAtomScope;
+}
+
+/*virtual*/ void
+morkBuilder::OnDictGlitch(morkEnv* ev, const morkGlitch& inGlitch)
+{
+ this->LogGlitch(ev, inGlitch, "dict");
+}
+
+/*virtual*/ void
+morkBuilder::OnDictEnd(morkEnv* ev, const morkSpan& inSpan)
+// mp:Dict ::= OnNewDict mp:DictItem* OnDictEnd
+{
+ MORK_USED_2(ev,inSpan);
+ // mParser_InDict = morkBool_kFalse;
+
+ mBuilder_DictForm = 0;
+ mBuilder_DictAtomScope = 0;
+}
+
+/*virtual*/ void
+morkBuilder::OnAlias(morkEnv* ev, const morkSpan& inSpan,
+ const morkMid& inMid)
+{
+ MORK_USED_1(inSpan);
+ if ( mParser_InDict )
+ {
+ morkMid mid = inMid; // local copy for modification
+ mid.mMid_Oid.mOid_Scope = mBuilder_DictAtomScope;
+ mBuilder_Store->AddAlias(ev, mid, mBuilder_DictForm);
+ }
+ else
+ ev->NewError("alias not in dict");
+}
+
+/*virtual*/ void
+morkBuilder::OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch)
+{
+ this->LogGlitch(ev, inGlitch, "alias");
+}
+
+
+morkCell*
+morkBuilder::AddBuilderCell(morkEnv* ev,
+ const morkMid& inMid, mork_change inChange)
+{
+ morkCell* outCell = 0;
+ mork_column column = inMid.mMid_Oid.mOid_Id;
+
+ if ( ev->Good() )
+ {
+ if ( mBuilder_CellsVecFill >= morkBuilder_kCellsVecSize )
+ this->FlushBuilderCells(ev);
+ if ( ev->Good() )
+ {
+ if ( mBuilder_CellsVecFill < morkBuilder_kCellsVecSize )
+ {
+ mork_fill indx = mBuilder_CellsVecFill++;
+ outCell = mBuilder_CellsVec + indx;
+ outCell->SetColumnAndChange(column, inChange);
+ outCell->mCell_Atom = 0;
+ }
+ else
+ ev->NewError("out of builder cells");
+ }
+ }
+ return outCell;
+}
+
+/*virtual*/ void
+morkBuilder::OnMinusCell(morkEnv* ev)
+{
+ MORK_USED_1(ev);
+ mBuilder_DoCutCell = morkBool_kTrue;
+}
+
+/*virtual*/ void
+morkBuilder::OnNewCell(morkEnv* ev, const morkPlace& inPlace,
+ const morkMid* inMid, const morkBuf* inBuf)
+// Exactly one of inMid and inBuf is nil, and the other is non-nil.
+// When hex ID syntax is used for a column, then inMid is not nil, and
+// when a naked string names a column, then inBuf is not nil.
+
+ // mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
+ // mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
+ // mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
+{
+ MORK_USED_1(inPlace);
+ // mParser_InCell = morkBool_kTrue;
+
+ mork_change cellChange = ( mBuilder_DoCutCell )?
+ morkChange_kCut : morkChange_kAdd;
+
+ mBuilder_DoCutCell = morkBool_kFalse;
+
+ mBuilder_CellAtomScope = mBuilder_RowAtomScope;
+
+ mBuilder_Cell = 0; // nil until determined for a row
+ morkStore* store = mBuilder_Store;
+ mork_scope scope = morkStore_kColumnSpaceScope;
+ morkMid tempMid; // space for local and modifiable cell mid
+ morkMid* cellMid = &tempMid; // default to local if inMid==0
+
+ if ( inMid ) // mid parameter is actually provided?
+ {
+ *cellMid = *inMid; // bitwise copy for modifiable local mid
+
+ if ( !cellMid->mMid_Oid.mOid_Scope )
+ {
+ if ( cellMid->mMid_Buf )
+ {
+ scope = store->BufToToken(ev, cellMid->mMid_Buf);
+ cellMid->mMid_Buf = 0; // don't do scope lookup again
+ ev->NewWarning("column mids need column scope");
+ }
+ cellMid->mMid_Oid.mOid_Scope = scope;
+ }
+ }
+ else if ( inBuf ) // buf points to naked column string name?
+ {
+ cellMid->ClearMid();
+ cellMid->mMid_Oid.mOid_Id = store->BufToToken(ev, inBuf);
+ cellMid->mMid_Oid.mOid_Scope = scope; // kColumnSpaceScope
+ }
+ else
+ ev->NilPointerError(); // either inMid or inBuf must be non-nil
+
+ mork_column column = cellMid->mMid_Oid.mOid_Id;
+
+ if ( mBuilder_Row && ev->Good() ) // this cell must be inside a row
+ {
+ // mBuilder_Cell = this->AddBuilderCell(ev, *cellMid, cellChange);
+
+ if ( mBuilder_CellsVecFill >= morkBuilder_kCellsVecSize )
+ this->FlushBuilderCells(ev);
+ if ( ev->Good() )
+ {
+ if ( mBuilder_CellsVecFill < morkBuilder_kCellsVecSize )
+ {
+ mork_fill ix = mBuilder_CellsVecFill++;
+ morkCell* cell = mBuilder_CellsVec + ix;
+ cell->SetColumnAndChange(column, cellChange);
+
+ cell->mCell_Atom = 0;
+ mBuilder_Cell = cell;
+ }
+ else
+ ev->NewError("out of builder cells");
+ }
+ }
+
+ else if ( mParser_InMeta && ev->Good() ) // cell is in metainfo structure?
+ {
+ if ( scope == morkStore_kColumnSpaceScope )
+ {
+ if ( mParser_InTable ) // metainfo for table?
+ {
+ if ( column == morkStore_kKindColumn )
+ mBuilder_MetaTokenSlot = &mBuilder_TableKind;
+ else if ( column == morkStore_kStatusColumn )
+ mBuilder_MetaTokenSlot = &mBuilder_TableStatus;
+ else if ( column == morkStore_kRowScopeColumn )
+ mBuilder_MetaTokenSlot = &mBuilder_TableRowScope;
+ else if ( column == morkStore_kAtomScopeColumn )
+ mBuilder_MetaTokenSlot = &mBuilder_TableAtomScope;
+ else if ( column == morkStore_kFormColumn )
+ mBuilder_MetaTokenSlot = &mBuilder_TableForm;
+ }
+ else if ( mParser_InDict ) // metainfo for dict?
+ {
+ if ( column == morkStore_kAtomScopeColumn )
+ mBuilder_MetaTokenSlot = &mBuilder_DictAtomScope;
+ else if ( column == morkStore_kFormColumn )
+ mBuilder_MetaTokenSlot = &mBuilder_DictForm;
+ }
+ else if ( mParser_InRow ) // metainfo for row?
+ {
+ if ( column == morkStore_kAtomScopeColumn )
+ mBuilder_MetaTokenSlot = &mBuilder_RowAtomScope;
+ else if ( column == morkStore_kRowScopeColumn )
+ mBuilder_MetaTokenSlot = &mBuilder_RowRowScope;
+ else if ( column == morkStore_kFormColumn )
+ mBuilder_MetaTokenSlot = &mBuilder_RowForm;
+ }
+ }
+ else
+ ev->NewWarning("expected column scope");
+ }
+}
+
+/*virtual*/ void
+morkBuilder::OnCellGlitch(morkEnv* ev, const morkGlitch& inGlitch)
+{
+ this->LogGlitch(ev, inGlitch, "cell");
+}
+
+/*virtual*/ void
+morkBuilder::OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat)
+{
+ morkCell* cell = mBuilder_Cell;
+ if ( cell )
+ {
+ mBuilder_CellForm = inCharsetFormat;
+ }
+ else
+ this->NilBuilderCellError(ev);
+}
+
+/*virtual*/ void
+morkBuilder::OnCellEnd(morkEnv* ev, const morkSpan& inSpan)
+// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
+{
+ MORK_USED_2(ev,inSpan);
+ // mParser_InCell = morkBool_kFalse;
+
+ mBuilder_MetaTokenSlot = 0;
+ mBuilder_CellAtomScope = mBuilder_RowAtomScope;
+}
+
+/*virtual*/ void
+morkBuilder::OnValue(morkEnv* ev, const morkSpan& inSpan,
+ const morkBuf& inBuf)
+// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
+// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
+{
+ MORK_USED_1(inSpan);
+ morkStore* store = mBuilder_Store;
+ morkCell* cell = mBuilder_Cell;
+ if ( cell )
+ {
+ mdbYarn yarn;
+ yarn.mYarn_Buf = inBuf.mBuf_Body;
+ yarn.mYarn_Fill = yarn.mYarn_Size = inBuf.mBuf_Fill;
+ yarn.mYarn_More = 0;
+ yarn.mYarn_Form = mBuilder_CellForm;
+ yarn.mYarn_Grow = 0;
+ morkAtom* atom = store->YarnToAtom(ev, &yarn, PR_TRUE /* create */);
+ cell->SetAtom(ev, atom, store->StorePool());
+ }
+ else if ( mParser_InMeta )
+ {
+ mork_token* metaSlot = mBuilder_MetaTokenSlot;
+ if ( metaSlot )
+ {
+ if ( metaSlot == &mBuilder_TableStatus ) // table status?
+ {
+ if ( mParser_InTable && mBuilder_Table )
+ {
+ const char* body = (const char*) inBuf.mBuf_Body;
+ mork_fill bufFill = inBuf.mBuf_Fill;
+ if ( body && bufFill )
+ {
+ const char* bodyEnd = body + bufFill;
+ while ( body < bodyEnd )
+ {
+ int c = *body++;
+ switch ( c )
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ mBuilder_TablePriority = (mork_priority) ( c - '0' );
+ break;
+
+ case 'u':
+ case 'U':
+ mBuilder_TableIsUnique = morkBool_kTrue;
+ break;
+
+ case 'v':
+ case 'V':
+ mBuilder_TableIsVerbose = morkBool_kTrue;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ mork_token token = store->BufToToken(ev, &inBuf);
+ if ( token )
+ {
+ *metaSlot = token;
+ if ( metaSlot == &mBuilder_TableKind ) // table kind?
+ {
+ if ( mParser_InTable && mBuilder_Table )
+ mBuilder_Table->mTable_Kind = token;
+ }
+ }
+ }
+ }
+ }
+ else
+ this->NilBuilderCellError(ev);
+}
+
+/*virtual*/ void
+morkBuilder::OnValueMid(morkEnv* ev, const morkSpan& inSpan,
+ const morkMid& inMid)
+// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
+// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
+{
+ MORK_USED_1(inSpan);
+ morkStore* store = mBuilder_Store;
+ morkCell* cell = mBuilder_Cell;
+
+ morkMid valMid; // local mid for modifications
+ mdbOid* valOid = &valMid.mMid_Oid; // ref to oid inside mid
+ *valOid = inMid.mMid_Oid; // bitwise copy inMid's oid
+
+ if ( inMid.mMid_Buf )
+ {
+ if ( !valOid->mOid_Scope )
+ store->MidToOid(ev, inMid, valOid);
+ }
+ else if ( !valOid->mOid_Scope )
+ valOid->mOid_Scope = mBuilder_CellAtomScope;
+
+ if ( cell )
+ {
+ morkBookAtom* atom = store->MidToAtom(ev, valMid);
+ if ( atom )
+ cell->SetAtom(ev, atom, store->StorePool());
+ else
+ ev->NewError("undefined cell value alias");
+ }
+ else if ( mParser_InMeta )
+ {
+ mork_token* metaSlot = mBuilder_MetaTokenSlot;
+ if ( metaSlot )
+ {
+ mork_scope valScope = valOid->mOid_Scope;
+ if ( !valScope || valScope == morkStore_kColumnSpaceScope )
+ {
+ if ( ev->Good() && valMid.HasSomeId() )
+ {
+ *metaSlot = valOid->mOid_Id;
+ if ( metaSlot == &mBuilder_TableKind ) // table kind?
+ {
+ if ( mParser_InTable && mBuilder_Table )
+ {
+ mBuilder_Table->mTable_Kind = valOid->mOid_Id;
+ }
+ else
+ ev->NewWarning("mBuilder_TableKind not in table");
+ }
+ else if ( metaSlot == &mBuilder_TableStatus ) // table status?
+ {
+ if ( mParser_InTable && mBuilder_Table )
+ {
+ // $$ what here??
+ }
+ else
+ ev->NewWarning("mBuilder_TableStatus not in table");
+ }
+ }
+ }
+ else
+ this->NonColumnSpaceScopeError(ev);
+ }
+ }
+ else
+ this->NilBuilderCellError(ev);
+}
+
+/*virtual*/ void
+morkBuilder::OnRowMid(morkEnv* ev, const morkSpan& inSpan,
+ const morkMid& inMid)
+// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
+// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
+{
+ MORK_USED_1(inSpan);
+ morkStore* store = mBuilder_Store;
+ morkCell* cell = mBuilder_Cell;
+ if ( cell )
+ {
+ mdbOid rowOid = inMid.mMid_Oid;
+ if ( inMid.mMid_Buf )
+ {
+ if ( !rowOid.mOid_Scope )
+ store->MidToOid(ev, inMid, &rowOid);
+ }
+ else if ( !rowOid.mOid_Scope )
+ rowOid.mOid_Scope = mBuilder_RowRowScope;
+
+ if ( ev->Good() )
+ {
+ morkPool* pool = store->StorePool();
+ morkAtom* atom = pool->NewRowOidAtom(ev, rowOid, &store->mStore_Zone);
+ if ( atom )
+ {
+ cell->SetAtom(ev, atom, pool);
+ morkRow* row = store->OidToRow(ev, &rowOid);
+ if ( row ) // found or created such a row?
+ row->AddRowGcUse(ev);
+ }
+ }
+ }
+ else
+ this->NilBuilderCellError(ev);
+}
+
+/*virtual*/ void
+morkBuilder::OnTableMid(morkEnv* ev, const morkSpan& inSpan,
+ const morkMid& inMid)
+// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
+// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
+{
+ MORK_USED_1(inSpan);
+ morkStore* store = mBuilder_Store;
+ morkCell* cell = mBuilder_Cell;
+ if ( cell )
+ {
+ mdbOid tableOid = inMid.mMid_Oid;
+ if ( inMid.mMid_Buf )
+ {
+ if ( !tableOid.mOid_Scope )
+ store->MidToOid(ev, inMid, &tableOid);
+ }
+ else if ( !tableOid.mOid_Scope )
+ tableOid.mOid_Scope = mBuilder_RowRowScope;
+
+ if ( ev->Good() )
+ {
+ morkPool* pool = store->StorePool();
+ morkAtom* atom = pool->NewTableOidAtom(ev, tableOid, &store->mStore_Zone);
+ if ( atom )
+ {
+ cell->SetAtom(ev, atom, pool);
+ morkTable* table = store->OidToTable(ev, &tableOid,
+ /*optionalMetaRowOid*/ (mdbOid*) 0);
+ if ( table ) // found or created such a table?
+ table->AddTableGcUse(ev);
+ }
+ }
+ }
+ else
+ this->NilBuilderCellError(ev);
+}
+
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkBuilder.h
@@ -0,0 +1,335 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MORKBUILDER_
+#define _MORKBUILDER_ 1
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKPARSER_
+#include "morkParser.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+/*| kCellsVecSize: length of cell vector buffer inside morkBuilder
+|*/
+#define morkBuilder_kCellsVecSize 64
+
+#define morkBuilder_kDefaultBytesPerParseSegment 512 /* plausible to big */
+
+#define morkDerived_kBuilder /*i*/ 0x4275 /* ascii 'Bu' */
+
+class morkBuilder /*d*/ : public morkParser {
+
+// public: // slots inherited from morkParser (meant to inform only)
+ // nsIMdbHeap* mNode_Heap;
+
+ // mork_base mNode_Base; // must equal morkBase_kNode
+ // mork_derived mNode_Derived; // depends on specific node subclass
+
+ // mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
+ // mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
+ // mork_able mNode_Mutable; // can this node be modified?
+ // mork_load mNode_Load; // is this node clean or dirty?
+
+ // mork_uses mNode_Uses; // refcount for strong refs
+ // mork_refs mNode_Refs; // refcount for strong refs + weak refs
+
+
+ // nsIMdbHeap* mParser_Heap; // refcounted heap used for allocation
+ // morkStream* mParser_Stream; // refcounted input stream
+
+ // mork_u4 mParser_Tag; // must equal morkParser_kTag
+ // mork_count mParser_MoreGranularity; // constructor inBytesPerParseSegment
+
+ // mork_u4 mParser_State; // state where parser should resume
+
+ // after finding ends of group transactions, we can re-seek the start:
+ // mork_pos mParser_GroupContentStartPos; // start of this group
+
+ // mdbOid mParser_TableOid; // table oid if inside a table
+ // mdbOid mParser_RowOid; // row oid if inside a row
+ // mork_gid mParser_GroupId; // group ID if inside a group
+
+ // mork_bool mParser_InPort; // called OnNewPort but not OnPortEnd?
+ // mork_bool mParser_InDict; // called OnNewDict but not OnDictEnd?
+ // mork_bool mParser_InCell; // called OnNewCell but not OnCellEnd?
+ // mork_bool mParser_InMeta; // called OnNewMeta but not OnMetaEnd?
+
+ // morkMid mParser_Mid; // current alias being parsed
+ // note that mParser_Mid.mMid_Buf points at mParser_ScopeCoil below:
+
+ // blob coils allocated in mParser_Heap
+ // morkCoil mParser_ScopeCoil; // place to accumulate ID scope blobs
+ // morkCoil mParser_ValueCoil; // place to accumulate value blobs
+ // morkCoil mParser_ColumnCoil; // place to accumulate column blobs
+ // morkCoil mParser_StringCoil; // place to accumulate string blobs
+
+ // morkSpool mParser_ScopeSpool; // writes to mParser_ScopeCoil
+ // morkSpool mParser_ValueSpool; // writes to mParser_ValueCoil
+ // morkSpool mParser_ColumnSpool; // writes to mParser_ColumnCoil
+ // morkSpool mParser_StringSpool; // writes to mParser_StringCoil
+
+ // yarns allocated in mParser_Heap
+ // morkYarn mParser_MidYarn; // place to receive from MidToYarn()
+
+ // span showing current ongoing file position status:
+ // morkSpan mParser_PortSpan; // span of current db port file
+
+ // various spans denoting nested subspaces inside the file's port span:
+ // morkSpan mParser_GroupSpan; // span of current transaction group
+ // morkSpan mParser_DictSpan;
+ // morkSpan mParser_AliasSpan;
+ // morkSpan mParser_MetaDictSpan;
+ // morkSpan mParser_TableSpan;
+ // morkSpan mParser_MetaTableSpan;
+ // morkSpan mParser_RowSpan;
+ // morkSpan mParser_MetaRowSpan;
+ // morkSpan mParser_CellSpan;
+ // morkSpan mParser_ColumnSpan;
+ // morkSpan mParser_SlotSpan;
+
+// ````` ````` ````` ````` ````` ````` ````` `````
+protected: // protected morkBuilder members
+
+ // weak refs that do not prevent closure of referenced nodes:
+ morkStore* mBuilder_Store; // weak ref to builder's store
+
+ // strong refs that do indeed prevent closure of referenced nodes:
+ morkTable* mBuilder_Table; // current table being built (or nil)
+ morkRow* mBuilder_Row; // current row being built (or nil)
+ morkCell* mBuilder_Cell; // current cell within CellsVec (or nil)
+
+ morkRowSpace* mBuilder_RowSpace; // space for mBuilder_CellRowScope
+ morkAtomSpace* mBuilder_AtomSpace; // space for mBuilder_CellAtomScope
+
+ morkAtomSpace* mBuilder_OidAtomSpace; // ground atom space for oids
+ morkAtomSpace* mBuilder_ScopeAtomSpace; // ground atom space for scopes
+
+ // scoped object ids for current objects under construction:
+ mdbOid mBuilder_TableOid; // full oid for current table
+ mdbOid mBuilder_RowOid; // full oid for current row
+
+ // tokens that become set as the result of meta cells in port rows:
+ mork_cscode mBuilder_PortForm; // default port charset format
+ mork_scope mBuilder_PortRowScope; // port row scope
+ mork_scope mBuilder_PortAtomScope; // port atom scope
+
+ // tokens that become set as the result of meta cells in meta tables:
+ mork_cscode mBuilder_TableForm; // default table charset format
+ mork_scope mBuilder_TableRowScope; // table row scope
+ mork_scope mBuilder_TableAtomScope; // table atom scope
+ mork_kind mBuilder_TableKind; // table kind
+
+ mork_token mBuilder_TableStatus; // dummy: priority/unique/verbose
+
+ mork_priority mBuilder_TablePriority; // table priority
+ mork_bool mBuilder_TableIsUnique; // table uniqueness
+ mork_bool mBuilder_TableIsVerbose; // table verboseness
+ mork_u1 mBuilder_TablePadByte; // for u4 alignment
+
+ // tokens that become set as the result of meta cells in meta rows:
+ mork_cscode mBuilder_RowForm; // default row charset format
+ mork_scope mBuilder_RowRowScope; // row scope per row metainfo
+ mork_scope mBuilder_RowAtomScope; // row atom scope
+
+ // meta tokens currently in force, driven by meta info slots above:
+ mork_cscode mBuilder_CellForm; // cell charset format
+ mork_scope mBuilder_CellAtomScope; // cell atom scope
+
+ mork_cscode mBuilder_DictForm; // dict charset format
+ mork_scope mBuilder_DictAtomScope; // dict atom scope
+
+ mork_token* mBuilder_MetaTokenSlot; // pointer to some slot above
+
+ // If any of these 'cut' bools are true, it means a minus was seen in the
+ // Mork source text to indicate removal of content from some container.
+ // (Note there is no corresponding 'add' bool, since add is the default.)
+ // CutRow implies the current row should be cut from the table.
+ // CutCell implies the current column should be cut from the row.
+ mork_bool mBuilder_DoCutRow; // row with kCut change
+ mork_bool mBuilder_DoCutCell; // cell with kCut change
+ mork_u1 mBuilder_row_pad; // pad to u4 alignment
+ mork_u1 mBuilder_cell_pad; // pad to u4 alignment
+
+ morkCell mBuilder_CellsVec[ morkBuilder_kCellsVecSize + 1 ];
+ mork_fill mBuilder_CellsVecFill; // count used in CellsVec
+ // Note when mBuilder_CellsVecFill equals morkBuilder_kCellsVecSize, and
+ // another cell is added, this means all the cells in the vector above
+ // must be flushed to the current row being built to create more room.
+
+protected: // protected inlines
+
+ mork_bool CellVectorIsFull() const
+ { return ( mBuilder_CellsVecFill == morkBuilder_kCellsVecSize ); }
+
+// { ===== begin morkNode interface =====
+public: // morkNode virtual methods
+ virtual void CloseMorkNode(morkEnv* ev); // CloseBuilder() only if open
+ virtual ~morkBuilder(); // assert that CloseBuilder() executed earlier
+
+public: // morkYarn construction & destruction
+ morkBuilder(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
+ morkStream* ioStream, // the readonly stream for input bytes
+ mdb_count inBytesPerParseSegment, // target for ParseMore()
+ nsIMdbHeap* ioSlotHeap, morkStore* ioStore
+ );
+
+ void CloseBuilder(morkEnv* ev); // called by CloseMorkNode();
+
+private: // copying is not allowed
+ morkBuilder(const morkBuilder& other);
+ morkBuilder& operator=(const morkBuilder& other);
+
+public: // dynamic type identification
+ mork_bool IsBuilder() const
+ { return IsNode() && mNode_Derived == morkDerived_kBuilder; }
+// } ===== end morkNode methods =====
+
+public: // errors
+ static void NonBuilderTypeError(morkEnv* ev);
+ static void NilBuilderCellError(morkEnv* ev);
+ static void NilBuilderRowError(morkEnv* ev);
+ static void NilBuilderTableError(morkEnv* ev);
+ static void NonColumnSpaceScopeError(morkEnv* ev);
+
+ void LogGlitch(morkEnv* ev, const morkGlitch& inGlitch,
+ const char* inKind);
+
+public: // other builder methods
+
+ morkCell* AddBuilderCell(morkEnv* ev,
+ const morkMid& inMid, mork_change inChange);
+
+ void FlushBuilderCells(morkEnv* ev);
+
+// ````` ````` ````` ````` ````` ````` ````` `````
+public: // in virtual morkParser methods, data flow subclass to parser
+
+ virtual void MidToYarn(morkEnv* ev,
+ const morkMid& inMid, // typically an alias to concat with strings
+ mdbYarn* outYarn);
+ // The parser might ask that some aliases be turned into yarns, so they
+ // can be concatenated into longer blobs under some circumstances. This
+ // is an alternative to using a long and complex callback for many parts
+ // for a single cell value.
+
+// ````` ````` ````` ````` ````` ````` ````` `````
+public: // out virtual morkParser methods, data flow parser to subclass
+
+ virtual void OnNewPort(morkEnv* ev, const morkPlace& inPlace);
+ virtual void OnPortGlitch(morkEnv* ev, const morkGlitch& inGlitch);
+ virtual void OnPortEnd(morkEnv* ev, const morkSpan& inSpan);
+
+ virtual void OnNewGroup(morkEnv* ev, const morkPlace& inPlace, mork_gid inGid);
+ virtual void OnGroupGlitch(morkEnv* ev, const morkGlitch& inGlitch);
+ virtual void OnGroupCommitEnd(morkEnv* ev, const morkSpan& inSpan);
+ virtual void OnGroupAbortEnd(morkEnv* ev, const morkSpan& inSpan);
+
+ virtual void OnNewPortRow(morkEnv* ev, const morkPlace& inPlace,
+ const morkMid& inMid, mork_change inChange);
+ virtual void OnPortRowGlitch(morkEnv* ev, const morkGlitch& inGlitch);
+ virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan);
+
+ virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace,
+ const morkMid& inMid, mork_bool inCutAllRows);
+ virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch);
+ virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan);
+
+ virtual void OnNewMeta(morkEnv* ev, const morkPlace& inPlace);
+ virtual void OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch);
+ virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan);
+
+ virtual void OnMinusRow(morkEnv* ev);
+ virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace,
+ const morkMid& inMid, mork_bool inCutAllCols);
+ virtual void OnRowPos(morkEnv* ev, mork_pos inRowPos);
+ virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch);
+ virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan);
+
+ virtual void OnNewDict(morkEnv* ev, const morkPlace& inPlace);
+ virtual void OnDictGlitch(morkEnv* ev, const morkGlitch& inGlitch);
+ virtual void OnDictEnd(morkEnv* ev, const morkSpan& inSpan);
+
+ virtual void OnAlias(morkEnv* ev, const morkSpan& inSpan,
+ const morkMid& inMid);
+
+ virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch);
+
+ virtual void OnMinusCell(morkEnv* ev);
+ virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace,
+ const morkMid* inMid, const morkBuf* inBuf);
+ // Exactly one of inMid and inBuf is nil, and the other is non-nil.
+ // When hex ID syntax is used for a column, then inMid is not nil, and
+ // when a naked string names a column, then inBuf is not nil.
+
+ virtual void OnCellGlitch(morkEnv* ev, const morkGlitch& inGlitch);
+ virtual void OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat);
+ virtual void OnCellEnd(morkEnv* ev, const morkSpan& inSpan);
+
+ virtual void OnValue(morkEnv* ev, const morkSpan& inSpan,
+ const morkBuf& inBuf);
+
+ virtual void OnValueMid(morkEnv* ev, const morkSpan& inSpan,
+ const morkMid& inMid);
+
+ virtual void OnRowMid(morkEnv* ev, const morkSpan& inSpan,
+ const morkMid& inMid);
+
+ virtual void OnTableMid(morkEnv* ev, const morkSpan& inSpan,
+ const morkMid& inMid);
+
+// ````` ````` ````` ````` ````` ````` ````` `````
+public: // public non-poly morkBuilder methods
+
+
+public: // typesafe refcounting inlines calling inherited morkNode methods
+ static void SlotWeakBuilder(morkBuilder* me,
+ morkEnv* ev, morkBuilder** ioSlot)
+ { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+
+ static void SlotStrongBuilder(morkBuilder* me,
+ morkEnv* ev, morkBuilder** ioSlot)
+ { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#endif /* _MORKBUILDER_ */
new file mode 100644
--- /dev/null
+++ b/db/mork/src/morkCell.cpp
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MDB_
+#include "mdb.h"
+#endif
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKNODE_
+#include "morkNode.h"
+#endif
+
+#ifndef _MORKSTORE_
+#include "morkStore.h"
+#endif
+
+#ifndef _MORKPOOL_
+#include "morkPool.h"
+#endif
+
+#ifndef _MORKENV_
+#include "morkEnv.h"
+#endif
+
+#ifndef _MORKCELL_
+#include "morkCell.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+void
+morkCell::SetYarn(morkEnv* ev, const mdbYarn* inYarn, morkStore* ioStore)
+{
+ morkAtom* atom = ioStore->YarnToAtom(ev, inYarn, PR_TRUE /* create */);
+ if ( atom )
+ this->SetAtom(ev, atom, ioStore->StorePool()); // refcounts atom
+}
+
+void
+morkCell::GetYarn(morkEnv* ev, mdbYarn* outYarn) const
+{
+ MORK_USED_1(ev);
+ mCell_Atom->GetYarn(outYarn);
+}
+
+void
+morkCell::AliasYarn(morkEnv* ev, mdbYarn* outYarn) const
+{
+ MORK_USED_1(ev);
+ mCell_Atom->AliasYarn(outYarn);
+}
+
+
+void
+morkCell::SetCellClean()
+{
+ mork_column col = this->GetColumn();
+ this->SetColumnAndChange(col, morkChange_kNil);
+}
+
+void
+morkCell::SetCellDirty()
+{
+ mork_column col = this->GetColumn();
+ this->SetColumnAndChange(col, morkChange_kAdd);
+}
+
+void
+morkCell::SetAtom(morkEnv* ev, morkAtom* ioAtom, morkPool* ioPool)
+ // SetAtom() "acquires" the new ioAtom if non-nil, by calling AddCellUse()
+ // to increase the refcount, and puts ioAtom into mCell_Atom. If the old
+ // atom in mCell_Atom is non-nil, then it is "released" first by a call to
+ // CutCellUse(), and if the use count then becomes zero, then the old atom
+ // is deallocated by returning it to the pool ioPool. (And this is
+ // why ioPool is a parameter to this method.) Note that ioAtom can be nil
+ // to cause the cell to refer to nothing, and the old atom in mCell_Atom
+ // can also be nil, and all the atom refcounting is handled correctly.
+ //
+ // Note that if ioAtom was just created, it typically has a zero use count
+ // before calling SetAtom(). But use count is one higher after SetAtom().
+{
+ morkAtom* oldAtom = mCell_Atom;
+ if ( oldAtom != ioAtom ) // ioAtom is not already installed in this cell?
+ {
+ if ( oldAtom )
+ {
+ mCell_Atom = 0;
+ if ( oldAtom->CutCellUse(ev) == 0 )
+ {
+ // this was zapping atoms still in use - comment out until davidmc
+ // can figure out a better fix.
+// if ( ioPool )
+// {
+// if ( oldAtom->IsBook() )
+// ((morkBookAtom*) oldAtom)->CutBookAtomFromSpace(ev);
+
+// ioPool->ZapAtom(ev, oldAtom);
+// }
+// else
+// ev->NilPointerError();
+ }
+ }
+ if ( ioAtom )