]>
jfr.im git - irc/quakenet/newserv.git/blob - parser/parser.c
4 #include "../lib/sstring.h"
5 #include "../lib/irc_string.h"
6 #include "../core/error.h"
14 int insertcommand(Command
*c
, CommandTree
*ct
, int depth
);
15 int deletecommand(sstring
*cmdname
, CommandTree
*ct
, int depth
, CommandHandler handler
);
16 Command
*findcommand(CommandTree
*ct
, const char *command
, int depth
);
17 int countcommandtree(CommandTree
*ct
);
21 * This creates a new command tree.
23 * Uses malloc() as it's a pretty rare event.
26 CommandTree
*newcommandtree() {
29 nct
=(void *)malloc(sizeof(CommandTree
));
30 memset(nct
,0,sizeof(CommandTree
));
35 /* destroycommandtree:
37 * This frees a tree and all it's subtrees
40 void destroycommandtree(CommandTree
*ct
) {
45 destroycommandtree((CommandTree
*)ct
->next
[i
]);
51 freesstring(ct
->cmd
->command
);
52 if(ct
->cmd
->ext
&& ct
->cmd
->destroyext
)
53 (ct
->cmd
->destroyext
)(ct
->cmd
->ext
);
61 * This returns the number of commands registered in
62 * a particular (sub-)tree. This will come in handy
63 * later for deleting commands etc.
66 int countcommandtree(CommandTree
*ct
) {
78 sum
+=countcommandtree((CommandTree
*)ct
->next
[i
]);
83 /* sanitisecommandname:
85 * Converts the given command name to uppercase and checks for bad chars.
87 * Returns 1 if bad chars were found
89 static int sanitisecommandname(const char *cmdname
, char *cmdbuf
) {
92 strncpy(cmdbuf
,cmdname
,MAX_COMMAND_LEN
);
93 cmdbuf
[MAX_COMMAND_LEN
-1]='\0';
97 /* Sanity check the string */
99 cmdbuf
[i
]=toupper(cmdbuf
[i
]);
100 if (cmdbuf
[i
]<'A' || cmdbuf
[i
]>'Z') {
101 /* Someone tried to register an invalid command name */
110 * addcommandhelptotree:
112 * This installs a specific command in a tree, with a help paramater.
114 * This function builds the Command structure in addition to
115 * installing it in the tree
118 Command
*addcommandexttotree(CommandTree
*ct
, const char *cmdname
, int level
, int maxparams
, CommandHandler handler
, void *ext
) {
120 char cmdbuf
[MAX_COMMAND_LEN
];
122 if (sanitisecommandname(cmdname
, cmdbuf
))
125 /* Generate the struct.. */
126 nc
=(void *)malloc(sizeof(Command
));
127 nc
->command
=getsstring(cmdbuf
, MAX_COMMAND_LEN
);
129 nc
->maxparams
=maxparams
;
135 if ((c
=findcommandintree(ct
,cmdname
,1))!=NULL
) {
136 /* Found something already. Append our entry to the end */
137 while (c
->next
!=NULL
)
138 c
=(Command
*)c
->next
;
139 c
->next
=(struct Command
*)nc
;
140 } else if (insertcommand(nc
,ct
,0)) {
141 /* Erk, that didn't work.. */
142 freesstring(nc
->command
);
154 * insertcommand: internal recursive function to do actual command insertion
157 int insertcommand(Command
*c
, CommandTree
*ct
, int depth
) {
158 int nextcharindex
=c
->command
->content
[depth
]-'A';
160 if ((c
->command
->length
==depth
) || (countcommandtree(ct
)==0)) {
163 /* There is already another command at this level */
164 if(ct
->final
[0]=='\0') {
165 /* It's a conflict with us, shouldn't happen */
168 oldcharindex
=ct
->final
[0]-'A';
169 if (ct
->next
[oldcharindex
] != NULL
) {
170 /* Shouldn't happen */
171 Error("parser",ERR_ERROR
,"Unexpected command subtree conflicts with final value");
173 ct
->next
[oldcharindex
]=(struct CommandTree
*)newcommandtree();
175 insertcommand(ct
->cmd
,(CommandTree
*)ct
->next
[oldcharindex
],depth
+1);
178 /* Use a static NUL string rather than the allocated one if possible. */
179 if (c
->command
->length
> depth
)
180 ct
->final
=&(c
->command
->content
[depth
]);
185 if ((ct
->cmd
!=NULL
) && (ct
->final
[0]!='\0')) {
186 int oldcharindex
=ct
->final
[0]-'A';
187 /* Someone marked this node as final, we have to undo that since we're now here too */
188 if (ct
->next
[oldcharindex
] != NULL
) {
189 Error("parser",ERR_ERROR
,"Unexpected command subtree conflicts with final value");
190 /* Shouldn't happen */
192 ct
->next
[oldcharindex
]=(struct CommandTree
*)newcommandtree();
194 insertcommand(ct
->cmd
,(CommandTree
*)ct
->next
[oldcharindex
],depth
+1);
199 if (ct
->next
[nextcharindex
]==NULL
) {
200 ct
->next
[nextcharindex
]=(struct CommandTree
*)newcommandtree();
202 return insertcommand(c
,(CommandTree
*)ct
->next
[nextcharindex
],depth
+1);
206 int deletecommandfromtree(CommandTree
*ct
, const char *cmdname
, CommandHandler handler
) {
208 char cmdbuf
[MAX_COMMAND_LEN
+1];
211 if (sanitisecommandname(cmdname
, cmdbuf
))
214 tmpstr
=getsstring(cmdbuf
, MAX_COMMAND_LEN
);
215 i
=deletecommand(tmpstr
,ct
,0,handler
);
221 int deletecommand(sstring
*cmdname
, CommandTree
*ct
, int depth
, CommandHandler handler
) {
223 int nextcharindex
=(cmdname
->content
[depth
])-'A';
226 if (depth
==cmdname
->length
) {
227 /* Hit the end of the string.. the command should be in this node */
228 if ((ct
->cmd
==NULL
) ||
229 (ct
->cmd
->command
->length
!= cmdname
->length
) ||
230 (strncmp(ct
->cmd
->command
->content
,cmdname
->content
,cmdname
->length
))) {
233 for(ch
=&(ct
->cmd
);*ch
;ch
=(Command
**)&((*ch
)->next
)) {
234 if ((*ch
)->handler
==handler
) {
236 (*ch
)=(Command
*)((*ch
)->next
);
237 freesstring(c
->command
);
238 if(c
->ext
&& c
->destroyext
)
239 (c
->destroyext
)(c
->ext
);
245 } else if ((ct
->final
) && (ct
->final
[0]==cmdname
->content
[depth
])) {
246 /* We have a potentially matching final string here, double check */
247 if ((ct
->cmd
->command
->length
!= cmdname
->length
) ||
248 (strncmp(ct
->cmd
->command
->content
,cmdname
->content
,cmdname
->length
))) {
251 /* Find the command in the potential chain and remove it */
252 for(ch
=&(ct
->cmd
);*ch
;ch
=(Command
**)&((*ch
)->next
)) {
253 if ((*ch
)->handler
==handler
) {
255 (*ch
)=(Command
*)((*ch
)->next
);
256 freesstring(c
->command
);
257 if(c
->ext
&& c
->destroyext
)
258 (c
->destroyext
)(c
->ext
);
261 /* We need to regenerate the final pointer if needed;
262 * if ct->cmd is still pointing to a command it has the same name.
263 * Otherwise we should clear it.*/
265 ct
->final
=&(ct
->cmd
->command
->content
[depth
]);
274 /* We're going to have to recurse.. */
275 if (ct
->next
[nextcharindex
]==NULL
) {
278 i
=deletecommand(cmdname
,(CommandTree
*)ct
->next
[nextcharindex
],depth
+1,handler
);
279 if (countcommandtree((CommandTree
*)ct
->next
[nextcharindex
])==0) {
280 free(ct
->next
[nextcharindex
]);
281 ct
->next
[nextcharindex
]=NULL
;
289 * findcommandintree: Takes a command string and returns the relevant
290 * structure, if found.
293 Command
*findcommandintree(CommandTree
*ct
, const char *command
, int strictcheck
) {
296 c
=findcommand(ct
,command
,0);
302 (ircd_strncmp(command
,c
->command
->content
,c
->command
->length
) ||
303 (c
->command
->length
!= strlen(command
))))
310 * findcommand: Internal recursive function to find a command
313 Command
*findcommand(CommandTree
*ct
, const char *command
, int depth
) {
314 int nextchar
=toupper(command
[depth
]);
316 /* If we've run out of string, we return whatever we find in this node,
317 * be it NULL or otherwise. */
318 if (nextchar
=='\0') {
322 if ((ct
->cmd
!=NULL
) && ct
->final
[0]==nextchar
) {
326 if (nextchar
<'A' || nextchar
>'Z') {
330 if (ct
->next
[nextchar
-'A']==NULL
) {
333 return findcommand((CommandTree
*)ct
->next
[nextchar
-'A'], command
, depth
+1);
338 * getcommandlist: Returns the contents of a CommandTree in a user-supplied Command * array
341 int getcommandlist(CommandTree
*ct
, Command
**commandlist
, int maxcommands
) {
349 commandlist
[count
++]=ct
->cmd
;
354 count
+=getcommandlist(ct
->next
[i
], &commandlist
[count
], maxcommands
-count
);
361 /* Returns the command name given a handler */
362 sstring
*getcommandname(CommandTree
*ct
, CommandHandler handler
) {
366 if(ct
->cmd
&& ct
->cmd
->handler
== handler
) {
367 return ct
->cmd
->command
;
372 s
=getcommandname(ct
->next
[i
], handler
);