msvcp80: Fixed typo in spec file.
[wine] / dlls / msvcp100 / string.c
1 /*
2  * Copyright 2010 Piotr Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22
23 #include "msvcp.h"
24 #include "stdio.h"
25 #include "assert.h"
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(msvcp);
31
32 /* _String_iterator<char> and _String_const_iterator<char> class */
33 /* char_traits<char> */
34 /* ?assign@?$char_traits@D@std@@SAXAADABD@Z */
35 /* ?assign@?$char_traits@D@std@@SAXAEADAEBD@Z */
36 static void MSVCP_char_traits_char_assign(char *ch, const char *assign)
37 {
38     *ch = *assign;
39 }
40
41 /* ?assign@?$char_traits@D@std@@SAPADPADID@Z */
42 /* ?assign@?$char_traits@D@std@@SAPEADPEAD_KD@Z */
43 static char* MSVCP_char_traits_char_assignn(char *str, MSVCP_size_t num, char c)
44 {
45     return memset(str, c, num);
46 }
47
48 /* ?length@?$char_traits@D@std@@SAIPBD@Z */
49 /* ?length@?$char_traits@D@std@@SA_KPEBD@Z */
50 static MSVCP_size_t MSVCP_char_traits_char_length(const char *str)
51 {
52     return strlen(str);
53 }
54
55 /* ?_Copy_s@?$char_traits@D@std@@SAPADPADIPBDI@Z */
56 /* ?_Copy_s@?$char_traits@D@std@@SAPEADPEAD_KPEBD1@Z */
57 static char* MSVCP_char_traits_char__Copy_s(char *dest,
58         MSVCP_size_t size, const char *src, MSVCP_size_t count)
59 {
60     if(!dest || !src || size<count) {
61         if(dest && size)
62             dest[0] = '\0';
63         _invalid_parameter(NULL, NULL, NULL, 0, 0);
64         return dest;
65     }
66
67     return memcpy(dest, src, count);
68 }
69
70 /* ?_Move_s@?$char_traits@D@std@@SAPADPADIPBDI@Z */
71 /* ?_Move_s@?$char_traits@D@std@@SAPEADPEAD_KPEBD1@Z */
72 static char* MSVCP_char_traits_char__Move_s(char *dest,
73         MSVCP_size_t size, const char *src, MSVCP_size_t count)
74 {
75     if(!dest || !src || size<count) {
76         if(dest && size)
77             dest[0] = '\0';
78         _invalid_parameter(NULL, NULL, NULL, 0, 0);
79         return dest;
80     }
81
82     return memmove(dest, src, count);
83 }
84
85 /* char_traits<wchar_t> */
86 /* ?assign@?$char_traits@_W@std@@SAXAA_WAB_W@Z */
87 /* ?assign@?$char_traits@_W@std@@SAXAEA_WAEB_W@Z */
88 static void MSVCP_char_traits_wchar_assign(wchar_t *ch,
89         const wchar_t *assign)
90 {
91     *ch = *assign;
92 }
93
94 /* ?length@?$char_traits@_W@std@@SAIPB_W@Z */
95 /* ?length@?$char_traits@_W@std@@SA_KPEB_W@Z */
96 static MSVCP_size_t MSVCP_char_traits_wchar_length(const wchar_t *str)
97 {
98     return wcslen((WCHAR*)str);
99 }
100
101 /* ?_Copy_s@?$char_traits@_W@std@@SAPA_WPA_WIPB_WI@Z */
102 /* ?_Copy_s@?$char_traits@_W@std@@SAPEA_WPEA_W_KPEB_W1@Z */
103 static wchar_t* MSVCP_char_traits_wchar__Copy_s(wchar_t *dest,
104         MSVCP_size_t size, const wchar_t *src, MSVCP_size_t count)
105 {
106     if(!dest || !src || size<count) {
107         if(dest && size)
108             dest[0] = '\0';
109         _invalid_parameter(NULL, NULL, NULL, 0, 0);
110         return dest;
111     }
112
113     return memcpy(dest, src, count * sizeof(wchar_t));
114 }
115
116 /* ?_Move_s@?$char_traits@_W@std@@SAPA_WPA_WIPB_WI@Z */
117 /* ?_Move_s@?$char_traits@_W@std@@SAPEA_WPEA_W_KPEB_W1@Z */
118 static wchar_t* MSVCP_char_traits_wchar__Move_s(wchar_t *dest,
119         MSVCP_size_t size, const wchar_t *src, MSVCP_size_t count)
120 {
121     if(!dest || !src || size<count) {
122         if(dest && size)
123             dest[0] = '\0';
124         _invalid_parameter(NULL, NULL, NULL, 0, 0);
125         return dest;
126     }
127
128     return memmove(dest, src, count * sizeof(WCHAR));
129 }
130
131 /* _String_base */
132 /* ?_Xlen@_String_base@std@@SAXXZ */
133 static void MSVCP__String_base_Xlen(void)
134 {
135     static const char msg[] = "string too long";
136
137     TRACE("\n");
138     throw_exception(EXCEPTION_LENGTH_ERROR, msg);
139 }
140
141 /* _String_base */
142 /* ?_Xran@_String_base@std@@SAXXZ */
143 static void MSVCP__String_base_Xran(void)
144 {
145     static const char msg[] = "invalid string position";
146
147     TRACE("\n");
148     throw_exception(EXCEPTION_OUT_OF_RANGE, msg);
149 }
150
151
152 /* basic_string<char, char_traits<char>, allocator<char>> */
153 /* ?npos@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@2IB */
154 /* ?npos@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@2_KB */
155 static const MSVCP_size_t MSVCP_basic_string_char_npos = -1;
156
157 /* ?_Myptr@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IAEPADXZ */
158 /* ?_Myptr@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IEAAPEADXZ */
159 static char* basic_string_char_ptr(basic_string_char *this)
160 {
161     if(this->res < BUF_SIZE_CHAR)
162         return this->data.buf;
163     return this->data.ptr;
164 }
165
166 /* ?_Myptr@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IBEPBDXZ */
167 /* ?_Myptr@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IEBAPEBDXZ */
168 static const char* basic_string_char_const_ptr(const basic_string_char *this)
169 {
170     if(this->res < BUF_SIZE_CHAR)
171         return this->data.buf;
172     return this->data.ptr;
173 }
174
175 /* ?_Eos@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IAEXI@Z */
176 /* ?_Eos@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IEAAX_K@Z */
177 static void basic_string_char_eos(basic_string_char *this, MSVCP_size_t len)
178 {
179     static const char nullbyte = '\0';
180
181     this->size = len;
182     MSVCP_char_traits_char_assign(basic_string_char_ptr(this)+len, &nullbyte);
183 }
184
185 /* ?_Inside@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IAE_NPBD@Z */
186 /* ?_Inside@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IEAA_NPEBD@Z */
187 static MSVCP_bool basic_string_char_inside(
188         basic_string_char *this, const char *ptr)
189 {
190     char *cstr = basic_string_char_ptr(this);
191
192     return ptr>=cstr && ptr<cstr+this->size;
193 }
194
195 /* ?_Tidy@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IAEX_NI@Z */
196 /* ?_Tidy@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IEAAX_N_K@Z */
197 static void basic_string_char_tidy(basic_string_char *this,
198         MSVCP_bool built, MSVCP_size_t new_size)
199 {
200     if(built && BUF_SIZE_CHAR<=this->res) {
201         char *ptr = this->data.ptr;
202
203         if(new_size > 0)
204             MSVCP_char_traits_char__Copy_s(this->data.buf, BUF_SIZE_CHAR, ptr, new_size);
205         MSVCP_allocator_char_deallocate(this->allocator, ptr, this->res+1);
206     }
207
208     this->res = BUF_SIZE_CHAR-1;
209     basic_string_char_eos(this, new_size);
210 }
211
212 /* ?_Grow@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IAE_NI_N@Z */
213 /* ?_Grow@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IEAA_N_K_N@Z */
214 static MSVCP_bool basic_string_char_grow(
215         basic_string_char *this, MSVCP_size_t new_size, MSVCP_bool trim)
216 {
217     if(this->res < new_size) {
218         MSVCP_size_t new_res = new_size, len = this->size;
219         char *ptr;
220
221         new_res |= 0xf;
222
223         if(new_res/3 < this->res/2)
224             new_res = this->res + this->res/2;
225
226         ptr = MSVCP_allocator_char_allocate(this->allocator, new_res+1);
227         if(!ptr)
228             ptr = MSVCP_allocator_char_allocate(this->allocator, new_size+1);
229         else
230             new_size = new_res;
231         if(!ptr) {
232             ERR("Out of memory\n");
233             basic_string_char_tidy(this, TRUE, 0);
234             return FALSE;
235         }
236
237         MSVCP_char_traits_char__Copy_s(ptr, new_size,
238                 basic_string_char_ptr(this), this->size);
239         basic_string_char_tidy(this, TRUE, 0);
240         this->data.ptr = ptr;
241         this->res = new_size;
242         basic_string_char_eos(this, len);
243     } else if(trim && new_size < BUF_SIZE_CHAR)
244         basic_string_char_tidy(this, TRUE,
245                 new_size<this->size ? new_size : this->size);
246     else if(new_size == 0)
247         basic_string_char_eos(this, 0);
248
249     return (new_size>0);
250 }
251
252 /* ?erase@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV12@II@Z */
253 /* ?erase@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAAEAV12@_K0@Z */
254 static basic_string_char* MSVCP_basic_string_char_erase(
255         basic_string_char *this, MSVCP_size_t pos, MSVCP_size_t len)
256 {
257     TRACE("%p %lu %lu\n", this, pos, len);
258
259     if(pos > this->size)
260         MSVCP__String_base_Xran();
261
262     if(len > this->size-pos)
263         len = this->size-pos;
264
265     if(len) {
266         MSVCP_char_traits_char__Move_s(basic_string_char_ptr(this)+pos,
267                 this->res-pos, basic_string_char_ptr(this)+pos+len,
268                 this->size-pos-len);
269         basic_string_char_eos(this, this->size-len);
270     }
271
272     return this;
273 }
274
275 /* ?assign@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV12@ABV12@II@Z */
276 /* ?assign@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAAEAV12@AEBV12@_K1@Z */
277 static basic_string_char* MSVCP_basic_string_char_assign_substr(
278         basic_string_char *this, const basic_string_char *assign,
279         MSVCP_size_t pos, MSVCP_size_t len)
280 {
281     TRACE("%p %p %lu %lu\n", this, assign, pos, len);
282
283     if(assign->size < pos)
284         MSVCP__String_base_Xran();
285
286     if(len > assign->size-pos)
287         len = assign->size-pos;
288
289     if(this == assign) {
290         MSVCP_basic_string_char_erase(this, pos+len, MSVCP_basic_string_char_npos);
291         MSVCP_basic_string_char_erase(this, 0, pos);
292     } else if(basic_string_char_grow(this, len, FALSE)) {
293         MSVCP_char_traits_char__Copy_s(basic_string_char_ptr(this),
294                 this->res, basic_string_char_const_ptr(assign)+pos, len);
295         basic_string_char_eos(this, len);
296     }
297
298     return this;
299 }
300
301 /* ??4?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV01@ABV01@@Z */
302 /* ??4?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAAEAV01@AEBV01@@Z */
303 static basic_string_char* MSVCP_basic_string_char_assign(
304         basic_string_char *this, const basic_string_char *assign)
305 {
306     return MSVCP_basic_string_char_assign_substr(this, assign,
307             0, MSVCP_basic_string_char_npos);
308 }
309
310 /* ?assign@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV12@PBDI@Z */
311 /* ?assign@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAAEAV12@PEBD_K@Z */
312 static basic_string_char* MSVCP_basic_string_char_assign_cstr_len(
313         basic_string_char *this, const char *str, MSVCP_size_t len)
314 {
315     TRACE("%p %s %lu\n", this, debugstr_an(str, len), len);
316
317     if(basic_string_char_inside(this, str))
318         return MSVCP_basic_string_char_assign_substr(this, this,
319                 str-basic_string_char_ptr(this), len);
320     else if(basic_string_char_grow(this, len, FALSE)) {
321         MSVCP_char_traits_char__Copy_s(basic_string_char_ptr(this),
322                 this->res, str, len);
323         basic_string_char_eos(this, len);
324     }
325
326     return this;
327 }
328
329 /* ??4?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV01@PBD@Z */
330 /* ??4?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAAEAV01@PEBD@Z */
331 static basic_string_char* MSVCP_basic_string_char_assign_cstr(
332         basic_string_char *this, const char *str)
333 {
334     return MSVCP_basic_string_char_assign_cstr_len(this, str,
335             MSVCP_char_traits_char_length(str));
336 }
337
338 /* ?c_str@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEPBDXZ */
339 /* ?c_str@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEBAPEBDXZ */
340 /* ?data@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEPBDXZ */
341 /* ?data@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEBAPEBDXZ */
342 const char* MSVCP_basic_string_char_c_str(const basic_string_char *this)
343 {
344     TRACE("%p\n", this);
345     return basic_string_char_const_ptr(this);
346 }
347
348 /* ??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@ABV01@@Z */
349 /* ??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@AEBV01@@Z */
350 basic_string_char* MSVCP_basic_string_char_copy_ctor(
351     basic_string_char *this, const basic_string_char *copy)
352 {
353     TRACE("%p %p\n", this, copy);
354
355     basic_string_char_tidy(this, FALSE, 0);
356     MSVCP_basic_string_char_assign(this, copy);
357     return this;
358 }
359
360 /* ??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ */
361 /* ??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@XZ */
362 basic_string_char* MSVCP_basic_string_char_ctor(basic_string_char *this)
363 {
364     TRACE("%p\n", this);
365
366     basic_string_char_tidy(this, FALSE, 0);
367     return this;
368 }
369
370 /* ??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z */
371 /* ??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@PEBD@Z */
372 basic_string_char* MSVCP_basic_string_char_ctor_cstr(
373         basic_string_char *this, const char *str)
374 {
375     TRACE("%p %s\n", this, debugstr_a(str));
376
377     basic_string_char_tidy(this, FALSE, 0);
378     MSVCP_basic_string_char_assign_cstr(this, str);
379     return this;
380 }
381
382 /* ??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ */
383 /* ??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@XZ */
384 void MSVCP_basic_string_char_dtor(basic_string_char *this)
385 {
386     TRACE("%p\n", this);
387     basic_string_char_tidy(this, TRUE, 0);
388 }
389
390 /* ?size@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEIXZ */
391 /* ?size@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEBA_KXZ */
392 /* ?length@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEIXZ */
393 /* ?length@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEBA_KXZ */
394 MSVCP_size_t MSVCP_basic_string_char_length(const basic_string_char *this)
395 {
396     TRACE("%p\n", this);
397     return this->size;
398 }
399
400 /* ?append@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV12@ID@Z */
401 /* ?append@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAAEAV12@_KD@Z */
402 static basic_string_char* MSVCP_basic_string_char_append_len_ch(basic_string_char *this, MSVCP_size_t count, char ch)
403 {
404     TRACE("%p %lu %c\n", this, count, ch);
405
406     if(MSVCP_basic_string_char_npos-this->size <= count)
407         MSVCP__String_base_Xlen();
408
409     if(basic_string_char_grow(this, this->size+count, FALSE)) {
410         MSVCP_char_traits_char_assignn(basic_string_char_ptr(this)+this->size, count, ch);
411         basic_string_char_eos(this, this->size+count);
412     }
413
414     return this;
415 }
416
417 /* ??Y?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV01@D@Z */
418 /* ??Y?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAAEAV01@D@Z */
419 /* ?push_back@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEXD@Z */
420 /* ?push_back@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAXD@Z */
421 basic_string_char* MSVCP_basic_string_char_append_ch(basic_string_char *this, char ch)
422 {
423     return MSVCP_basic_string_char_append_len_ch(this, 1, ch);
424 }
425
426 /* basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> */
427 /* basic_string<unsigned short, char_traits<unsigned short>, allocator<unsigned short>> */
428 /* ?npos@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@2IB */
429 /* ?npos@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@2_KB */
430 /* ?npos@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@2IB */
431 /* ?npos@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@2_KB */
432 const MSVCP_size_t MSVCP_basic_string_wchar_npos = -1;
433
434 /* ?_Myptr@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IAEPA_WXZ */
435 /* ?_Myptr@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IEAAPEA_WXZ */
436 /* ?_Myptr@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@IAEPAGXZ */
437 /* ?_Myptr@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@IEAAPEAGXZ */
438 static wchar_t* basic_string_wchar_ptr(basic_string_wchar *this)
439 {
440     if(this->res < BUF_SIZE_WCHAR)
441         return this->data.buf;
442     return this->data.ptr;
443 }
444
445 /* ?_Myptr@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IBEPB_WXZ */
446 /* ?_Myptr@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IEBAPEB_WXZ */
447 /* ?_Myptr@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@IBEPBGXZ */
448 /* ?_Myptr@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@IEBAPEBGXZ */
449 static const wchar_t* basic_string_wchar_const_ptr(const basic_string_wchar *this)
450 {
451     if(this->res < BUF_SIZE_WCHAR)
452         return this->data.buf;
453     return this->data.ptr;
454 }
455
456 /* ?_Eos@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IAEXI@Z */
457 /* ?_Eos@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IEAAX_K@Z */
458 /* ?_Eos@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@IAEXI@Z */
459 /* ?_Eos@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@IEAAX_K@Z */
460 static void basic_string_wchar_eos(basic_string_wchar *this, MSVCP_size_t len)
461 {
462     static const wchar_t nullbyte_w = '\0';
463
464     this->size = len;
465     MSVCP_char_traits_wchar_assign(basic_string_wchar_ptr(this)+len, &nullbyte_w);
466 }
467
468 /* ?_Inside@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IAE_NPB_W@Z */
469 /* ?_Inside@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IEAA_NPEB_W@Z */
470 /* ?_Inside@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@IAE_NPBG@Z */
471 /* ?_Inside@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@IEAA_NPEBG@Z */
472 static MSVCP_bool basic_string_wchar_inside(
473         basic_string_wchar *this, const wchar_t *ptr)
474 {
475     wchar_t *cstr = basic_string_wchar_ptr(this);
476
477     return ptr>=cstr && ptr<cstr+this->size;
478 }
479
480 /* ?_Tidy@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IAEX_NI@Z */
481 /* ?_Tidy@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IEAAX_N_K@Z */
482 /* ?_Tidy@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@IAEX_NI@Z */
483 /* ?_Tidy@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@IEAAX_N_K@Z */
484 static void basic_string_wchar_tidy(basic_string_wchar *this,
485         MSVCP_bool built, MSVCP_size_t new_size)
486 {
487     if(built && BUF_SIZE_WCHAR<=this->res) {
488         wchar_t *ptr = this->data.ptr;
489
490         if(new_size > 0)
491             MSVCP_char_traits_wchar__Copy_s(this->data.buf, BUF_SIZE_WCHAR, ptr, new_size);
492         MSVCP_allocator_wchar_deallocate(this->allocator, ptr, this->res+1);
493     }
494
495     this->res = BUF_SIZE_WCHAR-1;
496     basic_string_wchar_eos(this, new_size);
497 }
498
499 /* ?_Grow@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IAE_NI_N@Z */
500 /* ?_Grow@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IEAA_N_K_N@Z */
501 /* ?_Grow@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@IAE_NI_N@Z */
502 /* ?_Grow@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@IEAA_N_K_N@Z */
503 static MSVCP_bool basic_string_wchar_grow(
504         basic_string_wchar *this, MSVCP_size_t new_size, MSVCP_bool trim)
505 {
506     if(this->res < new_size) {
507         MSVCP_size_t new_res = new_size, len = this->size;
508         wchar_t *ptr;
509
510         new_res |= 0xf;
511
512         if(new_res/3 < this->res/2)
513             new_res = this->res + this->res/2;
514
515         ptr = MSVCP_allocator_wchar_allocate(this->allocator, new_res+1);
516         if(!ptr)
517             ptr = MSVCP_allocator_wchar_allocate(this->allocator, new_size+1);
518         else
519             new_size = new_res;
520         if(!ptr) {
521             ERR("Out of memory\n");
522             basic_string_wchar_tidy(this, TRUE, 0);
523             return FALSE;
524         }
525
526         MSVCP_char_traits_wchar__Copy_s(ptr, new_size,
527                 basic_string_wchar_ptr(this), this->size);
528         basic_string_wchar_tidy(this, TRUE, 0);
529         this->data.ptr = ptr;
530         this->res = new_size;
531         basic_string_wchar_eos(this, len);
532     } else if(trim && new_size < BUF_SIZE_WCHAR)
533         basic_string_wchar_tidy(this, TRUE,
534                 new_size<this->size ? new_size : this->size);
535     else if(new_size == 0)
536         basic_string_wchar_eos(this, 0);
537
538     return (new_size>0);
539 }
540
541 /* ?erase@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAEAAV12@II@Z */
542 /* ?erase@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAAAEAV12@_K0@Z */
543 /* ?erase@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEAAV12@II@Z */
544 /* ?erase@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QEAAAEAV12@_K0@Z */
545 static basic_string_wchar* MSVCP_basic_string_wchar_erase(
546             basic_string_wchar *this, MSVCP_size_t pos, MSVCP_size_t len)
547 {
548     TRACE("%p %lu %lu\n", this, pos, len);
549
550     if(pos > this->size)
551         MSVCP__String_base_Xran();
552
553     if(len > this->size-pos)
554         len = this->size-pos;
555
556     if(len) {
557         MSVCP_char_traits_wchar__Move_s(basic_string_wchar_ptr(this)+pos,
558                 this->res-pos, basic_string_wchar_ptr(this)+pos+len,
559                 this->size-pos-len);
560         basic_string_wchar_eos(this, this->size-len);
561     }
562
563     return this;
564 }
565
566 /* ?assign@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAEAAV12@ABV12@II@Z */
567 /* ?assign@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAAAEAV12@AEBV12@_K1@Z */
568 /* ?assign@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEAAV12@ABV12@II@Z */
569 /* ?assign@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QEAAAEAV12@AEBV12@_K1@Z */
570 static basic_string_wchar* MSVCP_basic_string_wchar_assign_substr(
571             basic_string_wchar *this, const basic_string_wchar *assign,
572             MSVCP_size_t pos, MSVCP_size_t len)
573 {
574     TRACE("%p %p %lu %lu\n", this, assign, pos, len);
575
576     if(assign->size < pos)
577         MSVCP__String_base_Xran();
578
579     if(len > assign->size-pos)
580         len = assign->size-pos;
581
582     if(this == assign) {
583         MSVCP_basic_string_wchar_erase(this, pos+len, MSVCP_basic_string_wchar_npos);
584         MSVCP_basic_string_wchar_erase(this, 0, pos);
585     } else if(basic_string_wchar_grow(this, len, FALSE)) {
586         MSVCP_char_traits_wchar__Copy_s(basic_string_wchar_ptr(this),
587                 this->res, basic_string_wchar_const_ptr(assign)+pos, len);
588         basic_string_wchar_eos(this, len);
589     }
590
591     return this;
592 }
593
594 /* ?assign@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAEAAV12@PB_WI@Z */
595 /* ?assign@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAAAEAV12@PEB_W_K@Z */
596 /* ?assign@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEAAV12@PBGI@Z */
597 /* ?assign@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QEAAAEAV12@PEBG_K@Z */
598 static basic_string_wchar* MSVCP_basic_string_wchar_assign_cstr_len(
599             basic_string_wchar *this, const wchar_t *str, MSVCP_size_t len)
600 {
601     TRACE("%p %s %lu\n", this, debugstr_wn(str, len), len);
602
603     if(basic_string_wchar_inside(this, str))
604         return MSVCP_basic_string_wchar_assign_substr(this, this,
605                 str-basic_string_wchar_ptr(this), len);
606     else if(basic_string_wchar_grow(this, len, FALSE)) {
607         MSVCP_char_traits_wchar__Copy_s(basic_string_wchar_ptr(this),
608                 this->res, str, len);
609         basic_string_wchar_eos(this, len);
610     }
611
612     return this;
613 }
614
615 /* ?assign@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAEAAV12@PB_W@Z */
616 /* ?assign@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAAAEAV12@PEB_W@Z */
617 /* ??4?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAEAAV01@PB_W@Z */
618 /* ??4?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAAAEAV01@PEB_W@Z */
619 /* ?assign@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEAAV12@PBG@Z */
620 /* ?assign@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QEAAAEAV12@PEBG@Z */
621 /* ??4?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEAAV01@PBG@Z */
622 /* ??4?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QEAAAEAV01@PEBG@Z */
623 static basic_string_wchar* MSVCP_basic_string_wchar_assign_cstr(
624             basic_string_wchar *this, const wchar_t *str)
625 {
626     return MSVCP_basic_string_wchar_assign_cstr_len(this, str,
627             MSVCP_char_traits_wchar_length(str));
628 }
629
630 /* ?c_str@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QBEPB_WXZ */
631 /* ?c_str@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEBAPEB_WXZ */
632 /* ?data@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QBEPB_WXZ */
633 /* ?data@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEBAPEB_WXZ */
634 /* ?c_str@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBEPBGXZ */
635 /* ?c_str@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QEBAPEBGXZ */
636 /* ?data@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBEPBGXZ */
637 /* ?data@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QEBAPEBGXZ */
638 const wchar_t* MSVCP_basic_string_wchar_c_str(const basic_string_wchar *this)
639 {
640     TRACE("%p\n", this);
641     return basic_string_wchar_const_ptr(this);
642 }
643
644 /* ??0?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAE@PB_W@Z */
645 /* ??0?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAA@PEB_W@Z */
646 /* ??0?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAE@PBG@Z */
647 /* ??0?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QEAA@PEBG@Z */
648 basic_string_wchar* MSVCP_basic_string_wchar_ctor_cstr(
649             basic_string_wchar *this, const wchar_t *str)
650 {
651     TRACE("%p %s\n", this, debugstr_w(str));
652
653     basic_string_wchar_tidy(this, FALSE, 0);
654     MSVCP_basic_string_wchar_assign_cstr(this, str);
655     return this;
656 }
657
658 /* ??1?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAE@XZ */
659 /* ??1?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAA@XZ */
660 /* ??1?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAE@XZ */
661 /* ??1?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QEAA@XZ */
662 void MSVCP_basic_string_wchar_dtor(basic_string_wchar *this)
663 {
664     TRACE("%p\n", this);
665     basic_string_wchar_tidy(this, TRUE, 0);
666 }
667
668 /* ?size@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QBEIXZ */
669 /* ?size@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEBA_KXZ */
670 /* ?length@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QBEIXZ */
671 /* ?length@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEBA_KXZ */
672 /* ?size@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBEIXZ */
673 /* ?size@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QEBA_KXZ */
674 /* ?length@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBEIXZ */
675 /* ?length@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QEBA_KXZ */
676 MSVCP_size_t MSVCP_basic_string_wchar_length(const basic_string_wchar *this)
677 {
678     TRACE("%p\n", this);
679     return this->size;
680 }
681
682 /* ??0?$_Yarn@D@std@@QAE@XZ */
683 /* ??0?$_Yarn@D@std@@QEAA@XZ */
684 DEFINE_THISCALL_WRAPPER(_Yarn_char_ctor, 4)
685 _Yarn_char* __thiscall _Yarn_char_ctor(_Yarn_char *this)
686 {
687     TRACE("(%p)\n", this);
688
689     this->str = NULL;
690     this->null_str = '\0';
691     return this;
692 }
693
694 /* ?_Tidy@?$_Yarn@D@std@@AAEXXZ */
695 /* ?_Tidy@?$_Yarn@D@std@@AEAAXXZ */
696 DEFINE_THISCALL_WRAPPER(_Yarn_char__Tidy, 4)
697 void __thiscall _Yarn_char__Tidy(_Yarn_char *this)
698 {
699     TRACE("(%p)\n", this);
700
701     if(this->str)
702         MSVCRT_operator_delete(this->str);
703     this->str = NULL;
704 }
705
706 /* ??4?$_Yarn@D@std@@QAEAAV01@PBD@Z */
707 /* ??4?$_Yarn@D@std@@QEAAAEAV01@PEBD@Z */
708 DEFINE_THISCALL_WRAPPER(_Yarn_char_op_assign_cstr, 8)
709 _Yarn_char* __thiscall _Yarn_char_op_assign_cstr(_Yarn_char *this, const char *str)
710 {
711     TRACE("(%p %p)\n", this, str);
712
713     _Yarn_char__Tidy(this);
714
715     if(str) {
716         MSVCP_size_t len = strlen(str);
717
718         this->str = MSVCRT_operator_new((len+1)*sizeof(char));
719         if(!this->str) {
720             ERR("out of memory\n");
721             return NULL;
722         }
723         memcpy(this->str, str, (len+1)*sizeof(char));
724     }
725     return this;
726 }
727
728 /* ??0?$_Yarn@D@std@@QAE@PBD@Z */
729 /* ??0?$_Yarn@D@std@@QEAA@PEBD@Z */
730 DEFINE_THISCALL_WRAPPER(_Yarn_char_ctor_cstr, 8)
731 _Yarn_char* __thiscall _Yarn_char_ctor_cstr(_Yarn_char *this, const char *str)
732 {
733     TRACE("(%p %p)\n", this, str);
734
735     _Yarn_char_ctor(this);
736     return _Yarn_char_op_assign_cstr(this, str);
737 }
738
739 /* ??4?$_Yarn@D@std@@QAEAAV01@ABV01@@Z */
740 /* ??4?$_Yarn@D@std@@QEAAAEAV01@AEBV01@@Z */
741 DEFINE_THISCALL_WRAPPER(_Yarn_char_op_assign, 8)
742 _Yarn_char* __thiscall _Yarn_char_op_assign(_Yarn_char *this, const _Yarn_char *rhs)
743 {
744     TRACE("(%p %p)\n", this, rhs);
745
746     return _Yarn_char_op_assign_cstr(this, rhs->str);
747 }
748
749 /* ??0?$_Yarn@D@std@@QAE@ABV01@@Z */
750 /* ??0?$_Yarn@D@std@@QEAA@AEBV01@@Z */
751 DEFINE_THISCALL_WRAPPER(_Yarn_char_copy_ctor, 8)
752 _Yarn_char* __thiscall _Yarn_char_copy_ctor(_Yarn_char *this, const _Yarn_char *copy)
753 {
754     TRACE("(%p %p)\n", this, copy);
755
756     _Yarn_char_ctor(this);
757     return _Yarn_char_op_assign(this, copy);
758 }
759
760 /* ??1?$_Yarn@D@std@@QAE@XZ */
761 /* ??1?$_Yarn@D@std@@QEAA@XZ */
762 DEFINE_THISCALL_WRAPPER(_Yarn_char_dtor, 4)
763 void __thiscall _Yarn_char_dtor(_Yarn_char *this)
764 {
765     TRACE("(%p)\n", this);
766     _Yarn_char__Tidy(this);
767 }
768
769 /* ?_C_str@?$_Yarn@D@std@@QBEPBDXZ */
770 /* ?_C_str@?$_Yarn@D@std@@QEBAPEBDXZ */
771 /* ?c_str@?$_Yarn@D@std@@QBEPBDXZ */
772 /* ?c_str@?$_Yarn@D@std@@QEBAPEBDXZ */
773 DEFINE_THISCALL_WRAPPER(_Yarn_char_c_str, 4)
774 const char* __thiscall _Yarn_char_c_str(const _Yarn_char *this)
775 {
776     TRACE("(%p)\n", this);
777     return this->str ? this->str : &this->null_str;
778 }
779
780 /* ?_Empty@?$_Yarn@D@std@@QBE_NXZ */
781 /* ?_Empty@?$_Yarn@D@std@@QEBA_NXZ */
782 /* ?empty@?$_Yarn@D@std@@QBE_NXZ */
783 /* ?empty@?$_Yarn@D@std@@QEBA_NXZ */
784 DEFINE_THISCALL_WRAPPER(_Yarn_char_empty, 4)
785 MSVCP_bool __thiscall _Yarn_char_empty(const _Yarn_char *this)
786 {
787     TRACE("(%p)\n", this);
788     return !this->str;
789 }