Projects/worblehat-old
Projects
/
worblehat-old
Archived
12
0
Fork 0
This repository has been archived on 2024-07-04. You can view files and clone it, but cannot push or open issues or pull requests.
worblehat-old/lisp/libyaz.lisp

272 lines
7.0 KiB
Common Lisp
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(in-package #:z3950)
(define-foreign-library libyaz
(t (:default "libyaz.3")))
(use-foreign-library libyaz)
(defctype zoom-options :pointer)
(defcfun "ZOOM_options_create" zoom-options)
(defcfun "ZOOM_options_create_with_parent" zoom-options
(parent zoom-options))
(defcfun "ZOOM_options_destroy" :void
(opt zoom-options))
(defcfun "ZOOM_options_get" :string
(opt zoom-options)
(name :string))
(defcfun "ZOOM_options_set" :void
(opt zoom-options)
(name :string)
(v :string))
;; TODO: ZOOM_options_callback.
(defctype zoom-connection :pointer)
(defcfun "ZOOM_connection_new" zoom-connection
(host :string)
(portnum :int))
(defcfun "ZOOM_connection_create" zoom-connection
(options :pointer))
(defcfun "ZOOM_connection_connect" :void
(connection zoom-connection)
(host :string)
(portnum :int))
(defcfun "ZOOM_connection_destroy" :void
(connection zoom-connection))
(defctype string-ptr :pointer)
(defcfun "ZOOM_connection_error" :int
(connection zoom-connection)
(cp string-ptr)
(addinfo string-ptr))
(defcfun "ZOOM_connection_option_get" :string
(connection zoom-connection)
(key :string))
(defcfun "ZOOM_connection_option_set" :void
(connection zoom-connection)
(key :string)
(value :string))
(defctype zoom-query :pointer)
(defcfun "ZOOM_query_create" zoom-query)
(defcfun "ZOOM_query_destroy" :void
(query zoom-query))
(defcfun "ZOOM_query_prefix" :int
(query zoom-query)
(str :string))
(defcfun "ZOOM_query_cql" :int
(query zoom-query)
(str :string))
(defcfun "ZOOM_query_sortby" :int
(query zoom-query)
(criteria :string))
(defctype zoom-resultset :pointer)
(defcfun "ZOOM_connection_search" zoom-resultset
(connection zoom-connection)
(query zoom-query))
(defcfun "ZOOM_connection_search_pqf" zoom-resultset
(connection zoom-connection)
(q :string))
(defcfun "ZOOM_resultset_destroy" :void
(resultset zoom-resultset))
(defcfun "ZOOM_resultset_option_set" :void
(resultset zoom-resultset)
(key :string)
(val :string))
(defcfun "ZOOM_resultset_option_get" :string
(resultset zoom-resultset)
(key :string))
(defcfun "ZOOM_resultset_size" size
(resultset zoom-resultset))
(defctype zoom-record :pointer)
(defctype zoom-record-ptr :pointer)
(defcfun "ZOOM_resultset_records" :void
(resultset zoom-resultset)
(recs zoom-record-ptr)
(start size)
(count size))
(defcfun "ZOOM_resultset_record" zoom-record
(resultset zoom-resultset)
(pos size))
(defctype size-ptr :pointer)
(defcfun "ZOOM_record_get" :pointer
(record zoom-record)
(type :string)
(len size-ptr))
;; TODO: ZOOM_record_error.
(defcfun "ZOOM_record_clone" zoom-record
(rec zoom-record))
(defcfun "ZOOM_record_destroy" :void
(rec zoom-record))
;; TODO: Scan.
(defcfun "memcpy" :pointer
(dest :pointer)
(src :pointer)
(n size))
;;;
;;; Lisp API
;;;
(defclass connection ()
((foreign)
(charset :initarg :charset :accessor connection-charset)
(result-sets :initform nil :accessor connection-result-sets)))
(define-condition connection-error (error)
((cp :initarg :cp)
(addinfo :initarg :addinfo))
(:report (lambda (condition stream)
(with-slots (cp addinfo) condition
(format stream "~A: ~A" cp addinfo)))))
(defmethod check-for-connection-error ((c connection))
(with-slots (foreign) c
(cffi:with-foreign-object (cp :pointer)
(cffi:with-foreign-object (addinfo :pointer)
(unless (zerop (zoom-connection-error foreign cp addinfo))
(error 'connection-error
:cp (cffi:foreign-string-to-lisp (mem-ref cp :pointer))
:addinfo (cffi:foreign-string-to-lisp
(mem-ref addinfo :pointer))))))))
(defun connect (host &key port (charset :utf8))
(let ((c (make-instance 'connection :charset charset)))
(with-slots (foreign) c
(setf foreign (zoom-connection-create (cffi:null-pointer)))
(zoom-connection-connect foreign host (or port 0)))
(check-for-connection-error c)
c))
(defmethod disconnect ((c connection))
"Close the connection to the Z39.50 server."
(with-slots (result-sets foreign) c
(when foreign
(dolist (weak-ref result-sets)
(when #1=(trivial-garbage:weak-pointer-value weak-ref)
(close-result-set #1#)))
(zoom-connection-destroy foreign)
(setf foreign nil)
t)))
(defmacro with-open-connection ((var host &rest connect-args)
&body body)
`(let ((,var (connect ,host ,@connect-args)))
(unwind-protect (progn ,@body)
(disconnect ,var))))
(defmethod connection-host ((c connection))
(with-slots (foreign) c
(zoom-connection-option-get foreign "host")))
(defclass result-set ()
((foreign :initarg :foreign)
(connection :initarg :connection :reader result-set-connection)))
(defmethod initialize-instance :after ((rs result-set) &key)
(push (trivial-garbage:make-weak-pointer rs)
(connection-result-sets (result-set-connection rs))))
(defmethod close-result-set ((rs result-set))
(with-slots (foreign) rs
(when foreign
(zoom-resultset-destroy foreign)
(setf foreign nil)
t)))
(defmethod (setf result-set-preferred-record-syntax) (value (rs result-set))
(with-slots (foreign) rs
(zoom-resultset-option-set foreign "preferredRecordSyntax" value)))
(defmethod result-set-size ((rs result-set))
(with-slots (foreign) rs
(zoom-resultset-size foreign)))
(defmethod result-set-record ((rs result-set) i &key (form :raw))
(with-slots (foreign) rs
(let ((r (zoom-resultset-record foreign i)))
(let ((syntax (cffi:foreign-string-to-lisp
(zoom-record-get r "syntax" (cffi:null-pointer)))))
(with-foreign-object (len :int)
(let* ((src (zoom-record-get r (ecase form
(:raw "raw; charset=marc8"))
len))
(buf (cffi:make-shareable-byte-vector (cffi:mem-ref len
:int))))
(with-pointer-to-vector-data (dest buf)
(memcpy dest src (cffi:mem-ref len :int)))
(values buf syntax)))))))
(defmethod search-pqf ((c connection) (q string))
(make-instance 'result-set
:connection c
:foreign (with-slots (foreign) c
;; (let ((cffi:*default-foreign-encoding*
;; (connection-charset c)))
(zoom-connection-search-pqf foreign q)
;; )
)))
(defmacro with-query ((var) &body body)
`(let ((,var (zoom-query-create)))
(unwind-protect (progn ,@body)
(zoom-query-destroy ,var))))
(defmethod search-cql ((c connection) (query-string string))
(with-query (q)
(zoom-query-cql q query-string) ;; FIXME: Return value?
(with-slots (foreign) c
(make-instance 'result-set
:connection c
:foreign (zoom-connection-search foreign q)))))
(defun test-loc ()
(with-open-connection (c "z3950.loc.gov:7490/Voyager" :charset :latin1)
(let ((rs (search-pqf c "@1=4 \"Alt imellem\"")))
(setf (result-set-preferred-record-syntax rs) "MARC21")
(result-set-record rs 0))))
(defun test-bibsys ()
(with-open-connection (c "z3950.bibsys.no" :port 2100 :charset :latin1)
(let ((rs (search-pqf c "@1=4 \"Fru Inger til Østråt\"")))
(setf (result-set-preferred-record-syntax rs) "NORMARC")
(result-set-record rs 0))))