]>
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
);
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
, sender
, display
, limit
);
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
);
174 reply(sender
, "Parsing: %s", ast_printtree(buf
, sizeof(buf
), tree
, reg_chansearch
));
175 search
= ctx
.parser(&ctx
, (char *)tree
);
177 reply(sender
, "Parse error: %s", parseError
);
181 reply(sender
, "Executing...");
183 header(sender
, headerarg
);
184 chansearch_exe(search
, &ctx
, sender
, display
, limit
);
186 (search
->free
)(&ctx
, search
);
191 int ast_usersearch(searchASTExpr
*tree
, replyFunc reply
, void *sender
, wallFunc wall
, UserDisplayFunc display
, HeaderFunc header
, void *headerarg
, int limit
) {
193 searchASTCache cache
;
197 memset(&cache
, 0, sizeof(cache
));
200 newsearch_ctxinit(&ctx
, search_astparse
, reply
, wall
, &cache
, reg_usersearch
, sender
);
203 reply(sender
, "Parsing: %s", ast_printtree(buf
, sizeof(buf
), tree
, reg_usersearch
));
204 search
= ctx
.parser(&ctx
, (char *)tree
);
206 reply(sender
, "Parse error: %s", parseError
);
210 reply(sender
, "Executing...");
212 header(sender
, headerarg
);
213 usersearch_exe(search
, &ctx
, sender
, display
, limit
);
215 (search
->free
)(&ctx
, search
);
221 /* horribly inefficient -- don't call me very often! */
222 static char *ast_printtree_real(StringBuf
*buf
, searchASTExpr
*expr
, searchCmd
*cmd
) {
224 if(expr
->type
== AST_NODE_CHILD
) {
226 sstring
*command
= getcommandname(cmd
->searchtree
, (void *)expr
->u
.child
->fn
);
229 snprintf(lbuf
, sizeof(lbuf
), "(%s", command
->content
);
231 snprintf(lbuf
, sizeof(lbuf
), "(%p", expr
->u
.child
->fn
);
235 for(i
=0;i
<expr
->u
.child
->argc
;i
++) {
237 ast_printtree_real(buf
, expr
->u
.child
->argv
[i
], cmd
);
241 } else if(expr
->type
== AST_NODE_LITERAL
) {
242 sbaddstr(buf
, expr
->u
.literal
);
244 sbaddstr(buf
, "???");
250 char *ast_printtree(char *buf
, size_t bufsize
, searchASTExpr
*expr
, searchCmd
*cmd
) {
254 b
.capacity
= bufsize
;
258 p
= ast_printtree_real(&b
, expr
, cmd
);