Commit 0b5042eecf45a76c17a4c14df21b44fb80e3913b

Thomas de Grivel 2022-12-25T03:59:33

wip facts_save

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);
+}