Change local counter to size_t
[yaz-moved-to-github.git] / src / marcdisp.c
index ff4c97e..3271889 100644 (file)
@@ -1,5 +1,5 @@
 /* This file is part of the YAZ toolkit.
- * Copyright (C) 1995-2013 Index Data
+ * Copyright (C) Index Data
  * See the file LICENSE for details.
  */
 
@@ -257,7 +257,7 @@ static int element_name_append_attribute_value(
     /* TODO Map special codes to something possible for XML ELEMENT names */
 
     int encode = 0;
-    int index = 0;
+    size_t index = 0;
     int success = 0;
     for (index = 0; index < code_len; index++)
     {
@@ -371,53 +371,48 @@ void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
     check_ascii(mt, leader, 7, 'a');
     check_ascii(mt, leader, 8, '#');
     check_ascii(mt, leader, 9, '#');
-    if (!atoi_n_check(leader+10, 1, indicator_length))
+    if (!atoi_n_check(leader+10, 1, indicator_length) || *indicator_length == 0)
     {
-        yaz_marc_cprintf(mt,
-                         "Indicator length at offset 10 should hold a digit."
-                         " Assuming 2");
+        yaz_marc_cprintf(mt, "Indicator length at offset 10 should"
+                         " hold a number 1-9. Assuming 2");
         leader[10] = '2';
         *indicator_length = 2;
     }
-    if (!atoi_n_check(leader+11, 1, identifier_length))
+    if (!atoi_n_check(leader+11, 1, identifier_length) || *identifier_length == 0)
     {
-        yaz_marc_cprintf(mt,
-                         "Identifier length at offset 11 should hold a digit."
-                         " Assuming 2");
+        yaz_marc_cprintf(mt, "Identifier length at offset 11 should "
+                         " hold a number 1-9. Assuming 2");
         leader[11] = '2';
         *identifier_length = 2;
     }
     if (!atoi_n_check(leader+12, 5, base_address))
     {
-        yaz_marc_cprintf(mt,
-                         "Base address at offsets 12..16 should hold a number."
-                         " Assuming 0");
+        yaz_marc_cprintf(mt, "Base address at offsets 12..16 should"
+                         " hold a number. Assuming 0");
         *base_address = 0;
     }
     check_ascii(mt, leader, 17, '#');
     check_ascii(mt, leader, 18, '#');
     check_ascii(mt, leader, 19, '#');
-    if (!atoi_n_check(leader+20, 1, length_data_entry))
+    if (!atoi_n_check(leader+20, 1, length_data_entry) ||
+        *length_data_entry < 3)
     {
-        yaz_marc_cprintf(mt,
-                         "Length data entry at offset 20 should hold a digit."
-                         " Assuming 4");
+        yaz_marc_cprintf(mt, "Length data entry at offset 20 should"
+                         " hold a number 3-9. Assuming 4");
         *length_data_entry = 4;
         leader[20] = '4';
     }
-    if (!atoi_n_check(leader+21, 1, length_starting))
+    if (!atoi_n_check(leader+21, 1, length_starting) || *length_starting < 4)
     {
-        yaz_marc_cprintf(mt,
-                         "Length starting at offset 21 should hold a digit."
-                         " Assuming 5");
+        yaz_marc_cprintf(mt, "Length starting at offset 21 should"
+                         " hold a number 4-9. Assuming 5");
         *length_starting = 5;
         leader[21] = '5';
     }
     if (!atoi_n_check(leader+22, 1, length_implementation))
     {
-        yaz_marc_cprintf(mt,
-                         "Length implementation at offset 22 should hold a digit."
-                         " Assuming 0");
+        yaz_marc_cprintf(mt, "Length implementation at offset 22 should"
+                         " hold a number. Assuming 0");
         *length_implementation = 0;
         leader[22] = '0';
     }
@@ -469,6 +464,15 @@ static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
         }
         return 1; /* giving up */
     }
+    else
+    {
+        int error = 0;
+        size_t no_read = 0;
+        (void) yaz_read_UTF8_char((const unsigned char *) buf, strlen(buf),
+                                  &no_read, &error);
+        if (error == 0 && no_read > 0)
+            return no_read;
+    }
     return 1; /* we don't know */
 }
 
