SRW/SRU 1.1
authorAdam Dickmeiss <adam@indexdata.dk>
Sat, 20 Dec 2003 00:51:19 +0000 (00:51 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Sat, 20 Dec 2003 00:51:19 +0000 (00:51 +0000)
CHANGELOG
client/client.c
include/yaz/srw.h
src/Makefile.am
src/seshigh.c
src/soap.c
src/srw.c
src/srwutil.c [new file with mode: 0644]
src/zoom-c.c
src/zoom-p.h
win/makefile

index 02b5a79..bdab6c2 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,10 @@ Possible compatibility problems with earlier versions marked with '*'.
 
 --- NOT YET RELEASED
 
+* SRW/SRU 1.1. Since the Namespace has changed for SRW/SRU, it means that
+this version is incompatible with version 1.0 and older YAZ SRW/SRU
+implementations.
+
 CQL changes to reflect recent changes to the specification:
 * Documentation talks about context sets instead of index sets.
 * Documentation talks about indexes instead of qualifiers.
index a02c99c..0b0e8fe 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 1995-2003, Index Data
  * See the file LICENSE for details.
  *
- * $Id: client.c,v 1.215 2003-12-18 17:02:24 mike Exp $
+ * $Id: client.c,v 1.216 2003-12-20 00:51:19 adam Exp $
  */
 
 #include <stdio.h>
@@ -1131,7 +1131,7 @@ static int send_srw(Z_SRW_PDU *sr)
     char *path = 0;
     char ctype[50];
     Z_SOAP_Handler h[2] = {
-        {"http://www.loc.gov/zing/srw/v1.0/", 0, (Z_SOAP_fun) yaz_srw_codec},
+        {"http://www.loc.gov/zing/srw/", 0, (Z_SOAP_fun) yaz_srw_codec},
         {0, 0, 0}
     };
     ODR o = odr_createmem(ODR_ENCODE);
@@ -2133,6 +2133,29 @@ static int cmd_itemorder(const char *arg)
     return 2;
 }
 
