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