--- /dev/null
+Changes between the current version of the C++ binding specification
+(http://zoom.z3950.org/bind/cplusplus/zoom-1.0g.hh) and the
+specification generated in "interface.h" in this directory (which I
+expect to become version 1.3a of the official specification.)
+
+--
+
+Add #include <stddef.h> for size_t
+
+Add comment about G++'s rejection of throw(ZOOM:error) clause
+
+Add destructor declaration to connection class.
+
+Remove errcode(), errmsg() and addinfo() methods from the connection
+and resultSet classes, since exceptions should be used in these
+enlightened days.
+
+Rename the record::recordSyntax enumeration to record::syntax, and add
+an UNKNOWN element.
+
+Remove "virtual" from all the record class's methods, including its
+destructor, since we no longer expect to derive record subclasses
+representing records expressed in specific record-syntaxes -- see
+version 1.3 of the ZOOM AAPI.
+
+Remove the nfields() and field() methods from the record class --
+again, see v1.3 of the AAPI.
+
+Add some substance to the error base class: it can now be created
+(with an error-code specified), and the error-code may be both fetched
+and rendered as a human-readable string. This is necessary so that
+it's possible to meaningfully catch(error e).
+
+Add the missing char *errmsg() method to the systemError and bib1Error
+classes.
+
+Add a new error subclass, queryError, for reporting malformed query
+strings etc.
--- /dev/null
+# $Header: /home/cvsroot/yaz++/zoom/Attic/Makefile,v 1.1 2002-08-08 13:31:54 mike Exp $
+
+CCC = g++ # ... until I figure out what the standard
+ # Make macro name is for the C++ compiler.
+CPPFLAGS := -Wall -g
+L = libzoom.a
+OBJ = $L(zerr.o) $L(zconn.o) $L(zquery.o) $L(zrs.o) $L(zrec.o)
+
+all: interface.h zclient
+
+zclient: zclient.o $L
+ @echo CCC = $(CCC)
+ $(CCC) $(CPPFLAGS) -o zclient zclient.o $L -lyaz
+
+test: zclient
+ ./zclient bagel.indexdata.dk 210 gils '@and mineral epicenter'
+
+$L: $(OBJ)
+ ranlib $L
+
+$(OBJ): zoom++.h
+
+zclient.o: zoom++.h
+
+zoom++.h: master-header
+ rm -f $@
+ sed 's/^* / /; s/^*/ /' $< > $@
+ chmod -w $@
+
+interface.h: master-header
+ rm -f $@
+ grep -v '^*' $< > $@
+ chmod -w $@
+
+clean:
+ rm -f zoom++.h interface.h zclient *.[ao] core
--- /dev/null
+This is an initial implementation of the ZOOM C++ binding
+(http://zoom.z3950.org/bind/cplusplus/) for the Yaz toolkit.
+It's a rather obvious thin layer on top of Yaz's ZOOM-C
+implementation.
+
+The build environment will no doubt need to be tweaked to fit
+in with the way that the rest of Yaz++ is built.
+
+Only one wrinkle, really: we want the ZOOM C++ header file for two
+different purposes: one is to function as an interface specification
+that can go on the ZOOM web-site, and one is to actually build
+against. The requirements of these two manifestations of the header
+file are rather different in that the latter needs to include
+implementation details that the former very explicitly does _not_
+want. Accordingly, we automatically generate both versions from a
+master copy in which the implementation-dependent lines are preceded
+by asterisks(*). So we have:
+
+ master-header The master copy, which may be edited.
+ interface.h The read-only, automatically-generated file
+ that can be considered a formal specification
+ of the ZOOM C++ interface.
+ zoom++.h The read-only, automatically-generated file
+ that is actually used in the build process,
+ and ought quite possibly to be moved into
+ ../include/yaz++/zoom.h
+
+Good luck!
--- /dev/null
+// $Header: /home/cvsroot/yaz++/zoom/master-header,v 1.1 2002-08-08 13:31:54 mike Exp $
+//
+// ZOOM C++ Binding.
+// The ZOOM homepage is at http://zoom.z3950.org/
+//
+// Derived from version 1.0g at
+// http://zoom.z3950.org/bind/cplusplus/zoom-1.0g.hh
+
+#include <stddef.h> // for size_t
+
+*/*
+* * This is a bit stupid. The fact that our ZOOM-C++ implementation is
+* * based on the ZOOM-C implementation is our Dirty Little Secret, and
+* * there is in principle no reason why client code need be bothered
+* * with it. Except of course that the public class declarations in
+* * C++ have to lay their private parts out for the world to see
+* * (oo-er). Hence the inclusion of <yaz/zoom.h>
+* */
+*#include <yaz/zoom.h>
+*
+namespace ZOOM {
+ // Forward declarations for type names.
+ class query;
+ class resultSet;
+ class record;
+
+ const char *option (const char *key);
+ const char *option (const char *key, const char *val);
+ int errcode ();
+ char *errmsg ();
+ char *addinfo ();
+
+ class connection {
+* ZOOM_connection c;
+ public:
+ connection (const char *hostname, int portnum);
+ // ### I would like to add a ``throw (ZOOM::error)'' clause
+ // here, but it looks like G++ 2.95.2 doesn't recognise it.
+ ~connection ();
+ const char *option (const char *key) const;
+ const char *option (const char *key, const char *val);
+* ZOOM_connection _getYazConnection() const { return c; } // package-private
+ };
+
+ class query {
+ // pure virtual class: derive concrete subclasses from it.
+* protected:
+* ZOOM_query q;
+ public:
+ virtual ~query ();
+* ZOOM_query _getYazQuery() const { return q; } // package-private
+ };
+
+ class prefixQuery : public query {
+ public:
+ prefixQuery (const char *pqn);
+ ~prefixQuery();
+ };
+
+ class CCLQuery : public query {
+ public:
+ CCLQuery (const char *ccl, void *qualset);
+ ~CCLQuery();
+ };
+
+ class resultSet {
+* connection &owner;
+* ZOOM_resultset rs;
+ public:
+ resultSet (connection &c, const query &q);
+ ~resultSet ();
+ const char *option (const char *key) const;
+ const char *option (const char *key, const char *val);
+ size_t size () const;
+ const record *getRecord (size_t i) const;
+ };
+
+ class record {
+* const resultSet *owner;
+* ZOOM_record r;
+ public:
+* record::record(const resultSet *rs, ZOOM_record rec):
+* owner(rs), r(rec) {}
+ ~record ();
+ enum syntax {
+ UNKNOWN, GRS1, SUTRS, USMARC, UKMARC, XML
+ };
+ record *clone () const;
+ syntax recsyn () const;
+ const char *render () const;
+ const char *rawdata () const;
+ };
+
+ class error {
+* protected:
+* int code;
+ public:
+ error (int code);
+ int errcode () const;
+ const char *errmsg () const;
+ };
+
+ class systemError: public error {
+ public:
+ systemError ();
+ int errcode () const;
+ const char *errmsg () const;
+ };
+
+ class bib1Error: public error {
+* const char *info;
+ public:
+* ~bib1Error();
+ bib1Error (int errcode, const char *addinfo);
+ int errcode () const;
+ const char *errmsg () const;
+ const char *addinfo () const;
+ };
+
+ class queryError: public error {
+* const char *q;
+ public:
+* ~queryError();
+ static const int PREFIX = 1;
+ static const int CCL = 2;
+ queryError (int qtype, const char *source);
+ int errcode () const;
+ const char *errmsg () const;
+ const char *addinfo () const;
+ };
+}
--- /dev/null
+// $Header: /home/cvsroot/yaz++/zoom/zclient.cpp,v 1.1 2002-08-08 13:31:54 mike Exp $
+
+// Trivial sample client
+
+#include <stdlib.h> // for atoi()
+#include <iostream.h>
+#include "zoom++.h"
+
+int main(int argc, char **argv)
+{
+ if (argc != 5) {
+ cerr << "Usage: " << argv[0] <<
+ " <host> <port> <db> <@prefix-search>\n";
+ return 1;
+ }
+
+ const char *hostname = argv[1];
+ const int port = atoi(argv[2]);
+ const char *dbname = argv[3];
+ const char *searchSpec = argv[4];
+
+ ZOOM::connection *conn;
+ try {
+ conn = new ZOOM::connection(hostname, port);
+ } catch(ZOOM::bib1Error err) {
+ cerr << argv[0] << ": connect: " <<
+ err.errmsg() << " (" << err.addinfo() << ")\n";
+ return 2;
+ } catch(ZOOM::error err) {
+ cerr << argv[0] << ": connect: " << err.errmsg() << "\n";
+ return 2;
+ }
+
+ conn->option("databaseName", dbname);
+ ZOOM::prefixQuery pq(searchSpec);
+ ZOOM::resultSet *rs;
+ try {
+ rs = new ZOOM::resultSet(*conn, pq);
+ } catch(ZOOM::bib1Error err) {
+ cerr << argv[0] << ": searchSpec: " <<
+ err.errmsg() << " (" << err.addinfo() << ")\n";
+ return 3;
+ }
+
+ size_t n = rs->size();
+ cout << "found " << n << " records:\n";
+ for (size_t i = 0; i < n; i++) {
+ const ZOOM::record *rec = rs->getRecord(i);
+ cout << "=== record " << i+1 << " (recsyn " << rec->recsyn()
+ << ") ===\n" << rec->render();
+ }
+
+ return 0;
+}
--- /dev/null
+// $Header: /home/cvsroot/yaz++/zoom/zconn.cpp,v 1.1 2002-08-08 13:31:54 mike Exp $
+
+// Z39.50 Connection class
+
+#include "zoom++.h"
+
+
+namespace ZOOM {
+ connection::connection(const char *hostname, int portnum) {
+ c = ZOOM_connection_new(hostname, portnum);
+
+ int errcode;
+ const char *errmsg; // unused: carries same info as `errcode'
+ const char *addinfo;
+ if ((errcode = ZOOM_connection_error(c, &errmsg, &addinfo)) != 0) {
+ throw bib1Error(errcode, addinfo);
+ }
+ }
+
+ const char *connection::option(const char *key) const {
+ return ZOOM_connection_option_get(c, key);
+ }
+
+ const char *connection::option(const char *key, const char *val) {
+ // ### There may be memory-management issues here.
+ const char *old = ZOOM_connection_option_get(c, key);
+ ZOOM_connection_option_set(c, key, val);
+ return old;
+ }
+
+ connection::~connection() {
+ ZOOM_connection_destroy(c);
+ }
+}
--- /dev/null
+// $Header: /home/cvsroot/yaz++/zoom/Attic/zerr.cpp,v 1.1 2002-08-08 13:31:54 mike Exp $
+
+// Z39.50 Error classes
+
+#include <errno.h>
+#include <string.h> // for strerror(), strlen(), strcpy()
+#include <stdio.h> // for sprintf()
+#include <yaz/diagbib1.h>
+#include "zoom++.h"
+
+
+namespace ZOOM {
+ error::error(int errcode) {
+ code = errcode;
+ }
+
+ int error::errcode() const {
+ return code;
+ }
+
+ const char *error::errmsg() const {
+ static char buf[40];
+ sprintf(buf, "error #%d", code);
+ return buf;
+ }
+
+
+
+ systemError::systemError() : error::error(errno){
+ code = errno;
+ }
+
+ int systemError::errcode() const {
+ return code;
+ }
+
+ const char *systemError::errmsg() const {
+ return strerror(code);
+ }
+
+
+
+ bib1Error::bib1Error(int errcode, const char *addinfo) :
+ error::error(errcode) {
+ info = new char[strlen(addinfo)+1];
+ strcpy((char*) info, addinfo);
+ }
+
+ bib1Error::~bib1Error() {
+ delete info;
+ }
+
+ int bib1Error::errcode() const {
+ return code;
+ }
+
+ const char *bib1Error::errmsg() const {
+ return diagbib1_str(code);
+ }
+
+ const char *bib1Error::addinfo() const {
+ return info;
+ }
+
+
+
+ queryError::queryError(int qtype, const char *source) :
+ error::error(qtype) {
+ q = new char[strlen(source)+1];
+ strcpy((char*) q, source);
+ }
+
+ queryError::~queryError() {
+ delete q;
+ }
+
+ int queryError::errcode() const {
+ return code;
+ }
+
+ const char *queryError::errmsg() const {
+ switch (code) {
+ case PREFIX: return "bad prefix search";
+ case CCL: return "bad CCL search";
+ default: break;
+ }
+ return "bad search (unknown type)";
+ }
+
+ const char *queryError::addinfo() const {
+ return q;
+ }
+}
--- /dev/null
+// $Header: /home/cvsroot/yaz++/zoom/zquery.cpp,v 1.1 2002-08-08 13:31:54 mike Exp $
+
+// Z39.50 Query classes
+
+#include "zoom++.h"
+
+
+namespace ZOOM {
+ query::~query() {
+ ZOOM_query_destroy(q);
+ q = 0;
+ }
+
+
+
+ prefixQuery::prefixQuery(const char *pqn) {
+ q = ZOOM_query_create();
+ if (ZOOM_query_prefix(q, pqn) == -1) {
+ ZOOM_query_destroy(q);
+ throw queryError(queryError::PREFIX, pqn);
+ }
+ }
+
+ // The binding specification says we have to have destructors for
+ // the query subclasses, so in they go -- even though they don't
+ // actually _do_ anything that inheriting the base query type's
+ // destructor wouldn't do. It's an irritant of C++ that the
+ // declaration of a subclass has to express explicitly the
+ // implementation detail of whether destruction is implemented
+ // by a specific destructor or by inheritance. Oh well.
+ //
+ // ### Not sure whether I need to do nothing at all, and the
+ // superclass destructor gets called anyway (I think that only
+ // works when you _don't_ define a destructor so that the default
+ // one pertains) or whether I need to duplicate the functionality
+ // of that destructor. Let's play safe by assuming the latter and
+ // zeroing what we free so that we get bitten if we're wrong.
+ //
+ prefixQuery::~prefixQuery() {
+ ZOOM_query_destroy(q);
+ q = 0;
+ }
+
+
+
+ CCLQuery::CCLQuery(const char *ccl, void *qualset) {
+ throw "Oops. No CCL support in ZOOM-C yet. Sorry.";
+ }
+
+ CCLQuery::~CCLQuery() {
+ ZOOM_query_destroy(q);
+ q = 0;
+ }
+}
--- /dev/null
+// $Header: /home/cvsroot/yaz++/zoom/zrec.cpp,v 1.1 2002-08-08 13:31:54 mike Exp $
+
+// Z39.50 Record class
+
+#include "zoom++.h"
+#include <string.h> // for strcasecmp()
+
+
+namespace ZOOM {
+ record::~record() {
+ if (owner == 0) {
+ // Must have been clone()d
+ ZOOM_record_destroy(r);
+ }
+ }
+
+ // ### Would this operation be better expressed as a copy constructor?
+ record *record::clone() const {
+ // It's tempting just to replace `r' with a clone, and return
+ // `this', but probably more honest to allocate a new C++
+ // record object.
+
+ record *rec = new record(0, 0);
+ if ((rec->r = ZOOM_record_clone(r)) == 0) {
+ // Presumably an out-of-memory error
+ throw systemError();
+ }
+
+ return rec;
+ }
+
+ // It's tempting to modify this method just to return either the
+ // string that ZOOM_record_get("syntax") gives us, or the VAL_*
+ // value from Yaz's OID database, but we'd break the nominal
+ // plug-compatibility of competing C++ binding implementations
+ // if we did that.
+ //
+ record::syntax record::recsyn() const {
+ const char *syn = ZOOM_record_get(r, "syntax", 0);
+
+ // These string constants are from yaz/util/oid.c
+ if (!strcasecmp(syn, "xml"))
+ return XML;
+ else if (!strcasecmp(syn, "GRS-1"))
+ return GRS1;
+ else if (!strcasecmp(syn, "SUTRS"))
+ return SUTRS;
+ else if (!strcasecmp(syn, "USmarc"))
+ return USMARC;
+ else if (!strcasecmp(syn, "UKmarc"))
+ return UKMARC;
+ else if (!strcasecmp(syn, "XML") ||
+ !strcasecmp(syn, "text-XML") ||
+ !strcasecmp(syn, "application-XML"))
+ return XML;
+
+ return UNKNOWN;
+ }
+
+ const char *record::render() const {
+ int len;
+ return ZOOM_record_get(r, "render", &len);
+ }
+
+ const char *record::rawdata() const {
+ int len;
+ return ZOOM_record_get(r, "raw", &len);
+ }
+}
--- /dev/null
+// $Header: /home/cvsroot/yaz++/zoom/zrs.cpp,v 1.1 2002-08-08 13:31:54 mike Exp $
+
+// Z39.50 Result Set class
+
+#include "zoom++.h"
+
+
+namespace ZOOM {
+ resultSet::resultSet(connection &c, const query &q) : owner(c) {
+ ZOOM_connection yazc = c._getYazConnection();
+ rs = ZOOM_connection_search(yazc, q._getYazQuery());
+ int errcode;
+ const char *errmsg; // unused: carries same info as `errcode'
+ const char *addinfo;
+
+ if ((errcode = ZOOM_connection_error(yazc, &errmsg, &addinfo)) != 0) {
+ throw bib1Error(errcode, addinfo);
+ }
+ }
+
+ resultSet::~resultSet() {
+ ZOOM_resultset_destroy(rs);
+ }
+
+ const char *resultSet::option(const char *key) const {
+ return ZOOM_resultset_option_get(rs, key);
+ }
+
+ const char *resultSet::option(const char *key, const char *val) {
+ // ### There may be memory-management issues here.
+ const char *old = ZOOM_resultset_option_get(rs, key);
+ ZOOM_resultset_option_set(rs, key, val);
+ return old;
+ }
+
+ size_t resultSet::size() const {
+ return ZOOM_resultset_size(rs);
+ }
+
+ const record *resultSet::getRecord(size_t i) const {
+ ZOOM_record rec;
+ if ((rec = ZOOM_resultset_record(rs, i)) == 0) {
+ const char *errmsg; // unused: carries same info as `errcode'
+ const char *addinfo;
+ int errcode = ZOOM_connection_error(owner._getYazConnection(),
+ &errmsg, &addinfo);
+ throw bib1Error(errcode, addinfo);
+ }
+
+ // Memory management is odd here. The ZOOM-C record we've
+ // just fetched (`rec') is owned by the ZOOM-C result-set we
+ // fetched it from (`rs'), so all we need to allocate is a
+ // ZOOM-C++ wrapper for it, which is destroyed at the
+ // appropriate time -- but the underlying (ZOOM-C) record is
+ // _not_ destroyed at that time, because it's done when the
+ // underlying result-set is deleted.
+ return new record(this, rec);
+ }
+}