1 : #define VSTR_SC_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 : /* functions which are shortcuts */
22 :
23 : #include "main.h"
24 :
25 : int vstr_sc_fmt_cb_beg(Vstr_base *base, size_t *pos,
26 : Vstr_fmt_spec *spec, size_t *obj_len,
27 : unsigned int flags)
28 145644 : {
29 145644 : char sign = 0;
30 145644 : size_t space_len = 0;
31 145644 : size_t zero_len = 0;
32 145644 : size_t xobj_len = 0;
33 145644 : size_t quote_len = 0;
34 145644 : int num_p = FALSE;
35 :
36 145644 : if (flags & VSTR_FLAG_SC_FMT_CB_BEG_OBJ_STR)
37 : {
38 29348 : if (spec->fmt_precision && spec->fmt_field_width &&
39 : (spec->obj_field_width > spec->obj_precision))
40 5 : spec->obj_field_width = spec->obj_precision;
41 :
42 29348 : if (spec->fmt_precision && (*obj_len > spec->obj_precision))
43 20 : *obj_len = spec->obj_precision;
44 : }
45 :
46 145644 : if (!(flags & VSTR_FLAG_SC_FMT_CB_BEG_OBJ_NUM))
47 61569 : spec->fmt_zero = FALSE;
48 : else
49 : {
50 84075 : unsigned int num_base = 10;
51 :
52 84075 : num_p = TRUE;
53 :
54 84075 : if (0) { }
55 84075 : else if (flags & VSTR_FLAG02(SC_FMT_CB_BEG_OBJ, HEXNUM_L, HEXNUM_H))
56 4716 : num_base = 16;
57 79359 : else if (flags & VSTR_FLAG01(SC_FMT_CB_BEG_OBJ, OCTNUM))
58 2318 : num_base = 8;
59 77041 : else if (flags & VSTR_FLAG02(SC_FMT_CB_BEG_OBJ, BINNUM_L, BINNUM_H))
60 49761 : num_base = 2;
61 :
62 84075 : if (!spec->fmt_hash)
63 66846 : flags &= ~VSTR_FLAG05(SC_FMT_CB_BEG_OBJ,
64 : HEXNUM_L, HEXNUM_H, OCTNUM, BINNUM_L, BINNUM_H);
65 :
66 84075 : if (spec->fmt_quote) /* setup length with ',' additions properly */
67 : {
68 2884 : quote_len = vstr__add_fmt_grouping_num_sz(base, num_base, *obj_len);
69 2884 : quote_len -= *obj_len;
70 2884 : if (!quote_len) /* speed */
71 1901 : spec->fmt_quote = FALSE;
72 2884 : xobj_len += quote_len;
73 : }
74 :
75 84075 : if (flags & VSTR_FLAG_SC_FMT_CB_BEG_OBJ_NEG)
76 : {
77 1178 : sign = '-';
78 1178 : ++xobj_len;
79 : }
80 82897 : else if ((flags & VSTR_FLAG_SC_FMT_CB_BEG_OBJ_NUM) && spec->fmt_plus)
81 : {
82 300 : sign = '+';
83 300 : ++xobj_len;
84 : }
85 82597 : else if ((flags & VSTR_FLAG_SC_FMT_CB_BEG_OBJ_NUM) && spec->fmt_space)
86 : {
87 30 : sign = ' ';
88 30 : ++xobj_len;
89 : }
90 :
91 84075 : if (0) { }
92 84075 : else if (flags & VSTR_FLAG02(SC_FMT_CB_BEG_OBJ, HEXNUM_L, HEXNUM_H))
93 1814 : xobj_len += 2;
94 82261 : else if (flags & VSTR_FLAG01(SC_FMT_CB_BEG_OBJ, OCTNUM))
95 871 : xobj_len += 1;
96 81390 : else if (flags & VSTR_FLAG02(SC_FMT_CB_BEG_OBJ, BINNUM_L, BINNUM_H))
97 13220 : xobj_len += 2;
98 :
99 : /* xtra object length's don't count with the precision */
100 84075 : if (spec->fmt_precision && ((*obj_len + quote_len) < spec->obj_precision))
101 : {
102 10719 : spec->obj_precision -= (*obj_len + quote_len);
103 10719 : zero_len = spec->obj_precision;
104 10719 : spec->fmt_zero = FALSE;
105 : }
106 : }
107 :
108 145644 : if (spec->fmt_field_width &&
109 : ((*obj_len + xobj_len + zero_len) < spec->obj_field_width))
110 : {
111 57389 : spec->obj_field_width -= (*obj_len + xobj_len + zero_len);
112 57389 : if (spec->fmt_zero)
113 3339 : zero_len = spec->obj_field_width;
114 : else
115 54050 : space_len = spec->obj_field_width;
116 : }
117 : else
118 88255 : spec->fmt_field_width = FALSE;
119 :
120 145644 : if (!spec->fmt_minus && space_len)
121 : {
122 26098 : if (!vstr_add_rep_chr(base, *pos, ' ', space_len))
123 2623 : return (FALSE);
124 23475 : *pos += space_len;
125 23475 : space_len = 0;
126 : }
127 :
128 143021 : if (num_p)
129 : {
130 81624 : if (sign)
131 : {
132 1474 : if (!vstr_add_rep_chr(base, *pos, sign, 1))
133 36 : return (FALSE);
134 1438 : ++*pos;
135 : }
136 :
137 81588 : if (0) { }
138 81588 : else if (flags & VSTR_FLAG02(SC_FMT_CB_BEG_OBJ, HEXNUM_L, HEXNUM_H))
139 : {
140 1814 : char hexout = 'x';
141 :
142 1814 : if (flags & VSTR_FLAG_SC_FMT_CB_BEG_OBJ_HEXNUM_H)
143 902 : hexout = 'X';
144 :
145 1814 : if (!vstr_add_rep_chr(base, *pos, '0', 1))
146 48 : return (FALSE);
147 1766 : ++*pos;
148 1766 : if (!vstr_add_rep_chr(base, *pos, hexout, 1))
149 48 : return (FALSE);
150 1718 : ++*pos;
151 : }
152 79774 : else if (flags & VSTR_FLAG01(SC_FMT_CB_BEG_OBJ, OCTNUM))
153 : {
154 871 : if (!vstr_add_rep_chr(base, *pos, '0', 1))
155 24 : return (FALSE);
156 847 : ++*pos;
157 : }
158 78903 : else if (flags & VSTR_FLAG02(SC_FMT_CB_BEG_OBJ, BINNUM_L, BINNUM_H))
159 : {
160 13070 : char binout = 'b';
161 :
162 13070 : if (flags & VSTR_FLAG_SC_FMT_CB_BEG_OBJ_BINNUM_H)
163 2402 : binout = 'B';
164 :
165 13070 : if (!vstr_add_rep_chr(base, *pos, '0', 1))
166 189 : return (FALSE);
167 12881 : ++*pos;
168 12881 : if (!vstr_add_rep_chr(base, *pos, binout, 1))
169 180 : return (FALSE);
170 12701 : ++*pos;
171 : }
172 :
173 81099 : if (zero_len)
174 : {
175 13506 : if (!vstr_add_rep_chr(base, *pos, '0', zero_len))
176 2374 : return (FALSE);
177 11132 : *pos += zero_len;
178 11132 : zero_len = 0;
179 : }
180 : }
181 :
182 140122 : spec->obj_precision = quote_len;
183 140122 : spec->obj_field_width = space_len;
184 :
185 140122 : return (TRUE);
186 : }
187 :
188 : int vstr_sc_fmt_cb_end(Vstr_base *base, size_t pos,
189 : Vstr_fmt_spec *spec, size_t obj_len)
190 125393 : {
191 125393 : size_t space_len = 0;
192 :
193 125393 : if (spec->fmt_field_width)
194 40288 : space_len += spec->obj_field_width;
195 :
196 125393 : if (spec->fmt_quote) /* number grows */
197 653 : obj_len += spec->obj_precision;
198 :
199 125393 : if (spec->fmt_minus)
200 22064 : if (!vstr_add_rep_chr(base, pos + obj_len, ' ', space_len))
201 3232 : return (FALSE);
202 :
203 122161 : return (TRUE);
204 : }
205 :
206 : static int vstr__sc_fmt_add_cb_vstr(Vstr_base *base, size_t pos,
207 : Vstr_fmt_spec *spec)
208 1495 : {
209 1495 : Vstr_base *sf = VSTR_FMT_CB_ARG_PTR(spec, 0);
210 1495 : size_t sf_pos = VSTR_FMT_CB_ARG_VAL(spec, size_t, 1);
211 1495 : size_t sf_len = VSTR_FMT_CB_ARG_VAL(spec, size_t, 2);
212 1495 : unsigned int sf_flags = VSTR_FMT_CB_ARG_VAL(spec, unsigned int, 3);
213 :
214 1495 : if (!vstr_sc_fmt_cb_beg(base, &pos, spec, &sf_len,
215 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_STR))
216 3 : return (FALSE);
217 :
218 1492 : if (!vstr_add_vstr(base, pos, sf, sf_pos, sf_len, sf_flags))
219 2 : return (FALSE);
220 :
221 1490 : if (!vstr_sc_fmt_cb_end(base, pos, spec, sf_len))
222 3 : return (FALSE);
223 :
224 1487 : return (TRUE);
225 : }
226 :
227 : int vstr_sc_fmt_add_vstr(Vstr_conf *conf, const char *name)
228 6095 : {
229 6095 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_vstr,
230 : VSTR_TYPE_FMT_PTR_VOID,
231 : VSTR_TYPE_FMT_SIZE_T,
232 : VSTR_TYPE_FMT_SIZE_T,
233 : VSTR_TYPE_FMT_UINT,
234 : VSTR_TYPE_FMT_END));
235 : }
236 :
237 : static int vstr__sc_fmt_add_cb_buf(Vstr_base *base, size_t pos,
238 : Vstr_fmt_spec *spec)
239 446 : {
240 446 : const char *buf = VSTR_FMT_CB_ARG_PTR(spec, 0);
241 446 : size_t sf_len = VSTR_FMT_CB_ARG_VAL(spec, size_t, 1);
242 :
243 446 : if (!buf)
244 : {
245 15 : buf = base->conf->loc->null_ref->ptr;
246 15 : if (sf_len > base->conf->loc->null_len)
247 10 : sf_len = base->conf->loc->null_len;
248 : }
249 :
250 446 : if (!vstr_sc_fmt_cb_beg(base, &pos, spec, &sf_len,
251 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_STR))
252 3 : return (FALSE);
253 :
254 443 : if (!vstr_add_buf(base, pos, buf, sf_len))
255 3 : return (FALSE);
256 :
257 440 : if (!vstr_sc_fmt_cb_end(base, pos, spec, sf_len))
258 3 : return (FALSE);
259 :
260 437 : return (TRUE);
261 : }
262 :
263 : int vstr_sc_fmt_add_buf(Vstr_conf *conf, const char *name)
264 5892 : {
265 5892 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_buf,
266 : VSTR_TYPE_FMT_PTR_CHAR,
267 : VSTR_TYPE_FMT_SIZE_T,
268 : VSTR_TYPE_FMT_END));
269 : }
270 :
271 : static int vstr__sc_fmt_add_cb_ptr(Vstr_base *base, size_t pos,
272 : Vstr_fmt_spec *spec)
273 422 : {
274 422 : const char *ptr = VSTR_FMT_CB_ARG_PTR(spec, 0);
275 422 : size_t sf_len = VSTR_FMT_CB_ARG_VAL(spec, size_t, 1);
276 :
277 422 : if (!ptr)
278 : {
279 15 : ptr = base->conf->loc->null_ref->ptr;
280 15 : if (sf_len > base->conf->loc->null_len)
281 10 : sf_len = base->conf->loc->null_len;
282 : }
283 :
284 422 : if (!vstr_sc_fmt_cb_beg(base, &pos, spec, &sf_len,
285 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_STR))
286 3 : return (FALSE);
287 :
288 419 : if (!vstr_add_ptr(base, pos, ptr, sf_len))
289 2 : return (FALSE);
290 :
291 417 : if (!vstr_sc_fmt_cb_end(base, pos, spec, sf_len))
292 2 : return (FALSE);
293 :
294 415 : return (TRUE);
295 : }
296 :
297 : int vstr_sc_fmt_add_ptr(Vstr_conf *conf, const char *name)
298 5745 : {
299 5745 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_ptr,
300 : VSTR_TYPE_FMT_PTR_CHAR,
301 : VSTR_TYPE_FMT_SIZE_T,
302 : VSTR_TYPE_FMT_END));
303 : }
304 :
305 : static int vstr__sc_fmt_add_cb_non(Vstr_base *base, size_t pos,
306 : Vstr_fmt_spec *spec)
307 400 : {
308 400 : size_t sf_len = VSTR_FMT_CB_ARG_VAL(spec, size_t, 0);
309 :
310 400 : if (!vstr_sc_fmt_cb_beg(base, &pos, spec, &sf_len,
311 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_STR))
312 3 : return (FALSE);
313 :
314 397 : if (!vstr_add_non(base, pos, sf_len))
315 2 : return (FALSE);
316 :
317 395 : if (!vstr_sc_fmt_cb_end(base, pos, spec, sf_len))
318 3 : return (FALSE);
319 :
320 392 : return (TRUE);
321 : }
322 :
323 : int vstr_sc_fmt_add_non(Vstr_conf *conf, const char *name)
324 5619 : {
325 5619 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_non,
326 : VSTR_TYPE_FMT_SIZE_T,
327 : VSTR_TYPE_FMT_END));
328 : }
329 :
330 : static int vstr__sc_fmt_add_cb_ref(Vstr_base *base, size_t pos,
331 : Vstr_fmt_spec *spec)
332 400 : {
333 400 : Vstr_ref *ref = VSTR_FMT_CB_ARG_PTR(spec, 0);
334 400 : size_t sf_off = VSTR_FMT_CB_ARG_VAL(spec, size_t, 1);
335 400 : size_t sf_len = VSTR_FMT_CB_ARG_VAL(spec, size_t, 2);
336 :
337 400 : assert(ref);
338 :
339 400 : if (!vstr_sc_fmt_cb_beg(base, &pos, spec, &sf_len,
340 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_STR))
341 3 : return (FALSE);
342 :
343 397 : if (!vstr_add_ref(base, pos, ref, sf_off, sf_len))
344 2 : return (FALSE);
345 :
346 395 : if (!vstr_sc_fmt_cb_end(base, pos, spec, sf_len))
347 3 : return (FALSE);
348 :
349 392 : return (TRUE);
350 : }
351 :
352 : int vstr_sc_fmt_add_ref(Vstr_conf *conf, const char *name)
353 8995 : {
354 8995 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_ref,
355 : VSTR_TYPE_FMT_PTR_VOID,
356 : VSTR_TYPE_FMT_SIZE_T,
357 : VSTR_TYPE_FMT_SIZE_T,
358 : VSTR_TYPE_FMT_END));
359 : }
360 :
361 : static int vstr__sc_fmt_add_cb_rep_chr(Vstr_base *base, size_t pos,
362 : Vstr_fmt_spec *spec)
363 382 : {
364 382 : int chr = VSTR_FMT_CB_ARG_VAL(spec, int, 0);
365 382 : size_t sf_len = VSTR_FMT_CB_ARG_VAL(spec, size_t, 1);
366 :
367 382 : if (!vstr_sc_fmt_cb_beg(base, &pos, spec, &sf_len,
368 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_STR))
369 2 : return (FALSE);
370 :
371 380 : if (!vstr_add_rep_chr(base, pos, chr, sf_len))
372 4 : return (FALSE);
373 :
374 376 : if (!vstr_sc_fmt_cb_end(base, pos, spec, sf_len))
375 2 : return (FALSE);
376 :
377 374 : return (TRUE);
378 : }
379 :
380 : int vstr_sc_fmt_add_rep_chr(Vstr_conf *conf, const char *name)
381 5192 : {
382 5192 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_rep_chr,
383 : VSTR_TYPE_FMT_INT,
384 : VSTR_TYPE_FMT_SIZE_T,
385 : VSTR_TYPE_FMT_END));
386 : }
387 :
388 : #define BKMG_SWITCH() \
389 : if (0) do { /* do nothing */ } while (FALSE)
390 :
391 : #define BKMG_CASE(x, y) \
392 : else if (bkmg >= val_ ## x ) \
393 : do \
394 : { \
395 : bkmg_whole = bkmg / val_ ## x ; \
396 : mov_dot_back = y; \
397 : end_bkmg = buf_ ## x ; \
398 : } while (FALSE)
399 :
400 : #define BKMG_LEN_NUM(x, Ty, z) do { \
401 : Ty bkmg_tmp = (z); \
402 : x = 1; \
403 : while (bkmg_tmp >= 10) \
404 : { \
405 : ++ x; \
406 : bkmg_tmp /= 10; \
407 : } \
408 : } while (FALSE)
409 :
410 :
411 : static int vstr__sc_fmt_add_cb_bkmg__beg(Vstr_base *base, size_t *pos,
412 : Vstr_fmt_spec *spec, size_t *sf_len,
413 : unsigned int val_len,
414 : unsigned int mov_dot_back,
415 : const char *end_bkmg,
416 : unsigned int *ret_prec,
417 : char buf_dot[2])
418 23503 : {
419 23503 : unsigned int prec = 0;
420 :
421 : /* NOTE: hard to do due to . and , -- change cb_beg ?
422 : * shouldn't trigger anyway */
423 23503 : spec->fmt_quote = FALSE;
424 :
425 23503 : if (spec->fmt_precision)
426 216 : prec = spec->obj_precision;
427 : else
428 23287 : prec = 2;
429 23503 : spec->fmt_precision = FALSE; /* for cb_beg */
430 :
431 23503 : if (prec > mov_dot_back)
432 20545 : prec = mov_dot_back;
433 :
434 : /* One of...
435 : * NNN '.' N+ end_bkmg
436 : * NNN end_bkmg */
437 23503 : *sf_len = val_len + !!prec + prec + strlen(end_bkmg);
438 :
439 23503 : if (!vstr_sc_fmt_cb_beg(base, pos, spec, sf_len,
440 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_NUM))
441 7 : return (FALSE);
442 :
443 23496 : if (prec)
444 2846 : buf_dot[0] = '.';
445 :
446 23496 : *ret_prec = prec;
447 :
448 23496 : return (TRUE);
449 : }
450 :
451 : static int vstr__sc_fmt_add_cb_bkmg__end(Vstr_base *base, size_t pos,
452 : Vstr_fmt_spec *spec, size_t sf_len,
453 : unsigned int val_len,
454 : unsigned int mov_dot_back,
455 : unsigned int prec,
456 : unsigned int num_added)
457 23455 : {
458 23455 : size_t num_keep = 0;
459 :
460 23455 : assert(val_len == (num_added - mov_dot_back));
461 23455 : assert(num_added >= val_len);
462 23455 : assert(num_added > mov_dot_back);
463 :
464 23455 : if (prec && !vstr_mov(base, pos + val_len,
465 : base, pos + num_added + 1, 1))
466 12 : return (FALSE);
467 :
468 23443 : num_keep = val_len + prec;
469 23443 : if (num_added > num_keep)
470 2898 : vstr_del(base, pos + 1 + num_keep + !!prec, (num_added - num_keep));
471 :
472 23443 : if (!vstr_sc_fmt_cb_end(base, pos, spec, sf_len))
473 3 : return (FALSE);
474 :
475 23440 : return (TRUE);
476 : }
477 :
478 : static int vstr__sc_fmt_add_cb_bkmg__uint(Vstr_base *base, size_t pos,
479 : Vstr_fmt_spec *spec,
480 : const char *buf_B,
481 : const char *buf_K,
482 : const char *buf_M,
483 : const char *buf_G)
484 175 : {
485 175 : const unsigned int val_K = (1000);
486 175 : const unsigned int val_M = (1000 * 1000);
487 175 : const unsigned int val_G = (1000 * 1000 * 1000);
488 175 : unsigned int bkmg = VSTR_FMT_CB_ARG_VAL(spec, unsigned int, 0);
489 175 : unsigned int bkmg_whole = bkmg;
490 175 : unsigned int val_len = 0;
491 175 : size_t sf_len = SIZE_MAX;
492 175 : const char *end_bkmg = buf_B;
493 175 : unsigned int num_added = 0;
494 175 : unsigned int mov_dot_back = 0;
495 175 : unsigned int prec = 0;
496 175 : char buf_dot[2] = {0, 0};
497 175 : int num_iadded = 0;
498 :
499 175 : assert(strlen(buf_B) <= strlen(buf_M));
500 175 : assert(strlen(buf_K) == strlen(buf_M));
501 175 : assert(strlen(buf_K) == strlen(buf_G));
502 :
503 175 : BKMG_SWITCH();
504 175 : BKMG_CASE(G, 9);
505 98 : BKMG_CASE(M, 6);
506 60 : BKMG_CASE(K, 3);
507 :
508 175 : BKMG_LEN_NUM(val_len, unsigned int, bkmg_whole);
509 :
510 175 : if (!vstr__sc_fmt_add_cb_bkmg__beg(base, &pos, spec, &sf_len, val_len,
511 : mov_dot_back, end_bkmg, &prec, buf_dot))
512 3 : return (FALSE);
513 :
514 172 : if (!vstr_add_sysfmt(base, pos, "%u%n%s%s", bkmg, &num_iadded,
515 : buf_dot, end_bkmg))
516 14 : return (FALSE);
517 158 : num_added = num_iadded;
518 :
519 158 : return (vstr__sc_fmt_add_cb_bkmg__end(base, pos, spec, sf_len, val_len,
520 : mov_dot_back, prec, num_added));
521 : }
522 :
523 : static int vstr__sc_fmt_add_cb_bkmg__uintmax(Vstr_base *base, size_t pos,
524 : Vstr_fmt_spec *spec,
525 : const char *buf_B,
526 : const char *buf_K,
527 : const char *buf_M,
528 : const char *buf_G,
529 : const char *buf_T,
530 : const char *buf_P,
531 : const char *buf_E)
532 23328 : {
533 23328 : const unsigned int val_K = (1000U);
534 23328 : const unsigned int val_M = (1000U * 1000U);
535 23328 : const unsigned int val_G = (1000U * 1000U * 1000U);
536 23328 : const uintmax_t val_T = (1000ULL * val_G);
537 23328 : const uintmax_t val_P = (1000ULL * val_T);
538 23328 : const uintmax_t val_E = (1000ULL * val_P);
539 23328 : uintmax_t bkmg = VSTR_FMT_CB_ARG_VAL(spec, uintmax_t, 0);
540 23328 : uintmax_t bkmg_whole = bkmg;
541 23328 : unsigned int val_len = 0;
542 23328 : size_t sf_len = SIZE_MAX;
543 23328 : const char *end_bkmg = buf_B;
544 23328 : unsigned int num_added = 0;
545 23328 : unsigned int mov_dot_back = 0;
546 23328 : unsigned int prec = 0;
547 23328 : char buf_dot[2] = {0, 0};
548 23328 : int num_iadded = 0;
549 :
550 23328 : assert(strlen(buf_B) <= strlen(buf_M));
551 23328 : assert(strlen(buf_K) == strlen(buf_M));
552 23328 : assert(strlen(buf_K) == strlen(buf_G));
553 23328 : assert(strlen(buf_K) == strlen(buf_T));
554 23328 : assert(strlen(buf_K) == strlen(buf_P));
555 23328 : assert(strlen(buf_K) == strlen(buf_E));
556 :
557 23328 : BKMG_SWITCH();
558 23328 : BKMG_CASE(E, 18);
559 23303 : BKMG_CASE(P, 15);
560 23252 : BKMG_CASE(T, 12);
561 23215 : BKMG_CASE(G, 9);
562 23200 : BKMG_CASE(M, 6);
563 22975 : BKMG_CASE(K, 3);
564 :
565 23328 : BKMG_LEN_NUM(val_len, uintmax_t, bkmg_whole);
566 :
567 23328 : if (!vstr__sc_fmt_add_cb_bkmg__beg(base, &pos, spec, &sf_len, val_len,
568 : mov_dot_back, end_bkmg, &prec, buf_dot))
569 4 : return (FALSE);
570 :
571 23324 : if (!vstr_add_sysfmt(base, pos, "%ju%n%s%s", bkmg, &num_iadded,
572 : buf_dot, end_bkmg))
573 27 : return (FALSE);
574 23297 : num_added = num_iadded;
575 :
576 23297 : return (vstr__sc_fmt_add_cb_bkmg__end(base, pos, spec, sf_len, val_len,
577 : mov_dot_back, prec, num_added));
578 : }
579 :
580 : static int vstr__sc_fmt_add_cb_bkmg_Byte_uint(Vstr_base *base, size_t pos,
581 : Vstr_fmt_spec *spec)
582 106 : {
583 106 : return (vstr__sc_fmt_add_cb_bkmg__uint(base, pos, spec,
584 : "B", "KB", "MB", "GB"));
585 : }
586 :
587 : int vstr_sc_fmt_add_bkmg_Byte_uint(Vstr_conf *conf, const char *name)
588 5066 : {
589 5066 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_bkmg_Byte_uint,
590 : VSTR_TYPE_FMT_UINT,
591 : VSTR_TYPE_FMT_END));
592 : }
593 :
594 : static int vstr__sc_fmt_add_cb_bkmg_Bytes_uint(Vstr_base *base, size_t pos,
595 : Vstr_fmt_spec *spec)
596 24 : {
597 24 : return (vstr__sc_fmt_add_cb_bkmg__uint(base, pos, spec,
598 : "B/s", "KB/s", "MB/s", "GB/s"));
599 : }
600 :
601 : int vstr_sc_fmt_add_bkmg_Bytes_uint(Vstr_conf *conf, const char *name)
602 4968 : {
603 4968 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_bkmg_Bytes_uint,
604 : VSTR_TYPE_FMT_UINT,
605 : VSTR_TYPE_FMT_END));
606 : }
607 :
608 : static int vstr__sc_fmt_add_cb_bkmg_bit_uint(Vstr_base *base, size_t pos,
609 : Vstr_fmt_spec *spec)
610 30 : {
611 30 : return (vstr__sc_fmt_add_cb_bkmg__uint(base, pos, spec,
612 : "b", "Kb", "Mb", "Gb"));
613 : }
614 :
615 : int vstr_sc_fmt_add_bkmg_bit_uint(Vstr_conf *conf, const char *name)
616 4870 : {
617 4870 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_bkmg_bit_uint,
618 : VSTR_TYPE_FMT_UINT,
619 : VSTR_TYPE_FMT_END));
620 : }
621 :
622 : static int vstr__sc_fmt_add_cb_bkmg_bits_uint(Vstr_base *base, size_t pos,
623 : Vstr_fmt_spec *spec)
624 15 : {
625 15 : return (vstr__sc_fmt_add_cb_bkmg__uint(base, pos, spec,
626 : "b/s", "Kb/s", "Mb/s", "Gb/s"));
627 : }
628 :
629 : int vstr_sc_fmt_add_bkmg_bits_uint(Vstr_conf *conf, const char *name)
630 4772 : {
631 4772 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_bkmg_bits_uint,
632 : VSTR_TYPE_FMT_UINT,
633 : VSTR_TYPE_FMT_END));
634 : }
635 :
636 : /* intmax */
637 :
638 : static int vstr__sc_fmt_add_cb_bkmg_Byte_uintmax(Vstr_base *base, size_t pos,
639 : Vstr_fmt_spec *spec)
640 23264 : {
641 23264 : return (vstr__sc_fmt_add_cb_bkmg__uintmax(base, pos, spec, "B",
642 : "KB", "MB", "GB",
643 : "TB", "PB", "EB"));
644 : }
645 :
646 : int vstr_sc_fmt_add_bkmg_Byte_uintmax(Vstr_conf *conf, const char *name)
647 4674 : {
648 4674 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_bkmg_Byte_uintmax,
649 : VSTR_TYPE_FMT_UINTMAX_T,
650 : VSTR_TYPE_FMT_END));
651 : }
652 :
653 : static int vstr__sc_fmt_add_cb_bkmg_Bytes_uintmax(Vstr_base *base, size_t pos,
654 : Vstr_fmt_spec *spec)
655 22 : {
656 22 : return (vstr__sc_fmt_add_cb_bkmg__uintmax(base, pos, spec, "B/s",
657 : "KB/s", "MB/s", "GB/s",
658 : "TB/s", "PB/s", "EB/s"));
659 : }
660 :
661 : int vstr_sc_fmt_add_bkmg_Bytes_uintmax(Vstr_conf *conf, const char *name)
662 4576 : {
663 4576 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_bkmg_Bytes_uintmax,
664 : VSTR_TYPE_FMT_UINTMAX_T,
665 : VSTR_TYPE_FMT_END));
666 : }
667 :
668 : static int vstr__sc_fmt_add_cb_bkmg_bit_uintmax(Vstr_base *base, size_t pos,
669 : Vstr_fmt_spec *spec)
670 15 : {
671 15 : return (vstr__sc_fmt_add_cb_bkmg__uintmax(base, pos, spec, "b",
672 : "Kb", "Mb", "Gb",
673 : "Tb", "Pb", "Eb"));
674 : }
675 :
676 : int vstr_sc_fmt_add_bkmg_bit_uintmax(Vstr_conf *conf, const char *name)
677 4478 : {
678 4478 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_bkmg_bit_uintmax,
679 : VSTR_TYPE_FMT_UINTMAX_T,
680 : VSTR_TYPE_FMT_END));
681 : }
682 :
683 : static int vstr__sc_fmt_add_cb_bkmg_bits_uintmax(Vstr_base *base, size_t pos,
684 : Vstr_fmt_spec *spec)
685 27 : {
686 27 : return (vstr__sc_fmt_add_cb_bkmg__uintmax(base, pos, spec, "b/s",
687 : "Kb/s", "Mb/s", "Gb/s",
688 : "Tb/s", "Pb/s", "Eb/s"));
689 : }
690 :
691 : int vstr_sc_fmt_add_bkmg_bits_uintmax(Vstr_conf *conf, const char *name)
692 4380 : {
693 4380 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_bkmg_bits_uintmax,
694 : VSTR_TYPE_FMT_UINTMAX_T,
695 : VSTR_TYPE_FMT_END));
696 : }
697 :
698 : static unsigned int vstr__sc_fmt_num10_len(unsigned int num)
699 7347 : { /* could use the log10() trick, but then we'd have to link in the math
700 : * library */
701 7347 : unsigned int ret = 0;
702 :
703 22811 : while (num > 0)
704 : {
705 15464 : num /= 10;
706 15464 : ++ret;
707 : }
708 :
709 7347 : if (!ret) return (1); /* 0 == one character */
710 :
711 6290 : return (ret);
712 : }
713 :
714 : static unsigned int vstr__sc_fmt_num16_len(unsigned int num)
715 8432 : {
716 8432 : ASSERT(num < 0x00010000);
717 : /*
718 : if (num & 0xF0000000) return (8);
719 : if (num & 0x0F000000) return (7);
720 : if (num & 0x00F00000) return (6);
721 : if (num & 0x000F0000) return (5);
722 : */
723 :
724 8432 : if (num & 0x0000F000) return (4);
725 7590 : if (num & 0x00000F00) return (3);
726 7051 : if (num & 0x000000F0) return (2);
727 5494 : if (num & 0x0000000F) return (1);
728 :
729 2915 : return (1);
730 : }
731 :
732 : /*
733 : * Note that :: expansion at either end doesn't remove as many characters...
734 : *
735 : * 1. a:a:a:a:b:b:b:b -> a:a:a:a:b:b:b:b
736 : * 2. a:a:a:a:b:b:b:0 -> a:a:a:a:b:b:b::
737 : * 3. a:a:a:a:b:b:0:0 -> a:a:a:a:b:b::
738 : * 4. 0:0:a:a:b:b:b:b -> ::a:a:b:b:b:b
739 : * 5. 0:a:a:a:b:b:b:b -> ::a:a:a:b:b:b:b
740 : * 6. a:a:a:0:0:b:b:b -> a:a:a::b:b:b
741 : *
742 : * ...it's not obvious if you should change in the 2nd and 5th cases.
743 : *
744 : */
745 : static unsigned int vstr__sc_fmt_num_ipv6_compact(unsigned int *ips,
746 : unsigned int max_num,
747 : size_t *pos)
748 916 : {
749 916 : unsigned int scan = 0;
750 916 : unsigned int ret_max = 0;
751 916 : unsigned int ret_cur = 0;
752 916 : int atend = 0;
753 :
754 7144 : while (scan < max_num)
755 : {
756 6228 : if (!ips[scan])
757 2152 : ++ret_cur;
758 : else
759 : {
760 4076 : if ((ret_cur > ret_max) ||
761 : ((ret_cur == ret_max) && (ret_cur != scan) && atend))
762 : {
763 921 : if (ret_cur == scan)
764 486 : atend = 1;
765 : else
766 435 : atend = 0;
767 921 : *pos = scan - ret_cur;
768 921 : ret_max = ret_cur;
769 : }
770 4076 : ret_cur = 0;
771 : }
772 :
773 6228 : ++scan;
774 : }
775 916 : if (ret_cur == scan)
776 15 : atend = 1;
777 916 : if (ret_cur > ret_max)
778 : {
779 50 : atend += 1;
780 50 : ret_max = ret_cur;
781 50 : *pos = scan - ret_cur;
782 : }
783 :
784 916 : return (!ret_max ? 0 : (1 + ((ret_max - 1) * 2) - atend));
785 : }
786 :
787 : static int vstr__sc_fmt_add_cb_ipv4_vec(Vstr_base *base, size_t pos,
788 : Vstr_fmt_spec *spec)
789 389 : {
790 389 : unsigned int *ips = VSTR_FMT_CB_ARG_PTR(spec, 0);
791 389 : size_t len = 0;
792 :
793 389 : assert((ips[0] <= 255) && (ips[1] <= 255) &&
794 : (ips[2] <= 255) && (ips[3] <= 255));
795 :
796 389 : len = (vstr__sc_fmt_num10_len(ips[0]) + vstr__sc_fmt_num10_len(ips[1]) +
797 : vstr__sc_fmt_num10_len(ips[2]) + vstr__sc_fmt_num10_len(ips[3]) + 3);
798 :
799 389 : if (!vstr_sc_fmt_cb_beg(base, &pos, spec, &len,
800 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_ATOM))
801 16 : return (FALSE);
802 :
803 373 : if (!vstr_add_fmt(base, pos, "%u.%u.%u.%u",
804 : ips[0], ips[1], ips[2], ips[3]))
805 7 : return (FALSE);
806 :
807 366 : if (!vstr_sc_fmt_cb_end(base, pos, spec, len))
808 16 : return (FALSE);
809 :
810 350 : return (TRUE);
811 : }
812 :
813 : int vstr_sc_fmt_add_ipv4_vec(Vstr_conf *conf, const char *name)
814 4086 : {
815 4086 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_ipv4_vec,
816 : VSTR_TYPE_FMT_PTR_VOID,
817 : VSTR_TYPE_FMT_END));
818 : }
819 :
820 : static unsigned int vstr__sc_fmt_num_ipv6_std(unsigned int *ips,
821 : unsigned int max_num)
822 1205 : {
823 1205 : unsigned int scan = 0;
824 1205 : unsigned int ret = 0;
825 :
826 9637 : while (scan < max_num)
827 : {
828 8432 : ret += vstr__sc_fmt_num16_len(ips[scan]);
829 8432 : ++scan;
830 : }
831 :
832 1205 : return (ret);
833 : }
834 :
835 : static int vstr__sc_fmt_num_ipv6(unsigned int *ips, unsigned int type,
836 : size_t *pos_compact, size_t *ret_len)
837 1989 : {
838 1989 : size_t len = 0;
839 :
840 1989 : assert((ips[0] <= 0xFFFF) && (ips[1] <= 0xFFFF) &&
841 : (ips[2] <= 0xFFFF) && (ips[3] <= 0xFFFF) &&
842 : (ips[4] <= 0xFFFF) && (ips[5] <= 0xFFFF) &&
843 : (ips[6] <= 0xFFFF) && (ips[7] <= 0xFFFF));
844 :
845 1989 : switch (type)
846 : {
847 : case VSTR_TYPE_SC_FMT_CB_IPV6_ALIGNED:
848 636 : len = 7 + 4*8; break;
849 : case VSTR_TYPE_SC_FMT_CB_IPV6_STD:
850 235 : len = (vstr__sc_fmt_num_ipv6_std(ips, 8) + 7); break;
851 : case VSTR_TYPE_SC_FMT_CB_IPV6_COMPACT:
852 : {
853 366 : size_t len_minus = vstr__sc_fmt_num_ipv6_compact(ips, 8, pos_compact);
854 366 : len = (vstr__sc_fmt_num_ipv6_std(ips, 8) + 7 - len_minus);
855 : }
856 366 : break;
857 :
858 : case VSTR_TYPE_SC_FMT_CB_IPV6_IPV4_ALIGNED:
859 : case VSTR_TYPE_SC_FMT_CB_IPV6_IPV4_STD:
860 : case VSTR_TYPE_SC_FMT_CB_IPV6_IPV4_COMPACT:
861 : {
862 744 : if (0) { }
863 744 : else if (type == VSTR_TYPE_SC_FMT_CB_IPV6_IPV4_ALIGNED)
864 140 : len = 6 + 4*6;
865 604 : else if (type == VSTR_TYPE_SC_FMT_CB_IPV6_IPV4_STD)
866 54 : len = (vstr__sc_fmt_num_ipv6_std(ips, 6) + 6);
867 550 : else if (type == VSTR_TYPE_SC_FMT_CB_IPV6_IPV4_COMPACT)
868 : {
869 550 : size_t len_minus = vstr__sc_fmt_num_ipv6_compact(ips, 6, pos_compact);
870 550 : len = (vstr__sc_fmt_num_ipv6_std(ips, 6) + 6 - len_minus);
871 : }
872 :
873 : /* add the ipv4 address on the end using the last 2 16bit entities */
874 744 : len += vstr__sc_fmt_num10_len((ips[6] >> 8) & 0xFF);
875 744 : len += vstr__sc_fmt_num10_len((ips[6] >> 0) & 0xFF);
876 744 : len += vstr__sc_fmt_num10_len((ips[7] >> 8) & 0xFF);
877 744 : len += vstr__sc_fmt_num10_len((ips[7] >> 0) & 0xFF);
878 744 : len += 3;
879 : }
880 744 : break;
881 :
882 : default:
883 8 : ASSERT_RET(FALSE, FALSE);
884 : }
885 :
886 1981 : *ret_len = len;
887 :
888 1981 : return (TRUE);
889 : }
890 :
891 : static int vstr__sc_fmt_prnt_ipv6_compact(Vstr_base *base, size_t pos,
892 : unsigned int *ips,
893 : unsigned int max_num,
894 : size_t pos_compact)
895 892 : {
896 892 : unsigned int scan = 0;
897 892 : int done = FALSE;
898 :
899 5439 : while (scan < max_num)
900 : {
901 4708 : int len = 0;
902 :
903 4708 : if (scan == pos_compact)
904 : {
905 1513 : assert(!ips[scan]);
906 2765 : while ((scan < max_num) && !ips[scan])
907 1900 : ++scan;
908 :
909 865 : if (!vstr_add_rep_chr(base, pos, ':', 2))
910 34 : return (FALSE);
911 831 : pos += 2;
912 :
913 831 : done = FALSE;
914 831 : continue;
915 : }
916 :
917 3843 : if (!vstr_add_fmt(base, pos, "%s%X%n", done ? ":" : "", ips[scan], &len))
918 127 : return (FALSE);
919 3716 : pos += len;
920 :
921 3716 : done = TRUE;
922 3716 : ++scan;
923 : }
924 :
925 731 : if ((max_num != 8) && done) /* NOTE: hack to make sure the string ends
926 : * in a ':' character for the ipv4 part */
927 384 : if (!vstr_add_rep_chr(base, pos, ':', 1))
928 16 : return (FALSE);
929 :
930 715 : return (TRUE);
931 : }
932 :
933 : static int vstr__sc_fmt_prnt_ipv6(Vstr_base *base, size_t pos,
934 : unsigned int type,
935 : unsigned int *ips,
936 : size_t pos_compact)
937 1908 : {
938 1908 : size_t orig_len = base->len;
939 :
940 1908 : if (0) { }
941 1908 : else if (type == VSTR_TYPE_SC_FMT_CB_IPV6_IPV4_ALIGNED)
942 : {
943 133 : if (!vstr_add_fmt(base, pos, "%04X:%04X:%04X:%04X:%04X:%04X:",
944 : ips[0], ips[1], ips[2], ips[3],
945 : ips[4], ips[5]))
946 15 : return (FALSE);
947 : }
948 1775 : else if (type == VSTR_TYPE_SC_FMT_CB_IPV6_STD)
949 : {
950 223 : if (!vstr_add_fmt(base, pos, "%X:%X:%X:%X:%X:%X:%X:%X",
951 : ips[0], ips[1], ips[2], ips[3],
952 : ips[4], ips[5], ips[6], ips[7]))
953 12 : return (FALSE);
954 : }
955 1552 : else if (type == VSTR_TYPE_SC_FMT_CB_IPV6_IPV4_STD)
956 : {
957 43 : if (!vstr_add_fmt(base, pos, "%X:%X:%X:%X:%X:%X:",
958 : ips[0], ips[1], ips[2], ips[3],
959 : ips[4], ips[5]))
960 7 : return (FALSE);
961 : }
962 1509 : else if (type == VSTR_TYPE_SC_FMT_CB_IPV6_COMPACT)
963 : {
964 353 : if (!vstr__sc_fmt_prnt_ipv6_compact(base, pos, ips, 8, pos_compact))
965 11 : return (FALSE);
966 : }
967 1156 : else if (type == VSTR_TYPE_SC_FMT_CB_IPV6_IPV4_COMPACT)
968 : {
969 539 : if (!vstr__sc_fmt_prnt_ipv6_compact(base, pos, ips, 6, pos_compact))
970 166 : return (FALSE);
971 : }
972 : else /* if (type == VSTR_TYPE_SC_FMT_CB_IPV6_ALIGNED) */
973 : { /* always last ... so prints with screwed types */
974 617 : if (!vstr_add_fmt(base, pos, "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",
975 : ips[0], ips[1], ips[2], ips[3],
976 : ips[4], ips[5], ips[6], ips[7]))
977 37 : return (FALSE);
978 : }
979 :
980 1660 : pos += base->len - orig_len;
981 :
982 1660 : if ((type == VSTR_TYPE_SC_FMT_CB_IPV6_IPV4_ALIGNED) ||
983 : (type == VSTR_TYPE_SC_FMT_CB_IPV6_IPV4_STD) ||
984 : (type == VSTR_TYPE_SC_FMT_CB_IPV6_IPV4_COMPACT))
985 527 : if (!vstr_add_fmt(base, pos, "%u.%u.%u.%u",
986 : (ips[6] >> 8) & 0xFF, (ips[6] >> 0) & 0xFF,
987 : (ips[7] >> 8) & 0xFF, (ips[7] >> 0) & 0xFF))
988 136 : return (FALSE);
989 :
990 1524 : return (TRUE);
991 : }
992 :
993 : static int vstr__sc_fmt_add_cb_ipv6_vec(Vstr_base *base, size_t pos,
994 : Vstr_fmt_spec *spec)
995 730 : {
996 730 : unsigned int *ips = VSTR_FMT_CB_ARG_PTR(spec, 0);
997 730 : unsigned int type = VSTR_FMT_CB_ARG_VAL(spec, unsigned int, 1);
998 730 : size_t len = 0;
999 730 : size_t pos_compact = 9;
1000 :
1001 730 : if (!vstr__sc_fmt_num_ipv6(ips, type, &pos_compact, &len))
1002 4 : return (FALSE);
1003 :
1004 726 : if (!vstr_sc_fmt_cb_beg(base, &pos, spec, &len,
1005 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_ATOM))
1006 10 : return (FALSE);
1007 :
1008 716 : if (!vstr__sc_fmt_prnt_ipv6(base, pos, type, ips, pos_compact))
1009 154 : return (FALSE);
1010 :
1011 562 : if (!vstr_sc_fmt_cb_end(base, pos, spec, len))
1012 10 : return (FALSE);
1013 :
1014 552 : return (TRUE);
1015 : }
1016 :
1017 : int vstr_sc_fmt_add_ipv6_vec(Vstr_conf *conf, const char *name)
1018 3967 : {
1019 3967 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_ipv6_vec,
1020 : VSTR_TYPE_FMT_PTR_VOID,
1021 : VSTR_TYPE_FMT_UINT,
1022 : VSTR_TYPE_FMT_END));
1023 : }
1024 :
1025 : static int vstr__sc_fmt_add_cb_ipv4_vec_cidr(Vstr_base *base, size_t pos,
1026 : Vstr_fmt_spec *spec)
1027 312 : {
1028 312 : unsigned int *ips = VSTR_FMT_CB_ARG_PTR(spec, 0);
1029 312 : unsigned int cidr = VSTR_FMT_CB_ARG_VAL(spec, unsigned int, 1);
1030 312 : size_t len = 0;
1031 :
1032 312 : assert((ips[0] <= 255) && (ips[1] <= 255) &&
1033 : (ips[2] <= 255) && (ips[3] <= 255) && (cidr <= 32));
1034 :
1035 312 : len = (vstr__sc_fmt_num10_len(ips[0]) + vstr__sc_fmt_num10_len(ips[1]) +
1036 : vstr__sc_fmt_num10_len(ips[2]) + vstr__sc_fmt_num10_len(ips[3]) +
1037 : vstr__sc_fmt_num10_len(cidr) + 4);
1038 :
1039 312 : if (!vstr_sc_fmt_cb_beg(base, &pos, spec, &len,
1040 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_ATOM))
1041 15 : return (FALSE);
1042 :
1043 297 : if (!vstr_add_fmt(base, pos, "%u.%u.%u.%u/%u",
1044 : ips[0], ips[1], ips[2], ips[3], cidr))
1045 8 : return (FALSE);
1046 :
1047 289 : if (!vstr_sc_fmt_cb_end(base, pos, spec, len))
1048 15 : return (FALSE);
1049 :
1050 274 : return (TRUE);
1051 : }
1052 :
1053 : int vstr_sc_fmt_add_ipv4_vec_cidr(Vstr_conf *conf, const char *name)
1054 3820 : {
1055 3820 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_ipv4_vec_cidr,
1056 : VSTR_TYPE_FMT_PTR_VOID,
1057 : VSTR_TYPE_FMT_UINT,
1058 : VSTR_TYPE_FMT_END));
1059 : }
1060 :
1061 : static int vstr__sc_fmt_add_cb_ipv6_vec_cidr(Vstr_base *base, size_t pos,
1062 : Vstr_fmt_spec *spec)
1063 1259 : {
1064 1259 : unsigned int *ips = VSTR_FMT_CB_ARG_PTR(spec, 0);
1065 1259 : unsigned int type = VSTR_FMT_CB_ARG_VAL(spec, unsigned int, 1);
1066 1259 : unsigned int cidr = VSTR_FMT_CB_ARG_VAL(spec, unsigned int, 2);
1067 1259 : size_t len = 0;
1068 1259 : size_t saved_len = 0;
1069 1259 : size_t pos_compact = 9;
1070 1259 : size_t orig_len = 0;
1071 :
1072 1259 : assert(cidr <= 128);
1073 :
1074 1259 : if (!vstr__sc_fmt_num_ipv6(ips, type, &pos_compact, &len))
1075 4 : return (FALSE);
1076 :
1077 1255 : len += 1 + vstr__sc_fmt_num10_len(cidr);
1078 1255 : saved_len = len;
1079 :
1080 1255 : if (!vstr_sc_fmt_cb_beg(base, &pos, spec, &len,
1081 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_ATOM))
1082 63 : return (FALSE);
1083 :
1084 1192 : orig_len = base->len;
1085 1192 : if (!vstr__sc_fmt_prnt_ipv6(base, pos, type, ips, pos_compact))
1086 230 : return (FALSE);
1087 962 : if (!vstr_add_fmt(base, pos + (base->len - orig_len), "/%u", cidr))
1088 34 : return (FALSE);
1089 928 : ASSERT((base->len - orig_len) == saved_len);
1090 :
1091 928 : if (!vstr_sc_fmt_cb_end(base, pos, spec, len))
1092 63 : return (FALSE);
1093 :
1094 865 : return (TRUE);
1095 : }
1096 :
1097 : int vstr_sc_fmt_add_ipv6_vec_cidr(Vstr_conf *conf, const char *name)
1098 3652 : {
1099 3652 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_ipv6_vec_cidr,
1100 : VSTR_TYPE_FMT_PTR_VOID,
1101 : VSTR_TYPE_FMT_UINT,
1102 : VSTR_TYPE_FMT_UINT,
1103 : VSTR_TYPE_FMT_END));
1104 : }
1105 :
1106 : #define VSTR__SC_FMT_MAKE_CB_BASE2(T, Tn, up) \
1107 : T val = VSTR_FMT_CB_ARG_VAL(spec, T, 0); \
1108 : int flags = (VSTR_FLAG_SC_FMT_CB_BEG_OBJ_NUM | \
1109 : ((up) ? \
1110 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_BINNUM_H : \
1111 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_BINNUM_L)); \
1112 : char buf[(sizeof(T) * CHAR_BIT) + 1]; \
1113 : size_t obj_len = 0; \
1114 : size_t len = 0; \
1115 : \
1116 : len = obj_len = vstr_sc_conv_num_ ## Tn (buf, sizeof(buf), val, "01", 2); \
1117 : \
1118 : if (!vstr_sc_fmt_cb_beg(base, &pos, spec, &len, flags)) \
1119 : return (FALSE); \
1120 : \
1121 : if (!vstr_sc_add_grpbasenum_buf(base, pos, 2, buf, obj_len)) \
1122 : return (FALSE); \
1123 : \
1124 : if (!vstr_sc_fmt_cb_end(base, pos, spec, len)) \
1125 : return (FALSE); \
1126 : \
1127 : return (TRUE)
1128 :
1129 : static int vstr__sc_fmt_add_cb_upper_base2_uint(Vstr_base *base, size_t pos,
1130 : Vstr_fmt_spec *spec)
1131 4804 : {
1132 4804 : VSTR__SC_FMT_MAKE_CB_BASE2(unsigned int, uint, TRUE);
1133 : }
1134 :
1135 : int vstr_sc_fmt_add_upper_base2_uint(Vstr_conf *conf, const char *name)
1136 3498 : {
1137 3498 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_upper_base2_uint,
1138 : VSTR_TYPE_FMT_UINT,
1139 : VSTR_TYPE_FMT_END));
1140 : }
1141 :
1142 : static int vstr__sc_fmt_add_cb_upper_base2_ulong(Vstr_base *base, size_t pos,
1143 : Vstr_fmt_spec *spec)
1144 6885 : {
1145 6885 : VSTR__SC_FMT_MAKE_CB_BASE2(unsigned long, ulong, TRUE);
1146 : }
1147 :
1148 : int vstr_sc_fmt_add_upper_base2_ulong(Vstr_conf *conf, const char *name)
1149 3400 : {
1150 3400 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_upper_base2_ulong,
1151 : VSTR_TYPE_FMT_ULONG,
1152 : VSTR_TYPE_FMT_END));
1153 : }
1154 :
1155 : static int vstr__sc_fmt_add_cb_upper_base2_size(Vstr_base *base, size_t pos,
1156 : Vstr_fmt_spec *spec)
1157 6794 : {
1158 6794 : VSTR__SC_FMT_MAKE_CB_BASE2(size_t, size, TRUE);
1159 : }
1160 :
1161 : int vstr_sc_fmt_add_upper_base2_size(Vstr_conf *conf, const char *name)
1162 3302 : {
1163 3302 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_upper_base2_size,
1164 : VSTR_TYPE_FMT_SIZE_T,
1165 : VSTR_TYPE_FMT_END));
1166 : }
1167 :
1168 : static int vstr__sc_fmt_add_cb_upper_base2_uintmax(Vstr_base *base, size_t pos,
1169 : Vstr_fmt_spec *spec)
1170 6794 : {
1171 6794 : VSTR__SC_FMT_MAKE_CB_BASE2(uintmax_t, uintmax, TRUE);
1172 : }
1173 :
1174 : int vstr_sc_fmt_add_upper_base2_uintmax(Vstr_conf *conf, const char *name)
1175 3204 : {
1176 3204 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_upper_base2_uintmax,
1177 : VSTR_TYPE_FMT_UINTMAX_T,
1178 : VSTR_TYPE_FMT_END));
1179 : }
1180 :
1181 : static int vstr__sc_fmt_add_cb_lower_base2_uint(Vstr_base *base, size_t pos,
1182 : Vstr_fmt_spec *spec)
1183 4764 : {
1184 4764 : VSTR__SC_FMT_MAKE_CB_BASE2(unsigned int, uint, FALSE);
1185 : }
1186 :
1187 : int vstr_sc_fmt_add_lower_base2_uint(Vstr_conf *conf, const char *name)
1188 3106 : {
1189 3106 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_lower_base2_uint,
1190 : VSTR_TYPE_FMT_UINT,
1191 : VSTR_TYPE_FMT_END));
1192 : }
1193 :
1194 : static int vstr__sc_fmt_add_cb_lower_base2_ulong(Vstr_base *base, size_t pos,
1195 : Vstr_fmt_spec *spec)
1196 6044 : {
1197 6044 : VSTR__SC_FMT_MAKE_CB_BASE2(unsigned long, ulong, FALSE);
1198 : }
1199 :
1200 : int vstr_sc_fmt_add_lower_base2_ulong(Vstr_conf *conf, const char *name)
1201 3008 : {
1202 3008 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_lower_base2_ulong,
1203 : VSTR_TYPE_FMT_ULONG,
1204 : VSTR_TYPE_FMT_END));
1205 : }
1206 :
1207 : static int vstr__sc_fmt_add_cb_lower_base2_size(Vstr_base *base, size_t pos,
1208 : Vstr_fmt_spec *spec)
1209 6872 : {
1210 6872 : VSTR__SC_FMT_MAKE_CB_BASE2(size_t, size, FALSE);
1211 : }
1212 :
1213 : int vstr_sc_fmt_add_lower_base2_size(Vstr_conf *conf, const char *name)
1214 2910 : {
1215 2910 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_lower_base2_size,
1216 : VSTR_TYPE_FMT_SIZE_T,
1217 : VSTR_TYPE_FMT_END));
1218 : }
1219 :
1220 : static int vstr__sc_fmt_add_cb_lower_base2_uintmax(Vstr_base *base, size_t pos,
1221 : Vstr_fmt_spec *spec)
1222 6794 : {
1223 6794 : VSTR__SC_FMT_MAKE_CB_BASE2(uintmax_t, uintmax, FALSE);
1224 : }
1225 :
1226 : int vstr_sc_fmt_add_lower_base2_uintmax(Vstr_conf *conf, const char *name)
1227 2812 : {
1228 2812 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_lower_base2_uintmax,
1229 : VSTR_TYPE_FMT_UINTMAX_T,
1230 : VSTR_TYPE_FMT_END));
1231 : }
1232 :
1233 : #define VSTR__SC_FMT_ADD(x, n, nchk) \
1234 : if (ret && \
1235 : !VSTR_SC_FMT_ADD(conf, vstr_sc_fmt_add_ ## x, "{" n, nchk, "}")) \
1236 : ret = FALSE
1237 :
1238 : int vstr_sc_fmt_add_all(Vstr_conf *conf)
1239 885 : {
1240 885 : int ret = TRUE;
1241 :
1242 885 : VSTR__SC_FMT_ADD(vstr, "vstr", "p%zu%zu%u");
1243 885 : VSTR__SC_FMT_ADD(buf, "buf", "s%zu");
1244 885 : VSTR__SC_FMT_ADD(ptr, "ptr", "s%zu");
1245 885 : VSTR__SC_FMT_ADD(non, "non", "zu");
1246 885 : VSTR__SC_FMT_ADD(ref, "ref", "p%zu%zu");
1247 :
1248 : /* FIXME: tmp because I screwed up the definition for 1.0.0 --
1249 : * had wrong types */
1250 885 : if (!(vstr_sc_fmt_add_ref (conf, "{ref" ":%" "p%u%zu}") &&
1251 : vstr_sc_fmt_add_ref (conf, "{ref" ":%" "*" "p%u%zu}") &&
1252 : vstr_sc_fmt_add_ref (conf, "{ref" ":%" ".*" "p%u%zu}") &&
1253 : vstr_sc_fmt_add_ref (conf, "{ref" ":%" "*.*" "p%u%zu}")))
1254 16 : ret = FALSE;
1255 :
1256 885 : VSTR__SC_FMT_ADD(rep_chr, "rep_chr", "c%zu");
1257 :
1258 885 : VSTR__SC_FMT_ADD(bkmg_Byte_uint, "BKMG.u", "u");
1259 885 : VSTR__SC_FMT_ADD(bkmg_Bytes_uint, "BKMG/s.u", "u");
1260 885 : VSTR__SC_FMT_ADD(bkmg_bit_uint, "bKMG.u", "u");
1261 885 : VSTR__SC_FMT_ADD(bkmg_bits_uint, "bKMG/s.u", "u");
1262 :
1263 885 : VSTR__SC_FMT_ADD(bkmg_Byte_uintmax, "BKMG.ju", "ju");
1264 885 : VSTR__SC_FMT_ADD(bkmg_Bytes_uintmax, "BKMG/s.ju", "ju");
1265 885 : VSTR__SC_FMT_ADD(bkmg_bit_uintmax, "bKMG.ju", "ju");
1266 885 : VSTR__SC_FMT_ADD(bkmg_bits_uintmax, "bKMG/s.ju", "ju");
1267 :
1268 885 : if (ret && !vstr__sc_fmt_add_posix(conf))
1269 28 : ret = FALSE;
1270 :
1271 885 : VSTR__SC_FMT_ADD(ipv4_vec, "ipv4.v", "p");
1272 885 : VSTR__SC_FMT_ADD(ipv6_vec, "ipv6.v", "p%u");
1273 885 : VSTR__SC_FMT_ADD(ipv4_vec_cidr, "ipv4.v+C", "p%u");
1274 885 : VSTR__SC_FMT_ADD(ipv6_vec_cidr, "ipv6.v+C", "p%u%u");
1275 :
1276 885 : VSTR__SC_FMT_ADD(upper_base2_uint, "B.u", "u");
1277 885 : VSTR__SC_FMT_ADD(upper_base2_ulong, "B.lu", "lu");
1278 885 : VSTR__SC_FMT_ADD(upper_base2_size, "B.zu", "zu");
1279 885 : VSTR__SC_FMT_ADD(upper_base2_uintmax, "B.ju", "ju");
1280 :
1281 885 : VSTR__SC_FMT_ADD(lower_base2_uint, "b.u", "u");
1282 885 : VSTR__SC_FMT_ADD(lower_base2_ulong, "b.lu", "lu");
1283 885 : VSTR__SC_FMT_ADD(lower_base2_size, "b.zu", "zu");
1284 885 : VSTR__SC_FMT_ADD(lower_base2_uintmax, "b.ju", "ju");
1285 :
1286 885 : return (ret);
1287 : }
1288 : #undef VSTR__SC_FMT_ADD
1289 :
1290 : void vstr_sc_basename(const Vstr_base *base, size_t pos, size_t len,
1291 : size_t *ret_pos, size_t *ret_len)
1292 55 : {
1293 55 : size_t ls = vstr_srch_chr_rev(base, pos, len, '/');
1294 55 : size_t end_pos = vstr_sc_poslast(pos, len);
1295 :
1296 55 : if (!ls)
1297 : {
1298 15 : *ret_pos = pos;
1299 15 : *ret_len = len;
1300 : }
1301 40 : else if (ls == pos)
1302 : {
1303 5 : *ret_pos = pos;
1304 5 : *ret_len = 0;
1305 : }
1306 35 : else if (ls == end_pos)
1307 : {
1308 15 : ls = vstr_spn_cstr_chrs_rev(base, pos, len, "/");
1309 15 : vstr_sc_basename(base, pos, len - ls, ret_pos, ret_len);
1310 : }
1311 : else
1312 : {
1313 20 : ++ls;
1314 20 : *ret_pos = ls;
1315 20 : *ret_len = len - (ls - pos);
1316 : }
1317 : }
1318 :
1319 : void vstr_sc_dirname(const Vstr_base *base, size_t pos, size_t len,
1320 : size_t *ret_len)
1321 62 : {
1322 62 : size_t ls = vstr_srch_chr_rev(base, pos, len, '/');
1323 62 : size_t end_pos = vstr_sc_poslast(pos, len);
1324 :
1325 62 : if (!ls)
1326 10 : *ret_len = 0;
1327 52 : else if (ls == end_pos)
1328 : {
1329 20 : ls = vstr_spn_cstr_chrs_rev(base, pos, len, "/");
1330 20 : len -= ls;
1331 20 : if (!len)
1332 10 : *ret_len = 1;
1333 : else
1334 10 : vstr_sc_dirname(base, pos, len, ret_len);
1335 : }
1336 : else
1337 : {
1338 32 : len = VSTR_SC_POSDIFF(pos, ls);
1339 32 : *ret_len = len - vstr_spn_cstr_chrs_rev(base, pos, len - 1, "/");
1340 : }
1341 : }
1342 :
1343 : int vstr_sc_add_grpbasenum_buf(Vstr_base *base, size_t pos,
1344 : unsigned int num_base,
1345 : const void *passed_buf, size_t len)
1346 59320 : {
1347 59320 : size_t orig_pos = pos;
1348 59320 : const char *buf = passed_buf; /* so we can move it */
1349 59320 : Vstr_locale_num_base *srch = NULL;
1350 59320 : int done = FALSE;
1351 :
1352 59320 : ASSERT(base && buf);
1353 :
1354 59320 : srch = vstr__loc_num_srch(base->conf->loc, num_base, FALSE);
1355 113205 : while (len)
1356 : {
1357 67579 : unsigned int num = vstr__add_fmt_grouping_mod(srch->grouping->ptr, len);
1358 :
1359 67579 : if (done)
1360 : {
1361 16457 : if (!vstr_add_buf(base, pos,
1362 : srch->thousands_sep_ref->ptr, srch->thousands_sep_len))
1363 53 : goto malloc_failed;
1364 :
1365 16404 : pos += srch->thousands_sep_len;
1366 : }
1367 :
1368 67526 : if (!vstr_add_buf(base, pos, buf, num))
1369 13641 : goto malloc_failed;
1370 :
1371 53885 : pos += num;
1372 53885 : buf += num;
1373 53885 : ASSERT(num <= len);
1374 53885 : len -= num;
1375 :
1376 53885 : done = TRUE;
1377 : }
1378 :
1379 45626 : return (TRUE);
1380 :
1381 : malloc_failed:
1382 13694 : vstr_del(base, orig_pos + 1, pos - orig_pos);
1383 :
1384 13694 : return (FALSE);
1385 : }
1386 :
1387 : int vstr_sc_add_grpbasenum_ptr(Vstr_base *base, size_t pos,
1388 : unsigned int num_base,
1389 : const void *passed_ptr, size_t len)
1390 22 : {
1391 22 : size_t orig_pos = pos;
1392 22 : const char *ptr = passed_ptr; /* so we can move it */
1393 22 : Vstr_locale_num_base *srch = NULL;
1394 22 : int done = FALSE;
1395 :
1396 22 : ASSERT(base && ptr);
1397 :
1398 22 : srch = vstr__loc_num_srch(base->conf->loc, num_base, FALSE);
1399 84 : while (len)
1400 : {
1401 69 : unsigned int num = vstr__add_fmt_grouping_mod(srch->grouping->ptr, len);
1402 :
1403 69 : if (done)
1404 : {
1405 47 : if (!vstr_add_ref(base, pos,
1406 : srch->thousands_sep_ref, 0, srch->thousands_sep_len))
1407 3 : goto malloc_failed;
1408 :
1409 44 : pos += srch->thousands_sep_len;
1410 : }
1411 :
1412 66 : if (!vstr_add_ptr(base, pos, ptr, num))
1413 4 : goto malloc_failed;
1414 :
1415 62 : pos += num;
1416 62 : ptr += num;
1417 62 : ASSERT(num <= len);
1418 62 : len -= num;
1419 :
1420 62 : done = TRUE;
1421 : }
1422 :
1423 15 : return (TRUE);
1424 :
1425 : malloc_failed:
1426 7 : vstr_del(base, orig_pos + 1, pos - orig_pos);
1427 :
1428 7 : return (FALSE);
1429 : }
1430 :
1431 : int vstr_sc_add_grpbasenum_ref(Vstr_base *base, size_t pos,
1432 : unsigned int num_base,
1433 : Vstr_ref *ref, size_t off, size_t len)
1434 24 : {
1435 24 : size_t orig_pos = pos;
1436 24 : Vstr_locale_num_base *srch = NULL;
1437 24 : int done = FALSE;
1438 :
1439 24 : ASSERT(base && ref);
1440 :
1441 24 : srch = vstr__loc_num_srch(base->conf->loc, num_base, FALSE);
1442 88 : while (len)
1443 : {
1444 78 : unsigned int num = vstr__add_fmt_grouping_mod(srch->grouping->ptr, len);
1445 :
1446 78 : if (done)
1447 : {
1448 54 : if (!vstr_add_ref(base, pos,
1449 : srch->thousands_sep_ref, 0, srch->thousands_sep_len))
1450 6 : goto malloc_failed;
1451 :
1452 48 : pos += srch->thousands_sep_len;
1453 : }
1454 :
1455 72 : if (!vstr_add_ref(base, pos, ref, off, num))
1456 8 : goto malloc_failed;
1457 :
1458 64 : pos += num;
1459 64 : off += num;
1460 64 : ASSERT(num <= len);
1461 64 : len -= num;
1462 :
1463 64 : done = TRUE;
1464 : }
1465 :
1466 10 : return (TRUE);
1467 :
1468 : malloc_failed:
1469 14 : vstr_del(base, orig_pos + 1, pos - orig_pos);
1470 :
1471 14 : return (FALSE);
1472 : }
1473 :
1474 : #define VSTR__SC_CONV_NUM(T) \
1475 : char buf_beg[BUF_NUM_TYPE_SZ(T)]; \
1476 : char *buf = buf_beg + sizeof(buf_beg); \
1477 : size_t ret = 0; \
1478 : \
1479 : ASSERT_RET(out && chrs_base, 0); \
1480 : ASSERT_RET(num_base >= 2, 0); \
1481 : ASSERT_RET(len >= 2, 0); \
1482 : \
1483 : if (!val) { out[0] = chrs_base[0]; out[1] = 0; return (1); } \
1484 : \
1485 : VSTR__ADD_FMT_NUM(T, val, num_base); \
1486 : \
1487 : ret = (sizeof(buf_beg) - (buf - buf_beg)); \
1488 : \
1489 : if (len <= ret) { out[0] = 0; return (0); } \
1490 : \
1491 : vstr_wrap_memcpy(out, buf, ret); \
1492 : out[ret] = 0; \
1493 : \
1494 : return (ret)
1495 :
1496 : size_t vstr_sc_conv_num_uint(char *out, size_t len, unsigned int val,
1497 : const char *chrs_base, unsigned int num_base)
1498 16627 : {
1499 16627 : VSTR__SC_CONV_NUM(unsigned int);
1500 : }
1501 :
1502 : size_t vstr_sc_conv_num10_uint(char *out, size_t len, unsigned int val)
1503 33101 : {
1504 33101 : static const char chrs_base[] = "0123456789";
1505 33101 : const unsigned int num_base = 10;
1506 33101 : VSTR__SC_CONV_NUM(unsigned int);
1507 : }
1508 :
1509 : size_t vstr_sc_conv_num_ulong(char *out, size_t len, unsigned long val,
1510 : const char *chrs_base, unsigned int num_base)
1511 12934 : {
1512 12934 : VSTR__SC_CONV_NUM(unsigned long);
1513 : }
1514 :
1515 : size_t vstr_sc_conv_num10_ulong(char *out, size_t len, unsigned long val)
1516 5 : {
1517 5 : static const char chrs_base[] = "0123456789";
1518 5 : const unsigned int num_base = 10;
1519 5 : VSTR__SC_CONV_NUM(unsigned long);
1520 : }
1521 :
1522 : size_t vstr_sc_conv_num_size(char *out, size_t len, size_t val,
1523 : const char *chrs_base, unsigned int num_base)
1524 13671 : {
1525 13671 : VSTR__SC_CONV_NUM(size_t);
1526 : }
1527 :
1528 : size_t vstr_sc_conv_num10_size(char *out, size_t len, size_t val)
1529 140 : {
1530 140 : static const char chrs_base[] = "0123456789";
1531 140 : const unsigned int num_base = 10;
1532 140 : VSTR__SC_CONV_NUM(size_t);
1533 : }
1534 :
1535 : size_t vstr_sc_conv_num_uintmax(char *out, size_t len, uintmax_t val,
1536 : const char *chrs_base, unsigned int num_base)
1537 13593 : {
1538 13593 : VSTR__SC_CONV_NUM(uintmax_t);
1539 : }
1540 :
1541 : size_t vstr_sc_conv_num10_uintmax(char *out, size_t len, uintmax_t val)
1542 1498 : {
1543 1498 : static const char chrs_base[] = "0123456789";
1544 1498 : const unsigned int num_base = 10;
1545 1498 : VSTR__SC_CONV_NUM(uintmax_t);
1546 : }
|