diff --git a/libc3/facts.c b/libc3/facts.c
index 2d3d1ca..0488356 100644
--- a/libc3/facts.c
+++ b/libc3/facts.c
@@ -282,6 +282,82 @@ e_bool facts_remove_fact (s_facts *facts, const s_fact *fact)
return false;
}
+sw facts_save (s_facts *facts, const s8 *path)
+{
+ s_buf *buf;
+ u64 digest = 0;
+ u64 dump_pos = 0;
+ FILE *fp;
+ u64 log_pos = 0;
+ sw r;
+ sw result = 0;
+ assert(facts);
+ assert(path);
+ assert(! facts->log);
+ buf = buf_new_alloc(1024);
+ if (! (fp = fopen(path, "wb"))) {
+ warn("fopen: %s", path);
+ return -1;
+ }
+ buf_file_open_w(buf, fp);
+ if ((r = facts_save_header(facts, buf, digest, dump_pos,
+ log_pos)) < 0)
+ goto ko;
+ result += r;
+ dump_pos = result;
+ if ((r = facts_dump(facts, buf)) < 0)
+ goto ko;
+ result += r;
+ log_pos = result;
+ buf_flush(buf);
+ fseek(fp, 0, SEEK_SET);
+ if ((r = facts_save_header(facts, buf, digest, dump_pos,
+ log_pos)) < 0)
+ goto ko;
+ buf_flush(buf);
+ fseek(fp, log_pos, SEEK_SET);
+ facts->log = buf;
+ return result;
+ ko:
+ fclose(fp);
+ return r;
+}
+
+sw facts_save_header (const s_facts *facts, s_buf *buf, u64 digest,
+ u64 dump_pos, u64 log_pos)
+{
+ sw r;
+ sw result = 0;
+ if ((r = buf_write_1(buf, "%{count: 0x")) < 0)
+ return r;
+ result += r;
+ if ((r = buf_inspect_u64_hex(buf, facts_count(facts))) < 0)
+ return r;
+ result += r;
+ if ((r = buf_write_1(buf, ",\n digest: 0x")) < 0)
+ return r;
+ result += r;
+ if ((r = buf_inspect_u64_hex(buf, digest)) < 0)
+ return r;
+ result += r;
+ if ((r = buf_write_1(buf, ",\n dump: 0x")) < 0)
+ return r;
+ result += r;
+ if ((r = buf_inspect_u64_hex(buf, dump_pos)) < 0)
+ return r;
+ result += r;
+ if ((r = buf_write_1(buf, ",\n log: 0x")) < 0)
+ return r;
+ result += r;
+ if ((r = buf_inspect_u64_hex(buf, log_pos)) < 0)
+ return r;
+ result += r;
+ if ((r = buf_write_1(buf, "}\n")) < 0)
+ return r;
+ result += r;
+ return result;
+}
+
e_bool facts_unref_tag (s_facts *facts, const s_tag *tag)
{
s_set_item__tag *item;
diff --git a/libc3/facts.h b/libc3/facts.h
index 2b6bf25..e7707fc 100644
--- a/libc3/facts.h
+++ b/libc3/facts.h
@@ -16,6 +16,8 @@
#include "types.h"
+#define facts_count(facts) (facts->facts.count)
+
/* Stack allocation compatible functions */
void facts_clean (s_facts *facts);
s_facts * facts_init (s_facts *facts, s_buf *log);
@@ -34,9 +36,10 @@ s_fact * facts_add_tags (s_facts *facts, const s_tag *subject,
void facts_close (s_facts *facts);
sw facts_load (s_facts *facts, s_buf *buf);
sw facts_load_file (s_facts *facts, const s8 *path);
-sw facts_open (s_facts *facts, const s8 *path);
+sw facts_open_file (s_facts *facts, const s8 *path);
s_tag * facts_ref_tag (s_facts *facts, const s_tag *tag);
e_bool facts_remove_fact (s_facts *facts, const s_fact *fact);
+sw facts_save (s_facts *facts, const s8 *path);
e_bool facts_unref_tag (s_facts *facts, const s_tag *tag);
/* Observers */
@@ -46,6 +49,7 @@ s_fact * facts_find_fact (const s_facts *facts, const s_fact *fact);
s_tag * facts_find_tag (const s_facts *facts, const s_tag *tag);
sw facts_log_add (s_buf *log, const s_fact *fact);
sw facts_log_remove (s_buf *log, const s_fact *fact);
-sw facts_save (s_facts *facts, const s8 *path);
+sw facts_save_header (const s_facts *facts, s_buf *buf,
+ u64 digest, u64 dump_pos, u64 log_pos);
#endif /* FACTS_H */
diff --git a/libc3/hash.c b/libc3/hash.c
index 9b5a015..f4b4b14 100644
--- a/libc3/hash.c
+++ b/libc3/hash.c
@@ -39,3 +39,10 @@ uw hash_result (t_hash_context *context)
SHA1Final(digest, context);
return *((uw *) digest);
}
+
+u64 hash_result_u64 (t_hash_context *context)
+{
+ u8 digest[SHA1_DIGEST_LENGTH];
+ SHA1Final(digest, context);
+ return *((u64 *) digest);
+}
diff --git a/libc3/hash.h b/libc3/hash.h
index f752fb7..e616cdc 100644
--- a/libc3/hash.h
+++ b/libc3/hash.h
@@ -26,5 +26,6 @@ t_hash_context * hash_init (t_hash_context *context);
t_hash_context * hash_update (t_hash_context *context,
const void *data, uw size);
uw hash_result (t_hash_context *context);
+u64 hash_result_u64 (t_hash_context *context);
#endif /* HASH_H */
diff --git a/test/facts_test.c b/test/facts_test.c
index 9bd589b..ca9cfc4 100644
--- a/test/facts_test.c
+++ b/test/facts_test.c
@@ -28,6 +28,7 @@ void facts_test_log_add ();
void facts_test_log_remove ();
void facts_test_new_delete ();
void facts_test_remove ();
+void facts_test_save ();
void facts_test ()
{
@@ -39,6 +40,7 @@ void facts_test ()
facts_test_log_add();
facts_test_log_remove();
facts_test_dump_file();
+ facts_test_save();
}
void facts_test_add ()
@@ -401,3 +403,53 @@ void facts_test_remove ()
}
facts_clean(&facts);
}
+
+void facts_test_save ()
+{
+ uw i = 0;
+ s8 *p[24] = {
+ "\"a\"",
+ ":a",
+ "A",
+ "a",
+ "[]",
+ "[[], []]",
+ "{:a, :b}",
+ "{{:a, :b}, {:c, :d}}",
+ "{a, b}",
+ "{{a, b}, {c, d}}",
+ "0",
+ "1",
+ "10",
+ "0x100",
+ "0x10000",
+ "0x100000000",
+ "0x10000000000000000",
+ "-1",
+ "-10",
+ "-0x100",
+ "-0x10000",
+ "-0x100000000",
+ "-0x10000000000000000",
+ NULL
+ };
+ s_fact fact[24];
+ s_facts facts;
+ facts_init(&facts, NULL);
+ while (p[i]) {
+ fact_test_init_1(fact + i, p[i]);
+ facts_add_fact(&facts, fact + i);
+ i++;
+ }
+ facts_save(&facts, "facts_test_save.facts");
+ test_file_compare("facts_test_save.facts",
+ "facts_test_save.facts.expected");
+ if (g_test_last_ok)
+ unlink("facts_test_save.facts");
+ i = 0;
+ while (p[i]) {
+ fact_test_clean_1(fact + i);
+ i++;
+ }
+ facts_clean(&facts);
+}