1 : #define VSTR_ADD_FMT_C
2 : /*
3 : * Copyright (C) 2002, 2003, 2004 James Antill
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Lesser General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Lesser General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public
16 : * License along with this library; if not, write to the Free Software
17 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 : *
19 : * email: james@and.org
20 : */
21 : /* Registration/deregistration of custom format specifiers */
22 : #include "main.h"
23 :
24 :
25 : static
26 : Vstr__fmt_usr_name_node **
27 : vstr__fmt_usr_srch(Vstr_conf *conf, const char *name)
28 350883 : {
29 350883 : Vstr__fmt_usr_name_node **scan = &conf->fmt_usr_names;
30 350883 : size_t len = strlen(name);
31 :
32 16274108 : while (*scan)
33 : {
34 16089178 : assert(!(*scan)->next || ((*scan)->name_len <= (*scan)->next->name_len));
35 :
36 16089178 : if (((*scan)->name_len == len) &&
37 : !vstr_wrap_memcmp((*scan)->name_str, name, len))
38 165953 : return (scan);
39 :
40 15923225 : scan = &(*scan)->next;
41 : }
42 :
43 184930 : return (NULL);
44 : }
45 :
46 : /* like srch, but matches in a format (Ie. not zero terminated) */
47 : Vstr__fmt_usr_name_node *vstr__fmt_usr_match(Vstr_conf *conf, const char *fmt)
48 220465 : {
49 220465 : Vstr__fmt_usr_name_node *scan = conf->fmt_usr_names;
50 220465 : size_t fmt_max_len = 0;
51 :
52 220465 : if (conf->fmt_usr_curly_braces)
53 : { /* we know they follow a format of one of...
54 : "{" [^}]* "}"
55 : "[" [^]]* "]"
56 : "<" [^>]* ">"
57 : "(" [^)]* ")"
58 : * so we can find the length */
59 195515 : char *ptr = NULL;
60 195515 : size_t len = 0;
61 :
62 195515 : switch (*fmt)
63 : {
64 75743 : case '{': ptr = strchr(fmt, '}'); break;
65 270 : case '[': ptr = strchr(fmt, ']'); break;
66 119497 : case '<': ptr = strchr(fmt, '>'); break;
67 5 : case '(': ptr = strchr(fmt, ')');
68 1 : ASSERT_NO_SWITCH_DEF();
69 : }
70 :
71 195515 : if (!ptr)
72 4 : return (NULL);
73 :
74 195511 : len = (ptr - fmt) + 1;
75 24140379 : while (scan)
76 : {
77 24140375 : assert(!scan->next || (scan->name_len <= scan->next->name_len));
78 :
79 24140375 : if ((scan->name_len == len) &&
80 : !vstr_wrap_memcmp(scan->name_str, fmt, len))
81 195507 : break;
82 :
83 23944868 : ASSERT_RET(scan->name_len <= len, NULL);
84 :
85 23944868 : scan = scan->next;
86 : }
87 :
88 195511 : return (scan);
89 : }
90 :
91 24950 : if (!conf->fmt_name_max)
92 : {
93 1021 : while (scan)
94 : {
95 1016 : if (conf->fmt_name_max < scan->name_len)
96 85 : conf->fmt_name_max = scan->name_len;
97 :
98 1016 : scan = scan->next;
99 : }
100 :
101 5 : scan = conf->fmt_usr_names;
102 : }
103 :
104 24950 : fmt_max_len = strnlen(fmt, conf->fmt_name_max);
105 1488546 : while (scan && (fmt_max_len >= scan->name_len))
106 : {
107 1483861 : assert(!scan->next || (scan->name_len <= scan->next->name_len));
108 :
109 1483861 : if (!vstr_wrap_memcmp(fmt, scan->name_str, scan->name_len))
110 20265 : return (scan);
111 :
112 1463596 : scan = scan->next;
113 : }
114 :
115 4685 : return (NULL);
116 : }
117 :
118 : #define VSTR__FMT_ADD_Q(name, len, b1, b2) ( \
119 : ((name)[0] == (b1)) && \
120 : ((name)[(len) - 1] == (b2)) && \
121 : (((len) == 2) || ((len) > 2)) && \
122 : !memchr((name) + 1, (b1), (len) - 2) && \
123 : !memchr((name) + 1, (b2), (len) - 2) \
124 : )
125 :
126 : int vstr_fmt_add(Vstr_conf *passed_conf, const char *name,
127 : int (*func)(Vstr_base *, size_t, Vstr_fmt_spec *), ...)
128 130851 : {
129 130851 : Vstr_conf *conf = passed_conf ? passed_conf : vstr__options.def;
130 130851 : Vstr__fmt_usr_name_node **scan = &conf->fmt_usr_names;
131 130851 : va_list ap;
132 130851 : unsigned int count = 1;
133 130851 : unsigned int scan_type = 0;
134 130851 : Vstr__fmt_usr_name_node *node = NULL;
135 :
136 130851 : if (vstr__fmt_usr_srch(conf, name))
137 5 : return (FALSE);
138 :
139 130846 : node = VSTR__MK(sizeof(Vstr__fmt_usr_name_node) +
140 : (sizeof(unsigned int) * count));
141 :
142 130846 : if (!node)
143 : {
144 201 : conf->malloc_bad = TRUE;
145 201 : return (FALSE);
146 : }
147 :
148 130645 : node->name_str = name;
149 130645 : node->name_len = strlen(name);
150 130645 : node->func = func;
151 :
152 130645 : if (conf->fmt_usr_curly_braces &&
153 : !VSTR__FMT_ADD_Q(name, node->name_len, '{', '}') &&
154 : !VSTR__FMT_ADD_Q(name, node->name_len, '[', ']') &&
155 : !VSTR__FMT_ADD_Q(name, node->name_len, '<', '>') &&
156 : !VSTR__FMT_ADD_Q(name, node->name_len, '(', ')'))
157 20 : conf->fmt_usr_curly_braces = FALSE;
158 :
159 130645 : va_start(ap, func);
160 338694 : while ((scan_type = va_arg(ap, unsigned int)))
161 : {
162 208343 : Vstr__fmt_usr_name_node *tmp_node = NULL;
163 :
164 208343 : ++count;
165 208343 : if (!VSTR__MV(node, tmp_node, (sizeof(Vstr__fmt_usr_name_node) +
166 : (sizeof(unsigned int) * count))))
167 : {
168 294 : conf->malloc_bad = TRUE;
169 294 : VSTR__F(node);
170 294 : va_end(ap);
171 294 : return (FALSE);
172 : }
173 :
174 208049 : assert(FALSE ||
175 : (scan_type == VSTR_TYPE_FMT_INT) ||
176 : (scan_type == VSTR_TYPE_FMT_UINT) ||
177 : (scan_type == VSTR_TYPE_FMT_LONG) ||
178 : (scan_type == VSTR_TYPE_FMT_ULONG) ||
179 : (scan_type == VSTR_TYPE_FMT_LONG_LONG) ||
180 : (scan_type == VSTR_TYPE_FMT_ULONG_LONG) ||
181 : (scan_type == VSTR_TYPE_FMT_SSIZE_T) ||
182 : (scan_type == VSTR_TYPE_FMT_SIZE_T) ||
183 : (scan_type == VSTR_TYPE_FMT_PTRDIFF_T) ||
184 : (scan_type == VSTR_TYPE_FMT_INTMAX_T) ||
185 : (scan_type == VSTR_TYPE_FMT_UINTMAX_T) ||
186 : (scan_type == VSTR_TYPE_FMT_DOUBLE) ||
187 : (scan_type == VSTR_TYPE_FMT_DOUBLE_LONG) ||
188 : (scan_type == VSTR_TYPE_FMT_PTR_VOID) ||
189 : (scan_type == VSTR_TYPE_FMT_PTR_CHAR) ||
190 : (scan_type == VSTR_TYPE_FMT_PTR_WCHAR_T) ||
191 : (scan_type == VSTR_TYPE_FMT_ERRNO) ||
192 : (scan_type == VSTR_TYPE_FMT_PTR_SIGNED_CHAR) ||
193 : (scan_type == VSTR_TYPE_FMT_PTR_SHORT) ||
194 : (scan_type == VSTR_TYPE_FMT_PTR_INT) ||
195 : (scan_type == VSTR_TYPE_FMT_PTR_LONG) ||
196 : (scan_type == VSTR_TYPE_FMT_PTR_LONG_LONG) ||
197 : (scan_type == VSTR_TYPE_FMT_PTR_SSIZE_T) ||
198 : (scan_type == VSTR_TYPE_FMT_PTR_PTRDIFF_T) ||
199 : (scan_type == VSTR_TYPE_FMT_PTR_INTMAX_T) ||
200 : FALSE);
201 :
202 208049 : node->types[count - 2] = scan_type;
203 : }
204 130351 : assert(count >= 1);
205 130351 : node->types[count - 1] = scan_type;
206 130351 : node->sz = count;
207 :
208 130351 : va_end(ap);
209 :
210 130351 : if (!*scan || (conf->fmt_name_max && (conf->fmt_name_max < node->name_len)))
211 6334 : conf->fmt_name_max = node->name_len;
212 :
213 5301418 : while (*scan)
214 : {
215 5295084 : if ((*scan)->name_len >= node->name_len)
216 124017 : break;
217 :
218 5171067 : scan = &(*scan)->next;
219 : }
220 :
221 130351 : node->next = *scan;
222 130351 : *scan = node;
223 :
224 130351 : assert(vstr__fmt_usr_srch(conf, name));
225 :
226 130351 : return (TRUE);
227 : }
228 :
229 : void vstr_fmt_del(Vstr_conf *passed_conf, const char *name)
230 155246 : {
231 155246 : Vstr_conf *conf = passed_conf ? passed_conf : vstr__options.def;
232 155246 : Vstr__fmt_usr_name_node **scan = vstr__fmt_usr_srch(conf, name);
233 :
234 155246 : if (scan)
235 : {
236 101167 : Vstr__fmt_usr_name_node *tmp = *scan;
237 :
238 101167 : assert(tmp);
239 :
240 101167 : *scan = tmp->next;
241 :
242 101167 : if (tmp->name_len == conf->fmt_name_max)
243 792 : conf->fmt_name_max = 0;
244 :
245 101167 : VSTR__F(tmp);
246 : }
247 : }
248 :
249 : int vstr_fmt_srch(Vstr_conf *passed_conf, const char *name)
250 65 : {
251 65 : Vstr_conf *conf = passed_conf ? passed_conf : vstr__options.def;
252 65 : return (!!vstr__fmt_usr_srch(conf, name));
253 : }
|