Browse Source

Initial revision

Dave Beckett 19 years ago
parent
commit
5a459893ae
39 changed files with 4850 additions and 0 deletions
  1. 16 0
      .cvsignore
  2. 67 0
      APIs
  3. 1 0
      AUTHORS
  4. 339 0
      COPYING
  5. 7 0
      ChangeLog
  6. 11 0
      INTERPRETATIONS
  7. 38 0
      Makefile.am
  8. 0 0
      NEWS
  9. 38 0
      README
  10. 25 0
      acconfig.h
  11. 15 0
      acinclude.m4
  12. 143 0
      aclocal.m4
  13. 41 0
      bithelp.h
  14. 132 0
      configure.in
  15. 16 0
      librdf/.cvsignore
  16. 38 0
      librdf/Makefile.am
  17. 319 0
      librdf/rdf_digest.c
  18. 94 0
      librdf/rdf_digest.h
  19. 378 0
      librdf/rdf_hash.c
  20. 124 0
      librdf/rdf_hash.h
  21. 227 0
      librdf/rdf_hash_gdbm.c
  22. 23 0
      librdf/rdf_hash_gdbm.h
  23. 40 0
      librdf/rdf_init.c
  24. 68 0
      librdf/rdf_model.h
  25. 348 0
      librdf/rdf_node.c
  26. 96 0
      librdf/rdf_node.h
  27. 215 0
      librdf/rdf_statement.c
  28. 57 0
      librdf/rdf_statement.h
  29. 111 0
      librdf/rdf_uri.c
  30. 52 0
      librdf/rdf_uri.h
  31. 342 0
      md5.c
  32. 49 0
      rdf_config.h
  33. 24 0
      rdf_hash_db.c
  34. 280 0
      rdf_hash_list.c
  35. 23 0
      rdf_hash_list.h
  36. 35 0
      rmd.h
  37. 563 0
      rmd160.c
  38. 336 0
      sha1.c
  39. 119 0
      types.h

+ 16 - 0
.cvsignore

@@ -0,0 +1,16 @@
+Doxyfile
+Makefile
+Makefile.in
+RCS
+config.cache
+config.h*
+config.log
+config.status
+configure
+gnupg*
+java-model
+librdf*gz
+not-used
+stamp-h*
+test*
+.deps*

+ 67 - 0
APIs

@@ -0,0 +1,67 @@
+
+Mozilla  - http://www.mozilla.org/rdf/back-end-architecture.html
+
+  Resource - uniquely identified by a URI (not true M&S)
+    Interface nsIRDFResource - http://lxr.mozilla.org/seamonkey/source/rdf/base/idl/nsIRDFResource.idl
+
+  Literal  - uniquely maps to a string (not true M&S)
+    Interface nsIRDFLiteral - http://lxr.mozilla.org/seamonkey/source/rdf/base/idl/nsIRDFLiteral.idl
+
+  Interface nsIRDFNode - Resource or Literal
+     http://lxr.mozilla.org/seamonkey/source/rdf/base/idl/nsIRDFNode.idl
+    
+    method - equalsNode
+
+    3 implementations for wstring, long long and long values.
+
+  Statement - consists of:
+     subject (Resource), predicate (Resource) and object (Resource / Literal)
+
+  [Property not defined]
+
+  [Reification - not used ]
+
+  Data Source - sets of Statements, querying and triple operations
+    Interface nsIRDFDataSource - http://lxr.mozilla.org/seamonkey/source/rdf/base/idl/nsIRDFDataSource.idl
+    
+    Querying:
+      Node GetSource(Resource Source, Node target)
+      Enumerator GetSources(Resource Source, Node target)
+      Node GetTarget(Resource Source, Resource property)
+      Enumerator GetTargets(Resource Source, Resource property)
+
+    Entering / removing triples
+      void Assert(Resource source, Resource property, Node target)
+      void Unassert(Resource source, Resource property, Node target)
+      bool hasAssertion(Resource source, Resource property, Node target)
+ 
+    Modification
+      void change(Resource source, Resource property, Node oldtarget, Node newtarget)
+      void move(Resource oldsource, Resource newsource, Resource property, Node target)
+
+    (observing)
+
+    Cursors
+      Enumerator ArcLabelsIn(Node node)
+      Enumerator ArcLabelsOut(Resource source)
+
+
+    Enumerator GetAllResources()
+
+  Interface nsIRDFService - manages named datasources
+    http://lxr.mozilla.org/seamonkey/source/rdf/base/idl/nsIRDFService.idl
+
+  Interface nsIRDFCompositeDataSource - combines datasources, acts as one
+    http://lxr.mozilla.org/seamonkey/source/rdf/base/idl/nsIRDFCompositeDataSource.idl
+
+  Interface nsIRDFObserver, nsIRDFContainer - user side for access
+
+
+  Interface SimpleEnumerator
+     http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsIEnumerator.idl
+
+     bool hasMoreElements()
+     void* getNext();
+
+ 
+

+ 1 - 0
AUTHORS

@@ -0,0 +1 @@
+Dave Beckett <Dave.Beckett@bristol.ac.uk>

+ 339 - 0
COPYING

@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

+ 7 - 0
ChangeLog

@@ -0,0 +1,7 @@
+2000-06-21  Dave Beckett  <cmdjb@jarjar.ilrt.bris.ac.uk>
+
+	* It compiles and builds as a GNU automake/conf suite with 
+	'make distcheck' and 'make check'
+
+
+

+ 11 - 0
INTERPRETATIONS

