5 #include "../irc/irc_config.h"
6 #include "../lib/irc_string.h"
7 #include "../parser/parser.h"
8 #include "../control/control.h"
9 #include "../lib/splitline.h"
10 #include "../lib/version.h"
11 #include "../lib/stringbuf.h"
12 #include "../lib/strlfunc.h"
13 #include "../lib/array.h"
14 #include "newsearch.h"
18 CommandTree
*searchCmdTree
;
19 searchList
*globalterms
= NULL
;
21 int do_nicksearch(void *source
, int cargc
, char **cargv
);
22 int do_chansearch(void *source
, int cargc
, char **cargv
);
23 int do_usersearch(void *source
, int cargc
, char **cargv
);
25 void printnick_channels(searchCtx
*, nick
*, nick
*);
26 void printchannel(searchCtx
*, nick
*, chanindex
*);
27 void printchannel_topic(searchCtx
*, nick
*, chanindex
*);
28 void printchannel_services(searchCtx
*, nick
*, chanindex
*);
30 UserDisplayFunc defaultuserfn
= printuser
;
31 NickDisplayFunc defaultnickfn
= printnick
;
32 ChanDisplayFunc defaultchanfn
= printchannel
;
34 searchCmd
*reg_nicksearch
, *reg_chansearch
, *reg_usersearch
;
36 searchCmd
*registersearchcommand(char *name
, int level
, CommandHandler cmd
, void *defaultdisplayfunc
) {
40 registercontrolhelpcmd(name
, NO_OPER
,4, cmd
, "Usage: <criteria\nSearches with the given criteria");
42 acmd
=(struct searchCmd
*)malloc(sizeof(struct searchCmd
));
46 acmd
->name
= getsstring( name
, NSMAX_COMMAND_LEN
);
47 acmd
->outputtree
= newcommandtree();
48 acmd
->searchtree
= newcommandtree();
50 addcommandtotree(searchCmdTree
, name
, 0, 0, (CommandHandler
)acmd
);
54 registersearchterm( acmd
, sl
->name
->content
, sl
->cmd
);
61 void deregistersearchcommand(searchCmd
*scmd
) {
62 deregistercontrolcmd(scmd
->name
->content
, (CommandHandler
)scmd
->handler
);
63 destroycommandtree(scmd
->outputtree
);
64 destroycommandtree(scmd
->searchtree
);
65 freesstring(scmd
->name
);
69 void regdisp( searchCmd
*cmd
, const char *name
, void *handler
) {
70 addcommandtotree(cmd
->outputtree
, name
, 0, 0, (CommandHandler
) handler
);
73 void unregdisp( searchCmd
*cmd
, const char *name
, void *handler
) {
74 deletecommandfromtree(cmd
->outputtree
, name
, (CommandHandler
) handler
);
77 void *findcommandinlist( searchList
*sl
, char *name
){
79 if(strcmp(sl
->name
->content
,name
) == 0 ) {
87 const char *parseError
;
88 /* used for *_free functions that need to warn users of certain things
89 i.e. hitting too many users in a (kill) or (gline) */
93 searchCmdTree
=newcommandtree();
95 reg_nicksearch
= (searchCmd
*)registersearchcommand("nicksearch",NO_OPER
,&do_nicksearch
, printnick
);
96 reg_chansearch
= (searchCmd
*)registersearchcommand("chansearch",NO_OPER
,&do_chansearch
, printchannel
);
97 reg_usersearch
= (searchCmd
*)registersearchcommand("usersearch",NO_OPER
,&do_usersearch
, printuser
);
99 /* Boolean operations */
100 registerglobalsearchterm("and",and_parse
);
101 registerglobalsearchterm("not",not_parse
);
102 registerglobalsearchterm("or",or_parse
);
104 registerglobalsearchterm("eq",eq_parse
);
106 registerglobalsearchterm("lt",lt_parse
);
107 registerglobalsearchterm("gt",gt_parse
);
109 /* String operations */
110 registerglobalsearchterm("match",match_parse
);
111 registerglobalsearchterm("regex",regex_parse
);
112 registerglobalsearchterm("length",length_parse
);
114 /* Nickname operations */
115 registersearchterm(reg_nicksearch
, "hostmask",hostmask_parse
); /* nick only */
116 registersearchterm(reg_nicksearch
, "realname",realname_parse
); /* nick only */
117 registersearchterm(reg_nicksearch
, "authname",authname_parse
); /* nick only */
118 registersearchterm(reg_nicksearch
, "authts",authts_parse
); /* nick only */
119 registersearchterm(reg_nicksearch
, "ident",ident_parse
); /* nick only */
120 registersearchterm(reg_nicksearch
, "host",host_parse
); /* nick only */
121 registersearchterm(reg_nicksearch
, "channel",channel_parse
); /* nick only */
122 registersearchterm(reg_nicksearch
, "timestamp",timestamp_parse
); /* nick only */
123 registersearchterm(reg_nicksearch
, "country",country_parse
); /* nick only */
124 registersearchterm(reg_nicksearch
, "ip",ip_parse
); /* nick only */
125 registersearchterm(reg_nicksearch
, "channels",channels_parse
); /* nick only */
126 registersearchterm(reg_nicksearch
, "server",server_parse
); /* nick only */
127 registersearchterm(reg_nicksearch
, "authid",authid_parse
); /* nick only */
129 /* Channel operations */
130 registersearchterm(reg_chansearch
, "exists",exists_parse
); /* channel only */
131 registersearchterm(reg_chansearch
, "services",services_parse
); /* channel only */
132 registersearchterm(reg_chansearch
, "size",size_parse
); /* channel only */
133 registersearchterm(reg_chansearch
, "name",name_parse
); /* channel only */
134 registersearchterm(reg_chansearch
, "topic",topic_parse
); /* channel only */
135 registersearchterm(reg_chansearch
, "oppct",oppct_parse
); /* channel only */
136 registersearchterm(reg_chansearch
, "uniquehostpct",hostpct_parse
); /* channel only */
137 registersearchterm(reg_chansearch
, "authedpct",authedpct_parse
); /* channel only */
138 registersearchterm(reg_chansearch
, "kick",kick_parse
); /* channel only */
140 /* Nickname / channel operations */
141 registersearchterm(reg_chansearch
, "modes",modes_parse
);
142 registersearchterm(reg_nicksearch
, "modes",modes_parse
);
143 registersearchterm(reg_chansearch
, "nick",nick_parse
);
144 registersearchterm(reg_nicksearch
, "nick",nick_parse
);
146 /* Kill / gline parameters */
147 registersearchterm(reg_chansearch
,"kill",kill_parse
);
148 registersearchterm(reg_chansearch
,"gline",gline_parse
);
149 registersearchterm(reg_nicksearch
,"kill",kill_parse
);
150 registersearchterm(reg_nicksearch
,"gline",gline_parse
);
152 /* Iteration functionality */
153 registerglobalsearchterm("any",any_parse
);
154 registerglobalsearchterm("all",all_parse
);
155 registerglobalsearchterm("var",var_parse
);
157 /* Iterable functions */
158 registersearchterm(reg_nicksearch
, "channeliter",channeliter_parse
); /* nick only */
160 /* Notice functionality */
161 registersearchterm(reg_chansearch
,"notice",notice_parse
);
162 registersearchterm(reg_nicksearch
,"notice",notice_parse
);
164 /* Nick output filters */
165 regdisp(reg_nicksearch
,"default",printnick
);
166 regdisp(reg_nicksearch
,"channels",printnick_channels
);
168 /* Channel output filters */
169 regdisp(reg_chansearch
,"default",printchannel
);
170 regdisp(reg_chansearch
,"topic",printchannel_topic
);
171 regdisp(reg_chansearch
,"services",printchannel_services
);
173 /* Nick output filters */
174 regdisp(reg_usersearch
,"default",printuser
);
179 searchList
*sl
, *psl
;
181 Command
*cmdlist
[100];
188 n
=getcommandlist(searchCmdTree
,cmdlist
,100);
190 deregistersearchterm( (searchCmd
*)cmdlist
[i
]->handler
, psl
->name
->content
, psl
->cmd
);
193 freesstring(psl
->name
);
198 deregistersearchcommand( reg_nicksearch
);
199 deregistersearchcommand( reg_chansearch
);
200 deregistersearchcommand( reg_usersearch
);
201 destroycommandtree( searchCmdTree
);
204 void registerglobalsearchterm(char *term
, parseFunc parsefunc
) {
205 searchList
*sl
= malloc(sizeof(searchList
));
207 Command
*cmdlist
[100];
210 sl
->name
= getsstring(term
, NSMAX_COMMAND_LEN
);
213 if ( globalterms
!= NULL
) {
214 sl
->next
= globalterms
;
218 n
=getcommandlist(searchCmdTree
,cmdlist
,100);
220 registersearchterm( (searchCmd
*)cmdlist
[i
]->handler
,term
, parsefunc
);
224 void deregisterglobalsearchterm(char *term
, parseFunc parsefunc
) {
226 Command
*cmdlist
[100];
227 searchList
*sl
, *psl
=NULL
;
231 if ( strcmp( sl
->name
->content
, term
) == 0 ) {
240 psl
->next
= sl
->next
;
243 n
=getcommandlist(searchCmdTree
,cmdlist
,100);
245 deregistersearchterm( (searchCmd
*)cmdlist
[i
]->handler
, term
, parsefunc
);
247 freesstring(sl
->name
);
252 void registersearchterm(searchCmd
*cmd
, char *term
, parseFunc parsefunc
) {
253 addcommandtotree(cmd
->searchtree
, term
, 0, 0, (CommandHandler
) parsefunc
);
256 void deregistersearchterm(searchCmd
*cmd
, char *term
, parseFunc parsefunc
) {
257 deletecommandfromtree(cmd
->searchtree
, term
, (CommandHandler
) parsefunc
);
260 static void controlwallwrapper(int level
, char *format
, ...) {
264 va_start(ap
, format
);
265 vsnprintf(buf
, sizeof(buf
), format
, ap
);
266 controlwall(NO_OPER
, level
, "%s", buf
);
270 int parseopts(int cargc
, char **cargv
, int *arg
, int *limit
, void **subset
, void **display
, CommandTree
*sl
, replyFunc reply
, void *sender
) {
273 struct irc_in_addr sin
; unsigned char bits
;
275 if (*cargv
[0] == '-') {
279 for (ch
=cargv
[0]+1;*ch
;ch
++) {
283 reply(sender
,"Error: -l switch requires an argument");
286 *limit
=strtoul(cargv
[(*arg
)++],NULL
,10);
291 reply(sender
,"Error: -d switch requires an argument");
294 cmd
=findcommandintree(sl
, cargv
[*arg
],1);
296 reply(sender
,"Error: unknown output format %s",cargv
[*arg
]);
299 *display
=(void *)cmd
->handler
;
305 reply(sender
,"Error: -s switch requires an argument");
308 if (ipmask_parse(cargv
[*arg
], &sin
, &bits
) == 0) {
309 reply(sender
, "Error: Invalid CIDR mask supplied");
312 *subset
= (void *)refnode(iptree
, &sin
, bits
);
317 reply(sender
,"Unrecognised flag -%c.",*ch
);
325 void newsearch_ctxinit(searchCtx
*ctx
, searchParseFunc searchfn
, replyFunc replyfn
, wallFunc wallfn
, void *arg
, searchCmd
*cmd
) {
326 memset(ctx
, 0, sizeof(searchCtx
));
328 ctx
->reply
= replyfn
;
330 ctx
->parser
= searchfn
;
332 ctx
->searchcmd
= cmd
;
335 int do_nicksearch_real(replyFunc reply
, wallFunc wall
, void *source
, int cargc
, char **cargv
) {
336 nick
*sender
= source
;
337 struct searchNode
*search
;
340 NickDisplayFunc display
=defaultnickfn
;
347 ret
= parseopts(cargc
, cargv
, &arg
, &limit
, NULL
, (void **)&display
, reg_nicksearch
->outputtree
, reply
, sender
);
352 reply(sender
,"No search terms - aborting.");
357 rejoinline(cargv
[arg
],cargc
-arg
);
360 newsearch_ctxinit(&ctx
, search_parse
, reply
, wall
, NULL
, reg_nicksearch
);
362 if (!(search
= ctx
.parser(&ctx
, cargv
[arg
]))) {
363 reply(sender
,"Parse error: %s",parseError
);
367 nicksearch_exe(search
, &ctx
, sender
, display
, limit
);
369 (search
->free
)(&ctx
, search
);
374 int do_nicksearch(void *source
, int cargc
, char **cargv
) {
375 return do_nicksearch_real(controlreply
, controlwallwrapper
, source
, cargc
, cargv
);
378 void nicksearch_exe(struct searchNode
*search
, searchCtx
*ctx
, nick
*sender
, NickDisplayFunc display
, int limit
) {
381 unsigned int cmarker
;
382 unsigned int tchans
=0,uchans
=0;
385 senderNSExtern
= sender
;
387 /* Get a marker value to mark "seen" channels for unique count */
388 cmarker
=nextchanmarker();
390 /* The top-level node needs to return a BOOL */
391 search
=coerceNode(ctx
, search
, RETURNTYPE_BOOL
);
393 for (i
=0;i
<NICKHASHSIZE
;i
++) {
394 for (np
=nicktable
[i
];np
;np
=np
->next
) {
395 if ((search
->exe
)(ctx
, search
, np
)) {
396 /* Add total channels */
397 tchans
+= np
->channels
->cursi
;
399 /* Check channels for uniqueness */
400 cs
=(channel
**)np
->channels
->content
;
401 for (j
=0;j
<np
->channels
->cursi
;j
++) {
402 if (cs
[j
]->index
->marker
!= cmarker
) {
403 cs
[j
]->index
->marker
=cmarker
;
409 display(ctx
, sender
, np
);
412 ctx
->reply(sender
, "--- More than %d matches, skipping the rest",limit
);
418 ctx
->reply(sender
,"--- End of list: %d matches; users were on %u channels (%u unique, %.1f average clones)",
419 matches
, tchans
, uchans
, (float)tchans
/uchans
);
422 int do_chansearch_real(replyFunc reply
, wallFunc wall
, void *source
, int cargc
, char **cargv
) {
423 nick
*sender
= source
;
424 struct searchNode
*search
;
427 ChanDisplayFunc display
=defaultchanfn
;
434 ret
= parseopts(cargc
, cargv
, &arg
, &limit
, NULL
, (void **)&display
, reg_chansearch
->outputtree
, reply
, sender
);
439 reply(sender
,"No search terms - aborting.");
444 rejoinline(cargv
[arg
],cargc
-arg
);
447 newsearch_ctxinit(&ctx
, search_parse
, reply
, wall
, NULL
, reg_chansearch
);
448 if (!(search
= ctx
.parser(&ctx
, cargv
[arg
]))) {
449 reply(sender
,"Parse error: %s",parseError
);
453 chansearch_exe(search
, &ctx
, sender
, display
, limit
);
455 (search
->free
)(&ctx
, search
);
460 int do_chansearch(void *source
, int cargc
, char **cargv
) {
461 return do_chansearch_real(controlreply
, controlwallwrapper
, source
, cargc
, cargv
);
464 void chansearch_exe(struct searchNode
*search
, searchCtx
*ctx
, nick
*sender
, ChanDisplayFunc display
, int limit
) {
468 senderNSExtern
= sender
;
470 search
=coerceNode(ctx
, search
, RETURNTYPE_BOOL
);
472 for (i
=0;i
<CHANNELHASHSIZE
;i
++) {
473 for (cip
=chantable
[i
];cip
;cip
=cip
->next
) {
474 if ((search
->exe
)(ctx
, search
, cip
)) {
476 display(ctx
, sender
, cip
);
478 ctx
->reply(sender
, "--- More than %d matches, skipping the rest",limit
);
484 ctx
->reply(sender
,"--- End of list: %d matches", matches
);
487 int do_usersearch_real(replyFunc reply
, wallFunc wall
, void *source
, int cargc
, char **cargv
) {
488 nick
*sender
= source
;
489 struct searchNode
*search
;
492 UserDisplayFunc display
=defaultuserfn
;
499 ret
= parseopts(cargc
, cargv
, &arg
, &limit
, NULL
, (void **)&display
, reg_usersearch
->outputtree
, reply
, sender
);
504 reply(sender
,"No search terms - aborting.");
509 rejoinline(cargv
[arg
],cargc
-arg
);
512 newsearch_ctxinit(&ctx
, search_parse
, reply
, wall
, NULL
, reg_usersearch
);
513 if (!(search
= ctx
.parser(&ctx
, cargv
[arg
]))) {
514 reply(sender
,"Parse error: %s",parseError
);
518 usersearch_exe(search
, &ctx
, sender
, display
, limit
);
520 (search
->free
)(&ctx
, search
);
525 int do_usersearch(void *source
, int cargc
, char **cargv
) {
526 return do_usersearch_real(controlreply
, controlwallwrapper
, source
, cargc
, cargv
);
529 void usersearch_exe(struct searchNode
*search
, searchCtx
*ctx
, nick
*sender
, UserDisplayFunc display
, int limit
) {
533 senderNSExtern
= sender
;
535 search
=coerceNode(ctx
, search
, RETURNTYPE_BOOL
);
537 for (i
=0;i
<AUTHNAMEHASHSIZE
;i
++) {
538 for (aup
=authnametable
[i
];aup
;aup
=aup
->next
) {
539 if ((search
->exe
)(ctx
, search
, aup
)) {
541 display(ctx
, sender
, aup
);
543 ctx
->reply(sender
, "--- More than %d matches, skipping the rest",limit
);
549 ctx
->reply(sender
,"--- End of list: %d matches", matches
);
552 /* Free a coerce node */
553 void free_coerce(searchCtx
*ctx
, struct searchNode
*thenode
) {
554 struct coercedata
*cd
=thenode
->localdata
;
556 cd
->child
->free(ctx
, cd
->child
);
557 free(thenode
->localdata
);
561 /* Free a coerce node with a stringbuf allocated */
562 void free_coercestring(searchCtx
*ctx
, struct searchNode
*thenode
) {
563 free(((struct coercedata
*)thenode
->localdata
)->u
.stringbuf
);
564 free_coerce(ctx
, thenode
);
567 /* exe_tostr_null: return the constant string */
568 void *exe_tostr_null(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
569 struct coercedata
*cd
=thenode
->localdata
;
571 return cd
->u
.stringbuf
;
574 /* exe_val_null: return the constant value */
575 void *exe_val_null(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
576 struct coercedata
*cd
=thenode
->localdata
;
578 return (void *)cd
->u
.val
;
581 /* Lots of very dull type conversion functions */
582 void *exe_inttostr(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
583 struct coercedata
*cd
=thenode
->localdata
;
585 sprintf(cd
->u
.stringbuf
, "%lu", (unsigned long)(cd
->child
->exe
)(ctx
, cd
->child
, theinput
));
587 return cd
->u
.stringbuf
;
590 void *exe_booltostr(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
591 struct coercedata
*cd
=thenode
->localdata
;
593 if ((cd
->child
->exe
)(ctx
, cd
->child
, theinput
)) {
594 sprintf(cd
->u
.stringbuf
,"1");
596 cd
->u
.stringbuf
[0]='\0';
599 return cd
->u
.stringbuf
;
602 void *exe_strtoint(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
603 struct coercedata
*cd
=thenode
->localdata
;
605 return (void *)strtoul((cd
->child
->exe
)(ctx
,cd
->child
,theinput
),NULL
,10);
608 void *exe_booltoint(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
609 struct coercedata
*cd
=thenode
->localdata
;
611 /* Don't need to do anything */
612 return (cd
->child
->exe
)(ctx
, cd
->child
, theinput
);
615 void *exe_strtobool(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
616 struct coercedata
*cd
=thenode
->localdata
;
617 char *ch
=(cd
->child
->exe
)(ctx
, cd
->child
, theinput
);
619 if (!ch
|| *ch
=='\0' || (*ch
=='0' && ch
[1]=='\0')) {
626 void *exe_inttobool(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
627 struct coercedata
*cd
=thenode
->localdata
;
629 if ((cd
->child
->exe
)(ctx
, cd
->child
, theinput
)) {
636 struct searchNode
*coerceNode(searchCtx
*ctx
, struct searchNode
*thenode
, int type
) {
637 struct searchNode
*anode
;
638 struct coercedata
*cd
;
640 /* You can't coerce a NULL */
644 /* No effort required to coerce to the same type */
645 if (type
==(thenode
->returntype
& RETURNTYPE_TYPE
))
648 anode
=(struct searchNode
*)malloc(sizeof(struct searchNode
));
649 anode
->localdata
=cd
=(struct coercedata
*)malloc(sizeof(struct coercedata
));
651 anode
->returntype
=type
; /* We'll return what they want, always */
652 anode
->free
=free_coerce
;
655 case RETURNTYPE_STRING
:
656 /* For a string we'll need a buffer */
657 /* A 64-bit number prints out to 20 digits, this leaves some slack */
658 cd
->u
.stringbuf
=malloc(25);
659 anode
->free
=free_coercestring
;
661 switch(thenode
->returntype
& RETURNTYPE_TYPE
) {
664 if (thenode
->returntype
& RETURNTYPE_CONST
) {
665 /* Constant node: sort it out now */
666 sprintf(cd
->u
.stringbuf
, "%lu", (unsigned long)thenode
->exe(ctx
, thenode
, NULL
));
667 anode
->exe
=exe_tostr_null
;
668 anode
->returntype
|= RETURNTYPE_CONST
;
671 anode
->exe
=exe_inttostr
;
675 case RETURNTYPE_BOOL
:
676 if (thenode
->returntype
& RETURNTYPE_CONST
) {
677 /* Constant bool value */
678 if (thenode
->exe(ctx
, thenode
,NULL
)) {
680 sprintf(cd
->u
.stringbuf
, "1");
682 cd
->u
.stringbuf
[0] = '\0';
684 anode
->exe
=exe_tostr_null
;
685 anode
->returntype
|= RETURNTYPE_CONST
;
687 /* Variable bool value */
688 anode
->exe
=exe_booltostr
;
696 switch (thenode
->returntype
& RETURNTYPE_TYPE
) {
697 case RETURNTYPE_STRING
:
698 if (thenode
->returntype
& RETURNTYPE_CONST
) {
699 cd
->u
.val
=strtoul((thenode
->exe
)(ctx
, thenode
, NULL
), NULL
, 10);
700 anode
->exe
=exe_val_null
;
701 anode
->returntype
|= RETURNTYPE_CONST
;
703 anode
->exe
=exe_strtoint
;
708 case RETURNTYPE_BOOL
:
709 if (thenode
->returntype
& RETURNTYPE_CONST
) {
710 if ((thenode
->exe
)(ctx
, thenode
,NULL
))
715 anode
->exe
=exe_val_null
;
716 anode
->returntype
|= RETURNTYPE_CONST
;
718 anode
->exe
=exe_booltoint
;
725 case RETURNTYPE_BOOL
:
727 switch (thenode
->returntype
& RETURNTYPE_TYPE
) {
728 case RETURNTYPE_STRING
:
729 if (thenode
->returntype
& RETURNTYPE_CONST
) {
730 char *rv
=(char *)((thenode
->exe
)(ctx
, thenode
, NULL
));
731 if (!rv
|| *rv
=='\0' || (*rv
=='0' && rv
[1]=='\0'))
736 anode
->exe
=exe_val_null
;
737 anode
->returntype
|= RETURNTYPE_CONST
;
739 anode
->exe
=exe_strtobool
;
745 if (thenode
->returntype
& RETURNTYPE_CONST
) {
746 if ((thenode
->exe
)(ctx
, thenode
,NULL
))
751 anode
->exe
=exe_val_null
;
752 anode
->returntype
|= RETURNTYPE_CONST
;
754 anode
->exe
=exe_inttobool
;
764 /* Literals always return constant strings... */
765 void *literal_exe(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
766 if (thenode
->localdata
)
767 return ((sstring
*)thenode
->localdata
)->content
;
772 void literal_free(searchCtx
*ctx
, struct searchNode
*thenode
) {
773 freesstring(thenode
->localdata
);
778 * Given an input string, return a searchNode.
781 struct searchNode
*search_parse(searchCtx
*ctx
, char *input
) {
782 /* OK, we need to split the input into chunks on spaces and brackets.. */
783 char *argvector
[100];
788 struct searchNode
*thenode
;
790 /* If it starts with a bracket, it's a function call.. */
792 /* Skip past string */
793 for (ch
=input
;*ch
;ch
++);
794 if (*(ch
-1) != ')') {
795 parseError
= "Bracket mismatch!";
801 /* Split further args */
802 i
=-1; /* i = -1 BoW, 0 = inword, 1 = bracket nest depth */
803 j
=0; /* j = current arg */
807 for (ch
=input
;*ch
;ch
++) {
812 } else if (*ch
!= ' ') {
816 } else if (*ch
=='\"') {
828 } else if (*ch
=='\"') {
830 } else if (*ch
==' ') {
833 if(j
>= (sizeof(argvector
) / sizeof(*argvector
))) {
834 parseError
= "Too many arguments";
842 } else if (*ch
=='\"') {
844 } else if (*ch
=='(') {
846 } else if (*ch
==')') {
853 parseError
= "Bracket mismatch!";
857 if (*(ch
-1) == 0) /* if the last character was a space */
858 j
--; /* remove an argument */
860 if (!(cmd
=findcommandintree(ctx
->searchcmd
->searchtree
,argvector
[0],1))) {
861 parseError
= "Unknown command";
864 return ((parseFunc
)cmd
->handler
)(ctx
, j
, argvector
+1);
869 for (ch
=input
;*ch
;ch
++);
871 if (*(ch
-1) != '\"') {
872 parseError
="Quote mismatch";
881 for (ch
=input
;*ch
;ch
++) {
885 } else if (*ch
=='\\') {
893 if (!(thenode
=(struct searchNode
*)malloc(sizeof(struct searchNode
)))) {
894 parseError
= "malloc: could not allocate memory for this search.";
898 thenode
->localdata
= getsstring(thestring
,512);
899 thenode
->returntype
= RETURNTYPE_CONST
| RETURNTYPE_STRING
;
900 thenode
->exe
= literal_exe
;
901 thenode
->free
= literal_free
;
907 void nssnprintf(char *buf
, size_t size
, const char *format
, nick
*np
) {
920 for(p
=format
;*p
;p
++) {
922 if(!sbaddchar(&b
, *p
))
930 if(!sbaddchar(&b
, *p
))
940 c
= np
->ident
; break;
942 c
= np
->host
->name
->content
; break;
944 snprintf(hostbuf
, sizeof(hostbuf
), "%s", IPtostr(np
->p_ipaddr
));
948 snprintf(hostbuf
, sizeof(hostbuf
), "%s!%s@%s", np
->nick
, np
->ident
, IPtostr(np
->p_ipaddr
));
952 c
= "(bad format specifier)";
967 static char *var_tochar(searchCtx
*ctx
, char *arg
, searchNode
**variable
) {
968 *variable
= ctx
->parser(ctx
, arg
);
969 if (!(*variable
= coerceNode(ctx
, *variable
, RETURNTYPE_STRING
)))
972 if(!((*variable
)->returntype
& RETURNTYPE_CONST
)) {
973 parseError
= "only constant variables allowed";
974 ((*variable
)->free
)(ctx
, *variable
);
978 return (char *)((*variable
)->exe
)(ctx
, *variable
, NULL
);
981 void free_val_null(searchCtx
*ctx
, struct searchNode
*thenode
) {
984 struct searchVariable
*var_register(searchCtx
*ctx
, char *arg
, int type
) {
985 searchNode
*variable
;
986 struct searchVariable
*us
;
990 if(ctx
->lastvar
>= MAX_VARIABLES
) {
991 parseError
= "Maximum number of variables reached";
995 us
= &ctx
->vars
[ctx
->lastvar
];
997 var
= var_tochar(ctx
, arg
, &variable
);
1001 strlcpy(us
->name
, var
, sizeof(us
->name
));
1002 (variable
->free
)(ctx
, variable
);
1004 for(i
=0;i
<ctx
->lastvar
;i
++) {
1005 if(!strcmp(us
->name
, ctx
->vars
[i
].name
)) {
1006 parseError
= "variable name already in use";
1012 us
->data
.returntype
= type
;
1013 us
->data
.localdata
= &us
->cdata
;
1014 us
->data
.exe
= exe_val_null
;
1015 us
->data
.free
= free_val_null
;
1017 us
->cdata
.child
= NULL
;
1021 searchNode
*var_get(searchCtx
*ctx
, char *arg
) {
1022 searchNode
*variable
, *found
= NULL
;
1024 char *var
= var_tochar(ctx
, arg
, &variable
);
1028 for(i
=0;i
<ctx
->lastvar
;i
++) {
1029 if(!strcmp(var
, ctx
->vars
[i
].name
)) {
1030 found
= &ctx
->vars
[i
].data
;
1034 (variable
->free
)(ctx
, variable
);
1037 parseError
= "variable not found";
1041 void var_setstr(struct searchVariable
*v
, char *data
) {
1042 v
->cdata
.u
.stringbuf
= data
;