]> jfr.im git - irc/quakenet/newserv.git/blob - newsearch/newsearch_ast.c
5925d447f4fa4870434a073f6eafc7c4d66b91e1
[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 typedef 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 */
21 static 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 */
36 static 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;
43 for(i=0;i<expr->u.child->argc;i++) {
44 searchASTExpr *d = treesearch(expr->u.child->argv[i], loc);
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 */
56 searchASTExpr *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 */
74 static 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... */
80 searchNode *search_astparse(searchCtx *ctx, char *loc) {
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:
104 v = (char **)malloc(expr->u.child->argc * sizeof(char *));
105 if(!v) {
106 parseError = "malloc: could not allocate memory for this search.";
107 return NULL;
108 }
109 for(i=0;i<expr->u.child->argc;i++) {
110 searchASTExpr *child = expr->u.child->argv[i];
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
127 node = expr->u.child->fn(ctx, expr->u.child->argc, v);
128 free(v);
129 return node;
130 default:
131 parseError = "static_parse: bad node type";
132 return NULL;
133 }
134 }
135
136 int ast_nicksearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, NickDisplayFunc display, HeaderFunc header, void *headerarg, int limit) {
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
145 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_nicksearch);
146
147 buf[0] = '\0';
148 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_nicksearch));
149 search = ctx.parser(&ctx, (char *)tree);
150 if(!search) {
151 reply(sender, "Parse error: %s", parseError);
152 return CMD_ERROR;
153 }
154
155 reply(sender, "Executing...");
156 if(header)
157 header(sender, headerarg);
158 nicksearch_exe(search, &ctx, sender, display, limit);
159
160 (search->free)(&ctx, search);
161
162 return CMD_OK;
163 }
164
165 int ast_chansearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, ChanDisplayFunc display, HeaderFunc header, void *headerarg, int limit) {
166 searchCtx ctx;
167 searchASTCache cache;
168 searchNode *search;
169 char buf[1024];
170
171 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_chansearch);
172
173 buf[0] = '\0';
174 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_chansearch));
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 chansearch_exe(search, &ctx, sender, display, limit);
185
186 (search->free)(&ctx, search);
187
188 return CMD_OK;
189 }
190
191 int ast_usersearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, UserDisplayFunc display, HeaderFunc header, void *headerarg, int limit) {
192 searchCtx ctx;
193 searchASTCache cache;
194 searchNode *search;
195 char buf[1024];
196
197 memset(&cache, 0, sizeof(cache));
198 cache.tree = tree;
199
200 newsearch_ctxinit(&ctx, search_astparse, reply, wall, &cache, reg_usersearch);
201
202 buf[0] = '\0';
203 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree, reg_usersearch));
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 usersearch_exe(search, &ctx, sender, display, limit);
214
215 (search->free)(&ctx, search);
216
217 return CMD_OK;
218 }
219
220
221 /* horribly inefficient -- don't call me very often! */
222 static char *ast_printtree_real(StringBuf *buf, searchASTExpr *expr, searchCmd *cmd) {
223 char lbuf[256];
224 if(expr->type == AST_NODE_CHILD) {
225 int i;
226 sstring *command = getcommandname(cmd->searchtree, (void *)expr->u.child->fn);
227
228 if(command) {
229 snprintf(lbuf, sizeof(lbuf), "(%s", command->content);
230 } else {
231 snprintf(lbuf, sizeof(lbuf), "(%p", expr->u.child->fn);
232 }
233 sbaddstr(buf, lbuf);
234
235 for(i=0;i<expr->u.child->argc;i++) {
236 sbaddchar(buf, ' ');
237 ast_printtree_real(buf, expr->u.child->argv[i], cmd);
238 }
239 sbaddchar(buf, ')');
240
241 } else if(expr->type == AST_NODE_LITERAL) {
242 sbaddstr(buf, expr->u.literal);
243 } else {
244 sbaddstr(buf, "???");
245 }
246
247 return buf->buf;
248 }
249
250 char *ast_printtree(char *buf, size_t bufsize, searchASTExpr *expr, searchCmd *cmd) {
251 StringBuf b;
252 char *p;
253
254 b.capacity = bufsize;
255 b.len = 0;
256 b.buf = buf;
257
258 p = ast_printtree_real(&b, expr, cmd);
259
260 sbterminate(&b);
261 return p;
262 }