+static int cmd_explain(const char *arg)
+{
+    if (protocol != PROTO_HTTP)
+       return 0;
+#if HAVE_XML2
+    if (!conn)
+       cmd_open(0);
+    if (1)
+    {
+       Z_SRW_PDU *sr = 0;
+       
+       setno = 1;
+       
+       /* save this for later .. when fetching individual records */
+       sr = yaz_srw_get(out, Z_SRW_explain_request);
+       send_srw(sr);
+       return 2;
+    }
+#else
+    return 0;
+#endif
+}
+    
 static int cmd_find(const char *arg)
 {
     if (!*arg)
@@ -3248,6 +3271,28 @@ struct timeval tv_start, tv_end;
 #endif
 
 #if HAVE_XML2
+static void handle_srw_record(Z_SRW_record *rec)
+{
+    if (rec->recordPosition)
+    {
+       printf ("pos=%d", *rec->recordPosition);
+       setno = *rec->recordPosition + 1;
+    }
+    if (rec->recordSchema)
+       printf (" schema=%s", rec->recordSchema);
+    printf ("\n");
+    if (rec->recordData_buf && rec->recordData_len)
+    {
+       fwrite(rec->recordData_buf, 1, rec->recordData_len, stdout);
+       printf ("\n");
+    }
+}
+
+static void handle_srw_explain_response(Z_SRW_explainResponse *res)
+{
+    handle_srw_record(&res->record);
+}
+
 static void handle_srw_response(Z_SRW_searchRetrieveResponse *res)
 {
     int i;
@@ -3266,23 +3311,7 @@ static void handle_srw_response(Z_SRW_searchRetrieveResponse *res)
     if (res->numberOfRecords)
         printf ("Number of hits: %d\n", *res->numberOfRecords);
     for (i = 0; i<res->num_records; i++)
-    {
-        Z_SRW_record *rec = res->records + i;
-
-        if (rec->recordPosition)
-        {
-            printf ("pos=%d", *rec->recordPosition);
-            setno = *rec->recordPosition + 1;
-        }
-        if (rec->recordSchema)
-            printf (" schema=%s", rec->recordSchema);
-        printf ("\n");
-        if (rec->recordData_buf && rec->recordData_len)
-        {
-            fwrite(rec->recordData_buf, 1, rec->recordData_len, stdout);
-            printf ("\n");
-        }
-    }
+       handle_srw_record(res->records + i);
 }
 
 static void http_response(Z_HTTP_Response *hres)
@@ -3297,7 +3326,7 @@ static void http_response(Z_HTTP_Response *hres)
         Z_SOAP *soap_package = 0;
         ODR o = odr_createmem(ODR_DECODE);
         Z_SOAP_Handler soap_handlers[2] = {
-            {"http://www.loc.gov/zing/srw/v1.0/", 0,
+            {"http://www.loc.gov/zing/srw/", 0,
              (Z_SOAP_fun) yaz_srw_codec},
             {0, 0, 0}
         };
@@ -3310,10 +3339,12 @@ static void http_response(Z_HTTP_Response *hres)
             Z_SRW_PDU *sr = soap_package->u.generic->p;
             if (sr->which == Z_SRW_searchRetrieve_response)
                 handle_srw_response(sr->u.response);
+            else if (sr->which == Z_SRW_explain_response)
+                handle_srw_explain_response(sr->u.explain_response);
             else
                 ret = -1;
         }
-        else if (!ret && (soap_package->which == Z_SOAP_fault
+        else if (soap_package && (soap_package->which == Z_SOAP_fault
                           || soap_package->which == Z_SOAP_error))
         {
             printf ("HTTP Error Status=%d\n", hres->code);
@@ -3321,6 +3352,9 @@ static void http_response(Z_HTTP_Response *hres)
                     soap_package->u.fault->fault_code);
             printf ("SOAP Fault string %s\n", 
                     soap_package->u.fault->fault_string);
+           if (soap_package->u.fault->details)
+               printf ("SOAP Details %s\n", 
+                       soap_package->u.fault->details);
         }
         else
             ret = -1;
@@ -3555,7 +3589,6 @@ int cmd_set_otherinfo(const char* args)
         printf("Error otherinfo index to large (%d>%d)\n",otherinfoNo,maxOtherInfosSupported);
     }
     
-    
     oidval = oid_getvalbyname (oid);
     if(oidval == -1 ) {
         printf("Error in set_otherinfo command unknown oid %s \n",oid);
@@ -3769,6 +3802,7 @@ static struct {
     {"adm-commit", cmd_adm_commit, "",NULL,0,NULL},
     {"adm-shutdown", cmd_adm_shutdown, "",NULL,0,NULL},
     {"adm-startup", cmd_adm_startup, "",NULL,0,NULL},
+    {"explain", cmd_explain, "", NULL, 0, NULL},
     {"help", cmd_help, "", NULL,0,NULL},
     {0,0,0,0,0,0}
 };
index bf61fda..a1ecadd 100644 (file)
@@ -2,13 +2,14 @@
  * Copyright (c) 2002-2003, Index Data.
  * See the file LICENSE for details.
  *
- * $Id: srw.h,v 1.8 2003-12-09 12:51:16 adam Exp $
+ * $Id: srw.h,v 1.9 2003-12-20 00:51:19 adam Exp $
  */
 
 #ifndef YAZ_SRW_H
 #define YAZ_SRW_H
 
 #include <yaz/soap.h>
+#include <yaz/zgdu.h>
 
 YAZ_BEGIN_CDECL
 
@@ -69,13 +70,12 @@ typedef struct {
 } Z_SRW_searchRetrieveResponse;
 
 typedef struct {
-    int dummy;
+    char *recordPacking;
+    char *database;
 } Z_SRW_explainRequest;
 
 typedef struct {
-    int explainPacking;
-    char *explainData_buf;
-    int explainData_len;
+    Z_SRW_record record;
 } Z_SRW_explainResponse;
     
 #define Z_SRW_searchRetrieve_request  1
@@ -91,6 +91,8 @@ typedef struct {
         Z_SRW_explainRequest *explain_request;
         Z_SRW_explainResponse *explain_response;
     } u;
+    char *srw_version;
+    char *database;
 } Z_SRW_PDU;
 
 YAZ_EXPORT int yaz_srw_codec(ODR o, void * pptr,
@@ -104,6 +106,13 @@ YAZ_EXPORT int yaz_diag_bib1_to_srw (int bib1_code);
 
 YAZ_EXPORT int yaz_diag_srw_to_bib1(int srw_code);
 
+YAZ_EXPORT char *yaz_uri_val(const char *path, const char *name, ODR o);
+YAZ_EXPORT void yaz_uri_val_int(const char *path, const char *name,
+                               ODR o, int **intp);
+YAZ_EXPORT int yaz_check_for_srw(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
+                                char **soap_ns, ODR decode);
+YAZ_EXPORT int yaz_check_for_sru(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
+                                char **soap_ns, ODR decode);
 YAZ_END_CDECL
 
 #endif
index 9295705..3f2cf90 100644 (file)
@@ -1,6 +1,6 @@
 ## Copyright (C) 1994-2003, Index Data
 ## All rights reserved.
-## $Id: Makefile.am,v 1.1 2003-10-27 12:21:30 adam Exp $
+## $Id: Makefile.am,v 1.2 2003-12-20 00:51:19 adam Exp $
 
 if ISTHR
 thrlib=libyazthread.la
@@ -56,8 +56,8 @@ libyaz_la_SOURCES=version.c options.c log.c marcdisp.c oid.c wrbuf.c \
   ill-core.c item-req.c ill-get.c \
   zget.c yaz-ccl.c diagbib1.c logrpn.c \
   otherinfo.c pquery.c sortspec.c z3950oid.c charneg.c \
-  zoom-c.c zoom-opt.c zoom-p.h grs1disp.c zgdu.c soap.c srw.c opacdisp.c \
-  cclfind.c ccltoken.c cclerrms.c cclqual.c cclptree.c \
+  zoom-c.c zoom-opt.c zoom-p.h grs1disp.c zgdu.c soap.c srw.c srwutil.c \
+  opacdisp.c cclfind.c ccltoken.c cclerrms.c cclqual.c cclptree.c \
   cclqfile.c cclstr.c \
   cql.y cqlstdio.c cqltransform.c cqlutil.c xcqlutil.c cqlstring.c \
   cqlstrer.c lexer.h \
index 9d7db7e..afc1e82 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 1995-2003, Index Data
  * See the file LICENSE for details.
  *
- * $Id: seshigh.c,v 1.4 2003-12-04 11:48:06 adam Exp $
+ * $Id: seshigh.c,v 1.5 2003-12-20 00:51:19 adam Exp $
  */
 
 /*
@@ -749,76 +749,19 @@ static void srw_bend_explain(association *assoc, request *req,
         (*assoc->init->bend_explain)(assoc->backend, &rr);
         if (rr.explain_buf)
         {
-            srw_res->explainData_buf = rr.explain_buf;
-            srw_res->explainData_len = strlen(rr.explain_buf);
+           int packing = Z_SRW_recordPacking_string;
+           if (srw_req->recordPacking && 
+               !strcmp(srw_req->recordPacking, "xml"))
+               packing = Z_SRW_recordPacking_XML;
+           srw_res->record.recordSchema = 0;
+           srw_res->record.recordPacking = packing;
+            srw_res->record.recordData_buf = rr.explain_buf;
+            srw_res->record.recordData_len = strlen(rr.explain_buf);
+           srw_res->record.recordPosition = 0;
         }
     }
 }
 
-static int hex_digit (int ch)
-{
-    if (ch >= '0' && ch <= '9')
-        return ch - '0';
-    else if (ch >= 'a' && ch <= 'f')
-        return ch - 'a'+10;
-    else if (ch >= 'A' && ch <= 'F')
-        return ch - 'A'+10;
-    return 0;
-}
-
-static char *uri_val(const char *path, const char *name, ODR o)
-{
-    size_t nlen = strlen(name);
-    if (*path != '?')
-        return 0;
-    path++;
-    while (path && *path)
-    {
-        const char *p1 = strchr(path, '=');
-        if (!p1)
-            break;
-        if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
-        {
-            size_t i = 0;
-            char *ret;
-            
-            path = p1 + 1;
-            p1 = strchr(path, '&');
-            if (!p1)
-                p1 = strlen(path) + path;
-            ret = odr_malloc(o, p1 - path + 1);
-            while (*path && *path != '&')
-            {
-                if (*path == '+')
-                {
-                    ret[i++] = ' ';
-                    path++;
-                }
-                else if (*path == '%' && path[1] && path[2])
-                {
-                    ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
-                    path = path + 3;
-                }
-                else
-                    ret[i++] = *path++;
-            }
-            ret[i] = '\0';
-            return ret;
-        }
-        path = strchr(p1, '&');
-        if (path)
-            path++;
-    }
-    return 0;
-}
-
-void uri_val_int(const char *path, const char *name, ODR o, int **intp)
-{
-    const char *v = uri_val(path, name, o);
-    if (v)
-        *intp = odr_intdup(o, atoi(v));
-}
-
 static void process_http_request(association *assoc, request *req)
 {
     Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
@@ -831,17 +774,17 @@ static void process_http_request(association *assoc, request *req)
     {
         char *db = "Default";
         const char *p0 = hreq->path, *p1;
+       const char *operation = 0;
 #if HAVE_XML2
         int ret = -1;
         char *charset = 0;
         Z_SOAP *soap_package = 0;
         static Z_SOAP_Handler soap_handlers[2] = {
-            {"http://www.loc.gov/zing/srw/v1.0/", 0,
+            {"http://www.loc.gov/zing/srw/", 0,
              (Z_SOAP_fun) yaz_srw_codec},
             {0, 0, 0}
         };
 #endif
-        
         if (*p0 == '/')
             p0++;
         p1 = strchr(p0, '?');
@@ -853,14 +796,18 @@ static void process_http_request(association *assoc, request *req)
             memcpy (db, p0, p1 - p0);
             db[p1 - p0] = '\0';
         }
+       if (p1)
+           operation = yaz_uri_val(p1, "operation", o);
+       if (!operation)
+           operation = "explain";
 #if HAVE_XML2
-        if (p1 && *p1 == '?' && p1[1])
+        if (p1 && !strcmp(operation, "searchRetrieve"))
         {
             Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
             Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_searchRetrieve_request);
-            char *query = uri_val(p1, "query", o);
-            char *pQuery = uri_val(p1, "pQuery", o);
-            char *sortKeys = uri_val(p1, "sortKeys", o);
+            char *query = yaz_uri_val(p1, "query", o);
+            char *pQuery = yaz_uri_val(p1, "pQuery", o);
+            char *sortKeys = yaz_uri_val(p1, "sortKeys", o);
             
             if (query)
             {
@@ -877,16 +824,14 @@ static void process_http_request(association *assoc, request *req)
                 sr->u.request->sort_type = Z_SRW_sort_type_sort;
                 sr->u.request->sort.sortKeys = sortKeys;
             }
-            sr->u.request->recordSchema = uri_val(p1, "recordSchema", o);
-            sr->u.request->recordPacking = uri_val(p1, "recordPacking", o);
+            sr->u.request->recordSchema = yaz_uri_val(p1, "recordSchema", o);
+            sr->u.request->recordPacking = yaz_uri_val(p1, "recordPacking", o);
             if (!sr->u.request->recordPacking)
                 sr->u.request->recordPacking = "xml";
-            uri_val_int(p1, "maximumRecords", o, 
+            yaz_uri_val_int(p1, "maximumRecords", o, 
                         &sr->u.request->maximumRecords);
-            uri_val_int(p1, "startRecord", o,
+            yaz_uri_val_int(p1, "startRecord", o,
                         &sr->u.request->startRecord);
-            if (sr->u.request->startRecord)
-                yaz_log(LOG_LOG, "startRecord=%d", *sr->u.request->startRecord);
             sr->u.request->database = db;
             srw_bend_search(assoc, req, sr->u.request, res->u.response);
             
@@ -917,17 +862,21 @@ static void process_http_request(association *assoc, request *req)
                 strcat(ctype, charset);
                 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
             }
-
         }
-        else
+        else if (p1 && !strcmp(operation, "explain"))
         {
             Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
             Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_explain_request);
 
+            sr->u.explain_request->recordPacking =
+               yaz_uri_val(p1, "recordPacking", o);
+            if (!sr->u.explain_request->recordPacking)
+                sr->u.explain_request->recordPacking = "xml";
+
             srw_bend_explain(assoc, req, sr->u.explain_request,
                             res->u.explain_response);
 
-            if (res->u.explain_response->explainData_buf)
+            if (res->u.explain_response->record.recordData_buf)
             {
                 soap_package = odr_malloc(o, sizeof(*soap_package));
                 soap_package->which = Z_SOAP_generic;
@@ -1062,7 +1011,7 @@ static void process_http_request(association *assoc, request *req)
 
             static Z_SOAP_Handler soap_handlers[2] = {
 #if HAVE_XML2
-                {"http://www.loc.gov/zing/srw/v1.0/", 0,
+                {"http://www.loc.gov/zing/srw/", 0,
                  (Z_SOAP_fun) yaz_srw_codec},
 #endif
                 {0, 0, 0}
@@ -1087,8 +1036,22 @@ static void process_http_request(association *assoc, request *req)
                 soap_package->u.generic->no == 0)
             {
                 /* SRW package */
+               char *db = "Default";
+               const char *p0 = hreq->path, *p1;
                 Z_SRW_PDU *sr = soap_package->u.generic->p;
-                
+               
+               if (*p0 == '/')
+                   p0++;
+               p1 = strchr(p0, '?');
+               if (!p1)
+                   p1 = p0 + strlen(p0);
+               if (p1 != p0)
+               {
+                   db = (char*) odr_malloc(assoc->decode, p1 - p0 + 1);
+                   memcpy (db, p0, p1 - p0);
+                   db[p1 - p0] = '\0';
+               }
+
                 if (sr->which == Z_SRW_searchRetrieve_request)
                 {
                     Z_SRW_PDU *res =
@@ -1096,23 +1059,8 @@ static void process_http_request(association *assoc, request *req)
                                     Z_SRW_searchRetrieve_response);
 
                     if (!sr->u.request->database)
-                    {
-                        const char *p0 = hreq->path, *p1;
-                        if (*p0 == '/')
-                            p0++;
-                        p1 = strchr(p0, '?');
-                        if (!p1)
-                            p1 = p0 + strlen(p0);
-                        if (p1 != p0)
-                        {
-                            sr->u.request->database =
-                                odr_malloc(assoc->decode, p1 - p0 + 1);
-                            memcpy (sr->u.request->database, p0, p1 - p0);
-                            sr->u.request->database[p1 - p0] = '\0';
-                        }
-                        else
-                            sr->u.request->database = "Default";
-                    }
+                       sr->u.request->database = db;
+
                     srw_bend_search(assoc, req, sr->u.request,
                                     res->u.response);
                     
@@ -1124,9 +1072,12 @@ static void process_http_request(association *assoc, request *req)
                     Z_SRW_PDU *res =
                         yaz_srw_get(assoc->encode, Z_SRW_explain_response);
 
+                    if (!sr->u.explain_request->database)
+                       sr->u.explain_request->database = db;
+
                     srw_bend_explain(assoc, req, sr->u.explain_request,
                                      res->u.explain_response);
-                    if (!res->u.explain_response->explainData_buf)
+                    if (!res->u.explain_response->record.recordData_buf)
                     {
                         z_soap_error(assoc->encode, soap_package,
                                      "SOAP-ENV:Client", "Explain Not Supported", 0);
@@ -1589,7 +1540,7 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb)
                assoc->init->implementation_name,
                odr_prepend(assoc->encode, "GFS", resp->implementationName));
 
-    version = odr_strdup(assoc->encode, "$Revision: 1.4 $");
+    version = odr_strdup(assoc->encode, "$Revision: 1.5 $");
     if (strlen(version) > 10)  /* check for unexpanded CVS strings */
        version[strlen(version)-2] = '\0';
     resp->implementationVersion = odr_prepend(assoc->encode,
index 64310bc..f33f2de 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 2002-2003, Index Data.
  * See the file LICENSE for details.
  *
- * $Id: soap.c,v 1.2 2003-12-18 23:04:23 adam Exp $
+ * $Id: soap.c,v 1.3 2003-12-20 00:51:19 adam Exp $
  */
 
 #include <yaz/soap.h>
@@ -111,6 +111,12 @@ int z_soap_codec_enc(ODR o, Z_SOAP **pp,
             return z_soap_error(o, p, "SOAP-ENV:Client",
                                 "SOAP No content for Body", 0);
         }
+        if (!ptr->ns)
+        {
+            xmlFreeDoc(doc);
+            return z_soap_error(o, p, "SOAP-ENV:Client",
+                                "SOAP No namespace for content", 0);
+        }
         /* check for fault package */
         if (!strcmp(ptr->ns->href, p->ns)
             && !strcmp(ptr->name, "Fault") && ptr->children)
@@ -205,7 +211,6 @@ int z_soap_codec_enc(ODR o, Z_SOAP **pp,
                                     handlers[no].ns);
             if (ret)
            {
-               xmlFreeNode(envelope_ptr);
                xmlFreeDoc(doc);
                 return ret;
            }
@@ -227,7 +232,6 @@ int z_soap_codec_enc(ODR o, Z_SOAP **pp,
             memcpy(*content_buf, buf_out, len_out);
             xmlFree(buf_out);
         }
-       xmlFreeNode(envelope_ptr);
         xmlFreeDoc(doc);
         return 0;
     }
index 2405c4c..3f39cf3 100644 (file)
--- a/src/srw.c
+++ b/src/srw.c
@@ -2,7 +2,7 @@
  * Copyright (c) 2002-2003, Index Data.
  * See the file LICENSE for details.
  *
- * $Id: srw.c,v 1.2 2003-12-18 17:05:20 mike Exp $
+ * $Id: srw.c,v 1.3 2003-12-20 00:51:19 adam Exp $
  */
 
 #include <yaz/srw.h>
@@ -26,21 +26,24 @@ static void add_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len)
     }
 }
 
