Allow multiple record syntaxes to be specified in 'format' command.
[yaz-moved-to-github.git] / client / client.c
index f85f0e1..258c338 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: client.c,v 1.292 2005-06-25 15:46:01 adam Exp $
+ * $Id: client.c,v 1.297 2005-09-21 19:46:33 adam Exp $
  */
 
 #include <stdio.h>
@@ -100,7 +100,10 @@ static int mediumSetPresentNumber = 0;
 static Z_ElementSetNames *elementSetNames = 0; 
 static int setno = 1;                   /* current set offset */
 static enum oid_proto protocol = PROTO_Z3950;      /* current app protocol */
-static enum oid_value recordsyntax = VAL_USMARC;
+#define RECORDSYNTAX_MAX 20
+static enum oid_value recordsyntax_list[RECORDSYNTAX_MAX]  = { VAL_USMARC };
+static int recordsyntax_size = 1;
+
 static char *record_schema = 0;
 static int sent_close = 0;
 static NMEM session_mem = NULL;         /* memory handle for init-response */
@@ -133,6 +136,7 @@ static int scan_stepSize = 0;
 static int scan_position = 1;
 static int scan_size = 20;
 static char cur_host[200];
+static int last_hit_count = 0;
 
 typedef enum {
     QueryType_Prefix,
@@ -405,7 +409,7 @@ static int process_initResponse(Z_InitResponse *res)
                 if (oid->value == VAL_OCLCUI) {
                     Z_OCLC_UserInformation *oclc_ui;
                     ODR decode = odr_createmem(ODR_DECODE);
-                    odr_setbuf(decode, sat->buf, sat->len, 0);
+                    odr_setbuf(decode, (char *) sat->buf, sat->len, 0);
                     if (!z_OCLC_UserInformation(decode, &oclc_ui, 0, 0))
                         printf ("Bad OCLC UserInformation:\n");
                     else
@@ -1447,7 +1451,7 @@ static int send_SRW_searchRequest(const char *arg)
 
     if (record_schema)
         sr->u.request->recordSchema = record_schema;
-    if (recordsyntax == VAL_TEXT_XML)
+    if (recordsyntax_size == 1 && recordsyntax_list[0] == VAL_TEXT_XML)
         sr->u.explain_request->recordPacking = "xml";
     return send_srw(sr);
 }
@@ -1526,9 +1530,9 @@ static int send_searchRequest(const char *arg)
     if (smallSetUpperBound > 0 || (largeSetLowerBound > 1 &&
         mediumSetPresentNumber > 0))
     {
-        req->preferredRecordSyntax =
-            yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax);
-
+        if (recordsyntax_list > 0)
+            req->preferredRecordSyntax =
+                yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax_list[0]);
         req->smallSetElementSetNames =
             req->mediumSetElementSetNames = elementSetNames;
     }
@@ -1668,6 +1672,7 @@ static int process_searchResponse(Z_SearchResponse *res)
     else
         printf("Search was a bloomin' failure.\n");
     printf("Number of hits: %d", *res->resultCount);
+    last_hit_count = *res->resultCount;
     if (setnumber >= 0)
         printf (", setno %d", setnumber);
     printf ("\n");
