#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nfs_iio.h"
#include "nfs_pmatch.h"
#include "nfs_dt.h"
typedef struct _nfs_dt_TrieNode {
unsigned short nt_index;
short bindex;
int kindex;
int left;
int right;
} nfs_dt_TrieNode;
#define nfs_dt_MAX_SKN_SIZE 60
#ifdef nfs_dt_MAX_SUBNAME_SIZE
#undef nfs_dt_MAX_SUBNAME_SIZE
#define nfs_dt_MAX_SUBNAME_SIZE 4096
#endif
typedef struct _nfs_dt_KeyNode {
int next;
char name [nfs_dt_MAX_SKN_SIZE];
} nfs_dt_KeyNode;
static char* find_prefix(char* s, char* buffer) {
int idx = 0;
while ( (s[idx] != 0) &&
(s[idx] != '*') &&
(s[idx] != '?') &&
(s[idx] != '[') ) {
buffer[idx] = s[idx];
idx++;
}
buffer[idx] = 0;
return buffer;
}
static int trienode_get(nfs_dt_DT* dt, int node, nfs_dt_TrieNode* n) {
nfs_iio_seek(dt->file, dt->channel1, node * sizeof(nfs_dt_TrieNode));
return nfs_iio_read(dt->file, dt->channel1, n, sizeof(nfs_dt_TrieNode));
}
static int keynode_get(nfs_dt_DT* dt, int node, nfs_dt_KeyNode* n) {
nfs_iio_seek(dt->file, dt->channel2, node * sizeof(nfs_dt_KeyNode));
return nfs_iio_read(dt->file, dt->channel2, n, sizeof(nfs_dt_KeyNode));
}
static int trienode_get_nt(nfs_dt_DT* dt, int node) {
int r;
unsigned short kk;
nfs_iio_seek(dt->file, dt->channel1,
node * sizeof(nfs_dt_TrieNode));
r = nfs_iio_read(dt->file, dt->channel1, &kk, sizeof(unsigned short));
return ((r < sizeof(unsigned short)) ? 0 : (int)kk);
}
static int trienode_get_left(nfs_dt_DT* dt, int node) {
int kk, r;
nfs_iio_seek(dt->file, dt->channel1,
node * sizeof(nfs_dt_TrieNode) +
(2 * sizeof(int))
);
r = nfs_iio_read(dt->file, dt->channel1, &kk, sizeof(int));
return ((r < sizeof(int)) ? 0 : kk);
}
static int trienode_get_right(nfs_dt_DT* dt, int node) {
int kk, r;
nfs_iio_seek(dt->file, dt->channel1,
node * sizeof(nfs_dt_TrieNode) +
(3 * sizeof(int))
);
r = nfs_iio_read(dt->file, dt->channel1, &kk, sizeof(int));
return ((r < sizeof(int)) ? 0 : kk);
}
static int trienode_get_bindex(nfs_dt_DT* dt, int node) {
short kk, r;
nfs_iio_seek(dt->file, dt->channel1,
node * sizeof(nfs_dt_TrieNode) +
(sizeof(short)
));
r = nfs_iio_read(dt->file, dt->channel1, &kk, sizeof(short));
return ((r < sizeof(short)) ? 0 : ((int)kk));
}
static int trienode_get_kindex(nfs_dt_DT* dt, int node) {
int kk, r;
nfs_iio_seek(dt->file, dt->channel1,
node * sizeof(nfs_dt_TrieNode) +
(sizeof(int)
));
r = nfs_iio_read(dt->file, dt->channel1, &kk, sizeof(int));
return ((r < sizeof(int)) ? 0 : (kk & 0x7fffffff));
}
static int trienode_is_free(nfs_dt_DT* dt, int node) {
nfs_dt_TrieNode ni;
int k;
if (node == 0)
return 0;
k = trienode_get(dt, node, &ni);
if (k < 0)
return 0;
return ((ni.kindex & 0x80000000) == 0);
}
static int keynode_is_free(nfs_dt_DT* dt, int node) {
nfs_dt_KeyNode ni;
int k;
if (node == 0)
return 0;
k = keynode_get(dt, node, &ni);
if (k < 0)
return 0;
return ((ni.next & 0x80000000) == 0);
}
static int trienode_set(nfs_dt_DT* dt, int node, nfs_dt_TrieNode* n) {
nfs_iio_seek(dt->file, dt->channel1, node * sizeof(nfs_dt_TrieNode));
return nfs_iio_write(dt->file, dt->channel1, n, sizeof(nfs_dt_TrieNode));
}
static int keynode_set(nfs_dt_DT* dt, int node, nfs_dt_KeyNode* n) {
nfs_iio_seek(dt->file, dt->channel2, node * sizeof(nfs_dt_KeyNode));
return nfs_iio_write(dt->file, dt->channel2, n, sizeof(nfs_dt_KeyNode));
}
static int trienode_set_nt(nfs_dt_DT* dt, int node, int nt) {
unsigned short kk = (unsigned short)nt;
nfs_iio_seek(dt->file, dt->channel1,
node * sizeof(nfs_dt_TrieNode));
return nfs_iio_write(dt->file, dt->channel1, &kk, sizeof(unsigned short));
}
static int trienode_set_left(nfs_dt_DT* dt, int node, int left) {
int kk = left;
nfs_iio_seek(dt->file, dt->channel1,
node * sizeof(nfs_dt_TrieNode) +
(sizeof(int) +
sizeof(int)
));
return nfs_iio_write(dt->file, dt->channel1, &kk, sizeof(int));
}
static int trienode_set_right(nfs_dt_DT* dt, int node, int right) {
int kk = right;
nfs_iio_seek(dt->file, dt->channel1,
node * sizeof(nfs_dt_TrieNode) +
(sizeof(int) +
sizeof(int) +
sizeof(int)
));
return nfs_iio_write(dt->file, dt->channel1, &kk, sizeof(int));
}
#ifdef UNUSED
static int trienode_set_bindex(nfs_dt_DT* dt, int node, int bindex) {
short kk = (short)bindex;
nfs_iio_seek(dt->file, dt->channel1,
node * sizeof(nfs_dt_TrieNode) +
(sizeof(unsigned short)
));
return nfs_iio_write(dt->file, dt->channel1, &kk, sizeof(short));
}
#endif
#ifdef UNUSED
static int trienode_set_kindex(nfs_dt_DT* dt, int node, int kindex) {
int kk = kindex | 0x80000000;
nfs_iio_seek(dt->file, dt->channel1,
node * sizeof(nfs_dt_TrieNode) +
(sizeof(int)
));
return nfs_iio_write(dt->file, dt->channel1, &kk, sizeof(int));
}
#endif
static int trienode_clear(nfs_dt_DT* dt, int node) {
nfs_dt_TrieNode ni;
ni.nt_index = 0;
ni.bindex = 0;
ni.kindex = 0;
ni.left = node;
ni.right = node;
return trienode_set(dt, node, &ni);
}
static int keynode_clear(nfs_dt_DT* dt, int node) {
nfs_dt_KeyNode ni;
memset(&ni, 0, sizeof(ni));
ni.next = 0;
ni.name[0] = 0;
return keynode_set(dt, node, &ni);
}
static int fnode_free(nfs_dt_DT* dt, int start) {
int next = start;
int k;
nfs_dt_KeyNode kn;
while (next != 0) {
k = next;
keynode_get(dt, k, &kn);
next = kn.next & 0x7fffffff;
keynode_clear(dt, k);
if (k < dt->unallocated2)
dt->unallocated2 = k;
}
return 0;
}
static int keynode_find_first_free(nfs_dt_DT* dt, int start);
static int fnode_allocate(nfs_dt_DT* dt, char* key) {
int keynodes[1024];
int nr_keynodes;
int klen, i;
nfs_dt_KeyNode kn;
klen = strlen(key);
nr_keynodes = 1 + (klen / nfs_dt_MAX_SKN_SIZE);
i = 0;
while (i < nr_keynodes) {
keynodes[i] = dt->unallocated2;
dt->unallocated2 = keynode_find_first_free(dt, dt->unallocated2 + 1);
i++;
}
for (i = 0; i < nr_keynodes; i++) {
if (i == (nr_keynodes - 1))
kn.next = 0x80000000;
else
kn.next = 0x80000000 | keynodes[i+1];
strncpy(kn.name, (char*)key + i * nfs_dt_MAX_SKN_SIZE, nfs_dt_MAX_SKN_SIZE);
keynode_set(dt, keynodes[i], &kn);
}
return keynodes[0];
}
static int node_copy_key(nfs_dt_DT* dt, int from, int to) {
nfs_dt_TrieNode tn1, tn2;
int old_kn2;
trienode_get (dt, from, &tn1);
trienode_get (dt, to, &tn2);
old_kn2 = tn2.kindex & 0x7fffffff;
tn2.nt_index = tn1.nt_index;
tn2.kindex = tn1.kindex;
trienode_set(dt, to, &tn2);
fnode_free(dt, old_kn2);
return 0;
}
static int fnode_extract_key(nfs_dt_DT* dt, int node, char* key) {
register int i, j;
int k, next;
nfs_dt_KeyNode kn;
i = 0;
next = node;
while (next > 0) {
k = next;
keynode_get(dt, k, &kn);
j = 0;
while ((j < nfs_dt_MAX_SKN_SIZE) && (kn.name[j] != 0))
key[i++] = kn.name[j++];
next = (kn.next & 0x7fffffff);
}
key[i] = 0;
return 0;
}
static int trienode_find_first_free(nfs_dt_DT* dt, int start) {
int index = (start - 1);
do { ++index; } while (!trienode_is_free(dt, index) || (index <= 0));
return index;
}
static int keynode_find_first_free(nfs_dt_DT* dt, int start) {
int index = (start - 1);
do { ++index; } while (!keynode_is_free(dt, index) || (index <= 0));
return index;
}
#ifdef UNUSED
static int node_recover(nfs_dt_DT* dt, int node_idx) {
int kidx;
kidx = trienode_get_kindex(dt, node_idx);
trienode_clear(dt, node_idx);
keynode_clear(dt, kidx);
if (node_idx < dt->unallocated)
dt->unallocated = node_idx;
if (kidx < dt->unallocated2)
dt->unallocated2 = kidx;
return 0;
}
#endif
static int trienode_recover(nfs_dt_DT* dt, int node_idx) {
trienode_clear(dt, node_idx);
if (node_idx < dt->unallocated)
dt->unallocated = node_idx;
return 0;
}
static int node_allocate(nfs_dt_DT* dt, char* filename, int nt_index, int bindex) {
int keynode, trienode;
nfs_dt_TrieNode tn;
keynode = fnode_allocate(dt, filename);
trienode = dt->unallocated;
tn.nt_index = nt_index;
tn.bindex = bindex;
tn.kindex = keynode | 0x80000000;
tn.left = 0;
tn.right = 0;
trienode_set(dt, trienode, &tn);
dt->unallocated = trienode_find_first_free(dt, dt->unallocated);
return trienode;
}
static int bit_get(char* bit_stream, int n) {
int k = (n & 0x7);
if (n < 0) return 2;
return ( (*(bit_stream + (n >> 3))) >> k) & 0x1;
}
static int bit_first_different(char* bit_stream1, char* bit_stream2) {
int n = 0;
int d = 0;
while ( (bit_stream1[n] == bit_stream2[n]) &&
(bit_stream1[n] != 0) &&
(bit_stream2[n] != 0) )
n++;
while (bit_get(&bit_stream1[n], d) == bit_get(&bit_stream2[n], d))
d++;
return ((n << 3) + d);
}
static int p_init_head(nfs_dt_DT* dt) {
nfs_dt_TrieNode tn;
nfs_dt_KeyNode kn;
kn.next = 0x80000000;
kn.name[0] = '.';
kn.name[1] = 0;
tn.nt_index = 0;
tn.bindex = -1;
tn.kindex = 0x80000000;
tn.left = 0;
tn.right = 0;
keynode_set(dt, 0, &kn);
return trienode_set(dt, 0, &tn);
}
static int p_get_head(nfs_dt_DT* dt) {
return 0;
}
static int p_compare_keys(nfs_dt_DT* dt, char* key, int node) {
nfs_dt_TrieNode tn;
nfs_dt_KeyNode kn;
int i, j, s;
s = strlen(key);
trienode_get(dt, node, &tn);
i = 0;
j = (tn.kindex & 0x7fffffff);
while (i < s) {
keynode_get(dt, j, &kn);
if (strncmp((char*)key + i, kn.name, nfs_dt_MAX_SKN_SIZE) != 0)
return 0;
j = kn.next & 0x7fffffff;
i += nfs_dt_MAX_SKN_SIZE;
}
return 1;
}
static int p_find_first_different_bit(nfs_dt_DT* dt, char* key, int node) {
nfs_dt_TrieNode tn;
char tempname[4096];
trienode_get(dt, node, &tn);
fnode_extract_key(dt, tn.kindex & 0x7fffffff, tempname);
return bit_first_different(key, tempname);
}
static int p_insert_key(nfs_dt_DT* dt, char* key, int nt_index) {
int p, t, x, px, pt;
int i = 0;
p = p_get_head(dt);
t = trienode_get_right(dt, p);
pt = trienode_get_bindex(dt, t);
while (trienode_get_bindex(dt, p) < pt) {
p = t;
t = bit_get(key, pt) ? trienode_get_right(dt, t) : trienode_get_left(dt, t);
pt = trienode_get_bindex(dt, t);
}
if (p_compare_keys(dt, key, t))
return -1;
i = p_find_first_different_bit(dt, key, t);
p = p_get_head(dt);
x = trienode_get_right(dt, p);
px = trienode_get_bindex(dt, x);
while ( (trienode_get_bindex(dt, p) < px) && (px < i) ) {
p = x;
x = bit_get(key, px) ? trienode_get_right(dt, x) : trienode_get_left(dt, x);
px = trienode_get_bindex(dt, x);
}
t = node_allocate(dt, key, nt_index, i);
trienode_set_left(dt, t, (bit_get(key, i) ? x : t));
trienode_set_right(dt, t, (bit_get(key, i) ? t : x));
if (bit_get(key, trienode_get_bindex(dt, p)))
trienode_set_right(dt, p, t);
else
trienode_set_left(dt, p, t);
return t;
}
static int p_lookup_key(nfs_dt_DT* dt, char* key) {
int p, x, px;
p = p_get_head(dt);
x = trienode_get_right(dt, p);
px = trienode_get_bindex(dt, x);
while (trienode_get_bindex(dt, p) < px) {
p = x;
x = bit_get(key, px) ? trienode_get_right(dt, x) : trienode_get_left(dt, x);
px = trienode_get_bindex(dt, x);
}
if (!p_compare_keys(dt, key, x))
return -1;
return x;
}
static int p_lookup_key_n(nfs_dt_DT* dt, char* key, int n) {
int p, x, px;
p = p_get_head(dt);
x = trienode_get_right(dt, p);
px = trienode_get_bindex(dt, x);
while ( (trienode_get_bindex(dt, p) < px) && (px < n) ) {
p = x;
x = bit_get(key, px) ? trienode_get_right(dt, x) : trienode_get_left(dt, x);
px = trienode_get_bindex(dt, x);
}
return p;
}
static int p_remove_key(nfs_dt_DT* dt, char* k) {
int p, t, x, pp, lp, pt, px;
int bp, bl, br;
char key[nfs_dt_MAX_SUBNAME_SIZE + 1];
pp = -1;
p = p_get_head(dt);
t = trienode_get_right(dt, p);
pt = trienode_get_bindex(dt, t);
while (trienode_get_bindex(dt, p) < pt) {
pp = p;
p = t;
t = bit_get(k, pt) ? trienode_get_right(dt, t) : trienode_get_left(dt, t);
pt = trienode_get_bindex(dt, t);
}
if (!p_compare_keys(dt, k, t))
return -1;
if (t != p)
node_copy_key(dt, p, t);
bp = trienode_get_bindex(dt, p);
bl = trienode_get_bindex(dt, trienode_get_left(dt, p));
br = trienode_get_bindex(dt, trienode_get_right(dt, p));
if ((bl > bp) || (br > bp)) {
if (p != t) {
fnode_extract_key(dt, trienode_get_kindex(dt, p), key);
lp = p;
x = bit_get(key, trienode_get_bindex(dt, p)) ? trienode_get_right(dt, p) : trienode_get_left(dt, p);
px = trienode_get_bindex(dt, x);
while (trienode_get_bindex(dt, lp) < px) {
lp = x;
x = bit_get(key, px) ? trienode_get_right(dt, x) : trienode_get_left(dt, x);
px = trienode_get_bindex(dt, x);
}
if (!p_compare_keys(dt, key, x))
return -1;
if (bit_get(key, trienode_get_bindex(dt, lp)))
trienode_set_right(dt, lp, t);
else
trienode_set_left(dt, lp, t);
}
if (pp != p) {
int ch;
ch = bit_get(k, trienode_get_bindex(dt, p)) ? trienode_get_left(dt, p) : trienode_get_right(dt, p);
if (bit_get(k, trienode_get_bindex(dt, pp)))
trienode_set_right(dt, pp, ch);
else
trienode_set_left(dt, pp, ch);
}
} else {
if (pp != p) {
bl = trienode_get_left(dt, p);
br = trienode_get_right(dt, p);
if (bit_get(k, trienode_get_bindex(dt, pp)))
trienode_set_right(dt, pp, (((bl == br) && (bl == p)) ? pp : ((bl==p)?br:bl)));
else
trienode_set_left(dt, pp, (((bl == br) && (bl == p)) ? pp : ((bl==p)?br:bl)));
}
}
trienode_recover(dt, p);
return 0;
}
static char nfs_glob_key[nfs_dt_MAX_SUBNAME_SIZE];
static int p_node_iterate(nfs_dt_DT* dt, int root, int from_bidx, char* pattern, int flags,
int (*p)(nfs_dt_DT* dt,
char* filename,
int node,
void* tmp),
void* tmp) {
int bidx, tl, tr;
bidx = trienode_get_bindex(dt, root);
if (bidx <= from_bidx) {
if (root <= 0)
return 1;
fnode_extract_key(dt, trienode_get_kindex(dt, root), nfs_glob_key);
if (nfs_pmatch(pattern, nfs_glob_key, flags) != FNM_NOMATCH)
if (p != 0)
if (!p(dt, nfs_glob_key, root, tmp))
return 0;
return 1;
}
tl = trienode_get_left(dt, root);
tr = trienode_get_right(dt, root);
if (!p_node_iterate(dt, tl, bidx, pattern, flags, p, tmp))
return 0;
if (!p_node_iterate(dt, tr, bidx, pattern, flags, p, tmp))
return 0;
return 1;
}
nfs_dt_DT* nfs_dt_create(nfs_iio_File* file, int bpc1, int bpc2) {
nfs_dt_DT* dt;
int chn1, chn2;
if (file == NULL)
return NULL;
if (bpc1 == 0)
bpc1 = nfs_dt_DEF_CHANNEL1_SIZE;
if (bpc2 == 0)
bpc2 = nfs_dt_DEF_CHANNEL2_SIZE;
chn1 = nfs_iio_allocate_channel(file, bpc1);
chn2 = nfs_iio_allocate_channel(file, bpc2);
dt = (nfs_dt_DT*)malloc(sizeof(nfs_dt_DT));
dt->file = file;
dt->channel1 = chn1;
dt->channel2 = chn2;
dt->unallocated = 1;
dt->unallocated2 = 1;
p_init_head(dt);
return dt;
}
nfs_dt_DT* nfs_dt_open(nfs_iio_File* file, int channel1, int channel2) {
nfs_dt_DT* dt;
dt = (nfs_dt_DT*)malloc(sizeof(nfs_dt_DT));
dt->file = file;
dt->channel1 = channel1;
dt->channel2 = channel2;
dt->unallocated = trienode_find_first_free(dt, 1);
dt->unallocated2 = keynode_find_first_free(dt, 1);
return dt;
}
int nfs_dt_close(nfs_dt_DT* dt) {
if (dt != NULL)
free(dt);
return 0;
}
int nfs_dt_destroy(nfs_dt_DT* dt) {
nfs_dt_close(dt);
return 0;
}
int nfs_dt_filename_add(nfs_dt_DT* dt, char* filename) {
if (filename == NULL)
return -1;
return p_insert_key(dt, filename, 0);
}
int nfs_dt_filename_delete(nfs_dt_DT* dt, char* filename) {
if (filename == NULL)
return -1;
return p_remove_key(dt, filename);
}
int nfs_dt_filename_lookup(nfs_dt_DT* dt, char* filename) {
if (filename == NULL)
return -1;
return p_lookup_key(dt, filename);
}
int nfs_dt_filename_glob(nfs_dt_DT* dt,
char* pattern,
int flags,
int (*p)(nfs_dt_DT* dt,
char* filename,
int filename_idx,
void* tmp),
void* tmp) {
char prefix[256];
int start;
find_prefix(pattern, prefix);
start = p_lookup_key_n(dt, prefix, strlen(prefix) * 8);
p_node_iterate(dt, start, trienode_get_bindex(dt, start) - 1, pattern, flags, p, tmp);
return 0;
}
int nfs_dt_filename_get_nt_index(nfs_dt_DT* dt, int filename_idx) {
return trienode_get_nt(dt, filename_idx);
}
int nfs_dt_filename_set_nt_index(nfs_dt_DT* dt, int filename_idx, int nt_idx) {
return trienode_set_nt(dt, filename_idx, nt_idx);
}
int nfs_dt_filename_get_name(nfs_dt_DT* dt, int filename_idx, char* buffer) {
fnode_extract_key(dt, trienode_get_kindex(dt, filename_idx), buffer);
return 0;
}