6 #include "../irc/irc_config.h"
7 #include "../lib/irc_string.h"
8 #include "../parser/parser.h"
9 #include "../control/control.h"
10 #include "../lib/splitline.h"
11 #include "../lib/version.h"
12 #include "../lib/stringbuf.h"
13 #include "../lib/strlfunc.h"
17 CommandTree
*searchTree
;
18 CommandTree
*chanOutputTree
;
19 CommandTree
*nickOutputTree
;
20 CommandTree
*userOutputTree
;
22 int do_nicksearch(void *source
, int cargc
, char **cargv
);
23 int do_chansearch(void *source
, int cargc
, char **cargv
);
24 int do_usersearch(void *source
, int cargc
, char **cargv
);
26 void printnick_channels(searchCtx
*, nick
*, nick
*);
27 void printchannel(searchCtx
*, nick
*, chanindex
*);
28 void printchannel_topic(searchCtx
*, nick
*, chanindex
*);
29 void printchannel_services(searchCtx
*, nick
*, chanindex
*);
31 UserDisplayFunc defaultuserfn
= printuser
;
32 NickDisplayFunc defaultnickfn
= printnick
;
33 ChanDisplayFunc defaultchanfn
= printchannel
;
35 void registersearchterm(char *term
, parseFunc parsefunc
);
36 void deregistersearchterm(char *term
, parseFunc parsefunc
);
38 void regchandisp(const char *name
, ChanDisplayFunc handler
) {
39 addcommandtotree(chanOutputTree
, name
, 0, 0, (CommandHandler
)handler
);
42 void unregchandisp(const char *name
, ChanDisplayFunc handler
) {
43 deletecommandfromtree(chanOutputTree
, name
, (CommandHandler
)handler
);
46 void regnickdisp(const char *name
, NickDisplayFunc handler
) {
47 addcommandtotree(nickOutputTree
, name
, 0, 0, (CommandHandler
)handler
);
50 void unregnickdisp(const char *name
, NickDisplayFunc handler
) {
51 deletecommandfromtree(nickOutputTree
, name
, (CommandHandler
)handler
);
54 void reguserdisp(const char *name
, UserDisplayFunc handler
) {
55 addcommandtotree(userOutputTree
, name
, 0, 0, (CommandHandler
)handler
);
58 void unreguserdisp(const char *name
, UserDisplayFunc handler
) {
59 deletecommandfromtree(userOutputTree
, name
, (CommandHandler
)handler
);
62 const char *parseError
;
63 /* used for *_free functions that need to warn users of certain things
64 i.e. hitting too many users in a (kill) or (gline) */
68 searchTree
=newcommandtree();
69 chanOutputTree
=newcommandtree();
70 nickOutputTree
=newcommandtree();
71 userOutputTree
=newcommandtree();
73 /* Boolean operations */
74 registersearchterm("and",and_parse
);
75 registersearchterm("not",not_parse
);
76 registersearchterm("or",or_parse
);
78 registersearchterm("eq",eq_parse
);
80 registersearchterm("lt",lt_parse
);
81 registersearchterm("gt",gt_parse
);
83 /* String operations */
84 registersearchterm("match",match_parse
);
85 registersearchterm("regex",regex_parse
);
86 registersearchterm("length",length_parse
);
88 /* Nickname operations */
89 registersearchterm("hostmask",hostmask_parse
);
90 registersearchterm("realname",realname_parse
);
91 registersearchterm("authname",authname_parse
);
92 registersearchterm("authts",authts_parse
);
93 registersearchterm("ident",ident_parse
);
94 registersearchterm("host",host_parse
);
95 registersearchterm("channel",channel_parse
);
96 registersearchterm("timestamp",timestamp_parse
);
97 registersearchterm("country",country_parse
);
98 registersearchterm("ip",ip_parse
);
99 registersearchterm("channels",channels_parse
);
100 registersearchterm("server",server_parse
);
101 registersearchterm("authid",authid_parse
);
103 /* Channel operations */
104 registersearchterm("exists",exists_parse
);
105 registersearchterm("services",services_parse
);
106 registersearchterm("size",size_parse
);
107 registersearchterm("name",name_parse
);
108 registersearchterm("topic",topic_parse
);
109 registersearchterm("oppct",oppct_parse
);
110 registersearchterm("uniquehostpct",hostpct_parse
);
111 registersearchterm("authedpct",authedpct_parse
);
112 registersearchterm("kick",kick_parse
);
114 /* Nickname / channel operations */
115 registersearchterm("modes",modes_parse
);
116 registersearchterm("nick",nick_parse
);
118 /* Kill / gline parameters */
119 registersearchterm("kill",kill_parse
);
120 registersearchterm("gline",gline_parse
);
122 /* Iteration functionality */
123 registersearchterm("any",any_parse
);
124 registersearchterm("all",all_parse
);
125 registersearchterm("var",var_parse
);
127 /* Iterable functions */
128 registersearchterm("channeliter",channeliter_parse
);
130 /* Notice functionality */
131 registersearchterm("notice",notice_parse
);
133 /* Nick output filters */
134 regnickdisp("default",printnick
);
135 regnickdisp("channels",printnick_channels
);
137 /* Channel output filters */
138 regchandisp("default",printchannel
);
139 regchandisp("topic",printchannel_topic
);
140 regchandisp("services",printchannel_services
);
142 /* Nick output filters */
143 reguserdisp("default",printuser
);
145 registercontrolhelpcmd("nicksearch",NO_OPER
,4,do_nicksearch
, "Usage: nicksearch <criteria>\nSearches for nicknames with the given criteria.");
146 registercontrolhelpcmd("chansearch",NO_OPER
,4,do_chansearch
, "Usage: chansearch <criteria>\nSearches for channels with the given criteria.");
147 registercontrolhelpcmd("usersearch",NO_OPER
,4,do_usersearch
, "Usage: usersearch <criteria>\nSearches for users with the given criteria.");
151 destroycommandtree(searchTree
);
152 destroycommandtree(chanOutputTree
);
153 destroycommandtree(nickOutputTree
);
154 destroycommandtree(userOutputTree
);
155 deregistercontrolcmd("nicksearch", do_nicksearch
);
156 deregistercontrolcmd("chansearch", do_chansearch
);
157 deregistercontrolcmd("usersearch", do_usersearch
);
160 void registersearchterm(char *term
, parseFunc parsefunc
) {
161 addcommandtotree(searchTree
, term
, 0, 0, (CommandHandler
) parsefunc
);
164 void deregistersearchterm(char *term
, parseFunc parsefunc
) {
165 deletecommandfromtree(searchTree
, term
, (CommandHandler
) parsefunc
);
168 static void controlwallwrapper(int level
, char *format
, ...) {
172 va_start(ap
, format
);
173 vsnprintf(buf
, sizeof(buf
), format
, ap
);
174 controlwall(NO_OPER
, level
, "%s", buf
);
178 static int parseopts(int cargc
, char **cargv
, int *arg
, int *limit
, void **display
, CommandTree
*tree
, replyFunc reply
, void *sender
) {
182 if (*cargv
[0] == '-') {
186 for (ch
=cargv
[0]+1;*ch
;ch
++) {
190 reply(sender
,"Error: -l switch requires an argument");
193 *limit
=strtoul(cargv
[(*arg
)++],NULL
,10);
198 reply(sender
,"Error: -d switch requires an argument");
201 cmd
=findcommandintree(tree
, cargv
[*arg
], 1);
203 reply(sender
,"Error: unknown output format %s",cargv
[*arg
]);
206 *display
=(void *)cmd
->handler
;
211 reply(sender
,"Unrecognised flag -%c.",*ch
);
219 void newsearch_ctxinit(searchCtx
*ctx
, searchParseFunc searchfn
, replyFunc replyfn
, wallFunc wallfn
, void *arg
) {
220 memset(ctx
, 0, sizeof(searchCtx
));
222 ctx
->reply
= replyfn
;
224 ctx
->parser
= searchfn
;
228 int do_nicksearch_real(replyFunc reply
, wallFunc wall
, void *source
, int cargc
, char **cargv
) {
229 nick
*sender
= source
;
230 struct searchNode
*search
;
233 NickDisplayFunc display
=defaultnickfn
;
240 ret
= parseopts(cargc
, cargv
, &arg
, &limit
, (void **)&display
, nickOutputTree
, reply
, sender
);
245 reply(sender
,"No search terms - aborting.");
250 rejoinline(cargv
[arg
],cargc
-arg
);
253 newsearch_ctxinit(&ctx
, search_parse
, reply
, wall
, NULL
);
255 if (!(search
= ctx
.parser(&ctx
, SEARCHTYPE_NICK
, cargv
[arg
]))) {
256 reply(sender
,"Parse error: %s",parseError
);
260 nicksearch_exe(search
, &ctx
, sender
, display
, limit
);
262 (search
->free
)(&ctx
, search
);
267 int do_nicksearch(void *source
, int cargc
, char **cargv
) {
268 return do_nicksearch_real(controlreply
, controlwallwrapper
, source
, cargc
, cargv
);
271 void nicksearch_exe(struct searchNode
*search
, searchCtx
*ctx
, nick
*sender
, NickDisplayFunc display
, int limit
) {
274 unsigned int cmarker
;
275 unsigned int tchans
=0,uchans
=0;
278 senderNSExtern
= sender
;
280 /* Get a marker value to mark "seen" channels for unique count */
281 cmarker
=nextchanmarker();
283 /* The top-level node needs to return a BOOL */
284 search
=coerceNode(ctx
, search
, RETURNTYPE_BOOL
);
286 for (i
=0;i
<NICKHASHSIZE
;i
++) {
287 for (np
=nicktable
[i
];np
;np
=np
->next
) {
288 if ((search
->exe
)(ctx
, search
, np
)) {
289 /* Add total channels */
290 tchans
+= np
->channels
->cursi
;
292 /* Check channels for uniqueness */
293 cs
=(channel
**)np
->channels
->content
;
294 for (j
=0;j
<np
->channels
->cursi
;j
++) {
295 if (cs
[j
]->index
->marker
!= cmarker
) {
296 cs
[j
]->index
->marker
=cmarker
;
302 display(ctx
, sender
, np
);
305 ctx
->reply(sender
, "--- More than %d matches, skipping the rest",limit
);
311 ctx
->reply(sender
,"--- End of list: %d matches; users were on %u channels (%u unique, %.1f average clones)",
312 matches
, tchans
, uchans
, (float)tchans
/uchans
);
315 int do_chansearch_real(replyFunc reply
, wallFunc wall
, void *source
, int cargc
, char **cargv
) {
316 nick
*sender
= source
;
317 struct searchNode
*search
;
320 ChanDisplayFunc display
=defaultchanfn
;
327 ret
= parseopts(cargc
, cargv
, &arg
, &limit
, (void **)&display
, chanOutputTree
, reply
, sender
);
332 reply(sender
,"No search terms - aborting.");
337 rejoinline(cargv
[arg
],cargc
-arg
);
340 newsearch_ctxinit(&ctx
, search_parse
, reply
, wall
, NULL
);
341 if (!(search
= ctx
.parser(&ctx
, SEARCHTYPE_CHANNEL
, cargv
[arg
]))) {
342 reply(sender
,"Parse error: %s",parseError
);
346 chansearch_exe(search
, &ctx
, sender
, display
, limit
);
348 (search
->free
)(&ctx
, search
);
353 int do_chansearch(void *source
, int cargc
, char **cargv
) {
354 return do_chansearch_real(controlreply
, controlwallwrapper
, source
, cargc
, cargv
);
357 void chansearch_exe(struct searchNode
*search
, searchCtx
*ctx
, nick
*sender
, ChanDisplayFunc display
, int limit
) {
361 senderNSExtern
= sender
;
363 search
=coerceNode(ctx
, search
, RETURNTYPE_BOOL
);
365 for (i
=0;i
<CHANNELHASHSIZE
;i
++) {
366 for (cip
=chantable
[i
];cip
;cip
=cip
->next
) {
367 if ((search
->exe
)(ctx
, search
, cip
)) {
369 display(ctx
, sender
, cip
);
371 ctx
->reply(sender
, "--- More than %d matches, skipping the rest",limit
);
377 ctx
->reply(sender
,"--- End of list: %d matches", matches
);
380 int do_usersearch_real(replyFunc reply
, wallFunc wall
, void *source
, int cargc
, char **cargv
) {
381 nick
*sender
= source
;
382 struct searchNode
*search
;
385 UserDisplayFunc display
=defaultuserfn
;
392 ret
= parseopts(cargc
, cargv
, &arg
, &limit
, (void **)&display
, userOutputTree
, reply
, sender
);
397 reply(sender
,"No search terms - aborting.");
402 rejoinline(cargv
[arg
],cargc
-arg
);
405 newsearch_ctxinit(&ctx
, search_parse
, reply
, wall
, NULL
);
406 if (!(search
= ctx
.parser(&ctx
, SEARCHTYPE_USER
, cargv
[arg
]))) {
407 reply(sender
,"Parse error: %s",parseError
);
411 usersearch_exe(search
, &ctx
, sender
, display
, limit
);
413 (search
->free
)(&ctx
, search
);
418 int do_usersearch(void *source
, int cargc
, char **cargv
) {
419 return do_usersearch_real(controlreply
, controlwallwrapper
, source
, cargc
, cargv
);
422 void usersearch_exe(struct searchNode
*search
, searchCtx
*ctx
, nick
*sender
, UserDisplayFunc display
, int limit
) {
426 senderNSExtern
= sender
;
428 search
=coerceNode(ctx
, search
, RETURNTYPE_BOOL
);
430 for (i
=0;i
<AUTHNAMEHASHSIZE
;i
++) {
431 for (aup
=authnametable
[i
];aup
;aup
=aup
->next
) {
432 if ((search
->exe
)(ctx
, search
, aup
)) {
434 display(ctx
, sender
, aup
);
436 ctx
->reply(sender
, "--- More than %d matches, skipping the rest",limit
);
442 ctx
->reply(sender
,"--- End of list: %d matches", matches
);
445 /* Free a coerce node */
446 void free_coerce(searchCtx
*ctx
, struct searchNode
*thenode
) {
447 struct coercedata
*cd
=thenode
->localdata
;
449 cd
->child
->free(ctx
, cd
->child
);
450 free(thenode
->localdata
);
454 /* Free a coerce node with a stringbuf allocated */
455 void free_coercestring(searchCtx
*ctx
, struct searchNode
*thenode
) {
456 free(((struct coercedata
*)thenode
->localdata
)->u
.stringbuf
);
457 free_coerce(ctx
, thenode
);
460 /* exe_tostr_null: return the constant string */
461 void *exe_tostr_null(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
462 struct coercedata
*cd
=thenode
->localdata
;
464 return cd
->u
.stringbuf
;
467 /* exe_val_null: return the constant value */
468 void *exe_val_null(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
469 struct coercedata
*cd
=thenode
->localdata
;
471 return (void *)cd
->u
.val
;
474 /* Lots of very dull type conversion functions */
475 void *exe_inttostr(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
476 struct coercedata
*cd
=thenode
->localdata
;
478 sprintf(cd
->u
.stringbuf
, "%lu", (unsigned long)(cd
->child
->exe
)(ctx
, cd
->child
, theinput
));
480 return cd
->u
.stringbuf
;
483 void *exe_booltostr(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
484 struct coercedata
*cd
=thenode
->localdata
;
486 if ((cd
->child
->exe
)(ctx
, cd
->child
, theinput
)) {
487 sprintf(cd
->u
.stringbuf
,"1");
489 cd
->u
.stringbuf
[0]='\0';
492 return cd
->u
.stringbuf
;
495 void *exe_strtoint(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
496 struct coercedata
*cd
=thenode
->localdata
;
498 return (void *)strtoul((cd
->child
->exe
)(ctx
,cd
->child
,theinput
),NULL
,10);
501 void *exe_booltoint(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
502 struct coercedata
*cd
=thenode
->localdata
;
504 /* Don't need to do anything */
505 return (cd
->child
->exe
)(ctx
, cd
->child
, theinput
);
508 void *exe_strtobool(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
509 struct coercedata
*cd
=thenode
->localdata
;
510 char *ch
=(cd
->child
->exe
)(ctx
, cd
->child
, theinput
);
512 if (!ch
|| *ch
=='\0' || (*ch
=='0' && ch
[1]=='\0')) {
519 void *exe_inttobool(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
520 struct coercedata
*cd
=thenode
->localdata
;
522 if ((cd
->child
->exe
)(ctx
, cd
->child
, theinput
)) {
529 struct searchNode
*coerceNode(searchCtx
*ctx
, struct searchNode
*thenode
, int type
) {
530 struct searchNode
*anode
;
531 struct coercedata
*cd
;
533 /* You can't coerce a NULL */
537 /* No effort required to coerce to the same type */
538 if (type
==(thenode
->returntype
& RETURNTYPE_TYPE
))
541 anode
=(struct searchNode
*)malloc(sizeof(struct searchNode
));
542 anode
->localdata
=cd
=(struct coercedata
*)malloc(sizeof(struct coercedata
));
544 anode
->returntype
=type
; /* We'll return what they want, always */
545 anode
->free
=free_coerce
;
548 case RETURNTYPE_STRING
:
549 /* For a string we'll need a buffer */
550 /* A 64-bit number prints out to 20 digits, this leaves some slack */
551 cd
->u
.stringbuf
=malloc(25);
552 anode
->free
=free_coercestring
;
554 switch(thenode
->returntype
& RETURNTYPE_TYPE
) {
557 if (thenode
->returntype
& RETURNTYPE_CONST
) {
558 /* Constant node: sort it out now */
559 sprintf(cd
->u
.stringbuf
, "%lu", (unsigned long)thenode
->exe(ctx
, thenode
, NULL
));
560 anode
->exe
=exe_tostr_null
;
561 anode
->returntype
|= RETURNTYPE_CONST
;
564 anode
->exe
=exe_inttostr
;
568 case RETURNTYPE_BOOL
:
569 if (thenode
->returntype
& RETURNTYPE_CONST
) {
570 /* Constant bool value */
571 if (thenode
->exe(ctx
, thenode
,NULL
)) {
573 sprintf(cd
->u
.stringbuf
, "1");
575 cd
->u
.stringbuf
[0] = '\0';
577 anode
->exe
=exe_tostr_null
;
578 anode
->returntype
|= RETURNTYPE_CONST
;
580 /* Variable bool value */
581 anode
->exe
=exe_booltostr
;
589 switch (thenode
->returntype
& RETURNTYPE_TYPE
) {
590 case RETURNTYPE_STRING
:
591 if (thenode
->returntype
& RETURNTYPE_CONST
) {
592 cd
->u
.val
=strtoul((thenode
->exe
)(ctx
, thenode
, NULL
), NULL
, 10);
593 anode
->exe
=exe_val_null
;
594 anode
->returntype
|= RETURNTYPE_CONST
;
596 anode
->exe
=exe_strtoint
;
601 case RETURNTYPE_BOOL
:
602 if (thenode
->returntype
& RETURNTYPE_CONST
) {
603 if ((thenode
->exe
)(ctx
, thenode
,NULL
))
608 anode
->exe
=exe_val_null
;
609 anode
->returntype
|= RETURNTYPE_CONST
;
611 anode
->exe
=exe_booltoint
;
618 case RETURNTYPE_BOOL
:
620 switch (thenode
->returntype
& RETURNTYPE_TYPE
) {
621 case RETURNTYPE_STRING
:
622 if (thenode
->returntype
& RETURNTYPE_CONST
) {
623 char *rv
=(char *)((thenode
->exe
)(ctx
, thenode
, NULL
));
624 if (!rv
|| *rv
=='\0' || (*rv
=='0' && rv
[1]=='\0'))
629 anode
->exe
=exe_val_null
;
630 anode
->returntype
|= RETURNTYPE_CONST
;
632 anode
->exe
=exe_strtobool
;
638 if (thenode
->returntype
& RETURNTYPE_CONST
) {
639 if ((thenode
->exe
)(ctx
, thenode
,NULL
))
644 anode
->exe
=exe_val_null
;
645 anode
->returntype
|= RETURNTYPE_CONST
;
647 anode
->exe
=exe_inttobool
;
657 /* Literals always return constant strings... */
658 void *literal_exe(searchCtx
*ctx
, struct searchNode
*thenode
, void *theinput
) {
659 if (thenode
->localdata
)
660 return ((sstring
*)thenode
->localdata
)->content
;
665 void literal_free(searchCtx
*ctx
, struct searchNode
*thenode
) {
666 freesstring(thenode
->localdata
);
671 * Given an input string, return a searchNode.
674 struct searchNode
*search_parse(searchCtx
*ctx
, int type
, char *input
) {
675 /* OK, we need to split the input into chunks on spaces and brackets.. */
676 char *argvector
[100];
681 struct searchNode
*thenode
;
683 /* If it starts with a bracket, it's a function call.. */
685 /* Skip past string */
686 for (ch
=input
;*ch
;ch
++);
687 if (*(ch
-1) != ')') {
688 parseError
= "Bracket mismatch!";
694 /* Split further args */
695 i
=-1; /* i = -1 BoW, 0 = inword, 1 = bracket nest depth */
696 j
=0; /* j = current arg */
700 for (ch
=input
;*ch
;ch
++) {
705 } else if (*ch
!= ' ') {
709 } else if (*ch
=='\"') {
721 } else if (*ch
=='\"') {
723 } else if (*ch
==' ') {
726 if(j
>= (sizeof(argvector
) / sizeof(*argvector
))) {
727 parseError
= "Too many arguments";
735 } else if (*ch
=='\"') {
737 } else if (*ch
=='(') {
739 } else if (*ch
==')') {
746 parseError
= "Bracket mismatch!";
750 if (*(ch
-1) == 0) /* if the last character was a space */
751 j
--; /* remove an argument */
753 if (!(cmd
=findcommandintree(searchTree
,argvector
[0],1))) {
754 parseError
= "Unknown command";
757 return ((parseFunc
)cmd
->handler
)(ctx
, type
, j
, argvector
+1);
762 for (ch
=input
;*ch
;ch
++);
764 if (*(ch
-1) != '\"') {
765 parseError
="Quote mismatch";
774 for (ch
=input
;*ch
;ch
++) {
778 } else if (*ch
=='\\') {
786 if (!(thenode
=(struct searchNode
*)malloc(sizeof(struct searchNode
)))) {
787 parseError
= "malloc: could not allocate memory for this search.";
791 thenode
->localdata
= getsstring(thestring
,512);
792 thenode
->returntype
= RETURNTYPE_CONST
| RETURNTYPE_STRING
;
793 thenode
->exe
= literal_exe
;
794 thenode
->free
= literal_free
;
800 void nssnprintf(char *buf
, size_t size
, const char *format
, nick
*np
) {
813 for(p
=format
;*p
;p
++) {
815 if(!sbaddchar(&b
, *p
))
823 if(!sbaddchar(&b
, *p
))
833 c
= np
->ident
; break;
835 c
= np
->host
->name
->content
; break;
837 snprintf(hostbuf
, sizeof(hostbuf
), "%s", IPtostr(np
->p_ipaddr
));
841 snprintf(hostbuf
, sizeof(hostbuf
), "%s!%s@%s", np
->nick
, np
->ident
, IPtostr(np
->p_ipaddr
));
845 c
= "(bad format specifier)";
860 static char *var_tochar(searchCtx
*ctx
, int nstype
, char *arg
, searchNode
**variable
) {
861 *variable
= ctx
->parser(ctx
, nstype
, arg
);
862 if (!(*variable
= coerceNode(ctx
, *variable
, RETURNTYPE_STRING
)))
865 if(!((*variable
)->returntype
& RETURNTYPE_CONST
)) {
866 parseError
= "only constant variables allowed";
867 ((*variable
)->free
)(ctx
, *variable
);
871 return (char *)((*variable
)->exe
)(ctx
, *variable
, NULL
);
874 void free_val_null(searchCtx
*ctx
, struct searchNode
*thenode
) {
877 struct searchVariable
*var_register(searchCtx
*ctx
, int nstype
, char *arg
, int type
) {
878 searchNode
*variable
;
879 struct searchVariable
*us
;
883 if(ctx
->lastvar
>= MAX_VARIABLES
) {
884 parseError
= "Maximum number of variables reached";
888 us
= &ctx
->vars
[ctx
->lastvar
];
890 var
= var_tochar(ctx
, nstype
, arg
, &variable
);
894 strlcpy(us
->name
, var
, sizeof(us
->name
));
895 (variable
->free
)(ctx
, variable
);
897 for(i
=0;i
<ctx
->lastvar
;i
++) {
898 if(!strcmp(us
->name
, ctx
->vars
[i
].name
)) {
899 parseError
= "variable name already in use";
905 us
->data
.returntype
= type
;
906 us
->data
.localdata
= &us
->cdata
;
907 us
->data
.exe
= exe_val_null
;
908 us
->data
.free
= free_val_null
;
910 us
->cdata
.child
= NULL
;
914 searchNode
*var_get(searchCtx
*ctx
, int nstype
, char *arg
) {
915 searchNode
*variable
, *found
= NULL
;
917 char *var
= var_tochar(ctx
, nstype
, arg
, &variable
);
921 for(i
=0;i
<ctx
->lastvar
;i
++) {
922 if(!strcmp(var
, ctx
->vars
[i
].name
)) {
923 found
= &ctx
->vars
[i
].data
;
927 (variable
->free
)(ctx
, variable
);
930 parseError
= "variable not found";
934 void var_setstr(struct searchVariable
*v
, char *data
) {
935 v
->cdata
.u
.stringbuf
= data
;