@@ -2132,6 +2137,11 @@ static int send_itemorder(const char *type, int itemno)
 
 static int only_z3950()
 {
+    if (!conn)
+    {
+        printf ("Not connected yet\n");
+        return 1;
+    }
     if (protocol == PROTO_HTTP)
     {
         printf ("Not supported by SRW\n");
@@ -2165,7 +2175,7 @@ static int cmd_update_common(const char *arg, int version)
     Z_External *record_this = 0;
 
     if (only_z3950())
-        return 0;
+        return 1;
     *action = 0;
     *recid = 0;
     sscanf (arg, "%19s %19s%n", action, recid, &noread);
@@ -2313,43 +2323,49 @@ static int cmd_update_common(const char *arg, int version)
 
 static int cmd_xmles(const char *arg)
 {
-    int noread = 0;
-    char oid_str[51];
-    int oid_value_xmles = VAL_XMLES;
-    Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest);
-    Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
-
-    Z_External *ext = (Z_External *) odr_malloc(out, sizeof(*ext));
-    req->taskSpecificParameters = ext;
-    ext->descriptor = 0;
-    ext->which = Z_External_octet;
-    ext->u.single_ASN1_type = (Odr_oct *) odr_malloc (out, sizeof(Odr_oct));
-
-    sscanf(arg, "%50s%n", oid_str, &noread);
-    if (noread == 0)
-    {
-        printf("Missing OID for xmles\n");
-        return 0;
-    }
-    arg += noread;
-    oid_value_xmles  = oid_getvalbyname(oid_str);
-    if (oid_value_xmles == VAL_NONE)
+    if (only_z3950())
+        return 1;
+    else
     {
-        printf("Bad OID: %s\n", oid_str);
-        return 0;
+        int noread = 0;
+        char oid_str[51];
+        int oid_value_xmles = VAL_XMLES;
+        Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest);
+        Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
+        
+        Z_External *ext = (Z_External *) odr_malloc(out, sizeof(*ext));
+        
+        req->taskSpecificParameters = ext;
+        ext->indirect_reference = 0;
+        ext->descriptor = 0;
+        ext->which = Z_External_octet;
+        ext->u.single_ASN1_type = (Odr_oct *) odr_malloc (out, sizeof(Odr_oct));        
+        sscanf(arg, "%50s%n", oid_str, &noread);
+        if (noread == 0)
+        {
+            printf("Missing OID for xmles\n");
+            return 0;
+        }
+        arg += noread;
+        oid_value_xmles  = oid_getvalbyname(oid_str);
+        if (oid_value_xmles == VAL_NONE)
+        {
+            printf("Bad OID: %s\n", oid_str);
+            return 0;
+        }
+        
+        if (parse_cmd_doc(&arg, out, (char **) &ext->u.single_ASN1_type->buf,
+                          &ext->u.single_ASN1_type->len, 0) == 0)
+            return 0;
+        req->packageType = yaz_oidval_to_z3950oid(out, CLASS_EXTSERV,
+                                                  oid_value_xmles);
+        
+        ext->direct_reference = yaz_oidval_to_z3950oid(out, CLASS_EXTSERV,
+                                                       oid_value_xmles);
+        send_apdu(apdu);
+        
+        return 2;
     }
-
-    if (parse_cmd_doc(&arg, out, (char **) &ext->u.single_ASN1_type->buf,
-                      &ext->u.single_ASN1_type->len, 0) == 0)
-        return 0;
-    req->packageType = yaz_oidval_to_z3950oid(out, CLASS_EXTSERV,
-                                              oid_value_xmles);
-
-    ext->direct_reference = yaz_oidval_to_z3950oid(out, CLASS_EXTSERV,
-                                                   oid_value_xmles);
-    send_apdu(apdu);
-
-    return 2;
 }
 
 static int cmd_itemorder(const char *arg)
@@ -2358,7 +2374,7 @@ static int cmd_itemorder(const char *arg)
     int itemno;
    
     if (only_z3950())
-        return 0;
+        return 1;
     if (sscanf (arg, "%10s %d", type, &itemno) != 2)
         return 0;
 
@@ -2415,7 +2431,7 @@ static int cmd_explain(const char *arg)
         
         /* save this for later .. when fetching individual records */
         sr = yaz_srw_get(out, Z_SRW_explain_request);
-        if (recordsyntax == VAL_TEXT_XML)
+        if (recordsyntax_size > 0 && recordsyntax_list[0] == VAL_TEXT_XML)
             sr->u.explain_request->recordPacking = "xml";
         send_srw(sr);
         return 2;
@@ -2431,8 +2447,8 @@ static int cmd_init(const char *arg)
         strncpy (cur_host, arg, sizeof(cur_host)-1);
         cur_host[sizeof(cur_host)-1] = 0;
     }
-    if (!conn || protocol != PROTO_Z3950)
-       return 0;
+    if (only_z3950())
+        return 1;
     send_initRequest(cur_host);
     return 2;
 }