-static void add_xsd_string_n(xmlNodePtr ptr, const char *elem, char *val,
-                             int len)
+xmlNodePtr add_xsd_string_n(xmlNodePtr ptr, const char *elem, char *val,
+                           int len)
 {
     if (val)
     {
         xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
         xmlNodePtr t = xmlNewTextLen(val, len);
         xmlAddChild(c, t);
+       return t;
     }
+    return 0;
 }
 
-static void add_xsd_string(xmlNodePtr ptr, const char *elem, char *val)
+xmlNodePtr add_xsd_string(xmlNodePtr ptr, const char *elem, char *val)
 {
     if (val)
-        xmlNewChild(ptr, 0, elem, val);
+        return xmlNewChild(ptr, 0, elem, val);
+    return 0;
 }
 
 static void add_xsd_integer(xmlNodePtr ptr, const char *elem, int *val)
@@ -159,6 +162,69 @@ static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
     return 1;
 }
 
+static int yaz_srw_record(ODR o, xmlNodePtr pptr, Z_SRW_record *rec,
+                         void *client_data, const char *ns)
+{
+    if (o->direction == ODR_DECODE)
+    {
+       int pack = Z_SRW_recordPacking_string;
+       xmlNodePtr ptr;
+       rec->recordSchema = 0;
+       rec->recordData_buf = 0;
+       rec->recordData_len = 0;
+       rec->recordPosition = 0;
+       for (ptr = pptr->children; ptr; ptr = ptr->next)
+       {
+           char *spack = 0;
+           
+           if (match_xsd_string(ptr, "recordSchema", o, 
+                                &rec->recordSchema))
+               ;
+           else if (match_xsd_string(ptr, "recordPacking", o, &spack))
+           {
+               if (pack && !strcmp(spack, "xml"))
+                   pack = Z_SRW_recordPacking_XML;
+               if (pack && !strcmp(spack, "string"))
+                   pack = Z_SRW_recordPacking_string;
+           }
+           else if (match_xsd_integer(ptr, "recordPosition", o, 
+                                      &rec->recordPosition))
+               ;
+           else 
+           {
+               if (pack == Z_SRW_recordPacking_XML)
+                   match_xsd_XML_n(ptr, "recordData", o, 
+                                   &rec->recordData_buf,
+                                   &rec->recordData_len);
+               if (pack == Z_SRW_recordPacking_string)
+                   match_xsd_string_n(ptr, "recordData", o, 
+                                      &rec->recordData_buf,
+                                      &rec->recordData_len);
+           }
+       }
+       rec->recordPacking = pack;
+    }
+    else if (o->direction == ODR_ENCODE)
+    {
+       xmlNodePtr ptr = pptr;
+       add_xsd_string(ptr, "recordSchema", rec->recordSchema);
+       switch(rec->recordPacking)
+       {
+       case Z_SRW_recordPacking_string:
+           add_xsd_string(ptr, "recordPacking", "string");
+           add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
+                            rec->recordData_len);
+           break;
+       case Z_SRW_recordPacking_XML:
+           add_xsd_string(ptr, "recordPacking", "xml");
+           add_XML_n(ptr, "recordData", rec->recordData_buf,
+                     rec->recordData_len);
+           break;
+       }
+       add_xsd_integer(ptr, "recordPosition", rec->recordPosition);
+    }
+}
+
 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
                            int *num, void *client_data, const char *ns)
 {
@@ -180,31 +246,7 @@ static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
         {
             if (ptr->type == XML_ELEMENT_NODE &&
                 !strcmp(ptr->name, "record"))
-            {
-                xmlNodePtr rptr;
-                (*recs)[i].recordSchema = 0;
-                (*recs)[i].recordPacking = Z_SRW_recordPacking_string;
-                (*recs)[i].recordData_buf = 0;
-                (*recs)[i].recordData_len = 0;
-                (*recs)[i].recordPosition = 0;
-                for (rptr = ptr->children; rptr; rptr = rptr->next)
-                {
-                    if (match_xsd_string(rptr, "recordSchema", o, 
-                                         &(*recs)[i].recordSchema))
-                        ;
-                    else if (match_xsd_string_n(rptr, "recordData", o, 
-                                                &(*recs)[i].recordData_buf,
-                                                &(*recs)[i].recordData_len))
-                        ;
-                    else if (match_xsd_XML_n(rptr, "recordXML", o, 
-                                             &(*recs)[i].recordData_buf,
-                                             &(*recs)[i].recordData_len))
-                        (*recs)[i].recordPacking = Z_SRW_recordPacking_XML;
-                    else if (match_xsd_integer(rptr, "recordPosition", o, 
-                                               &(*recs)[i].recordPosition))
-                        ;
-                }
-            }
+               yaz_srw_record(o, ptr, (*recs)+i, client_data, ns);
         }
     }
     else if (o->direction == ODR_ENCODE)
