1 : /* Copyright (c) 2007 Paul Rosenfeld
2 : James Antill -- See LICENSE file for terms. */
3 : #ifndef USTR_SPLIT_H
4 : #error " Include ustr-split.h before this file."
5 : #endif
6 :
7 : #if !defined(USTR_FMT_INTERNAL_H) && !defined(USTR_IO_H)
8 : #include <stdio.h>
9 : #endif
10 :
11 : USTR_CONF_i_PROTO
12 : struct Ustr *ustrp__split_buf(struct Ustr_pool *p,
13 : const struct Ustr *s1, size_t *poff,
14 : const void *sep, size_t slen, struct Ustr *ret,
15 : unsigned int flags)
16 280 : {
17 210 : size_t len = ustr_len(s1);
18 280 : size_t off = *poff;
19 280 : size_t found_pos = 0;
20 280 : size_t ret_len = 0;
21 :
22 140 : USTR_ASSERT(ustrp__assert_valid(!!p, s1));
23 :
24 280 : USTR_ASSERT_RET(off <= len, USTR_NULL);
25 :
26 280 : if (!slen || (off == len))
27 : {
28 60 : ustrp__free(p, ret);
29 60 : errno = 0; /* only way to tell between FAILURE and END */
30 60 : return (USTR_NULL);
31 : }
32 :
33 : /* Separator not found, just return the rest of the string */
34 220 : if (!(found_pos = ustr_srch_buf_fwd(s1, off, sep, slen)))
35 : {
36 28 : ret_len = len - off;
37 28 : *poff = len;
38 28 : goto copy_buf;
39 : }
40 :
41 : /* Set the offset for the next, must skip sep */
42 192 : *poff = (found_pos - 1) + slen;
43 192 : if (!(flags & (USTR_FLAG_SPLIT_RET_SEP | USTR_FLAG_SPLIT_RET_NON)))
44 : {
45 84 : const char *ptr = ustr_cstr(s1);
46 :
47 296 : while (((len - *poff) >= slen) && !memcmp(ptr + *poff, sep, slen))
48 72 : *poff += slen;
49 : }
50 :
51 : /* If we don't wish to return blanks or separators, we might get "a,,b" with
52 : * sep="," so we need to skip the first "found" separator -- so just try
53 : * again */
54 192 : if (((found_pos - 1) == off) &&
55 : !(flags & (USTR_FLAG_SPLIT_RET_SEP | USTR_FLAG_SPLIT_RET_NON)))
56 20 : return (ustrp__split_buf(p, s1, poff, sep, slen, ret, flags));
57 :
58 172 : ret_len = (found_pos - 1) - off;
59 172 : if (flags & USTR_FLAG_SPLIT_RET_SEP) /* Include sep in the return value */
60 44 : ret_len += slen;
61 :
62 200 : copy_buf:
63 200 : if (ret)
64 : {
65 32 : if (!ustrp__set_subustr(p, &ret, s1, off + 1, ret_len))
66 : {
67 4 : ustrp__free(p, ret);
68 4 : return (USTR_NULL);
69 : }
70 :
71 28 : return (ret);
72 : }
73 :
74 168 : if (flags & USTR_FLAG_SPLIT_KEEP_CONF)
75 24 : return (ustrp__dup_subustr(p, s1, off + 1, ret_len));
76 :
77 144 : return (ustrp__dupx_buf(p, USTR__DUPX_DEF, ustr_cstr(s1) + off, ret_len));
78 : }
79 : USTR_CONF_I_PROTO
80 : struct Ustr *ustr_split_buf(const struct Ustr *s1, size_t *off,
81 : const void *sep, size_t slen, struct Ustr *ret,
82 : unsigned int flags)
83 84 : { return (ustrp__split_buf(0, s1, off, sep, slen, ret, flags)); }
84 : USTR_CONF_I_PROTO
85 : struct Ustrp *ustrp_split_buf(struct Ustr_pool *p,
86 : const struct Ustrp *s1, size_t *off,
87 : const void *sep, size_t slen, struct Ustrp *ret,
88 : unsigned int flags)
89 16 : { return (USTRP(ustrp__split_buf(p, &s1->s, off, sep, slen, &ret->s, flags))); }
90 :
91 : USTR_CONF_I_PROTO
92 : struct Ustr *ustr_split(const struct Ustr *s1, size_t *off,
93 : const struct Ustr *sep, struct Ustr *ret,
94 : unsigned int flags)
95 144 : {
96 72 : USTR_ASSERT(ustrp__assert_valid(0, sep));
97 144 : return (ustrp__split_buf(0, s1,off,ustr_cstr(sep),ustr_len(sep), ret, flags));
98 : }
99 :
100 : USTR_CONF_I_PROTO
101 : struct Ustrp *ustrp_split(struct Ustr_pool *p,
102 : const struct Ustrp *s1, size_t *off,
103 : const struct Ustrp *sep, struct Ustrp *ret,
104 : unsigned int flags)
105 16 : {
106 8 : USTR_ASSERT(ustrp_assert_valid(sep));
107 20 : return (USTRP(ustrp__split_buf(p, &s1->s, off, ustrp_cstr(sep),ustrp_len(sep),
108 : &ret->s, flags)));
109 : }
110 :
111 : USTR_CONF_i_PROTO
112 : struct Ustr *ustrp__split_spn_chrs(struct Ustr_pool *p, const struct Ustr *s1,
113 : size_t *poff, const char *seps, size_t slen,
114 : struct Ustr *ret, unsigned int flags)
115 380 : {
116 285 : size_t len = ustr_len(s1);
117 380 : size_t off = *poff;
118 380 : size_t spn = 0;
119 380 : size_t sep = 0;
120 380 : size_t ret_len = 0;
121 :
122 190 : USTR_ASSERT(ustrp__assert_valid(!!p, s1));
123 :
124 380 : USTR_ASSERT_RET(off <= len, USTR_NULL);
125 :
126 380 : if (!slen || (off == len))
127 : {
128 28 : ustrp__free(p, ret);
129 28 : errno = 0; /* only way to tell between FAILURE and END */
130 28 : return (USTR_NULL);
131 : }
132 :
133 352 : spn = ustr_cspn_chrs_fwd(s1, off, seps, slen);
134 352 : if (!spn && !(flags & (USTR_FLAG_SPLIT_RET_SEP | USTR_FLAG_SPLIT_RET_NON)))
135 : {
136 4 : *poff += ustr_spn_chrs_fwd(s1, off, seps, slen);
137 4 : return (ustrp__split_spn_chrs(p, s1, poff, seps, slen, ret, flags));
138 : }
139 :
140 : /* if there's any data left the first byte must be in seps */
141 :
142 348 : if (flags & (USTR_FLAG_SPLIT_RET_SEP | USTR_FLAG_SPLIT_RET_NON))
143 252 : sep = !((off + spn) == len);
144 : else
145 96 : sep = ustr_spn_chrs_fwd(s1, off + spn, seps, slen);
146 174 : USTR_ASSERT(!sep == !ustr_spn_chrs_fwd(s1, off + spn, seps, slen));
147 :
148 348 : *poff += spn + sep;
149 :
150 348 : ret_len = spn;
151 348 : if (flags & USTR_FLAG_SPLIT_RET_SEP) /* Include seps in the return value */
152 168 : ret_len += sep;
153 :
154 348 : if (ret)
155 : {
156 16 : if (!ustrp__set_subustr(p, &ret, s1, off + 1, ret_len))
157 4 : return (USTR_NULL);
158 :
159 12 : return (ret);
160 : }
161 :
162 332 : if (flags & USTR_FLAG_SPLIT_KEEP_CONF)
163 4 : return (ustrp__dup_subustr(p, s1, off + 1, ret_len));
164 :
165 328 : return (ustrp__dupx_buf(p, USTR__DUPX_DEF, ustr_cstr(s1) + off, ret_len));
166 : }
167 : USTR_CONF_I_PROTO
168 : struct Ustr *ustr_split_spn_chrs(const struct Ustr *s1, size_t *poff,
169 : const char *seps, size_t slen,
170 : struct Ustr *ret, unsigned int flags)
171 348 : { return (ustrp__split_spn_chrs(0, s1, poff, seps, slen, ret, flags)); }
172 : USTR_CONF_I_PROTO
173 : struct Ustrp *ustrp_split_spn_chrs(struct Ustr_pool *p, const struct Ustrp *s1,
174 : size_t *poff, const char *seps, size_t slen,
175 : struct Ustrp *ret, unsigned int flags)
176 8 : { return (USTRP(ustrp__split_spn_chrs(p, &s1->s, poff, seps, slen,
177 : &ret->s, flags))); }
178 :
179 : USTR_CONF_I_PROTO
180 : struct Ustr *ustr_split_spn(const struct Ustr *s1, size_t *off,
181 : const struct Ustr *sep, struct Ustr *ret,
182 : unsigned int flags)
183 16 : {
184 8 : USTR_ASSERT(ustrp__assert_valid(0, sep));
185 16 : return (ustrp__split_spn_chrs(0, s1, off, ustr_cstr(sep), ustr_len(sep),
186 : ret, flags));
187 : }
188 :
189 : USTR_CONF_I_PROTO
190 : struct Ustrp *ustrp_split_spn(struct Ustr_pool *p,
191 : const struct Ustrp *s1, size_t *off,
192 : const struct Ustrp *sep, struct Ustrp *ret,
193 : unsigned int flags)
194 4 : {
195 2 : USTR_ASSERT(ustrp_assert_valid(sep));
196 5 : return (USTRP(ustrp__split_spn_chrs(p, &s1->s, off, ustrp_cstr(sep),
197 : ustrp_len(sep), &ret->s, flags)));
198 : }
|