xref: /reactos/dll/win32/riched20/string.c (revision 64527aa9)
1 /*
2  * RichEdit - string operations
3  *
4  * Copyright 2004 by Krzysztof Foltman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "editor.h"
22 
23 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
24 
ME_GetOptimalBuffer(int nLen)25 static int ME_GetOptimalBuffer(int nLen)
26 {
27   return ((sizeof(WCHAR) * nLen) + 128) & ~63;
28 }
29 
make_string(void (* free)(ME_String *))30 static ME_String *make_string( void (*free)(ME_String *) )
31 {
32   ME_String *s = heap_alloc( sizeof(*s) );
33 
34   if (s) s->free = free;
35   return s;
36 }
37 
38 /* Create a ME_String using the const string provided.
39  * str must exist for the lifetime of the returned ME_String.
40  */
ME_MakeStringConst(const WCHAR * str,int len)41 ME_String *ME_MakeStringConst(const WCHAR *str, int len)
42 {
43   ME_String *s = make_string( NULL );
44   if (!s) return NULL;
45 
46   s->szData = (WCHAR *)str;
47   s->nLen = len;
48   s->nBuffer = 0;
49   return s;
50 }
51 
heap_string_free(ME_String * s)52 static void heap_string_free(ME_String *s)
53 {
54   heap_free( s->szData );
55 }
56 
57 /* Create a buffer (uninitialized string) of size nMaxChars */
ME_MakeStringEmpty(int nMaxChars)58 ME_String *ME_MakeStringEmpty(int nMaxChars)
59 {
60   ME_String *s = make_string( heap_string_free );
61 
62   if (!s) return NULL;
63   s->nLen = nMaxChars;
64   s->nBuffer = ME_GetOptimalBuffer(s->nLen + 1);
65   s->szData = heap_alloc( s->nBuffer * sizeof(WCHAR) );
66   if (!s->szData)
67   {
68     heap_free( s );
69     return NULL;
70   }
71   s->szData[s->nLen] = 0;
72   return s;
73 }
74 
ME_MakeStringN(LPCWSTR szText,int nMaxChars)75 ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars)
76 {
77   ME_String *s = ME_MakeStringEmpty(nMaxChars);
78 
79   if (!s) return NULL;
80   memcpy(s->szData, szText, s->nLen * sizeof(WCHAR));
81   return s;
82 }
83 
84 /* Make a string by repeating a char nMaxChars times */
ME_MakeStringR(WCHAR cRepeat,int nMaxChars)85 ME_String *ME_MakeStringR(WCHAR cRepeat, int nMaxChars)
86 {
87   int i;
88   ME_String *s = ME_MakeStringEmpty(nMaxChars);
89 
90   if (!s) return NULL;
91   for (i = 0; i < nMaxChars; i++)
92     s->szData[i] = cRepeat;
93   return s;
94 }
95 
ME_DestroyString(ME_String * s)96 void ME_DestroyString(ME_String *s)
97 {
98   if (!s) return;
99   if (s->free) s->free( s );
100   heap_free( s );
101 }
102 
ME_InsertString(ME_String * s,int ofs,const WCHAR * insert,int len)103 BOOL ME_InsertString(ME_String *s, int ofs, const WCHAR *insert, int len)
104 {
105     DWORD new_len = s->nLen + len + 1;
106     WCHAR *new;
107 
108     assert( s->nBuffer ); /* Not a const string */
109     assert( ofs <= s->nLen );
110 
111     if( new_len > s->nBuffer )
112     {
113         s->nBuffer = ME_GetOptimalBuffer( new_len );
114         new = heap_realloc( s->szData, s->nBuffer * sizeof(WCHAR) );
115         if (!new) return FALSE;
116         s->szData = new;
117     }
118 
119     memmove( s->szData + ofs + len, s->szData + ofs, (s->nLen - ofs + 1) * sizeof(WCHAR) );
120     memcpy( s->szData + ofs, insert, len * sizeof(WCHAR) );
121     s->nLen += len;
122 
123     return TRUE;
124 }
125 
ME_AppendString(ME_String * s,const WCHAR * append,int len)126 BOOL ME_AppendString(ME_String *s, const WCHAR *append, int len)
127 {
128     return ME_InsertString( s, s->nLen, append, len );
129 }
130 
ME_VSplitString(ME_String * orig,int charidx)131 ME_String *ME_VSplitString(ME_String *orig, int charidx)
132 {
133   ME_String *s;
134 
135   assert(orig->nBuffer); /* Not a const string */
136   assert(charidx>=0);
137   assert(charidx<=orig->nLen);
138 
139   s = ME_MakeStringN(orig->szData+charidx, orig->nLen-charidx);
140   if (!s) return NULL;
141 
142   orig->nLen = charidx;
143   orig->szData[charidx] = '\0';
144   return s;
145 }
146 
ME_StrDeleteV(ME_String * s,int nVChar,int nChars)147 void ME_StrDeleteV(ME_String *s, int nVChar, int nChars)
148 {
149   int end_ofs = nVChar + nChars;
150 
151   assert(s->nBuffer); /* Not a const string */
152   assert(nChars >= 0);
153   assert(nVChar >= 0);
154   assert(end_ofs <= s->nLen);
155 
156   memmove(s->szData + nVChar, s->szData + end_ofs,
157           (s->nLen - end_ofs + 1) * sizeof(WCHAR));
158   s->nLen -= nChars;
159 }
160 
161 static int
ME_WordBreakProc(LPWSTR s,INT start,INT len,INT code)162 ME_WordBreakProc(LPWSTR s, INT start, INT len, INT code)
163 {
164 #ifndef __REACTOS__
165   /* FIXME: Native also knows about punctuation */
166 #endif
167   TRACE("s==%s, start==%d, len==%d, code==%d\n",
168         debugstr_wn(s, len), start, len, code);
169 
170   switch (code)
171   {
172     case WB_ISDELIMITER:
173       return ME_IsWSpace(s[start]);
174     case WB_LEFT:
175     case WB_MOVEWORDLEFT:
176       while (start && ME_IsWSpace(s[start - 1]))
177         start--;
178 #ifdef __REACTOS__
179       while (start && !ME_IsWSpace(s[start - 1]) && !iswpunct(s[start - 1]))
180         start--;
181 #else
182       while (start && !ME_IsWSpace(s[start - 1]))
183         start--;
184 #endif
185       return start;
186     case WB_RIGHT:
187     case WB_MOVEWORDRIGHT:
188 #ifdef __REACTOS__
189       while (start < len && !ME_IsWSpace(s[start]) && !iswpunct(s[start]))
190         start++;
191 #else
192       while (start < len && !ME_IsWSpace(s[start]))
193         start++;
194 #endif
195       while (start < len && ME_IsWSpace(s[start]))
196         start++;
197       return start;
198   }
199   return 0;
200 }
201 
202 
203 int
ME_CallWordBreakProc(ME_TextEditor * editor,WCHAR * str,INT len,INT start,INT code)204 ME_CallWordBreakProc(ME_TextEditor *editor, WCHAR *str, INT len, INT start, INT code)
205 {
206   if (!editor->pfnWordBreak) {
207     return ME_WordBreakProc(str, start, len, code);
208   } else if (!editor->bEmulateVersion10) {
209     /* MSDN lied about the third parameter for EditWordBreakProc being the number
210      * of characters, it is actually the number of bytes of the string. */
211     return editor->pfnWordBreak(str, start, len * sizeof(WCHAR), code);
212   } else {
213     int result;
214     int buffer_size = WideCharToMultiByte(CP_ACP, 0, str, len,
215                                           NULL, 0, NULL, NULL);
216     char *buffer = heap_alloc(buffer_size);
217     if (!buffer) return 0;
218     WideCharToMultiByte(CP_ACP, 0, str, len,
219                         buffer, buffer_size, NULL, NULL);
220     result = editor->pfnWordBreak((WCHAR*)buffer, start, buffer_size, code);
221     heap_free(buffer);
222     return result;
223   }
224 }
225 
ME_ToUnicode(LONG codepage,LPVOID psz,INT * len)226 LPWSTR ME_ToUnicode(LONG codepage, LPVOID psz, INT *len)
227 {
228   *len = 0;
229   if (!psz) return NULL;
230 
231   if (codepage == CP_UNICODE)
232   {
233     *len = lstrlenW(psz);
234     return psz;
235   }
236   else {
237     WCHAR *tmp;
238     int nChars = MultiByteToWideChar(codepage, 0, psz, -1, NULL, 0);
239 
240     if(!nChars) return NULL;
241 
242     if((tmp = heap_alloc( nChars * sizeof(WCHAR) )) != NULL)
243       *len = MultiByteToWideChar(codepage, 0, psz, -1, tmp, nChars) - 1;
244     return tmp;
245   }
246 }
247 
ME_EndToUnicode(LONG codepage,LPVOID psz)248 void ME_EndToUnicode(LONG codepage, LPVOID psz)
249 {
250   if (codepage != CP_UNICODE)
251     heap_free( psz );
252 }
253