1 /* This file is part of the Zebra server.
2 Copyright (C) 2004-2013 Index Data
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 \brief indexes records and extract tokens for indexing and sorting
43 #include <yaz/snprintf.h>
45 static int log_level_extract = 0;
46 static int log_level_details = 0;
47 static int log_level_initialized = 0;
49 /* 1 if we use eliminitate identical delete/insert keys */
50 /* eventually this the 0-case code will be removed */
54 static void extract_flush_record_keys2(ZebraHandle zh, zint sysno,
55 zebra_rec_keys_t ins_keys,
57 zebra_rec_keys_t del_keys,
60 static void extract_flush_record_keys(ZebraHandle zh, zint sysno,
62 zebra_rec_keys_t reckeys,
66 static void zebra_init_log_level(void)
68 if (!log_level_initialized)
70 log_level_initialized = 1;
72 log_level_extract = yaz_log_module_level("extract");
73 log_level_details = yaz_log_module_level("indexdetails");
77 static WRBUF wrbuf_hex_str(const char *cstr)
80 WRBUF w = wrbuf_alloc();
81 for (i = 0; cstr[i]; i++)
83 if (cstr[i] < ' ' || cstr[i] > 126)
84 wrbuf_printf(w, "\\%02X", cstr[i] & 0xff);
86 wrbuf_putc(w, cstr[i]);
92 static void extract_flush_sort_keys(ZebraHandle zh, zint sysno,
93 int cmd, zebra_rec_keys_t skp);
94 static void extract_schema_add(struct recExtractCtrl *p, Odr_oid *oid);
95 static void extract_token_add(RecWord *p);
97 static void check_log_limit(ZebraHandle zh)
99 if (zh->records_processed + zh->records_skipped == zh->m_file_verbose_limit)
101 yaz_log(YLOG_LOG, "More than %d file log entries. Omitting rest",
102 zh->m_file_verbose_limit);
106 static void logRecord(ZebraHandle zh)
109 ++zh->records_processed;
110 if (!(zh->records_processed % 1000))
112 yaz_log(YLOG_LOG, "Records: "ZINT_FORMAT" i/u/d "
113 ZINT_FORMAT"/"ZINT_FORMAT"/"ZINT_FORMAT,
114 zh->records_processed, zh->records_inserted,
115 zh->records_updated, zh->records_deleted);
119 static void init_extractCtrl(ZebraHandle zh, struct recExtractCtrl *ctrl)
121 ctrl->flagShowRecords = !zh->m_flag_rw;
125 static void extract_add_index_string(RecWord *p,
126 zinfo_index_category_t cat,
127 const char *str, int length);
129 static void extract_set_store_data_prepare(struct recExtractCtrl *p);
131 static void extract_init(struct recExtractCtrl *p, RecWord *w)
134 w->index_name = "any";
142 struct snip_rec_info {
144 zebra_snippets *snippets;
147 static int parse_complete_field(RecWord *p, zebra_map_t zm,
150 const char *b = p->term_buf;
151 const char **map = 0;
152 int i = 0, remain = p->term_len;
155 map = zebra_maps_input(zm, &b, remain, 1);
156 while (remain > 0 && i < IT_MAX_WORD)
158 while (map && *map && **map == *CHR_SPACE)
160 remain = p->term_len - (b - p->term_buf);
164 int first = i ? 0 : 1; /* first position */
165 map = zebra_maps_input(zm, &b, remain, first);
173 if (i && i < IT_MAX_WORD)
174 buf[i++] = *CHR_SPACE;
175 while (map && *map && **map != *CHR_SPACE)
177 const char *cp = *map;
179 if (**map == *CHR_CUT)
185 if (i >= IT_MAX_WORD)
187 while (i < IT_MAX_WORD && *cp)
190 remain = p->term_len - (b - p->term_buf);
193 map = zebra_maps_input(zm, &b, remain, 0);
202 static void snippet_add_complete_field(RecWord *p, int ord,
205 struct snip_rec_info *h = p->extractCtrl->handle;
206 char buf[IT_MAX_WORD+1];
207 int i = parse_complete_field(p, zm, buf);
212 if (p->term_len && p->term_buf && zebra_maps_is_index(zm))
213 zebra_snippets_appendn(h->snippets, p->seqno, 0, ord,
214 p->term_buf, p->term_len);
218 static void snippet_add_incomplete_field(RecWord *p, int ord, zebra_map_t zm)
220 struct snip_rec_info *h = p->extractCtrl->handle;
221 const char *b = p->term_buf;
222 int remain = p->term_len;
224 const char **map = 0;
225 const char *start = b;
226 const char *last = b;
229 map = zebra_maps_input(zm, &b, remain, 0);
236 while (map && *map && **map == *CHR_SPACE)
238 remain = p->term_len - (b - p->term_buf);
241 map = zebra_maps_input(zm, &b, remain, 0);
247 if (start != last && zebra_maps_is_index(zm))
249 zebra_snippets_appendn(h->snippets, p->seqno, 1, ord,
250 start, last - start);
253 while (map && *map && **map != *CHR_SPACE)
255 remain = p->term_len - (b - p->term_buf);
258 map = zebra_maps_input(zm, &b, remain, 0);
268 if (zebra_maps_is_first_in_field(zm))
270 /* first in field marker */
274 if (start != last && zebra_maps_is_index(zm))
275 zebra_snippets_appendn(h->snippets, p->seqno, 0, ord,
276 start, last - start);
283 static void snippet_add_icu(RecWord *p, int ord, zebra_map_t zm)
285 struct snip_rec_info *h = p->extractCtrl->handle;
287 const char *res_buf = 0;
290 const char *display_buf = 0;
291 size_t display_len = 0;
293 zebra_map_tokenize_start(zm, p->term_buf, p->term_len);
294 while (zebra_map_tokenize_next(zm, &res_buf, &res_len,
295 &display_buf, &display_len))
297 if (zebra_maps_is_index(zm))
298 zebra_snippets_appendn(h->snippets, p->seqno, 0, ord,
299 display_buf, display_len);
304 static void snippet_token_add(RecWord *p)
306 struct snip_rec_info *h = p->extractCtrl->handle;
307 ZebraHandle zh = h->zh;
308 zebra_map_t zm = zebra_map_get_or_add(zh->reg->zebra_maps, p->index_type);
312 ZebraExplainInfo zei = zh->reg->zei;
313 int ch = zebraExplain_lookup_attr_str(
314 zei, zinfo_index_category_index, p->index_type, p->index_name);
316 if (zebra_maps_is_icu(zm))
317 snippet_add_icu(p, ch, zm);
320 if (zebra_maps_is_complete(zm))
321 snippet_add_complete_field(p, ch, zm);
323 snippet_add_incomplete_field(p, ch, zm);
328 static void snippet_schema_add(
329 struct recExtractCtrl *p, Odr_oid *oid)
334 void extract_snippet(ZebraHandle zh, zebra_snippets *sn,
335 struct ZebraRecStream *stream,
336 RecType rt, void *recTypeClientData)
338 struct recExtractCtrl extractCtrl;
339 struct snip_rec_info info;
341 extractCtrl.stream = stream;
342 extractCtrl.first_record = 1;
343 extractCtrl.init = extract_init;
344 extractCtrl.tokenAdd = snippet_token_add;
345 extractCtrl.schemaAdd = snippet_schema_add;
349 extractCtrl.dh = zh->reg->dh;
353 extractCtrl.handle = &info;
354 extractCtrl.match_criteria[0] = '\0';
355 extractCtrl.staticrank = 0;
356 extractCtrl.action = action_insert;
358 init_extractCtrl(zh, &extractCtrl);
360 extractCtrl.setStoreData = 0;
362 (*rt->extract)(recTypeClientData, &extractCtrl);
365 static void searchRecordKey(ZebraHandle zh,
366 zebra_rec_keys_t reckeys,
367 const char *index_name,
368 const char **ws, int ws_length)
372 zinfo_index_category_t cat = zinfo_index_category_index;
374 for (i = 0; i<ws_length; i++)
378 ch = zebraExplain_lookup_attr_str(zh->reg->zei, cat, "0", index_name);
380 ch = zebraExplain_lookup_attr_str(zh->reg->zei, cat, "p", index_name);
382 ch = zebraExplain_lookup_attr_str(zh->reg->zei, cat, "w", index_name);
387 if (zebra_rec_keys_rewind(reckeys))
394 while (zebra_rec_keys_read(reckeys, &str, &slen, &key))
396 assert(key.len <= IT_KEY_LEVEL_MAX && key.len > 2);
398 seqno = key.mem[key.len-1];
400 if (key.mem[0] == ch)
406 woff = seqno - startSeq;
407 if (woff >= 0 && woff < ws_length)
414 #define FILE_MATCH_BLANK "\t "
416 static char *get_match_from_spec(ZebraHandle zh,
417 zebra_rec_keys_t reckeys,
418 const char *fname, const char *spec)
420 static char dstBuf[2048]; /* static here ??? */
422 const char *s = spec;
426 for (; *s && strchr(FILE_MATCH_BLANK, *s); s++)
433 char attset_str[64], attname_str[64];
437 for (s++; strchr(FILE_MATCH_BLANK, *s); s++)
439 for (i = 0; *s && *s != ',' && *s != ')' &&
440 !strchr(FILE_MATCH_BLANK, *s); s++)
441 if (i+1 < sizeof(attset_str))
442 attset_str[i++] = *s;
443 attset_str[i] = '\0';
445 for (; strchr(FILE_MATCH_BLANK, *s); s++)
448 strcpy(attname_str, attset_str);
451 for (s++; strchr(FILE_MATCH_BLANK, *s); s++)
453 for (i = 0; *s && *s != ')' &&
454 !strchr(FILE_MATCH_BLANK, *s); s++)
455 if (i+1 < sizeof(attname_str))
456 attname_str[i++] = *s;
457 attname_str[i] = '\0';
461 yaz_log(YLOG_WARN, "Missing ) in match criteria %s in group %s",
462 spec, zh->m_group ? zh->m_group : "none");
467 searchRecordKey(zh, reckeys, attname_str, ws, 32);
468 if (0) /* for debugging */
470 for (i = 0; i<32; i++)
474 WRBUF w = wrbuf_hex_str(ws[i]);
475 yaz_log(YLOG_LOG, "ws[%d] = %s", i, wrbuf_cstr(w));
481 for (i = 0; i<32; i++)
490 dst += strlen(ws[i]);
494 yaz_log(YLOG_WARN, "Record didn't contain match"
495 " fields in (%s,%s)", attset_str, attname_str);
503 const char *spec_src = NULL;
504 const char *s1 = ++s;
505 while (*s1 && !strchr(FILE_MATCH_BLANK, *s1))
509 if (spec_len > sizeof(special)-1)
510 spec_len = sizeof(special)-1;
511 memcpy(special, s, spec_len);
512 special[spec_len] = '\0';
515 if (!strcmp(special, "group"))
516 spec_src = zh->m_group;
517 else if (!strcmp(special, "database"))
518 spec_src = zh->basenames[0];
519 else if (!strcmp(special, "filename")) {
522 else if (!strcmp(special, "type"))
523 spec_src = zh->m_record_type;
528 strcpy(dst, spec_src);
529 dst += strlen(spec_src);
532 else if (*s == '\"' || *s == '\'')
534 int stopMarker = *s++;
538 while (*s && *s != stopMarker)
540 if (i+1 < sizeof(tmpString))
541 tmpString[i++] = *s++;
546 strcpy(dst, tmpString);
547 dst += strlen(tmpString);
551 yaz_log(YLOG_WARN, "Syntax error in match criteria %s in group %s",
552 spec, zh->m_group ? zh->m_group : "none");
559 yaz_log(YLOG_WARN, "No match criteria for record %s in group %s",
560 fname, zh->m_group ? zh->m_group : "none");
565 if (0) /* for debugging */
567 WRBUF w = wrbuf_hex_str(dstBuf);
568 yaz_log(YLOG_LOG, "get_match_from_spec %s", wrbuf_cstr(w));
575 struct recordLogInfo {
578 struct recordGroup *rGroup;
581 /** \brief add the always-matches index entry and map to real record ID
582 \param ctrl record control
583 \param record_id custom record ID
584 \param sysno system record ID
586 This function serves two purposes.. It adds the always matches
587 entry and makes a pointer from the custom record ID (if defined)
588 back to the system record ID (sysno)
589 See zebra_recid_to_sysno .
591 static void all_matches_add(struct recExtractCtrl *ctrl, zint record_id,
595 extract_init(ctrl, &word);
596 word.record_id = record_id;
597 /* we use the seqno as placeholder for a way to get back to
598 record database from _ALLRECORDS.. This is used if a custom
599 RECORD was defined */
601 word.index_name = "_ALLRECORDS";
602 word.index_type = "w";
604 extract_add_index_string(&word, zinfo_index_category_alwaysmatches,
608 /* forward declaration */
609 ZEBRA_RES zebra_extract_records_stream(ZebraHandle zh,
610 struct ZebraRecStream *stream,
611 enum zebra_recctrl_action_t action,
612 const char *recordType,
614 const char *match_criteria,
617 void *recTypeClientData);
620 ZEBRA_RES zebra_extract_file(ZebraHandle zh, zint *sysno, const char *fname,
621 enum zebra_recctrl_action_t action)
623 ZEBRA_RES r = ZEBRA_OK;
628 const char *original_record_type = 0;
630 void *recTypeClientData;
631 struct ZebraRecStream stream, *streamp;
633 zebra_init_log_level();
635 if (!zh->m_group || !*zh->m_group)
638 sprintf(gprefix, "%s.", zh->m_group);
640 yaz_log(log_level_extract, "zebra_extract_file %s", fname);
642 /* determine file extension */
644 for (i = strlen(fname); --i >= 0; )
647 else if (fname[i] == '.')
649 strcpy(ext, fname+i+1);
652 /* determine file type - depending on extension */
653 original_record_type = zh->m_record_type;
654 if (!zh->m_record_type)
656 sprintf(ext_res, "%srecordType.%s", gprefix, ext);
657 zh->m_record_type = res_get(zh->res, ext_res);
659 if (!zh->m_record_type)
662 if (zh->records_processed + zh->records_skipped
663 < zh->m_file_verbose_limit)
664 yaz_log(YLOG_LOG, "? %s", fname);
665 zh->records_skipped++;
668 /* determine match criteria */
669 if (!zh->m_record_id)
671 sprintf(ext_res, "%srecordId.%s", gprefix, ext);
672 zh->m_record_id = res_get(zh->res, ext_res);
676 recType_byName(zh->reg->recTypes, zh->res, zh->m_record_type,
677 &recTypeClientData)))
679 yaz_log(YLOG_WARN, "No such record type: %s", zh->m_record_type);
683 switch(recType->version)
688 yaz_log(YLOG_WARN, "Bad filter version: %s", zh->m_record_type);
690 if (sysno && (action == action_delete || action == action_a_delete))
698 if (zh->path_reg && !yaz_is_abspath(fname))
700 strcpy(full_rep, zh->path_reg);
701 strcat(full_rep, "/");
702 strcat(full_rep, fname);
705 strcpy(full_rep, fname);
707 if ((fd = open(full_rep, O_BINARY|O_RDONLY)) == -1)
709 yaz_log(YLOG_WARN|YLOG_ERRNO, "open %s", full_rep);
710 zh->m_record_type = original_record_type;
714 zebra_create_stream_fd(streamp, fd, 0);
716 r = zebra_extract_records_stream(zh, streamp,
720 0, /*match_criteria */
722 recType, recTypeClientData);
724 stream.destroy(streamp);
725 zh->m_record_type = original_record_type;
730 If sysno is provided, then it's used to identify the reocord.
731 If not, and match_criteria is provided, then sysno is guessed
732 If not, and a record is provided, then sysno is got from there
736 ZEBRA_RES zebra_buffer_extract_record(ZebraHandle zh,
737 const char *buf, size_t buf_size,
738 enum zebra_recctrl_action_t action,
739 const char *recordType,
741 const char *match_criteria,
744 struct ZebraRecStream stream;
749 if (recordType && *recordType)
751 yaz_log(log_level_extract,
752 "Record type explicitly specified: %s", recordType);
753 recType = recType_byName(zh->reg->recTypes, zh->res, recordType,
758 if (!(zh->m_record_type))
760 yaz_log(YLOG_WARN, "No such record type defined");
763 yaz_log(log_level_extract, "Get record type from rgroup: %s",
765 recType = recType_byName(zh->reg->recTypes, zh->res,
766 zh->m_record_type, &clientData);
767 recordType = zh->m_record_type;
772 yaz_log(YLOG_WARN, "No such record type: %s", recordType);
776 zebra_create_stream_mem(&stream, buf, buf_size);
778 res = zebra_extract_records_stream(zh, &stream,
784 recType, clientData);
785 stream.destroy(&stream);
789 static ZEBRA_RES zebra_extract_record_stream(ZebraHandle zh,
790 struct ZebraRecStream *stream,
791 enum zebra_recctrl_action_t action,
792 const char *recordType,
794 const char *match_criteria,
797 void *recTypeClientData,
802 RecordAttr *recordAttr;
803 struct recExtractCtrl extractCtrl;
805 const char *matchStr = 0;
807 off_t start_offset = 0, end_offset = 0;
808 const char *pr_fname = fname; /* filename to print .. */
809 int show_progress = zh->records_processed + zh->records_skipped
810 < zh->m_file_verbose_limit ? 1:0;
812 zebra_init_log_level();
815 pr_fname = "<no file>"; /* make it printable if file is omitted */
817 zebra_rec_keys_reset(zh->reg->keys);
818 zebra_rec_keys_reset(zh->reg->sortKeys);
820 if (zebraExplain_curDatabase(zh->reg->zei, zh->basenames[0]))
822 if (zebraExplain_newDatabase(zh->reg->zei, zh->basenames[0],
823 zh->m_explain_database))
829 off_t null_offset = 0;
830 extractCtrl.stream = stream;
832 start_offset = stream->tellf(stream);
834 extractCtrl.first_record = start_offset ? 0 : 1;
836 stream->endf(stream, &null_offset);;
838 extractCtrl.init = extract_init;
839 extractCtrl.tokenAdd = extract_token_add;
840 extractCtrl.schemaAdd = extract_schema_add;
841 extractCtrl.dh = zh->reg->dh;
842 extractCtrl.handle = zh;
843 extractCtrl.match_criteria[0] = '\0';
844 extractCtrl.staticrank = 0;
845 extractCtrl.action = action;
847 init_extractCtrl(zh, &extractCtrl);
849 extract_set_store_data_prepare(&extractCtrl);
851 r = (*recType->extract)(recTypeClientData, &extractCtrl);
853 if (action == action_update)
855 action = extractCtrl.action;
860 case RECCTRL_EXTRACT_EOF:
862 case RECCTRL_EXTRACT_ERROR_GENERIC:
863 /* error occured during extraction ... */
864 yaz_log(YLOG_WARN, "extract error: generic");
866 case RECCTRL_EXTRACT_ERROR_NO_SUCH_FILTER:
867 /* error occured during extraction ... */
868 yaz_log(YLOG_WARN, "extract error: no such filter");
870 case RECCTRL_EXTRACT_SKIP:
872 yaz_log(YLOG_LOG, "skip %s %s " ZINT_FORMAT,
873 recordType, pr_fname, (zint) start_offset);
876 end_offset = stream->endf(stream, 0);
878 stream->seekf(stream, end_offset);
881 case RECCTRL_EXTRACT_OK:
884 yaz_log(YLOG_WARN, "extract error: unknown error: %d", r);
887 end_offset = stream->endf(stream, 0);
889 stream->seekf(stream, end_offset);
891 end_offset = stream->tellf(stream);
893 if (extractCtrl.match_criteria[0])
894 match_criteria = extractCtrl.match_criteria;
899 if (zh->m_flag_rw == 0)
901 yaz_log(YLOG_LOG, "test %s %s " ZINT_FORMAT, recordType,
902 pr_fname, (zint) start_offset);
903 /* test mode .. Do not perform match */
911 if (match_criteria && *match_criteria)
912 matchStr = match_criteria;
915 if (zh->m_record_id && *zh->m_record_id)
917 matchStr = get_match_from_spec(zh, zh->reg->keys, pr_fname,
921 yaz_log(YLOG_LOG, "error %s %s " ZINT_FORMAT, recordType,
922 pr_fname, (zint) start_offset);
927 WRBUF w = wrbuf_alloc();
929 for (i = 0; i < strlen(matchStr); i++)
931 wrbuf_printf(w, "%02X", matchStr[i] & 0xff);
933 yaz_log(YLOG_LOG, "Got match %s", wrbuf_cstr(w));
940 int db_ord = zebraExplain_get_database_ord(zh->reg->zei);
941 char *rinfo = dict_lookup_ord(zh->reg->matchDict, db_ord,
945 if (log_level_extract)
947 WRBUF w = wrbuf_hex_str(matchStr);
948 yaz_log(log_level_extract, "matchStr: %s", wrbuf_cstr(w));
953 assert(*rinfo == sizeof(*sysno));
954 memcpy(sysno, rinfo+1, sizeof(*sysno));
961 /* new record AKA does not exist already */
962 if (action == action_delete)
964 yaz_log(YLOG_LOG, "delete %s %s " ZINT_FORMAT, recordType,
965 pr_fname, (zint) start_offset);
966 yaz_log(YLOG_WARN, "cannot delete record above (seems new)");
969 else if (action == action_a_delete)
972 yaz_log(YLOG_LOG, "adelete %s %s " ZINT_FORMAT, recordType,
973 pr_fname, (zint) start_offset);
976 else if (action == action_replace)
978 yaz_log(YLOG_LOG, "update %s %s " ZINT_FORMAT, recordType,
979 pr_fname, (zint) start_offset);
980 yaz_log(YLOG_WARN, "cannot update record above (seems new)");
984 yaz_log(YLOG_LOG, "add %s %s " ZINT_FORMAT, recordType, pr_fname,
985 (zint) start_offset);
986 rec = rec_new(zh->reg->records);
993 all_matches_add(&extractCtrl,
994 zebra_rec_keys_get_custom_record_id(zh->reg->keys),
999 recordAttr = rec_init_attr(zh->reg->zei, rec);
1000 if (extractCtrl.staticrank < 0)
1002 yaz_log(YLOG_WARN, "Negative staticrank for record. Set to 0");
1003 extractCtrl.staticrank = 0;
1008 int db_ord = zebraExplain_get_database_ord(zh->reg->zei);
1009 dict_insert_ord(zh->reg->matchDict, db_ord, matchStr,
1010 sizeof(*sysno), sysno);
1013 extract_flush_sort_keys(zh, *sysno, 1, zh->reg->sortKeys);
1015 extract_flush_record_keys2(zh, *sysno,
1016 zh->reg->keys, extractCtrl.staticrank,
1017 0, recordAttr->staticrank);
1019 extract_flush_record_keys(zh, *sysno, 1, zh->reg->keys,
1020 extractCtrl.staticrank);
1022 recordAttr->staticrank = extractCtrl.staticrank;
1023 zh->records_inserted++;
1027 /* record already exists */
1028 zebra_rec_keys_t delkeys = zebra_rec_keys_open();
1029 zebra_rec_keys_t sortKeys = zebra_rec_keys_open();
1030 if (action == action_insert)
1032 yaz_log(YLOG_LOG, "skipped %s %s " ZINT_FORMAT,
1033 recordType, pr_fname, (zint) start_offset);
1038 rec = rec_get(zh->reg->records, *sysno);
1043 all_matches_add(&extractCtrl,
1044 zebra_rec_keys_get_custom_record_id(zh->reg->keys),
1048 recordAttr = rec_init_attr(zh->reg->zei, rec);
1050 /* decrease total size */
1051 zebraExplain_recordBytesIncrement(zh->reg->zei,
1052 - recordAttr->recordSize);
1054 zebra_rec_keys_set_buf(delkeys,
1055 rec->info[recInfo_delKeys],
1056 rec->size[recInfo_delKeys],
1058 zebra_rec_keys_set_buf(sortKeys,
1059 rec->info[recInfo_sortKeys],
1060 rec->size[recInfo_sortKeys],
1063 extract_flush_sort_keys(zh, *sysno, 0, sortKeys);
1065 extract_flush_record_keys(zh, *sysno, 0, delkeys,
1066 recordAttr->staticrank);
1068 if (action == action_delete || action == action_a_delete)
1070 /* record going to be deleted */
1072 extract_flush_record_keys2(zh, *sysno, 0, recordAttr->staticrank,
1073 delkeys, recordAttr->staticrank);
1075 if (zebra_rec_keys_empty(delkeys))
1077 yaz_log(YLOG_LOG, "delete %s %s " ZINT_FORMAT, recordType,
1078 pr_fname, (zint) start_offset);
1079 yaz_log(YLOG_WARN, "cannot delete file above, "
1080 "storeKeys false (3)");
1085 yaz_log(YLOG_LOG, "delete %s %s " ZINT_FORMAT, recordType,
1086 pr_fname, (zint) start_offset);
1087 zh->records_deleted++;
1090 int db_ord = zebraExplain_get_database_ord(zh->reg->zei);
1091 dict_delete_ord(zh->reg->matchDict, db_ord, matchStr);
1093 rec_del(zh->reg->records, &rec);
1095 zebra_rec_keys_close(delkeys);
1096 zebra_rec_keys_close(sortKeys);
1102 { /* update or special_update */
1104 yaz_log(YLOG_LOG, "update %s %s " ZINT_FORMAT, recordType,
1105 pr_fname, (zint) start_offset);
1106 extract_flush_sort_keys(zh, *sysno, 1, zh->reg->sortKeys);
1109 extract_flush_record_keys2(zh, *sysno,
1110 zh->reg->keys, extractCtrl.staticrank,
1111 delkeys, recordAttr->staticrank);
1113 extract_flush_record_keys(zh, *sysno, 1,
1114 zh->reg->keys, extractCtrl.staticrank);
1116 recordAttr->staticrank = extractCtrl.staticrank;
1117 zh->records_updated++;
1119 zebra_rec_keys_close(delkeys);
1120 zebra_rec_keys_close(sortKeys);
1122 /* update file type */
1123 xfree(rec->info[recInfo_fileType]);
1124 rec->info[recInfo_fileType] =
1125 rec_strdup(recordType, &rec->size[recInfo_fileType]);
1127 /* update filename */
1128 xfree(rec->info[recInfo_filename]);
1129 rec->info[recInfo_filename] =
1130 rec_strdup(fname, &rec->size[recInfo_filename]);
1132 /* update delete keys */
1133 xfree(rec->info[recInfo_delKeys]);
1134 if (!zebra_rec_keys_empty(zh->reg->keys) && zh->m_store_keys == 1)
1136 zebra_rec_keys_get_buf(zh->reg->keys,
1137 &rec->info[recInfo_delKeys],
1138 &rec->size[recInfo_delKeys]);
1142 rec->info[recInfo_delKeys] = NULL;
1143 rec->size[recInfo_delKeys] = 0;
1145 /* update sort keys */
1146 xfree(rec->info[recInfo_sortKeys]);
1148 zebra_rec_keys_get_buf(zh->reg->sortKeys,
1149 &rec->info[recInfo_sortKeys],
1150 &rec->size[recInfo_sortKeys]);
1154 recordAttr->recordSize = end_offset - start_offset;
1155 zebraExplain_recordBytesIncrement(zh->reg->zei,
1156 recordAttr->recordSize);
1159 /* set run-number for this record */
1160 recordAttr->runNumber =
1161 zebraExplain_runNumberIncrement(zh->reg->zei, 0);
1163 /* update store data */
1164 xfree(rec->info[recInfo_storeData]);
1166 /* update store data */
1167 if (zh->store_data_buf)
1169 rec->size[recInfo_storeData] = zh->store_data_size;
1170 rec->info[recInfo_storeData] = zh->store_data_buf;
1171 zh->store_data_buf = 0;
1172 recordAttr->recordSize = zh->store_data_size;
1174 else if (zh->m_store_data)
1176 off_t cur_offset = stream->tellf(stream);
1178 rec->size[recInfo_storeData] = recordAttr->recordSize;
1179 rec->info[recInfo_storeData] = (char *)
1180 xmalloc(recordAttr->recordSize);
1181 stream->seekf(stream, start_offset);
1182 stream->readf(stream, rec->info[recInfo_storeData],
1183 recordAttr->recordSize);
1184 stream->seekf(stream, cur_offset);
1188 rec->info[recInfo_storeData] = NULL;
1189 rec->size[recInfo_storeData] = 0;
1191 /* update database name */
1192 xfree(rec->info[recInfo_databaseName]);
1193 rec->info[recInfo_databaseName] =
1194 rec_strdup(zh->basenames[0], &rec->size[recInfo_databaseName]);
1197 recordAttr->recordOffset = start_offset;
1199 /* commit this record */
1200 rec_put(zh->reg->records, &rec);
1205 /** \brief extracts records from stream
1206 \param zh Zebra Handle
1207 \param stream stream that we read from
1208 \param action (action_insert, action_replace, action_delete, ..)
1209 \param recordType Record filter type "grs.xml", etc.
1210 \param sysno pointer to sysno if already known; NULL otherwise
1211 \param match_criteria (NULL if not already given)
1212 \param fname filename that we read from (for logging purposes only)
1213 \param recType record type
1214 \param recTypeClientData client data for record type
1215 \returns ZEBRA_OK for success; ZEBRA_FAIL for failure
1217 ZEBRA_RES zebra_extract_records_stream(ZebraHandle zh,
1218 struct ZebraRecStream *stream,
1219 enum zebra_recctrl_action_t action,
1220 const char *recordType,
1222 const char *match_criteria,
1225 void *recTypeClientData)
1227 ZEBRA_RES res = ZEBRA_OK;
1231 res = zebra_extract_record_stream(zh, stream,
1237 recType, recTypeClientData, &more);
1243 if (res != ZEBRA_OK)
1251 ZEBRA_RES zebra_extract_explain(void *handle, Record rec, data1_node *n)
1253 ZebraHandle zh = (ZebraHandle) handle;
1254 struct recExtractCtrl extractCtrl;
1256 if (zebraExplain_curDatabase(zh->reg->zei,
1257 rec->info[recInfo_databaseName]))
1260 if (zebraExplain_newDatabase(zh->reg->zei,
1261 rec->info[recInfo_databaseName], 0))
1265 zebra_rec_keys_reset(zh->reg->keys);
1266 zebra_rec_keys_reset(zh->reg->sortKeys);
1268 extractCtrl.init = extract_init;
1269 extractCtrl.tokenAdd = extract_token_add;
1270 extractCtrl.schemaAdd = extract_schema_add;
1271 extractCtrl.dh = zh->reg->dh;
1273 init_extractCtrl(zh, &extractCtrl);
1275 extractCtrl.flagShowRecords = 0;
1276 extractCtrl.match_criteria[0] = '\0';
1277 extractCtrl.staticrank = 0;
1278 extractCtrl.action = action_update;
1280 extractCtrl.handle = handle;
1281 extractCtrl.first_record = 1;
1283 extract_set_store_data_prepare(&extractCtrl);
1286 grs_extract_tree(&extractCtrl, n);
1288 if (rec->size[recInfo_delKeys])
1290 zebra_rec_keys_t delkeys = zebra_rec_keys_open();
1292 zebra_rec_keys_t sortkeys = zebra_rec_keys_open();
1294 zebra_rec_keys_set_buf(delkeys, rec->info[recInfo_delKeys],
1295 rec->size[recInfo_delKeys],
1298 extract_flush_record_keys2(zh, rec->sysno,
1299 zh->reg->keys, 0, delkeys, 0);
1301 extract_flush_record_keys(zh, rec->sysno, 0, delkeys, 0);
1302 extract_flush_record_keys(zh, rec->sysno, 1, zh->reg->keys, 0);
1304 zebra_rec_keys_close(delkeys);
1306 zebra_rec_keys_set_buf(sortkeys, rec->info[recInfo_sortKeys],
1307 rec->size[recInfo_sortKeys],
1310 extract_flush_sort_keys(zh, rec->sysno, 0, sortkeys);
1311 zebra_rec_keys_close(sortkeys);
1316 extract_flush_record_keys2(zh, rec->sysno, zh->reg->keys, 0, 0, 0);
1318 extract_flush_record_keys(zh, rec->sysno, 1, zh->reg->keys, 0);
1321 extract_flush_sort_keys(zh, rec->sysno, 1, zh->reg->sortKeys);
1323 xfree(rec->info[recInfo_delKeys]);
1324 zebra_rec_keys_get_buf(zh->reg->keys,
1325 &rec->info[recInfo_delKeys],
1326 &rec->size[recInfo_delKeys]);
1328 xfree(rec->info[recInfo_sortKeys]);
1329 zebra_rec_keys_get_buf(zh->reg->sortKeys,
1330 &rec->info[recInfo_sortKeys],
1331 &rec->size[recInfo_sortKeys]);
1335 void zebra_it_key_str_dump(ZebraHandle zh, struct it_key *key,
1336 const char *str, size_t slen, NMEM nmem, int level)
1338 char keystr[200]; /* room for zints to print */
1339 int ord = CAST_ZINT_TO_INT(key->mem[0]);
1340 const char *index_type;
1342 const char *string_index;
1344 zebraExplain_lookup_ord(zh->reg->zei, ord, &index_type,
1345 0/* db */, &string_index);
1348 for (i = 0; i < key->len; i++)
1350 sprintf(keystr + strlen(keystr), ZINT_FORMAT " ", key->mem[i]);
1353 if (*str < CHR_BASE_CHAR)
1356 char dst_buf[200]; /* room for special chars */
1358 strcpy(dst_buf , "?");
1360 if (!strcmp(str, ""))
1361 strcpy(dst_buf, "alwaysmatches");
1362 if (!strcmp(str, FIRST_IN_FIELD_STR))
1363 strcpy(dst_buf, "firstinfield");
1364 else if (!strcmp(str, CHR_UNKNOWN))
1365 strcpy(dst_buf, "unknown");
1366 else if (!strcmp(str, CHR_SPACE))
1367 strcpy(dst_buf, "space");
1369 for (i = 0; i<slen; i++)
1371 sprintf(dst_buf + strlen(dst_buf), " %d", str[i] & 0xff);
1373 yaz_log(level, "%s%s %s %s", keystr, index_type,
1374 string_index, dst_buf);
1379 zebra_term_untrans_iconv(zh, nmem, index_type, &dst_term, str);
1381 yaz_log(level, "%s%s %s \"%s\"", keystr, index_type,
1382 string_index, dst_term);
1385 WRBUF w = wrbuf_alloc();
1386 wrbuf_write_escaped(w, str, strlen(str));
1387 yaz_log(level, "%s%s %s %s", keystr, index_type,
1388 string_index, wrbuf_cstr(w));
1394 void extract_rec_keys_log(ZebraHandle zh, int is_insert,
1395 zebra_rec_keys_t reckeys,
1398 if (zebra_rec_keys_rewind(reckeys))
1403 NMEM nmem = nmem_create();
1405 while(zebra_rec_keys_read(reckeys, &str, &slen, &key))
1407 zebra_it_key_str_dump(zh, &key, str, slen, nmem, level);
1414 void extract_rec_keys_adjust(ZebraHandle zh, int is_insert,
1415 zebra_rec_keys_t reckeys)
1417 ZebraExplainInfo zei = zh->reg->zei;
1421 struct ord_stat *next;
1424 if (zebra_rec_keys_rewind(reckeys))
1426 struct ord_stat *ord_list = 0;
1430 struct it_key key_in;
1431 while(zebra_rec_keys_read(reckeys, &str, &slen, &key_in))
1433 int ord = CAST_ZINT_TO_INT(key_in.mem[0]);
1435 for (p = ord_list; p ; p = p->next)
1443 p = xmalloc(sizeof(*p));
1454 struct ord_stat *p1 = p;
1457 zebraExplain_ord_adjust_occurrences(zei, p->ord, p->no, 1);
1459 zebraExplain_ord_adjust_occurrences(zei, p->ord, - p->no, -1);
1467 static void extract_flush_record_keys2(
1468 ZebraHandle zh, zint sysno,
1469 zebra_rec_keys_t ins_keys, zint ins_rank,
1470 zebra_rec_keys_t del_keys, zint del_rank)
1472 ZebraExplainInfo zei = zh->reg->zei;
1476 if (!zh->reg->key_block)
1478 int mem = 1024*1024 * atoi( res_get_def( zh->res, "memmax", "8"));
1479 const char *key_tmp_dir = res_get_def(zh->res, "keyTmpDir", ".");
1480 int use_threads = atoi(res_get_def(zh->res, "threads", "1"));
1481 zh->reg->key_block = key_block_create(mem, key_tmp_dir, use_threads);
1486 extract_rec_keys_adjust(zh, 1, ins_keys);
1488 zebraExplain_recordCountIncrement(zei, 1);
1489 zebra_rec_keys_rewind(ins_keys);
1493 extract_rec_keys_adjust(zh, 0, del_keys);
1495 zebraExplain_recordCountIncrement(zei, -1);
1496 zebra_rec_keys_rewind(del_keys);
1502 const char *del_str;
1503 struct it_key del_key_in;
1507 const char *ins_str;
1508 struct it_key ins_key_in;
1512 del = zebra_rec_keys_read(del_keys, &del_str, &del_slen,
1515 ins = zebra_rec_keys_read(ins_keys, &ins_str, &ins_slen,
1518 if (del && ins && ins_rank == del_rank
1519 && !key_compare(&del_key_in, &ins_key_in)
1520 && ins_slen == del_slen && !memcmp(del_str, ins_str, del_slen))
1530 key_block_write(zh->reg->key_block, sysno,
1531 &del_key_in, 0, del_str, del_slen,
1532 del_rank, zh->m_staticrank);
1534 key_block_write(zh->reg->key_block, sysno,
1535 &ins_key_in, 1, ins_str, ins_slen,
1536 ins_rank, zh->m_staticrank);
1538 yaz_log(log_level_extract, "normal=%d optimized=%d", normal, optimized);
1541 static void extract_flush_record_keys(
1542 ZebraHandle zh, zint sysno, int cmd,
1543 zebra_rec_keys_t reckeys,
1546 ZebraExplainInfo zei = zh->reg->zei;
1548 extract_rec_keys_adjust(zh, cmd, reckeys);
1550 if (log_level_details)
1552 yaz_log(log_level_details, "Keys for record " ZINT_FORMAT " %s",
1553 sysno, cmd ? "insert" : "delete");
1554 extract_rec_keys_log(zh, cmd, reckeys, log_level_details);
1557 if (!zh->reg->key_block)
1559 int mem = 1024*1024 * atoi( res_get_def( zh->res, "memmax", "8"));
1560 const char *key_tmp_dir = res_get_def(zh->res, "keyTmpDir", ".");
1561 int use_threads = atoi(res_get_def(zh->res, "threads", "1"));
1562 zh->reg->key_block = key_block_create(mem, key_tmp_dir, use_threads);
1564 zebraExplain_recordCountIncrement(zei, cmd ? 1 : -1);
1567 yaz_log(YLOG_LOG, "sysno=" ZINT_FORMAT " cmd=%d", sysno, cmd);
1568 print_rec_keys(zh, reckeys);
1570 if (zebra_rec_keys_rewind(reckeys))
1574 struct it_key key_in;
1575 while(zebra_rec_keys_read(reckeys, &str, &slen, &key_in))
1577 key_block_write(zh->reg->key_block, sysno,
1578 &key_in, cmd, str, slen,
1579 staticrank, zh->m_staticrank);
1585 ZEBRA_RES zebra_rec_keys_to_snippets1(ZebraHandle zh,
1586 zebra_rec_keys_t reckeys,
1587 zebra_snippets *snippets)
1589 NMEM nmem = nmem_create();
1590 if (zebra_rec_keys_rewind(reckeys))
1595 while (zebra_rec_keys_read(reckeys, &str, &slen, &key))
1600 const char *index_type;
1602 assert(key.len <= IT_KEY_LEVEL_MAX && key.len > 2);
1603 seqno = key.mem[key.len-1];
1604 ord = CAST_ZINT_TO_INT(key.mem[0]);
1606 zebraExplain_lookup_ord(zh->reg->zei, ord, &index_type,
1607 0/* db */, 0 /* string_index */);
1609 zebra_term_untrans_iconv(zh, nmem, index_type,
1611 zebra_snippets_append(snippets, seqno, 0, ord, dst_term);
1619 void print_rec_keys(ZebraHandle zh, zebra_rec_keys_t reckeys)
1621 yaz_log(YLOG_LOG, "print_rec_keys");
1622 if (zebra_rec_keys_rewind(reckeys))
1627 while (zebra_rec_keys_read(reckeys, &str, &slen, &key))
1629 char dst_buf[IT_MAX_WORD];
1631 const char *index_type;
1632 int ord = CAST_ZINT_TO_INT(key.mem[0]);
1634 assert(key.len <= IT_KEY_LEVEL_MAX && key.len > 2);
1636 zebraExplain_lookup_ord(zh->reg->zei, ord, &index_type, &db, 0);
1638 seqno = key.mem[key.len-1];
1640 zebra_term_untrans(zh, index_type, dst_buf, str);
1642 yaz_log(YLOG_LOG, "ord=%d seqno=" ZINT_FORMAT
1643 " term=%s", ord, seqno, dst_buf);
1648 static void extract_add_index_string(RecWord *p, zinfo_index_category_t cat,
1649 const char *str, int length)
1652 ZebraHandle zh = p->extractCtrl->handle;
1653 ZebraExplainInfo zei = zh->reg->zei;
1656 ch = zebraExplain_lookup_attr_str(zei, cat, p->index_type, p->index_name);
1658 ch = zebraExplain_add_attr_str(zei, cat, p->index_type, p->index_name);
1662 key.mem[i++] = p->record_id;
1663 key.mem[i++] = p->section_id;
1665 if (zh->m_segment_indexing)
1666 key.mem[i++] = p->segment;
1667 key.mem[i++] = p->seqno;
1670 zebra_rec_keys_write(zh->reg->keys, str, length, &key);
1673 static void extract_add_sort_string(RecWord *p, const char *str, int length)
1676 ZebraHandle zh = p->extractCtrl->handle;
1677 ZebraExplainInfo zei = zh->reg->zei;
1679 zinfo_index_category_t cat = zinfo_index_category_sort;
1681 ch = zebraExplain_lookup_attr_str(zei, cat, p->index_type, p->index_name);
1683 ch = zebraExplain_add_attr_str(zei, cat, p->index_type, p->index_name);
1686 key.mem[1] = p->record_id;
1687 key.mem[2] = p->section_id;
1689 zebra_rec_keys_write(zh->reg->sortKeys, str, length, &key);
1692 static void extract_add_staticrank_string(RecWord *p,
1693 const char *str, int length)
1696 struct recExtractCtrl *ctrl = p->extractCtrl;
1698 if (length > sizeof(valz)-1)
1699 length = sizeof(valz)-1;
1701 memcpy(valz, str, length);
1702 valz[length] = '\0';
1703 ctrl->staticrank = atozint(valz);
1706 static void extract_add_string(RecWord *p, zebra_map_t zm,
1707 const char *string, int length)
1713 if (log_level_details)
1716 WRBUF w = wrbuf_alloc();
1718 wrbuf_write_escaped(w, string, length);
1719 yaz_log(log_level_details, "extract_add_string: %s", wrbuf_cstr(w));
1722 if (zebra_maps_is_index(zm))
1724 extract_add_index_string(p, zinfo_index_category_index,
1726 if (zebra_maps_is_alwaysmatches(zm))
1729 memcpy(&word, p, sizeof(word));
1732 extract_add_index_string(
1733 &word, zinfo_index_category_alwaysmatches, "", 0);
1736 else if (zebra_maps_is_sort(zm))
1738 extract_add_sort_string(p, string, length);
1740 else if (zebra_maps_is_staticrank(zm))
1742 extract_add_staticrank_string(p, string, length);
1746 static void extract_add_incomplete_field(RecWord *p, zebra_map_t zm)
1748 const char *b = p->term_buf;
1749 int remain = p->term_len;
1751 const char **map = 0;
1754 map = zebra_maps_input(zm, &b, remain, 0);
1758 char buf[IT_MAX_WORD+1];
1762 while (map && *map && **map == *CHR_SPACE)
1764 remain = p->term_len - (b - p->term_buf);
1766 map = zebra_maps_input(zm, &b, remain, 0);
1773 while (map && *map && **map != *CHR_SPACE)
1775 const char *cp = *map;
1777 while (i < IT_MAX_WORD && *cp)
1779 remain = p->term_len - (b - p->term_buf);
1781 map = zebra_maps_input(zm, &b, remain, 0);
1791 if (zebra_maps_is_first_in_field(zm))
1793 /* first in field marker */
1794 extract_add_string(p, zm, FIRST_IN_FIELD_STR, FIRST_IN_FIELD_LEN);
1798 extract_add_string(p, zm, buf, i);
1803 static void extract_add_complete_field(RecWord *p, zebra_map_t zm)
1805 char buf[IT_MAX_WORD+1];
1806 int i = parse_complete_field(p, zm, buf);
1809 extract_add_string(p, zm, buf, i);
1813 static void extract_add_icu(RecWord *p, zebra_map_t zm)
1815 const char *res_buf = 0;
1818 zebra_map_tokenize_start(zm, p->term_buf, p->term_len);
1819 while (zebra_map_tokenize_next(zm, &res_buf, &res_len, 0, 0))
1821 if (res_len > IT_MAX_WORD)
1823 yaz_log(YLOG_LOG, "Truncating long term %ld", (long) res_len);
1824 res_len = IT_MAX_WORD;
1826 extract_add_string(p, zm, res_buf, res_len);
1832 /** \brief top-level indexing handler for recctrl system
1833 \param p token data to be indexed
1837 extract_add_{in}_complete / extract_add_icu
1840 extract_add_index_string
1842 extract_add_sort_string
1844 extract_add_staticrank_string
1847 static void extract_token_add(RecWord *p)
1849 ZebraHandle zh = p->extractCtrl->handle;
1850 zebra_map_t zm = zebra_map_get_or_add(zh->reg->zebra_maps, p->index_type);
1852 if (log_level_details)
1854 yaz_log(log_level_details, "extract_token_add "
1855 "type=%s index=%s seqno=" ZINT_FORMAT " s=%.*s",
1856 p->index_type, p->index_name,
1857 p->seqno, p->term_len, p->term_buf);
1859 if (zebra_maps_is_icu(zm))
1861 extract_add_icu(p, zm);
1865 if (zebra_maps_is_complete(zm))
1866 extract_add_complete_field(p, zm);
1868 extract_add_incomplete_field(p, zm);
1872 static void extract_set_store_data_cb(struct recExtractCtrl *p,
1873 void *buf, size_t sz)
1875 ZebraHandle zh = (ZebraHandle) p->handle;
1877 xfree(zh->store_data_buf);
1878 zh->store_data_buf = 0;
1879 zh->store_data_size = 0;
1882 zh->store_data_buf = xmalloc(sz);
1883 zh->store_data_size = sz;
1884 memcpy(zh->store_data_buf, buf, sz);
1888 static void extract_set_store_data_prepare(struct recExtractCtrl *p)
1890 ZebraHandle zh = (ZebraHandle) p->handle;
1891 xfree(zh->store_data_buf);
1892 zh->store_data_buf = 0;
1893 zh->store_data_size = 0;
1894 p->setStoreData = extract_set_store_data_cb;
1897 static void extract_schema_add(struct recExtractCtrl *p, Odr_oid *oid)
1899 ZebraHandle zh = (ZebraHandle) p->handle;
1900 zebraExplain_addSchema(zh->reg->zei, oid);
1903 void extract_flush_sort_keys(ZebraHandle zh, zint sysno,
1904 int cmd, zebra_rec_keys_t reckeys)
1907 yaz_log(YLOG_LOG, "extract_flush_sort_keys cmd=%d sysno=" ZINT_FORMAT,
1909 extract_rec_keys_log(zh, cmd, reckeys, YLOG_LOG);
1912 if (zebra_rec_keys_rewind(reckeys))
1914 zebra_sort_index_t si = zh->reg->sort_index;
1917 struct it_key key_in;
1919 NMEM nmem = nmem_create();
1920 struct sort_add_ent {
1923 struct sort_add_ent *next;
1928 struct sort_add_ent *sort_ent_list = 0;
1930 while (zebra_rec_keys_read(reckeys, &str, &slen, &key_in))
1932 int ord = CAST_ZINT_TO_INT(key_in.mem[0]);
1933 zint filter_sysno = key_in.mem[1];
1934 zint section_id = key_in.mem[2];
1936 struct sort_add_ent **e = &sort_ent_list;
1937 for (; *e; e = &(*e)->next)
1938 if ((*e)->ord == ord && section_id == (*e)->section_id)
1942 *e = nmem_malloc(nmem, sizeof(**e));
1944 (*e)->wrbuf = wrbuf_alloc();
1947 (*e)->sysno = filter_sysno ? filter_sysno : sysno;
1948 (*e)->section_id = section_id;
1951 wrbuf_write((*e)->wrbuf, str, slen);
1952 wrbuf_putc((*e)->wrbuf, '\0');
1956 zint last_sysno = 0;
1957 struct sort_add_ent *e = sort_ent_list;
1958 for (; e; e = e->next)
1960 if (last_sysno != e->sysno)
1962 zebra_sort_sysno(si, e->sysno);
1963 last_sysno = e->sysno;
1965 zebra_sort_type(si, e->ord);
1967 zebra_sort_add(si, e->section_id, e->wrbuf);
1969 zebra_sort_delete(si, e->section_id);
1970 wrbuf_destroy(e->wrbuf);
1980 * c-file-style: "Stroustrup"
1981 * indent-tabs-mode: nil
1983 * vim: shiftwidth=4 tabstop=8 expandtab