@@ -628,6 +632,8 @@ int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
         return yaz_marc_write_iso2709(mt, wr);
     case YAZ_MARC_CHECK:
         return yaz_marc_write_check(mt, wr);
+    case YAZ_MARC_JSON:
+        return yaz_marc_write_json(mt, wr);
     }
     return -1;
 }
@@ -1234,6 +1240,91 @@ int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
     return 0;
 }
 
+int yaz_marc_write_json(yaz_marc_t mt, WRBUF w)
+{
+    int identifier_length;
+    struct yaz_marc_node *n;
+    const char *leader = 0;
+    int first = 1;
+
+    wrbuf_puts(w, "{\n");
+    for (n = mt->nodes; n; n = n->next)
+        if (n->which == YAZ_MARC_LEADER)
+            leader = n->u.leader;
+
+    if (!leader)
+        return -1;
+
+    if (!atoi_n_check(leader+11, 1, &identifier_length))
+        return -1;
+
+    wrbuf_puts(w, "\t\"leader\":\"");
+    wrbuf_json_puts(w, leader);
+    wrbuf_puts(w, "\",\n");
+    wrbuf_puts(w, "\t\"fields\":\n\t[\n");
+
+    for (n = mt->nodes; n; n = n->next)
+    {
+        struct yaz_marc_subfield *s;
+        const char *sep = "";
+        switch (n->which)
+        {
+        case YAZ_MARC_LEADER:
+        case YAZ_MARC_COMMENT:
+            break;
+        case YAZ_MARC_CONTROLFIELD:
+            if (first)
+                first = 0;
+            else
+                wrbuf_puts(w, ",\n");
+            wrbuf_puts(w, "\t\t{\n\t\t\t\"");
+            wrbuf_iconv_json_puts(w, mt->iconv_cd, n->u.controlfield.tag);
+            wrbuf_puts(w, "\":\"");
+            wrbuf_iconv_json_puts(w, mt->iconv_cd, n->u.controlfield.data);
+            wrbuf_puts(w, "\"\n\t\t}");
+            break;
+        case YAZ_MARC_DATAFIELD:
+            if (first)
+                first = 0;
+            else
+                wrbuf_puts(w, ",\n");
+
+            wrbuf_puts(w, "\t\t{\n\t\t\t\"");
+            wrbuf_json_puts(w, n->u.datafield.tag);
+            wrbuf_puts(w, "\":\n\t\t\t{\n\t\t\t\t\"subfields\":\n\t\t\t\t[\n");
+            for (s = n->u.datafield.subfields; s; s = s->next)
+            {
+                size_t using_code_len = get_subfield_len(mt, s->code_data,
+                                                         identifier_length);
+                wrbuf_puts(w, sep);
+                sep = ",\n";
+                wrbuf_puts(w, "\t\t\t\t\t{\n\t\t\t\t\t\t\"");
+                wrbuf_iconv_json_write(w, mt->iconv_cd,
+                                       s->code_data, using_code_len);
+                wrbuf_puts(w, "\":\"");
+                wrbuf_iconv_json_puts(w, mt->iconv_cd,
+                                      s->code_data + using_code_len);
+                wrbuf_puts(w, "\"\n\t\t\t\t\t}");
+            }
+            wrbuf_puts(w, "\n\t\t\t\t]");
+            if (n->u.datafield.indicator[0])
+            {
+                int i;
+                for (i = 0; n->u.datafield.indicator[i]; i++)
+                {
+                    wrbuf_printf(w, ",\n\t\t\t\t\"ind%d\":\"%c\"", i + 1,
+                                 n->u.datafield.indicator[i]);
+                }
+            }
+            wrbuf_puts(w, "\n\t\t\t}\n");
+            wrbuf_puts(w, "\n\t\t}");
+            break;
+        }
+    }
+    wrbuf_puts(w, "\n\t]\n");
+    wrbuf_puts(w, "}\n");
+    return 0;
+}
 
 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
 {
@@ -1364,6 +1455,8 @@ int yaz_marc_decode_formatstr(const char *arg)
         mode = YAZ_MARC_XCHANGE;
     if (!strcmp(arg, "line"))
         mode = YAZ_MARC_LINE;
+    if (!strcmp(arg, "json"))
+        mode = YAZ_MARC_JSON;
     return mode;
 }