- RTF reader doesn't use RichEdit messages anymore (which saves on
[wine] / dlls / riched20 / string.c
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "editor.h"     
22
23 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
24
25 int ME_GetOptimalBuffer(int nLen)
26 {
27   return ((2*nLen+1)+128)&~63;
28 }
29
30 ME_String *ME_MakeString(LPCWSTR szText)
31 {
32   ME_String *s = ALLOC_OBJ(ME_String);
33   s->nLen = lstrlenW(szText);
34   s->nBuffer = ME_GetOptimalBuffer(s->nLen+1);
35   s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer);
36   lstrcpyW(s->szData, szText);
37   return s;
38 }
39
40 ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars)
41 {
42   ME_String *s = ALLOC_OBJ(ME_String);
43   int i;
44   for (i=0; i<nMaxChars && szText[i]; i++)
45     ;
46   s->nLen = i;
47   s->nBuffer = ME_GetOptimalBuffer(s->nLen+1);
48   s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer);
49   lstrcpynW(s->szData, szText, s->nLen+1);
50   return s;
51 }
52
53 ME_String *ME_StrDup(ME_String *s)
54 {
55   return ME_MakeStringN(s->szData, s->nLen);
56 }
57
58 void ME_DestroyString(ME_String *s)
59 {
60   FREE_OBJ(s->szData);
61   FREE_OBJ(s);
62 }
63
64 void ME_AppendString(ME_String *s1, ME_String *s2)
65 {
66   if (s1->nLen+s2->nLen+1 <= s1->nBuffer) {
67     lstrcpyW(s1->szData+s1->nLen, s2->szData);
68     s1->nLen += s2->nLen;
69   }
70   else
71   {
72     WCHAR *buf;
73     s1->nBuffer = ME_GetOptimalBuffer(s1->nLen+s2->nLen+1);
74
75     buf = ALLOC_N_OBJ(WCHAR, s1->nBuffer); 
76     lstrcpyW(buf, s1->szData);
77     lstrcpyW(buf+s1->nLen, s2->szData);
78     FREE_OBJ(s1->szData);
79     s1->szData = buf;
80     s1->nLen += s2->nLen;
81   }
82 }
83
84 ME_String *ME_ConcatString(ME_String *s1, ME_String *s2)
85 {
86   ME_String *s = ALLOC_OBJ(ME_String);
87   s->nLen = s1->nLen+s2->nLen;
88   s->nBuffer = ME_GetOptimalBuffer(s1->nLen+s2->nLen+1);
89   s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer);
90   lstrcpyW(s->szData, s1->szData);
91   lstrcpyW(s->szData+s1->nLen, s2->szData);
92   return s;  
93 }
94
95 ME_String *ME_VSplitString(ME_String *orig, int charidx)
96 {
97   ME_String *s;
98
99   /*if (charidx<0) charidx = 0;
100   if (charidx>orig->nLen) charidx = orig->nLen;
101   */
102   assert(charidx>=0);
103   assert(charidx<=orig->nLen);
104
105   s = ME_MakeString(orig->szData+charidx);
106   orig->nLen = charidx;
107   orig->szData[charidx] = L'\0';
108   return s;
109 }
110
111 int ME_IsWhitespaces(ME_String *s)
112 {
113   /* FIXME multibyte */
114   WCHAR *pos = s->szData;
115   while(ME_IsWSpace(*pos++))
116     ;
117   pos--;
118   if (*pos)
119     return 0;
120   else
121     return 1;
122 }
123
124 int ME_IsSplitable(ME_String *s)
125 {
126   /* FIXME multibyte */
127   WCHAR *pos = s->szData;
128   WCHAR ch;
129   while(ME_IsWSpace(*pos++))
130     ;
131   pos--;
132   while((ch = *pos++) != 0)
133   {
134     if (ME_IsWSpace(*pos++))
135       return 1;
136   }
137   return 0;
138 }
139
140 /* FIXME multibyte */
141 /*
142 int ME_CalcSkipChars(ME_String *s)
143 {
144   int cnt = 0;
145   while(cnt < s->nLen && s->szData[s->nLen-1-cnt]==' ')
146     cnt++;
147   return cnt;
148 }
149 */
150
151 int ME_StrLen(ME_String *s) { 
152   return s->nLen;
153 }
154
155 int ME_StrVLen(ME_String *s) {
156   return s->nLen;
157 }
158
159 /* FIXME we use widechars, not multibytes, inside, no need for complex logic anymore */
160 int ME_StrRelPos(ME_String *s, int nVChar, int *pRelChars)
161 {
162   TRACE("%s,%d,&%d\n", debugstr_w(s->szData), nVChar, *pRelChars);
163
164   assert(*pRelChars);
165   if (!*pRelChars) return nVChar;
166   
167   if (*pRelChars>0)
168   {
169     while(nVChar<s->nLen && *pRelChars>0)
170     {
171       nVChar++;
172       (*pRelChars)--;
173     }
174     return nVChar;
175   }
176
177   while(nVChar>0 && *pRelChars<0)
178   {
179     nVChar--;
180     (*pRelChars)++;
181   }
182   return nVChar;
183 }
184
185 int ME_StrRelPos2(ME_String *s, int nVChar, int nRelChars)
186 {
187   return ME_StrRelPos(s, nVChar, &nRelChars);
188 }
189
190 int ME_VPosToPos(ME_String *s, int nVPos)
191 {
192   return nVPos;
193   /*
194   int i = 0, len = 0;
195   if (!nVPos)
196     return 0;
197   while (i < s->nLen)
198   {
199     if (i == nVPos)
200       return len;
201     if (s->szData[i]=='\\') i++;
202     i++;
203     len++;
204   }
205   return len;
206   */
207 }
208
209 int ME_PosToVPos(ME_String *s, int nPos)
210 {
211   if (!nPos)
212     return 0;
213   return ME_StrRelPos2(s, 0, nPos);
214 }
215
216 void ME_StrDeleteV(ME_String *s, int nVChar, int nChars)
217 {
218   int end_ofs;
219   
220   assert(nVChar >=0 && nVChar <= s->nLen);
221   assert(nChars >= 0);
222   assert(nVChar+nChars <= s->nLen);
223   
224   end_ofs = ME_StrRelPos2(s, nVChar, nChars);
225   assert(end_ofs <= s->nLen);
226   memmove(s->szData+nVChar, s->szData+end_ofs, 2*(s->nLen+1-end_ofs));
227   s->nLen -= (end_ofs - nVChar);
228 }
229
230 int ME_GetCharFwd(ME_String *s, int nPos)
231 {
232   int nVPos = 0;
233   
234   assert(nPos < ME_StrLen(s));
235   if (nPos)
236     nVPos = ME_StrRelPos2(s, nVPos, nPos);
237   
238   if (nVPos < s->nLen)
239     return s->szData[nVPos];
240   return -1;
241 }
242
243 int ME_GetCharBack(ME_String *s, int nPos)
244 {
245   int nVPos = ME_StrVLen(s);
246   
247   assert(nPos < ME_StrLen(s));
248   if (nPos)
249     nVPos = ME_StrRelPos2(s, nVPos, -nPos);
250   
251   if (nVPos < s->nLen)
252     return s->szData[nVPos];
253   return -1;
254 }
255
256 int ME_FindNonWhitespaceV(ME_String *s, int nVChar) {
257   int i;
258   for (i = nVChar; isspace(s->szData[i]) && i<s->nLen; i++)
259     ;
260     
261   return i;
262 }
263
264 /* note: returns offset of the first trailing whitespace */
265 int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) {
266   int i;
267   for (i = nVChar; i>0 && isspace(s->szData[i-1]); i--)
268     ;
269     
270   return i;
271 }
272
273 /* note: returns offset of the first trailing nonwhitespace */
274 int ME_ReverseFindWhitespaceV(ME_String *s, int nVChar) {
275   int i;
276   for (i = nVChar; i>0 && !isspace(s->szData[i-1]); i--)
277     ;
278     
279   return i;
280 }
281
282 LPWSTR ME_ToUnicode(HWND hWnd, LPVOID psz)
283 {
284   if (IsWindowUnicode(hWnd))
285     return (LPWSTR)psz;
286   else {
287     WCHAR *tmp;
288     int nChars = MultiByteToWideChar(CP_ACP, 0, (char *)psz, -1, NULL, 0);
289     if((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL)
290       MultiByteToWideChar(CP_ACP, 0, (char *)psz, -1, tmp, nChars);
291     return tmp;
292   }
293 }
294
295 void ME_EndToUnicode(HWND hWnd, LPVOID psz)
296 {
297   if (IsWindowUnicode(hWnd))
298     FREE_OBJ(psz);
299 }
300
301 LPSTR ME_ToAnsi(HWND hWnd, LPVOID psz)
302 {
303   if (!IsWindowUnicode(hWnd))
304     return (LPSTR)psz;
305   else {
306     char *tmp;
307     int nChars = WideCharToMultiByte(CP_ACP, 0, (WCHAR *)psz, -1, NULL, 0, NULL, NULL);
308     if((tmp = ALLOC_N_OBJ(char, nChars)) != NULL)
309       WideCharToMultiByte(CP_ACP, 0, (WCHAR *)psz, -1, tmp, nChars, NULL, NULL);
310     return tmp;
311   }
312 }
313
314 void ME_EndToAnsi(HWND hWnd, LPVOID psz)
315 {
316   if (!IsWindowUnicode(hWnd))
317     FREE_OBJ(psz);
318 }