@@ -0,0 +1,11 @@
+M&S[x] refers to RDF Model and Syntax serialisation syntax production [x]
+- see http://www.w3.org/TR/REC-rdf-syntax/
+
+In RDF/XML
+  A description contains propertyElts and describes an identified resource - M&S [2]
+  A propertyElt is either a property+value or property+resource reference
+  A property has a namespace prefix + name - M&S [6],[7],[10
+  A resource has a URI reference or an ID - M&S [4],[9]
+  A value is either a description or a string - M&S [8]
+
+=> FOR NOW, IGNORING URI / namespace prefix+ name distinction

+ 38 - 0
Makefile.am

@@ -0,0 +1,38 @@
+#
+# automake-file for librdf
+#
+# $Source$
+# $Id$
+#
+#
+
+noinst_LIBRARIES = librdf.a
+
+librdf_a_SOURCES = rdf_init.c rdf_uri.c rdf_node.c rdf_statement.c rdf_digest.c \
+rdf_hash.c rdf_hash_list.c \
+rdf_config.h \
+rdf_uri.h rdf_node.h rdf_statement.h rdf_digest.h rdf_hash.h rdf_hash_gdbm.h \
+rdf_hash_list.h \
+bithelp.h types.h rmd.h
+
+librdf_a_LIBADD = @DIGEST_OBJS@ @HASH_OBJS@
+librdf_a_DEPENDENCIES = @DIGEST_OBJS@ @HASH_OBJS@
+EXTRA_librdf_a_SOURCES = md5.c sha1.c rmd160.c rdf_hash_gdbm.c
+
+TESTS=rdf_node_test rdf_digest_test rdf_hash_test rdf_statement_test
+
+CLEANFILES=$(TESTS) test.gdbm
+
+CFLAGS=-g -Wall
+
+rdf_node_test: rdf_node.c librdf.a
+	$(LINK) -I$(srcdir) -I. -DRDF_NODE_TEST $(srcdir)/rdf_node.c librdf.a
+
+rdf_digest_test: rdf_digest.c librdf.a
+	$(LINK) -I$(srcdir) -I. -DRDF_DIGEST_TEST $(srcdir)/rdf_digest.c librdf.a
+
+rdf_statement_test: rdf_statement.c librdf.a
+	$(LINK) -I$(srcdir) -I. -DRDF_STATEMENT_TEST $(srcdir)/rdf_statement.c librdf.a
+
+rdf_hash_test: rdf_hash.c librdf.a
+	$(LINK) -I$(srcdir) -I. -DRDF_HASH_TEST $(srcdir)/rdf_hash.c librdf.a $(LIBS)

+ 0 - 0
NEWS


+ 38 - 0
README

@@ -0,0 +1,38 @@
+Bits taken from GNUPG 1.0.1 (GPL license)
+bithelp.h types.h md5.c rmd.h rmd160.c sha1.c
+
+
+
+Interface Design for 'Classes'
+
+Prototypes and structures (aka Interface) in rdf_foo.h
+
+Implementation and static variables in rdf_foo.c
+
+simple constructor
+  new_rdf_foo(void)
+returns
+  rdf_foo*
+
+complex constructor(s)
+  new_rdf_foo_from_X(X* x)
+returns
+  rdf_foo*
+
+destructor
+  free_rdf_foo(void)
+returns
+  rdf_foo*
+
+class initialiser
+   void init_rdf_foo(void)
+
+methods
+  ... rdf_foo_method1(...)
+returns
+  ...
+
+
+methods called
+   ..._as_string do not allocate a new string
+   ..._to_string use RDF_MALLOC to create a new string that must be freed

+ 25 - 0
acconfig.h

@@ -0,0 +1,25 @@
+/* package name */
+#define PACKAGE
+
+/* package version */
+#define VERSION
+
+/* defined if specific types are already defined as typedefs */
+#undef HAVE_BYTE_TYPEDEF
+#undef HAVE_USHORT_TYPEDEF
+#undef HAVE_ULONG_TYPEDEF
+#undef HAVE_U16_TYPEDEF
+#undef HAVE_U32_TYPEDEF
+
+/* defined if specific message digests are available */
+#undef HAVE_SHA1_DIGEST
+#undef HAVE_MD5_DIGEST
+#undef HAVE_RIPEM160_DIGEST
+
+/* defined if specific message digests are available */
+#undef HAVE_OPENSSL_CRYPTO_MD5_DIGEST
+#undef HAVE_OPENSSL_CRYPTO_SHA1_DIGEST
+#undef HAVE_OPENSSL_CRYPTO_RIPEM160_DIGEST
+
+/* defined if specific hashes are available */
+#undef HAVE_GDBM_HASH

+ 15 - 0
acinclude.m4

@@ -0,0 +1,15 @@
+AC_DEFUN(GNUPG_CHECK_TYPEDEF,
+  [ AC_MSG_CHECKING(for $1 typedef)
+    AC_CACHE_VAL(gnupg_cv_typedef_$1,
+    [AC_TRY_COMPILE([#include <stdlib.h>
+    #include <sys/types.h>], [
+    #undef $1
+    int a = sizeof($1);
+    ], gnupg_cv_typedef_$1=yes, gnupg_cv_typedef_$1=no )])
+    AC_MSG_RESULT($gnupg_cv_typedef_$1)
+    if test "$gnupg_cv_typedef_$1" = yes; then
+        AC_DEFINE($2)
+    fi
+  ])
+
+

+ 143 - 0
aclocal.m4

@@ -0,0 +1,143 @@
+dnl aclocal.m4 generated automatically by aclocal 1.4
+
+dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+AC_DEFUN(GNUPG_CHECK_TYPEDEF,
+  [ AC_MSG_CHECKING(for $1 typedef)
+    AC_CACHE_VAL(gnupg_cv_typedef_$1,
+    [AC_TRY_COMPILE([#include <stdlib.h>
+    #include <sys/types.h>], [
+    #undef $1
+    int a = sizeof($1);
+    ], gnupg_cv_typedef_$1=yes, gnupg_cv_typedef_$1=no )])
+    AC_MSG_RESULT($gnupg_cv_typedef_$1)
+    if test "$gnupg_cv_typedef_$1" = yes; then
+        AC_DEFINE($2)
+    fi
+  ])
+
+
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file.
+
+AC_DEFUN(AM_CONFIG_HEADER,
+[AC_PREREQ([2.12])
+AC_CONFIG_HEADER([$1])
+dnl When config.status generates a header, we must update the stamp-h file.
+dnl This file resides in the same directory as the config header
+dnl that is generated.  We must strip everything past the first ":",
+dnl and everything past the last "/".
+AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
+ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>,
+<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>,
+<<am_indx=1
+for am_file in <<$1>>; do
+  case " <<$>>CONFIG_HEADERS " in
+  *" <<$>>am_file "*<<)>>
+    echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx
+    ;;
+  esac
+  am_indx=`expr "<<$>>am_indx" + 1`
+done<<>>dnl>>)
+changequote([,]))])
+
+# Do all the work for Automake.  This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN(AM_INIT_AUTOMAKE,
+[AC_REQUIRE([AC_PROG_INSTALL])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN(AM_SANITY_CHECK,
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "[$]*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "[$]*" != "X $srcdir/configure conftestfile" \
+      && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "[$]2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN(AM_MISSING_PROG,
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+   $1=$2
+   AC_MSG_RESULT(found)
+else
+   $1="$3/missing $2"
+   AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+

+ 41 - 0
bithelp.h

@@ -0,0 +1,41 @@
+/* bithelp.h  -  Some bit manipulation helpers
+ *	Copyright (C) 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_BITHELP_H
+#define G10_BITHELP_H
+
+
+/****************
+ * Rotate a 32 bit integer by n bytes
+ */
+#if defined(__GNUC__) && defined(__i386__)
+static inline u32
+rol( u32 x, int n)
+{
+	__asm__("roll %%cl,%0"
+		:"=r" (x)
+		:"0" (x),"c" (n));
+	return x;
+}
+#else
+  #define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
+#endif
+
+
+#endif /*G10_BITHELP_H*/

+ 132 - 0
configure.in

@@ -0,0 +1,132 @@
+dnl
+dnl Configure for librdf
+dnl
+dnl (Process this file with autoconf to produce a configure script.)
+
+AC_REVISION($Revision$)dnl
+
+AC_PREREQ(2.13)
+AC_INIT(rdf_node.c)
+AM_CONFIG_HEADER(config.h)
+
+AM_INIT_AUTOMAKE(librdf, 1.0)
+
+
+dnl Checks for programs.
+
+AC_CANONICAL_HOST
+AC_ARG_PROGRAM
+AM_SANITY_CHECK
+AC_PROG_CC
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+
+
+dnl Checks for libraries.
+
+AC_CHECK_HEADERS(gdbm.h)
+if test "$ac_cv_header_gdbm_h" = yes ; then
+  AC_CHECK_LIB(gdbm,gdbm_firstkey)
+fi
+
+AC_CHECK_HEADERS(openssl/crypto.h)
+if test "$ac_cv_header_openssl_crypto_h" = yes ; then
+  AC_CHECK_LIB(crypto,MD5)
+  if test "$ac_cv_lib_crypto_MD5" = yes ; then
+    AC_DEFINE(HAVE_OPENSSL_CRYPTO_MD5_DIGEST)
+  fi
+  AC_CHECK_LIB(crypto,SHA)
+  if test "$ac_cv_lib_crypto_SHA" = yes ; then
+    AC_DEFINE(HAVE_OPENSSL_CRYPTO_SHA1_DIGEST)
+  fi
+fi
+
+
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(unistd.h stdlib.h)
+
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_C_BIGENDIAN
+
+GNUPG_CHECK_TYPEDEF(byte, HAVE_BYTE_TYPEDEF)
+GNUPG_CHECK_TYPEDEF(ushort, HAVE_USHORT_TYPEDEF)
+GNUPG_CHECK_TYPEDEF(ulong, HAVE_ULONG_TYPEDEF)
+GNUPG_CHECK_TYPEDEF(u16, HAVE_U16_TYPEDEF)
+GNUPG_CHECK_TYPEDEF(u32, HAVE_U32_TYPEDEF)
+
+AC_CHECK_SIZEOF(unsigned short, 2)
+AC_CHECK_SIZEOF(unsigned int, 4)
+AC_CHECK_SIZEOF(unsigned long, 4)
+
+if test "$ac_cv_sizeof_unsigned_short" = "0" \
+   || test "$ac_cv_sizeof_unsigned_int" = "0" \
+   || test "$ac_cv_sizeof_unsigned_long" = "0"; then
+    AC_MSG_WARN([Hmmm, something is wrong with the sizes - using defaults]);
+fi
+
+
+dnl Checks for library functions.
+
+
+dnl Checks for modules
+DIGEST_OBJS=
+DIGEST_SRCS=
+AC_MSG_CHECKING(for sha1 digest module)
+if test -r $srcdir/sha1.c; then
+  AC_MSG_RESULT(yes);
+  AC_DEFINE(HAVE_SHA1_DIGEST)
+  DIGEST_OBJS="$DIGEST_OBJS sha1.o"
+  DIGEST_SRCS="$DIGEST_SRCS sha1.c"
+else
+  AC_MSG_RESULT(no);
+
+fi
+AC_MSG_CHECKING(for md5 digest module)
+if test -r $srcdir/md5.c; then
+  AC_MSG_RESULT(yes);
+  AC_DEFINE(HAVE_MD5_DIGEST)
+  DIGEST_OBJS="$DIGEST_OBJS md5.o"
+  DIGEST_SRCS="$DIGEST_SRCS md5.c"
+else
+  AC_MSG_RESULT(no);
+fi
+AC_MSG_CHECKING(for ripem160 digest module)
+if test -r $srcdir/rmd160.c; then
+  AC_MSG_RESULT(yes);
+  AC_DEFINE(HAVE_RIPEM160_DIGEST)
+  DIGEST_OBJS="$DIGEST_OBJS rmd160.o"
+  DIGEST_SRCS="$DIGEST_SRCS rmd160.c"
+else
+  AC_MSG_RESULT(no);
+fi
+AC_SUBST(DIGEST_OBJS)
+AC_SUBST(DIGEST_SRCS)
+
+
+HASH_OBJS=
+HASH_SRCS=
+AC_MSG_CHECKING(for libgdbm support)
+if test "$ac_cv_lib_gdbm_gdbm_firstkey" = yes ; then
+  AC_MSG_RESULT(yes);
+  AC_DEFINE(HAVE_GDBM_HASH)
+  HASH_OBJS="$HASH_OBJS rdf_hash_gdbm.o"
+  HASH_SRCS="$HASH_SRCS rdf_hash_gdbm.o"
+  LIBS="$LIBS -lgdbm"
+else
+  AC_MSG_RESULT(no);
+fi
+AC_SUBST(HASH_OBJS)
+AC_SUBST(HASH_SRCS)
+
+
+AC_OUTPUT([Makefile])

+ 16 - 0
librdf/.cvsignore

@@ -0,0 +1,16 @@
+Doxyfile
+Makefile
+Makefile.in
+RCS
+config.cache
+config.h*
+config.log
+config.status
+configure
+gnupg*
+java-model
+librdf*gz
+not-used
+stamp-h*
+test*
+.deps*

+ 38 - 0
librdf/Makefile.am

@@ -0,0 +1,38 @@
+#
+# automake-file for librdf
+#
+# $Source$
+# $Id$
+#
+#
+
+noinst_LIBRARIES = librdf.a
+
+librdf_a_SOURCES = rdf_init.c rdf_uri.c rdf_node.c rdf_statement.c rdf_digest.c \
+rdf_hash.c rdf_hash_list.c \
+rdf_config.h \
+rdf_uri.h rdf_node.h rdf_statement.h rdf_digest.h rdf_hash.h rdf_hash_gdbm.h \
+rdf_hash_list.h \
+bithelp.h types.h rmd.h
+
+librdf_a_LIBADD = @DIGEST_OBJS@ @HASH_OBJS@
+librdf_a_DEPENDENCIES = @DIGEST_OBJS@ @HASH_OBJS@
+EXTRA_librdf_a_SOURCES = md5.c sha1.c rmd160.c rdf_hash_gdbm.c
+
+TESTS=rdf_node_test rdf_digest_test rdf_hash_test rdf_statement_test
+
+CLEANFILES=$(TESTS) test.gdbm
+
+CFLAGS=-g -Wall
+
+rdf_node_test: rdf_node.c librdf.a
+	$(LINK) -I$(srcdir) -I. -DRDF_NODE_TEST $(srcdir)/rdf_node.c librdf.a
+
+rdf_digest_test: rdf_digest.c librdf.a
+	$(LINK) -I$(srcdir) -I. -DRDF_DIGEST_TEST $(srcdir)/rdf_digest.c librdf.a
+
+rdf_statement_test: rdf_statement.c librdf.a
+	$(LINK) -I$(srcdir) -I. -DRDF_STATEMENT_TEST $(srcdir)/rdf_statement.c librdf.a
+
+rdf_hash_test: rdf_hash.c librdf.a
+	$(LINK) -I$(srcdir) -I. -DRDF_HASH_TEST $(srcdir)/rdf_hash.c librdf.a $(LIBS)

+ 319 - 0
librdf/rdf_digest.c

@@ -0,0 +1,319 @@
+/*
+ * RDF Digest Factory / Digest implementation
+ *
+ * $Source$
+ * $Id$
+ *
+ * (C) Dave Beckett 2000 ILRT, University of Bristol
+ * http://www.ilrt.bristol.ac.uk/people/cmdjb/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <rdf_config.h>
+#include <rdf_digest.h>
+#include <rdf_uri.h>
+
+
+/** List of digest factories */
+static rdf_digest_factory *digests=NULL;
+
+
+/** register a hash factory
+ * @param name the name of the hash
+ * @param factory function to be called to register the factor parameters
+ */
+void
+rdf_digest_register_factory(const char *name,
+                           void (*factory) (rdf_digest_factory*)
+                           )
+{
+  rdf_digest_factory *d, *digest;
+  char *name_copy;
+
+  RDF_DEBUG2(rdf_digest_register_factory,
+             "Received registration for digest %s\n", name);
+
+  digest=(rdf_digest_factory*)RDF_CALLOC(rdf_digest_factory, sizeof(rdf_digest_factory), 1);
+  if(!digest)
+    RDF_FATAL(rdf_digest_register_factory, "Out of memory\n");
+
+  name_copy=(char*)RDF_CALLOC(cstring, strlen(name)+1, 1);
+  if(!name_copy) {
+    RDF_FREE(rdf_digest, digest);
+    RDF_FATAL(rdf_digest_register_factory, "Out of memory\n");
+  }
+  strcpy(name_copy, name);
+  digest->name=name_copy;
+
+  for(d = digests; d; d = d->next ) {
+    if(!strcmp(d->name, name_copy)) {
+      RDF_FATAL2(rdf_digest_register_factory, "digest %s already registered\n", d->name);
+    }
+  }
+
+  
+
+  /* Call the digest registration function on the new object */
+  (*factory)(digest);
+
+
+  RDF_DEBUG4(rdf_digest_register_factory, "%s has context size %d and digest size %d\n", name, digest->context_length, digest->digest_length);
+
+  digest->next = digests;
+  digests = digest;
+  
+}
+
+/** get a digest factory
+ * @param name the name of the factor
+ * @returns the factory or NULL if not found
+ */
+rdf_digest_factory*
+get_rdf_digest_factory(const char *name) 
+{
+  rdf_digest_factory *factory;
+
+  /* return 1st digest if no particular one wanted - why? */
+  if(!name) {
+    factory=digests;
+    if(!factory) {
+      RDF_DEBUG(get_rdf_digest_factory, "No (default) digests registered\n");
+      return NULL;
+    }
+  } else {
+    for(factory=digests; factory; factory=factory->next) {
+      if(!strcmp(factory->name, name)) {
+        break;
+      }
+    }
+    /* else FACTORY with name digest_name not found */
+    if(!factory) {
+      RDF_DEBUG2(get_rdf_digest_factory, "No digest with name %s found\n",
+              name);
+      return NULL;
+    }
+  }
+  
+  return factory;
+}
+
+
+/** rdf_digest object constructor
+ * @param factory the digest factory to use to create this digest
+ */
+rdf_digest*
+new_rdf_digest(rdf_digest_factory *factory)
+{
+  rdf_digest* d;
+
+  d=(rdf_digest*)RDF_CALLOC(rdf_digest, sizeof(rdf_digest), 1);
+  if(!d)
+    return NULL;
+
+  d->context=(char*)RDF_CALLOC(digest_context, factory->context_length, 1);
+  if(!d->context) {
+    free_rdf_digest(d);
+    return NULL;
+  }
+
+  d->digest=(unsigned char*)RDF_CALLOC(digest_digest, factory->digest_length, 1);
+  if(!d->digest) {
+    free_rdf_digest(d);
+    return NULL;
+  }
+
+  d->factory=factory;
+  
+  return d;
+}
+
+
+/** rdf_digest object destructor
+ * @param digest the digest
+ */
+void
+free_rdf_digest(rdf_digest *digest) 
+{
+  if(digest->context)
+    RDF_FREE(digest_context, digest->context);
+  if(digest->digest)
+    RDF_FREE(digest_digest, digest->digest);
+  RDF_FREE(rdf_digest, digest);
+}
+
+
+
+/* methods */
+
+/** initialise/reinitialise the digest
+ * @param digest the digest
+ */
+void
+rdf_digest_init(rdf_digest* digest) 
+{
+  (*(digest->factory->init))(digest->context);
+}
+
+
+/** add more data to the digest
+ * @param digest the digest
+ * @param buf the data buffer
+ * @param the length of the data
+ */
+void
+rdf_digest_update(rdf_digest* digest, unsigned char *buf, size_t length) 
+{
+  (*(digest->factory->update))(digest->context, buf, length);
+}
+
+
+/** finish digesting
+ * @param digest the digest
+ * @see rdf_digest_get_digest
+ */
+void
+rdf_digest_final(rdf_digest* digest) 
+{
+  void* digest_data;
+  
+  (*(digest->factory->final))(digest->context);
+
+  digest_data=(*(digest->factory->get_digest))(digest->context);
+  memcpy(digest->digest, digest_data, digest->factory->digest_length);
+}
+
+
+/** return the digest data
+ * @param digest the digest
+ */
+void*
+rdf_digest_get_digest(rdf_digest* digest)
+{
+  return digest->digest;
+}
+
+
+/** convert the digest object to a string representation
+ * @note assumes that the digest has been finalised
+ * @node allocates a new string since this is a _to_ method
+ * @returns an allocated string that must be freed by the caller
+ */
+char *
+rdf_digest_to_string(rdf_digest* digest)
+{
+  unsigned char* data=digest->digest;
+  int mdlen=digest->factory->digest_length;
+  char* b;
+  int i;
+  
+  b=(char*)RDF_MALLOC(cstring, 1+(mdlen<<1));
+  if(!b) {
+    RDF_DEBUG(rdf_digest_to_string, "Out of memory\n");
+    return NULL;
+  }
+  
+  for(i=0; i<mdlen; i++)
+    sprintf(b+(i<<1), "%02x", (unsigned int)data[i]);
+  b[i<<1]='\0';
+  
+  return(b);
+}
+
+
+/* fh is actually a FILE* */
+void
+rdf_digest_print(rdf_digest* digest, FILE* fh)
+{
+  char *s=rdf_digest_to_string(digest);
+  
+  if(!s)
+    return;
+  fputs(s, fh);
+  RDF_FREE(cstring, s);
+}
+
+
+/* class initialisation */
+
+void
+init_rdf_digest(void) 
+{
+#ifdef HAVE_SHA1_DIGEST
+  sha1_constructor();
+#endif
+#ifdef HAVE_MD5_DIGEST
+  md5_constructor();
+#endif
+#ifdef HAVE_RIPEM160_DIGEST
+  rmd160_constructor();
+#endif
+}
+
+
+
+#ifdef RDF_DIGEST_TEST
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+
+int
+main(int argc, char *argv[]) 
+{
+  rdf_digest_factory* factory;
+  rdf_digest* d;
+  char *test_data="http://www.ilrt.bristol.ac.uk/people/cmdjb/";
+  char *test_digest_types[]={"MD5", "SHA1", "FAKE", "RIPEM160", NULL};
+  int i;
+  char *type;
+  char *program=argv[0];
+  
+  
+  /* initialise digest module */
+  init_rdf_digest();
+
+  for(i=0; (type=test_digest_types[i]); i++) {
+    fprintf(stderr, "%s: Trying to create new %s digest\n", program, type);
+    factory=get_rdf_digest_factory(type);
+    if(!factory) {
+      fprintf(stderr, "%s: No digest factory called %s\n", program, type);
+      continue;
+    }
+    
+    d=new_rdf_digest(factory);
+    if(!d) {
+      fprintf(stderr, "%s: Failed to create new digest type %s\n", program, type);
+      continue;
+    }
+    fprintf(stderr, "%s: Initialising digest type %s\n", program, type);
+    rdf_digest_init(d);
+
+    fprintf(stderr, "%s: Writing data into digest\n", program);
+    rdf_digest_update(d, (unsigned char*)test_data, strlen(test_data));
+
+    fprintf(stderr, "%s: Finishing digesting\n", program);
+    rdf_digest_final(d);
+
+    fprintf(stderr, "%s: %s digest of data is: ", program, type);
+    rdf_digest_print(d, stderr);
+    fprintf(stderr, "\n");
+    
+    fprintf(stderr, "%s: Freeing digest\n", program);
+    free_rdf_digest(d);
+  }
+  
+    
+  /* keep gcc -Wall happy */
+  return(0);
+}
+
+#endif

+ 94 - 0
librdf/rdf_digest.h

@@ -0,0 +1,94 @@
+/*
+ * RDF Digest Factory / Digest interfaces and definition
+ *
+ * $Source$
+ * $Id$
+ *
+ * (C) Dave Beckett 2000 ILRT, University of Bristol
+ * http://www.ilrt.bristol.ac.uk/people/cmdjb/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+
+#ifndef RDF_DIGEST_H
+#define RDF_DIGEST_H
+
+typedef void* RDF_DIGEST;
+
+/* based on the GNUPG cipher/digest registration stuff */
+struct rdf_digest_factory_s 
+{
+  struct rdf_digest_factory_s* next;
+  char *   name;
+
+  /* the rest of this structure is populated by the
+     digest-specific register function */
+  const char * version;
+  size_t  context_length;
+  size_t  digest_length;
+
+  /* functions (over context) */
+  void (*init)( void *c );
+  void (*update)( void *c, unsigned char *buf, size_t nbytes );
+  void (*final)( void *c );
+  unsigned char *(*get_digest)( void *c );
+};
+typedef struct rdf_digest_factory_s rdf_digest_factory;
+
+
+typedef struct
+{
+  char *context;
+  unsigned char *digest;
+  rdf_digest_factory* factory;
+} rdf_digest;
+
+
+void
+rdf_digest_register_factory(const char *name,
+                            void (*factory) (rdf_digest_factory*)
+                            );
+
+rdf_digest_factory*
+get_rdf_digest_factory(const char *name);
+
+
+/* module init */
+void init_rdf_digest(void);
+                    
+/* constructor */
+rdf_digest* new_rdf_digest(rdf_digest_factory *factory);
+
+/* destructor */
+void free_rdf_digest(rdf_digest *digest);
+
+
+/* methods */
+void rdf_digest_init(rdf_digest* digest);
+void rdf_digest_update(rdf_digest* digest, unsigned char *buf, size_t length);
+void rdf_digest_final(rdf_digest* digest);
+void* rdf_digest_get_digest(rdf_digest* digest);
+
+char* rdf_digest_to_string(rdf_digest* digest);
+void rdf_digest_print(rdf_digest* digest, FILE* fh);
+
+
+/* in sha1.c */
+#ifdef HAVE_SHA1_DIGEST
+void sha1_constructor(void);
+#endif
+/* in md5.c */
+#ifdef HAVE_MD5_DIGEST
+void md5_constructor(void);
+#endif
+/* in rmd160.c */
+#ifdef HAVE_RIPEM160_DIGEST
+void rmd160_constructor(void);
+#endif
+
+#endif

+ 378 - 0
librdf/rdf_hash.c

@@ -0,0 +1,378 @@
+/*
+ * RDF HASH Implementation
+ *
+ * $Source$
+ * $Id$
+ *
+ * (C) Dave Beckett 2000 ILRT, University of Bristol
+ * http://www.ilrt.bristol.ac.uk/people/cmdjb/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <rdf_config.h>
+
+#include <rdf_hash.h>
+#ifdef HAVE_GDBM_HASH
+#include <rdf_hash_gdbm.h>
+#endif
+#include <rdf_hash_list.h>
+
+
+/** initialise module */
+void
+init_rdf_hash(void) 
+{
+#ifdef HAVE_GDBM_HASH
+  init_rdf_hash_gdbm();
+#endif
+  init_rdf_hash_list();
+}
+
+/** list of hash factories */
+static rdf_hash_factory* hashes;
+
+
+/* class methods */
+
+/** register a hash factory */
+void rdf_hash_register_factory(const char *name,
+                               void (*factory) (rdf_hash_factory*)
+                               ) 
+{
+  rdf_hash_factory *hash, *h;
+  char *name_copy;
+
+  RDF_DEBUG2(rdf_hash_register_factory,
+             "Received registration for hash %s\n", name);
+
+  hash=(rdf_hash_factory*)RDF_CALLOC(rdf_hash_factory, sizeof(rdf_hash_factory), 1);
+  if(!hash)
+    RDF_FATAL(rdf_hash_register_factory, "Out of memory\n");
+
+  name_copy=(char*)RDF_CALLOC(cstring, strlen(name)+1, 1);
+  if(!name_copy) {
+    RDF_FREE(rdf_hash, hash);
+    RDF_FATAL(rdf_hash_register_factory, "Out of memory\n");
+  }
+  strcpy(name_copy, name);
+  hash->name=name_copy;
+
+  for(h = hashes; h; h = h->next ) {
+    if(!strcmp(h->name, name_copy)) {
+      RDF_FATAL2(rdf_hash_register_factory, "hash %s already registered\n", h->name);
+    }
+  }
+
+  /* Call the hash registration function on the new object */
+  (*factory)(hash);
+
+
+  RDF_DEBUG3(rdf_hash_register_factory, "%s has context size %d\n", name, hash->context_length);
+
+  hash->next = hashes;
+  hashes = hash;
+}
+
+
+/** return the hash factory for a given name or NULL */
+rdf_hash_factory*
+get_rdf_hash_factory (const char *name) 
+{
+  rdf_hash_factory *factory;
+
+  /* return 1st hash if no particular one wanted - why? */
+  if(!name) {
+    factory=hashes;
+    if(!factory) {
+      RDF_DEBUG(get_rdf_hash_factory, "No (default) hashes registered\n");
+      return NULL;
+    }
+  } else {
+    for(factory=hashes; factory; factory=factory->next) {
+      if(!strcmp(factory->name, name)) {
+        break;
+      }
+    }
+    /* else FACTORY name not found */
+    if(!factory) {
+      RDF_DEBUG2(get_rdf_hash_factory, "No hash with name %s found\n",
+              name);
+      return NULL;
+    }
+  }
+  
+  return factory;
+}
+
+
+
+/* constructors */
+
+/** constructor for rdf_hash
+ * @param factory object from the factory
+ */
+rdf_hash*
+new_rdf_hash (rdf_hash_factory* factory) {
+  rdf_hash* h;
+
+  h=(rdf_hash*)RDF_CALLOC(rdf_hash, sizeof(rdf_hash), 1);
+  if(!h)
+    return NULL;
+
+  h->context=(char*)RDF_CALLOC(hash_context, factory->context_length, 1);
+  if(!h->context) {
+    free_rdf_hash(h);
+    return NULL;
+  }
+
+  h->factory=factory;
+
+  return h;
+}
+
+
+/** destructor for rdf_hash objects */
+void
+free_rdf_hash (rdf_hash* hash) 
+{
+  RDF_FREE(rdf_hash, hash);
+}
+
+/* methods */
+
+/** open/create hash with identifier (usually file or URI), mode and options */
+int
+rdf_hash_open(rdf_hash* hash, char *identifier, void *mode, void *options) 
+{
+  return (*(hash->factory->open))(hash->context, identifier, mode, options);
+}
+
+/** end hash association */
+int
+rdf_hash_close(rdf_hash* hash)
+{
+  return (*(hash->factory->close))(hash->context);
+}
+
+
+/** retrieve / insert key/data pairs from hash according to flags */
+int
+rdf_hash_get(rdf_hash* hash, void *key, size_t key_len,
+             void **value, size_t* value_len, unsigned int flags)
+{
+  rdf_hash_data hd_key, hd_value;
+  int result;
+  
+  /* copy key pointers and lengths into rdf_hash_data structures */
+  hd_key.data=key; hd_key.size=key_len;
+  
+  result=(*(hash->factory->get))(hash->context, &hd_key, &hd_value, flags);
+  /* copy out results into user variables */
+  *value=hd_value.data; *value_len=hd_value.size;
+  return result;
+}
+
+/** insert key/value pairs into hash according to flags */
+int
+rdf_hash_put(rdf_hash* hash, void *key, size_t key_len,
+             void *value, size_t value_len, unsigned int flags)
+{
+  rdf_hash_data hd_key, hd_value;
+
+  /* copy pointers and lengths into rdf_hash_data structures */
+  hd_key.data=key; hd_key.size=key_len;
+  hd_value.data=value; hd_value.size=value_len;
+
+  /* call generic routine using rdf_hash_data structs */
+  return (*(hash->factory->put))(hash->context, &hd_key, &hd_value, flags);
+}
+
+
+/** delete a key (and associated value) from hash */
+int
+rdf_hash_delete(rdf_hash* hash, void *key, size_t key_len)
+{
+  rdf_hash_data hd_key;
+
+  /* copy key pointers and lengths into rdf_hash_data structures */
+  hd_key.data=key; hd_key.size=key_len;
+
+  return (*(hash->factory->delete_key))(hash->context, &hd_key);
+}
+
+/** retrieve a key/value pair via cursor-based/sequential access */
+int
+rdf_hash_get_seq(rdf_hash* hash, void **key, size_t* key_len,
+                 unsigned int flags)
+{
+  rdf_hash_data hd_key;
+  
+  int result=(*(hash->factory->get_seq))(hash->context, &hd_key, flags);
+  /* copy out results into user variables */
+  *key=hd_key.data; *key_len=hd_key.size;
+  return result;
+}
+
+/** flush any cached information to disk if appropriate */
+int
+rdf_hash_sync(rdf_hash* hash)
+{
+  return (*(hash->factory->sync))(hash->context);
+}
+
+/** get the file descriptor for the hash, if it is file based (for locking) */
+int
+rdf_hash_get_fd(rdf_hash* hash)
+{
+  return (*(hash->factory->get_fd))(hash->context);
+}
+
+/** return the 'first' hash key in a sequential access of the hash
+ * Note: the key pointer will return newly allocated memory each time.
+ * @param hash hash object
+ * @param key pointer to void* where key will be stored
+ * @param key_len pointer to size_t where length will be stored
+ */
+
+int
+rdf_hash_first(rdf_hash* hash, void** key, size_t* key_len)
+{
+  return rdf_hash_get_seq(hash, key, key_len, RDF_HASH_FLAGS_FIRST);
+}
+
+/**
+ * return the 'next' hash key in a sequential access of the hash as
+ * started by rdf_hash_first
+ * Note: the key pointer will return newly allocated memory each time.
+ * @param hash hash object
+ * @param key pointer to void* where key will be stored
+ * @param key_len pointer to size_t where length will be stored
+ * @see rdf_hash_first()
+ */
+int
+rdf_hash_next(rdf_hash* hash, void** key, size_t* key_len)
+{
+  return rdf_hash_get_seq(hash, key, key_len, RDF_HASH_FLAGS_NEXT);
+}
+
+
+
+/** pretty-print the has to a file descriptior.
+ * @param hash the hash
+ * @param fh   file descriptork   actually a FILE*
+ */
+void
+rdf_hash_print (rdf_hash* hash, FILE *fh) 
+
+{
+  void *key;
+  size_t key_len;
+  void *value;
+  size_t value_len;
+
+  fprintf(fh, "%s hash: {\n", hash->factory->name);
+  for(rdf_hash_first(hash, &key, &key_len);
+      key;
+      rdf_hash_next(hash, &key, &key_len)) {
+    rdf_hash_get(hash, key, key_len, &value, &value_len, 0);
+    fputs("  '", fh);
+    fwrite(key, key_len, 1, fh);
+    fputs("'=>'", fh);
+    fwrite(value, value_len, 1, fh);
+    fputs("'\n", fh);
+
+    /* key points to new data each time */
+    RDF_FREE(cstring, key);
+  }
+  fputc('}', fh);
+}
+
+
+
+
+
+#ifdef RDF_HASH_TEST
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+
+int
+main(int argc, char *argv[]) 
+{
+  rdf_hash_factory* factory;
+  rdf_hash* h;
+  char *test_hash_types[]={"GDBM", "FAKE", "LIST", NULL};
+  char *test_hash_values[]={"colour", "yellow",
+                            "age", "new",
+                            "size", "large",
+                            "fruit", "banana",
+                            NULL, NULL};
+  char *test_hash_delete_key="size";
+  int i,j;
+  char *type;
+  char *key, *value;
+  char *program=argv[0];
+  
+  
+  /* initialise hash module */
+  init_rdf_hash();
+
+  for(i=0; (type=test_hash_types[i]); i++) {
+    fprintf(stderr, "%s: Trying to create new %s hash\n", program, type);
+    factory=get_rdf_hash_factory(type);
+    if(!factory) {
+      fprintf(stderr, "%s: No hash factory called %s\n", program, type);
+      continue;
+    }
+    
+    h=new_rdf_hash(factory);
+    if(!h) {
+      fprintf(stderr, "%s: Failed to create new hash type %s\n", program, type);
+      continue;
+    }
+
+    rdf_hash_open(h, "test.gdbm", "mode", "options");
+
+    for(j=0; test_hash_values[j]; j+=2) {
+      key=test_hash_values[j];
+      value=test_hash_values[j+1];
+      fprintf(stderr, "%s: Adding key/value pair: %s=%s\n", program, key, value);
+      
+      rdf_hash_put(h, key, strlen(key), value, strlen(value),
+                   0);
+      
+      fprintf(stderr, "%s: resulting ", program);    
+      rdf_hash_print(h, stderr);
+      fprintf(stderr, "\n");
+    }
+
+    fprintf(stderr, "%s: Deleting key '%s'\n", program, test_hash_delete_key);
+    rdf_hash_delete(h, test_hash_delete_key, strlen(test_hash_delete_key));
+
+    fprintf(stderr, "%s: resulting ", program);    
+    rdf_hash_print(h, stderr);
+    fprintf(stderr, "\n");
+    
+    rdf_hash_close(h);
+
+    fprintf(stderr, "%s: Freeing hash\n", program);
+    free_rdf_hash(h);
+  }
+  
+    
+  /* keep gcc -Wall happy */
+  return(0);
+}
+
+#endif

+ 124 - 0
librdf/rdf_hash.h

@@ -0,0 +1,124 @@
+/*
+ * RDF Hash Factory and Hash interfaces and definitions
+ *
+ * $Source$
+ * $Id$
+ *
+ * (C) Dave Beckett 2000 ILRT, University of Bristol
+ * http://www.ilrt.bristol.ac.uk/people/cmdjb/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef RDF_HASH_H
+#define RDF_HASH_H
+
+
+/** data type used to describe hash key and data */
+typedef struct 
+{
+  void *data;
+  size_t size;
+} rdf_hash_data;
+
+
+/* Return the current hash key/value pair in a sequence
+ * @see rdf_hash_get_seq
+ */
+#define RDF_HASH_FLAGS_CURRENT 0
+
+/* Return first hash key/value pair in a sequence
+ * @see rdf_hash_get_seq
+ */
+#define RDF_HASH_FLAGS_FIRST 1
+
+/* Return next hash key/value pair in a sequence
+ * @see rdf_hash_get_seq
+ */
+#define RDF_HASH_FLAGS_NEXT 2
+
+/** A Hash Factory */
+struct rdf_hash_factory_s {
+  struct rdf_hash_factory_s* next;
+  char* name;
+
+  /* the rest of this structure is populated by the
+     hash-specific register function */
+  size_t context_length;
+
+  /* open/create hash with identifier and options  */
+  int (*open)(void* context, char *identifier, void *mode, void *options);
+  /* end hash association */
+  int (*close)(void* context);
+
+  /* retrieve / insert key/data pairs according to flags */
+  int (*get)(void* context, rdf_hash_data *key, rdf_hash_data *data, unsigned int flags);
+  int (*put)(void* context, rdf_hash_data *key, rdf_hash_data *data, unsigned int flags);
+
+  int (*delete_key)(void* context, rdf_hash_data *key);
+  /* retrieve a key/data pair via cursor-based/sequential access */
+  int (*get_seq)(void* context, rdf_hash_data *key, unsigned int flags);
+  /* flush any cached information to disk */
+  int (*sync)(void* context);
+  /* get the file descriptor for the hash, if it is file based (for locking) */
+  int (*get_fd)(void* context);
+};
+
+typedef struct rdf_hash_factory_s rdf_hash_factory;
+
+/** A hash object */
+typedef struct
+{
+  char *context;
+  rdf_hash_factory* factory;
+} rdf_hash;
+
+
+
+/* module init */
+void init_rdf_hash(void);
+
+
+/* class methods */
+void rdf_hash_register_factory(const char *name,
+                               void (*factory) (rdf_hash_factory*)
+                               );
+rdf_hash_factory* get_rdf_hash_factory(const char *name);
+
+/* constructor */
+rdf_hash* new_rdf_hash(rdf_hash_factory* factory);
+
+/* destructor */
+void free_rdf_hash(rdf_hash *hash);
+
+
+/* methods */
+
+/* open/create hash with identifier and options  */
+int rdf_hash_open(rdf_hash* hash, char *identifier, void *mode, void *options);
+/* end hash association */
+int rdf_hash_close(rdf_hash* hash);
+
+/* retrieve / insert key/data pairs according to flags */
+int rdf_hash_get(rdf_hash* hash, void *key, size_t key_len, void **value, size_t *value_len, unsigned int flags);
+int rdf_hash_put(rdf_hash* hash, void *key, size_t key_len, void *value, size_t value_len, unsigned int flags);
+
+int rdf_hash_delete(rdf_hash* hash, void *key, size_t key_len);
+/* retrieve a key/data pair via cursor-based/sequential access */
+int rdf_hash_get_seq(rdf_hash* hash, void **key, size_t* key_len, unsigned int flags);
+/* flush any cached information to disk */
+int rdf_hash_sync(rdf_hash* hash);
+/* get the file descriptor for the hash, if it is file based (for locking) */
+int rdf_hash_get_fd(rdf_hash* hash);
+
+/* extra methods */
+void rdf_hash_print(rdf_hash* hash, FILE *fh);
+int rdf_hash_first(rdf_hash* hash, void** key, size_t* key_len);
+int rdf_hash_next(rdf_hash* hash, void** key, size_t* key_len);
+
+#endif
+

+ 227 - 0
librdf/rdf_hash_gdbm.c

@@ -0,0 +1,227 @@
+/*
+ * RDF DB GDBM Interface Implementation
+ *
+ * $Source$
+ * $Id$
+ *
+ * (C) Dave Beckett 2000 ILRT, University of Bristol
+ * http://www.ilrt.bristol.ac.uk/people/cmdjb/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+#include <gdbm.h>
+
+
+#include <rdf_config.h>
+#include <rdf_hash.h>
+#include <rdf_hash_gdbm.h>
+
+
+typedef struct 
+{
+  GDBM_FILE gdbm_file;
+  datum current_key;
+} rdf_hash_gdbm_context;
+
+
+/* prototypes for local functions */
+static int rdf_hash_gdbm_open(void* context, char *identifier, void *mode, void *options);
+static int rdf_hash_gdbm_close(void* context);
+static int rdf_hash_gdbm_get(void* context, rdf_hash_data *key, rdf_hash_data *data, unsigned int flags);
+static int rdf_hash_gdbm_put(void* context, rdf_hash_data *key, rdf_hash_data *data, unsigned int flags);
+static int rdf_hash_gdbm_delete(void* context, rdf_hash_data *key);
+static int rdf_hash_gdbm_get_seq(void* context, rdf_hash_data *key, unsigned int flags);
+static int rdf_hash_gdbm_sync(void* context);
+static int rdf_hash_gdbm_get_fd(void* context);
+
+static void rdf_hash_gdbm_register_factory(rdf_hash_factory *factory);
+
+
+/* functions implementing hash api */
+
+static int
+rdf_hash_gdbm_open(void* context, char *identifier, void *mode, void *options) 
+{
+  rdf_hash_gdbm_context* gdbm_context=(rdf_hash_gdbm_context*)context;
+  GDBM_FILE gdbm;
+
+  gdbm=gdbm_open(identifier, 512, GDBM_WRCREAT, 0644, 0);
+  if(!gdbm)
+    return 1;
+
+  gdbm_context->gdbm_file=gdbm;
+  return 0;
+}
+
+static int
+rdf_hash_gdbm_close(void* context) 
+{
+  rdf_hash_gdbm_context* gdbm_context=(rdf_hash_gdbm_context*)context;
+  gdbm_close(gdbm_context->gdbm_file);
+  return 0;
+}
+
+
+static int
+rdf_hash_gdbm_get(void* context, rdf_hash_data *key, rdf_hash_data *data, unsigned int flags) 
+{
+  rdf_hash_gdbm_context* gdbm_context=(rdf_hash_gdbm_context*)context;
+  datum gdbm_data;
+  datum gdbm_key;
+
+  /* Initialise GDBM version of key */
+  gdbm_key.dptr = (char*)key->data;
+  gdbm_key.dsize = key->size;
+  
+  gdbm_data = gdbm_fetch(gdbm_context->gdbm_file, gdbm_key);
+  if(!gdbm_data.dptr) {
+    /* not found */
+    data->data = NULL;
+    return 0;
+  }
+  
+  data->data = RDF_MALLOC(gdbm_data, gdbm_data.dsize);
+  if(!data->data) {
+    free(gdbm_data.dptr);
+    return 1;
+  }
+  memcpy(data->data, gdbm_data.dptr, gdbm_data.dsize);
+  data->size = gdbm_data.dsize;
+
+  /* always allocated by GDBM using system malloc */
+  free(gdbm_data.dptr);
+  return 0;
+}
+
+
+static int
+rdf_hash_gdbm_put(void* context, rdf_hash_data *key, rdf_hash_data *value, unsigned int flags) 
+{
+  rdf_hash_gdbm_context* gdbm_context=(rdf_hash_gdbm_context*)context;
+  datum gdbm_data;
+  datum gdbm_key;
+
+  /* Initialise GDBM version of key */
+  gdbm_key.dptr = (char*)key->data;
+  gdbm_key.dsize = key->size;
+  
+  /* Initialise GDBM version of data */
+  gdbm_data.dptr = (char*)value->data;
+  gdbm_data.dsize = value->size;
+
+  /* flags can be GDBM_INSERT or GDBM_REPLACE */
+  gdbm_store(gdbm_context->gdbm_file, gdbm_key, gdbm_data, GDBM_REPLACE);
+  return 0;
+}
+
+
+static int
+rdf_hash_gdbm_delete(void* context, rdf_hash_data *key) 
+{
+  rdf_hash_gdbm_context* gdbm_context=(rdf_hash_gdbm_context*)context;
+  datum gdbm_key;
+
+  /* Initialise GDBM version of key */
+  gdbm_key.dptr = (char*)key->data;
+  gdbm_key.dsize = key->size;
+  
+  gdbm_delete(gdbm_context->gdbm_file, gdbm_key);
+  return 0;
+}
+
+
+static int
+rdf_hash_gdbm_get_seq(void* context, rdf_hash_data *key, unsigned int flags) 
+{
+  rdf_hash_gdbm_context* gdbm_context=(rdf_hash_gdbm_context*)context;
+  datum gdbm_key;
+
+  if(flags == RDF_HASH_FLAGS_FIRST) {
+    gdbm_key=gdbm_firstkey(gdbm_context->gdbm_file);
+  } else if (flags == RDF_HASH_FLAGS_NEXT) {
+    gdbm_key=gdbm_nextkey(gdbm_context->gdbm_file, gdbm_context->current_key);
+  } else { /* RDF_HASH_FLAGS_CURRENT */
+    gdbm_key.dsize=gdbm_context->current_key.dsize;
+    gdbm_key.dptr=gdbm_context->current_key.dptr;
+  }
+  
+  
+  key->data = RDF_MALLOC(gdbm_data, gdbm_key.dsize);
+  if(!key->data) {
+    /* always allocated by GDBM using system malloc */
+    if(flags != RDF_HASH_FLAGS_CURRENT)
+      free(gdbm_key.dptr);
+    return 1;
+  }
+  memcpy(key->data, gdbm_key.dptr, gdbm_key.dsize);
+  key->size = gdbm_key.dsize;
+
+  if(flags != RDF_HASH_FLAGS_CURRENT) {
+    /* save new current key */
+    if(gdbm_context->current_key.dsize)
+      RDF_FREE(gdbm_data, gdbm_context->current_key.dptr);
+    gdbm_context->current_key.dsize=gdbm_key.dsize;
+    gdbm_context->current_key.dptr=(char*)RDF_MALLOC(gdbm_data, gdbm_key.dsize);
+    if(!gdbm_context->current_key.dptr)
+      return 1;
+    memcpy(gdbm_context->current_key.dptr, gdbm_key.dptr, gdbm_key.dsize);
+    
+    /* always allocated by GDBM using system malloc */
+    free(gdbm_key.dptr);
+  }
+
+  return 0;
+}
+
+static int
+rdf_hash_gdbm_sync(void* context) 
+{
+  rdf_hash_gdbm_context* gdbm_context=(rdf_hash_gdbm_context*)context;
+  gdbm_sync(gdbm_context->gdbm_file);
+  return 0;
+}
+
+static int
+rdf_hash_gdbm_get_fd(void* context) 
+{
+  rdf_hash_gdbm_context* gdbm_context=(rdf_hash_gdbm_context*)context;
+  int fd;
+
+  fd=gdbm_fdesc(gdbm_context->gdbm_file);
+  return fd;
+}
+
+
+/* local function to register GDBM hash functions */
+
+static void
+rdf_hash_gdbm_register_factory(rdf_hash_factory *factory) 
+{
+  factory->context_length = sizeof(rdf_hash_gdbm_context);
+
+  factory->open    = rdf_hash_gdbm_open;
+  factory->close   = rdf_hash_gdbm_close;
+  factory->get     = rdf_hash_gdbm_get;
+  factory->put     = rdf_hash_gdbm_put;
+  factory->delete_key  = rdf_hash_gdbm_delete;
+  factory->get_seq = rdf_hash_gdbm_get_seq;
+  factory->sync    = rdf_hash_gdbm_sync;
+  factory->get_fd  = rdf_hash_gdbm_get_fd;
+}
+
+void
+init_rdf_hash_gdbm(void)
+{
+  rdf_hash_register_factory("GDBM", &rdf_hash_gdbm_register_factory);
+}

+ 23 - 0
librdf/rdf_hash_gdbm.h

@@ -0,0 +1,23 @@
+/*
+ * RDF DB GDBM Interface definition
+ *
+ * $Source$
+ * $Id$
+ *
+ * (C) Dave Beckett 2000 ILRT, University of Bristol
+ * http://www.ilrt.bristol.ac.uk/people/cmdjb/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+
+#ifndef RDF_HASH_GDBM_H
+#define RDF_HASH_GDBM_H
+
+void init_rdf_hash_gdbm(void);
+
+#endif

+ 40 - 0
librdf/rdf_init.c

@@ -0,0 +1,40 @@
+/*
+ * RDF Node implementation
+ *   RDF:Resource
+ *   RDF:Property
+ *   (object) - RDF:Literal / RDF:Resource
+ *
+ * $Source$
+ * $Id$
+ *
+ * (C) Dave Beckett 2000 ILRT, University of Bristol
+ * http://www.ilrt.bristol.ac.uk/people/cmdjb/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <rdf_config.h>
+#include <rdf_uri.h>
+#include <rdf_node.h>
+#include <rdf_digest.h>
+#include <rdf_statement.h>
+
+
+void rdf_init_world(char *digest_factory_name) 
+{
+  rdf_digest_factory* digest_factory;
+
+  digest_factory=get_rdf_digest_factory(digest_factory_name);
+  
+  init_rdf_uri(digest_factory);
+  init_rdf_node(digest_factory);
+  init_rdf_statement();
+}

+ 68 - 0
librdf/rdf_model.h

@@ -0,0 +1,68 @@
+/*
+ * RDF Model definition
+ *
+ * $Source$
+ * $Id$
+ *
+ * (C) Dave Beckett 2000 ILRT, University of Bristol
+ * http://www.ilrt.bristol.ac.uk/people/cmdjb/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+
+#ifndef RDF_NODE_H
+#define RDF_NODE_H
+
+#include <rdf_uri.h>
+#include <rdf_node.h>
+
+/* placeholder */
+typedef struct {
+  int count; /* number of stored statements */
+  rdf_model_storage* storage;
+} rdf_model;
+
+
+/* class methods */
+void init_rdf_model(void);
+
+
+/* constructors */
+
+/* Create a new Model */
+int new_rdf_model();
+
+/* Create a new Model from an existing Model - CLONE */
+int new_rdf_model_from_model(rdf_model* model);
+
+/* destructor */
+void free_rdf_model(rdf_model *model);
+
+
+/* functions / methods */
+int rdf_model_size(rdf_model* model);
+
+int rdf_model_add(rdf_model* model, rdf_node* subject, rdf_node* property, rdf_node* object);
+int rdf_model_add_string_literal_statement(rdf_model* model, rdf_node* subject, rdf_node* property, char* string);
+int rdf_model_add_statement(rdf_model* model, rdf_statement* statement);
+int rdf_model_remove_statement(rdf_model* model, rdf_statement* statement);
+int rdf_model_contains_statement(rdf_model* model, rdf_statement* statement);
+/* returns an interator that returns all statements */
+rdf_iterator* rdf_model_get_all_statements(rdf_model* model);
+
+/* any of subject, property or object can be NULL */
+/* returns count of number of matching statements */
+int rdf_model_find(rdf_model* model, rdf_node* subject, rdf_node* property, rdf_node* object);
+/* returns iterator object that returns matching rdf_statements */
+rdf_iterator* rdf_model_find_(rdf_model* model, rdf_node* subject, rdf_node* property, rdf_node* object);
+
+/* get/set the model source URI */
+rdf_uri* rdf_model_get_source_uri(rdf_model* model);
+int rdf_model_set_source_uri(rdf_model* model, rdf_uri *uri);
+
+#endif

+ 348 - 0
librdf/rdf_node.c

@@ -0,0 +1,348 @@
+/*
+ * RDF Node implementation
+ *   RDF:Resource
+ *   RDF:Property
+ *   (object) - RDF:Literal / RDF:Resource
+ *
+ * $Source$
+ * $Id$
+ *
+ * (C) Dave Beckett 2000 ILRT, University of Bristol
+ * http://www.ilrt.bristol.ac.uk/people/cmdjb/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <rdf_config.h>
+#include <rdf_uri.h>
+#include <rdf_node.h>
+#include <rdf_digest.h>
+
+
+/* statics */
+static rdf_digest_factory *rdf_node_digest_factory=NULL;
+
+void init_rdf_node(rdf_digest_factory* factory) 
+{
+  rdf_node_digest_factory=factory;
+}
+
+
+
+/* class functions */
+
+/* constructors */
+
+/* Create a new Node with NULL URI. */
+rdf_node*
+new_rdf_node(void)
+{
+  return new_rdf_node_from_uri_string((char*)NULL);
+}
+
+    
+
+/* Create a new Node and set the URI (can be NULL). */
+rdf_node*
+new_rdf_node_from_uri_string(char *uri_string) 
+{
+  rdf_node* new_rdf_node;
+  rdf_uri *new_uri;
+  
+  new_rdf_node = (rdf_node*)RDF_CALLOC(rdf_node, 1, sizeof(rdf_node));
+  if(!new_rdf_node)
+    return NULL;
+
+  /* set type (actually not needed since calloc above sets type to 0) */
+  new_rdf_node->type = RDF_NODE_TYPE_RESOURCE;
+  
+  new_rdf_node->value.resource.uri = NULL;
+  if(uri_string != NULL) {
+    new_uri=new_rdf_uri(uri_string);
+    if (!new_uri) {
+      free_rdf_node(new_rdf_node);
+      return NULL;
+    }
+    if(!rdf_node_set_uri(new_rdf_node, new_uri)) {
+      free_rdf_node(new_rdf_node);
+      return NULL;
+    }
+  }
+  return new_rdf_node;
+}
+
+    
+
+/* Create a new Node and set the URI. */
+rdf_node*
+new_rdf_node_from_uri(rdf_uri *uri) 
+{
+  char *uri_string=rdf_uri_as_string(uri); /* note: does not allocate string */
+  rdf_node* new_node=new_rdf_node_from_uri_string(uri_string);
+  /* thus no need for RDF_FREE(uri_string); */
+  return new_node;
+}
+
+
+/* Create a new literal Node. */
+rdf_node*
+new_rdf_node_from_literal(char *string, char *xml_language) 
+{
+  rdf_node* new_node;
+  
+  new_node = (rdf_node*)RDF_CALLOC(rdf_node, 1, sizeof(rdf_node));
+  if(!new_node)
+    return NULL;
+
+  /* set type */
+  new_node->type=RDF_NODE_TYPE_LITERAL;
+
+  if (rdf_node_set_literal_value(new_node, string, xml_language)) {
+    free_rdf_node(new_node);
+    return NULL;
+  }
+
+  return new_node;
+}
+
+
+/* Create a new Node from an existing Node - CLONE */
+rdf_node*
+new_rdf_node_from_node(rdf_node *node) 
+{
+  rdf_node* new_node;
+  rdf_uri *new_uri;
+  
+  new_node = (rdf_node*)RDF_CALLOC(rdf_node, 1, sizeof(rdf_node));
+  if(!new_node)
+    return NULL;
+
+  if(node->type == RDF_NODE_TYPE_RESOURCE) {
+    new_uri=new_rdf_uri_from_uri(node->value.resource.uri);
+    if(!new_uri){
+      RDF_FREE(rdf_node, new_node);
+      return NULL;
+    }
+    rdf_node_set_uri(new_node, new_uri);
+  } else {
+    /* must be a RDF_NODE_TYPE_LITERAL */
+    if (rdf_node_set_literal_value(node,
+                                   node->value.literal.string,
+                                   node->value.literal.xml_language)) {
+      RDF_FREE(rdf_node, new_node);
+      return NULL;
+    }
+  }
+
+  return new_node;
+}
+
+
+/* destructor */
+void
+free_rdf_node(rdf_node *r) 
+{
+  if(r->type == RDF_NODE_TYPE_RESOURCE) {
+    if(r->value.resource.uri != NULL)
+      free_rdf_uri(r->value.resource.uri);
+  } else {
+    if(r->value.literal.string != NULL)
+      RDF_FREE(cstring, r->value.literal.string);
+    if(r->value.literal.xml_language != NULL)
+      RDF_FREE(cstring, r->value.literal.xml_language);
+  }
+  RDF_FREE(rdf_node, r);
+}
+
+
+/* functions / methods */
+
+/* returns pointer to *shared* copy of URI - must copy if used elsewhere */
+rdf_uri*
+rdf_node_get_uri(rdf_node* node) 
+{
+  return node->value.resource.uri;
+}
+
+
+/* Set the URI of the node */
+int
+rdf_node_set_uri(rdf_node* node, rdf_uri *uri)
+{
+  rdf_uri* new_uri=new_rdf_uri_from_uri(uri);
+  if(!new_uri)
+    return 0;
+
+  /* delete old URI */
+  if(node->value.resource.uri)
+    free_rdf_uri(node->value.resource.uri);
+
+  /* set new one */
+  node->value.resource.uri=new_uri;
+  return 1;
+}
+
+
+
+/* Get the type of the node */
+int
+rdf_node_get_type(rdf_node* node) 
+{
+  return node->type;
+}
+
+
+/* Set the type of the node */
+void
+rdf_node_set_type(rdf_node* node, int type)
+{
+  node->type=type;
+}
+
+
+/* Get the literal value of the node */
+char*
+rdf_node_get_literal_value(rdf_node* node) 
+{
+  if(node->type != RDF_NODE_TYPE_LITERAL)
+    return NULL;
+  return node->value.literal.string;
+}
+
+char*
+rdf_node_get_literal_value_language(rdf_node* node) 
+{
+  if(node->type != RDF_NODE_TYPE_LITERAL)
+    return NULL;
+  return node->value.literal.xml_language;
+}
+
+
+int
+rdf_node_set_literal_value(rdf_node* node, char* value, char *xml_language) 
+{
+  char *new_value;
+  char *new_xml_language=NULL;
+
+  new_value=(char*)RDF_MALLOC(cstring, strlen(value)+1);
+  if(!new_value)
+    return 1;
+  strcpy(new_value, value);
+  
+  if(xml_language) {
+    new_xml_language=(char*)RDF_MALLOC(cstring, strlen(xml_language)+1);
+    if(!new_xml_language) {
+      RDF_FREE(cstring, value);
+      return 1;
+    }
+    strcpy(new_xml_language, xml_language);
+  }
+
+  if(node->value.literal.string)
+    RDF_FREE(cstring, node->value.literal.string);
+  node->value.literal.string=(char*)new_value;
+  if(node->value.literal.xml_language)
+    RDF_FREE(cstring, node->value.literal.xml_language);
+  node->value.literal.xml_language=new_xml_language;
+
+  return 0;
+}
+
+
+/* allocates a new string since this is a _to_ method */
+char*
+rdf_node_to_string(rdf_node* node) 
+{
+  char *uri_string;
+  char *s;
+
+  switch(node->type) {
+    case RDF_NODE_TYPE_RESOURCE:
+      uri_string=rdf_uri_to_string(node->value.resource.uri);
+      if(!uri_string)
+        return NULL;
+      s=(char*)RDF_MALLOC(cstring, strlen(uri_string)+3);
+      if(!s) {
+        RDF_FREE(cstring, uri_string);
+        return NULL;
+      }
+      sprintf(s, "[%s]", uri_string);
+      break;
+    case RDF_NODE_TYPE_LITERAL:
+      s=(char*)RDF_MALLOC(cstring, strlen(node->value.literal.string)+1);
+      if(!s)
+        return NULL;
+      strcpy(s, node->value.literal.string);
+      break;
+    default:
+      RDF_FATAL2(rdf_node_string, "Illegal node type %d seen\n", node->type);
+  }
+  return s;
+}
+
+
+rdf_digest*
+rdf_node_get_digest(rdf_node* node) 
+{
+  return rdf_uri_get_digest(node->value.resource.uri);
+}
+
+
+
+#ifdef RDF_NODE_TEST
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+
+int
+main(int argc, char *argv[]) 
+{
+  rdf_node* node;
+  char *hp_string1="http://www.ilrt.bristol.ac.uk/people/cmdjb/";
+  char *hp_string2="http://purl.org/net/dajobe/";
+  rdf_uri *uri, *uri2;
+
+  char *program=argv[0];
+  
+  fprintf(stderr, "%s: Creating home page node from string\n", program);
+  node=new_rdf_node_from_uri_string(hp_string1);
+
+  fprintf(stderr, "%s: Home page URI is ", program);
+  rdf_uri_print(rdf_node_get_uri(node), stderr);
+  fputs("\n", stderr);
+
+  fprintf(stderr, "%s: Creating URI from string '%s'\n", program, hp_string2);
+  uri=new_rdf_uri(hp_string2);
+  fprintf(stderr, "%s: Setting node URI to new URI ", program);
+  rdf_uri_print(uri, stderr);
+  fputs("\n", stderr);
+  
+  
+  rdf_node_set_uri(node, uri);
+
+  uri2=rdf_node_get_uri(node);
+  fprintf(stderr, "%s: Node now has URI ", program);
+  rdf_uri_print(uri2, stderr);
+  fputs("\n", stderr);
+  
+
+  fprintf(stderr, "%s: Freeing URI\n", program);
+  free_rdf_uri(uri);
+
+  fprintf(stderr, "%s: Freeing node\n", program);
+  free_rdf_node(node);
+
+  /* keep gcc -Wall happy */
+  return(0);
+}
+
+#endif

+ 96 - 0
librdf/rdf_node.h

@@ -0,0 +1,96 @@
+/*
+ * RDF Node definition
+ *
+ * $Source$
+ * $Id$
+ *
+ * (C) Dave Beckett 2000 ILRT, University of Bristol
+ * http://www.ilrt.bristol.ac.uk/people/cmdjb/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+
+#ifndef RDF_NODE_H
+#define RDF_NODE_H
+
+#include <rdf_uri.h>
+#include <rdf_digest.h>
+/* A resource (also a property) - has a URI */
+#define RDF_NODE_TYPE_RESOURCE 0
+/* A literal - an XML string + language */
+#define RDF_NODE_TYPE_LITERAL  1
+
+typedef struct 
+{
+  int type;
+  union
+  {
+    union
+    {
+      /* resources have URIs */
+      rdf_uri *uri;
+    } resource;
+    struct
+    {
+      /* literals have string values and maybe an XML language */
+      char *string;
+      char *xml_language; /* yuck */
+    } literal;
+  } value;
+}
+rdf_node;
+
+
+/* class methods */
+void init_rdf_node(rdf_digest_factory* factory);
+
+
+/* initialising functions / constructors */
+
+/* Create a new Node. */
+rdf_node* new_rdf_node(void);
+
+/* Create a new resource Node from URI string. */
+rdf_node* new_rdf_node_from_uri_string(char *string);
+
+/* Create a new resource Node from URI object. */
+rdf_node* new_rdf_node_from_uri(rdf_uri *uri);
+
+/* Create a new Node from literal string / language. */
+rdf_node* new_rdf_node_from_literal(char *string, char *xml_language);
+
+/* Create a new Node from an existing Node - CLONE */
+rdf_node* new_rdf_node_from_node(rdf_node *node);
+
+/* destructor */
+void free_rdf_node(rdf_node *r);
+
+
+
+/* functions / methods */
+
+rdf_uri* rdf_node_get_uri(rdf_node* node);
+int rdf_node_set_uri(rdf_node* node, rdf_uri *uri);
+
+int rdf_node_get_type(rdf_node* node);
+void rdf_node_set_type(rdf_node* node, int type);
+
+char* rdf_node_get_literal_value(rdf_node* node);
+char* rdf_node_get_literal_value_language(rdf_node* node);
+int rdf_node_set_literal_value(rdf_node* node, char* value, char *xml_language);
+
+rdf_digest* rdf_node_get_digest(rdf_node* node);
+
+char *rdf_node_to_string(rdf_node* node);
+
+
+/* utility functions */
+int rdf_node_equals(rdf_node* first_node, rdf_node* second_node);
+
+
+#endif

+ 215 - 0
librdf/rdf_statement.c

@@ -0,0 +1,215 @@
+/*
+ * RDF Statement implementation
+ *
+ * $Source$
+ * $Id$
+ *
+ * (C) Dave Beckett 2000 ILRT, University of Bristol
+ * http://www.ilrt.bristol.ac.uk/people/cmdjb/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <rdf_config.h>
+#include <rdf_node.h>
+#include <rdf_statement.h>
+
+
+/* class methods */
+
+void
+init_rdf_statement(void) 
+{
+}
+
+
+/* constructor */
+/* Create a new empty Statement */
+rdf_statement*
+new_rdf_statement(void) 
+{
+  rdf_statement* new_rdf_statement;
+  
+  new_rdf_statement = (rdf_statement*)RDF_CALLOC(rdf_statement, 1, sizeof(rdf_statement));
+  if(!new_rdf_statement)
+    return NULL;
+
+  return new_rdf_statement;
+}
+
+
+/* destructor */
+
+void
+free_rdf_statement(rdf_statement* statement)
+{
+  if(statement->subject)
+    free_rdf_node(statement->subject);
+  if(statement->predicate)
+    free_rdf_node(statement->predicate);
+  if(statement->object)
+    free_rdf_node(statement->object);
+  RDF_FREE(rdf_statement, statement);
+}
+
+
+
+/* methods */
+
+rdf_node*
+rdf_statement_get_subject(rdf_statement *statement) 
+{
+  return statement->subject;
+}
+
+
+int
+rdf_statement_set_subject(rdf_statement *statement, rdf_node *node)
+{
+  /*
+  if(statement->subject)
+    free_rdf_node(statement->subject);
+  return (statement->subject=new_rdf_node_from_node(node)) != NULL;
+  */
+  statement->subject=node;
+  return 0;
+}
+
+
+rdf_node*
+rdf_statement_get_predicate(rdf_statement *statement) 
+{
+  return statement->predicate;
+}
+
+
+int
+rdf_statement_set_predicate(rdf_statement *statement, rdf_node *node)
+{
+  /*
+  if(statement->predicate)
+    free_rdf_node(statement->predicate);
+  return (statement->predicate=new_rdf_node_from_node(node)) != NULL;
+  */
+  statement->predicate=node;
+  return 0;
+}
+
+
+rdf_node*
+rdf_statement_get_object(rdf_statement *statement) 
+{
+  return statement->object;
+}
+
+
+int
+rdf_statement_set_object(rdf_statement *statement, rdf_node *node)
+{
+  /*
+  if(statement->object)
+    free_rdf_node(statement->object);
+  return (statement->object=new_rdf_node_from_node(node)) != NULL;
+  */
+  statement->object=node;
+  return 0;
+}
+
+
+/* allocates a new string since this is a _to_ method */
+char *
+rdf_statement_to_string(rdf_statement *statement)
+{
+  char *subject_string, *predicate_string, *object_string;
+  char *s;
+  int statement_string_len;
+  char *format;
+
+  subject_string=rdf_node_to_string(statement->subject);
+  if(!subject_string)
+    return NULL;
+  
+  predicate_string=rdf_node_to_string(statement->predicate);
+  if(!predicate_string) {
+    RDF_FREE(cstring, subject_string);
+    return NULL;
+  }
+
+  object_string=rdf_node_to_string(statement->object);
+  if(!object_string) {
+    RDF_FREE(cstring, subject_string);
+    RDF_FREE(cstring, predicate_string);
+    return NULL;
+  }
+
+#define RDF_STATEMENT_FORMAT_STRING_LITERAL "{%s ,%s, \"%s\"}"
+#define RDF_STATEMENT_FORMAT_RESOURCE_LITERAL "{%s ,%s, %s}"
+  statement_string_len=1 + strlen(subject_string) +   /* "{%s" */
+                       2 + strlen(predicate_string) + /* " ,%s" */
+                       2 + strlen(object_string) +    /* " ,%s" */
+                       1 + 1;                         /* "}\0" */
+  if(rdf_node_get_type(statement->object) == RDF_NODE_TYPE_LITERAL) {
+    format=RDF_STATEMENT_FORMAT_STRING_LITERAL;
+    statement_string_len+=2; /* Extra "" around literal */
+  } else {
+    format=RDF_STATEMENT_FORMAT_RESOURCE_LITERAL;
+  }
+    
+  s=(char*)RDF_MALLOC(cstring, statement_string_len);
+  if(!s) {
+    RDF_FREE(cstring, subject_string);
+    RDF_FREE(cstring, predicate_string);
+    RDF_FREE(cstring, object_string);
+    return NULL;
+  }
+  sprintf(s, format, predicate_string, subject_string, object_string);
+
+  return s;
+}
+
+
+
+
+#ifdef RDF_STATEMENT_TEST
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+
+int
+main(int argc, char *argv[]) 
+{
+  rdf_statement* statement;
+  char *program=argv[0];
+  char *s;
+  
+  /* initialise statement module */
+  init_rdf_statement();
+
+  fprintf(stderr, "%s: Creating statement\n", program);
+  statement=new_rdf_statement();
+
+  rdf_statement_set_subject(statement, new_rdf_node_from_uri_string("http://www.ilrt.bris.ac.uk/people/cmdjb/"));
+  rdf_statement_set_predicate(statement, new_rdf_node_from_uri_string("http://purl.org/dc/elements/1.1/#Creator"));
+  rdf_statement_set_object(statement, new_rdf_node_from_literal("Dave Beckett", NULL));
+
+  s=rdf_statement_to_string(statement);
+  fprintf(stderr, "%s: Resulting statement: %s\n", program, s);
+  free(s);
+
+  fprintf(stderr, "%s: Freeing statement\n", program);
+  free_rdf_statement(statement);
+  
+  /* keep gcc -Wall happy */
+  return(0);
+}
+
+#endif

+ 57 - 0
librdf/rdf_statement.h

@@ -0,0 +1,57 @@
+/*
+ * RDF Statement definition
+ *
+ * $Source$
+ * $Id$
+ *
+ * (C) Dave Beckett 2000 ILRT, University of Bristol
+ * http://www.ilrt.bristol.ac.uk/people/cmdjb/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+
+#ifndef RDF_STATEMENT_H
+#define RDF_STATEMENT_H
+
+#include <rdf_node.h>
+#include <rdf_uri.h>
+
+typedef struct 
+{
+  rdf_node* subject;
+  rdf_node* predicate;
+  rdf_node* object;
+  rdf_uri*  provenance; /* ha ha */
+}
+rdf_statement;
+
+
+/* class methods */
+void init_rdf_statement(void);
+
+/* initialising functions / constructors */
+
+/* Create a new Statement. */
+rdf_statement* new_rdf_statement(void);
+
+/* destructor */
+void free_rdf_statement(rdf_statement* statement);
+
+
+/* functions / methods */
+