]> jfr.im git - irc/quakenet/newserv.git/blame - newsearch/newsearch_ast.c
New module: nickwatch
[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
4860501e 130int ast_nicksearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, NickDisplayFunc display, HeaderFunc header, void *headerarg, int limit, nick *target) {
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
4860501e 139 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_nicksearch, sender, display, limit, target);
0a659cde
CP
140
141 buf[0] = '\0';
a92bb8e1 142 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_nicksearch));
f33f3f52 143 search = ctx.parser(&ctx, (char *)tree);
0a659cde
CP
144 if(!search) {
145 reply(sender, "Parse error: %s", parseError);
146 return CMD_ERROR;
147 }
148
149 reply(sender, "Executing...");
2181a10f
CP
150 if(header)
151 header(sender, headerarg);
6b2202d0 152 nicksearch_exe(search, &ctx);
0a659cde
CP
153
154 (search->free)(&ctx, search);
155
156 return CMD_OK;
157}
158
4860501e 159int ast_whowassearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, WhowasDisplayFunc display, HeaderFunc header, void *headerarg, int limit, whowas *target) {
0eb4cbd3
GB
160 searchCtx ctx;
161 searchASTCache cache;
162 searchNode *search;
163 char buf[1024];
164
165 memset(&cache, 0, sizeof(cache));
166 cache.tree = tree;
167
4860501e 168 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_whowassearch, sender, display, limit, target);
0eb4cbd3
GB
169
170 buf[0] = '\0';
171 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_whowassearch));
172 search = ctx.parser(&ctx, (char *)tree);
173 if(!search) {
174 reply(sender, "Parse error: %s", parseError);
175 return CMD_ERROR;
176 }
177
178 reply(sender, "Executing...");
179 if(header)
180 header(sender, headerarg);
181 whowassearch_exe(search, &ctx);
182
183 (search->free)(&ctx, search);
184
185 return CMD_OK;
186}
187
4860501e 188int ast_chansearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, ChanDisplayFunc display, HeaderFunc header, void *headerarg, int limit, chanindex *target) {
0a659cde
CP
189 searchCtx ctx;
190 searchASTCache cache;
191 searchNode *search;
192 char buf[1024];
193
4860501e 194 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_chansearch, sender, display, limit, target);
0a659cde 195
3819ea3f
CP
196 memset(&cache, 0, sizeof(cache));
197 cache.tree = tree;
198
0a659cde 199 buf[0] = '\0';
a92bb8e1 200 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_chansearch));
f33f3f52 201 search = ctx.parser(&ctx, (char *)tree);
0a659cde
CP
202 if(!search) {
203 reply(sender, "Parse error: %s", parseError);
204 return CMD_ERROR;
205 }
206
207 reply(sender, "Executing...");
2181a10f
CP
208 if(header)
209 header(sender, headerarg);
6b2202d0 210 chansearch_exe(search, &ctx);
0a659cde
CP
211
212 (search->free)(&ctx, search);
213
214 return CMD_OK;
215}
216
4860501e 217int ast_usersearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, UserDisplayFunc display, HeaderFunc header, void *headerarg, int limit, authname *target) {
cef8cb48
CP
218 searchCtx ctx;
219 searchASTCache cache;
220 searchNode *search;
221 char buf[1024];
222
223 memset(&cache, 0, sizeof(cache));
224 cache.tree = tree;
225
4860501e 226 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_usersearch, sender, display, limit, target);
cef8cb48
CP
227
228 buf[0] = '\0';
a92bb8e1 229 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_usersearch));
f33f3f52 230 search = ctx.parser(&ctx, (char *)tree);
cef8cb48
CP
231 if(!search) {
232 reply(sender, "Parse error: %s", parseError);
233 return CMD_ERROR;
234 }
235
236 reply(sender, "Executing...");
2181a10f
CP
237 if(header)
238 header(sender, headerarg);
6b2202d0 239 usersearch_exe(search, &ctx);
cef8cb48
CP
240
241 (search->free)(&ctx, search);
242
243 return CMD_OK;
244}
245
a3176c57
CP
246
247/* horribly inefficient -- don't call me very often! */
a92bb8e1 248static char *ast_printtree_real(StringBuf *buf, searchASTExpr *expr, searchCmd *cmd) {
0a659cde
CP
249 char lbuf[256];
250 if(expr->type == AST_NODE_CHILD) {
251 int i;
68d05acb 252 sstring *command = getcommandname(cmd->searchtree, (void *)expr->u.child.fn);
0a659cde
CP
253
254 if(command) {
a3176c57 255 snprintf(lbuf, sizeof(lbuf), "(%s", command->content);
0a659cde 256 } else {
68d05acb 257 snprintf(lbuf, sizeof(lbuf), "(%p", expr->u.child.fn);
0a659cde 258 }
a3176c57 259 sbaddstr(buf, lbuf);
0a659cde 260
68d05acb 261 for(i=0;i<expr->u.child.argc;i++) {
a3176c57 262 sbaddchar(buf, ' ');
68d05acb 263 ast_printtree_real(buf, &expr->u.child.argv[i], cmd);
a3176c57
CP
264 }
265 sbaddchar(buf, ')');
0a659cde 266
0a659cde 267 } else if(expr->type == AST_NODE_LITERAL) {
68d05acb 268 char *p;
47d8abc1
CP
269
270 sbaddchar(buf, '"');
271
272 for(p=expr->u.literal;*p;p++) {
273 if(*p == '\\' || *p == '"')
274 sbaddchar(buf, '\\');
275 sbaddchar(buf, *p);
68d05acb
CP
276 }
277
47d8abc1 278 sbaddchar(buf, '"');
0a659cde 279 } else {
a3176c57 280 sbaddstr(buf, "???");
0a659cde
CP
281 }
282
a3176c57
CP
283 return buf->buf;
284}
285
a92bb8e1 286char *ast_printtree(char *buf, size_t bufsize, searchASTExpr *expr, searchCmd *cmd) {
a3176c57
CP
287 StringBuf b;
288 char *p;
289
290 b.capacity = bufsize;
291 b.len = 0;
292 b.buf = buf;
293
a92bb8e1 294 p = ast_printtree_real(&b, expr, cmd);
a3176c57
CP
295
296 sbterminate(&b);
297 return p;
0a659cde 298}