uint16_t json_object(char **in_buf, uint16_t len, char *name){ return put_json(in_buf, len, OBJ_BEGIN, name, 0, 0); }
uint16_t json_end(char **in_buf, uint16_t len){ return put_json(in_buf, len, END, NULL, 0, 0); }
void put_json_str (char *str, FILE *fp) { char c; int i = 0; while ((c = str[i++]) != '\0') put_json(c, fp); }
uint16_t json_start(char **in_buf, uint16_t len){ return put_json(in_buf, len, ROOT_BEGIN, NULL, 0, 0); }
int main (int argc, char *argv[]) { FILE *fpi = stdin, *fpo = stdout, *fpmap; struct mapper mapper; struct record record; struct map *map; struct field *field; struct buf *val_buf = buf_new(1024), *xml_buf = NULL; char *xml_key, *key_buf, prev_seq[9], seq[9], tag[4], ind1, ind2; int file_args = 0, array = 1, xml = 0, mapfile = 0, count = 0, first = 0, first_sub = 0, first_char, skip_sub = 0, c, i, j; tag[3] = '\0'; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--usage") || !strcmp(argv[i], "--help") || !strcmp(argv[i], "-?")) { usage(argv[0], 0); } else if (!strcmp(argv[i], "--newline")) { array = 0; } else if (!strcmp(argv[i], "--xml")) { xml = 1; } else if (!strcmp(argv[i], "--json")) { xml = 0; } else if (!strcmp(argv[i], "--xmlkey")) { if (++i == argc) usage(argv[0], 1); xml_key = argv[i]; xml_buf = buf_new(2048); } else if (!strcmp(argv[i], "--mapfile")) { if (++i == argc) usage(argv[0], 1); key_buf = malloc(256); if ((fpmap = fopen(argv[i], "r")) == NULL) { fprintf(stderr, "Can't open %s for reading\n", argv[i]); return 1; } if (!mapfile) { mapfile = 1; mapper.size = mapper.grow = 100; mapper.used = 0; mapper.maps = malloc(sizeof(struct map) * mapper.size); record.size = record.grow = 100; record.used = 0; record.fields = malloc(sizeof(struct field) * record.size); for (j = 0; j < record.size; j++) { record.fields[j].val = buf_new(1024); } } while ((c = getc(fpmap)) != EOF) { if (isspace(c)) continue; if (c == '#') { while (more(c = getc(fpmap))); continue; } map = mapper.maps + mapper.used; map->key = NULL; map->tag[0] = c; map->tag[1] = getc(fpmap); map->tag[2] = getc(fpmap); if (isspace(c = getc(fpmap))) { map->op = '\0'; } else { map->op = c; fscanf(fpmap, "%s", map->subfields); } fscanf(fpmap, "%s", key_buf); for (j = 0; j < mapper.used; j++) { if (!strcmp(mapper.maps[j].key, key_buf)) { map->key = mapper.maps[j].key; break; } } if (!map->key) { map->key = malloc(strlen(key_buf) + 1); strcpy(map->key, key_buf); } mapper.used++; if (mapper.used == mapper.size) { mapper.size += mapper.grow; mapper.maps = realloc(mapper.maps, sizeof(struct map) * mapper.size); } } free(key_buf); fclose(fpmap); } else { switch (++file_args) { case 1: if ((fpi = fopen(argv[i], "r")) == NULL) { fprintf(stderr, "Can't open %s for reading\n", argv[i]); return 1; } break; case 2: if ((fpo = fopen(argv[i], "w")) == NULL) { fprintf(stderr, "Can't open %s for writing\n", argv[i]); return 1; } break; } } } if (xml) { fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?><collection xmlns=\"http://www.loc.gov/MARC21/slim\">", fpo); } else if (array) { fputs("[", fpo); } while ((c = getc(fpi)) != EOF) { if (isspace(c)) continue; seq[0] = c; for (i = 1; i < 9; ++i) seq[i] = getc(fpi); getc(fpi); for (i = 0; i < 3; ++i) tag[i] = getc(fpi); ind1 = getc(fpi); ind2 = getc(fpi); for (i = 0; i < 3; ++i) getc(fpi); val_buf->used = 0; while (more(c = getc(fpi))) buf_add(val_buf, c); buf_add(val_buf, '\0'); if (!count || strncmp(seq, prev_seq, 9)) { if (count++) { if (xml_buf) { buf_add_str(xml_buf, "</record>"); buf_add(xml_buf, '\0'); } if (mapfile) { fputs("{", fpo); for (i = 0; i < record.used; i++) { field = record.fields + i; if (i) putc(',', fpo); buf_add(field->val, '\0'); fprintf(fpo, "\"%s\":[%s]", field->key, field->val->str); } if (xml_buf) { if (i) putc(',', fpo); fprintf(fpo, "\"%s\":\"", xml_key); put_json_str(xml_buf->str, fpo); putc('\"', fpo); } fputs(array ? "},\n" : "}\n", fpo); record.used = 0; } else if (xml) { fputs("</record>\n", fpo); } else { fputs(array ? "]},\n" : "]}\n", fpo); } if (xml_buf) { xml_buf->used = 0; } } } for (i = 0; i < 9; ++i) prev_seq[i] = seq[i]; if (mapfile) { for (i = 0; i < mapper.used; i++) { map = mapper.maps + i; if ((map->tag[0] == '*' || map->tag[0] == tag[0]) && (map->tag[1] == '*' || map->tag[1] == tag[1]) && (map->tag[2] == '*' || map->tag[2] == tag[2])) { field = NULL; for (j = 0; j < record.used; j++) { field = record.fields + j; if (field->key == map->key) { break; } field = NULL; } if (!field) { field = record.fields + record.used; field->key = map->key; field->val->used = 0; record.used++; } skip_sub = 0; first_char = 1; for (j = 0; j < val_buf->used-1; j++) { if (val_buf->str[j] == '$' && val_buf->str[j+1] == '$') { j+= 2; if ( (map->op == '+' && strchr(map->subfields, val_buf->str[j]) == NULL) || (map->op == '-' && strchr(map->subfields, val_buf->str[j]) != NULL) ) { skip_sub = 1; continue; } skip_sub = 0; j++; if (j == val_buf->used-1) break; } if (!skip_sub) { if (first_char) { if (field->val->used) buf_add(field->val, ','); buf_add(field->val, '"'); first_char = 0; } if (val_buf->str[j] == '"') buf_add(field->val, '\\'); if (val_buf->str[j] == '\\') buf_add(field->val, '\\'); buf_add(field->val, val_buf->str[j]); } } if (!first_char) buf_add(field->val, '"'); } } } if (!strncmp(tag, "FMT", 3)) continue; if (!strncmp(tag, "LDR", 3)) { if (xml_buf) { buf_add_str(xml_buf, "<record><leader>"); buf_add_str(xml_buf, val_buf->str); buf_add_str(xml_buf, "</leader>"); } else if (xml) { fprintf(fpo, "<record><leader>%s</leader>", val_buf->str); } else if (!mapfile) { fprintf(fpo, "{\"leader\":\"%s\",\"fields\":[", val_buf->str); } first = 1; continue; } if (first) { first = 0; } else if (!xml_buf && !xml && !mapfile) { putc(',', fpo); } if (tag[0] == '0' && tag[1] == '0') { if (xml_buf) { buf_add_str(xml_buf, "<controlfield tag=\""); for (i = 0; i < 3; i++) buf_add(xml_buf, tag[i]); buf_add_str(xml_buf, "\">"); buf_add_xml_str(xml_buf, val_buf->str); buf_add_str(xml_buf, "</controlfield>"); } else if (xml) { fprintf(fpo, "<controlfield tag=\"%3s\">", tag); for (i = 0; i < val_buf->used-1; i++) put_xml(val_buf->str[i], fpo); fputs("</controlfield>", fpo); } else if (!mapfile) { fprintf(fpo, "{\"%3s\":\"", tag); for (i = 0; i < val_buf->used-1; i++) put_json(val_buf->str[i], fpo); fputs("\"}", fpo); } } else { if (xml_buf) { buf_add_str(xml_buf, "<datafield tag=\""); for (i = 0; i < 3; i++) buf_add(xml_buf, tag[i]); buf_add_str(xml_buf, "\" ind1=\""); buf_add(xml_buf, ind1); buf_add_str(xml_buf, "\" ind2=\""); buf_add(xml_buf, ind2); buf_add_str(xml_buf, "\">"); } else if (xml) { fprintf(fpo, "<datafield tag=\"%3s\" ind1=\"%c\" ind2=\"%c\">", tag, ind1, ind2); } else if (!mapfile) { fprintf(fpo, "{\"%3s\":{\"ind1\":\"%c\",\"ind2\":\"%c\",\"subfields\":[", tag, ind1, ind2); } first_sub = 1; for (i = 0; i < val_buf->used-1; i++) { if (val_buf->str[i] == '$' && val_buf->str[i+1] == '$') { i+= 2; if (first_sub) { first_sub = 0; } else { if (xml_buf) { buf_add_str(xml_buf, "</subfield>"); } else if (xml) { fputs("</subfield>", fpo); } else if (!mapfile) { fputs("\"},", fpo); } } if (xml_buf) { buf_add_str(xml_buf, "<subfield code=\""); buf_add(xml_buf, val_buf->str[i]); buf_add_str(xml_buf, "\">"); } else if (xml) { fprintf(fpo, "<subfield code=\"%c\">", val_buf->str[i]); } else if (!mapfile) { fprintf(fpo, "{\"%c\":\"", val_buf->str[i]); } continue; } if (xml_buf) { buf_add_xml(xml_buf, val_buf->str[i]); } else if (xml) { put_xml(val_buf->str[i], fpo); } else if (!mapfile) { put_json(val_buf->str[i], fpo); } } if (!first_sub) { if (xml_buf) { buf_add_str(xml_buf, "</subfield>"); } else if (xml) { fputs("</subfield>", fpo); } else if (!mapfile) { fputs("\"}", fpo); } } if (xml_buf) { buf_add_str(xml_buf, "</datafield>"); } else if (xml) { fputs("</datafield>", fpo); } else if (!mapfile) { fputs("]", fpo); } } } if (count && mapfile) { fputs("{", fpo); for (i = 0; i < record.used; i++) { field = record.fields + i; if (i) putc(',', fpo); buf_add(field->val, '\0'); fprintf(fpo, "\"%s\":[%s]", field->key, field->val->str); } if (xml_buf) { if (i) putc(',', fpo); fprintf(fpo, "\"%s\":\"", xml_key); put_json_str(xml_buf->str, fpo); putc('\"', fpo); } } if (xml) { if (count) fputs("</record>", fpo); fputs("</collection>", fpo); } else { if (count) fputs("}", fpo); if (array) fputs("]", fpo); } fclose(fpi); fclose(fpo); return 0; }