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 25 static int ME_GetOptimalBuffer(int nLen) 26 { 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; 30 } 31 32 /* Create a buffer (uninitialized string) of size nMaxChars */ 33 static ME_String *ME_MakeStringB(int nMaxChars) 34 { 35 ME_String *s = ALLOC_OBJ(ME_String); 36 37 s->nLen = nMaxChars; 38 s->nBuffer = ME_GetOptimalBuffer(s->nLen + 1); 39 s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer); 40 s->szData[s->nLen] = 0; 41 return s; 42 } 43 44 ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars) 45 { 46 ME_String *s = ME_MakeStringB(nMaxChars); 47 /* Native allows NULL chars */ 48 memcpy(s->szData, szText, s->nLen * sizeof(WCHAR)); 49 return s; 50 } 51 52 /* Make a string by repeating a char nMaxChars times */ 53 ME_String *ME_MakeStringR(WCHAR cRepeat, int nMaxChars) 54 { 55 int i; 56 ME_String *s = ME_MakeStringB(nMaxChars); 57 for (i = 0; i < nMaxChars; i++) 58 s->szData[i] = cRepeat; 59 return s; 60 } 61 62 ME_String *ME_StrDup(const ME_String *s) 63 { 64 return ME_MakeStringN(s->szData, s->nLen); 65 } 66 67 void ME_DestroyString(ME_String *s) 68 { 69 if (!s) return; 70 FREE_OBJ(s->szData); 71 FREE_OBJ(s); 72 } 73 74 void ME_AppendString(ME_String *s1, const ME_String *s2) 75 { 76 if (s1->nLen+s2->nLen+1 <= s1->nBuffer) 77 { 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 { 82 WCHAR *buf; 83 s1->nBuffer = ME_GetOptimalBuffer(s1->nLen+s2->nLen+1); 84 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)); 88 FREE_OBJ(s1->szData); 89 s1->szData = buf; 90 s1->nLen += s2->nLen; 91 s1->szData[s1->nLen] = 0; 92 } 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_MakeStringN(orig->szData+charidx, orig->nLen-charidx); 106 orig->nLen = charidx; 107 orig->szData[charidx] = '\0'; 108 return s; 109 } 110 111 int ME_IsWhitespaces(const 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(const ME_String *s) 125 { 126 WCHAR *pos = s->szData; 127 WCHAR ch; 128 while(ME_IsWSpace(*pos++)) 129 ; 130 pos--; 131 while((ch = *pos++) != 0) 132 { 133 if (ME_IsWSpace(ch)) 134 return 1; 135 } 136 return 0; 137 } 138 139 void ME_StrDeleteV(ME_String *s, int nVChar, int nChars) 140 { 141 int end_ofs = nVChar + nChars; 142 143 assert(nChars >= 0); 144 assert(nVChar >= 0); 145 assert(end_ofs <= s->nLen); 146 147 memmove(s->szData + nVChar, s->szData + end_ofs, 148 (s->nLen - end_ofs + 1) * sizeof(WCHAR)); 149 s->nLen -= nChars; 150 } 151 152 int ME_FindNonWhitespaceV(const ME_String *s, int nVChar) { 153 int i; 154 for (i = nVChar; i<s->nLen && ME_IsWSpace(s->szData[i]); i++) 155 ; 156 157 return i; 158 } 159 160 /* note: returns offset of the first trailing whitespace */ 161 int ME_ReverseFindNonWhitespaceV(const ME_String *s, int nVChar) { 162 int i; 163 for (i = nVChar; i>0 && ME_IsWSpace(s->szData[i-1]); i--) 164 ; 165 166 return i; 167 } 168 169 /* note: returns offset of the first trailing nonwhitespace */ 170 int ME_ReverseFindWhitespaceV(const ME_String *s, int nVChar) { 171 int i; 172 for (i = nVChar; i>0 && !ME_IsWSpace(s->szData[i-1]); i--) 173 ; 174 175 return i; 176 } 177 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); 185 /* convert number of bytes to number of characters. */ 186 len /= sizeof(WCHAR); 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: 200 while (start < len && !ME_IsWSpace(s[start])) 201 start++; 202 while (start < len && ME_IsWSpace(s[start])) 203 start++; 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 { 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); 223 char *buffer = heap_alloc(buffer_size); 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 } 230 } 231 232 LPWSTR ME_ToUnicode(BOOL unicode, LPVOID psz) 233 { 234 assert(psz != NULL); 235 236 if (unicode) 237 return psz; 238 else { 239 WCHAR *tmp; 240 int nChars = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0); 241 if((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL) 242 MultiByteToWideChar(CP_ACP, 0, psz, -1, tmp, nChars); 243 return tmp; 244 } 245 } 246 247 void ME_EndToUnicode(BOOL unicode, LPVOID psz) 248 { 249 if (!unicode) 250 FREE_OBJ(psz); 251 } 252