@@ -2476,11 +2492,6 @@ static int cmd_find(const char *arg)
 
 static int cmd_delete(const char *arg)
 {
-    if (!conn)
-    {
-        printf("Not connected yet\n");
-        return 0;
-    }
     if (only_z3950())
         return 0;
     if (!send_deleteResultSetRequest(arg))
@@ -2497,8 +2508,6 @@ static int cmd_ssub(const char *arg)
 
 static int cmd_lslb(const char *arg)
 {
-    if (only_z3950())
-        return 0;
     if (!(largeSetLowerBound = atoi(arg)))
         return 0;
     return 1;
@@ -2506,8 +2515,6 @@ static int cmd_lslb(const char *arg)
 
 static int cmd_mspn(const char *arg)
 {
-    if (only_z3950())
-        return 0;
     if (!(mediumSetPresentNumber = atoi(arg)))
         return 0;
     return 1;
@@ -2556,7 +2563,15 @@ static void parse_show_args(const char *arg_c, char *setstring,
         *p = '\0';
     }
     if (*arg)
-        *start = atoi(arg);
+    {
+        if (!strcmp(arg, "all"))
+        {
+            *number = last_hit_count;
+            *start = 1;
+        }
+        else
+            *start = atoi(arg);
+    }
     if (p && (p=strchr(p+1, '+')))
         strcpy (setstring, p+1);
     else if (setnumber >= 0)
@@ -2582,10 +2597,11 @@ static int send_presentRequest(const char *arg)
     req->resultSetStartPoint = &setno;
     req->numberOfRecordsRequested = &nos;
 
-    req->preferredRecordSyntax =
-        yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax);
+    if (recordsyntax_size == 1)
+        req->preferredRecordSyntax =
+            yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax_list[0]);
 
-    if (record_schema)
+    if (record_schema || recordsyntax_size >= 2)
     {
         req->recordComposition = &compo;
         compo.which = Z_RecordComp_complex;
@@ -2597,16 +2613,21 @@ static int send_presentRequest(const char *arg)
 
         compo.u.complex->generic = (Z_Specification *)
             odr_malloc(out, sizeof(*compo.u.complex->generic));
+        
         compo.u.complex->generic->which = Z_Schema_oid;
-
-        compo.u.complex->generic->schema.oid =
-            yaz_str_to_z3950oid(out, CLASS_SCHEMA, record_schema);
-
-        if (!compo.u.complex->generic->schema.oid)
+        if (!record_schema)
+            compo.u.complex->generic->schema.oid = 0;
+        else 
         {
-            /* OID wasn't a schema! Try record syntax instead. */
-            compo.u.complex->generic->schema.oid = (Odr_oid *)
-                yaz_str_to_z3950oid(out, CLASS_RECSYN, record_schema);
+            compo.u.complex->generic->schema.oid =
+                yaz_str_to_z3950oid(out, CLASS_SCHEMA, record_schema);
+            
+            if (!compo.u.complex->generic->schema.oid)
+            {
+                /* OID wasn't a schema! Try record syntax instead. */
+                compo.u.complex->generic->schema.oid = (Odr_oid *)
+                    yaz_str_to_z3950oid(out, CLASS_RECSYN, record_schema);
+            }
         }
         if (!elementSetNames)
             compo.u.complex->generic->elementSpec = 0;
@@ -2621,8 +2642,22 @@ static int send_presentRequest(const char *arg)
         }
         compo.u.complex->num_dbSpecific = 0;
         compo.u.complex->dbSpecific = 0;
-        compo.u.complex->num_recordSyntax = 0;
-        compo.u.complex->recordSyntax = 0;
+        if (recordsyntax_size >= 2)
+        {
+            int i;
+            compo.u.complex->num_recordSyntax = recordsyntax_size;
+            compo.u.complex->recordSyntax = (Odr_oid **)
+                odr_malloc(out, recordsyntax_size * sizeof(Odr_oid*));
+            for (i = 0; i < recordsyntax_size; i++)
+            compo.u.complex->recordSyntax[i] =                 
+                yaz_oidval_to_z3950oid(out, CLASS_RECSYN,
+                                       recordsyntax_list[i]);
+        }
+        else
+        {
+            compo.u.complex->num_recordSyntax = 0;
+            compo.u.complex->recordSyntax = 0;
+        }
     }
     else if (elementSetNames)
     {
@@ -2649,7 +2684,7 @@ static int send_SRW_presentRequest(const char *arg)
     sr->u.request->maximumRecords = odr_intdup(out, nos);
     if (record_schema)
         sr->u.request->recordSchema = record_schema;
-    if (recordsyntax == VAL_TEXT_XML)
+    if (recordsyntax_size == 1 && recordsyntax_list[0] == VAL_TEXT_XML)
         sr->u.request->recordPacking = "xml";
     return send_srw(sr);
 }
