]>
jfr.im git - irc/quakenet/newserv.git/blob - newsearch/newsearch_ast.c
2 #include "../lib/sstring.h"
3 #include "../lib/strlfunc.h"
4 #include "../lib/stringbuf.h"
8 /* at least we have some type safety... */
9 typedef union exprunion
{
14 typedef struct searchASTCache
{
16 searchASTExpr
*cache
[AST_RECENT
];
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
)
25 } else if(expr
->type
== AST_NODE_CHILD
) {
29 parseError
= "static_parse_compare: bad node type";
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
);
41 if(expr
->type
== AST_NODE_CHILD
) {
43 for(i
=0;i
<expr
->u
.child
->argc
;i
++) {
44 searchASTExpr
*d
= treesearch(expr
->u
.child
->argv
[i
], loc
);
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...
56 searchASTExpr
*cachesearch(searchASTCache
*cache
, exprunion
*loc
) {
57 searchASTExpr
*ret
= compareloc(cache
->tree
, loc
);
62 for(i
=0;i
<AST_RECENT
;i
++) {
65 ret
= compareloc(cache
->cache
[i
], loc
);
70 return treesearch(cache
->tree
, loc
);
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
;
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
);
88 parseError
= "WARNING: AST parsing failed";
93 case AST_NODE_LITERAL
:
94 if (!(node
=(searchNode
*)malloc(sizeof(searchNode
)))) {
95 parseError
= "malloc: could not allocate memory for this search.";
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
;
104 v
= (char **)malloc(expr
->u
.child
->argc
* sizeof(char *));
106 parseError
= "malloc: could not allocate memory for this search.";
109 for(i
=0;i
<expr
->u
.child
->argc
;i
++) {
110 searchASTExpr
*child
= expr
->u
.child
->argv
[i
];
112 cachepush(cache
, child
);
113 switch(child
->type
) {
114 case AST_NODE_LITERAL
:
115 v
[i
] = child
->u
.literal
;
118 v
[i
] = (char *)child
;
121 parseError
= "static_parse: bad child node type";
127 node
= expr
->u
.child
->fn(ctx
, type
, expr
->u
.child
->argc
, v
);
131 parseError
= "static_parse: bad node type";
136 int ast_nicksearch(searchASTExpr
*tree
, replyFunc reply
, void *sender
, wallFunc wall
, NickDisplayFunc display
, HeaderFunc header
, void *headerarg
, int limit
) {
138 searchASTCache cache
;
142 memset(&cache
, 0, sizeof(cache
));
147 ctx
.parser
= search_astparse
;
148 ctx
.arg
= (void *)&cache
;
151 reply(sender
, "Parsing: %s", ast_printtree(buf
, sizeof(buf
), tree
));
152 search
= ctx
.parser(&ctx
, SEARCHTYPE_NICK
, (char *)tree
);
154 reply(sender
, "Parse error: %s", parseError
);
158 reply(sender
, "Executing...");
160 header(sender
, headerarg
);
161 nicksearch_exe(search
, &ctx
, sender
, display
, limit
);
163 (search
->free
)(&ctx
, search
);
168 int ast_chansearch(searchASTExpr
*tree
, replyFunc reply
, void *sender
, wallFunc wall
, ChanDisplayFunc display
, HeaderFunc header
, void *headerarg
, int limit
) {
170 searchASTCache cache
;
176 ctx
.parser
= search_astparse
;
177 ctx
.arg
= (void *)&cache
;
180 reply(sender
, "Parsing: %s", ast_printtree(buf
, sizeof(buf
), tree
));
181 search
= ctx
.parser(&ctx
, SEARCHTYPE_CHANNEL
, (char *)tree
);
183 reply(sender
, "Parse error: %s", parseError
);
187 reply(sender
, "Executing...");
189 header(sender
, headerarg
);
190 chansearch_exe(search
, &ctx
, sender
, display
, limit
);
192 (search
->free
)(&ctx
, search
);
197 int ast_usersearch(searchASTExpr
*tree
, replyFunc reply
, void *sender
, wallFunc wall
, UserDisplayFunc display
, HeaderFunc header
, void *headerarg
, int limit
) {
199 searchASTCache cache
;
203 memset(&cache
, 0, sizeof(cache
));
208 ctx
.parser
= search_astparse
;
209 ctx
.arg
= (void *)&cache
;
212 reply(sender
, "Parsing: %s", ast_printtree(buf
, sizeof(buf
), tree
));
213 search
= ctx
.parser(&ctx
, SEARCHTYPE_USER
, (char *)tree
);
215 reply(sender
, "Parse error: %s", parseError
);
219 reply(sender
, "Executing...");
221 header(sender
, headerarg
);
222 usersearch_exe(search
, &ctx
, sender
, display
, limit
);
224 (search
->free
)(&ctx
, search
);
230 /* horribly inefficient -- don't call me very often! */
231 static char *ast_printtree_real(StringBuf
*buf
, searchASTExpr
*expr
) {
233 if(expr
->type
== AST_NODE_CHILD
) {
235 sstring
*command
= getcommandname(searchTree
, (void *)expr
->u
.child
->fn
);
238 snprintf(lbuf
, sizeof(lbuf
), "(%s", command
->content
);
240 snprintf(lbuf
, sizeof(lbuf
), "(%p", expr
->u
.child
->fn
);
244 for(i
=0;i
<expr
->u
.child
->argc
;i
++) {
246 ast_printtree_real(buf
, expr
->u
.child
->argv
[i
]);
250 } else if(expr
->type
== AST_NODE_LITERAL
) {
251 sbaddstr(buf
, expr
->u
.literal
);
253 sbaddstr(buf
, "???");
259 char *ast_printtree(char *buf
, size_t bufsize
, searchASTExpr
*expr
) {
263 b
.capacity
= bufsize
;
267 p
= ast_printtree_real(&b
, expr
);