1 : #define VSTR_C
2 : /*
3 : * Copyright (C) 1999, 2000, 2001, 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 : /* master file, contains most of the base functions */
22 : #include "main.h"
23 :
24 :
25 : /* validity checking function... only called from asserts */
26 : #ifndef NDEBUG
27 : static void vstr__cache_iovec_check(const Vstr_base *base)
28 5810910 : {
29 5810910 : unsigned int count = 0;
30 5810910 : Vstr_node *scan = NULL;
31 :
32 5810910 : if (!base->iovec_upto_date || !base->beg)
33 65414 : return;
34 :
35 4173576 : count = VSTR__CACHE(base)->vec->off;
36 4173576 : scan = base->beg;
37 :
38 4173576 : assert(scan->len > base->used);
39 4173576 : assert(VSTR__CACHE(base)->vec->sz >= base->num);
40 4173576 : assert(VSTR__CACHE(base)->vec->v[count].iov_len == (size_t)(scan->len - base->used));
41 4173576 : if (scan->type == VSTR_TYPE_NODE_NON)
42 89 : assert(!VSTR__CACHE(base)->vec->v[count].iov_base);
43 : else
44 4173487 : assert(VSTR__CACHE(base)->vec->v[count].iov_base ==
45 : (vstr_export__node_ptr(scan) + base->used));
46 4173576 : assert(VSTR__CACHE(base)->vec->t[count] == scan->type);
47 :
48 4173576 : if (!(scan = scan->next))
49 351338 : ASSERT(base->beg == base->end);
50 :
51 4173576 : ++count;
52 334756699 : while (scan)
53 : {
54 330583123 : assert(VSTR__CACHE(base)->vec->t[count] == scan->type);
55 330583123 : assert(VSTR__CACHE(base)->vec->v[count].iov_len == scan->len);
56 330583123 : assert(VSTR__CACHE(base)->vec->v[count].iov_base ==
57 : vstr_export__node_ptr(scan));
58 :
59 330583123 : ++count;
60 :
61 330583123 : if (!scan->next)
62 3822238 : assert(scan == base->end);
63 :
64 330583123 : scan = scan->next;
65 : }
66 : }
67 :
68 : static void vstr__cache_cstr_check(const Vstr_base *base)
69 5810910 : {
70 5810910 : Vstr__cache_data_cstr *data = NULL;
71 5810910 : const char *ptr = NULL;
72 :
73 5810910 : ASSERT(base->conf->cache_pos_cb_cstr == 3);
74 :
75 5810910 : if (!(data = vstr_cache_get(base, base->conf->cache_pos_cb_cstr)))
76 3490496 : return;
77 2320414 : if (!data->ref || !data->len)
78 46250 : return;
79 :
80 9638 : ASSERT(data->len < data->sz);
81 :
82 9638 : ptr = data->ref->ptr;
83 9638 : ptr += data->off;
84 :
85 : { /* special case vstr_cmp_buf_eq() ... works with _NON data */
86 9638 : Vstr_iter iter[1];
87 :
88 9638 : ASSERT(vstr_iter_fwd_beg(base, data->pos, data->len, iter));
89 :
90 108567 : do
91 : {
92 108567 : if (iter->node->type != VSTR_TYPE_NODE_NON)
93 108525 : ASSERT(!memcmp(iter->ptr, ptr, iter->len));
94 108567 : ptr += iter->len;
95 108567 : } while (vstr_iter_fwd_nxt(iter));
96 : }
97 : }
98 :
99 : int vstr__check_real_nodes(const Vstr_base *base)
100 5810910 : {
101 5810910 : size_t len = 0;
102 5810910 : size_t num = 0;
103 5810910 : unsigned int node_buf_used = FALSE;
104 5810910 : unsigned int node_non_used = FALSE;
105 5810910 : unsigned int node_ptr_used = FALSE;
106 5810910 : unsigned int node_ref_used = FALSE;
107 5810910 : Vstr_node *scan = base->beg;
108 :
109 5810910 : vstr__debug_malloc_check_mem(base);
110 :
111 5810910 : ASSERT(!base->used || (base->used < base->beg->len));
112 5810910 : ASSERT(!base->used || (base->beg->type == VSTR_TYPE_NODE_BUF));
113 5810910 : ASSERT((base->beg == base->end) || (base->num > 1));
114 :
115 539517071 : while (scan)
116 : {
117 533706161 : ASSERT(scan->len);
118 :
119 533706161 : switch (scan->type)
120 : {
121 88333785 : case VSTR_TYPE_NODE_BUF: node_buf_used = TRUE; break;
122 159167 : case VSTR_TYPE_NODE_NON: node_non_used = TRUE; break;
123 269207323 : case VSTR_TYPE_NODE_PTR: node_ptr_used = TRUE; break;
124 176005886 : case VSTR_TYPE_NODE_REF: node_ref_used = TRUE;
125 :
126 176005886 : ASSERT_NO_SWITCH_DEF();
127 : }
128 :
129 533706161 : len += scan->len;
130 :
131 533706161 : ++num;
132 :
133 533706161 : scan = scan->next;
134 : }
135 :
136 : /* it can be TRUE in the base and FALSE in reallity */
137 5810910 : assert(!node_buf_used || base->node_buf_used);
138 5810910 : assert(!node_non_used || base->node_non_used);
139 5810910 : assert(!node_ptr_used || base->node_ptr_used);
140 5810910 : assert(!node_ref_used || base->node_ref_used);
141 :
142 5810910 : assert(!!base->beg == !!base->end);
143 5810910 : assert(((len - base->used) == base->len) && (num == base->num));
144 :
145 5810910 : vstr__cache_iovec_check(base);
146 5810910 : vstr__cache_cstr_check(base);
147 :
148 5810910 : return (TRUE);
149 : }
150 :
151 : int vstr__check_spare_nodes(const Vstr_conf *conf)
152 5989311 : {
153 5989311 : unsigned int num = 0;
154 5989311 : Vstr_node *scan = NULL;
155 :
156 5989311 : vstr__debug_malloc_check_mem(conf);
157 :
158 5989311 : num = 0;
159 5989311 : scan = (Vstr_node *)conf->spare_buf_beg;
160 1508852309 : while (scan)
161 : {
162 1502862998 : ++num;
163 :
164 1502862998 : assert(scan->type == VSTR_TYPE_NODE_BUF);
165 :
166 1502862998 : scan = scan->next;
167 : }
168 5989311 : assert(conf->spare_buf_num == num);
169 :
170 5989311 : num = 0;
171 5989311 : scan = (Vstr_node *)conf->spare_non_beg;
172 6121767 : while (scan)
173 : {
174 132456 : ++num;
175 :
176 132456 : assert(scan->type == VSTR_TYPE_NODE_NON);
177 :
178 132456 : scan = scan->next;
179 : }
180 5989311 : assert(conf->spare_non_num == num);
181 :
182 5989311 : num = 0;
183 5989311 : scan = (Vstr_node *)conf->spare_ptr_beg;
184 461647735 : while (scan)
185 : {
186 455658424 : ++num;
187 :
188 455658424 : assert(scan->type == VSTR_TYPE_NODE_PTR);
189 :
190 455658424 : scan = scan->next;
191 : }
192 5989311 : assert(conf->spare_ptr_num == num);
193 :
194 5989311 : num = 0;
195 5989311 : scan = (Vstr_node *)conf->spare_ref_beg;
196 294328826 : while (scan)
197 : {
198 288339515 : ++num;
199 :
200 288339515 : assert(scan->type == VSTR_TYPE_NODE_REF);
201 :
202 288339515 : scan = scan->next;
203 : }
204 5989311 : assert(conf->spare_ref_num == num);
205 :
206 5989311 : return (TRUE);
207 : }
208 :
209 : static int vstr__check_spare_base(const Vstr_conf *conf)
210 22393 : {
211 22393 : Vstr_base *scan = NULL;
212 22393 : unsigned int num = 0;
213 :
214 22393 : ASSERT(conf);
215 :
216 22393 : scan = conf->spare_base_beg;
217 86813 : while (scan)
218 : { /* FIXME: ... BIG HACK */
219 64420 : ++num;
220 :
221 64420 : scan = (Vstr_base *)scan->beg;
222 : }
223 :
224 22393 : ASSERT(num == conf->spare_base_num);
225 :
226 22393 : return (TRUE);
227 : }
228 : #endif
229 :
230 : /* real functions... */
231 :
232 :
233 : size_t vstr__loc_thou_grp_strlen(const char *passed_str)
234 1077 : {
235 1077 : const unsigned char *str = (const unsigned char *)passed_str;
236 1077 : size_t len = 0;
237 :
238 3026 : while (*str && (*str < SCHAR_MAX))
239 : {
240 1949 : ++len;
241 1949 : ++str;
242 : }
243 :
244 1077 : if (*str)
245 15 : ++len;
246 :
247 1077 : return (len);
248 : }
249 :
250 : Vstr_locale_num_base *
251 : vstr__loc_num_srch(Vstr_locale *loc, unsigned int num_base, int clone)
252 2593305 : {
253 2593305 : Vstr_locale_num_base *scan = loc->num_beg;
254 2593305 : Vstr_locale_num_base *def = NULL;
255 :
256 3889759 : while (scan)
257 : {
258 2593936 : if (scan->num_base == num_base)
259 1297482 : return (scan);
260 :
261 1296454 : scan = scan->next;
262 : }
263 :
264 1295823 : ASSERT(num_base);
265 :
266 1295823 : def = vstr__loc_num_srch(loc, 0, FALSE);
267 :
268 1295823 : if (clone)
269 : {
270 41 : if (!(scan = VSTR__MK(sizeof(Vstr_locale_num_base))))
271 1 : return (NULL);
272 :
273 40 : scan->next = loc->num_beg;
274 :
275 40 : scan->num_base = num_base;
276 40 : scan->grouping = vstr_ref_add(def->grouping);
277 40 : scan->thousands_sep_ref = vstr_ref_add(def->thousands_sep_ref);
278 40 : scan->thousands_sep_len = def->thousands_sep_len;
279 40 : scan->decimal_point_ref = vstr_ref_add(def->decimal_point_ref);
280 40 : scan->decimal_point_len = def->decimal_point_len;
281 :
282 40 : loc->num_beg = scan;
283 :
284 40 : return (scan);
285 : }
286 :
287 1295782 : return (def);
288 : }
289 :
290 : static int vstr__make_conf_loc_def_numeric(Vstr_conf *conf)
291 6269 : {
292 6269 : Vstr_ref *ref = NULL;
293 :
294 6269 : ASSERT(conf);
295 6269 : ASSERT(conf->loc);
296 6269 : ASSERT(conf->loc->num_beg);
297 :
298 6269 : conf->loc->num_beg->num_base = 0;
299 6269 : conf->loc->num_beg->next = NULL;
300 :
301 6269 : if (!(conf->loc->name_lc_numeric_ref = vstr_ref_make_strdup("C")))
302 1 : goto fail_numeric;
303 :
304 6268 : if (!(ref = conf->loc->num_beg->grouping = vstr_ref_make_strdup("")))
305 1 : goto fail_grp;
306 :
307 6267 : conf->loc->num_beg->thousands_sep_ref = vstr_ref_add(ref);
308 :
309 6267 : if (!(conf->loc->num_beg->decimal_point_ref = vstr_ref_make_strdup(".")))
310 1 : goto fail_deci;
311 :
312 6266 : if (!(conf->loc->null_ref = vstr_ref_make_strdup("(null)")))
313 1 : goto fail_null;
314 :
315 6265 : conf->loc->name_lc_numeric_len = 1;
316 6265 : conf->loc->num_beg->thousands_sep_len = 0;
317 6265 : conf->loc->num_beg->decimal_point_len = 1;
318 6265 : conf->loc->null_len = strlen("(null)");
319 :
320 6265 : return (TRUE);
321 :
322 : /* vstr_ref_del(conf->loc->null_ref); */
323 : fail_null:
324 1 : vstr_ref_del(conf->loc->num_beg->decimal_point_ref);
325 : fail_deci:
326 2 : vstr_ref_del(conf->loc->num_beg->thousands_sep_ref);
327 2 : vstr_ref_del(conf->loc->num_beg->grouping);
328 : fail_grp:
329 3 : vstr_ref_del(conf->loc->name_lc_numeric_ref);
330 : fail_numeric:
331 :
332 4 : return (FALSE);
333 : }
334 :
335 : int vstr__make_conf_loc_numeric(Vstr_conf *conf, const char *name)
336 1035 : {
337 1035 : struct lconv *sys_loc = NULL;
338 1035 : const char *tmp = NULL;
339 1035 : Vstr_locale loc[1];
340 1035 : Vstr_locale_num_base num_beg[1];
341 :
342 1035 : ASSERT(conf);
343 1035 : ASSERT(conf->loc);
344 1035 : ASSERT(conf->loc->num_beg);
345 :
346 1035 : loc->num_beg = num_beg;
347 :
348 1035 : if (name)
349 1035 : tmp = setlocale(LC_NUMERIC, name);
350 :
351 1035 : if (!(sys_loc = localeconv()))
352 224 : return (FALSE);
353 : else
354 : {
355 1035 : const char *name_numeric = NULL;
356 1035 : size_t numeric_len = 0;
357 1035 : size_t grp_len = vstr__loc_thou_grp_strlen(SYS_LOC(grouping));
358 1035 : size_t thou_len = strlen(SYS_LOC(thousands_sep));
359 1035 : size_t deci_len = strlen(SYS_LOC(decimal_point));
360 1035 : Vstr_ref *ref = NULL;
361 :
362 1035 : if (VSTR__DEBUG_MALLOC_TST() ||
363 : !(name_numeric = setlocale(LC_NUMERIC, NULL))) /* name for "name" */
364 355 : name_numeric = "C";
365 1035 : numeric_len = strlen(name_numeric);
366 :
367 1035 : if (!(ref = vstr_ref_make_strdup(name_numeric)))
368 225 : goto fail_numeric;
369 1034 : loc->name_lc_numeric_ref = ref;
370 :
371 :
372 1034 : if (!(ref = vstr_ref_make_malloc(grp_len + 1)))
373 225 : goto fail_grp;
374 1033 : loc->num_beg->grouping = ref;
375 :
376 1033 : if (!(ref = vstr_ref_make_strdup(SYS_LOC(thousands_sep))))
377 225 : goto fail_thou;
378 1032 : loc->num_beg->thousands_sep_ref = ref;
379 :
380 1032 : if (!(ref = vstr_ref_make_strdup(SYS_LOC(decimal_point))))
381 225 : goto fail_deci;
382 1031 : loc->num_beg->decimal_point_ref = ref;
383 :
384 1031 : loc->name_lc_numeric_len = numeric_len;
385 :
386 : /* Grouping is different we have to make sure it is 0 terminated */
387 1031 : if (grp_len)
388 1031 : vstr_wrap_memcpy(loc->num_beg->grouping->ptr, SYS_LOC(grouping), grp_len);
389 1031 : ((char *)loc->num_beg->grouping->ptr)[grp_len] = 0;
390 :
391 1031 : loc->num_beg->thousands_sep_len = thou_len;
392 1031 : loc->num_beg->decimal_point_len = deci_len;
393 : }
394 :
395 1043 : while (TRUE)
396 : {
397 1043 : Vstr_locale_num_base *next = conf->loc->num_beg->next;
398 :
399 1043 : vstr_ref_del(conf->loc->num_beg->grouping);
400 1043 : vstr_ref_del(conf->loc->num_beg->thousands_sep_ref);
401 1043 : vstr_ref_del(conf->loc->num_beg->decimal_point_ref);
402 :
403 1043 : if (!next)
404 1031 : break;
405 :
406 236 : VSTR__F(conf->loc->num_beg);
407 236 : conf->loc->num_beg = next;
408 : }
409 :
410 1031 : vstr_ref_del(conf->loc->name_lc_numeric_ref);
411 1031 : conf->loc->name_lc_numeric_ref = loc->name_lc_numeric_ref;
412 1031 : conf->loc->name_lc_numeric_len = loc->name_lc_numeric_len;
413 :
414 1031 : conf->loc->num_beg->num_base = 0;
415 1031 : conf->loc->num_beg->grouping = loc->num_beg->grouping;
416 :
417 1031 : conf->loc->num_beg->thousands_sep_ref = loc->num_beg->thousands_sep_ref;
418 1031 : conf->loc->num_beg->thousands_sep_len = loc->num_beg->thousands_sep_len;
419 :
420 1031 : conf->loc->num_beg->decimal_point_ref = loc->num_beg->decimal_point_ref;
421 1031 : conf->loc->num_beg->decimal_point_len = loc->num_beg->decimal_point_len;
422 :
423 1031 : if (tmp)
424 1031 : setlocale(LC_NUMERIC, tmp);
425 :
426 1031 : return (TRUE);
427 :
428 : fail_deci:
429 225 : vstr_ref_del(loc->num_beg->thousands_sep_ref);
430 : fail_thou:
431 226 : vstr_ref_del(loc->num_beg->grouping);
432 : fail_grp:
433 227 : vstr_ref_del(loc->name_lc_numeric_ref);
434 : fail_numeric:
435 :
436 228 : if (tmp)
437 228 : setlocale(LC_NUMERIC, tmp);
438 :
439 228 : return (FALSE);
440 : }
441 :
442 : Vstr_conf *vstr_make_conf(void)
443 6275 : {
444 6275 : Vstr_conf *conf = VSTR__MK(sizeof(Vstr_conf));
445 :
446 6275 : if (!conf)
447 2 : goto fail_conf;
448 :
449 6273 : if (!vstr__cache_conf_init(conf))
450 1 : goto fail_cache;
451 :
452 6272 : if (!vstr__data_conf_init(conf))
453 1 : goto fail_data;
454 :
455 6271 : if (!(conf->loc = VSTR__MK(sizeof(Vstr_locale))))
456 1 : goto fail_loc;
457 :
458 6270 : if (!(conf->loc->num_beg = VSTR__MK(sizeof(Vstr_locale_num_base))))
459 1 : goto fail_loc_num;
460 :
461 6269 : if (!vstr__make_conf_loc_def_numeric(conf))
462 4 : goto fail_numeric;
463 :
464 6265 : conf->spare_buf_num = 0;
465 6265 : conf->spare_buf_beg = NULL;
466 :
467 6265 : conf->spare_non_num = 0;
468 6265 : conf->spare_non_beg = NULL;
469 :
470 6265 : conf->spare_ptr_num = 0;
471 6265 : conf->spare_ptr_beg = NULL;
472 :
473 6265 : conf->spare_ref_num = 0;
474 6265 : conf->spare_ref_beg = NULL;
475 :
476 6265 : conf->iov_min_alloc = 0;
477 6265 : conf->iov_min_offset = 0;
478 :
479 6265 : conf->buf_sz = 64 - (sizeof(Vstr_node_buf) + 8);
480 :
481 6265 : conf->fmt_usr_names = 0;
482 6265 : conf->fmt_usr_escape = 0;
483 :
484 6265 : conf->vstr__fmt_spec_make = NULL;
485 6265 : conf->vstr__fmt_spec_list_beg = NULL;
486 6265 : conf->vstr__fmt_spec_list_end = NULL;
487 :
488 6265 : conf->ref = 1;
489 :
490 6265 : conf->ref_link = NULL;
491 :
492 6265 : conf->ref_grp_ptr = NULL;
493 6265 : conf->ref_grp_buf2ref = NULL;
494 :
495 6265 : conf->free_do = TRUE;
496 6265 : conf->malloc_bad = FALSE;
497 6265 : conf->iovec_auto_update = TRUE;
498 6265 : conf->split_buf_del = FALSE;
499 :
500 6265 : conf->user_ref = 1;
501 :
502 6265 : conf->no_cache = FALSE;
503 6265 : conf->fmt_usr_curly_braces = TRUE;
504 6265 : conf->atomic_ops = TRUE;
505 :
506 6265 : conf->grpalloc_cache = VSTR_TYPE_CNTL_CONF_GRPALLOC_POS;
507 :
508 6265 : conf->spare_base_num = 0;
509 6265 : conf->spare_base_beg = NULL;
510 :
511 6265 : return (conf);
512 :
513 : fail_numeric:
514 4 : VSTR__F(conf->loc->num_beg);
515 : fail_loc_num:
516 5 : VSTR__F(conf->loc);
517 : fail_loc:
518 6 : VSTR__F(conf->data_usr_ents);
519 : fail_data:
520 7 : VSTR__F(conf->cache_cbs_ents);
521 : fail_cache:
522 8 : VSTR__F(conf);
523 : fail_conf:
524 :
525 10 : return (NULL);
526 : }
527 :
528 : static void vstr__add_conf(Vstr_conf *conf)
529 23293 : {
530 23293 : ++conf->ref;
531 : }
532 :
533 : void vstr__add_user_conf(Vstr_conf *conf)
534 45 : {
535 45 : assert(conf);
536 45 : assert(conf->user_ref <= conf->ref);
537 :
538 45 : ++conf->user_ref;
539 :
540 45 : vstr__add_conf(conf);
541 : }
542 :
543 : /* NOTE: magic also exists in vstr_add..c (vstr__convert_buf_ref_add)
544 : * for linked references */
545 :
546 : void vstr__add_base_conf(Vstr_base *base, Vstr_conf *conf)
547 23248 : {
548 23248 : assert(conf->user_ref <= conf->ref);
549 :
550 23248 : base->conf = conf;
551 23248 : vstr__add_conf(conf);
552 : }
553 :
554 : void vstr__del_grpalloc(Vstr_conf *conf, unsigned int num)
555 7419 : {
556 7419 : Vstr_base *scan = conf->spare_base_beg;
557 :
558 13579 : ASSERT(vstr__check_spare_base(conf));
559 :
560 15107 : while (scan && num)
561 : { /* FIXME: ... BIG HACK */
562 7688 : conf->spare_base_beg = (Vstr_base *)scan->beg;
563 :
564 7688 : if (scan->cache_available)
565 : {
566 6658 : if (VSTR__CACHE(scan)->vec)
567 : {
568 267 : VSTR__F(VSTR__CACHE(scan)->vec->v);
569 267 : VSTR__F(VSTR__CACHE(scan)->vec->t);
570 : }
571 6658 : VSTR__F(VSTR__CACHE(scan));
572 : }
573 7688 : VSTR__F(scan);
574 :
575 7688 : --conf->spare_base_num;
576 7688 : --num;
577 :
578 7688 : scan = conf->spare_base_beg;
579 : }
580 :
581 7419 : ASSERT(vstr__check_spare_base(conf));
582 : }
583 :
584 : void vstr__del_conf(Vstr_conf *conf)
585 32030 : {
586 32030 : assert(conf->ref > 0);
587 :
588 32030 : if (!--conf->ref)
589 : {
590 6057 : ASSERT(!conf->ref_link);
591 :
592 6057 : vstr__ref_grp_free(conf->ref_grp_ptr);
593 6057 : vstr__ref_grp_free(conf->ref_grp_buf2ref);
594 :
595 6057 : vstr_free_spare_nodes(conf, VSTR_TYPE_NODE_BUF, conf->spare_buf_num);
596 6057 : vstr_free_spare_nodes(conf, VSTR_TYPE_NODE_NON, conf->spare_non_num);
597 6057 : vstr_free_spare_nodes(conf, VSTR_TYPE_NODE_PTR, conf->spare_ptr_num);
598 6057 : vstr_free_spare_nodes(conf, VSTR_TYPE_NODE_REF, conf->spare_ref_num);
599 :
600 6057 : VSTR__DEBUG_MALLOC_CHECK_MEM(conf->loc->name_lc_numeric_ref);
601 6057 : vstr_ref_del(conf->loc->name_lc_numeric_ref);
602 :
603 12142 : while (conf->loc->num_beg)
604 : {
605 6085 : Vstr_locale_num_base *next = conf->loc->num_beg->next;
606 :
607 6085 : VSTR__DEBUG_MALLOC_CHECK_MEM(conf->loc->num_beg);
608 :
609 6085 : vstr_ref_del(conf->loc->num_beg->grouping);
610 6085 : vstr_ref_del(conf->loc->num_beg->thousands_sep_ref);
611 6085 : vstr_ref_del(conf->loc->num_beg->decimal_point_ref);
612 :
613 6085 : VSTR__F(conf->loc->num_beg);
614 6085 : conf->loc->num_beg = next;
615 : }
616 :
617 6057 : vstr_ref_del(conf->loc->null_ref);
618 :
619 6057 : VSTR__F(conf->loc);
620 :
621 6057 : vstr__data_conf_free(conf);
622 :
623 6057 : VSTR__F(conf->cache_cbs_ents);
624 :
625 6057 : vstr__add_fmt_free_conf(conf);
626 :
627 6057 : vstr__del_grpalloc(conf, conf->spare_base_num);
628 :
629 6057 : if (conf->free_do)
630 6057 : VSTR__F(conf);
631 : }
632 : }
633 :
634 : int vstr_swap_conf(Vstr_base *base, Vstr_conf **conf)
635 46 : {
636 46 : int can_change_conf = FALSE;
637 :
638 46 : assert(conf && *conf);
639 46 : assert((*conf)->user_ref > 0);
640 46 : assert((*conf)->user_ref <= (*conf)->ref);
641 :
642 46 : if (base->conf == *conf)
643 5 : return (TRUE);
644 :
645 : /* there are base string object using this configuration,
646 : * so we can't change it */
647 41 : if ((*conf)->user_ref == (*conf)->ref)
648 31 : can_change_conf = TRUE;
649 :
650 41 : if (base->conf->buf_sz != (*conf)->buf_sz)
651 : {
652 15 : if (!can_change_conf)
653 5 : return (FALSE);
654 :
655 10 : vstr_free_spare_nodes(*conf, VSTR_TYPE_NODE_BUF, (*conf)->spare_buf_num);
656 10 : (*conf)->buf_sz = base->conf->buf_sz;
657 : }
658 :
659 36 : if (!vstr__cache_subset_cbs(base->conf, *conf))
660 : {
661 16 : if (!can_change_conf)
662 5 : return (FALSE);
663 :
664 11 : if (!vstr__cache_dup_cbs(*conf, base->conf))
665 1 : return (FALSE);
666 : }
667 :
668 30 : --(*conf)->user_ref;
669 30 : ++base->conf->user_ref;
670 :
671 30 : SWAP_TYPE(*conf, base->conf, Vstr_conf *);
672 :
673 30 : return (TRUE);
674 : }
675 :
676 : void vstr_free_conf(Vstr_conf *conf)
677 6170 : {
678 6170 : if (!conf)
679 5 : return;
680 :
681 6165 : assert(conf->user_ref > 0);
682 6165 : assert(conf->user_ref <= conf->ref);
683 :
684 6165 : --conf->user_ref;
685 :
686 6165 : vstr__del_conf(conf);
687 : }
688 :
689 : int vstr_init(void)
690 3007 : {
691 3007 : if (!vstr__options.def)
692 : {
693 3007 : vstr__options.mmap_count = 0;
694 :
695 3007 : vstr__options.fd_count = 0;
696 :
697 3007 : vstr__options.mem_sz = 0;
698 3007 : vstr__options.mem_num = 0;
699 3007 : vstr__options.mem_vals = NULL;
700 :
701 : /* NOTE: don't set fail nums */
702 :
703 3007 : if (!(vstr__options.def = vstr_make_conf()))
704 1 : return (FALSE);
705 : }
706 :
707 3006 : return (TRUE);
708 : }
709 :
710 : void vstr_exit(void)
711 2925 : {
712 2925 : ASSERT((vstr__options.def->user_ref == 1) &&
713 : (vstr__options.def->ref == 1));
714 :
715 2925 : vstr_free_conf(vstr__options.def);
716 2925 : vstr__options.def = NULL;
717 :
718 607 : ASSERT(!vstr__options.mmap_count);
719 607 : ASSERT(!vstr__options.fd_count);
720 :
721 607 : VSTR__DEBUG_MALLOC_CHECK_EMPTY();
722 : }
723 :
724 : int vstr__cache_iovec_valid(Vstr_base *base)
725 167655 : {
726 167655 : unsigned int count = 0;
727 167655 : Vstr_node *scan = NULL;
728 :
729 167655 : if (base->iovec_upto_date)
730 131776 : return (TRUE);
731 :
732 35879 : if (!base->beg)
733 : {
734 1897 : if (base->cache_available && VSTR__CACHE(base) && VSTR__CACHE(base)->vec &&
735 : VSTR__CACHE(base)->vec->sz)
736 1897 : base->iovec_upto_date = TRUE;
737 :
738 1897 : return (TRUE);
739 : }
740 :
741 33982 : if (!vstr__cache_iovec_alloc(base, base->num))
742 80 : return (FALSE);
743 :
744 33902 : assert(VSTR__CACHE(base)->vec->off == base->conf->iov_min_offset);
745 :
746 33902 : count = base->conf->iov_min_offset;
747 33902 : scan = base->beg;
748 :
749 33902 : VSTR__CACHE(base)->vec->v[count].iov_len = scan->len - base->used;
750 33902 : if (scan->type == VSTR_TYPE_NODE_NON)
751 9 : VSTR__CACHE(base)->vec->v[count].iov_base = NULL;
752 : else
753 33893 : VSTR__CACHE(base)->vec->v[count].iov_base = (vstr_export__node_ptr(scan) +
754 : base->used);
755 33902 : VSTR__CACHE(base)->vec->t[count] = scan->type;
756 :
757 33902 : scan = scan->next;
758 33902 : ++count;
759 483969 : while (scan)
760 : {
761 450067 : VSTR__CACHE(base)->vec->t[count] = scan->type;
762 450067 : VSTR__CACHE(base)->vec->v[count].iov_len = scan->len;
763 450067 : VSTR__CACHE(base)->vec->v[count].iov_base = vstr_export__node_ptr(scan);
764 :
765 450067 : ++count;
766 450067 : scan = scan->next;
767 : }
768 :
769 33902 : base->iovec_upto_date = TRUE;
770 :
771 33902 : return (TRUE);
772 : }
773 :
774 : static void vstr__init_base(Vstr_conf *conf, Vstr_base *base)
775 23233 : {
776 23233 : base->beg = NULL;
777 23233 : base->end = NULL;
778 :
779 23233 : base->len = 0;
780 23233 : base->num = 0;
781 :
782 23233 : vstr__add_base_conf(base, conf);
783 :
784 23233 : base->used = 0;
785 23233 : base->free_do = FALSE;
786 23233 : base->iovec_upto_date = FALSE;
787 :
788 23233 : base->node_buf_used = FALSE;
789 23233 : base->node_non_used = FALSE;
790 23233 : base->node_ptr_used = FALSE;
791 23233 : base->node_ref_used = FALSE;
792 :
793 23233 : if (base->cache_available &&
794 : (base->grpalloc_cache >= VSTR_TYPE_CNTL_CONF_GRPALLOC_IOVEC))
795 : {
796 13036 : VSTR__CACHE(base)->vec->off = base->conf->iov_min_offset;
797 13036 : base->iovec_upto_date = TRUE;
798 : }
799 : }
800 :
801 : void vstr_free_base(Vstr_base *base)
802 24107 : {
803 24107 : Vstr_conf *conf = NULL;
804 :
805 24107 : if (!base)
806 1050 : return;
807 :
808 23057 : conf = base->conf;
809 :
810 23057 : ASSERT(vstr__check_spare_base(conf));
811 :
812 23057 : vstr__free_cache(base);
813 :
814 23057 : vstr_del(base, 1, base->len);
815 :
816 23057 : if (base->free_do)
817 : {
818 23057 : if (base->grpalloc_cache == base->conf->grpalloc_cache)
819 : { /* FIXME: massive hack */
820 23022 : base->beg = (Vstr_node *)base->conf->spare_base_beg;
821 23022 : base->conf->spare_base_beg = base;
822 23022 : ++base->conf->spare_base_num;
823 : }
824 : else
825 : {
826 35 : if (base->cache_available)
827 : {
828 25 : if (VSTR__CACHE(base)->vec)
829 : {
830 5 : VSTR__F(VSTR__CACHE(base)->vec->v);
831 5 : VSTR__F(VSTR__CACHE(base)->vec->t);
832 : }
833 25 : VSTR__F(VSTR__CACHE(base));
834 : }
835 35 : VSTR__F(base);
836 : }
837 : }
838 :
839 23057 : ASSERT(vstr__check_spare_base(conf));
840 :
841 23057 : vstr__del_conf(conf);
842 : }
843 :
844 : static Vstr_base *vstr__make_base_cache(Vstr_conf *conf)
845 8196 : {
846 8196 : Vstr_base *base = NULL;
847 8196 : size_t sz = 0;
848 8196 : unsigned int num = 0;
849 8196 : Vstr__cache *cache = NULL;
850 :
851 8196 : switch (conf->grpalloc_cache)
852 : {
853 : case VSTR_TYPE_CNTL_CONF_GRPALLOC_NONE:
854 1061 : num = 0; sz = sizeof(struct Vstr_base); break;
855 : case VSTR_TYPE_CNTL_CONF_GRPALLOC_POS:
856 6826 : num = 1; sz = sizeof(struct Vstr__base_p_cache); break;
857 : case VSTR_TYPE_CNTL_CONF_GRPALLOC_IOVEC:
858 41 : num = 2; sz = sizeof(struct Vstr__base_pi_cache); break;
859 : case VSTR_TYPE_CNTL_CONF_GRPALLOC_CSTR:
860 268 : num = 3; sz = sizeof(struct Vstr__base_pic_cache);
861 :
862 71 : ASSERT_NO_SWITCH_DEF();
863 : }
864 :
865 8196 : if (!(base = VSTR__MK(sz)))
866 148 : goto malloc_fail_base;
867 :
868 8048 : base->grpalloc_cache = conf->grpalloc_cache;
869 :
870 8048 : base->cache_internal = TRUE;
871 :
872 : /* allocate cache pointers */
873 8048 : if (!num)
874 : {
875 1061 : base->cache_available = FALSE;
876 1061 : ASSERT(conf->no_cache);
877 1061 : return (base);
878 : }
879 :
880 6987 : if (!(cache = VSTR__MK(sizeof(Vstr__cache) + (sizeof(void *) * num))))
881 147 : goto malloc_fail_cache;
882 :
883 6840 : cache->sz = num;
884 6840 : cache->vec = NULL;
885 :
886 6840 : vstr_wrap_memset(cache->data, 0, sizeof(void *) * num);
887 :
888 6840 : VSTR__CACHE(base) = cache;
889 6840 : base->cache_available = TRUE;
890 :
891 : /* NOTE: hand init/allocate empty data for each cache type,
892 : * this should really be in vstr_cache.c ... */
893 6840 : switch (conf->grpalloc_cache)
894 : {
895 : case VSTR_TYPE_CNTL_CONF_GRPALLOC_CSTR:
896 : {
897 265 : struct Vstr__base_pic_cache *ubase = (struct Vstr__base_pic_cache *)base;
898 265 : Vstr__cache_data_cstr *data = &ubase->real_cstr;
899 :
900 265 : data->ref = NULL;
901 265 : vstr_cache_set(base, 3, data);
902 297 : ASSERT(vstr_cache_get(base, 3) == data);
903 : }
904 297 : ASSERT(cache->sz >= 3);
905 : /* FALLTHOUGH */
906 :
907 : case VSTR_TYPE_CNTL_CONF_GRPALLOC_IOVEC:
908 : {
909 306 : struct Vstr__base_pi_cache *ubase = (struct Vstr__base_pi_cache *)base;
910 306 : Vstr__cache_data_iovec *data = &ubase->real_iov;
911 306 : size_t alloc_sz = 1 + conf->iov_min_alloc + conf->iov_min_offset;
912 :
913 306 : VSTR__CACHE(base)->vec = data;
914 :
915 306 : data->v = VSTR__MK(sizeof(struct iovec) * alloc_sz);
916 306 : data->t = NULL;
917 306 : data->off = conf->iov_min_offset;
918 306 : data->sz = 0;
919 :
920 306 : if (!data->v)
921 1 : goto malloc_fail_vec_v;
922 :
923 305 : assert(!data->t);
924 305 : data->t = VSTR__MK(alloc_sz);
925 :
926 305 : if (!data->t)
927 1 : goto malloc_fail_vec_t;
928 :
929 304 : data->sz = alloc_sz;
930 5484 : assert(!data->off);
931 :
932 : /* this is left NULL so that we don't call the cb */
933 5484 : ASSERT(vstr_cache_get(base, 2) == NULL);
934 : }
935 5484 : ASSERT(cache->sz >= 2);
936 : /* FALLTHOUGH */
937 :
938 : case VSTR_TYPE_CNTL_CONF_GRPALLOC_POS:
939 : {
940 6838 : struct Vstr__base_p_cache *ubase = (struct Vstr__base_p_cache *)base;
941 6838 : Vstr__cache_data_pos *data = &ubase->real_pos;
942 :
943 6838 : data->node = NULL;
944 :
945 6838 : vstr_cache_set(base, 1, data);
946 1429 : ASSERT(vstr_cache_get(base, 1) == data);
947 : }
948 1429 : ASSERT(cache->sz >= 1);
949 0 : ASSERT_NO_SWITCH_DEF();
950 : }
951 :
952 6838 : return (base);
953 :
954 : malloc_fail_vec_t:
955 1 : VSTR__F(VSTR__CACHE(base)->vec->v);
956 : malloc_fail_vec_v:
957 2 : VSTR__F(VSTR__CACHE(base));
958 : malloc_fail_cache:
959 149 : VSTR__F(base);
960 : malloc_fail_base:
961 297 : return (NULL);
962 : }
963 :
964 : Vstr_base *vstr_make_base(Vstr_conf *conf)
965 23530 : {
966 23530 : Vstr_base *base = NULL;
967 :
968 23530 : if (!conf)
969 18660 : conf = vstr__options.def;
970 :
971 23530 : ASSERT(vstr__check_spare_nodes(conf));
972 23530 : ASSERT(vstr__check_spare_base(conf));
973 :
974 23530 : if (conf->spare_base_num)
975 : {
976 15334 : Vstr__cache *cache = NULL;
977 :
978 15334 : base = conf->spare_base_beg;
979 15334 : conf->spare_base_beg = (Vstr_base *)base->beg;
980 15334 : --conf->spare_base_num;
981 :
982 15334 : ASSERT(base->grpalloc_cache == conf->grpalloc_cache);
983 :
984 15334 : ASSERT(base->cache_internal);
985 :
986 15334 : cache = VSTR__CACHE(base);
987 15334 : if (base->grpalloc_cache != VSTR_TYPE_CNTL_CONF_GRPALLOC_NONE)
988 15328 : VSTR__DEBUG_MALLOC_CHECK_MEM(cache);
989 :
990 15334 : switch (conf->grpalloc_cache)
991 : {
992 : case VSTR_TYPE_CNTL_CONF_GRPALLOC_CSTR:
993 : {
994 12408 : struct Vstr__base_pic_cache *ubase = (struct Vstr__base_pic_cache *)base;
995 12408 : Vstr__cache_data_cstr *data = &ubase->real_cstr;
996 :
997 12408 : data->ref = NULL;
998 12408 : vstr_cache_set(base, 3, data);
999 14436 : ASSERT(vstr_cache_get(base, 3) == data);
1000 : }
1001 14436 : ASSERT(cache->sz >= 3);
1002 : /* FALLTHOUGH */
1003 :
1004 : case VSTR_TYPE_CNTL_CONF_GRPALLOC_IOVEC:
1005 : /* this is left NULL so that we don't call the cb */
1006 14516 : ASSERT(vstr_cache_get(base, 2) == NULL);
1007 14516 : ASSERT(cache->sz >= 2);
1008 : /* FALLTHOUGH */
1009 :
1010 : case VSTR_TYPE_CNTL_CONF_GRPALLOC_POS:
1011 : {
1012 15305 : struct Vstr__base_p_cache *ubase = (struct Vstr__base_p_cache *)base;
1013 15305 : Vstr__cache_data_pos *data = &ubase->real_pos;
1014 :
1015 15305 : data->node = NULL;
1016 :
1017 15305 : vstr_cache_set(base, 1, data);
1018 15305 : ASSERT(vstr_cache_get(base, 1) == data);
1019 : }
1020 15305 : ASSERT(cache->sz >= 1);
1021 : /* FALLTHOUGH */
1022 :
1023 : case VSTR_TYPE_CNTL_CONF_GRPALLOC_NONE:
1024 :
1025 12007 : ASSERT_NO_SWITCH_DEF();
1026 : }
1027 : }
1028 8196 : else if (!(base = vstr__make_base_cache(conf)))
1029 297 : goto malloc_fail_base;
1030 :
1031 23233 : vstr__init_base(conf, base);
1032 :
1033 23233 : base->free_do = TRUE;
1034 :
1035 23233 : ASSERT(base->conf == conf);
1036 23233 : ASSERT(vstr__check_spare_nodes(conf));
1037 23233 : ASSERT(vstr__check_real_nodes(base));
1038 23233 : ASSERT(vstr__check_spare_base(conf));
1039 :
1040 23233 : return (base);
1041 :
1042 : malloc_fail_base:
1043 297 : conf->malloc_bad = TRUE;
1044 297 : return (NULL);
1045 : }
1046 :
1047 : Vstr_node *vstr__base_split_node(Vstr_base *base, Vstr_node *node, size_t pos)
1048 3813 : {
1049 3813 : Vstr_node *beg = NULL;
1050 :
1051 3813 : assert(base && pos && (pos <= node->len));
1052 :
1053 3813 : switch (node->type)
1054 : {
1055 : case VSTR_TYPE_NODE_BUF:
1056 2478 : if (!vstr_cntl_conf(base->conf,
1057 : VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_BUF, 1, UINT_MAX))
1058 35 : return (NULL);
1059 :
1060 2443 : --base->conf->spare_buf_num;
1061 2443 : beg = (Vstr_node *)base->conf->spare_buf_beg;
1062 2443 : base->conf->spare_buf_beg = (Vstr_node_buf *)beg->next;
1063 :
1064 2443 : vstr_wrap_memcpy(((Vstr_node_buf *)beg)->buf,
1065 : ((Vstr_node_buf *)node)->buf + pos, node->len - pos);
1066 :
1067 : /* poison the split */
1068 2443 : ASSERT(vstr_wrap_memset(((Vstr_node_buf *)node)->buf + pos, 0xFE,
1069 : node->len - pos));
1070 1971 : break;
1071 :
1072 : case VSTR_TYPE_NODE_NON:
1073 27 : if (!vstr_cntl_conf(base->conf,
1074 : VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_NON, 1, UINT_MAX))
1075 3 : return (NULL);
1076 :
1077 24 : --base->conf->spare_non_num;
1078 24 : beg = (Vstr_node *)base->conf->spare_non_beg;
1079 24 : base->conf->spare_non_beg = (Vstr_node_non *)beg->next;
1080 24 : break;
1081 :
1082 : case VSTR_TYPE_NODE_PTR:
1083 878 : if (!vstr_cntl_conf(base->conf,
1084 : VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_PTR, 1, UINT_MAX))
1085 43 : return (NULL);
1086 :
1087 835 : --base->conf->spare_ptr_num;
1088 835 : beg = (Vstr_node *)base->conf->spare_ptr_beg;
1089 835 : base->conf->spare_ptr_beg = (Vstr_node_ptr *)beg->next;
1090 :
1091 835 : ((Vstr_node_ptr *)beg)->ptr = ((char *)((Vstr_node_ptr *)node)->ptr) + pos;
1092 835 : break;
1093 :
1094 : case VSTR_TYPE_NODE_REF:
1095 : {
1096 430 : Vstr_ref *ref = NULL;
1097 :
1098 430 : if (!vstr_cntl_conf(base->conf,
1099 : VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_REF, 1, UINT_MAX))
1100 5 : return (NULL);
1101 :
1102 425 : --base->conf->spare_ref_num;
1103 425 : beg = (Vstr_node *)base->conf->spare_ref_beg;
1104 425 : base->conf->spare_ref_beg = (Vstr_node_ref *)beg->next;
1105 :
1106 425 : ref = ((Vstr_node_ref *)node)->ref;
1107 425 : ((Vstr_node_ref *)beg)->ref = vstr_ref_add(ref);
1108 425 : ((Vstr_node_ref *)beg)->off = ((Vstr_node_ref *)node)->off + pos;
1109 : }
1110 :
1111 97 : ASSERT_NO_SWITCH_DEF();
1112 : }
1113 :
1114 3727 : ++base->num;
1115 :
1116 3727 : base->iovec_upto_date = FALSE;
1117 :
1118 3727 : beg->len = node->len - pos;
1119 :
1120 3727 : if (!(beg->next = node->next))
1121 3120 : base->end = beg;
1122 3727 : node->next = beg;
1123 :
1124 3727 : node->len = pos;
1125 :
1126 3727 : return (node);
1127 : }
1128 :
1129 : static int vstr__make_spare_node(Vstr_conf *conf, unsigned int type)
1130 733200 : {
1131 733200 : Vstr_node *node = NULL;
1132 :
1133 733200 : switch (type)
1134 : {
1135 : case VSTR_TYPE_NODE_BUF:
1136 515437 : node = VSTR__MK(sizeof(Vstr_node_buf) + conf->buf_sz);
1137 515437 : break;
1138 : case VSTR_TYPE_NODE_NON:
1139 1949 : node = VSTR__MK(sizeof(Vstr_node_non));
1140 1949 : break;
1141 : case VSTR_TYPE_NODE_PTR:
1142 129236 : node = VSTR__MK(sizeof(Vstr_node_ptr));
1143 129236 : break;
1144 : case VSTR_TYPE_NODE_REF:
1145 86574 : node = VSTR__MK(sizeof(Vstr_node_ref));
1146 86574 : break;
1147 :
1148 : default:
1149 4 : ASSERT_RET(FALSE, FALSE);
1150 : }
1151 :
1152 733196 : if (!node)
1153 : {
1154 32753 : conf->malloc_bad = TRUE;
1155 32753 : return (FALSE);
1156 : }
1157 :
1158 700443 : node->len = 0;
1159 700443 : node->type = type;
1160 :
1161 700443 : switch (type)
1162 : {
1163 : case VSTR_TYPE_NODE_BUF:
1164 483261 : node->next = (Vstr_node *)conf->spare_buf_beg;
1165 483261 : conf->spare_buf_beg = (Vstr_node_buf *)node;
1166 483261 : ++conf->spare_buf_num;
1167 483261 : break;
1168 :
1169 : case VSTR_TYPE_NODE_NON:
1170 1917 : node->next = (Vstr_node *)conf->spare_non_beg;
1171 1917 : conf->spare_non_beg = (Vstr_node_non *)node;
1172 1917 : ++conf->spare_non_num;
1173 1917 : break;
1174 :
1175 : case VSTR_TYPE_NODE_PTR:
1176 128868 : node->next = (Vstr_node *)conf->spare_ptr_beg;
1177 128868 : conf->spare_ptr_beg = (Vstr_node_ptr *)node;
1178 128868 : ++conf->spare_ptr_num;
1179 128868 : break;
1180 :
1181 : case VSTR_TYPE_NODE_REF:
1182 86397 : node->next = (Vstr_node *)conf->spare_ref_beg;
1183 86397 : conf->spare_ref_beg = (Vstr_node_ref *)node;
1184 86397 : ++conf->spare_ref_num;
1185 : break;
1186 : }
1187 :
1188 700443 : return (TRUE);
1189 : }
1190 :
1191 : unsigned int vstr_make_spare_nodes(Vstr_conf *passed_conf, unsigned int type,
1192 : unsigned int num)
1193 351795 : {
1194 351795 : Vstr_conf *conf = passed_conf ? passed_conf : vstr__options.def;
1195 351795 : unsigned int count = 0;
1196 :
1197 772331 : assert(vstr__check_spare_nodes(conf));
1198 :
1199 1052238 : while (count < num)
1200 : {
1201 733200 : if (!vstr__make_spare_node(conf, type))
1202 : {
1203 32757 : assert(vstr__check_spare_nodes(conf));
1204 :
1205 32757 : return (count);
1206 : }
1207 :
1208 700443 : ++count;
1209 : }
1210 319038 : assert(count == num);
1211 :
1212 319038 : assert(vstr__check_spare_nodes(conf));
1213 :
1214 319038 : return (count);
1215 : }
1216 :
1217 : static int vstr__free_spare_node(Vstr_conf *conf, unsigned int type)
1218 765365 : {
1219 765365 : Vstr_node *scan = NULL;
1220 :
1221 765365 : switch (type)
1222 : {
1223 : case VSTR_TYPE_NODE_BUF:
1224 553435 : if (!conf->spare_buf_beg)
1225 80382 : return (FALSE);
1226 :
1227 473053 : scan = (Vstr_node *)conf->spare_buf_beg;
1228 :
1229 473053 : assert(scan->type == type);
1230 :
1231 473053 : conf->spare_buf_beg = (Vstr_node_buf *)scan->next;
1232 473053 : --conf->spare_buf_num;
1233 473053 : VSTR__F(scan);
1234 473053 : break;
1235 :
1236 : case VSTR_TYPE_NODE_NON:
1237 3495 : if (!conf->spare_non_beg)
1238 1578 : return (FALSE);
1239 :
1240 1917 : scan = (Vstr_node *)conf->spare_non_beg;
1241 :
1242 1917 : assert(scan->type == VSTR_TYPE_NODE_NON);
1243 :
1244 1917 : conf->spare_non_beg = (Vstr_node_non *)scan->next;
1245 1917 : --conf->spare_non_num;
1246 1917 : VSTR__F(scan);
1247 1917 : break;
1248 :
1249 : case VSTR_TYPE_NODE_PTR:
1250 125931 : if (!conf->spare_ptr_beg)
1251 2567 : return (FALSE);
1252 :
1253 123364 : scan = (Vstr_node *)conf->spare_ptr_beg;
1254 :
1255 123364 : assert(scan->type == VSTR_TYPE_NODE_PTR);
1256 :
1257 123364 : conf->spare_ptr_beg = (Vstr_node_ptr *)scan->next;
1258 123364 : --conf->spare_ptr_num;
1259 123364 : VSTR__F(scan);
1260 123364 : break;
1261 :
1262 : case VSTR_TYPE_NODE_REF:
1263 82500 : if (!conf->spare_ref_beg)
1264 1607 : return (FALSE);
1265 :
1266 80893 : scan = (Vstr_node *)conf->spare_ref_beg;
1267 :
1268 80893 : assert(scan->type == type);
1269 :
1270 80893 : conf->spare_ref_beg = (Vstr_node_ref *)scan->next;
1271 80893 : --conf->spare_ref_num;
1272 80893 : VSTR__F(scan);
1273 :
1274 21043 : ASSERT_NO_SWITCH_DEF();
1275 : }
1276 :
1277 679231 : return (TRUE);
1278 : }
1279 :
1280 : unsigned int vstr_free_spare_nodes(Vstr_conf *passed_conf, unsigned int type,
1281 : unsigned int num)
1282 110523 : {
1283 110523 : Vstr_conf *conf = passed_conf ? passed_conf : vstr__options.def;
1284 110523 : unsigned int count = 0;
1285 :
1286 515151 : assert(vstr__check_spare_nodes(conf));
1287 :
1288 789754 : while (count < num)
1289 : {
1290 765365 : if (!vstr__free_spare_node(conf, type))
1291 86134 : return (count);
1292 :
1293 679231 : ++count;
1294 : }
1295 24389 : assert(count == num);
1296 :
1297 24389 : assert(vstr__check_spare_nodes(conf));
1298 :
1299 24389 : return (count);
1300 : }
1301 :
1302 : /* vstr_base__pos() but returns a (Vstr_node **) instead of (Vstr_node *) */
1303 : Vstr_node **vstr__base_ptr_pos(const Vstr_base *base, size_t *pos,
1304 : unsigned int *num)
1305 782733 : {
1306 782733 : Vstr_node *const *scan = &base->beg;
1307 :
1308 782733 : ASSERT(base && pos && num);
1309 :
1310 782733 : *pos += base->used;
1311 782733 : *num = 1;
1312 :
1313 783135 : while (*pos > (*scan)->len)
1314 : {
1315 402 : *pos -= (*scan)->len;
1316 :
1317 402 : ASSERT((*scan)->next);
1318 402 : scan = &(*scan)->next;
1319 402 : ++*num;
1320 : }
1321 :
1322 782733 : return ((Vstr_node **) scan);
1323 : }
1324 :
1325 : struct Vstr__conf_ref_linked
1326 : {
1327 : Vstr_conf *conf;
1328 : unsigned int l_ref;
1329 : };
1330 :
1331 : /* put node on reference list */
1332 : static int vstr__convert_buf_ref_add(Vstr_conf *conf, Vstr_node *node)
1333 18207 : {
1334 18207 : struct Vstr__conf_ref_linked *ln_ref;
1335 :
1336 18207 : if (!(ln_ref = conf->ref_link))
1337 : {
1338 2802 : if (!(ln_ref = VSTR__MK(sizeof(struct Vstr__conf_ref_linked))))
1339 9 : return (FALSE);
1340 :
1341 2793 : ln_ref->conf = conf;
1342 2793 : ln_ref->l_ref = 0;
1343 :
1344 2793 : conf->ref_link = ln_ref;
1345 2793 : ++conf->ref;
1346 : }
1347 18198 : ASSERT(ln_ref->l_ref < VSTR__CONF_REF_LINKED_SZ);
1348 :
1349 18198 : ++ln_ref->l_ref;
1350 : /* this cast isn't ISO 9899:1999 compliant ... but fuck it */
1351 18198 : node->next = (Vstr_node *)ln_ref;
1352 :
1353 18198 : if (ln_ref->l_ref >= VSTR__CONF_REF_LINKED_SZ)
1354 2222 : conf->ref_link = NULL;
1355 :
1356 18198 : return (TRUE);
1357 : }
1358 :
1359 : /* call back ... relink */
1360 : static void vstr__ref_cb_relink_bufnode_ref(Vstr_ref *ref)
1361 18207 : {
1362 18207 : ASSERT(ref);
1363 :
1364 18207 : if (ref->ptr)
1365 : {
1366 18198 : char *tmp = ref->ptr;
1367 18198 : Vstr_node_buf *node = NULL;
1368 18198 : struct Vstr__conf_ref_linked *ln_ref = NULL;
1369 18198 : Vstr_conf *conf = NULL;
1370 :
1371 18198 : tmp -= offsetof(Vstr_node_buf, buf);
1372 18198 : node = (Vstr_node_buf *)tmp;
1373 18198 : ln_ref = (struct Vstr__conf_ref_linked *)(node->s.next);
1374 :
1375 18198 : conf = ln_ref->conf;
1376 :
1377 : /* manual relink ... Also ISO 9899:1999 violation */
1378 18198 : node->s.next = (Vstr_node *)ln_ref->conf->spare_buf_beg;
1379 18198 : ln_ref->conf->spare_buf_beg = node;
1380 18198 : ++ln_ref->conf->spare_buf_num;
1381 :
1382 18198 : if (!--ln_ref->l_ref)
1383 : {
1384 2793 : if (ln_ref->conf->ref_link == ln_ref)
1385 571 : ln_ref->conf->ref_link = NULL;
1386 :
1387 2793 : VSTR__F(ln_ref);
1388 2793 : vstr__del_conf(conf);
1389 : }
1390 : }
1391 : }
1392 :
1393 : void vstr__swap_node_X_X(const Vstr_base *base, size_t pos,
1394 : Vstr_node *node)
1395 30 : {
1396 30 : Vstr_node *old_scan = NULL;
1397 30 : size_t old_scan_len = 0;
1398 30 : Vstr_node **scan = NULL;
1399 30 : unsigned int num = 0;
1400 30 : Vstr__cache_data_pos *data = NULL;
1401 :
1402 30 : scan = vstr__base_ptr_pos(base, &pos, &num);
1403 :
1404 30 : old_scan = *scan;
1405 30 : old_scan_len = old_scan->len;
1406 :
1407 30 : node->next = (*scan)->next;
1408 30 : vstr__relink_nodes(base->conf, *scan, &(*scan)->next, 1);
1409 30 : *scan = node;
1410 :
1411 30 : if (!node->next)
1412 25 : ((Vstr_base *)base)->end = node;
1413 :
1414 30 : if (node == base->beg)
1415 25 : ((Vstr_base *)base)->used = 0;
1416 :
1417 30 : if ((data = vstr_cache_get(base, base->conf->cache_pos_cb_pos)) &&
1418 : (data->node == old_scan))
1419 : {
1420 5 : data->node = NULL;
1421 :
1422 5 : if (node->len >= old_scan_len)
1423 5 : data->node = node;
1424 : }
1425 :
1426 30 : switch (node->type)
1427 : {
1428 : /* -- note, should work, but not called like so currently --
1429 : case VSTR_TYPE_NODE_BUF: ((Vstr_base *)base)->node_buf_used = TRUE; break;
1430 : case VSTR_TYPE_NODE_NON: ((Vstr_base *)base)->node_non_used = TRUE; break;
1431 : */
1432 20 : case VSTR_TYPE_NODE_PTR: ((Vstr_base *)base)->node_ptr_used = TRUE; break;
1433 10 : case VSTR_TYPE_NODE_REF: ((Vstr_base *)base)->node_ref_used = TRUE;
1434 2 : ASSERT_NO_SWITCH_DEF();
1435 : }
1436 :
1437 30 : vstr__cache_iovec_reset_node(base, node, num);
1438 : }
1439 :
1440 :
1441 : int vstr__chg_node_buf_ref(const Vstr_base *base,
1442 : Vstr_node **scan, unsigned int num)
1443 18228 : {
1444 18228 : Vstr__cache_data_pos *data = NULL;
1445 18228 : Vstr_node *next_node = (*scan)->next; /* must be done now... */
1446 18228 : Vstr_ref *ref = NULL;
1447 18228 : Vstr_node_ref *node_ref = NULL;
1448 :
1449 18228 : assert((*scan)->type == VSTR_TYPE_NODE_BUF);
1450 :
1451 18228 : if (!vstr_cntl_conf(base->conf, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_REF,
1452 : 1, UINT_MAX))
1453 1 : goto fail_malloc_nodes;
1454 :
1455 18227 : if (!base->conf->ref_grp_buf2ref)
1456 : {
1457 549 : Vstr_ref_grp_ptr *tmp = NULL;
1458 :
1459 549 : if (!(tmp = vstr__ref_grp_make(vstr__ref_cb_relink_bufnode_ref, 0)))
1460 12 : goto fail_malloc_ref;
1461 537 : base->conf->ref_grp_buf2ref = tmp;
1462 : }
1463 :
1464 18215 : if (!(ref = vstr__ref_grp_add(&base->conf->ref_grp_buf2ref,
1465 : ((Vstr_node_buf *)(*scan))->buf)))
1466 8 : goto fail_malloc_ref;
1467 18207 : if (!vstr__convert_buf_ref_add(base->conf, *scan))
1468 9 : goto fail_malloc_conv_buf;
1469 :
1470 18198 : --base->conf->spare_ref_num;
1471 18198 : node_ref = base->conf->spare_ref_beg;
1472 18198 : base->conf->spare_ref_beg = (Vstr_node_ref *)node_ref->s.next;
1473 :
1474 18198 : ((Vstr_base *)base)->node_ref_used = TRUE;
1475 :
1476 18198 : node_ref->s.len = (*scan)->len;
1477 18198 : node_ref->ref = ref;
1478 18198 : node_ref->off = 0;
1479 18198 : if ((base->beg == *scan) && base->used)
1480 : {
1481 859 : node_ref->s.len -= base->used;
1482 859 : node_ref->off = base->used;
1483 859 : ((Vstr_base *)base)->used = 0;
1484 : }
1485 :
1486 18198 : if (!(node_ref->s.next = next_node))
1487 491 : ((Vstr_base *)base)->end = &node_ref->s;
1488 :
1489 : /* NOTE: we have just changed the type of the node, must update the cache */
1490 18198 : if ((data = vstr_cache_get(base, base->conf->cache_pos_cb_pos)) &&
1491 : (data->node == *scan))
1492 126 : data->node = &node_ref->s;
1493 18198 : if (base->iovec_upto_date)
1494 : {
1495 17821 : ASSERT(num);
1496 17821 : num += VSTR__CACHE(base)->vec->off - 1;
1497 17821 : assert(VSTR__CACHE(base)->vec->t[num] == VSTR_TYPE_NODE_BUF);
1498 17821 : VSTR__CACHE(base)->vec->t[num] = VSTR_TYPE_NODE_REF;
1499 : }
1500 :
1501 18198 : *scan = &node_ref->s;
1502 :
1503 18198 : return (TRUE);
1504 :
1505 : fail_malloc_conv_buf:
1506 9 : ref->ptr = NULL;
1507 9 : vstr_ref_del(ref);
1508 : fail_malloc_ref:
1509 29 : base->conf->malloc_bad = TRUE;
1510 : fail_malloc_nodes:
1511 30 : return (FALSE);
1512 : }
|