339 lines
7.9 KiB
C
339 lines
7.9 KiB
C
#include "mrklib_priv.h"
|
|
|
|
typedef struct
|
|
{
|
|
const char *arch;
|
|
Eina_Hash *name_hash;
|
|
Eina_Hash *category_hash;
|
|
Eina_Hash *tag_hash;
|
|
Eina_Hash *key_hash;
|
|
} Db;
|
|
|
|
struct _Mrk_Repodb
|
|
{
|
|
const char *repodir;
|
|
Eina_List *dbs;
|
|
Ecore_Exe *exe;
|
|
Eina_Bool update;
|
|
Eina_List *handlers;
|
|
struct {
|
|
void (*update) (void *data, Mrk_Repodb *repodb);
|
|
} func;
|
|
struct {
|
|
void *update;
|
|
} data;
|
|
};
|
|
|
|
static void
|
|
db_load_hash(Eina_Hash *hash, FILE *f)
|
|
{
|
|
char line[16384], *s;
|
|
int len;
|
|
Eina_List *list = NULL;
|
|
const char *key = NULL;
|
|
|
|
for (;;)
|
|
{
|
|
s = fgets(line, sizeof(line), f);
|
|
if (!s) break;;
|
|
len = strlen(s);
|
|
if (len < 1) continue;
|
|
s[len - 1] = 0;
|
|
if ((s[0] == '\t') && (key))
|
|
{
|
|
list = eina_list_append(list, eina_stringshare_add(s + 1));
|
|
}
|
|
else
|
|
{
|
|
if (key) eina_hash_set(hash, key, list);
|
|
list = NULL;
|
|
if (key) eina_stringshare_del(key);
|
|
key = eina_stringshare_add(s);
|
|
}
|
|
}
|
|
if (key) eina_hash_set(hash, key, list);
|
|
list = NULL;
|
|
if (key) eina_stringshare_del(key);
|
|
key = NULL;
|
|
}
|
|
|
|
static Eina_Bool
|
|
db_clear_hash_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata)
|
|
{
|
|
const char *s;
|
|
|
|
EINA_LIST_FREE(data, s)
|
|
{
|
|
eina_stringshare_del(s);
|
|
}
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static void
|
|
db_clear_hash(Eina_Hash *hash)
|
|
{
|
|
if (!hash) return;
|
|
eina_hash_foreach(hash, db_clear_hash_cb, NULL);
|
|
eina_hash_free(hash);
|
|
}
|
|
|
|
static void
|
|
db_clear(Mrk_Repodb *rdb)
|
|
{
|
|
Db *db;
|
|
|
|
EINA_LIST_FREE(rdb->dbs, db)
|
|
{
|
|
db_clear_hash(db->name_hash);
|
|
db_clear_hash(db->category_hash);
|
|
db_clear_hash(db->tag_hash);
|
|
db_clear_hash(db->key_hash);
|
|
free(db);
|
|
}
|
|
}
|
|
|
|
static void
|
|
db_load(Mrk_Repodb *rdb)
|
|
{
|
|
Eina_List *files;
|
|
char *s;
|
|
char tmp[PATH_MAX];
|
|
Db *db = NULL;
|
|
FILE *f;
|
|
|
|
files = ecore_file_ls(rdb->repodir);
|
|
EINA_LIST_FREE(files, s)
|
|
{
|
|
if ((s[0] == '.') || (!_mrk_util_arch_ok(s)))
|
|
{
|
|
free(s);
|
|
continue;
|
|
}
|
|
snprintf(tmp, sizeof(tmp), "%s/%s/.mrkdb-name.txt", rdb->repodir, s);
|
|
f = fopen(tmp, "rb");
|
|
if (f)
|
|
{
|
|
db = calloc(1, sizeof(Db));
|
|
if (db)
|
|
{
|
|
db->arch = eina_stringshare_add(s);
|
|
if (db->arch)
|
|
{
|
|
db->name_hash = eina_hash_string_superfast_new(NULL);
|
|
db->category_hash = eina_hash_string_superfast_new(NULL);
|
|
db->tag_hash = eina_hash_string_superfast_new(NULL);
|
|
db->key_hash = eina_hash_string_superfast_new(NULL);
|
|
rdb->dbs = eina_list_append(rdb->dbs, db);
|
|
db_load_hash(db->name_hash, f);
|
|
}
|
|
else
|
|
{
|
|
free(db);
|
|
db = NULL;
|
|
}
|
|
}
|
|
fclose(f);
|
|
}
|
|
if (db)
|
|
{
|
|
snprintf(tmp, sizeof(tmp), "%s/%s/.mrkdb-tag.txt", rdb->repodir, s);
|
|
f = fopen(tmp, "rb");
|
|
if (f)
|
|
{
|
|
db_load_hash(db->tag_hash, f);
|
|
fclose(f);
|
|
}
|
|
snprintf(tmp, sizeof(tmp), "%s/%s/.mrkdb-category.txt", rdb->repodir, s);
|
|
f = fopen(tmp, "rb");
|
|
if (f)
|
|
{
|
|
db_load_hash(db->category_hash, f);
|
|
fclose(f);
|
|
}
|
|
snprintf(tmp, sizeof(tmp), "%s/%s/.mrkdb-key.txt", rdb->repodir, s);
|
|
f = fopen(tmp, "rb");
|
|
if (f)
|
|
{
|
|
db_load_hash(db->key_hash, f);
|
|
fclose(f);
|
|
}
|
|
}
|
|
db = NULL;
|
|
}
|
|
}
|
|
|
|
static Db *
|
|
db_arch_find(Mrk_Repodb *rdb, const char *arch)
|
|
{
|
|
Eina_List *l;
|
|
Db *db;
|
|
|
|
if (!arch) return NULL;
|
|
EINA_LIST_FOREACH(rdb->dbs, l, db)
|
|
{
|
|
if (!strcmp(db->arch, arch))
|
|
{
|
|
if (rdb->dbs != l) rdb->dbs = eina_list_promote_list(rdb->dbs, l);
|
|
return db;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static Eina_List *
|
|
search_intersect(Eina_List *list_in, Eina_List *list2)
|
|
{
|
|
Eina_List *list = NULL, *ll;
|
|
const char *s, *ss;
|
|
int ok;
|
|
|
|
EINA_LIST_FREE(list_in, s)
|
|
{
|
|
ok = 0;
|
|
EINA_LIST_FOREACH(list2, ll, ss)
|
|
{
|
|
if (ss == s)
|
|
{
|
|
ok = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (ok) list = eina_list_append(list, s);
|
|
else eina_stringshare_del(s);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
static Eina_List *
|
|
db_search(Eina_Hash *hash, const char *search)
|
|
{
|
|
Eina_List *list = NULL, *tl, *l;
|
|
const char *s;
|
|
char *ts = strdup(search);
|
|
char *p, *end;
|
|
int i;
|
|
|
|
if (!ts) return NULL;
|
|
for (p = ts; *p; p++)
|
|
{
|
|
if (isspace(*p)) *p = 0;
|
|
end = p;
|
|
}
|
|
for (p = ts; p < end; p++)
|
|
{
|
|
if (!*p) continue;
|
|
tl = eina_hash_find(hash, p);
|
|
if (p == ts)
|
|
{
|
|
EINA_LIST_FOREACH(tl, l, s)
|
|
list = eina_list_append(list, eina_stringshare_add(s));
|
|
}
|
|
else
|
|
{
|
|
list = search_intersect(list, tl);
|
|
}
|
|
p += strlen(p);
|
|
}
|
|
free(ts);
|
|
return list;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_mrk_cb_exe_del(void *data, int type, void *event)
|
|
{
|
|
Ecore_Exe_Event_Del *e = event;
|
|
Mrk_Repodb *rdb = data;
|
|
const char *tag;
|
|
|
|
if (!e->exe) return EINA_TRUE;
|
|
tag = ecore_exe_tag_get(e->exe);
|
|
if (!tag) return EINA_TRUE;
|
|
if (!strcmp(tag, "-=# mrk serve - db exe #=-"))
|
|
{
|
|
if (ecore_exe_data_get(e->exe) != rdb) return EINA_TRUE;
|
|
if (e->exe != rdb->exe) return EINA_TRUE;
|
|
rdb->exe = NULL;
|
|
db_clear(rdb);
|
|
db_load(rdb);
|
|
if (rdb->update)
|
|
{
|
|
rdb->update = EINA_FALSE;
|
|
mrk_repodb_update(rdb);
|
|
}
|
|
if (rdb->func.update) rdb->func.update(rdb->data.update, rdb);
|
|
return EINA_FALSE;
|
|
}
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI Mrk_Repodb *
|
|
mrk_repodb_load(const char *repodir)
|
|
{
|
|
Mrk_Repodb *rdb;
|
|
|
|
rdb = calloc(1, sizeof(Mrk_Repodb));
|
|
if (!rdb) return NULL;
|
|
rdb->repodir = eina_stringshare_add(repodir);
|
|
rdb->handlers = eina_list_append(rdb->handlers,
|
|
ecore_event_handler_add
|
|
(ECORE_EXE_EVENT_DEL,
|
|
_mrk_cb_exe_del, rdb));
|
|
db_load(rdb);
|
|
return rdb;
|
|
}
|
|
|
|
EAPI void
|
|
mrk_repodb_free(Mrk_Repodb *rdb)
|
|
{
|
|
Ecore_Event_Handler *hnd;
|
|
|
|
EINA_LIST_FREE(rdb->handlers, hnd) ecore_event_handler_del(hnd);
|
|
db_clear(rdb);
|
|
if (rdb->exe) ecore_exe_free(rdb->exe);
|
|
free(rdb);
|
|
}
|
|
|
|
EAPI void
|
|
mrk_repodb_callback_update_set(Mrk_Repodb *rdb,
|
|
void (*update) (void *data, Mrk_Repodb *rdb),
|
|
void *update_data)
|
|
{
|
|
rdb->func.update = update;
|
|
rdb->data.update = update_data;
|
|
}
|
|
|
|
EAPI void
|
|
mrk_repodb_update(Mrk_Repodb *rdb)
|
|
{
|
|
char tmp[PATH_MAX];
|
|
|
|
if (rdb->exe)
|
|
{
|
|
rdb->update = EINA_TRUE;
|
|
return;
|
|
}
|
|
snprintf(tmp, sizeof(tmp), "mrk index %s/*-*", rdb->repodir);
|
|
rdb->exe = ecore_exe_pipe_run(tmp, 0, rdb);
|
|
if (rdb->exe) ecore_exe_tag_set(rdb->exe, "-=# mrk serve - db exe #=-");
|
|
}
|
|
|
|
EAPI const Eina_List *
|
|
mrk_repodb_category_list(Mrk_Repodb *rdb, const char *arch, const char *category)
|
|
{
|
|
Db *db = db_arch_find(rdb, arch);
|
|
Eina_List *list;
|
|
|
|
if (!db) return NULL;
|
|
if (!category) category = "@"; // @ is the "everything" category and list
|
|
return eina_hash_find(db->category_hash, category);
|
|
}
|
|
|
|
EAPI Eina_List *
|
|
mrk_repodb_search(Mrk_Repodb *rdb, const char *arch, const char *search)
|
|
{
|
|
Db *db = db_arch_find(rdb, arch);
|
|
|
|
if (!db) return NULL;
|
|
return db_search(db->key_hash, search);
|
|
}
|