]> jfr.im git - irc/quakenet/newserv.git/blame - newsearch/newsearch_ast.c
merge
[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
2181a10f 130int ast_nicksearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, NickDisplayFunc display, HeaderFunc header, void *headerarg, int limit) {
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
6b2202d0 139 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_nicksearch, sender, display, limit);
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
2181a10f 159int ast_chansearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, ChanDisplayFunc display, HeaderFunc header, void *headerarg, int limit) {
0a659cde
CP
160 searchCtx ctx;
161 searchASTCache cache;
162 searchNode *search;
163 char buf[1024];
164
6b2202d0 165 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_chansearch, sender, display, limit);
0a659cde 166
3819ea3f
CP
167 memset(&cache, 0, sizeof(cache));
168 cache.tree = tree;
169
0a659cde 170 buf[0] = '\0';
a92bb8e1 171 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_chansearch));
f33f3f52 172 search = ctx.parser(&ctx, (char *)tree);
0a659cde
CP
173 if(!search) {
174 reply(sender, "Parse error: %s", parseError);
175 return CMD_ERROR;
176 }
177
178 reply(sender, "Executing...");
2181a10f
CP
179 if(header)
180 header(sender, headerarg);
6b2202d0 181 chansearch_exe(search, &ctx);
0a659cde
CP
182
183 (search->free)(&ctx, search);
184
185 return CMD_OK;
186}
187
2181a10f 188int ast_usersearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, UserDisplayFunc display, HeaderFunc header, void *headerarg, int limit) {
cef8cb48
CP
189 searchCtx ctx;
190 searchASTCache cache;
191 searchNode *search;
192 char buf[1024];
193
194 memset(&cache, 0, sizeof(cache));
195 cache.tree = tree;
196
6b2202d0 197 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_usersearch, sender, display, limit);
cef8cb48
CP
198
199 buf[0] = '\0';
a92bb8e1 200 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_usersearch));
f33f3f52 201 search = ctx.parser(&ctx, (char *)tree);
cef8cb48
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 usersearch_exe(search, &ctx);
cef8cb48
CP
211
212 (search->free)(&ctx, search);
213
214 return CMD_OK;
215}
216
a3176c57
CP
217
218/* horribly inefficient -- don't call me very often! */
a92bb8e1 219static char *ast_printtree_real(StringBuf *buf, searchASTExpr *expr, searchCmd *cmd) {
0a659cde
CP
220 char lbuf[256];
221 if(expr->type == AST_NODE_CHILD) {
222 int i;
68d05acb 223 sstring *command = getcommandname(cmd->searchtree, (void *)expr->u.child.fn);
0a659cde
CP
224
225 if(command) {
a3176c57 226 snprintf(lbuf, sizeof(lbuf), "(%s", command->content);
0a659cde 227 } else {
68d05acb 228 snprintf(lbuf, sizeof(lbuf), "(%p", expr->u.child.fn);
0a659cde 229 }
a3176c57 230 sbaddstr(buf, lbuf);
0a659cde 231
68d05acb 232 for(i=0;i<expr->u.child.argc;i++) {
a3176c57 233 sbaddchar(buf, ' ');
68d05acb 234 ast_printtree_real(buf, &expr->u.child.argv[i], cmd);
a3176c57
CP
235 }
236 sbaddchar(buf, ')');
0a659cde 237
0a659cde 238 } else if(expr->type == AST_NODE_LITERAL) {
68d05acb 239 char *p;
47d8abc1
CP
240
241 sbaddchar(buf, '"');
242
243 for(p=expr->u.literal;*p;p++) {
244 if(*p == '\\' || *p == '"')
245 sbaddchar(buf, '\\');
246 sbaddchar(buf, *p);
68d05acb
CP
247 }
248
47d8abc1 249 sbaddchar(buf, '"');
0a659cde 250 } else {
a3176c57 251 sbaddstr(buf, "???");
0a659cde
CP
252 }
253
a3176c57
CP
254 return buf->buf;
255}
256
a92bb8e1 257char *ast_printtree(char *buf, size_t bufsize, searchASTExpr *expr, searchCmd *cmd) {
a3176c57
CP
258 StringBuf b;
259 char *p;
260
261 b.capacity = bufsize;
262 b.len = 0;
263 b.buf = buf;
264
a92bb8e1 265 p = ast_printtree_real(&b, expr, cmd);
a3176c57
CP
266
267 sbterminate(&b);
268 return p;
0a659cde 269}