@@ -2664,6 +2699,7 @@ static void close_session (void)
     odr_reset(out);
     odr_reset(in);
     odr_reset(print);
+    last_hit_count = 0;
 }
 
 void process_close(Z_Close *req)
@@ -2741,11 +2777,6 @@ int cmd_cancel(const char *arg)
         apdu->u.triggerResourceControlRequest;
     bool_t rfalse = 0;
     
-    if (!conn)
-    {
-        printf("Session not initialized yet\n");
-        return 0;
-    }
     if (only_z3950())
         return 0;
     if (session_initResponse &&
@@ -2968,11 +2999,6 @@ void process_deleteResultSetResponse (Z_DeleteResultSetResponse *res)
 
 int cmd_sort_generic(const char *arg, int newset)
 {
-    if (!conn)
-    {
-        printf("Session not initialized yet\n");
-        return 0;
-    }
     if (only_z3950())
         return 0;
     if (session_initResponse && 
@@ -3089,19 +3115,32 @@ int cmd_schema(const char *arg)
 
 int cmd_format(const char *arg)
 {
-    oid_value nsyntax;
+    const char *cp = arg;
+    int nor;
+    int idx = 0;
+    oid_value nsyntax[RECORDSYNTAX_MAX];
+    char form_str[41];
     if (!arg || !*arg)
     {
         printf("Usage: format <recordsyntax>\n");
         return 0;
     }
-    nsyntax = oid_getvalbyname (arg);
-    if (strcmp(arg, "none") && nsyntax == VAL_NONE)
+    while (sscanf(cp, "%40s%n", form_str, &nor) >= 1 && nor > 0 
+           && idx < RECORDSYNTAX_MAX)
     {
-        printf ("unknown record syntax\n");
-        return 0;
+        nsyntax[idx] = oid_getvalbyname(form_str);
+        if (!strcmp(form_str, "none"))
+            break;
+        if (nsyntax[idx] == VAL_NONE)
+        {
+            printf ("unknown record syntax: %s\n", form_str);
+            return 0;
+        }
+        cp += nor;
+        idx++;
     }
-    recordsyntax = nsyntax;
+    recordsyntax_size = idx;
+    memcpy(recordsyntax_list, nsyntax, idx * sizeof(*nsyntax));
     return 1;
 }
 
@@ -3178,11 +3217,8 @@ int cmd_close(const char *arg)
 {
     Z_APDU *apdu;
     Z_Close *req;
-    if (!conn)
-        return 0;
     if (only_z3950())
         return 0;
-
     apdu = zget_APDU(out, Z_APDU_close);
     req = apdu->u.close;
     *req->closeReason = Z_Close_finished;
@@ -4174,7 +4210,10 @@ int cmd_list_all(const char* args) {
     printf("ssub/lslb/mspn       : %d/%d/%d\n",smallSetUpperBound,largeSetLowerBound,mediumSetPresentNumber);
     
     /* print present related options */
-    printf("Format               : %s\n",yaz_z3950_oid_value_to_str(recordsyntax,CLASS_RECSYN));
+    printf("Format               : %s\n",
+           (recordsyntax_size > 0) ? 
+           yaz_z3950_oid_value_to_str(recordsyntax_list[0], CLASS_RECSYN) :
+           "none");
     printf("Schema               : %s\n",record_schema ? record_schema : "not set");
     printf("Elements             : %s\n",elementSetNames?elementSetNames->u.generic:"");
     
@@ -4245,6 +4284,7 @@ static struct {
 } cmd_array[] = {
     {"open", cmd_open, "('tcp'|'ssl')':<host>[':'<port>][/<db>]",NULL,0,NULL},
     {"quit", cmd_quit, "",NULL,0,NULL},
+    {"exit", cmd_quit, "",NULL,0,NULL},
     {"find", cmd_find, "<query>",NULL,0,NULL},
     {"delete", cmd_delete, "<setname>",NULL,0,NULL},
     {"base", cmd_base, "<base-name>",NULL,0,NULL},
@@ -4422,7 +4462,7 @@ int cmd_register_tab(const char* arg) {
 
 void process_cmd_line(char* line)
 {  
-    int i,res;
+    int i, res;
     char word[32], arg[10240];
     
 #if HAVE_GETTIMEOFDAY