-
Notifications
You must be signed in to change notification settings - Fork 0
/
query.lc
149 lines (137 loc) · 3.76 KB
/
query.lc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* Query API for TagDB
*
* Parses query strings and calls the appropriate methods.
*/
#include <malloc.h>
#include <string.h>
#include "query.h"
#include "types.h"
#include "scanner.h"
#include "set_ops.h"
#include "util.h"
#include "log.h"
#include "queries.c"
static int _log_level = 1;
// checks if the argc is correct and fills the result and type with the appropriate error
int check_argc (int argc, int required, gpointer *result, char **type)
{
if (argc < required)
{
%(qerr Too few arguments);
}
return argc;
}
/* Query functions
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 strings)
finally, functions will take a pointer to a TagDB and a table id as named arguments,
thus functions will have the form:
*/
/* 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
*/
query_t *parse (const char *s)
{
log_msg("");
if (s == NULL)
return NULL;
query_t *qr = malloc(sizeof(query_t));
char *qs = g_strstrip(g_strdup(s));
char *sep;
char *token = NULL;
GList *seps = g_list_new(" ", NULL);
GList *quotes = g_list_new("\"", NULL);
Scanner *scn = scanner_new2(seps, quotes);
scanner_set_str_stream(scn, qs);
g_free(qs);
token = scanner_next(scn, &sep);
const char *class_strings[] = {"FILE", "TAG", NULL};
qr->class_id = strv_index(class_strings, token);
if (qr->class_id == -1)
{
free(qr);
return NULL;
}
g_free(token);
token = scanner_next(scn, &sep);
qr->command_id = strv_index(query_cmdstrs[qr->class_id], token);
g_free(token);
if (qr->command_id == -1)
{
free(qr);
return NULL;
}
int i = 0;
while (!scanner_stream_is_empty(scn->stream) && i < MAX_QUERY_ARGS)
{
token = scanner_next(scn, &sep);
qr->argv[i] = token;
i++;
}
scanner_destroy(scn);
qr->argv[i] = NULL;
qr->argc = i;
return qr;
}
// action takes a compiled query and performs the action on the database db
// query
void act (TagDB *db, query_t *q, gpointer *result, char **type)
{
log_query_info(q);
query_functions[q->class_id][q->command_id](db, q->argc, q->argv, result, type);
// log_msg("Exiting act\n");
}
void print_query_info (query_t *q, printer p)
{
if (q==NULL)
{
p("query_info: got q==NULL\n");
return;
}
p("query info:\n");
p("\tclass: %s\n", query_class_names[ q->class_id ]);
p("\tcommand: %s\n", query_cmdstrs[q->class_id][q->command_id]);
p("\targc: %d\n", q->argc);
int i;
for (i = 0; i < q->argc; i++)
{
p("\targv[%d] = %s\n", i, q->argv[i]);
}
}
void query_info (query_t *q)
{
print_query_info(q, (printer)printf);
}
void log_query_info (query_t *q)
{
lock_log();
print_query_info(q, log_msg0);
unlock_log();
}
// does all of the steps for you
result_t *tagdb_query (TagDB *db, const char *query)
{
gpointer r = NULL;
query_t *q = parse(query);
if (q == NULL)
return tagdb_str_to_value(tagdb_err_t, "Invalid query");
char *type = NULL;
act(db, q, &r, &type);
query_destroy(q);
result_t *res = encapsulate(type, r);
g_free(type);
res_info(res, log_msg0);
return res;
}