Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 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 |
Jonathan Ernst | 360a3f9 | 2006-05-18 14:49:52 +0200 | [diff] [blame] | 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 19 | */ |
| 20 | |
Dylan Smith | 4b7e8f1 | 2009-02-07 13:20:55 -0500 | [diff] [blame] | 21 | #include "editor.h" |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 22 | |
| 23 | WINE_DEFAULT_DEBUG_CHANNEL(richedit); |
| 24 | |
Andrew Talbot | b53d7d3 | 2009-01-17 16:27:08 +0000 | [diff] [blame] | 25 | static int ME_GetOptimalBuffer(int nLen) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 26 | { |
Dylan Smith | 4b7e8f1 | 2009-02-07 13:20:55 -0500 | [diff] [blame] | 27 | /* FIXME: This seems wasteful for tabs and end of lines strings, |
| 28 | * since they have a small fixed length. */ |
| 29 | return ((sizeof(WCHAR) * nLen) + 128) & ~63; |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 30 | } |
| 31 | |
Dylan Smith | 4b7e8f1 | 2009-02-07 13:20:55 -0500 | [diff] [blame] | 32 | /* Create a buffer (uninitialized string) of size nMaxChars */ |
| 33 | static ME_String *ME_MakeStringB(int nMaxChars) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 34 | { |
| 35 | ME_String *s = ALLOC_OBJ(ME_String); |
Dylan Smith | 4b7e8f1 | 2009-02-07 13:20:55 -0500 | [diff] [blame] | 36 | |
| 37 | s->nLen = nMaxChars; |
| 38 | s->nBuffer = ME_GetOptimalBuffer(s->nLen + 1); |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 39 | s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer); |
Dylan Smith | 4b7e8f1 | 2009-02-07 13:20:55 -0500 | [diff] [blame] | 40 | s->szData[s->nLen] = 0; |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 41 | return s; |
| 42 | } |
| 43 | |
| 44 | ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars) |
| 45 | { |
Dylan Smith | 4b7e8f1 | 2009-02-07 13:20:55 -0500 | [diff] [blame] | 46 | ME_String *s = ME_MakeStringB(nMaxChars); |
| 47 | /* Native allows NULL chars */ |
| 48 | memcpy(s->szData, szText, s->nLen * sizeof(WCHAR)); |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 49 | return s; |
| 50 | } |
| 51 | |
Dylan Smith | 4b7e8f1 | 2009-02-07 13:20:55 -0500 | [diff] [blame] | 52 | /* Make a string by repeating a char nMaxChars times */ |
Matt Finnicum | 2b92bf7 | 2006-08-04 15:47:44 -0400 | [diff] [blame] | 53 | ME_String *ME_MakeStringR(WCHAR cRepeat, int nMaxChars) |
Dylan Smith | 4b7e8f1 | 2009-02-07 13:20:55 -0500 | [diff] [blame] | 54 | { |
Matt Finnicum | 2b92bf7 | 2006-08-04 15:47:44 -0400 | [diff] [blame] | 55 | int i; |
Dylan Smith | 4b7e8f1 | 2009-02-07 13:20:55 -0500 | [diff] [blame] | 56 | ME_String *s = ME_MakeStringB(nMaxChars); |
| 57 | for (i = 0; i < nMaxChars; i++) |
Matt Finnicum | 2b92bf7 | 2006-08-04 15:47:44 -0400 | [diff] [blame] | 58 | s->szData[i] = cRepeat; |
Matt Finnicum | 2b92bf7 | 2006-08-04 15:47:44 -0400 | [diff] [blame] | 59 | return s; |
| 60 | } |
| 61 | |
Andrew Talbot | 291dd7a | 2007-08-15 21:35:51 +0100 | [diff] [blame] | 62 | ME_String *ME_StrDup(const ME_String *s) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 63 | { |
| 64 | return ME_MakeStringN(s->szData, s->nLen); |
| 65 | } |
| 66 | |
| 67 | void ME_DestroyString(ME_String *s) |
| 68 | { |
Dylan Smith | 5d74f58 | 2009-01-28 01:34:56 -0500 | [diff] [blame] | 69 | if (!s) return; |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 70 | FREE_OBJ(s->szData); |
| 71 | FREE_OBJ(s); |
| 72 | } |
| 73 | |
Andrew Talbot | 291dd7a | 2007-08-15 21:35:51 +0100 | [diff] [blame] | 74 | void ME_AppendString(ME_String *s1, const ME_String *s2) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 75 | { |
Dylan Smith | f53f40b | 2009-02-07 13:20:46 -0500 | [diff] [blame] | 76 | if (s1->nLen+s2->nLen+1 <= s1->nBuffer) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 77 | { |
Dylan Smith | f53f40b | 2009-02-07 13:20:46 -0500 | [diff] [blame] | 78 | memcpy(s1->szData + s1->nLen, s2->szData, s2->nLen * sizeof(WCHAR)); |
| 79 | s1->nLen += s2->nLen; |
| 80 | s1->szData[s1->nLen] = 0; |
| 81 | } else { |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 82 | WCHAR *buf; |
| 83 | s1->nBuffer = ME_GetOptimalBuffer(s1->nLen+s2->nLen+1); |
| 84 | |
Dylan Smith | f53f40b | 2009-02-07 13:20:46 -0500 | [diff] [blame] | 85 | buf = ALLOC_N_OBJ(WCHAR, s1->nBuffer); |
| 86 | memcpy(buf, s1->szData, s1->nLen * sizeof(WCHAR)); |
| 87 | memcpy(buf + s1->nLen, s2->szData, s2->nLen * sizeof(WCHAR)); |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 88 | FREE_OBJ(s1->szData); |
| 89 | s1->szData = buf; |
| 90 | s1->nLen += s2->nLen; |
Dylan Smith | f53f40b | 2009-02-07 13:20:46 -0500 | [diff] [blame] | 91 | s1->szData[s1->nLen] = 0; |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 92 | } |
| 93 | } |
| 94 | |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 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 | |
Dylan Smith | 6d76d43 | 2008-06-25 11:33:26 -0400 | [diff] [blame] | 105 | s = ME_MakeStringN(orig->szData+charidx, orig->nLen-charidx); |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 106 | orig->nLen = charidx; |
Michael Stefaniuc | df01f67 | 2007-06-21 22:56:17 +0200 | [diff] [blame] | 107 | orig->szData[charidx] = '\0'; |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 108 | return s; |
| 109 | } |
| 110 | |
Andrew Talbot | 291dd7a | 2007-08-15 21:35:51 +0100 | [diff] [blame] | 111 | int ME_IsWhitespaces(const ME_String *s) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 112 | { |
| 113 | /* FIXME multibyte */ |
| 114 | WCHAR *pos = s->szData; |
Krzysztof Foltman | f089de1 | 2005-03-17 10:23:40 +0000 | [diff] [blame] | 115 | while(ME_IsWSpace(*pos++)) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 116 | ; |
| 117 | pos--; |
| 118 | if (*pos) |
| 119 | return 0; |
| 120 | else |
| 121 | return 1; |
| 122 | } |
| 123 | |
Andrew Talbot | 291dd7a | 2007-08-15 21:35:51 +0100 | [diff] [blame] | 124 | int ME_IsSplitable(const ME_String *s) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 125 | { |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 126 | WCHAR *pos = s->szData; |
| 127 | WCHAR ch; |
Krzysztof Foltman | f089de1 | 2005-03-17 10:23:40 +0000 | [diff] [blame] | 128 | while(ME_IsWSpace(*pos++)) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 129 | ; |
| 130 | pos--; |
| 131 | while((ch = *pos++) != 0) |
| 132 | { |
Krzysztof Foltman | 810b261 | 2005-03-19 17:06:17 +0000 | [diff] [blame] | 133 | if (ME_IsWSpace(ch)) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 134 | return 1; |
| 135 | } |
| 136 | return 0; |
| 137 | } |
| 138 | |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 139 | void ME_StrDeleteV(ME_String *s, int nVChar, int nChars) |
| 140 | { |
Dylan Smith | c8b4455 | 2009-02-07 13:21:29 -0500 | [diff] [blame] | 141 | int end_ofs = nVChar + nChars; |
| 142 | |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 143 | assert(nChars >= 0); |
Dylan Smith | c8b4455 | 2009-02-07 13:21:29 -0500 | [diff] [blame] | 144 | assert(nVChar >= 0); |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 145 | assert(end_ofs <= s->nLen); |
Dylan Smith | c8b4455 | 2009-02-07 13:21:29 -0500 | [diff] [blame] | 146 | |
| 147 | memmove(s->szData + nVChar, s->szData + end_ofs, |
| 148 | (s->nLen - end_ofs + 1) * sizeof(WCHAR)); |
| 149 | s->nLen -= nChars; |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 150 | } |
| 151 | |
Andrew Talbot | 291dd7a | 2007-08-15 21:35:51 +0100 | [diff] [blame] | 152 | int ME_FindNonWhitespaceV(const ME_String *s, int nVChar) { |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 153 | int i; |
Krzysztof Foltman | 810b261 | 2005-03-19 17:06:17 +0000 | [diff] [blame] | 154 | for (i = nVChar; i<s->nLen && ME_IsWSpace(s->szData[i]); i++) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 155 | ; |
| 156 | |
| 157 | return i; |
| 158 | } |
| 159 | |
| 160 | /* note: returns offset of the first trailing whitespace */ |
Andrew Talbot | 291dd7a | 2007-08-15 21:35:51 +0100 | [diff] [blame] | 161 | int ME_ReverseFindNonWhitespaceV(const ME_String *s, int nVChar) { |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 162 | int i; |
Krzysztof Foltman | 810b261 | 2005-03-19 17:06:17 +0000 | [diff] [blame] | 163 | for (i = nVChar; i>0 && ME_IsWSpace(s->szData[i-1]); i--) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 164 | ; |
| 165 | |
| 166 | return i; |
| 167 | } |
| 168 | |
| 169 | /* note: returns offset of the first trailing nonwhitespace */ |
Andrew Talbot | 291dd7a | 2007-08-15 21:35:51 +0100 | [diff] [blame] | 170 | int ME_ReverseFindWhitespaceV(const ME_String *s, int nVChar) { |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 171 | int i; |
Krzysztof Foltman | 810b261 | 2005-03-19 17:06:17 +0000 | [diff] [blame] | 172 | for (i = nVChar; i>0 && !ME_IsWSpace(s->szData[i-1]); i--) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 173 | ; |
| 174 | |
| 175 | return i; |
| 176 | } |
| 177 | |
Phil Krylov | 49eecf5 | 2006-01-12 11:54:57 +0100 | [diff] [blame] | 178 | |
| 179 | static int |
| 180 | ME_WordBreakProc(LPWSTR s, INT start, INT len, INT code) |
| 181 | { |
| 182 | /* FIXME: Native also knows about punctuation */ |
| 183 | TRACE("s==%s, start==%d, len==%d, code==%d\n", |
| 184 | debugstr_wn(s, len), start, len, code); |
Dylan Smith | 5039729 | 2008-10-23 01:07:31 -0400 | [diff] [blame] | 185 | /* convert number of bytes to number of characters. */ |
| 186 | len /= sizeof(WCHAR); |
Phil Krylov | 49eecf5 | 2006-01-12 11:54:57 +0100 | [diff] [blame] | 187 | switch (code) |
| 188 | { |
| 189 | case WB_ISDELIMITER: |
| 190 | return ME_IsWSpace(s[start]); |
| 191 | case WB_LEFT: |
| 192 | case WB_MOVEWORDLEFT: |
| 193 | while (start && ME_IsWSpace(s[start - 1])) |
| 194 | start--; |
| 195 | while (start && !ME_IsWSpace(s[start - 1])) |
| 196 | start--; |
| 197 | return start; |
| 198 | case WB_RIGHT: |
| 199 | case WB_MOVEWORDRIGHT: |
Dylan Smith | ba747f4 | 2008-06-25 11:33:19 -0400 | [diff] [blame] | 200 | while (start < len && !ME_IsWSpace(s[start])) |
| 201 | start++; |
| 202 | while (start < len && ME_IsWSpace(s[start])) |
| 203 | start++; |
Phil Krylov | 49eecf5 | 2006-01-12 11:54:57 +0100 | [diff] [blame] | 204 | return start; |
| 205 | } |
| 206 | return 0; |
| 207 | } |
| 208 | |
| 209 | |
| 210 | int |
| 211 | ME_CallWordBreakProc(ME_TextEditor *editor, ME_String *str, INT start, INT code) |
| 212 | { |
Dylan Smith | 5039729 | 2008-10-23 01:07:31 -0400 | [diff] [blame] | 213 | if (!editor->pfnWordBreak) { |
| 214 | return ME_WordBreakProc(str->szData, start, str->nLen*sizeof(WCHAR), code); |
| 215 | } else if (!editor->bEmulateVersion10) { |
| 216 | /* MSDN lied about the third parameter for EditWordBreakProc being the number |
| 217 | * of characters, it is actually the number of bytes of the string. */ |
| 218 | return editor->pfnWordBreak(str->szData, start, str->nLen*sizeof(WCHAR), code); |
| 219 | } else { |
| 220 | int result; |
| 221 | int buffer_size = WideCharToMultiByte(CP_ACP, 0, str->szData, str->nLen, |
| 222 | NULL, 0, NULL, NULL); |
Michael Stefaniuc | 90024d0 | 2008-11-03 22:36:03 +0100 | [diff] [blame] | 223 | char *buffer = heap_alloc(buffer_size); |
Dylan Smith | 5039729 | 2008-10-23 01:07:31 -0400 | [diff] [blame] | 224 | WideCharToMultiByte(CP_ACP, 0, str->szData, str->nLen, |
| 225 | buffer, buffer_size, NULL, NULL); |
| 226 | result = editor->pfnWordBreak(str->szData, start, str->nLen, code); |
| 227 | heap_free(buffer); |
| 228 | return result; |
| 229 | } |
Phil Krylov | 49eecf5 | 2006-01-12 11:54:57 +0100 | [diff] [blame] | 230 | } |
| 231 | |
Dmitry Timoshkov | 592b53d | 2007-03-22 19:09:43 +0800 | [diff] [blame] | 232 | LPWSTR ME_ToUnicode(BOOL unicode, LPVOID psz) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 233 | { |
Dmitry Timoshkov | 9bde411 | 2007-05-02 17:59:21 +0900 | [diff] [blame] | 234 | assert(psz != NULL); |
| 235 | |
Dmitry Timoshkov | 592b53d | 2007-03-22 19:09:43 +0800 | [diff] [blame] | 236 | if (unicode) |
Michael Stefaniuc | d1a7e41 | 2009-01-30 10:40:02 +0100 | [diff] [blame] | 237 | return psz; |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 238 | else { |
| 239 | WCHAR *tmp; |
Michael Stefaniuc | d1a7e41 | 2009-01-30 10:40:02 +0100 | [diff] [blame] | 240 | int nChars = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0); |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 241 | if((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL) |
Michael Stefaniuc | d1a7e41 | 2009-01-30 10:40:02 +0100 | [diff] [blame] | 242 | MultiByteToWideChar(CP_ACP, 0, psz, -1, tmp, nChars); |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 243 | return tmp; |
| 244 | } |
| 245 | } |
| 246 | |
Dmitry Timoshkov | 592b53d | 2007-03-22 19:09:43 +0800 | [diff] [blame] | 247 | void ME_EndToUnicode(BOOL unicode, LPVOID psz) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 248 | { |
Dmitry Timoshkov | 592b53d | 2007-03-22 19:09:43 +0800 | [diff] [blame] | 249 | if (!unicode) |
Krzysztof Foltman | d488f3f | 2005-03-05 11:19:14 +0000 | [diff] [blame] | 250 | FREE_OBJ(psz); |
| 251 | } |