]> jfr.im git - irc/quakenet/newserv.git/blame - newsearch/newsearch_ast.c
LUA: port luadb to dbapi2 to drop postgres dependency
[irc/quakenet/newserv.git] / newsearch / newsearch_ast.c
CommitLineData
0a659cde
CP
1#include "newsearch.h"
2#include "../lib/sstring.h"
3#include "../lib/strlfunc.h"
a3176c57 4#include "../lib/stringbuf.h"
0a659cde
CP
5#include <stdarg.h>
6#include <string.h>
7
8/* at least we have some type safety... */
9typedef union exprunion {
10 searchASTExpr *expr;
11 char *literal;
12} exprunion;
13
0a659cde
CP
14/* comares either a string and a string or an expression and an expression */
15static searchASTExpr *compareloc(searchASTExpr *expr, exprunion *loc) {
16 if(expr->type == AST_NODE_LITERAL) {
17 if(expr->u.literal == loc->literal)
18 return expr;
19 } else if(expr->type == AST_NODE_CHILD) {
20 if(expr == loc->expr)
21 return expr;
22 } else {
23 parseError = "static_parse_compare: bad node type";
24 return NULL;
25 }
26 return NULL;
27}
28
29/* searches the abstract syntax tree for the supplied expression/string */
30static searchASTExpr *treesearch(searchASTExpr *expr, exprunion *loc) {
31 searchASTExpr *ret = compareloc(expr, loc);
32 if(ret)
33 return ret;
34
35 if(expr->type == AST_NODE_CHILD) {
36 int i;
68d05acb
CP
37 for(i=0;i<expr->u.child.argc;i++) {
38 searchASTExpr *d = treesearch(&expr->u.child.argv[i], loc);
0a659cde
CP
39 if(d)
40 return d;
41 }
42 }
43 return NULL;
44}
45
46/*
47 * searches the AST cache, if this fails it goes and searches the tree.
48 * the cache is hit most of the time and I guess makes it nearly O(1) amortised...
49 */
50searchASTExpr *cachesearch(searchASTCache *cache, exprunion *loc) {
51 searchASTExpr *ret = compareloc(cache->tree, loc);
52 int i;
53 if(ret)
54 return ret;
55
56 for(i=0;i<AST_RECENT;i++) {
57 if(!cache->cache[i])
58 continue;
59 ret = compareloc(cache->cache[i], loc);
60 if(ret)
61 return ret;
62 }
63
64 return treesearch(cache->tree, loc);
65}
66
67/* pushes an item into the cache */
68static void cachepush(searchASTCache *cache, searchASTExpr *expr) {
69 cache->cache[cache->nextpos] = expr;
70 cache->nextpos = (cache->nextpos + 1) % AST_RECENT;
71}
72
73/* ast parser, the way we pass context around is very very hacky... */
f33f3f52 74searchNode *search_astparse(searchCtx *ctx, char *loc) {
0a659cde
CP
75 searchASTCache *cache = ctx->arg;
76 searchASTExpr *expr = cachesearch(cache, (exprunion *)&loc);
77 searchNode *node;
78 char **v;
79 int i;
80
81 if(!expr) {
82 parseError = "WARNING: AST parsing failed";
83 return NULL;
84 }
85
86 switch(expr->type) {
87 case AST_NODE_LITERAL:
88 if (!(node=(searchNode *)malloc(sizeof(searchNode)))) {
89 parseError = "malloc: could not allocate memory for this search.";
90 return NULL;
91 }
92 node->localdata = getsstring(expr->u.literal,512);
93 node->returntype = RETURNTYPE_CONST | RETURNTYPE_STRING;
94 node->exe = literal_exe;
95 node->free = literal_free;
96 return node;
97 case AST_NODE_CHILD:
68d05acb 98 v = (char **)malloc(expr->u.child.argc * sizeof(char *));
0a659cde
CP
99 if(!v) {
100 parseError = "malloc: could not allocate memory for this search.";
101 return NULL;
102 }
68d05acb
CP
103 for(i=0;i<expr->u.child.argc;i++) {
104 searchASTExpr *child = &expr->u.child.argv[i];
0a659cde
CP
105
106 cachepush(cache, child);
107 switch(child->type) {
108 case AST_NODE_LITERAL:
109 v[i] = child->u.literal;
110 break;
111 case AST_NODE_CHILD:
112 v[i] = (char *)child;
113 break;
114 default:
115 parseError = "static_parse: bad child node type";
116 free(v);
117 return NULL;
118 }
119 }
120
68d05acb 121 node = expr->u.child.fn(ctx, expr->u.child.argc, v);
0a659cde
CP
122 free(v);
123 return node;
124 default:
125 parseError = "static_parse: bad node type";
126 return NULL;
127 }
128}
129
59694aa9 130int ast_nicksearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, NickDisplayFunc display, HeaderFunc header, void *headerarg, int limit, array *targets) {
0a659cde
CP
131 searchCtx ctx;
132 searchASTCache cache;
133 searchNode *search;
134 char buf[1024];
135
136 memset(&cache, 0, sizeof(cache));
137 cache.tree = tree;
138
59694aa9 139 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_nicksearch, sender, display, limit, targets);
0a659cde
CP
140
141 buf[0] = '\0';
59694aa9
GB
142 if (!targets)
143 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_nicksearch));
f33f3f52 144 search = ctx.parser(&ctx, (char *)tree);
0a659cde 145 if(!search) {
59694aa9
GB
146 if (!targets)
147 reply(sender, "Parse error: %s", parseError);
0a659cde
CP
148 return CMD_ERROR;
149 }
150
59694aa9
GB
151 if (!targets)
152 reply(sender, "Executing...");
2181a10f
CP
153 if(header)
154 header(sender, headerarg);
6b2202d0 155 nicksearch_exe(search, &ctx);
0a659cde
CP
156
157 (search->free)(&ctx, search);
158
159 return CMD_OK;
160}
161
59694aa9 162int ast_whowassearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, WhowasDisplayFunc display, HeaderFunc header, void *headerarg, int limit, array *targets) {
0eb4cbd3
GB
163 searchCtx ctx;
164 searchASTCache cache;
165 searchNode *search;
166 char buf[1024];
167
168 memset(&cache, 0, sizeof(cache));
169 cache.tree = tree;
170
59694aa9 171 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_whowassearch, sender, display, limit, targets);
0eb4cbd3
GB
172
173 buf[0] = '\0';
174 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_whowassearch));
175 search = ctx.parser(&ctx, (char *)tree);
176 if(!search) {
177 reply(sender, "Parse error: %s", parseError);
178 return CMD_ERROR;
179 }
180
181 reply(sender, "Executing...");
182 if(header)
183 header(sender, headerarg);
184 whowassearch_exe(search, &ctx);
185
186 (search->free)(&ctx, search);
187
188 return CMD_OK;
189}
190
59694aa9 191int ast_chansearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, ChanDisplayFunc display, HeaderFunc header, void *headerarg, int limit, array *targets) {
0a659cde
CP
192 searchCtx ctx;
193 searchASTCache cache;
194 searchNode *search;
195 char buf[1024];
196
59694aa9 197 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_chansearch, sender, display, limit, targets);
0a659cde 198
3819ea3f
CP
199 memset(&cache, 0, sizeof(cache));
200 cache.tree = tree;
201
0a659cde 202 buf[0] = '\0';
a92bb8e1 203 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_chansearch));
f33f3f52 204 search = ctx.parser(&ctx, (char *)tree);
0a659cde
CP
205 if(!search) {
206 reply(sender, "Parse error: %s", parseError);
207 return CMD_ERROR;
208 }
209
210 reply(sender, "Executing...");
2181a10f
CP
211 if(header)
212 header(sender, headerarg);
6b2202d0 213 chansearch_exe(search, &ctx);
0a659cde
CP
214
215 (search->free)(&ctx, search);
216
217 return CMD_OK;
218}
219
59694aa9 220int ast_usersearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, UserDisplayFunc display, HeaderFunc header, void *headerarg, int limit, array *targets) {
cef8cb48
CP
221 searchCtx ctx;
222 searchASTCache cache;
223 searchNode *search;
224 char buf[1024];
225
226 memset(&cache, 0, sizeof(cache));
227 cache.tree = tree;
228
59694aa9 229 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_usersearch, sender, display, limit, targets);
cef8cb48
CP
230
231 buf[0] = '\0';
a92bb8e1 232 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_usersearch));
f33f3f52 233 search = ctx.parser(&ctx, (char *)tree);
cef8cb48
CP
234 if(!search) {
235 reply(sender, "Parse error: %s", parseError);
236 return CMD_ERROR;
237 }
238
239 reply(sender, "Executing...");
2181a10f
CP
240 if(header)
241 header(sender, headerarg);
6b2202d0 242 usersearch_exe(search, &ctx);
cef8cb48
CP
243
244 (search->free)(&ctx, search);
245
246 return CMD_OK;
247}
248
a3176c57
CP
249
250/* horribly inefficient -- don't call me very often! */
a92bb8e1 251static char *ast_printtree_real(StringBuf *buf, searchASTExpr *expr, searchCmd *cmd) {
0a659cde
CP
252 char lbuf[256];
253 if(expr->type == AST_NODE_CHILD) {
254 int i;
68d05acb 255 sstring *command = getcommandname(cmd->searchtree, (void *)expr->u.child.fn);
0a659cde
CP
256
257 if(command) {
a3176c57 258 snprintf(lbuf, sizeof(lbuf), "(%s", command->content);
0a659cde 259 } else {
68d05acb 260 snprintf(lbuf, sizeof(lbuf), "(%p", expr->u.child.fn);
0a659cde 261 }
a3176c57 262 sbaddstr(buf, lbuf);
0a659cde 263
68d05acb 264 for(i=0;i<expr->u.child.argc;i++) {
a3176c57 265 sbaddchar(buf, ' ');
68d05acb 266 ast_printtree_real(buf, &expr->u.child.argv[i], cmd);
a3176c57
CP
267 }
268 sbaddchar(buf, ')');
0a659cde 269
0a659cde 270 } else if(expr->type == AST_NODE_LITERAL) {
68d05acb 271 char *p;
47d8abc1
CP
272
273 sbaddchar(buf, '"');
274
275 for(p=expr->u.literal;*p;p++) {
276 if(*p == '\\' || *p == '"')
277 sbaddchar(buf, '\\');
278 sbaddchar(buf, *p);
68d05acb
CP
279 }
280
47d8abc1 281 sbaddchar(buf, '"');
0a659cde 282 } else {
a3176c57 283 sbaddstr(buf, "???");
0a659cde
CP
284 }
285
a3176c57
CP
286 return buf->buf;
287}
288
a92bb8e1 289char *ast_printtree(char *buf, size_t bufsize, searchASTExpr *expr, searchCmd *cmd) {
a3176c57
CP
290 StringBuf b;
291 char *p;
292
293 b.capacity = bufsize;
294 b.len = 0;
295 b.buf = buf;
296
a92bb8e1 297 p = ast_printtree_real(&b, expr, cmd);
a3176c57
CP
298
299 sbterminate(&b);
300 return p;
0a659cde 301}