1 : #define VSTR_MOV_C
2 : /*
3 : * Copyright (C) 2001, 2002, 2003 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 to move data from one vstr to another */
22 : #include "main.h"
23 :
24 : static int vstr__mov_slow(Vstr_base *base, size_t pos,
25 : Vstr_base *from_base, size_t from_pos, size_t len)
26 29 : {
27 29 : int ret = 0;
28 :
29 29 : assert(base != from_base);
30 :
31 29 : ret = vstr_add_vstr(base, pos,
32 : from_base, from_pos, len, VSTR_TYPE_ADD_DEF);
33 29 : if (!ret)
34 3 : return (FALSE);
35 :
36 26 : ret = vstr_del(from_base, from_pos, len);
37 26 : if (!ret)
38 : {
39 1 : ret = vstr_del(base, pos + 1, len);
40 1 : assert(ret); /* this must work as a split can't happen */
41 1 : return (FALSE);
42 : }
43 :
44 25 : return (ret);
45 : }
46 :
47 : static int vstr__mov_single_node(Vstr_base *base, size_t pos,
48 : size_t from_pos, size_t len)
49 3170 : {
50 3170 : Vstr_node *scan = NULL;
51 3170 : char tbuf[VSTR__STACK_BUF_SZ];
52 3170 : unsigned int num = 0;
53 :
54 3170 : if (len > sizeof(tbuf))
55 5 : return (FALSE);
56 :
57 : /* XX>XXXFFX = cp T, F1, FL; mv P1+FL, P1, F1-P1; cp P1, T, FL */
58 : /* 123456789 */
59 : /* XXFFXX>XX = cp T, F1, FL; mv F1, F1+FL, P1-F1; cp P1, T, FL */
60 :
61 3165 : scan = vstr_base__pos(base, &pos, &num, TRUE);
62 3165 : if ((scan->type == VSTR_TYPE_NODE_BUF) &&
63 : (vstr_base__pos(base, &from_pos, &num, TRUE) == scan) &&
64 : (scan->len > len) &&
65 : ((scan->len - len) >= from_pos))
66 : {
67 1837 : char *ptr = vstr_export__node_ptr(scan);
68 :
69 1837 : vstr_wrap_memcpy(tbuf, ptr + from_pos - 1, len);
70 1837 : if (pos > from_pos)
71 15 : vstr_wrap_memmove(ptr + from_pos + len - 1,
72 : ptr + from_pos - 1, (pos + 1) - from_pos); /* POSDIFF */
73 : else
74 1822 : vstr_wrap_memmove(ptr + pos + len,
75 : ptr + pos, from_pos - (pos + 1));
76 1837 : vstr_wrap_memcpy(ptr + pos, tbuf, len);
77 :
78 1837 : return (TRUE);
79 : }
80 :
81 1328 : return (FALSE);
82 : }
83 :
84 : /* *ret == start of data */
85 : static Vstr_node **vstr__mov_setup_beg(Vstr_base *base, size_t pos,
86 : unsigned int *num, Vstr_node **prev)
87 5342 : {
88 5342 : Vstr_node *scan = NULL;
89 :
90 5342 : assert(num && pos && prev);
91 5342 : --pos;
92 5342 : if (!pos)
93 : {
94 4008 : *num = 1;
95 4008 : vstr__base_zero_used(base);
96 4008 : *prev = NULL;
97 4008 : return (&base->beg);
98 : }
99 :
100 1334 : scan = vstr_base__pos(base, &pos, num, TRUE);
101 :
102 1334 : if ((pos != scan->len) && !(scan = vstr__base_split_node(base, scan, pos)))
103 42 : return (NULL);
104 :
105 1292 : ++*num;
106 :
107 1292 : *prev = scan;
108 1292 : return (&scan->next);
109 : }
110 :
111 : /* *ret == after end of data */
112 : static Vstr_node **vstr__mov_setup_end(Vstr_base *base, size_t pos,
113 : unsigned int *num)
114 10647 : {
115 10647 : Vstr_node *scan = NULL;
116 10647 : unsigned int dummy_num;
117 :
118 10647 : if (!num)
119 5347 : num = &dummy_num;
120 :
121 10647 : if (!pos)
122 : {
123 1132 : *num = 0;
124 1132 : vstr__base_zero_used(base);
125 1132 : return (&base->beg);
126 : }
127 :
128 9515 : scan = vstr_base__pos(base, &pos, num, TRUE);
129 :
130 9515 : if ((pos != scan->len) && !(scan = vstr__base_split_node(base, scan, pos)))
131 9 : return (NULL);
132 :
133 9506 : return (&scan->next);
134 : }
135 :
136 : static void vstr__mov_iovec_kill(Vstr_base *base)
137 10592 : {
138 10592 : if (!base->cache_available)
139 2045 : return;
140 :
141 8547 : assert(VSTR__CACHE(base));
142 :
143 8547 : base->iovec_upto_date = FALSE;
144 : }
145 :
146 : int vstr_mov(Vstr_base *base, size_t pos,
147 : Vstr_base *from_base, size_t from_pos, size_t len)
148 7243 : {
149 7243 : Vstr_node *from_prev = NULL;
150 7243 : Vstr_node **beg = NULL;
151 7243 : Vstr_node **end = NULL;
152 7243 : Vstr_node **con = NULL;
153 7243 : Vstr_node *tmp = NULL;
154 7243 : unsigned int beg_num = 0;
155 7243 : unsigned int end_num = 0;
156 7243 : unsigned int num = 0;
157 7243 : unsigned int from_node_buf_used = FALSE;
158 7243 : unsigned int from_node_non_used = FALSE;
159 7243 : unsigned int from_node_ptr_used = FALSE;
160 7243 : unsigned int from_node_ref_used = FALSE;
161 7243 : unsigned int count = 0;
162 :
163 7243 : if (!len)
164 20 : return (TRUE);
165 :
166 7223 : assert(!(!base || (pos > base->len) ||
167 : !from_base || (from_pos > from_base->len)));
168 :
169 7223 : if ((base->conf->buf_sz != from_base->conf->buf_sz) &&
170 : from_base->node_buf_used)
171 29 : return (vstr__mov_slow(base, pos, from_base, from_pos, len));
172 :
173 7194 : if (base == from_base)
174 : {
175 3180 : if ((pos >= (from_pos - 1)) && (pos < (from_pos + len)))
176 10 : return (TRUE); /* move a string anywhere into itself -- nop */
177 :
178 3170 : if (vstr__mov_single_node(base, pos, from_pos, len))
179 1837 : return (TRUE);
180 : }
181 :
182 5347 : assert(vstr__check_real_nodes(base));
183 5347 : assert((from_base == base) || vstr__check_real_nodes(from_base));
184 :
185 : /* have to aquire the pointers in the right order,
186 : * depending on which is first */
187 5347 : if (pos > from_pos)
188 3095 : goto move_up;
189 :
190 7548 : while (count < 2)
191 : {
192 5347 : if (!(con = vstr__mov_setup_end(base, pos, NULL)))
193 5 : return (FALSE);
194 5342 : ++count;
195 :
196 5342 : if (count >= 2)
197 3095 : break;
198 :
199 : move_up:
200 5342 : if (!(beg = vstr__mov_setup_beg(from_base, from_pos, &beg_num, &from_prev)))
201 42 : return (FALSE);
202 :
203 5300 : if (!(end = vstr__mov_setup_end(from_base, from_pos + len - 1, &end_num)))
204 4 : return (FALSE);
205 5296 : ++count;
206 : }
207 5296 : assert(count == 2);
208 :
209 5296 : from_node_buf_used = from_base->node_buf_used;
210 5296 : from_node_non_used = from_base->node_non_used;
211 5296 : from_node_ptr_used = from_base->node_ptr_used;
212 5296 : from_node_ref_used = from_base->node_ref_used;
213 :
214 : /* NOTE: the numbers might be off by one if con is before beg,
215 : * but that doesn't matter as we just need the difference */
216 5296 : num = end_num - beg_num + 1;
217 :
218 5296 : tmp = *beg;
219 5296 : if (!(*beg = *end))
220 4252 : from_base->end = from_prev;
221 :
222 5296 : ASSERT(!!from_base->beg == !!from_base->end);
223 :
224 5296 : from_base->len -= len;
225 5296 : from_base->num -= num;
226 5296 : vstr__cache_del(from_base, from_pos, len);
227 5296 : vstr__mov_iovec_kill(from_base);
228 :
229 5296 : if (!from_base->len)
230 : {
231 3972 : from_base->node_buf_used = FALSE;
232 3972 : from_base->node_non_used = FALSE;
233 3972 : from_base->node_ptr_used = FALSE;
234 3972 : from_base->node_ref_used = FALSE;
235 : }
236 :
237 5296 : beg = &tmp;
238 :
239 5296 : *end = *con;
240 5296 : *con = *beg;
241 :
242 5296 : if (!*end)
243 4013 : base->end = VSTR__CONV_PTR_NEXT_PREV(end);
244 :
245 5296 : base->len += len;
246 5296 : base->num += num;
247 :
248 5296 : base->node_buf_used |= from_node_buf_used;
249 5296 : base->node_non_used |= from_node_non_used;
250 5296 : base->node_ptr_used |= from_node_ptr_used;
251 5296 : base->node_ref_used |= from_node_ref_used;
252 :
253 5296 : vstr__cache_add(base, pos, len);
254 5296 : vstr__mov_iovec_kill(base); /* This is easy to rm, if they append */
255 :
256 5296 : assert(vstr__check_real_nodes(base));
257 5296 : assert((from_base == base) || vstr__check_real_nodes(from_base));
258 :
259 5296 : return (TRUE);
260 : }
|