@@ -213,19 +255,7 @@ static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
         for (i = 0; i < *num; i++)
         {
             xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
-            add_xsd_string(rptr, "recordSchema", (*recs)[i].recordSchema);
-            switch((*recs)[i].recordPacking)
-            {
-            case Z_SRW_recordPacking_string:
-                add_xsd_string_n(rptr, "recordData", (*recs)[i].recordData_buf,
-                                 (*recs)[i].recordData_len);
-                break;
-            case Z_SRW_recordPacking_XML:
-                add_XML_n(rptr, "recordXML", (*recs)[i].recordData_buf,
-                          (*recs)[i].recordData_len);
-                break;
-            }
-            add_xsd_integer(rptr, "recordPosition", (*recs)[i].recordPosition);
+           yaz_srw_record(o, rptr, (*recs)+i, client_data, ns);
         }
     }
     return 0;
@@ -289,20 +319,25 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
     xmlNodePtr pptr = vptr;
     if (o->direction == ODR_DECODE)
     {
+       Z_SRW_PDU **p = handler_data;
         xmlNodePtr method = pptr->children;
 
         while (method && method->type == XML_TEXT_NODE)
             method = method->next;
         
-        if (!method || method->type != XML_ELEMENT_NODE)
+       if (!method)
+           return -1;
+        if (method->type != XML_ELEMENT_NODE)
             return -1;
+
+       *p = odr_malloc(o, sizeof(**p));
+       (*p)->srw_version = odr_strdup(o, "1.1");
+       
         if (!strcmp(method->name, "searchRetrieveRequest"))
         {
-            Z_SRW_PDU **p = handler_data;
             xmlNodePtr ptr = method->children;
             Z_SRW_searchRetrieveRequest *req;
 
-            *p = odr_malloc(o, sizeof(**p));
             (*p)->which = Z_SRW_searchRetrieve_request;
             req = (*p)->u.request = odr_malloc(o, sizeof(*req));
             req->query_type = Z_SRW_query_type_cql;
@@ -344,16 +379,17 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
                 else if (match_xsd_string(ptr, "database", o,
                                            &req->database))
                     ;
+                else if (match_xsd_string(ptr, "version", o,
+                                           &(*p)->srw_version))
+                    ;
                 /* missing is xQuery, xSortKeys .. */
             }
         }
         else if (!strcmp(method->name, "searchRetrieveResponse"))
         {
-            Z_SRW_PDU **p = handler_data;
             xmlNodePtr ptr = method->children;
             Z_SRW_searchRetrieveResponse *res;
 
-            *p = odr_malloc(o, sizeof(**p));
             (*p)->which = Z_SRW_searchRetrieve_response;
             res = (*p)->u.response = odr_malloc(o, sizeof(*res));
 
@@ -388,53 +424,67 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
                                            &res->nextRecordPosition))
                     ;
