diff --git a/.gitmodules b/.gitmodules
index 5d0e411..a71fa1a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -12,3 +12,6 @@
[submodule "markdown/md4c"]
path = markdown/md4c
url = https://git.kmx.io/kc3-lang/md4c.git
+[submodule "libmd"]
+ path = libmd
+ url = https://git.hadrons.org/git/libmd.git
diff --git a/config.subr b/config.subr
index aa910a2..a9468bf 100644
--- a/config.subr
+++ b/config.subr
@@ -150,6 +150,15 @@ config_define() {
echo "#define $1 $2" >> "${CONFIG_H}"
}
+config_have() {
+ if "$2"; then
+ echo "#define HAVE_$1 1" >> "${CONFIG_H}"
+ else
+ echo "#define HAVE_$1 0" >> "${CONFIG_H}"
+ fi
+ eval "HAVE_$1=$2"
+}
+
config_have_bcrypt() {
OUT=".config_have_bcrypt"
OUT_C=".config_have_bcrypt.c"
@@ -193,6 +202,14 @@ config_have_crypt_newhash() {
rm -f "$OUT"
}
+config_have_pthread() {
+ if [ "x$(uname)" = "xDarwin" ]; then
+ config_have PTHREAD false
+ else
+ config_have PTHREAD true
+ fi
+}
+
config_have_stat_mtim() {
OUT=".config_have_stat_mtim"
OUT_C=".config_have_stat_mtim.c"
diff --git a/libkc3/configure b/libkc3/configure
index 5b74099..9510ad8 100755
--- a/libkc3/configure
+++ b/libkc3/configure
@@ -55,6 +55,7 @@ config_include sha1_h sys/types.h sha1.h HAVE_SHA1_H
config_define PREFIX "\"${PREFIX}\""
config_have_crypt_newhash
config_have_stat_mtim
+config_have_pthread
update_config_h
LIBS="$LIBS -lm -lpthread -rpath ${PREFIX}/lib"
diff --git a/libkc3/crypt_sha512.c b/libkc3/crypt_sha512.c
index d3ff2b4..21ba45f 100644
--- a/libkc3/crypt_sha512.c
+++ b/libkc3/crypt_sha512.c
@@ -12,6 +12,7 @@
#include <stdio.h>
#include <string.h>
#include "assert.h"
+#include "explicit_bzero.h"
#include "io.h"
#include "str.h"
#include "types.h"
diff --git a/libkc3/explicit_bzero.h b/libkc3/explicit_bzero.h
new file mode 100644
index 0000000..8662bc2
--- /dev/null
+++ b/libkc3/explicit_bzero.h
@@ -0,0 +1,20 @@
+/* kc3
+ * Copyright 2022,2023,2024 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef KC3_EXPLICIT_BZERO_H
+#define KC3_EXPLICIT_BZERO_H
+
+#ifdef __APPLE__
+# define explicit_bzero(p, size) bzero(p, size)
+#endif
+
+#endif /* KC3_EXPLICIT_BZERO_H */
diff --git a/libkc3/facts.c b/libkc3/facts.c
index e6e2741..3974096 100644
--- a/libkc3/facts.c
+++ b/libkc3/facts.c
@@ -48,29 +48,39 @@ const s_fact * facts_add_fact (s_facts *facts, const s_fact *fact)
s_set_item__fact *item;
assert(facts);
assert(fact);
+#if HAVE_PTHREAD
if (! facts_lock_w(facts))
return NULL;
+#endif
tmp.subject = facts_ref_tag(facts, fact->subject);
if (! tmp.subject) {
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
return NULL;
}
tmp.predicate = facts_ref_tag(facts, fact->predicate);
if (! tmp.predicate) {
facts_unref_tag(facts, tmp.subject);
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
return NULL;
}
tmp.object = facts_ref_tag(facts, fact->object);
if (! tmp.object) {
facts_unref_tag(facts, tmp.subject);
facts_unref_tag(facts, tmp.predicate);
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
return NULL;
}
tmp.id = 0;
if ((item = set_get__fact(&facts->facts, &tmp))) {
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
return &item->data;
}
tmp.id = facts->next_id;
@@ -107,13 +117,17 @@ const s_fact * facts_add_fact (s_facts *facts, const s_fact *fact)
goto ko;
}
facts->next_id++;
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
return f;
ko:
facts_unref_tag(facts, tmp.subject);
facts_unref_tag(facts, tmp.predicate);
facts_unref_tag(facts, tmp.object);
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
return NULL;
}
@@ -136,7 +150,9 @@ void facts_clean (s_facts *facts)
skiplist_delete__fact(facts->index_spo);
set_clean__fact(&facts->facts);
set_clean__tag(&facts->tags);
+#if HAVE_PTHREAD
facts_lock_clean(facts);
+#endif
}
void facts_close (s_facts *facts)
@@ -198,7 +214,9 @@ sw facts_dump (s_facts *facts, s_buf *buf)
" version: 1}\n")) < 0)
return r;
result += r;
+#if HAVE_PTHREAD
facts_lock_r(facts);
+#endif
facts_with_0(facts, &cursor, &subject.data.var, &predicate.data.var,
&object.data.var);
if (! facts_cursor_next(&cursor, &fact))
@@ -218,7 +236,9 @@ sw facts_dump (s_facts *facts, s_buf *buf)
}
r = result;
clean:
+#if HAVE_PTHREAD
facts_lock_unlock_r(facts);
+#endif
return r;
}
@@ -248,8 +268,10 @@ const s_fact ** facts_find_fact (s_facts *facts, const s_fact *fact,
s_set_item__fact *item;
assert(facts);
assert(fact);
+#if HAVE_PTHREAD
if (! facts_lock_r(facts))
return NULL;
+#endif
if (! facts_find_tag(facts, fact->subject, &f.subject))
return NULL;
if (! facts_find_tag(facts, fact->predicate, &f.predicate))
@@ -260,7 +282,9 @@ const s_fact ** facts_find_fact (s_facts *facts, const s_fact *fact,
if (f.subject && f.predicate && f.object &&
(item = set_get__fact((const s_set__fact *) &facts->facts, &f)))
*dest = &item->data;
+#if HAVE_PTHREAD
facts_lock_unlock_r(facts);
+#endif
return dest;
}
@@ -280,12 +304,16 @@ const s_tag ** facts_find_tag (s_facts *facts, const s_tag *tag,
s_set_item__tag *item;
assert(facts);
assert(tag);
+#if HAVE_PTHREAD
if (! facts_lock_r(facts))
return NULL;
+#endif
*dest = NULL;
if ((item = set_get__tag(&facts->tags, tag)))
*dest = &item->data;
+#if HAVE_PTHREAD
facts_lock_unlock_r(facts);
+#endif
return dest;
}
@@ -306,7 +334,9 @@ s_facts * facts_init (s_facts *facts)
tmp.index_osp = skiplist_new__fact(max_height, spacing);
assert(tmp.index_osp);
tmp.index_osp->compare = compare_fact_osp;
+#if HAVE_PTHREAD
facts_lock_init(facts);
+#endif
tmp.next_id = 1;
*facts = tmp;
return facts;
@@ -331,7 +361,9 @@ sw facts_load (s_facts *facts, s_buf *buf, const s_str *path)
return -1;
}
result += r;
+#if HAVE_PTHREAD
facts_lock_w(facts);
+#endif
while (1) {
if ((r = buf_read_1(buf, "replace ")) < 0)
break;
@@ -403,10 +435,14 @@ sw facts_load (s_facts *facts, s_buf *buf, const s_str *path)
fact_w_clean(&fact);
fact_w_clean(&fact_eval);
}
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
return result;
ko:
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
return -1;
}
@@ -429,6 +465,8 @@ sw facts_load_file (s_facts *facts, const s_str *path)
return result;
}
+#if HAVE_PTHREAD
+
s_facts * facts_lock_clean (s_facts *facts)
{
assert(facts);
@@ -552,6 +590,8 @@ s_facts * facts_lock_w (s_facts *facts)
return facts;
}
+#endif /* HAVE_PTHREAD */
+
sw facts_log_add (s_log *log, const s_fact *fact)
{
sw r;
@@ -764,7 +804,9 @@ bool * facts_remove_fact (s_facts *facts, const s_fact *fact,
const s_fact *found;
assert(facts);
assert(fact);
+#if HAVE_PTHREAD
facts_lock_w(facts);
+#endif
if (! facts_find_fact(facts, fact, &found))
return NULL;
*dest = false;
@@ -781,7 +823,9 @@ bool * facts_remove_fact (s_facts *facts, const s_fact *fact,
facts_unref_tag(facts, f.object);
*dest = true;
}
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
return dest;
}
@@ -824,22 +868,30 @@ const s_fact * facts_replace_tags (s_facts *facts, const s_tag *subject,
assert(predicate);
assert(object);
tag_init_var(&var, &g_sym_Tag);
+#if HAVE_PTHREAD
if (! facts_lock_w(facts))
return NULL;
+#endif
if (! facts_with_tags(facts, &cursor, (s_tag *) subject,
(s_tag *) predicate, &var)) {
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
return NULL;
}
if (! facts_cursor_next(&cursor, &fact)) {
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
return NULL;
}
while (fact) {
list = list_new(list);
list->tag.data.fact = *fact;
if (! facts_cursor_next(&cursor, &fact)) {
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
list_delete_all(list);
return NULL;
}
@@ -850,7 +902,9 @@ const s_fact * facts_replace_tags (s_facts *facts, const s_tag *subject,
! b) {
list_delete_all(list);
facts_transaction_rollback(facts, &transaction);
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
return NULL;
}
list = list_delete(list);
@@ -858,7 +912,9 @@ const s_fact * facts_replace_tags (s_facts *facts, const s_tag *subject,
facts_cursor_clean(&cursor);
fact = facts_add_tags(facts, subject, predicate, object);
facts_transaction_end(facts, &transaction);
+#if HAVE_PTHREAD
facts_lock_unlock_w(facts);
+#endif
return fact;
}
diff --git a/libkc3/facts.h b/libkc3/facts.h
index 0be502b..8b34939 100644
--- a/libkc3/facts.h
+++ b/libkc3/facts.h
@@ -14,6 +14,7 @@
#define LIBKC3_FACTS_H
#include "types.h"
+#include "config.h"
#define FACTS_EXT ".facts"
@@ -38,12 +39,14 @@ void facts_close (s_facts *facts);
sw facts_load (s_facts *facts, s_buf *buf,
const s_str *path);
sw facts_load_file (s_facts *facts, const s_str *path);
+#if HAVE_PTHREAD
s_facts * facts_lock_clean (s_facts *facts);
s_facts * facts_lock_init (s_facts *facts);
s_facts * facts_lock_r (s_facts *facts);
s_facts * facts_lock_unlock_r (s_facts *facts);
s_facts * facts_lock_unlock_w (s_facts *facts);
s_facts * facts_lock_w (s_facts *facts);
+#endif
sw facts_open_file (s_facts *facts, const s_str *path);
const s_tag * facts_ref_tag (s_facts *facts, const s_tag *tag);
bool * facts_remove_fact (s_facts *facts, const s_fact *fact,
diff --git a/libkc3/facts_cursor.c b/libkc3/facts_cursor.c
index d683ed1..1e8419c 100644
--- a/libkc3/facts_cursor.c
+++ b/libkc3/facts_cursor.c
@@ -12,6 +12,7 @@
*/
#include <stdlib.h>
#include "assert.h"
+#include "config.h"
#include "facts.h"
#include "facts_cursor.h"
#include "skiplist__fact.h"
@@ -29,7 +30,9 @@ void facts_cursor_clean (s_facts_cursor *cursor)
var_reset(&cursor->var_predicate);
if (cursor->var_object.ptr)
var_reset(&cursor->var_object);
+#if HAVE_PTHREAD
facts_cursor_lock_clean(cursor);
+#endif
}
s_facts_cursor * facts_cursor_init (s_facts *facts,
@@ -63,14 +66,18 @@ s_facts_cursor * facts_cursor_init (s_facts *facts,
tmp.end.object = TAG_LAST;
}
tmp.facts = facts;
+#if HAVE_PTHREAD
if (! facts_cursor_lock_init(&tmp)) {
facts_cursor_clean(&tmp);
return NULL;
}
+#endif
*cursor = tmp;
return cursor;
}
+#if HAVE_PTHREAD
+
s_facts_cursor * facts_cursor_lock (s_facts_cursor *cursor)
{
assert(cursor);
@@ -119,14 +126,18 @@ s_facts_cursor * facts_cursor_lock_unlock (s_facts_cursor *cursor)
return cursor;
}
+#endif /* HAVE_PTHREAD */
+
const s_fact ** facts_cursor_next (s_facts_cursor *cursor,
const s_fact **dest)
{
const s_fact *fact;
const s_sym *type;
assert(cursor);
+#if HAVE_PTHREAD
if (! facts_cursor_lock(cursor))
return NULL;
+#endif
if (cursor->node) {
next:
cursor->node = SKIPLIST_NODE_NEXT__fact(cursor->node, 0);
@@ -141,7 +152,9 @@ const s_fact ** facts_cursor_next (s_facts_cursor *cursor,
var_reset(&cursor->var_predicate);
if (cursor->var_object.ptr)
var_reset(&cursor->var_object);
+#if HAVE_PTHREAD
facts_cursor_lock_unlock(cursor);
+#endif
*dest = NULL;
return dest;
}
@@ -176,7 +189,9 @@ const s_fact ** facts_cursor_next (s_facts_cursor *cursor,
if (! var_set(&cursor->var_object, fact->object))
goto ko;
}
+#if HAVE_PTHREAD
facts_cursor_lock_unlock(cursor);
+#endif
*dest = fact;
return dest;
ko:
@@ -186,6 +201,8 @@ const s_fact ** facts_cursor_next (s_facts_cursor *cursor,
var_reset(&cursor->var_predicate);
if (cursor->var_object.ptr)
var_reset(&cursor->var_object);
+#if HAVE_PTHREAD
facts_cursor_lock_unlock(cursor);
+#endif
return NULL;
}
diff --git a/libkc3/facts_cursor.h b/libkc3/facts_cursor.h
index 1e752ca..347caa8 100644
--- a/libkc3/facts_cursor.h
+++ b/libkc3/facts_cursor.h
@@ -14,6 +14,7 @@
#define LIBKC3_FACTS_CURSOR_H
#include "types.h"
+#include "config.h"
/* Stack allocation compatible functions */
void facts_cursor_clean (s_facts_cursor *cursor);
@@ -24,10 +25,12 @@ s_facts_cursor * facts_cursor_init (s_facts *facts,
s_fact *end);
/* Modifiers */
+#if HAVE_PTHREAD
s_facts_cursor * facts_cursor_lock (s_facts_cursor *cursor);
s_facts_cursor * facts_cursor_lock_clean (s_facts_cursor *cursor);
s_facts_cursor * facts_cursor_lock_init (s_facts_cursor *cursor);
s_facts_cursor * facts_cursor_lock_unlock (s_facts_cursor *cursor);
+#endif
const s_fact ** facts_cursor_next (s_facts_cursor *cursor,
const s_fact **dest);
diff --git a/libkc3/sha1.c b/libkc3/sha1.c
new file mode 100644
index 0000000..247e5d1
--- /dev/null
+++ b/libkc3/sha1.c
@@ -0,0 +1,171 @@
+/* $OpenBSD: sha1.c,v 1.27 2019/06/07 22:56:36 dtucker Exp $ */
+
+/*
+ * SHA-1 in C
+ * By Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
+ *
+ * Test Vectors (from FIPS PUB 180-1)
+ * "abc"
+ * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+ * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+ * A million repetitions of "a"
+ * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+ */
+#include <string.h>
+#include "sha1.h"
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/*
+ * blk0() and blk() perform the initial expand.
+ * I got the idea of expanding during the round function from SSLeay
+ */
+#ifndef WORDS_BIGENDIAN
+# define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#else
+# define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/*
+ * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
+ */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+typedef union {
+ uint8_t c[64];
+ uint32_t l[16];
+} CHAR64LONG16;
+
+/*
+ * Hash a single 512-bit block. This is the core of the algorithm.
+ */
+void
+SHA1Transform(uint32_t state[5], const uint8_t buffer[SHA1_BLOCK_LENGTH])
+{
+ uint32_t a, b, c, d, e;
+ uint8_t workspace[SHA1_BLOCK_LENGTH];
+ CHAR64LONG16 *block = (CHAR64LONG16 *)workspace;
+
+ (void)memcpy(block, buffer, SHA1_BLOCK_LENGTH);
+
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/*
+ * SHA1Init - Initialize new context
+ */
+void
+SHA1Init(SHA1_CTX *context)
+{
+
+ /* SHA1 initialization constants */
+ context->count = 0;
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+}
+
+
+/*
+ * Run your data through this.
+ */
+void
+SHA1Update(SHA1_CTX *context, const uint8_t *data, size_t len)
+{
+ size_t i, j;
+
+ j = (size_t)((context->count >> 3) & 63);
+ context->count += (len << 3);
+ if ((j + len) > 63) {
+ (void)memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64)
+ SHA1Transform(context->state, (uint8_t *)&data[i]);
+ j = 0;
+ } else {
+ i = 0;
+ }
+ (void)memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/*
+ * Add padding and return the message digest.
+ */
+void
+SHA1Pad(SHA1_CTX *context)
+{
+ uint8_t finalcount[8];
+ unsigned int i;
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (uint8_t)((context->count >>
+ ((7 - (i & 7)) * 8)) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (uint8_t *)"\200", 1);
+ while ((context->count & 504) != 448)
+ SHA1Update(context, (uint8_t *)"\0", 1);
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+}
+
+void
+SHA1Final(uint8_t digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context)
+{
+ unsigned int i;
+
+ SHA1Pad(context);
+ for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
+ digest[i] = (uint8_t)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ memset(context, 0, sizeof(*context));
+}
diff --git a/libkc3/sha1.h b/libkc3/sha1.h
index d7db3bc..7d52d27 100644
--- a/libkc3/sha1.h
+++ b/libkc3/sha1.h
@@ -1,30 +1,58 @@
-/* kc3
- * Copyright 2022,2023,2024 kmx.io <contact@kmx.io>
- *
- * Permission is hereby granted to use this software granted the above
- * copyright notice and this permission paragraph are included in all
- * copies and substantial portions of this software.
- *
- * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
- * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
- * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
- * THIS SOFTWARE.
+/* $OpenBSD: sha1.h,v 1.24 2012/12/05 23:19:57 deraadt Exp $ */
+
+/*
+ * SHA-1 in C
+ * By Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
*/
-#ifndef LIBKC3_SHA1_H
-#define LIBKC3_SHA1_H
-
-#include "config.h"
-
-#if HAVE_SHA1_H
-# include <sha1.h>
-#else
-# if HAVE_SHA_H
-# include <sha.h>
-# define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
-# define SHA1Final SHA1_Final
-# define SHA1Init SHA1_Init
-# define SHA1Update SHA1_Update
-# endif
+
+#ifndef _SHA1_H
+#define _SHA1_H
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+#define SHA1_BLOCK_LENGTH 64
+#define SHA1_DIGEST_LENGTH 20
+#define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1)
+
+typedef struct {
+ uint32_t state[5];
+ uint64_t count;
+ uint8_t buffer[SHA1_BLOCK_LENGTH];
+} SHA1_CTX;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void SHA1Init(SHA1_CTX *);
+void SHA1Pad(SHA1_CTX *);
+void SHA1Transform(uint32_t [5], const uint8_t [SHA1_BLOCK_LENGTH]);
+void SHA1Update(SHA1_CTX *, const uint8_t *, size_t);
+void SHA1Final(uint8_t [SHA1_DIGEST_LENGTH], SHA1_CTX *);
+char *SHA1End(SHA1_CTX *, char *);
+char *SHA1File(const char *, char *);
+char *SHA1FileChunk(const char *, char *, off_t, off_t);
+char *SHA1Data(const uint8_t *, size_t, char *);
+
+#ifdef __cplusplus
+}
#endif
-#endif /* LIBKC3_SHA1_H */
+#define HTONDIGEST(x) do { \
+ x[0] = htonl(x[0]); \
+ x[1] = htonl(x[1]); \
+ x[2] = htonl(x[2]); \
+ x[3] = htonl(x[3]); \
+ x[4] = htonl(x[4]); } while (0)
+
+#define NTOHDIGEST(x) do { \
+ x[0] = ntohl(x[0]); \
+ x[1] = ntohl(x[1]); \
+ x[2] = ntohl(x[2]); \
+ x[3] = ntohl(x[3]); \
+ x[4] = ntohl(x[4]); } while (0)
+
+#endif /* _SHA1_H */
diff --git a/libkc3/sources.mk b/libkc3/sources.mk
index 8ed3417..b6599cb 100644
--- a/libkc3/sources.mk
+++ b/libkc3/sources.mk
@@ -92,6 +92,7 @@ HEADERS = \
"error.h" \
"error_handler.h" \
"eval.h" \
+ "explicit_bzero.h" \
"f128.h" \
"f32.h" \
"f64.h" \
@@ -317,6 +318,7 @@ SOURCES = \
"set_item__fact.c" \
"set_item__tag.c" \
"sh.c" \
+ "sha1.c" \
"sign.c" \
"skiplist__fact.c" \
"skiplist_node__fact.c" \
@@ -598,6 +600,7 @@ LO_SOURCES = \
"set_item__fact.c" \
"set_item__tag.c" \
"sh.c" \
+ "sha1.c" \
"sign.c" \
"skiplist__fact.c" \
"skiplist_node__fact.c" \
diff --git a/libkc3/sources.sh b/libkc3/sources.sh
index a497612..55b54bd 100644
--- a/libkc3/sources.sh
+++ b/libkc3/sources.sh
@@ -1,4 +1,4 @@
# sources.sh generated by update_sources
-HEADERS='abs.h alist.h alloc.h arg.h array.h assert.h binding.h block.h bool.h buf.h buf_fd.h buf_file.h buf_getc.h buf_getchar.h buf_inspect.h buf_inspect_s16.h buf_inspect_s16_binary.h buf_inspect_s16_decimal.h buf_inspect_s16_hexadecimal.h buf_inspect_s16_octal.h buf_inspect_s32.h buf_inspect_s32_binary.h buf_inspect_s32_decimal.h buf_inspect_s32_hexadecimal.h buf_inspect_s32_octal.h buf_inspect_s64.h buf_inspect_s64_binary.h buf_inspect_s64_decimal.h buf_inspect_s64_hexadecimal.h buf_inspect_s64_octal.h buf_inspect_s8.h buf_inspect_s8_binary.h buf_inspect_s8_decimal.h buf_inspect_s8_hexadecimal.h buf_inspect_s8_octal.h buf_inspect_sw.h buf_inspect_sw_binary.h buf_inspect_sw_decimal.h buf_inspect_sw_hexadecimal.h buf_inspect_sw_octal.h buf_inspect_u16.h buf_inspect_u16_binary.h buf_inspect_u16_decimal.h buf_inspect_u16_hexadecimal.h buf_inspect_u16_octal.h buf_inspect_u32.h buf_inspect_u32_binary.h buf_inspect_u32_decimal.h buf_inspect_u32_hexadecimal.h buf_inspect_u32_octal.h buf_inspect_u64.h buf_inspect_u64_binary.h buf_inspect_u64_decimal.h buf_inspect_u64_hexadecimal.h buf_inspect_u64_octal.h buf_inspect_u8.h buf_inspect_u8_binary.h buf_inspect_u8_decimal.h buf_inspect_u8_hexadecimal.h buf_inspect_u8_octal.h buf_inspect_uw.h buf_inspect_uw_binary.h buf_inspect_uw_decimal.h buf_inspect_uw_hexadecimal.h buf_inspect_uw_octal.h buf_parse.h buf_parse_s16.h buf_parse_s32.h buf_parse_s64.h buf_parse_s8.h buf_parse_sw.h buf_parse_u16.h buf_parse_u32.h buf_parse_u64.h buf_parse_u8.h buf_parse_uw.h buf_rw.h buf_save.h call.h cast.h ceiling.h cfn.h character.h compare.h complex.h cow.h crypt.h data.h env.h error.h error_handler.h eval.h f128.h f32.h f64.h fact.h fact_action.h fact_list.h facts.h facts_cursor.h facts_spec.h facts_spec_cursor.h facts_transaction.h facts_with.h facts_with_cursor.h fd.h file.h float.h fn.h fn_clause.h frame.h hash.h ident.h inspect.h integer.h io.h kc3.h kc3_main.h list.h list_init.h log.h map.h module.h operator.h pcomplex.h pcow.h pretty.h ptag.h ptr.h ptr_free.h queue.h quote.h ratio.h s16.h s32.h s64.h s8.h sequence.h set__fact.h set__tag.h set_cursor__fact.h set_cursor__tag.h set_item__fact.h set_item__tag.h sh.h sha1.h sign.h skiplist__fact.h skiplist_node__fact.h special_operator.h str.h struct.h struct_type.h sw.h sym.h tag.h tag_init.h tag_type.h time.h to_lisp.h tuple.h types.h u16.h u32.h u64.h u8.h ucd.h unquote.h uw.h var.h void.h '
-SOURCES='abs.c alist.c alloc.c arg.c array.c binding.c block.c bool.c buf.c buf_fd.c buf_file.c buf_getc.c buf_getchar.c buf_inspect.c buf_inspect_s16.c buf_inspect_s16_binary.c buf_inspect_s16_decimal.c buf_inspect_s16_hexadecimal.c buf_inspect_s16_octal.c buf_inspect_s32.c buf_inspect_s32_binary.c buf_inspect_s32_decimal.c buf_inspect_s32_hexadecimal.c buf_inspect_s32_octal.c buf_inspect_s64.c buf_inspect_s64_binary.c buf_inspect_s64_decimal.c buf_inspect_s64_hexadecimal.c buf_inspect_s64_octal.c buf_inspect_s8.c buf_inspect_s8_binary.c buf_inspect_s8_decimal.c buf_inspect_s8_hexadecimal.c buf_inspect_s8_octal.c buf_inspect_sw.c buf_inspect_sw_binary.c buf_inspect_sw_decimal.c buf_inspect_sw_hexadecimal.c buf_inspect_sw_octal.c buf_inspect_u16.c buf_inspect_u16_binary.c buf_inspect_u16_decimal.c buf_inspect_u16_hexadecimal.c buf_inspect_u16_octal.c buf_inspect_u32.c buf_inspect_u32_binary.c buf_inspect_u32_decimal.c buf_inspect_u32_hexadecimal.c buf_inspect_u32_octal.c buf_inspect_u64.c buf_inspect_u64_binary.c buf_inspect_u64_decimal.c buf_inspect_u64_hexadecimal.c buf_inspect_u64_octal.c buf_inspect_u8.c buf_inspect_u8_binary.c buf_inspect_u8_decimal.c buf_inspect_u8_hexadecimal.c buf_inspect_u8_octal.c buf_inspect_uw.c buf_inspect_uw_binary.c buf_inspect_uw_decimal.c buf_inspect_uw_hexadecimal.c buf_inspect_uw_octal.c buf_parse.c buf_parse_s16.c buf_parse_s32.c buf_parse_s64.c buf_parse_s8.c buf_parse_sw.c buf_parse_u16.c buf_parse_u32.c buf_parse_u64.c buf_parse_u8.c buf_parse_uw.c buf_rw.c buf_save.c call.c cast.c ceiling.c cfn.c character.c compare.c complex.c cow.c crypt.c crypt_sha512.c data.c env.c error.c error_handler.c eval.c f128.c f32.c f64.c fact.c fact_action.c fact_list.c facts.c facts_cursor.c facts_spec.c facts_spec_cursor.c facts_transaction.c facts_with.c facts_with_cursor.c fd.c file.c fn.c fn_clause.c frame.c hash.c ident.c inspect.c integer.c io.c kc3.c license.c list.c list_init.c log.c map.c module.c operator.c pcomplex.c pcow.c pretty.c ptag.c ptr.c ptr_free.c queue.c quote.c ratio.c s16.c s32.c s64.c s8.c sequence.c set__fact.c set__tag.c set_cursor__fact.c set_cursor__tag.c set_item__fact.c set_item__tag.c sh.c sign.c skiplist__fact.c skiplist_node__fact.c special_operator.c str.c struct.c struct_type.c sw.c sym.c tag.c tag_add.c tag_addi.c tag_band.c tag_bnot.c tag_bor.c tag_bxor.c tag_div.c tag_init.c tag_mod.c tag_mul.c tag_neg.c tag_shift_left.c tag_shift_right.c tag_sqrt.c tag_sub.c tag_type.c time.c to_lisp.c tuple.c u16.c u32.c u64.c u8.c ucd.c unquote.c uw.c var.c void.c '
-LO_SOURCES=' ../libtommath/bn_cutoffs.c ../libtommath/bn_mp_2expt.c ../libtommath/bn_mp_abs.c ../libtommath/bn_mp_add.c ../libtommath/bn_mp_add_d.c ../libtommath/bn_mp_and.c ../libtommath/bn_mp_clamp.c ../libtommath/bn_mp_clear.c ../libtommath/bn_mp_clear_multi.c ../libtommath/bn_mp_cmp.c ../libtommath/bn_mp_cmp_d.c ../libtommath/bn_mp_cmp_mag.c ../libtommath/bn_mp_cnt_lsb.c ../libtommath/bn_mp_complement.c ../libtommath/bn_mp_copy.c ../libtommath/bn_mp_count_bits.c ../libtommath/bn_mp_div.c ../libtommath/bn_mp_div_2.c ../libtommath/bn_mp_div_2d.c ../libtommath/bn_mp_div_3.c ../libtommath/bn_mp_div_d.c ../libtommath/bn_mp_dr_is_modulus.c ../libtommath/bn_mp_dr_reduce.c ../libtommath/bn_mp_dr_setup.c ../libtommath/bn_mp_error_to_string.c ../libtommath/bn_mp_exch.c ../libtommath/bn_mp_exptmod.c ../libtommath/bn_mp_gcd.c ../libtommath/bn_mp_get_double.c ../libtommath/bn_mp_get_i32.c ../libtommath/bn_mp_get_i64.c ../libtommath/bn_mp_get_mag_u32.c ../libtommath/bn_mp_get_mag_u64.c ../libtommath/bn_mp_grow.c ../libtommath/bn_mp_init.c ../libtommath/bn_mp_init_copy.c ../libtommath/bn_mp_init_multi.c ../libtommath/bn_mp_init_size.c ../libtommath/bn_mp_invmod.c ../libtommath/bn_mp_lcm.c ../libtommath/bn_mp_lshd.c ../libtommath/bn_mp_mod.c ../libtommath/bn_mp_mod_2d.c ../libtommath/bn_mp_montgomery_calc_normalization.c ../libtommath/bn_mp_montgomery_reduce.c ../libtommath/bn_mp_montgomery_setup.c ../libtommath/bn_mp_mul.c ../libtommath/bn_mp_mul_2.c ../libtommath/bn_mp_mul_2d.c ../libtommath/bn_mp_mul_d.c ../libtommath/bn_mp_mulmod.c ../libtommath/bn_mp_neg.c ../libtommath/bn_mp_or.c ../libtommath/bn_mp_radix_size.c ../libtommath/bn_mp_reduce.c ../libtommath/bn_mp_reduce_2k.c ../libtommath/bn_mp_reduce_2k_l.c ../libtommath/bn_mp_reduce_2k_setup.c ../libtommath/bn_mp_reduce_2k_setup_l.c ../libtommath/bn_mp_reduce_is_2k.c ../libtommath/bn_mp_reduce_is_2k_l.c ../libtommath/bn_mp_reduce_setup.c ../libtommath/bn_mp_rshd.c ../libtommath/bn_mp_set.c ../libtommath/bn_mp_set_double.c ../libtommath/bn_mp_set_i32.c ../libtommath/bn_mp_set_i64.c ../libtommath/bn_mp_set_l.c ../libtommath/bn_mp_set_u32.c ../libtommath/bn_mp_set_u64.c ../libtommath/bn_mp_set_ul.c ../libtommath/bn_mp_sqr.c ../libtommath/bn_mp_sqrt.c ../libtommath/bn_mp_sub.c ../libtommath/bn_mp_sub_d.c ../libtommath/bn_mp_xor.c ../libtommath/bn_mp_zero.c ../libtommath/bn_s_mp_add.c ../libtommath/bn_s_mp_balance_mul.c ../libtommath/bn_s_mp_exptmod.c ../libtommath/bn_s_mp_exptmod_fast.c ../libtommath/bn_s_mp_invmod_fast.c ../libtommath/bn_s_mp_invmod_slow.c ../libtommath/bn_s_mp_karatsuba_mul.c ../libtommath/bn_s_mp_karatsuba_sqr.c ../libtommath/bn_s_mp_montgomery_reduce_fast.c ../libtommath/bn_s_mp_mul_digs.c ../libtommath/bn_s_mp_mul_digs_fast.c ../libtommath/bn_s_mp_mul_high_digs.c ../libtommath/bn_s_mp_mul_high_digs_fast.c ../libtommath/bn_s_mp_rand_platform.c ../libtommath/bn_s_mp_sqr.c ../libtommath/bn_s_mp_sqr_fast.c ../libtommath/bn_s_mp_sub.c ../libtommath/bn_s_mp_toom_mul.c ../libtommath/bn_s_mp_toom_sqr.c abs.c alist.c alloc.c arg.c array.c binding.c block.c bool.c buf.c buf_fd.c buf_file.c buf_getc.c buf_getchar.c buf_inspect.c buf_inspect_s16.c buf_inspect_s16_binary.c buf_inspect_s16_decimal.c buf_inspect_s16_hexadecimal.c buf_inspect_s16_octal.c buf_inspect_s32.c buf_inspect_s32_binary.c buf_inspect_s32_decimal.c buf_inspect_s32_hexadecimal.c buf_inspect_s32_octal.c buf_inspect_s64.c buf_inspect_s64_binary.c buf_inspect_s64_decimal.c buf_inspect_s64_hexadecimal.c buf_inspect_s64_octal.c buf_inspect_s8.c buf_inspect_s8_binary.c buf_inspect_s8_decimal.c buf_inspect_s8_hexadecimal.c buf_inspect_s8_octal.c buf_inspect_sw.c buf_inspect_sw_binary.c buf_inspect_sw_decimal.c buf_inspect_sw_hexadecimal.c buf_inspect_sw_octal.c buf_inspect_u16.c buf_inspect_u16_binary.c buf_inspect_u16_decimal.c buf_inspect_u16_hexadecimal.c buf_inspect_u16_octal.c buf_inspect_u32.c buf_inspect_u32_binary.c buf_inspect_u32_decimal.c buf_inspect_u32_hexadecimal.c buf_inspect_u32_octal.c buf_inspect_u64.c buf_inspect_u64_binary.c buf_inspect_u64_decimal.c buf_inspect_u64_hexadecimal.c buf_inspect_u64_octal.c buf_inspect_u8.c buf_inspect_u8_binary.c buf_inspect_u8_decimal.c buf_inspect_u8_hexadecimal.c buf_inspect_u8_octal.c buf_inspect_uw.c buf_inspect_uw_binary.c buf_inspect_uw_decimal.c buf_inspect_uw_hexadecimal.c buf_inspect_uw_octal.c buf_parse.c buf_parse_s16.c buf_parse_s32.c buf_parse_s64.c buf_parse_s8.c buf_parse_sw.c buf_parse_u16.c buf_parse_u32.c buf_parse_u64.c buf_parse_u8.c buf_parse_uw.c buf_rw.c buf_save.c call.c cast.c ceiling.c cfn.c character.c compare.c complex.c cow.c crypt.c crypt_sha512.c data.c env.c error.c error_handler.c eval.c f128.c f32.c f64.c fact.c fact_action.c fact_list.c facts.c facts_cursor.c facts_spec.c facts_spec_cursor.c facts_transaction.c facts_with.c facts_with_cursor.c fd.c file.c fn.c fn_clause.c frame.c hash.c ident.c inspect.c integer.c io.c kc3.c license.c list.c list_init.c log.c map.c module.c operator.c pcomplex.c pcow.c pretty.c ptag.c ptr.c ptr_free.c queue.c quote.c ratio.c s16.c s32.c s64.c s8.c sequence.c set__fact.c set__tag.c set_cursor__fact.c set_cursor__tag.c set_item__fact.c set_item__tag.c sh.c sign.c skiplist__fact.c skiplist_node__fact.c special_operator.c str.c struct.c struct_type.c sw.c sym.c tag.c tag_add.c tag_addi.c tag_band.c tag_bnot.c tag_bor.c tag_bxor.c tag_div.c tag_init.c tag_mod.c tag_mul.c tag_neg.c tag_shift_left.c tag_shift_right.c tag_sqrt.c tag_sub.c tag_type.c time.c to_lisp.c tuple.c u16.c u32.c u64.c u8.c ucd.c unquote.c uw.c var.c void.c '
+HEADERS='abs.h alist.h alloc.h arg.h array.h assert.h binding.h block.h bool.h buf.h buf_fd.h buf_file.h buf_getc.h buf_getchar.h buf_inspect.h buf_inspect_s16.h buf_inspect_s16_binary.h buf_inspect_s16_decimal.h buf_inspect_s16_hexadecimal.h buf_inspect_s16_octal.h buf_inspect_s32.h buf_inspect_s32_binary.h buf_inspect_s32_decimal.h buf_inspect_s32_hexadecimal.h buf_inspect_s32_octal.h buf_inspect_s64.h buf_inspect_s64_binary.h buf_inspect_s64_decimal.h buf_inspect_s64_hexadecimal.h buf_inspect_s64_octal.h buf_inspect_s8.h buf_inspect_s8_binary.h buf_inspect_s8_decimal.h buf_inspect_s8_hexadecimal.h buf_inspect_s8_octal.h buf_inspect_sw.h buf_inspect_sw_binary.h buf_inspect_sw_decimal.h buf_inspect_sw_hexadecimal.h buf_inspect_sw_octal.h buf_inspect_u16.h buf_inspect_u16_binary.h buf_inspect_u16_decimal.h buf_inspect_u16_hexadecimal.h buf_inspect_u16_octal.h buf_inspect_u32.h buf_inspect_u32_binary.h buf_inspect_u32_decimal.h buf_inspect_u32_hexadecimal.h buf_inspect_u32_octal.h buf_inspect_u64.h buf_inspect_u64_binary.h buf_inspect_u64_decimal.h buf_inspect_u64_hexadecimal.h buf_inspect_u64_octal.h buf_inspect_u8.h buf_inspect_u8_binary.h buf_inspect_u8_decimal.h buf_inspect_u8_hexadecimal.h buf_inspect_u8_octal.h buf_inspect_uw.h buf_inspect_uw_binary.h buf_inspect_uw_decimal.h buf_inspect_uw_hexadecimal.h buf_inspect_uw_octal.h buf_parse.h buf_parse_s16.h buf_parse_s32.h buf_parse_s64.h buf_parse_s8.h buf_parse_sw.h buf_parse_u16.h buf_parse_u32.h buf_parse_u64.h buf_parse_u8.h buf_parse_uw.h buf_rw.h buf_save.h call.h cast.h ceiling.h cfn.h character.h compare.h complex.h cow.h crypt.h data.h env.h error.h error_handler.h eval.h explicit_bzero.h f128.h f32.h f64.h fact.h fact_action.h fact_list.h facts.h facts_cursor.h facts_spec.h facts_spec_cursor.h facts_transaction.h facts_with.h facts_with_cursor.h fd.h file.h float.h fn.h fn_clause.h frame.h hash.h ident.h inspect.h integer.h io.h kc3.h kc3_main.h list.h list_init.h log.h map.h module.h operator.h pcomplex.h pcow.h pretty.h ptag.h ptr.h ptr_free.h queue.h quote.h ratio.h s16.h s32.h s64.h s8.h sequence.h set__fact.h set__tag.h set_cursor__fact.h set_cursor__tag.h set_item__fact.h set_item__tag.h sh.h sha1.h sign.h skiplist__fact.h skiplist_node__fact.h special_operator.h str.h struct.h struct_type.h sw.h sym.h tag.h tag_init.h tag_type.h time.h to_lisp.h tuple.h types.h u16.h u32.h u64.h u8.h ucd.h unquote.h uw.h var.h void.h '
+SOURCES='abs.c alist.c alloc.c arg.c array.c binding.c block.c bool.c buf.c buf_fd.c buf_file.c buf_getc.c buf_getchar.c buf_inspect.c buf_inspect_s16.c buf_inspect_s16_binary.c buf_inspect_s16_decimal.c buf_inspect_s16_hexadecimal.c buf_inspect_s16_octal.c buf_inspect_s32.c buf_inspect_s32_binary.c buf_inspect_s32_decimal.c buf_inspect_s32_hexadecimal.c buf_inspect_s32_octal.c buf_inspect_s64.c buf_inspect_s64_binary.c buf_inspect_s64_decimal.c buf_inspect_s64_hexadecimal.c buf_inspect_s64_octal.c buf_inspect_s8.c buf_inspect_s8_binary.c buf_inspect_s8_decimal.c buf_inspect_s8_hexadecimal.c buf_inspect_s8_octal.c buf_inspect_sw.c buf_inspect_sw_binary.c buf_inspect_sw_decimal.c buf_inspect_sw_hexadecimal.c buf_inspect_sw_octal.c buf_inspect_u16.c buf_inspect_u16_binary.c buf_inspect_u16_decimal.c buf_inspect_u16_hexadecimal.c buf_inspect_u16_octal.c buf_inspect_u32.c buf_inspect_u32_binary.c buf_inspect_u32_decimal.c buf_inspect_u32_hexadecimal.c buf_inspect_u32_octal.c buf_inspect_u64.c buf_inspect_u64_binary.c buf_inspect_u64_decimal.c buf_inspect_u64_hexadecimal.c buf_inspect_u64_octal.c buf_inspect_u8.c buf_inspect_u8_binary.c buf_inspect_u8_decimal.c buf_inspect_u8_hexadecimal.c buf_inspect_u8_octal.c buf_inspect_uw.c buf_inspect_uw_binary.c buf_inspect_uw_decimal.c buf_inspect_uw_hexadecimal.c buf_inspect_uw_octal.c buf_parse.c buf_parse_s16.c buf_parse_s32.c buf_parse_s64.c buf_parse_s8.c buf_parse_sw.c buf_parse_u16.c buf_parse_u32.c buf_parse_u64.c buf_parse_u8.c buf_parse_uw.c buf_rw.c buf_save.c call.c cast.c ceiling.c cfn.c character.c compare.c complex.c cow.c crypt.c crypt_sha512.c data.c env.c error.c error_handler.c eval.c f128.c f32.c f64.c fact.c fact_action.c fact_list.c facts.c facts_cursor.c facts_spec.c facts_spec_cursor.c facts_transaction.c facts_with.c facts_with_cursor.c fd.c file.c fn.c fn_clause.c frame.c hash.c ident.c inspect.c integer.c io.c kc3.c license.c list.c list_init.c log.c map.c module.c operator.c pcomplex.c pcow.c pretty.c ptag.c ptr.c ptr_free.c queue.c quote.c ratio.c s16.c s32.c s64.c s8.c sequence.c set__fact.c set__tag.c set_cursor__fact.c set_cursor__tag.c set_item__fact.c set_item__tag.c sh.c sha1.c sign.c skiplist__fact.c skiplist_node__fact.c special_operator.c str.c struct.c struct_type.c sw.c sym.c tag.c tag_add.c tag_addi.c tag_band.c tag_bnot.c tag_bor.c tag_bxor.c tag_div.c tag_init.c tag_mod.c tag_mul.c tag_neg.c tag_shift_left.c tag_shift_right.c tag_sqrt.c tag_sub.c tag_type.c time.c to_lisp.c tuple.c u16.c u32.c u64.c u8.c ucd.c unquote.c uw.c var.c void.c '
+LO_SOURCES=' ../libtommath/bn_cutoffs.c ../libtommath/bn_mp_2expt.c ../libtommath/bn_mp_abs.c ../libtommath/bn_mp_add.c ../libtommath/bn_mp_add_d.c ../libtommath/bn_mp_and.c ../libtommath/bn_mp_clamp.c ../libtommath/bn_mp_clear.c ../libtommath/bn_mp_clear_multi.c ../libtommath/bn_mp_cmp.c ../libtommath/bn_mp_cmp_d.c ../libtommath/bn_mp_cmp_mag.c ../libtommath/bn_mp_cnt_lsb.c ../libtommath/bn_mp_complement.c ../libtommath/bn_mp_copy.c ../libtommath/bn_mp_count_bits.c ../libtommath/bn_mp_div.c ../libtommath/bn_mp_div_2.c ../libtommath/bn_mp_div_2d.c ../libtommath/bn_mp_div_3.c ../libtommath/bn_mp_div_d.c ../libtommath/bn_mp_dr_is_modulus.c ../libtommath/bn_mp_dr_reduce.c ../libtommath/bn_mp_dr_setup.c ../libtommath/bn_mp_error_to_string.c ../libtommath/bn_mp_exch.c ../libtommath/bn_mp_exptmod.c ../libtommath/bn_mp_gcd.c ../libtommath/bn_mp_get_double.c ../libtommath/bn_mp_get_i32.c ../libtommath/bn_mp_get_i64.c ../libtommath/bn_mp_get_mag_u32.c ../libtommath/bn_mp_get_mag_u64.c ../libtommath/bn_mp_grow.c ../libtommath/bn_mp_init.c ../libtommath/bn_mp_init_copy.c ../libtommath/bn_mp_init_multi.c ../libtommath/bn_mp_init_size.c ../libtommath/bn_mp_invmod.c ../libtommath/bn_mp_lcm.c ../libtommath/bn_mp_lshd.c ../libtommath/bn_mp_mod.c ../libtommath/bn_mp_mod_2d.c ../libtommath/bn_mp_montgomery_calc_normalization.c ../libtommath/bn_mp_montgomery_reduce.c ../libtommath/bn_mp_montgomery_setup.c ../libtommath/bn_mp_mul.c ../libtommath/bn_mp_mul_2.c ../libtommath/bn_mp_mul_2d.c ../libtommath/bn_mp_mul_d.c ../libtommath/bn_mp_mulmod.c ../libtommath/bn_mp_neg.c ../libtommath/bn_mp_or.c ../libtommath/bn_mp_radix_size.c ../libtommath/bn_mp_reduce.c ../libtommath/bn_mp_reduce_2k.c ../libtommath/bn_mp_reduce_2k_l.c ../libtommath/bn_mp_reduce_2k_setup.c ../libtommath/bn_mp_reduce_2k_setup_l.c ../libtommath/bn_mp_reduce_is_2k.c ../libtommath/bn_mp_reduce_is_2k_l.c ../libtommath/bn_mp_reduce_setup.c ../libtommath/bn_mp_rshd.c ../libtommath/bn_mp_set.c ../libtommath/bn_mp_set_double.c ../libtommath/bn_mp_set_i32.c ../libtommath/bn_mp_set_i64.c ../libtommath/bn_mp_set_l.c ../libtommath/bn_mp_set_u32.c ../libtommath/bn_mp_set_u64.c ../libtommath/bn_mp_set_ul.c ../libtommath/bn_mp_sqr.c ../libtommath/bn_mp_sqrt.c ../libtommath/bn_mp_sub.c ../libtommath/bn_mp_sub_d.c ../libtommath/bn_mp_xor.c ../libtommath/bn_mp_zero.c ../libtommath/bn_s_mp_add.c ../libtommath/bn_s_mp_balance_mul.c ../libtommath/bn_s_mp_exptmod.c ../libtommath/bn_s_mp_exptmod_fast.c ../libtommath/bn_s_mp_invmod_fast.c ../libtommath/bn_s_mp_invmod_slow.c ../libtommath/bn_s_mp_karatsuba_mul.c ../libtommath/bn_s_mp_karatsuba_sqr.c ../libtommath/bn_s_mp_montgomery_reduce_fast.c ../libtommath/bn_s_mp_mul_digs.c ../libtommath/bn_s_mp_mul_digs_fast.c ../libtommath/bn_s_mp_mul_high_digs.c ../libtommath/bn_s_mp_mul_high_digs_fast.c ../libtommath/bn_s_mp_rand_platform.c ../libtommath/bn_s_mp_sqr.c ../libtommath/bn_s_mp_sqr_fast.c ../libtommath/bn_s_mp_sub.c ../libtommath/bn_s_mp_toom_mul.c ../libtommath/bn_s_mp_toom_sqr.c abs.c alist.c alloc.c arg.c array.c binding.c block.c bool.c buf.c buf_fd.c buf_file.c buf_getc.c buf_getchar.c buf_inspect.c buf_inspect_s16.c buf_inspect_s16_binary.c buf_inspect_s16_decimal.c buf_inspect_s16_hexadecimal.c buf_inspect_s16_octal.c buf_inspect_s32.c buf_inspect_s32_binary.c buf_inspect_s32_decimal.c buf_inspect_s32_hexadecimal.c buf_inspect_s32_octal.c buf_inspect_s64.c buf_inspect_s64_binary.c buf_inspect_s64_decimal.c buf_inspect_s64_hexadecimal.c buf_inspect_s64_octal.c buf_inspect_s8.c buf_inspect_s8_binary.c buf_inspect_s8_decimal.c buf_inspect_s8_hexadecimal.c buf_inspect_s8_octal.c buf_inspect_sw.c buf_inspect_sw_binary.c buf_inspect_sw_decimal.c buf_inspect_sw_hexadecimal.c buf_inspect_sw_octal.c buf_inspect_u16.c buf_inspect_u16_binary.c buf_inspect_u16_decimal.c buf_inspect_u16_hexadecimal.c buf_inspect_u16_octal.c buf_inspect_u32.c buf_inspect_u32_binary.c buf_inspect_u32_decimal.c buf_inspect_u32_hexadecimal.c buf_inspect_u32_octal.c buf_inspect_u64.c buf_inspect_u64_binary.c buf_inspect_u64_decimal.c buf_inspect_u64_hexadecimal.c buf_inspect_u64_octal.c buf_inspect_u8.c buf_inspect_u8_binary.c buf_inspect_u8_decimal.c buf_inspect_u8_hexadecimal.c buf_inspect_u8_octal.c buf_inspect_uw.c buf_inspect_uw_binary.c buf_inspect_uw_decimal.c buf_inspect_uw_hexadecimal.c buf_inspect_uw_octal.c buf_parse.c buf_parse_s16.c buf_parse_s32.c buf_parse_s64.c buf_parse_s8.c buf_parse_sw.c buf_parse_u16.c buf_parse_u32.c buf_parse_u64.c buf_parse_u8.c buf_parse_uw.c buf_rw.c buf_save.c call.c cast.c ceiling.c cfn.c character.c compare.c complex.c cow.c crypt.c crypt_sha512.c data.c env.c error.c error_handler.c eval.c f128.c f32.c f64.c fact.c fact_action.c fact_list.c facts.c facts_cursor.c facts_spec.c facts_spec_cursor.c facts_transaction.c facts_with.c facts_with_cursor.c fd.c file.c fn.c fn_clause.c frame.c hash.c ident.c inspect.c integer.c io.c kc3.c license.c list.c list_init.c log.c map.c module.c operator.c pcomplex.c pcow.c pretty.c ptag.c ptr.c ptr_free.c queue.c quote.c ratio.c s16.c s32.c s64.c s8.c sequence.c set__fact.c set__tag.c set_cursor__fact.c set_cursor__tag.c set_item__fact.c set_item__tag.c sh.c sha1.c sign.c skiplist__fact.c skiplist_node__fact.c special_operator.c str.c struct.c struct_type.c sw.c sym.c tag.c tag_add.c tag_addi.c tag_band.c tag_bnot.c tag_bor.c tag_bxor.c tag_div.c tag_init.c tag_mod.c tag_mul.c tag_neg.c tag_shift_left.c tag_shift_right.c tag_sqrt.c tag_sub.c tag_type.c time.c to_lisp.c tuple.c u16.c u32.c u64.c u8.c ucd.c unquote.c uw.c var.c void.c '
diff --git a/libkc3/tag.c b/libkc3/tag.c
index dbfc6e7..32e737a 100644
--- a/libkc3/tag.c
+++ b/libkc3/tag.c
@@ -25,6 +25,7 @@
#include "compare.h"
#include "cow.h"
#include "env.h"
+#include "explicit_bzero.h"
#include "fn.h"
#include "frame.h"
#include "hash.h"
@@ -49,10 +50,6 @@
#include "unquote.h"
#include "var.h"
-#ifdef __APPLE__
-# define explicit_bzero(p, size) bzero(p, size)
-#endif
-
s_tag g_tag_first;
s_tag g_tag_last;
diff --git a/libmd b/libmd
new file mode 160000
index 0000000..d5b8e85
--- /dev/null
+++ b/libmd
@@ -0,0 +1 @@
+Subproject commit d5b8e853989a73f8fff9dc4e00dccd0b691b84f9