]>
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 /* comares either a string and a string or an expression and an expression */
15 static searchASTExpr
*compareloc(searchASTExpr
*expr
, exprunion
*loc
) {
16 if(expr
->type
== AST_NODE_LITERAL
) {
17 if(expr
->u
.literal
== loc
->literal
)
19 } else if(expr
->type
== AST_NODE_CHILD
) {
23 parseError
= "static_parse_compare: bad node type";
29 /* searches the abstract syntax tree for the supplied expression/string */
30 static searchASTExpr
*treesearch(searchASTExpr
*expr
, exprunion
*loc
) {
31 searchASTExpr
*ret
= compareloc(expr
, loc
);
35 if(expr
->type
== AST_NODE_CHILD
) {
37 for(i
=0;i
<expr
->u
.child
.argc
;i
++) {
38 searchASTExpr
*d
= treesearch(&expr
->u
.child
.argv
[i
], loc
);
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...
50 searchASTExpr
*cachesearch(searchASTCache
*cache
, exprunion
*loc
) {
51 searchASTExpr
*ret
= compareloc(cache
->tree
, loc
);
56 for(i
=0;i
<AST_RECENT
;i
++) {
59 ret
= compareloc(cache
->cache
[i
], loc
);
64 return treesearch(cache
->tree
, loc
);
67 /* pushes an item into the cache */
68 static void cachepush(searchASTCache
*cache
, searchASTExpr
*expr
) {
69 cache
->cache
[cache
->nextpos
] = expr
;
70 cache
->nextpos
= (cache
->nextpos
+ 1) % AST_RECENT
;
73 /* ast parser, the way we pass context around is very very hacky... */
74 searchNode
*search_astparse(searchCtx
*ctx
, char *loc
) {
75 searchASTCache
*cache
= ctx
->arg
;
76 searchASTExpr
*expr
= cachesearch(cache
, (exprunion
*)&loc
);
82 parseError
= "WARNING: AST parsing failed";
87 case AST_NODE_LITERAL
:
88 if (!(node
=(searchNode
*)malloc(sizeof(searchNode
)))) {
89 parseError
= "malloc: could not allocate memory for this search.";
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
;
98 v
= (char **)malloc(expr
->u
.child
.argc
* sizeof(char *));
100 parseError
= "malloc: could not allocate memory for this search.";
103 for(i
=0;i
<expr
->u
.child
.argc
;i
++) {
104 searchASTExpr
*child
= &expr
->u
.child
.argv
[i
];
106 cachepush(cache
, child
);
107 switch(child
->type
) {
108 case AST_NODE_LITERAL
:
109 v
[i
] = child
->u
.literal
;
112 v
[i
] = (char *)child
;
115 parseError
= "static_parse: bad child node type";
121 node
= expr
->u
.child
.fn(ctx
, expr
->u
.child
.argc
, v
);
125 parseError
= "static_parse: bad node type";
130 int ast_nicksearch(searchASTExpr
*tree
, replyFunc reply
, void *sender
, wallFunc wall
, NickDisplayFunc display
, HeaderFunc header
, void *headerarg
, int limit
) {
132 searchASTCache cache
;
136 memset(&cache
, 0, sizeof(cache
));
139 newsearch_ctxinit(&ctx
, search_astparse
, reply
, wall
, &cache
, reg_nicksearch
, sender
, display
, limit
);
142 reply(sender
, "Parsing: %s", ast_printtree(buf
, sizeof(buf
), tree
, reg_nicksearch
));
143 search
= ctx
.parser(&ctx
, (char *)tree
);
145 reply(sender
, "Parse error: %s", parseError
);
149 reply(sender
, "Executing...");
151 header(sender
, headerarg
);
152 nicksearch_exe(search
, &ctx
);
154 (search
->free
)(&ctx
, search
);
159 int ast_chansearch(searchASTExpr
*tree
, replyFunc reply
, void *sender
, wallFunc wall
, ChanDisplayFunc display
, HeaderFunc header
, void *headerarg
, int limit
) {
161 searchASTCache cache
;
165 newsearch_ctxinit(&ctx
, search_astparse
, reply
, wall
, &cache
, reg_chansearch
, sender
, display
, limit
);
167 memset(&cache
, 0, sizeof(cache
));
171 reply(sender
, "Parsing: %s", ast_printtree(buf
, sizeof(buf
), tree
, reg_chansearch
));
172 search
= ctx
.parser(&ctx
, (char *)tree
);
174 reply(sender
, "Parse error: %s", parseError
);
178 reply(sender
, "Executing...");
180 header(sender
, headerarg
);
181 chansearch_exe(search
, &ctx
);
183 (search
->free
)(&ctx
, search
);
188 int ast_usersearch(searchASTExpr
*tree
, replyFunc reply
, void *sender
, wallFunc wall
, UserDisplayFunc display
, HeaderFunc header
, void *headerarg
, int limit
) {
190 searchASTCache cache
;
194 memset(&cache
, 0, sizeof(cache
));
197 newsearch_ctxinit(&ctx
, search_astparse
, reply
, wall
, &cache
, reg_usersearch
, sender
, display
, limit
);
200 reply(sender
, "Parsing: %s", ast_printtree(buf
, sizeof(buf
), tree
, reg_usersearch
));
201 search
= ctx
.parser(&ctx
, (char *)tree
);
203 reply(sender
, "Parse error: %s", parseError
);
207 reply(sender
, "Executing...");
209 header(sender
, headerarg
);
210 usersearch_exe(search
, &ctx
);
212 (search
->free
)(&ctx
, search
);
218 /* horribly inefficient -- don't call me very often! */
219 static char *ast_printtree_real(StringBuf
*buf
, searchASTExpr
*expr
, searchCmd
*cmd
) {
221 if(expr
->type
== AST_NODE_CHILD
) {
223 sstring
*command
= getcommandname(cmd
->searchtree
, (void *)expr
->u
.child
.fn
);
226 snprintf(lbuf
, sizeof(lbuf
), "(%s", command
->content
);
228 snprintf(lbuf
, sizeof(lbuf
), "(%p", expr
->u
.child
.fn
);
232 for(i
=0;i
<expr
->u
.child
.argc
;i
++) {
234 ast_printtree_real(buf
, &expr
->u
.child
.argv
[i
], cmd
);
238 } else if(expr
->type
== AST_NODE_LITERAL
) {
243 for(p
=expr
->u
.literal
;*p
;p
++) {
244 if(*p
== '\\' || *p
== '"')
245 sbaddchar(buf
, '\\');
251 sbaddstr(buf
, "???");
257 char *ast_printtree(char *buf
, size_t bufsize
, searchASTExpr
*expr
, searchCmd
*cmd
) {
261 b
.capacity
= bufsize
;
265 p
= ast_printtree_real(&b
, expr
, cmd
);