+                else if (match_xsd_string(ptr, "version", o,
+                                           &(*p)->srw_version))
+                    ;
             }
         }
         else if (!strcmp(method->name, "explainRequest"))
         {
-            Z_SRW_PDU **p = handler_data;
             Z_SRW_explainRequest *req;
+           xmlNodePtr ptr = method->children;
             
-            *p = odr_malloc(o, sizeof(**p));
             (*p)->which = Z_SRW_explain_request;
             req = (*p)->u.explain_request = odr_malloc(o, sizeof(*req));
-            req->dummy = 0;
+           req->recordPacking = 0;
+           for (; ptr; ptr = ptr->next)
+           {
+               if (match_xsd_string(ptr, "recordPacking", o,
+                                    &req->recordPacking))
+                   ;
+                else if (match_xsd_string(ptr, "version", o,
+                                           &(*p)->srw_version))
+                   ;
+           }
         }
         else if (!strcmp(method->name, "explainResponse"))
         {
-            Z_SRW_PDU **p = handler_data;
             Z_SRW_explainResponse *res;
             xmlNodePtr ptr = method->children;
 
-            *p = odr_malloc(o, sizeof(**p));
             (*p)->which = Z_SRW_explain_response;
             res = (*p)->u.explain_response = odr_malloc(o, sizeof(*res));
-            res->explainData_buf = 0;
-            res->explainData_len = 0;
-            res->explainPacking = Z_SRW_recordPacking_string;
-            for (; ptr; ptr = ptr->next)
-            {
-                match_xsd_string_n(ptr, "Explain", o, 
-                                   &res->explainData_buf,
-                                   &res->explainData_len);
-            }
+           
+           for (; ptr; ptr = ptr->next)
+           {
+               if (match_element(ptr, "record"))
+                   yaz_srw_record(o, ptr, &res->record, client_data, ns);
+                else if (match_xsd_string(ptr, "version", o,
+                                         &(*p)->srw_version))
+                   ;
+           }
         }
         else
