+int zebra_string_norm (ZebraHandle zh, unsigned reg_id,
+ const char *input_str, int input_len,
+ char *output_str, int output_len)
+{
+ WRBUF wrbuf;
+ ASSERTZH;
+ zh->errCode=0;
+ if (!zh->reg->zebra_maps)
+ return -1;
+ wrbuf = zebra_replace(zh->reg->zebra_maps, reg_id, "",
+ input_str, input_len);
+ if (!wrbuf)
+ return -2;
+ if (wrbuf_len(wrbuf) >= output_len)
+ return -3;
+ if (wrbuf_len(wrbuf))
+ memcpy (output_str, wrbuf_buf(wrbuf), wrbuf_len(wrbuf));
+ output_str[wrbuf_len(wrbuf)] = '\0';
+ return wrbuf_len(wrbuf);
+}
+
+
+void zebra_set_state (ZebraHandle zh, int val, int seqno)
+{
+ char state_fname[256];
+ char *fname;
+ long p = getpid();
+ FILE *f;
+ ASSERTZH;
+ zh->errCode=0;
+
+ sprintf (state_fname, "state.%s.LCK", zh->reg_name);
+ fname = zebra_mk_fname (res_get(zh->res, "lockDir"), state_fname);
+ f = fopen (fname, "w");
+
+ yaz_log (LOG_DEBUG, "%c %d %ld", val, seqno, p);
+ fprintf (f, "%c %d %ld\n", val, seqno, p);
+ fclose (f);
+ xfree (fname);
+}
+
+void zebra_get_state (ZebraHandle zh, char *val, int *seqno)
+{
+ char state_fname[256];
+ char *fname;
+ FILE *f;
+
+ ASSERTZH;
+ zh->errCode=0;
+ sprintf (state_fname, "state.%s.LCK", zh->reg_name);
+ fname = zebra_mk_fname (res_get(zh->res, "lockDir"), state_fname);
+ f = fopen (fname, "r");
+ *val = 'o';
+ *seqno = 0;
+
+ if (f)
+ {
+ fscanf (f, "%c %d", val, seqno);
+ fclose (f);
+ }
+ xfree (fname);
+}
+
+int zebra_begin_read (ZebraHandle zh)
+{
+ int dirty = 0;
+ char val;
+ int seqno;
+ ASSERTZH;
+
+ assert (zh->res);
+
+ (zh->trans_no)++;
+
+ if (zh->trans_no != 1)
+ {
+ zebra_flush_reg (zh);
+ return 0;
+ }
+ zh->errCode=0;
+#if HAVE_SYS_TIMES_H
+ times (&zh->tms1);
+#endif
+ if (!zh->res)
+ {
+ (zh->trans_no)--;
+ zh->errCode = 109;
+ return -1;
+ }
+ if (!zh->lock_normal || !zh->lock_shadow)
+ {
+ (zh->trans_no)--;
+ zh->errCode = 2;
+ return -1;
+ }
+ zebra_get_state (zh, &val, &seqno);
+ if (val == 'd')
+ val = 'o';
+
+ if (!zh->reg)
+ dirty = 1;
+ else if (seqno != zh->reg->seqno)
+ {
+ yaz_log (LOG_LOG, "reopen seqno cur/old %d/%d",
+ seqno, zh->reg->seqno);
+ dirty = 1;
+ }
+ else if (zh->reg->last_val != val)
+ {
+ yaz_log (LOG_LOG, "reopen last cur/old %d/%d",
+ val, zh->reg->last_val);
+ dirty = 1;
+ }
+ if (!dirty)
+ return 0;
+
+ if (val == 'c')
+ zebra_lock_r (zh->lock_shadow);
+ else
+ zebra_lock_r (zh->lock_normal);
+
+ if (zh->reg)
+ zebra_register_close (zh->service, zh->reg);
+ zh->reg = zebra_register_open (zh->service, zh->reg_name,
+ 0, val == 'c' ? 1 : 0,
+ zh->res, zh->path_reg);
+ if (!zh->reg)
+ {
+ zh->errCode = 109;
+ return -1;
+ }
+ zh->reg->last_val = val;
+ zh->reg->seqno = seqno;
+
+ return 0;
+}
+
+void zebra_end_read (ZebraHandle zh)
+{
+ ASSERTZH;
+ (zh->trans_no)--;
+
+ if (zh->trans_no != 0)
+ return;
+#if HAVE_SYS_TIMES_H
+ times (&zh->tms2);
+ logf (LOG_LOG, "user/system: %ld/%ld",
+ (long) (zh->tms2.tms_utime - zh->tms1.tms_utime),
+ (long) (zh->tms2.tms_stime - zh->tms1.tms_stime));
+
+#endif
+
+ zebra_unlock (zh->lock_normal);
+ zebra_unlock (zh->lock_shadow);
+}
+
+void zebra_begin_trans (ZebraHandle zh)
+{
+ int pass;
+ int seqno = 0;
+ char val = '?';
+ const char *rval = 0;
+ ASSERTZHRES;
+
+ assert (zh->res);
+
+ (zh->trans_no++);
+ if (zh->trans_no != 1)
+ {
+ return;
+ }
+ zh->errCode=0;
+
+ yaz_log (LOG_LOG, "zebra_begin_trans");
+
+ zh->records_inserted = 0;
+ zh->records_updated = 0;
+ zh->records_deleted = 0;
+ zh->records_processed = 0;
+
+#if HAVE_SYS_TIMES_H
+ times (&zh->tms1);
+#endif
+
+ /* lock */
+ if (zh->shadow_enable)
+ rval = res_get (zh->res, "shadow");
+
+ for (pass = 0; pass < 2; pass++)
+ {
+ if (rval)
+ {
+ zebra_lock_r (zh->lock_normal);
+ zebra_lock_w (zh->lock_shadow);
+ }
+ else
+ {
+ zebra_lock_w (zh->lock_normal);
+ zebra_lock_w (zh->lock_shadow);
+ }
+
+ zebra_get_state (zh, &val, &seqno);
+ if (val == 'c')
+ {
+ yaz_log (LOG_LOG, "previous transaction didn't finish commit");
+ zebra_unlock (zh->lock_shadow);
+ zebra_unlock (zh->lock_normal);
+ zebra_commit (zh);
+ continue;
+ }
+ else if (val == 'd')
+ {
+ if (rval)
+ {
+ BFiles bfs = bfs_create (res_get (zh->res, "shadow"),
+ zh->path_reg);
+ yaz_log (LOG_LOG, "previous transaction didn't reach commit");
+ bf_commitClean (bfs, rval);
+ bfs_destroy (bfs);
+ }
+ else
+ {
+ yaz_log (LOG_WARN, "your previous transaction didn't finish");
+ }
+ }
+ break;
+ }
+ if (pass == 2)
+ {
+ yaz_log (LOG_FATAL, "zebra_begin_trans couldn't finish commit");
+ abort();
+ return;
+ }
+ zebra_set_state (zh, 'd', seqno);
+
+ zh->reg = zebra_register_open (zh->service, zh->reg_name,
+ 1, rval ? 1 : 0, zh->res,
+ zh->path_reg);
+
+ zh->reg->seqno = seqno;
+}
+
+void zebra_end_trans (ZebraHandle zh)
+{
+ char val;
+ int seqno;
+ const char *rval;
+ ASSERTZH;
+
+ zh->trans_no--;
+ if (zh->trans_no != 0)
+ return;
+ yaz_log (LOG_LOG, "zebra_end_trans");
+ rval = res_get (zh->res, "shadow");
+
+ zebraExplain_runNumberIncrement (zh->reg->zei, 1);
+
+ zebra_flush_reg (zh);
+
+ zebra_register_close (zh->service, zh->reg);
+ zh->reg = 0;
+
+ yaz_log (LOG_LOG, "Records: %7d i/u/d %d/%d/%d",
+ zh->records_processed, zh->records_inserted,
+ zh->records_updated, zh->records_deleted);
+
+ zebra_get_state (zh, &val, &seqno);
+ if (val != 'd')
+ {
+ BFiles bfs = bfs_create (rval, zh->path_reg);
+ yaz_log (LOG_LOG, "deleting shadow stuff val=%c", val);
+ bf_commitClean (bfs, rval);
+ bfs_destroy (bfs);
+ }
+ if (!rval)
+ seqno++;
+ zebra_set_state (zh, 'o', seqno);
+
+ zebra_unlock (zh->lock_shadow);
+ zebra_unlock (zh->lock_normal);
+
+#if HAVE_SYS_TIMES_H
+ times (&zh->tms2);
+ logf (LOG_LOG, "user/system: %ld/%ld",
+ (long) (zh->tms2.tms_utime - zh->tms1.tms_utime),
+ (long) (zh->tms2.tms_stime - zh->tms1.tms_stime));
+
+#endif
+}
+
+void zebra_repository_update (ZebraHandle zh)
+{
+ ASSERTZH;
+ zh->errCode=0;
+ logf (LOG_LOG, "updating %s", zh->rGroup.path);
+ repositoryUpdate (zh);
+}
+
+void zebra_repository_delete (ZebraHandle zh)
+{
+ ASSERTZH;
+ zh->errCode=0;
+ logf (LOG_LOG, "deleting %s", zh->rGroup.path);
+ repositoryDelete (zh);
+}
+
+void zebra_repository_show (ZebraHandle zh)
+{
+ ASSERTZH;
+ zh->errCode=0;
+ repositoryShow (zh);
+}
+
+int zebra_commit (ZebraHandle zh)
+{
+ int seqno;
+ char val;
+ const char *rval;
+ BFiles bfs;
+ ASSERTZH;
+ zh->errCode=0;
+
+ if (!zh->res)
+ {
+ zh->errCode = 109;
+ return -1;
+ }
+ rval = res_get (zh->res, "shadow");
+ if (!rval)
+ {
+ logf (LOG_WARN, "Cannot perform commit");
+ logf (LOG_WARN, "No shadow area defined");
+ return 0;
+ }
+
+ zebra_lock_w (zh->lock_normal);
+ zebra_lock_r (zh->lock_shadow);
+
+ bfs = bfs_create (res_get (zh->res, "register"), zh->path_reg);
+
+ zebra_get_state (zh, &val, &seqno);
+
+ if (rval && *rval)
+ bf_cache (bfs, rval);
+ if (bf_commitExists (bfs))
+ {
+ zebra_set_state (zh, 'c', seqno);
+
+ logf (LOG_LOG, "commit start");
+ bf_commitExec (bfs);
+#ifndef WIN32
+ sync ();
+#endif
+ logf (LOG_LOG, "commit clean");
+ bf_commitClean (bfs, rval);
+ seqno++;
+ zebra_set_state (zh, 'o', seqno);
+ }
+ else
+ {
+ logf (LOG_LOG, "nothing to commit");
+ }
+ bfs_destroy (bfs);
+
+ zebra_unlock (zh->lock_shadow);
+ zebra_unlock (zh->lock_normal);
+ return 0;
+}
+
+int zebra_init (ZebraHandle zh)
+{
+ const char *rval;
+ BFiles bfs = 0;
+ ASSERTZH;
+ zh->errCode=0;
+
+ if (!zh->res)
+ {
+ zh->errCode = 109;
+ return -1;
+ }
+ rval = res_get (zh->res, "shadow");
+
+ bfs = bfs_create (res_get (zh->service->global_res, "register"),
+ zh->path_reg);
+ if (rval && *rval)
+ bf_cache (bfs, rval);
+
+ bf_reset (bfs);
+ bfs_destroy (bfs);
+ zebra_set_state (zh, 'o', 0);
+ return 0;
+}
+
+int zebra_compact (ZebraHandle zh)
+{
+ BFiles bfs;
+ ASSERTZH;
+ zh->errCode=0;
+ if (!zh->res)
+ {
+ zh->errCode = 109;
+ return -1;
+ }
+ bfs = bfs_create (res_get (zh->res, "register"), zh->path_reg);
+ inv_compact (bfs);
+ bfs_destroy (bfs);
+ return 0;
+}
+
+int zebra_record_insert (ZebraHandle zh, const char *buf, int len)
+{
+ int sysno = 0;
+ int olderr;
+ ASSERTZH;
+ zh->errCode=0;
+ zebra_begin_trans (zh);
+ if (zh->errCode)
+ return 0; /* bad sysno */
+ extract_rec_in_mem (zh, "grs.sgml",
+ buf, len,
+ "Default", /* database */
+ 0 /* delete_flag */,
+ 0 /* test_mode */,
+ &sysno /* sysno */,
+ 1 /* store_keys */,
+ 1 /* store_data */,
+ 0 /* match criteria */);
+ olderr=zh->errCode;
+ zebra_end_trans (zh);
+ if (olderr)
+ zh->errCode=olderr;
+ return sysno;
+}
+
+void zebra_set_group (ZebraHandle zh, struct recordGroup *rg)
+{
+ ASSERTZH;
+ zh->errCode=0;
+ memcpy (&zh->rGroup, rg, sizeof(*rg));
+}
+
+void zebra_result (ZebraHandle zh, int *code, char **addinfo)
+{
+ ASSERTZH;
+ *code = zh->errCode;
+ *addinfo = zh->errString;
+}
+
+void zebra_shadow_enable (ZebraHandle zh, int value)
+{
+ ASSERTZH;
+ zh->errCode=0;
+ zh->shadow_enable = value;
+}
+
+int zebra_record_encoding (ZebraHandle zh, const char *encoding)
+{
+ ASSERTZH;
+ zh->errCode=0;
+ xfree (zh->record_encoding);
+
+ /*
+ * Fixme!
+ */
+
+ if (zh->iconv_to_utf8 != 0)
+ yaz_iconv_close(zh->iconv_to_utf8);
+ if (zh->iconv_from_utf8 != 0)
+ yaz_iconv_close(zh->iconv_from_utf8);
+
+ zh->record_encoding = xstrdup (encoding);
+
+ logf(LOG_DEBUG, "Reset record encoding: %s", encoding);
+
+ zh->iconv_to_utf8 =
+ yaz_iconv_open ("UTF-8", encoding);
+ if (zh->iconv_to_utf8 == 0)
+ yaz_log (LOG_WARN, "iconv: %s to UTF-8 unsupported", encoding);
+ zh->iconv_from_utf8 =
+ yaz_iconv_open (encoding, "UTF-8");
+ if (zh->iconv_to_utf8 == 0)
+ yaz_log (LOG_WARN, "iconv: UTF-8 to %s unsupported", encoding);
+
+ return 0;
+}
+
+void zebra_set_resource(ZebraHandle zh, const char *name, const char *value)
+{
+ ASSERTZH;
+ zh->errCode=0;
+ res_put(zh->res, name, value);
+}
+
+const char *zebra_get_resource(ZebraHandle zh,
+ const char *name, const char *defaultvalue)
+{
+ ASSERTZH;
+ zh->errCode=0;
+ return res_get_def( zh->res, name, (char *)defaultvalue);