]>
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
, 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
, 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
));
145 newsearch_ctxinit(&ctx
, search_astparse
, reply
, wall
, &cache
, reg_nicksearch
, sender
, display
, limit
);
148 reply(sender
, "Parsing: %s", ast_printtree(buf
, sizeof(buf
), tree
, reg_nicksearch
));
149 search
= ctx
.parser(&ctx
, (char *)tree
);
151 reply(sender
, "Parse error: %s", parseError
);
155 reply(sender
, "Executing...");
157 header(sender
, headerarg
);
158 nicksearch_exe(search
, &ctx
);
160 (search
->free
)(&ctx
, search
);
165 int ast_chansearch(searchASTExpr
*tree
, replyFunc reply
, void *sender
, wallFunc wall
, ChanDisplayFunc display
, HeaderFunc header
, void *headerarg
, int limit
) {
167 searchASTCache cache
;
171 newsearch_ctxinit(&ctx
, search_astparse
, reply
, wall
, &cache
, reg_chansearch
, sender
, display
, limit
);
173 memset(&cache
, 0, sizeof(cache
));
177 reply(sender
, "Parsing: %s", ast_printtree(buf
, sizeof(buf
), tree
, reg_chansearch
));
178 search
= ctx
.parser(&ctx
, (char *)tree
);
180 reply(sender
, "Parse error: %s", parseError
);
184 reply(sender
, "Executing...");
186 header(sender
, headerarg
);
187 chansearch_exe(search
, &ctx
);
189 (search
->free
)(&ctx
, search
);
194 int ast_usersearch(searchASTExpr
*tree
, replyFunc reply
, void *sender
, wallFunc wall
, UserDisplayFunc display
, HeaderFunc header
, void *headerarg
, int limit
) {
196 searchASTCache cache
;
200 memset(&cache
, 0, sizeof(cache
));
203 newsearch_ctxinit(&ctx
, search_astparse
, reply
, wall
, &cache
, reg_usersearch
, sender
, display
, limit
);
206 reply(sender
, "Parsing: %s", ast_printtree(buf
, sizeof(buf
), tree
, reg_usersearch
));
207 search
= ctx
.parser(&ctx
, (char *)tree
);
209 reply(sender
, "Parse error: %s", parseError
);
213 reply(sender
, "Executing...");
215 header(sender
, headerarg
);
216 usersearch_exe(search
, &ctx
);
218 (search
->free
)(&ctx
, search
);
224 /* horribly inefficient -- don't call me very often! */
225 static char *ast_printtree_real(StringBuf
*buf
, searchASTExpr
*expr
, searchCmd
*cmd
) {
227 if(expr
->type
== AST_NODE_CHILD
) {
229 sstring
*command
= getcommandname(cmd
->searchtree
, (void *)expr
->u
.child
.fn
);
232 snprintf(lbuf
, sizeof(lbuf
), "(%s", command
->content
);
234 snprintf(lbuf
, sizeof(lbuf
), "(%p", expr
->u
.child
.fn
);
238 for(i
=0;i
<expr
->u
.child
.argc
;i
++) {
240 ast_printtree_real(buf
, &expr
->u
.child
.argv
[i
], cmd
);
244 } else if(expr
->type
== AST_NODE_LITERAL
) {
249 for(p
=expr
->u
.literal
;*p
;p
++) {
250 if(*p
== '\\' || *p
== '"')
251 sbaddchar(buf
, '\\');
257 sbaddstr(buf
, "???");
263 char *ast_printtree(char *buf
, size_t bufsize
, searchASTExpr
*expr
, searchCmd
*cmd
) {
267 b
.capacity
= bufsize
;
271 p
= ast_printtree_real(&b
, expr
, cmd
);