Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Query interface works, 2 commands currently available

  • Loading branch information...
commit 912e8b47bb100dae0a641bd5f4a5e0057aaa9c22 1 parent 6e25f5b
Mark Watts authored
View
12 Makefile
@@ -1,9 +1,9 @@
-tagfs: tagfs.c tagdb.c util.c cmd.c code_table.c tokenizer.c
- gcc -o tagfs `pkg-config --libs --cflags glib-2.0 fuse` tagfs.c tagdb.c util.c cmd.c code_table.c tokenizer.c
+tagfs: tagfs.c tagdb.c util.c code_table.c tokenizer.c stream.c set_ops.c
+ gcc -o tagfs `pkg-config --libs --cflags glib-2.0 fuse` tagfs.c tagdb.c util.c code_table.c tokenizer.c stream.c set_ops.c
ttfs: test_tagfs.c tagdb.c util.c tokenizer.c code_table.c
gcc -g -o ttfs `pkg-config --libs --cflags glib-2.0` test_tagfs.c tagdb.c util.c tokenizer.c code_table.c
-ttdb: test_tagdb.c tagdb.c code_table.c util.c tokenizer.c set_ops.c
- gcc -g -o ttdb `pkg-config --libs --cflags glib-2.0` test_tagdb.c tagdb.c code_table.c util.c tokenizer.c set_ops.c
+ttdb: test_tagdb.c tagdb.c code_table.c util.c tokenizer.c set_ops.c stream.c
+ gcc -g -o ttdb `pkg-config --libs --cflags glib-2.0` test_tagdb.c tagdb.c code_table.c util.c tokenizer.c set_ops.c stream.c
tcmd: test_cmd.c tagdb.c util.c
gcc -g -o tcmd `pkg-config --libs --cflags glib-2.0` test_cmd.c tagdb.c util.c
tct: test_code_table.c util.c code_table.c
@@ -12,5 +12,9 @@ ths: util.c test_hash_sets.c set_ops.c
gcc -g -o ths `pkg-config --libs --cflags glib-2.0` test_hash_sets.c util.c set_ops.c
ttk: test_tokenizer.c tokenizer.c stream.c
gcc -g -o ttk `pkg-config --libs --cflags glib-2.0` test_tokenizer.c tokenizer.c stream.c
+tq: query.c test_query.c tagdb.c tokenizer.c stream.c util.c code_table.c tagdb_priv.c set_ops.c
+ gcc -o tq -g `pkg-config --libs --cflags glib-2.0` test_query.c query.c tagdb.c tokenizer.c stream.c util.c code_table.c tagdb_priv.c set_ops.c
testdb:
./generate_testdb.pl test.db 10 50 10 copies
+clean:
+ rm *.o
View
2  generate_testdb.pl
@@ -41,7 +41,7 @@ sub numbered_file_with_tags_upto_max
my $copies_dir = shift;
my @files = ();
open(FILE, ">", $name);
-for my $i (1 .. $size+1)
+for my $i (1 .. $size)
{
push @files, numbered_file_with_tags_upto_max($i, $max_tags,
$max_tags_per_file, $copies_dir);
View
157 query.c
@@ -0,0 +1,157 @@
+#include "query.h"
+#include "util.h"
+#include "tokenizer.h"
+// query api for tagdb
+// parses query strings and calls the appropriate methods from tagdb
+// also handles conversions from the external strings to internal ids
+// when necessary
+
+// Functions must return the type of their result (as enumerated in types.h) and the result itself
+// the function returns these in the two result arguments it is given
+// functions must accept an argument count and an argument list (NULL-terminated array of gpointers)
+// finally, functions will take a pointer to a tagdb and a table id as named arguments,
+// thus functions will have the form:
+// void (*func) (tagdb *db, int table_id, int argc, char **argv, gpointer result, int type)
+void tagdb_tag_is_empty (tagdb *db, int table_id, int argc, gchar **argv, gpointer *result, int *type)
+{
+ if (argc < 1)
+ return;
+ int tcode = tagdb_get_tag_code(db, argv[0]);
+ GHashTable *tmp = tagdb_get_item(db, tcode, table_id);
+ if (tmp != NULL)
+ {
+ *result = GINT_TO_POINTER((g_hash_table_size(tmp) == 0)?TRUE:FALSE);
+ *type = tagdb_int_t;
+ }
+ else
+ {
+ *result = GINT_TO_POINTER(TRUE);
+ *type = tagdb_int_t;
+ }
+}
+
+void tagdb_file_has_tags (tagdb *db, int table_id, int argc, gchar **argv, gpointer *result, int *type)
+{
+ if (argc < 1)
+ return;
+ GHashTable *tmp = tagdb_get_item(db, atoi((char*) argv[0]), table_id);
+ int i;
+ int tcode;
+ argc--;
+ argv++;
+ *type = tagdb_int_t;
+ for (i = 0; i < argc; i++)
+ {
+ tcode = tagdb_get_tag_code(db, argv[i]);
+ if (g_hash_table_lookup(tmp, GINT_TO_POINTER(tcode)) == NULL)
+ {
+ *result = GINT_TO_POINTER(FALSE);
+ return;
+ }
+ }
+ *result = GINT_TO_POINTER(TRUE);
+ return;
+}
+
+q_fn q_functions[] = {// Tag table funcs
+ tagdb_tag_is_empty,
+ // File table funcs
+ tagdb_file_has_tags,
+ NULL};
+
+// encode the command name
+int _name_to_code (const char *name)
+{
+ // remember, lists and iteration solve everything!
+ int i = 0;
+ while (q_commands[i] != NULL)
+ {
+ if (g_strcmp0(q_commands[i], name) == 0)
+ return i;
+ i++;
+ }
+ return -1;
+}
+
+
+/* lookup
+ * database queries shall be of the form
+ * (FILE HAS_TAGS file_id "argument1" OR "argument2" AND ...)
+ * or
+ * (TAG IS_EMPTY "tag_name")
+ * or
+ * (FILE TAG_VALUE file_id "tag_name")
+ * etc.
+ * So, the first atom is a table specifier, the second item is the action on that table
+ * and the rest are appropriate arguments to that action.
+ * arguments must be quoted
+ * and other query atoms are not quoted
+ * returns a compiled query object
+ */
+// parse (string) -> query_t
+query_t *parse (const char *s)
+{
+ query_t *qr = malloc(sizeof(query_t));
+ char *qs = g_strstrip(g_strdup(s));
+ char sep;
+ char *token;
+ GList *seps = g_list_new_charlist(' ', NULL);
+ Tokenizer *tok = tokenizer_new(seps);
+ tokenizer_set_str_stream(tok, qs);
+ token = tokenizer_next(tok, &sep);
+ if (g_strcmp0(token, "FILE") == 0)
+ {
+ qr->table_id = 0;
+ }
+ if (g_strcmp0(token, "TAG") == 0)
+ {
+ qr->table_id = 1;
+ }
+ g_free(token);
+ token = tokenizer_next(tok, &sep);
+ qr->command_id = _name_to_code(token);
+ g_free(token);
+ token = tokenizer_next(tok, &sep);
+ int i = 0;
+ while (token != NULL && i < 255)
+ {
+ qr->argv[i] = token;
+ i++;
+ token = tokenizer_next(tok, &sep);
+ }
+ qr->argv[i] = NULL;
+ qr->argc = i;
+ return qr;
+}
+
+// action takes a compiled query and performs the action on the database db
+// query
+int act (tagdb *db, query_t *q, gpointer *result, int *type)
+{
+ q_functions[q->command_id](db, q->table_id, q->argc, q->argv, result, type);
+}
+// -> (type, *object*)
+// encapsualtes the object in a result type
+// with info about the type based on type
+// we pass the database because encapsulation may make further
+// queries to acquire data that the user expects
+result_t *encapsulate (tagdb *db, int type, gpointer data)
+{
+ result_t *res = malloc(sizeof(result_t));
+ res->type = type;
+ switch (type)
+ {
+ case tagdb_dict_t:
+ res->data.d = data;
+ break;
+ case tagdb_int_t:
+ res->data.i = GPOINTER_TO_INT(data);
+ break;
+ case tagdb_str_t:
+ res->data.s = data;
+ break;
+ default:
+ res->data.b = data;
+ }
+ return res;
+}
View
14 query.h
@@ -0,0 +1,14 @@
+#ifndef QUERY_H
+#define QUERY_H
+#include "tagdb.h"
+#include "types.h"
+query_t *parse (const char *s);
+int act (tagdb *db, query_t *q, gpointer *result, int *type);
+typedef void (*q_fn) (tagdb *db, int table_id, int argc, gchar **argv, gpointer *result, int *type);
+result_t *encapsulate (tagdb *db, int type, gpointer data);
+static const char *q_commands[] = {// Tag table commands
+ "IS_EMPTY",
+ // File table commands
+ "HAS_TAGS",
+ NULL};
+#endif /* QUERY_H */
View
253 tagdb.c
@@ -2,100 +2,48 @@
#include "tokenizer.h"
#include "set_ops.h"
#include "util.h"
+#include "query.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
-// Reads in the db file
-// 4 separate data structures are read in for the db file
-// Two are hash tables for doing most of our accesses
-// The other two are code translation tables for the tags
-// and for the files
-void _dbstruct_from_file (tagdb *db, const char *db_fname)
+void *tagdb_save (tagdb *db, const char* filename)
{
- GList *seps = g_list_new_charlist(' ', ',', ':', 0);
-
- Tokenizer *tok = tokenizer_new(seps);
- if (tokenizer_set_file_stream(tok, db_fname) < 0)
+ if (filename == NULL)
{
- exit(1);
+ filename = db->db_fname;
}
-
- int file_id;
- int its_code;
- int max_id;
-
- GHashTable *forward = g_hash_table_new(g_direct_hash, g_direct_equal);
- GHashTable *reverse = g_hash_table_new(g_direct_hash, g_direct_equal);
- GHashTable *its_tags = g_hash_table_new(g_direct_hash, g_direct_equal);
- CodeTable *tag_codes = code_table_new();
-
- char sep;
- char *token = tokenizer_next(tok, &sep);
- file_id = 0;
- its_code = 0;
- max_id = file_id;
- while (token != NULL)
+ FILE *f = fopen(filename, "w");
+ GHashTableIter it,itt;
+ gpointer key, value, k, v;
+ g_hash_table_iter_init(&it, db->tables[FILE_TABLE]);
+ while (g_hash_table_iter_next(&it, &key, &value))
{
- if (sep == '=')
+ // print the id
+ fprintf(f, "%d", GPOINTER_TO_INT(key));
+ // print a |
+ fputc('|', f);
+ GHashTable *tags = tagdb_get_item(db, GPOINTER_TO_INT(key),
+ FILE_TABLE);
+ if (tags == NULL | g_hash_table_size(tags) == 0)
{
- // convert the token to a number and set as the file_id
- file_id = atoi(token);
- if (file_id == 0)
- {
- fprintf(stderr, "Got file_id == 0 in _db_struct_from_file\n");
- exit(1);
- }
- if (file_id > max_id)
- {
- max_id = file_id;
- }
- g_free(token);
- printf("file_id == %d", file_id);
+ fprintf(stderr, "warning: tagdb_save, tags == NULL or table size is 0\n");
+ fputs("*:* ", f);
+ continue;
}
- if (sep == ':')
+ g_hash_table_iter_init(&itt, tags);
+ while (g_hash_table_iter_next(&itt, &k, &v))
{
- // store the tag name and get its code
- its_code = code_table_ins_entry(tag_codes, token);
- g_free(token);
+ // print a tag
+ char *str;
+ str = code_table_get_value(db->tag_codes, GPOINTER_TO_INT(k));
+ fprintf(f, "%s:%s,", str, (char*) v);
}
- if (sep == ' ' | sep == ',' | sep == -1) // -1 is signals the end of the file
- {
- // store the file for this tag
- GHashTable *its_files = g_hash_table_lookup(reverse, GINT_TO_POINTER(its_code));
- if (its_files == NULL)
- {
- its_files = set_new(g_direct_hash, g_direct_equal, NULL);
- g_hash_table_insert(reverse, GINT_TO_POINTER(its_code), its_files);
- }
- set_add(its_files, GINT_TO_POINTER(file_id));
- // store the tag/value pair for this file
- g_hash_table_insert(its_tags, GINT_TO_POINTER(its_code), token);
- if (sep == ' ' | sep == -1)
- {
- // store this new file into forward with its tags
- g_hash_table_insert(forward, GINT_TO_POINTER(file_id), its_tags);
- }
- if (sep == ' ')
- {
- // make a new hash for the next file
- its_tags = g_hash_table_new(g_direct_hash, g_direct_equal);
- }
- }
- token = tokenizer_next(tok, &sep);
+ fseek(f, -1, SEEK_CUR);
+ fputc(' ', f);
}
- tokenizer_destroy(tok);
- g_free(token);
- db->last_id = max_id;
- db->tables[0] = forward;
- db->tables[1] = reverse;
- db->tag_codes = tag_codes;
-}
-
-void *tagdb_save (tagdb *db)
-{
- //
+ fclose(f);
}
tagdb *newdb (const char *db_fname)
@@ -107,12 +55,16 @@ tagdb *newdb (const char *db_fname)
return db;
}
-// gets list of file ids for some query
-// or gets list of tag ids for some query
-// or gets some string for some query
-// etc.
+// does all of the steps in query.c for you
+result_t *tagdb_query (tagdb *db, const char *query)
+{
+ gpointer r;
+ int type = -1;
+ act(db, parse(query), &r, &type);
+ return encapsulate(db, type, r);
+}
-GHashTable *tagdb_get_sub (tagdb *db, int item_id, int sub_id, int table_id)
+gpointer tagdb_get_sub (tagdb *db, int item_id, int sub_id, int table_id)
{
GHashTable *sub_table = tagdb_get_item(db, item_id, table_id);
if (sub_table != NULL)
@@ -130,15 +82,6 @@ GHashTable *tagdb_get_sub (tagdb *db, int item_id, int sub_id, int table_id)
// a corresponding removal should be done in the other table
// we can't do it here because recursion's a bitch, and structural
// modifications to hash tables aren't allowed.
-void _remove_sub (tagdb *db, int item_id, int sub_id, int table_id)
-{
- GHashTable *sub_table = tagdb_get_item(db, item_id, table_id);
- if (sub_table != NULL)
- {
- g_hash_table_remove(sub_table, GINT_TO_POINTER(sub_id));
- }
-}
-
// so we do it here
void tagdb_remove_sub (tagdb *db, int item_id, int sub_id, int table_id)
{
@@ -172,59 +115,9 @@ GHashTable *tagdb_get_item (tagdb *db, int item_id, int table_id)
}
// new_data may be NULL for tag table
-void _insert_sub (tagdb *db, int item_id, int new_id,
- gpointer new_data, int table_id)
-{
- GHashTable *sub_table = tagdb_get_item(db, item_id, table_id);
- if (sub_table == NULL)
- {
- if (table_id == TAG_TABLE)
- {
- sub_table = set_new(g_direct_hash, g_direct_equal, NULL);
- }
- else
- {
- sub_table = g_hash_table_new(g_direct_hash, g_direct_equal);
- }
- g_hash_table_insert(db->tables[table_id], GINT_TO_POINTER(item_id),
- sub_table);
- }
- if (table_id == TAG_TABLE)
- set_add(sub_table, GINT_TO_POINTER(new_id));
- else
- g_hash_table_insert(sub_table, GINT_TO_POINTER(new_id), new_data);
-}
// if item_id == -1 and it's a file then we give it a new_id of last_id + 1
// if it's a tag t
-void _insert_item (tagdb *db, int item_id,
- GHashTable *data, int table_id)
-{
- // inserts do not overwrite sub tables
- // although data is a hash table, that is only used as an interface
- // for collections with data
- // **you should not assume that the values in data will be the
- // ones in the resulting hash table**
- GHashTable *orig_table = tagdb_get_item(db, item_id, table_id);
- g_hash_table_insert(db->tables[table_id], GINT_TO_POINTER(item_id),
- set_union_s(data, orig_table));
- GHashTable *sub_table = tagdb_get_item(db, item_id, table_id);
-
- GHashTableIter it;
- gpointer key, value;
- g_hash_table_iter_init(&it, sub_table);
-
- int other = (table_id == FILE_TABLE)?TAG_TABLE:FILE_TABLE;
- while (g_hash_table_iter_next(&it, &key, &value))
- {
- // check if we have it, don't create it
- // this assumes that if we are inserting a tag with a
- // bunch of files (like a move directory or something)
- // the values being inserted are default values or something
- // like that.
- _insert_sub(db, GPOINTER_TO_INT(key), item_id, value, other);
- }
-}
// a 'filename' gets inserted with the "name" tag, but this isn't
// required
@@ -257,6 +150,7 @@ int tagdb_insert_item (tagdb *db, gpointer item,
}
}
+
// new_data may be NULL for tag table
void tagdb_insert_sub (tagdb *db, int item_id, int new_id,
gpointer new_data, int table_id)
@@ -265,6 +159,7 @@ void tagdb_insert_sub (tagdb *db, int item_id, int new_id,
_insert_sub(db, item_id, new_id, new_data, table_id);
_insert_sub(db, new_id, item_id, new_data, other);
}
+
GHashTable *tagdb_files (tagdb *db)
{
return tagdb_get_table(db, FILE_TABLE);
@@ -275,6 +170,29 @@ GHashTable *tagdb_get_table (tagdb *db, int table_id)
return db->tables[table_id];
}
+/*
+GHashTable *tagdb_get_files_by_tag_value (tagdb *db, const char *tag, gpointer value,
+ GCompareFunc cmp, int inclusion_condition)
+{
+ GHashTable *res = g_hash_table_new(g_direct_hash, g_direct_equal);
+ // look up tag in tag table
+ GHashTable *files = tagdb_get_item(db, tag, TAG_TABLE);
+ // filter those files by equality with value
+ GHashTableIter it;
+ gpointer k, v, not_used;
+ g_hash_table_iter_init(&it, files);
+ while (g_hash_table_iter_next(&it, &k, &not_used))
+ {
+ v = tagdb_get_sub(db, GPOINTER_TO_INT(k), tag, FILE_TABLE);
+ if (cmp(value, v) == inclusion_condition)
+ {
+ g_hash_table_insert(res, k, v);
+ }
+ }
+ return res;
+}
+*/
+
// tags is a list of tag IDs
GHashTable *get_files_by_tag_list (tagdb *db, GList *tags)
{
@@ -297,6 +215,11 @@ void tagdb_add_file_tag (tagdb *db, const char *tag_name, const char *file_name)
{
}
+int tagdb_get_tag_code (tagdb *db, const char *tag_name)
+{
+ return code_table_get_code(db->tag_codes, tag_name);
+}
+
/*
// returns a list of names of items which satisfy predicate
GList *tagdb_filter (tagdb *db, gboolean (*predicate)(gpointer key,
@@ -334,46 +257,4 @@ gboolean has_tag_filter (gpointer key, gpointer value, gpointer data)
}
return TRUE;
}
-
-// get files with tags
-// tag list must end with NULL
-GList *get_files_by_tags (tagdb *db, ...)
-{
- // I just copy the args into a GList. it's easier this way.
- GList *tags = NULL;
- va_list args;
- va_start(args, db);
-
- char *tag = va_arg(args, char*);
- while (tag != NULL)
- {
- tags = g_list_prepend(tags, tag);
- tag = va_arg(args, char*);
- }
- tags = g_list_reverse(tags);
- va_end(args);
- return get_files_by_tag_list(db, tags);
-}
-
-GList *get_files_by_tag_list (tagdb *db, GList *tags)
-{
- GList *file_tables = NULL;
- while (tags != NULL)
- {
- file_tables = g_list_append(file_tables, tagdb_get_tag_files(db, tags->data));
- tags = tags->next;
- }
- GList *tmp = g_hash_table_get_keys(intersect(file_tables));
- GList *res = NULL;
- GList *it = tmp;
- while (it != NULL)
- {
- int code = GPOINTER_TO_INT(it->data);
- char *fname = code_table_get_value(db->file_codes, code);
- res = g_list_prepend(res, fname);
- it = it->next;
- }
- g_list_free(tmp);
- return res;
-}
*/
View
15 tagdb.h
@@ -1,7 +1,9 @@
-#include <glib.h>
-#include "code_table.h"
#ifndef TAGDB_H
#define TAGDB_H
+#include <glib.h>
+#include "code_table.h"
+#include "types.h"
+
struct tagdb
{
GHashTable **tables;
@@ -19,11 +21,18 @@ tagdb *newdb (const char *fname);
GHashTable *tagdb_files (tagdb *db);
GHashTable *get_files_by_tag_list (tagdb *db, GList *tags);
+result_t *tagdb_query (tagdb *db, const char *query);
GHashTable *tagdb_get_item (tagdb *db, int item_id, int table_id);
-GHashTable *tagdb_get_sub (tagdb *db, int item_id, int sub_id, int table_id);
+gpointer tagdb_get_sub (tagdb *db, int item_id, int sub_id, int table_id);
GHashTable *tagdb_get_table(tagdb *db, int table_id);
int tagdb_insert_item (tagdb *db, gpointer item, GHashTable *data, int table_id);
void tagdb_insert_sub (tagdb *db, int item_id, int new_id, gpointer new_data, int table_id);
void tagdb_remove_item (tagdb *db, int item_id, int table_id);
void tagdb_remove_sub (tagdb *db, int item_id, int sub_id, int table_id);
+int tagdb_tag_code (tagdb *db, const char *tag_name);
+int tagdb_get_tag_code (tagdb *db, const char *tag_name);
+// Returns all of the matching files as
+// id=>tag_value pairs
+GHashTable *tagdb_get_files_by_tag_value (tagdb *db, const char *tag, gpointer value,
+ GCompareFunc cmp, int inclusion_condition);
#endif /*TAGDB_H*/
View
168 tagdb_priv.c
@@ -0,0 +1,168 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "tagdb.h"
+#include "set_ops.h"
+#include "tokenizer.h"
+// Reads in the db file
+// 4 separate data structures are read in for the db file
+// Two are hash tables for doing most of our accesses
+// The other two are code translation tables for the tags
+// and for the files
+void _dbstruct_from_file (tagdb *db, const char *db_fname)
+{
+ GList *seps = g_list_new_charlist('|', ' ', ',', ':', NULL);
+
+ Tokenizer *tok = tokenizer_new(seps);
+ if (tokenizer_set_file_stream(tok, db_fname) < 0)
+ {
+ exit(1);
+ }
+
+ int file_id;
+ int its_code;
+ int max_id;
+
+ GHashTable *forward = g_hash_table_new(g_direct_hash, g_direct_equal);
+ GHashTable *reverse = g_hash_table_new(g_direct_hash, g_direct_equal);
+ GHashTable *its_tags = g_hash_table_new(g_direct_hash, g_direct_equal);
+ CodeTable *tag_codes = code_table_new();
+
+ char sep;
+ char *token = tokenizer_next(tok, &sep);
+ file_id = 0;
+ its_code = 0;
+ max_id = file_id;
+ while (token != NULL)
+ {
+ if (sep == '|')
+ {
+ // convert the token to a number and set as the file_id
+ file_id = atoi(token);
+ if (file_id == 0)
+ {
+ fprintf(stderr, "Got file_id == 0 in _dbstruct_from_file\n");
+ exit(1);
+ }
+ if (file_id > max_id)
+ {
+ max_id = file_id;
+ }
+ g_free(token);
+ }
+ if (sep == ':')
+ {
+ // signifies no tags for the file
+ // we skip this by simply getting the next token
+ // storing the file
+ if (g_strcmp0(token, "*") == 0)
+ {
+ its_code = code_table_ins_entry(tag_codes, "UNTAGGED");
+ }
+ else
+ {
+ // store the tag name and get its code
+ its_code = code_table_ins_entry(tag_codes, token);
+ }
+ g_free(token);
+ }
+ if (sep == ' ' | sep == ',' | sep == -1) // -1 is signals the end of the file
+ {
+ if (its_code == 0)
+ {
+ fprintf(stderr, "Got its_code==0 in _dbstruct_from_file\n");
+ exit(1);
+ }
+ // store the file for this tag
+ GHashTable *its_files = g_hash_table_lookup(reverse, GINT_TO_POINTER(its_code));
+ if (its_files == NULL)
+ {
+ its_files = set_new(g_direct_hash, g_direct_equal, NULL);
+ g_hash_table_insert(reverse, GINT_TO_POINTER(its_code), its_files);
+ }
+ set_add(its_files, GINT_TO_POINTER(file_id));
+ // store the tag/value pair for this file
+ g_hash_table_insert(its_tags, GINT_TO_POINTER(its_code), token);
+ if (sep == ' ' | sep == -1)
+ {
+ // store this new file into forward with its tags
+ g_hash_table_insert(forward, GINT_TO_POINTER(file_id), its_tags);
+ }
+ if (sep == ' ')
+ {
+ // make a new hash for the next file
+ its_code = 0;
+ its_tags = g_hash_table_new(g_direct_hash, g_direct_equal);
+ }
+ // for error-checking
+ }
+ token = tokenizer_next(tok, &sep);
+ }
+ tokenizer_destroy(tok);
+ g_free(token);
+ db->last_id = max_id;
+ db->tables[0] = forward;
+ db->tables[1] = reverse;
+ db->tag_codes = tag_codes;
+}
+
+void _remove_sub (tagdb *db, int item_id, int sub_id, int table_id)
+{
+ GHashTable *sub_table = tagdb_get_item(db, item_id, table_id);
+ if (sub_table != NULL)
+ {
+ g_hash_table_remove(sub_table, GINT_TO_POINTER(sub_id));
+ }
+}
+
+void _insert_sub (tagdb *db, int item_id, int new_id,
+ gpointer new_data, int table_id)
+{
+ GHashTable *sub_table = tagdb_get_item(db, item_id, table_id);
+ if (sub_table == NULL)
+ {
+ if (table_id == TAG_TABLE)
+ {
+ sub_table = set_new(g_direct_hash, g_direct_equal, NULL);
+ }
+ else
+ {
+ sub_table = g_hash_table_new(g_direct_hash, g_direct_equal);
+ }
+ g_hash_table_insert(db->tables[table_id], GINT_TO_POINTER(item_id),
+ sub_table);
+ }
+ if (table_id == TAG_TABLE)
+ set_add(sub_table, GINT_TO_POINTER(new_id));
+ else
+ g_hash_table_insert(sub_table, GINT_TO_POINTER(new_id), new_data);
+}
+
+void _insert_item (tagdb *db, int item_id,
+ GHashTable *data, int table_id)
+{
+ // inserts do not overwrite sub tables
+ // although data is a hash table, that is only used as an interface
+ // for collections with data
+ // **you should not assume that the values in data will be the
+ // ones in the resulting hash table**
+ GHashTable *orig_table = tagdb_get_item(db, item_id, table_id);
+ g_hash_table_insert(db->tables[table_id], GINT_TO_POINTER(item_id),
+ set_union_s(data, orig_table));
+ GHashTable *sub_table = tagdb_get_item(db, item_id, table_id);
+
+ GHashTableIter it;
+ gpointer key, value;
+ g_hash_table_iter_init(&it, sub_table);
+
+ int other = (table_id == FILE_TABLE)?TAG_TABLE:FILE_TABLE;
+ while (g_hash_table_iter_next(&it, &key, &value))
+ {
+ // check if we have it, don't create it
+ // this assumes that if we are inserting a tag with a
+ // bunch of files (like a move directory or something)
+ // the values being inserted are default values or something
+ // like that.
+ _insert_sub(db, GPOINTER_TO_INT(key), item_id, value, other);
+ }
+}
+
View
94 test_query.c
@@ -0,0 +1,94 @@
+#include "query.h"
+#include "util.h"
+#include <stdio.h>
+
+void query_info (query_t *q)
+{
+ if (q==NULL)
+ {
+ fprintf(stderr, "query_info: got q==NULL\n");
+ return;
+ }
+ printf("query info:\n");
+ printf("\ttable_id: %s\n", (q->table_id==FILE_TABLE)?"FILE_TABLE":"TAG_TABLE");
+ printf("\tcommand: %s\n", q_commands[q->command_id]);
+ printf("\targc: %d\n", q->argc);
+ int i;
+ for (i = 0; i < q->argc; i++)
+ {
+ printf("\targv[%d] = %s\n", i, q->argv[i]);
+ }
+}
+
+void res_info (result_t *r)
+{
+ if (r == NULL)
+ {
+ return;
+ }
+ printf("result info:\n");
+ printf("\ttype: %d\n", r->type);
+ printf("\tdata: ");
+ switch (r->type)
+ {
+ case tagdb_dict_t:
+ print_hash(r->data.d);
+ break;
+ case tagdb_int_t:
+ printf("%d\n", r->data.i);
+ break;
+ case tagdb_str_t:
+ printf("%s\n", r->data.s);
+ break;
+ default:
+ printf("%p\n", r->data.b);
+ }
+}
+
+void query_file_has_tags (gpointer filen, gpointer db)
+{
+ printf("FILE NAME: %d\n", GPOINTER_TO_INT(filen));
+ gchar idstr[16];
+ sprintf(idstr, "%d", GPOINTER_TO_INT(filen));
+ gchar *str = g_strjoin(" ", "FILE HAS_TAGS", idstr, "tag048", "tag041", "tag012", NULL);
+ query_t *q = parse(str);
+ query_info(q);
+ gpointer r;
+ result_t *res;
+ int type = -1;
+ act((tagdb*) db, q, &r, &type);
+ res = encapsulate((tagdb*) db, type, r);
+ res_info(res);
+ printf("\n");
+
+ g_free(str);
+}
+
+void query_is_empty (gpointer tagname, gpointer db)
+{
+ printf("TAG NAME: %s\n", (gchar*) tagname);
+ gchar *str = g_strjoin(" ", "TAG IS_EMPTY", (gchar*) tagname, NULL);
+ query_t *q = parse(str);
+ query_info(q);
+ gpointer r;
+ result_t *res;
+ int type = -1;
+ act((tagdb*) db, q, &r, &type);
+ res = encapsulate((tagdb*) db, type, r);
+ res_info(res);
+ printf("\n");
+
+ g_free(str);
+}
+
+int main ()
+{
+ tagdb *db = newdb("test.db");
+ GList *t1 = g_list_new("blue", "name", "tag014");
+ GList *t2 = g_hash_table_get_keys(db->tables[FILE_TABLE]);
+ g_list_foreach(t1, query_is_empty, db);
+ g_list_foreach(t2, query_file_has_tags, db);
+ g_list_free(t1);
+ g_list_free(t2);
+ return 0;
+}
View
37 types.h
@@ -0,0 +1,37 @@
+#ifndef TYPES_H
+#define TYPES_H
+
+// enumeration of types in result_t
+enum _tagdb_types
+{
+ tagdb_dict_t,
+ tagdb_int_t,
+ tagdb_str_t,
+} tagdb_types;
+
+union result_d
+{
+ GHashTable *d;
+ int i;
+ char *s;
+ gpointer b;
+};
+
+struct query_t
+{
+ int table_id;
+ int command_id;
+ int argc;
+ gchar* argv[256];
+};
+
+struct result_t
+{
+ int type;
+ union result_d data;
+};
+
+typedef struct query_t query_t;
+typedef struct result_t result_t;
+
+#endif /* TYPES_H */
Please sign in to comment.
Something went wrong with that request. Please try again.