/** Initialize the message lookup trie with all known commands. */ void initmsgtree(void) { int i; memset(&msg_tree, 0, sizeof(msg_tree)); memset(&tok_tree, 0, sizeof(tok_tree)); for (i = 0; msgtab[i].cmd != NULL ; i++) { add_msg_element(&msg_tree, &msgtab[i], msgtab[i].cmd); add_msg_element(&tok_tree, &msgtab[i], msgtab[i].tok); } }
/* * How this works. * * The code first checks to see if its reached the end of the command * If so, that struct MessageTree has a msg pointer updated and the links * count incremented, since a msg pointer is a reference. * Then the code descends recursively, building the trie. * If a pointer index inside the struct MessageTree is NULL a new * child struct MessageTree has to be allocated. * The links (reference count) is incremented as they are created * in the parent. */ static void add_msg_element(struct MessageTree *mtree_p, struct Message *msg_p, const char *cmd) { struct MessageTree *ntree_p = NULL; if (*cmd == '\0') { mtree_p->msg = msg_p; mtree_p->links++; /* Have msg pointer, so up ref count */ } else { /* * *cmd & (MAXPTRLEN-1) * convert the char pointed to at *cmd from ASCII to an integer * between 0 and MAXPTRLEN. * Thus 'A' -> 0x1 'B' -> 0x2 'c' -> 0x3 etc. */ if ((ntree_p = mtree_p->pointers[*cmd & (MAXPTRLEN - 1)]) == NULL) { ntree_p = xcalloc(sizeof(*ntree_p)); mtree_p->pointers[*cmd & (MAXPTRLEN - 1)] = ntree_p; mtree_p->links++; /* Have new pointer, so up ref count */ } add_msg_element(ntree_p, msg_p, cmd + 1); } }
/** Registers a service mapping to the pseudocommand handler. * @param[in] map Service mapping to add. * @return Non-zero on success; zero if a command already used the name. */ int register_mapping(struct s_map *map) { struct Message *msg; if (msg_tree_parse(map->command, &msg_tree)) return 0; msg = (struct Message *)MyMalloc(sizeof(struct Message)); msg->cmd = map->command; msg->tok = map->command; msg->count = 0; msg->parameters = 2; msg->flags = MFLG_EXTRA; if (!(map->flags & SMAP_FAST)) msg->flags |= MFLG_SLOW; msg->bytes = 0; msg->extra = map; msg->handlers[UNREGISTERED_HANDLER] = m_ignore; msg->handlers[CLIENT_HANDLER] = m_pseudo; msg->handlers[SERVER_HANDLER] = m_ignore; msg->handlers[OPER_HANDLER] = m_pseudo; msg->handlers[SERVICE_HANDLER] = m_ignore; add_msg_element(&msg_tree, msg, msg->cmd); map->msg = msg; return 1; }
/* mod_add_cmd() * * inputs - pointer to struct Message * output - none * side effects - load this one command name */ void mod_add_cmd(struct Message *msg) { assert(msg); assert(msg->cmd); /* Command already added? */ if (msg_tree_parse(msg->cmd) == NULL) add_msg_element(&msg_tree, msg, msg->cmd); }
/** Add a message to the lookup trie. * @param[in,out] mtree_p Trie node to insert under. * @param[in] msg_p Message to insert. * @param[in] cmd Text of command to insert. */ void add_msg_element(struct MessageTree *mtree_p, struct Message *msg_p, char *cmd) { struct MessageTree *ntree_p; if (*cmd == '\0') { mtree_p->msg = msg_p; return; } if ((ntree_p = mtree_p->pointers[*cmd & (MAXPTRLEN-1)]) != NULL) { add_msg_element(ntree_p, msg_p, cmd+1); } else { ntree_p = (struct MessageTree *)MyCalloc(sizeof(struct MessageTree), 1); mtree_p->pointers[*cmd & (MAXPTRLEN-1)] = ntree_p; add_msg_element(ntree_p, msg_p, cmd+1); } }
/* mod_add_cmd() * * inputs - pointer to struct Message * output - none * side effects - load this one command name * msg->count msg->bytes is modified in place, in * modules address space. Might not want to do that... */ void mod_add_cmd(struct Message *msg) { struct Message *found_msg; if (msg == NULL) return; /* someone loaded a module with a bad messagetab */ assert(msg->cmd != NULL); /* command already added? */ if ((found_msg = msg_tree_parse(msg->cmd, &msg_tree)) != NULL) return; add_msg_element(&msg_tree, msg, msg->cmd); msg->count = msg->rcount = msg->bytes = 0; }