+ extract_flushRecordKeys (zh, rec->sysno, 1, &zh->reg->keys);
+ extract_flushSortKeys (zh, rec->sysno, 1, &zh->reg->sortKeys);
+
+ xfree (rec->info[recInfo_delKeys]);
+ rec->size[recInfo_delKeys] = zh->reg->keys.buf_used;
+ rec->info[recInfo_delKeys] = zh->reg->keys.buf;
+ zh->reg->keys.buf = NULL;
+ zh->reg->keys.buf_max = 0;
+ return 0;
+}
+
+void extract_flushRecordKeys (ZebraHandle zh, SYSNO sysno,
+ int cmd, struct recKeys *reckeys)
+{
+#if SU_SCHEME
+#else
+ unsigned char attrSet = (unsigned char) -1;
+ unsigned short attrUse = (unsigned short) -1;
+#endif
+ int seqno = 0;
+ int off = 0;
+ int ch = 0;
+ ZebraExplainInfo zei = zh->reg->zei;
+
+ if (!zh->reg->key_buf)
+ {
+ int mem = 8*1024*1024;
+ zh->reg->key_buf = (char**) xmalloc (mem);
+ zh->reg->ptr_top = mem/sizeof(char*);
+ zh->reg->ptr_i = 0;
+ zh->reg->key_buf_used = 0;
+ zh->reg->key_file_no = 0;
+ }
+ zebraExplain_recordCountIncrement (zei, cmd ? 1 : -1);
+ while (off < reckeys->buf_used)
+ {
+ const char *src = reckeys->buf + off;
+ struct it_key key;
+ int lead;
+
+ lead = *src++;
+
+#if SU_SCHEME
+ if ((lead & 3) < 3)
+ {
+ memcpy (&ch, src, sizeof(ch));
+ src += sizeof(ch);
+ }
+#else
+ if (!(lead & 1))
+ {
+ memcpy (&attrSet, src, sizeof(attrSet));
+ src += sizeof(attrSet);
+ }
+ if (!(lead & 2))
+ {
+ memcpy (&attrUse, src, sizeof(attrUse));
+ src += sizeof(attrUse);
+ }
+#endif
+ if (zh->reg->key_buf_used + 1024 >
+ (zh->reg->ptr_top -zh->reg->ptr_i)*sizeof(char*))
+ extract_flushWriteKeys (zh);
+ ++(zh->reg->ptr_i);
+ (zh->reg->key_buf)[zh->reg->ptr_top - zh->reg->ptr_i] =
+ (char*)zh->reg->key_buf + zh->reg->key_buf_used;
+#if SU_SCHEME
+#else
+ ch = zebraExplain_lookupSU (zei, attrSet, attrUse);
+ if (ch < 0)
+ ch = zebraExplain_addSU (zei, attrSet, attrUse);
+#endif
+ assert (ch > 0);
+ zh->reg->key_buf_used +=
+ key_SU_encode (ch,((char*)zh->reg->key_buf) +
+ zh->reg->key_buf_used);
+
+ while (*src)
+ ((char*)zh->reg->key_buf) [(zh->reg->key_buf_used)++] = *src++;
+ src++;
+ ((char*)(zh->reg->key_buf))[(zh->reg->key_buf_used)++] = '\0';
+ ((char*)(zh->reg->key_buf))[(zh->reg->key_buf_used)++] = cmd;
+
+ if (lead & 60)
+ seqno += ((lead>>2) & 15)-1;
+ else
+ {
+ memcpy (&seqno, src, sizeof(seqno));
+ src += sizeof(seqno);
+ }
+ key.seqno = seqno;
+ key.sysno = sysno;
+ memcpy ((char*)zh->reg->key_buf + zh->reg->key_buf_used, &key, sizeof(key));
+ (zh->reg->key_buf_used) += sizeof(key);
+ off = src - reckeys->buf;
+ }
+ assert (off == reckeys->buf_used);
+}
+
+void extract_flushWriteKeys (ZebraHandle zh)
+{
+ FILE *outf;
+ char out_fname[200];
+ char *prevcp, *cp;
+ struct encode_info encode_info;
+ int ptr_i = zh->reg->ptr_i;
+#if SORT_EXTRA
+ int i;
+#endif
+ if (!zh->reg->key_buf || ptr_i <= 0)
+ return;
+
+ (zh->reg->key_file_no)++;
+ logf (LOG_LOG, "sorting section %d", (zh->reg->key_file_no));
+#if !SORT_EXTRA
+ qsort (zh->reg->key_buf + zh->reg->ptr_top - ptr_i, ptr_i,
+ sizeof(char*), key_qsort_compare);
+ extract_get_fname_tmp (zh, out_fname, zh->reg->key_file_no);
+
+ if (!(outf = fopen (out_fname, "wb")))
+ {
+ logf (LOG_FATAL|LOG_ERRNO, "fopen %s", out_fname);
+ exit (1);
+ }
+ logf (LOG_LOG, "writing section %d", zh->reg->key_file_no);
+ prevcp = cp = (zh->reg->key_buf)[zh->reg->ptr_top - ptr_i];
+
+ encode_key_init (&encode_info);
+ encode_key_write (cp, &encode_info, outf);
+
+ while (--ptr_i > 0)
+ {
+ cp = (zh->reg->key_buf)[zh->reg->ptr_top - ptr_i];
+ if (strcmp (cp, prevcp))
+ {
+ encode_key_init (&encode_info);
+ encode_key_write (cp, &encode_info, outf);
+ prevcp = cp;
+ }
+ else
+ encode_key_write (cp + strlen(cp), &encode_info, outf);
+ }
+#else
+ qsort (key_buf + ptr_top-ptr_i, ptr_i, sizeof(char*), key_x_compare);
+ extract_get_fname_tmp (out_fname, key_file_no);
+
+ if (!(outf = fopen (out_fname, "wb")))
+ {
+ logf (LOG_FATAL|LOG_ERRNO, "fopen %s", out_fname);
+ exit (1);
+ }
+ logf (LOG_LOG, "writing section %d", key_file_no);
+ i = ptr_i;
+ prevcp = key_buf[ptr_top-i];
+ while (1)
+ if (!--i || strcmp (prevcp, key_buf[ptr_top-i]))
+ {
+ key_y_len = strlen(prevcp)+1;
+#if 0
+ logf (LOG_LOG, "key_y_len: %2d %02x %02x %s",
+ key_y_len, prevcp[0], prevcp[1], 2+prevcp);
+#endif
+ qsort (key_buf + ptr_top-ptr_i, ptr_i - i,
+ sizeof(char*), key_y_compare);
+ cp = key_buf[ptr_top-ptr_i];
+ --key_y_len;
+ encode_key_init (&encode_info);
+ encode_key_write (cp, &encode_info, outf);
+ while (--ptr_i > i)
+ {
+ cp = key_buf[ptr_top-ptr_i];
+ encode_key_write (cp+key_y_len, &encode_info, outf);
+ }
+ if (!i)
+ break;
+ prevcp = key_buf[ptr_top-ptr_i];
+ }
+#endif
+ if (fclose (outf))
+ {
+ logf (LOG_FATAL|LOG_ERRNO, "fclose %s", out_fname);
+ exit (1);
+ }
+ logf (LOG_LOG, "finished section %d", zh->reg->key_file_no);
+ zh->reg->ptr_i = 0;
+ zh->reg->key_buf_used = 0;
+}
+
+void extract_add_index_string (RecWord *p, const char *string,
+ int length)
+{
+ char *dst;
+ unsigned char attrSet;
+ unsigned short attrUse;
+ int lead = 0;
+ int diff = 0;
+ int *pseqno = &p->seqno;
+ ZebraHandle zh = p->extractCtrl->handle;
+ ZebraExplainInfo zei = zh->reg->zei;
+ struct recKeys *keys = &zh->reg->keys;
+
+ if (keys->buf_used+1024 > keys->buf_max)
+ {
+ char *b;
+
+ b = (char *) xmalloc (keys->buf_max += 128000);
+ if (keys->buf_used > 0)
+ memcpy (b, keys->buf, keys->buf_used);
+ xfree (keys->buf);
+ keys->buf = b;
+ }
+ dst = keys->buf + keys->buf_used;
+
+ attrSet = p->attrSet;
+ if (keys->buf_used > 0 && keys->prevAttrSet == attrSet)
+ lead |= 1;
+ else
+ keys->prevAttrSet = attrSet;
+ attrUse = p->attrUse;
+ if (keys->buf_used > 0 && keys->prevAttrUse == attrUse)
+ lead |= 2;
+ else
+ keys->prevAttrUse = attrUse;
+#if 1
+ diff = 1 + *pseqno - keys->prevSeqNo;
+ if (diff >= 1 && diff <= 15)
+ lead |= (diff << 2);
+ else
+ diff = 0;
+#endif
+ keys->prevSeqNo = *pseqno;
+
+ *dst++ = lead;
+
+#if SU_SCHEME
+ if ((lead & 3) < 3)
+ {
+ int ch = zebraExplain_lookupSU (zei, attrSet, attrUse);
+ if (ch < 0)
+ {
+ ch = zebraExplain_addSU (zei, attrSet, attrUse);
+ yaz_log (LOG_DEBUG, "addSU set=%d use=%d SU=%d",
+ attrSet, attrUse, ch);
+ }
+ assert (ch > 0);
+ memcpy (dst, &ch, sizeof(ch));
+ dst += sizeof(ch);
+ }
+#else
+ if (!(lead & 1))
+ {
+ memcpy (dst, &attrSet, sizeof(attrSet));
+ dst += sizeof(attrSet);
+ }
+ if (!(lead & 2))
+ {
+ memcpy (dst, &attrUse, sizeof(attrUse));
+ dst += sizeof(attrUse);
+ }
+#endif
+ *dst++ = p->reg_type;
+ memcpy (dst, string, length);
+ dst += length;
+ *dst++ = '\0';
+
+ if (!diff)
+ {
+ memcpy (dst, pseqno, sizeof(*pseqno));
+ dst += sizeof(*pseqno);
+ }
+ keys->buf_used = dst - keys->buf;
+}
+
+static void extract_add_sort_string (RecWord *p, const char *string,
+ int length)
+{
+ struct sortKey *sk;
+ ZebraHandle zh = p->extractCtrl->handle;
+
+ for (sk = zh->reg->sortKeys; sk; sk = sk->next)
+ if (sk->attrSet == p->attrSet && sk->attrUse == p->attrUse)
+ return;
+
+ sk = (struct sortKey *) xmalloc (sizeof(*sk));
+ sk->next = zh->reg->sortKeys;
+ zh->reg->sortKeys = sk;
+
+ sk->string = (char *) xmalloc (length);
+ sk->length = length;
+ memcpy (sk->string, string, length);
+
+ sk->attrSet = p->attrSet;
+ sk->attrUse = p->attrUse;
+}
+
+void extract_add_string (RecWord *p, const char *string, int length)
+{
+ assert (length > 0);
+ if (zebra_maps_is_sort (p->zebra_maps, p->reg_type))
+ extract_add_sort_string (p, string, length);
+ else
+ extract_add_index_string (p, string, length);