+       {
+           *p = 0;
             return -1;
-
+       }
     }
     else if (o->direction == ODR_ENCODE)
     {
         Z_SRW_PDU **p = handler_data;
+       xmlNsPtr ns_srw;
+       
         if ((*p)->which == Z_SRW_searchRetrieve_request)
         {
             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
             xmlNodePtr ptr = xmlNewChild(pptr, 0,
                                          "searchRetrieveRequest", 0);
-            xmlNsPtr ns_srw = xmlNewNs(ptr, ns, "zs");
-
-            xmlSetNs(ptr, ns_srw);
+           ns_srw = xmlNewNs(ptr, ns, "zs");
+           xmlSetNs(ptr, ns_srw);
 
+           if ((*p)->srw_version)
+               add_xsd_string(ptr, "version", (*p)->srw_version);
             switch(req->query_type)
             {
             case Z_SRW_query_type_cql:
@@ -469,9 +519,11 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
             xmlNodePtr ptr = xmlNewChild(pptr, 0,
                                          "searchRetrieveResponse", 0);
-            xmlNsPtr ns_srw = xmlNewNs(ptr, ns, "zs");
+           ns_srw = xmlNewNs(ptr, ns, "zs");
+           xmlSetNs(ptr, ns_srw);
 
-            xmlSetNs(ptr, ns_srw);
+           if ((*p)->srw_version)
+               add_xsd_string(ptr, "version", (*p)->srw_version);
             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
             add_xsd_string(ptr, "resultSetId", res->resultSetId);
             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
@@ -492,20 +544,23 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
         else if ((*p)->which == Z_SRW_explain_request)
         {
             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
-            xmlNsPtr ns_srw = xmlNewNs(ptr, ns, "zs");
+           ns_srw = xmlNewNs(ptr, ns, "zs");
+           xmlSetNs(ptr, ns_srw);
 
-            xmlSetNs(ptr, ns_srw);
+           if ((*p)->srw_version)
+               add_xsd_string(ptr, "version", (*p)->srw_version);
         }
         else if ((*p)->which == Z_SRW_explain_response)
         {
             Z_SRW_explainResponse *res = (*p)->u.explain_response;
             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
-            xmlNsPtr ns_srw = xmlNewNs(ptr, ns, "zs");
-
-            xmlSetNs(ptr, ns_srw);
+           ns_srw = xmlNewNs(ptr, ns, "zs");
+           xmlSetNs(ptr, ns_srw);
 
-            add_xsd_string_n(ptr, "Explain", res->explainData_buf,
-                             res->explainData_len);
+           if ((*p)->srw_version)
+               add_xsd_string(ptr, "version", (*p)->srw_version);
+            ptr = xmlNewChild(ptr, 0, "record", 0);
+           yaz_srw_record(o, ptr, &res->record, client_data, ns);
         }
         else
             return -1;
@@ -517,6 +572,8 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
 {
     Z_SRW_PDU *sr = odr_malloc(o, sizeof(*o));
+
+    sr->srw_version = odr_strdup(o, "1.1");
     sr->which = which;
     switch(which)
     {
@@ -531,7 +588,7 @@ Z_SRW_PDU *yaz_srw_get(ODR o, int which)
         sr->u.request->maximumRecords = 0;
         sr->u.request->recordSchema = 0;
         sr->u.request->recordPacking = 0;
-        sr->u.request->database = 0;
+       sr->u.request->database = 0;
         break;
     case Z_SRW_searchRetrieve_response:
         sr->u.response = (Z_SRW_searchRetrieveResponse *)
@@ -548,14 +605,14 @@ Z_SRW_PDU *yaz_srw_get(ODR o, int which)
     case Z_SRW_explain_request:
         sr->u.explain_request = (Z_SRW_explainRequest *)
             odr_malloc(o, sizeof(*sr->u.explain_request));
-        sr->u.explain_request->dummy = 0;
+        sr->u.explain_request->recordPacking = 0;
+       sr->u.explain_request->database = 0;
         break;
     case Z_SRW_explain_response:
         sr->u.explain_response = (Z_SRW_explainResponse *)
             odr_malloc(o, sizeof(*sr->u.explain_response));
-        sr->u.explain_response->explainPacking = 0; 
-        sr->u.explain_response->explainData_buf = 0;
-        sr->u.explain_response->explainData_len = 0;
+       sr->u.explain_response->record.recordData_buf = 0;
+       sr->u.explain_response->record.recordData_len = 0;
     }
     return sr;
 }
@@ -853,3 +910,4 @@ int yaz_diag_srw_to_bib1(int code)
     }
     return 1;
 }
+
diff --git a/src/srwutil.c b/src/srwutil.c
new file mode 100644 (file)
index 0000000..24a9189
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2002-2003, Index Data.
+ * See the file LICENSE for details.
+ *
+ * $Id: srwutil.c,v 1.1 2003-12-20 00:51:19 adam Exp $
+ */
+
+#include <yaz/srw.h>
+
+static int hex_digit (int ch)
+{
+    if (ch >= '0' && ch <= '9')
+        return ch - '0';
+    else if (ch >= 'a' && ch <= 'f')
+        return ch - 'a'+10;
+    else if (ch >= 'A' && ch <= 'F')
+        return ch - 'A'+10;
+    return 0;
+}
+
+char *yaz_uri_val(const char *path, const char *name, ODR o)
+{
+    size_t nlen = strlen(name);
+    if (*path != '?')
+        return 0;
+    path++;
+    while (path && *path)
+    {
+        const char *p1 = strchr(path, '=');
+        if (!p1)
+            break;
+        if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
+        {
+            size_t i = 0;
+            char *ret;
+            
+            path = p1 + 1;
+            p1 = strchr(path, '&');
+            if (!p1)
+                p1 = strlen(path) + path;
+            ret = odr_malloc(o, p1 - path + 1);
+            while (*path && *path != '&')
+            {
+                if (*path == '+')
+                {
+                    ret[i++] = ' ';
+                    path++;
+                }
+                else if (*path == '%' && path[1] && path[2])
+                {
+                    ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
+                    path = path + 3;
+                }
+                else
+                    ret[i++] = *path++;
+            }
+            ret[i] = '\0';
+            return ret;
+        }
+        path = strchr(p1, '&');
+        if (path)
+            path++;
+    }
+    return 0;
+}
+
+void yaz_uri_val_int(const char *path, const char *name, ODR o, int **intp)
+{
+    const char *v = yaz_uri_val(path, name, o);
+    if (v)
+        *intp = odr_intdup(o, atoi(v));
+}
+
+int yaz_check_for_srw(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
+                     char **soap_ns, ODR decode)
+{
+    if (!strcmp(hreq->method, "POST"))
+    {
+       const char *content_type = z_HTTP_header_lookup(hreq->headers,
+                                                       "Content-Type");
+       if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
+       {
+           char *db = "Default";
+           const char *p0 = hreq->path, *p1;
+           Z_SOAP *soap_package = 0;
+            int ret = -1;
+            int http_code = 500;
+            const char *charset_p = 0;
+            char *charset = 0;
+           
+            static Z_SOAP_Handler soap_handlers[2] = {
+#if HAVE_XML2
+                {"http://www.loc.gov/zing/srw/", 0,
+                 (Z_SOAP_fun) yaz_srw_codec},
+#endif
+                {0, 0, 0}
+            };
+           
+           if (*p0 == '/')
+               p0++;
+           p1 = strchr(p0, '?');
+           if (!p1)
+               p1 = p0 + strlen(p0);
+           if (p1 != p0)
+           {
+               db = (char*) odr_malloc(decode, p1 - p0 + 1);
+               memcpy (db, p0, p1 - p0);
+               db[p1 - p0] = '\0';
+           }
+
+            if ((charset_p = strstr(content_type, "; charset=")))
+            {
+                int i = 0;
+                charset_p += 10;
+                while (i < 20 && charset_p[i] &&
+                       !strchr("; \n\r", charset_p[i]))
+                    i++;
+                charset = (char*) odr_malloc(decode, i+1);
+                memcpy(charset, charset_p, i);
+                charset[i] = '\0';
+            }
+            ret = z_soap_codec(decode, &soap_package, 
+                               &hreq->content_buf, &hreq->content_len,
+                               soap_handlers);
+           if (!ret && soap_package->which == Z_SOAP_generic &&
+               soap_package->u.generic->no == 0)
+           {
+               *srw_pdu = (Z_SRW_PDU*) soap_package->u.generic->p;
+               
+               if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
+                   (*srw_pdu)->u.request->database == 0)
+                   (*srw_pdu)->u.request->database = db;
+
+               if ((*srw_pdu)->which == Z_SRW_explain_request &&
+                   (*srw_pdu)->u.explain_request->database == 0)
+                   (*srw_pdu)->u.explain_request->database = db;
+
+               *soap_ns = odr_strdup(decode, soap_package->ns);
+               return 0;
+           }
+           return 1;
+       }
+    }
+    return 2;
+}
+
+int yaz_check_for_sru(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
+                     char **soap_ns, ODR decode)
+{
+    if (!strcmp(hreq->method, "GET"))
+    {
+        char *db = "Default";
+        const char *p0 = hreq->path, *p1;
+       const char *operation = 0;
+#if HAVE_XML2
+        int ret = -1;
+        char *charset = 0;
+        Z_SOAP *soap_package = 0;
+        static Z_SOAP_Handler soap_handlers[2] = {
+            {"http://www.loc.gov/zing/srw/", 0,
+             (Z_SOAP_fun) yaz_srw_codec},
+            {0, 0, 0}
+        };
+#endif
+        
+        if (*p0 == '/')
+            p0++;
+        p1 = strchr(p0, '?');
+        if (!p1)
+            p1 = p0 + strlen(p0);
+        if (p1 != p0)
+        {
+            db = (char*) odr_malloc(decode, p1 - p0 + 1);
+            memcpy (db, p0, p1 - p0);
+            db[p1 - p0] = '\0';
+        }
+#if HAVE_XML2
+       if (p1)
+           operation = yaz_uri_val(p1, "operation", decode);
+       if (!operation)
+           operation = "explain";
+        if (p1 && !strcmp(operation, "searchRetrieve"))
+        {
+            Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
+            char *query = yaz_uri_val(p1, "query", decode);
+            char *pQuery = yaz_uri_val(p1, "pQuery", decode);
+            char *sortKeys = yaz_uri_val(p1, "sortKeys", decode);
+            
+           *srw_pdu = sr;
+            if (query)
+            {
+                sr->u.request->query_type = Z_SRW_query_type_cql;
+                sr->u.request->query.cql = query;
+            }
+            if (pQuery)
+            {
+                sr->u.request->query_type = Z_SRW_query_type_pqf;
+                sr->u.request->query.pqf = pQuery;
+            }
+            if (sortKeys)
+            {
+                sr->u.request->sort_type = Z_SRW_sort_type_sort;
+                sr->u.request->sort.sortKeys = sortKeys;
+            }
+            sr->u.request->recordSchema = yaz_uri_val(p1, "recordSchema", decode);
+            sr->u.request->recordPacking = yaz_uri_val(p1, "recordPacking", decode);
+            if (!sr->u.request->recordPacking)
+                sr->u.request->recordPacking = "xml";
+            yaz_uri_val_int(p1, "maximumRecords", decode, 
+                        &sr->u.request->maximumRecords);
+            yaz_uri_val_int(p1, "startRecord", decode,
+                        &sr->u.request->startRecord);
+
+            sr->u.request->database = db;
+           *soap_ns = "SRU";
+           return 0;
+        }
+       else if (p1 && !strcmp(operation, "explain"))
+       {
+            Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
+
+           *srw_pdu = sr;
+            sr->u.explain_request->recordPacking =
+               yaz_uri_val(p1, "recordPacking", decode);
+            if (!sr->u.explain_request->recordPacking)
+                sr->u.explain_request->recordPacking = "xml";
+           sr->u.explain_request->database = db;
+           *soap_ns = "SRU";
+           return 0;
+       }
+#endif
+       return 1;
+    }
+    return 2;
+}
index 7cd3244..7e3203a 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 2000-2003, Index Data
  * See the file LICENSE for details.
  *
