]> jfr.im git - irc/quakenet/newserv.git/blob - newsearch/newsearch_ast.c
LUA: port luadb to dbapi2 to drop postgres dependency
[irc/quakenet/newserv.git] / newsearch / newsearch_ast.c
1 #include "newsearch.h"
2 #include "../lib/sstring.h"
3 #include "../lib/strlfunc.h"
4 #include "../lib/stringbuf.h"
5 #include <stdarg.h>
6 #include <string.h>
7
8 /* at least we have some type safety... */
9 typedef union exprunion {
10 searchASTExpr *expr;
11 char *literal;
12 } exprunion;
13
14 /* comares either a string and a string or an expression and an expression */
15 static 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 */
30 static 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;
37 for(i=0;i<expr->u.child.argc;i++) {
38 searchASTExpr *d = treesearch(&expr->u.child.argv[i], loc);
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 */
50 searchASTExpr *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 */
68 static 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... */
74 searchNode *search_astparse(searchCtx *ctx, char *loc) {
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:
98 v = (char **)malloc(expr->u.child.argc * sizeof(char *));
99 if(!v) {
100 parseError = "malloc: could not allocate memory for this search.";
101 return NULL;
102 }
103 for(i=0;i<expr->u.child.argc;i++) {
104 searchASTExpr *child = &expr->u.child.argv[i];
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
121 node = expr->u.child.fn(ctx, expr->u.child.argc, v);
122 free(v);
123 return node;
124 default:
125 parseError = "static_parse: bad node type";
126 return NULL;
127 }
128 }
129
130 int ast_nicksearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, NickDisplayFunc display, HeaderFunc header, void *headerarg, int limit, array *targets) {
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
139 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_nicksearch, sender, display, limit, targets);
140
141 buf[0] = '\0';
142 if (!targets)
143 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_nicksearch));
144 search = ctx.parser(&ctx, (char *)tree);
145 if(!search) {
146 if (!targets)
147 reply(sender, "Parse error: %s", parseError);
148 return CMD_ERROR;
149 }
150
151 if (!targets)
152 reply(sender, "Executing...");
153 if(header)
154 header(sender, headerarg);
155 nicksearch_exe(search, &ctx);
156
157 (search->free)(&ctx, search);
158
159 return CMD_OK;
160 }
161
162 int ast_whowassearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, WhowasDisplayFunc display, HeaderFunc header, void *headerarg, int limit, array *targets) {
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
171 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_whowassearch, sender, display, limit, targets);
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
191 int ast_chansearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, ChanDisplayFunc display, HeaderFunc header, void *headerarg, int limit, array *targets) {
192 searchCtx ctx;
193 searchASTCache cache;
194 searchNode *search;
195 char buf[1024];
196
197 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_chansearch, sender, display, limit, targets);
198
199 memset(&cache, 0, sizeof(cache));
200 cache.tree = tree;
201
202 buf[0] = '\0';
203 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_chansearch));
204 search = ctx.parser(&ctx, (char *)tree);
205 if(!search) {
206 reply(sender, "Parse error: %s", parseError);
207 return CMD_ERROR;
208 }
209
210 reply(sender, "Executing...");
211 if(header)
212 header(sender, headerarg);
213 chansearch_exe(search, &ctx);
214
215 (search->free)(&ctx, search);
216
217 return CMD_OK;
218 }
219
220 int ast_usersearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, UserDisplayFunc display, HeaderFunc header, void *headerarg, int limit, array *targets) {
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
229 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_usersearch, sender, display, limit, targets);
230
231 buf[0] = '\0';
232 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_usersearch));
233 search = ctx.parser(&ctx, (char *)tree);
234 if(!search) {
235 reply(sender, "Parse error: %s", parseError);
236 return CMD_ERROR;
237 }
238
239 reply(sender, "Executing...");
240 if(header)
241 header(sender, headerarg);
242 usersearch_exe(search, &ctx);
243
244 (search->free)(&ctx, search);
245
246 return CMD_OK;
247 }
248
249
250 /* horribly inefficient -- don't call me very often! */
251 static char *ast_printtree_real(StringBuf *buf, searchASTExpr *expr, searchCmd *cmd) {
252 char lbuf[256];
253 if(expr->type == AST_NODE_CHILD) {
254 int i;
255 sstring *command = getcommandname(cmd->searchtree, (void *)expr->u.child.fn);
256
257 if(command) {
258 snprintf(lbuf, sizeof(lbuf), "(%s", command->content);
259 } else {
260 snprintf(lbuf, sizeof(lbuf), "(%p", expr->u.child.fn);
261 }
262 sbaddstr(buf, lbuf);
263
264 for(i=0;i<expr->u.child.argc;i++) {
265 sbaddchar(buf, ' ');
266 ast_printtree_real(buf, &expr->u.child.argv[i], cmd);
267 }
268 sbaddchar(buf, ')');
269
270 } else if(expr->type == AST_NODE_LITERAL) {
271 char *p;
272
273 sbaddchar(buf, '"');
274
275 for(p=expr->u.literal;*p;p++) {
276 if(*p == '\\' || *p == '"')
277 sbaddchar(buf, '\\');
278 sbaddchar(buf, *p);
279 }
280
281 sbaddchar(buf, '"');
282 } else {
283 sbaddstr(buf, "???");
284 }
285
286 return buf->buf;
287 }
288
289 char *ast_printtree(char *buf, size_t bufsize, searchASTExpr *expr, searchCmd *cmd) {
290 StringBuf b;
291 char *p;
292
293 b.capacity = bufsize;
294 b.len = 0;
295 b.buf = buf;
296
297 p = ast_printtree_real(&b, expr, cmd);
298
299 sbterminate(&b);
300 return p;
301 }