]> jfr.im git - irc/quakenet/newserv.git/blob - newsearch/newsearch_ast.c
Tidy up tree printing with stringbuf.
[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, int type, 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, type, 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, 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 ctx.reply = reply;
146 ctx.wall = wall;
147 ctx.parser = search_astparse;
148 ctx.arg = (void *)&cache;
149
150 buf[0] = '\0';
151 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree));
152 search = ctx.parser(&ctx, SEARCHTYPE_NICK, (char *)tree);
153 if(!search) {
154 reply(sender, "Parse error: %s", parseError);
155 return CMD_ERROR;
156 }
157
158 reply(sender, "Executing...");
159 nicksearch_exe(search, &ctx, sender, display, limit);
160
161 (search->free)(&ctx, search);
162
163 return CMD_OK;
164 }
165
166 int ast_chansearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, ChanDisplayFunc display, int limit) {
167 searchCtx ctx;
168 searchASTCache cache;
169 searchNode *search;
170 char buf[1024];
171
172 ctx.reply = reply;
173 ctx.wall = wall;
174 ctx.parser = search_astparse;
175 ctx.arg = (void *)&cache;
176
177 buf[0] = '\0';
178 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree));
179 search = ctx.parser(&ctx, SEARCHTYPE_CHANNEL, (char *)tree);
180 if(!search) {
181 reply(sender, "Parse error: %s", parseError);
182 return CMD_ERROR;
183 }
184
185 reply(sender, "Executing...");
186 chansearch_exe(search, &ctx, sender, display, limit);
187
188 (search->free)(&ctx, search);
189
190 return CMD_OK;
191 }
192
193 int ast_usersearch(searchASTExpr *tree, replyFunc reply, void *sender, wallFunc wall, UserDisplayFunc display, int limit) {
194 searchCtx ctx;
195 searchASTCache cache;
196 searchNode *search;
197 char buf[1024];
198
199 memset(&cache, 0, sizeof(cache));
200 cache.tree = tree;
201
202 ctx.reply = reply;
203 ctx.wall = wall;
204 ctx.parser = search_astparse;
205 ctx.arg = (void *)&cache;
206
207 buf[0] = '\0';
208 reply(sender, "Parsing: %s", ast_printtree(buf, sizeof(buf), tree));
209 search = ctx.parser(&ctx, SEARCHTYPE_USER, (char *)tree);
210 if(!search) {
211 reply(sender, "Parse error: %s", parseError);
212 return CMD_ERROR;
213 }
214
215 reply(sender, "Executing...");
216 usersearch_exe(search, &ctx, sender, display, limit);
217
218 (search->free)(&ctx, search);
219
220 return CMD_OK;
221 }
222
223
224 /* horribly inefficient -- don't call me very often! */
225 static char *ast_printtree_real(StringBuf *buf, searchASTExpr *expr) {
226 char lbuf[256];
227 if(expr->type == AST_NODE_CHILD) {
228 int i;
229 sstring *command = getcommandname(searchTree, (void *)expr->u.child->fn);
230
231 if(command) {
232 snprintf(lbuf, sizeof(lbuf), "(%s", command->content);
233 } else {
234 snprintf(lbuf, sizeof(lbuf), "(%p", expr->u.child->fn);
235 }
236 sbaddstr(buf, lbuf);
237
238 for(i=0;i<expr->u.child->argc;i++) {
239 sbaddchar(buf, ' ');
240 ast_printtree_real(buf, expr->u.child->argv[i]);
241 }
242 sbaddchar(buf, ')');
243
244 } else if(expr->type == AST_NODE_LITERAL) {
245 sbaddstr(buf, expr->u.literal);
246 } else {
247 sbaddstr(buf, "???");
248 }
249
250 return buf->buf;
251 }
252
253 char *ast_printtree(char *buf, size_t bufsize, searchASTExpr *expr) {
254 StringBuf b;
255 char *p;
256
257 b.capacity = bufsize;
258 b.len = 0;
259 b.buf = buf;
260
261 p = ast_printtree_real(&b, expr);
262
263 sbterminate(&b);
264 return p;
265 }