- * $Id: zoom-c.c,v 1.11 2003-12-11 00:37:22 adam Exp $
+ * $Id: zoom-c.c,v 1.12 2003-12-20 00:51:19 adam Exp $
  *
  * ZOOM layer for C, connections, result sets, queries.
  */
@@ -918,7 +918,7 @@ static zoom_ret ZOOM_connection_send_init (ZOOM_connection c)
        ZOOM_options_get(c->options, "implementationName"),
        odr_prepend(c->odr_out, "ZOOM-C", ireq->implementationName));
 
-    version = odr_strdup(c->odr_out, "$Revision: 1.11 $");
+    version = odr_strdup(c->odr_out, "$Revision: 1.12 $");
     if (strlen(version) > 10)  /* check for unexpanded CVS strings */
        version[strlen(version)-2] = '\0';
     ireq->implementationVersion = odr_prepend(c->odr_out,
@@ -1004,7 +1004,7 @@ static zoom_ret send_srw (ZOOM_connection c, Z_SRW_PDU *sr)
 {
     char ctype[50];
     Z_SOAP_Handler h[2] = {
-        {"http://www.loc.gov/zing/srw/v1.0/", 0, (Z_SOAP_fun) yaz_srw_codec},
+        {"http://www.loc.gov/zing/srw/", 0, (Z_SOAP_fun) yaz_srw_codec},
         {0, 0, 0}
     };
     ODR o = odr_createmem(ODR_ENCODE);
index b9d8223..d852feb 100644 (file)
@@ -1,12 +1,8 @@
 /*
  * Private C header for ZOOM C.
- * $Id: zoom-p.h,v 1.1 2003-10-27 12:21:36 adam Exp $
+ * $Id: zoom-p.h,v 1.2 2003-12-20 00:51:19 adam Exp $
  */
 
-#if HAVE_XSLT
-#include <yaz/srw.h>
-#endif
-
 #include <yaz/proto.h>
 #include <yaz/comstack.h>
 #include <yaz/wrbuf.h>
index 0d4f26f..dbf4780 100644 (file)
@@ -1,6 +1,6 @@
 # Copyright (C) 1994-2003, Index Data
 # All rights reserved.
-# $Id: makefile,v 1.66 2003-10-27 12:32:03 adam Exp $
+# $Id: makefile,v 1.67 2003-12-20 00:51:20 adam Exp $
 #
 # Programmed by
 #  HL: Heikki Levanto, Index Data
@@ -350,6 +350,7 @@ YAZ_ZUTIL_OBJS= \
    $(OBJDIR)\zgdu.obj \
    $(OBJDIR)\soap.obj \
    $(OBJDIR)\srw.obj \
+   $(OBJDIR)\srwutil.obj \
    $(OBJDIR)\zoom-c.obj \
    $(OBJDIR)\zoom-opt.obj