]> jfr.im git - irc/quakenet/newserv.git/blob - newsearch/newsearch_ast.c
d77f0a215bb443b04db79888568d6ffb95f6da70
[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) {
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);
140
141 buf[0] = '\0';
142 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_nicksearch));
143 search = ctx.parser(&ctx, (char *)tree);
144 if(!search) {
145 reply(sender, "Parse error: %s", parseError);
146 return CMD_ERROR;
147 }
148
149 reply(sender, "Executing...");
150 if(header)
151 header(sender, headerarg);
152 nicksearch_exe(search, &ctx);
153
154 (search->free)(&ctx, search);
155
156 return CMD_OK;
157 }
158
159 int ast_whowassearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, WhowasDisplayFunc display, HeaderFunc header, void *headerarg, int limit) {
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
168 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_whowassearch, sender, display, limit);
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
188 int ast_chansearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, ChanDisplayFunc display, HeaderFunc header, void *headerarg, int limit) {
189 searchCtx ctx;
190 searchASTCache cache;
191 searchNode *search;
192 char buf[1024];
193
194 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_chansearch, sender, display, limit);
195
196 memset(&cache, 0, sizeof(cache));
197 cache.tree = tree;
198
199 buf[0] = '\0';
200 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_chansearch));
201 search = ctx.parser(&ctx, (char *)tree);
202 if(!search) {
203 reply(sender, "Parse error: %s", parseError);
204 return CMD_ERROR;
205 }
206
207 reply(sender, "Executing...");
208 if(header)
209 header(sender, headerarg);
210 chansearch_exe(search, &ctx);
211
212 (search->free)(&ctx, search);
213
214 return CMD_OK;
215 }
216
217 int ast_usersearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, UserDisplayFunc display, HeaderFunc header, void *headerarg, int limit) {
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
226 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_usersearch, sender, display, limit);
227
228 buf[0] = '\0';
229 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_usersearch));
230 search = ctx.parser(&ctx, (char *)tree);
231 if(!search) {
232 reply(sender, "Parse error: %s", parseError);
233 return CMD_ERROR;
234 }
235
236 reply(sender, "Executing...");
237 if(header)
238 header(sender, headerarg);
239 usersearch_exe(search, &ctx);
240
241 (search->free)(&ctx, search);
242
243 return CMD_OK;
244 }
245
246
247 /* horribly inefficient -- don't call me very often! */
248 static char *ast_printtree_real(StringBuf *buf, searchASTExpr *expr, searchCmd *cmd) {
249 char lbuf[256];
250 if(expr->type == AST_NODE_CHILD) {
251 int i;
252 sstring *command = getcommandname(cmd->searchtree, (void *)expr->u.child.fn);
253
254 if(command) {
255 snprintf(lbuf, sizeof(lbuf), "(%s", command->content);
256 } else {
257 snprintf(lbuf, sizeof(lbuf), "(%p", expr->u.child.fn);
258 }
259 sbaddstr(buf, lbuf);
260
261 for(i=0;i<expr->u.child.argc;i++) {
262 sbaddchar(buf, ' ');
263 ast_printtree_real(buf, &expr->u.child.argv[i], cmd);
264 }
265 sbaddchar(buf, ')');
266
267 } else if(expr->type == AST_NODE_LITERAL) {
268 char *p;
269
270 sbaddchar(buf, '"');
271
272 for(p=expr->u.literal;*p;p++) {
273 if(*p == '\\' || *p == '"')
274 sbaddchar(buf, '\\');
275 sbaddchar(buf, *p);
276 }
277
278 sbaddchar(buf, '"');
279 } else {
280 sbaddstr(buf, "???");
281 }
282
283 return buf->buf;
284 }
285
286 char *ast_printtree(char *buf, size_t bufsize, searchASTExpr *expr, searchCmd *cmd) {
287 StringBuf b;
288 char *p;
289
290 b.capacity = bufsize;
291 b.len = 0;
292 b.buf = buf;
293
294 p = ast_printtree_real(&b, expr, cmd);
295
296 sbterminate(&b);
297 return p;
298 }