Macros: convert to tree for speed of lookup
[exim.git] / src / src / macro.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge 1995 - 2017 */
6 /* See the file NOTICE for conditions of use and distribution. */
7
8 /* Functions for handling macros */
9
10 #include "exim.h"
11
12 #ifdef MACRO_PREDEF
13 # undef store_get
14 # define store_get(nbytes) malloc((size_t)(nbytes))
15 #define string_copyn(s, len) strndup(CS(s), (len))
16 #endif
17
18 /*************************************************
19 *       Deal with an assignment to a macro       *
20 *************************************************/
21
22 /* We have a new definition; add to the collection.
23 Items are numbered so we can avoid recursion in expansions.
24
25 Args:
26  name   Name of the macro.  Will be copied.
27  val    Expansion result for the macro.  Will be copied.
28 */
29
30 macro_item *
31 macro_create(const uschar * name, const uschar * val, BOOL command_line)
32 {
33 int namelen = Ustrlen(name);
34 macro_item * m = store_get(sizeof(macro_item) + namelen);
35
36 /* fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val); */
37
38 m->command_line = command_line;
39 m->namelen = namelen;
40 m->replen = Ustrlen(val);
41 m->m_number = m_number++;
42 memset(&m->tnode, 0, sizeof(tree_node));
43 Ustrcpy(m->tnode.name, name);
44 m->tnode.data.ptr = string_copyn(val, m->replen);
45 (void) tree_insertnode(&tree_macros, &m->tnode);
46
47 return m;
48 }
49
50
51 /* Search for a macro, with an exact match on the name.
52 Return the node, or NULL for not-found.
53
54 Arguments:      name    key to search for
55 */
56
57 macro_item *
58 macro_search(const uschar * name)
59 {
60 tree_node * t;
61
62 t = tree_search(tree_macros, name);
63 return tnode_to_mitem(t);
64 }
65
66
67 /* Search for a macro with a (possibly improper) leading substring
68 matching the given name.  Return the node, or NULL for not-found.
69
70 Arguments:      name    key to search on
71 */
72
73 macro_item *
74 macro_search_prefix(const uschar * s)
75 {
76 tree_node * t;
77 int c;
78
79 for (t = tree_macros; t; t = c < 0 ? t->left : t->right)
80   if ((c = Ustrncmp(s, t->name, tnode_to_mitem(t)->namelen)) == 0)
81     return tnode_to_mitem(t);
82 return NULL;
83 }
84
85
86 /* Search for the macro with the largest possible leading substring
87 matching the given name. */
88
89 macro_item *
90 macro_search_largest_prefix(const uschar * s)
91 {
92 macro_item * found;
93 tree_node * child;
94 int c;
95
96 if ((found = macro_search_prefix(s)))
97   {
98   /* There could be a node with a larger substring also matching the
99   name.  If so it must be in the right subtree; either the right child
100   or (if that sorts after the name) in the left subtree of the right child. */
101
102   child = found->tnode.right;
103   while (child)
104     if ((c = Ustrncmp(s, child->name, tnode_to_mitem(child)->namelen)) == 0)
105       {
106       found = tnode_to_mitem(child);
107       child = found->tnode.right;
108       }
109     else if (c < 0 && (child = child->left))
110       continue;
111     else
112       break;
113   }
114 return found;
115 }
116
117
118
119 void
120 macro_print(uschar * name, uschar * val, void * ctx)
121 {
122 BOOL names_only = (BOOL)(long)ctx;
123 if (names_only)
124   printf("%s\n", CS name);
125 else
126   printf("%s=%s\n", CS name, CS val);
127 }
128
129
130
131 /* vi: aw ai sw=2
132 */
133 /* End of macro.c */