Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 1 | /* |
| 2 | * FormatMessage implementation |
| 3 | * |
| 4 | * Copyright 1996 Marcus Meissner |
| 5 | */ |
| 6 | |
| 7 | #include "config.h" |
| 8 | |
| 9 | #include <stdio.h> |
| 10 | #include <string.h> |
| 11 | |
| 12 | #include "windef.h" |
| 13 | #include "winbase.h" |
| 14 | #include "winerror.h" |
| 15 | #include "winnls.h" |
Alexandre Julliard | c7e7df8 | 2000-08-14 14:41:19 +0000 | [diff] [blame] | 16 | #include "wine/unicode.h" |
Alexandre Julliard | 072dfb5 | 2000-09-25 23:30:56 +0000 | [diff] [blame^] | 17 | #include "wine/winestring.h" |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 18 | |
| 19 | #include "heap.h" |
| 20 | #include "debugtools.h" |
| 21 | |
| 22 | DEFAULT_DEBUG_CHANNEL(resource); |
| 23 | |
| 24 | |
| 25 | /* Messages...used by FormatMessage32* (KERNEL32.something) |
| 26 | * |
| 27 | * They can be specified either directly or using a message ID and |
| 28 | * loading them from the resource. |
| 29 | * |
| 30 | * The resourcedata has following format: |
| 31 | * start: |
| 32 | * 0: DWORD nrofentries |
| 33 | * nrofentries * subentry: |
| 34 | * 0: DWORD firstentry |
| 35 | * 4: DWORD lastentry |
| 36 | * 8: DWORD offset from start to the stringentries |
| 37 | * |
| 38 | * (lastentry-firstentry) * stringentry: |
Marcus Meissner | 80d62c7 | 2000-08-02 00:56:28 +0000 | [diff] [blame] | 39 | * 0: WORD len (0 marks end) [ includes the 4 byte header length ] |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 40 | * 2: WORD flags |
| 41 | * 4: CHAR[len-4] |
| 42 | * (stringentry i of a subentry refers to the ID 'firstentry+i') |
| 43 | * |
| 44 | * Yes, ANSI strings in win32 resources. Go figure. |
| 45 | */ |
| 46 | |
| 47 | /********************************************************************** |
| 48 | * load_messageA (internal) |
| 49 | */ |
| 50 | static INT load_messageA( HMODULE instance, UINT id, WORD lang, |
| 51 | LPSTR buffer, INT buflen ) |
| 52 | { |
| 53 | HGLOBAL hmem; |
| 54 | HRSRC hrsrc; |
| 55 | PMESSAGE_RESOURCE_DATA mrd; |
| 56 | PMESSAGE_RESOURCE_BLOCK mrb; |
| 57 | PMESSAGE_RESOURCE_ENTRY mre; |
| 58 | int i,slen; |
| 59 | |
| 60 | TRACE("instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD)instance, (DWORD)id, buffer, (DWORD)buflen); |
| 61 | |
| 62 | /*FIXME: I am not sure about the '1' ... But I've only seen those entries*/ |
| 63 | hrsrc = FindResourceExW(instance,RT_MESSAGELISTW,(LPWSTR)1,lang); |
| 64 | if (!hrsrc) return 0; |
| 65 | hmem = LoadResource( instance, hrsrc ); |
| 66 | if (!hmem) return 0; |
| 67 | |
| 68 | mrd = (PMESSAGE_RESOURCE_DATA)LockResource(hmem); |
| 69 | mre = NULL; |
| 70 | mrb = &(mrd->Blocks[0]); |
| 71 | for (i=mrd->NumberOfBlocks;i--;) { |
| 72 | if ((id>=mrb->LowId) && (id<=mrb->HighId)) { |
| 73 | mre = (PMESSAGE_RESOURCE_ENTRY)(((char*)mrd)+mrb->OffsetToEntries); |
| 74 | id -= mrb->LowId; |
| 75 | break; |
| 76 | } |
| 77 | mrb++; |
| 78 | } |
| 79 | if (!mre) |
| 80 | return 0; |
| 81 | for (i=id;i--;) { |
| 82 | if (!mre->Length) |
| 83 | return 0; |
Marcus Meissner | 80d62c7 | 2000-08-02 00:56:28 +0000 | [diff] [blame] | 84 | mre = (PMESSAGE_RESOURCE_ENTRY)(((char*)mre)+mre->Length); |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 85 | } |
| 86 | slen=mre->Length; |
| 87 | TRACE(" - strlen=%d\n",slen); |
| 88 | i = min(buflen - 1, slen); |
| 89 | if (buffer == NULL) |
| 90 | return slen; |
| 91 | if (i>0) { |
James Abbatiello | dbdd94b | 2000-08-22 20:37:44 +0000 | [diff] [blame] | 92 | if (mre->Flags & MESSAGE_RESOURCE_UNICODE) |
| 93 | lstrcpynWtoA(buffer, (LPWSTR)mre->Text, i); |
| 94 | else |
| 95 | lstrcpynA(buffer, (LPSTR)mre->Text, i); |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 96 | buffer[i]=0; |
| 97 | } else { |
| 98 | if (buflen>1) { |
| 99 | buffer[0]=0; |
| 100 | return 0; |
| 101 | } |
| 102 | } |
| 103 | if (buffer) |
| 104 | TRACE("'%s' copied !\n", buffer); |
| 105 | return i; |
| 106 | } |
| 107 | |
| 108 | #if 0 /* FIXME */ |
| 109 | /********************************************************************** |
| 110 | * load_messageW (internal) |
| 111 | */ |
| 112 | static INT load_messageW( HMODULE instance, UINT id, WORD lang, |
| 113 | LPWSTR buffer, INT buflen ) |
| 114 | { |
| 115 | INT retval; |
| 116 | LPSTR buffer2 = NULL; |
| 117 | if (buffer && buflen) |
| 118 | buffer2 = HeapAlloc( GetProcessHeap(), 0, buflen ); |
| 119 | retval = load_messageA(instance,id,lang,buffer2,buflen); |
| 120 | if (buffer) |
| 121 | { |
| 122 | if (retval) { |
| 123 | lstrcpynAtoW( buffer, buffer2, buflen ); |
Alexandre Julliard | c7e7df8 | 2000-08-14 14:41:19 +0000 | [diff] [blame] | 124 | retval = strlenW( buffer ); |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 125 | } |
| 126 | HeapFree( GetProcessHeap(), 0, buffer2 ); |
| 127 | } |
| 128 | return retval; |
| 129 | } |
| 130 | #endif |
| 131 | |
| 132 | |
| 133 | /*********************************************************************** |
| 134 | * FormatMessageA (KERNEL32.138) |
| 135 | * FIXME: missing wrap, |
| 136 | */ |
| 137 | DWORD WINAPI FormatMessageA( |
| 138 | DWORD dwFlags, |
| 139 | LPCVOID lpSource, |
| 140 | DWORD dwMessageId, |
| 141 | DWORD dwLanguageId, |
| 142 | LPSTR lpBuffer, |
| 143 | DWORD nSize, |
| 144 | LPDWORD args /* va_list *args */ |
| 145 | ) { |
| 146 | #ifdef __i386__ |
| 147 | /* This implementation is completely dependant on the format of the va_list on x86 CPUs */ |
| 148 | LPSTR target,t; |
| 149 | DWORD talloced; |
| 150 | LPSTR from,f; |
| 151 | DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK; |
| 152 | BOOL eos = FALSE; |
| 153 | INT bufsize; |
| 154 | HMODULE hmodule = (HMODULE)lpSource; |
Andreas Mohr | eb38129 | 2000-08-07 17:09:58 +0000 | [diff] [blame] | 155 | CHAR ch; |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 156 | |
| 157 | TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n", |
| 158 | dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args); |
| 159 | if ((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) |
| 160 | && (dwFlags & FORMAT_MESSAGE_FROM_HMODULE)) return 0; |
| 161 | if ((dwFlags & FORMAT_MESSAGE_FROM_STRING) |
| 162 | &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) |
| 163 | || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0; |
| 164 | |
| 165 | if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK) |
| 166 | FIXME("line wrapping (%lu) not supported.\n", width); |
| 167 | from = NULL; |
| 168 | if (dwFlags & FORMAT_MESSAGE_FROM_STRING) { |
| 169 | from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource); |
| 170 | } |
| 171 | else { |
| 172 | dwMessageId &= 0xFFFF; |
| 173 | if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) |
| 174 | hmodule = GetModuleHandleA("kernel32"); |
| 175 | bufsize=load_messageA(hmodule,dwMessageId,dwLanguageId,NULL,100); |
| 176 | if (!bufsize) { |
| 177 | if (dwLanguageId) { |
| 178 | SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND); |
| 179 | return 0; |
| 180 | } |
| 181 | bufsize=load_messageA(hmodule,dwMessageId, |
| 182 | MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),NULL,100); |
| 183 | if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId, |
| 184 | MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),NULL,100); |
| 185 | if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId, |
| 186 | MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100); |
| 187 | if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId, |
| 188 | MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100); |
| 189 | if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId, |
| 190 | MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NULL,100); |
| 191 | if (!bufsize) { |
| 192 | SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND); |
| 193 | return 0; |
| 194 | } |
| 195 | } |
| 196 | from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 ); |
| 197 | load_messageA(hmodule,dwMessageId,dwLanguageId,from,bufsize+1); |
| 198 | } |
| 199 | target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100); |
| 200 | t = target; |
| 201 | talloced= 100; |
| 202 | |
Marcus Meissner | 5c18f69 | 2000-07-31 20:56:52 +0000 | [diff] [blame] | 203 | #define ADD_TO_T(c) do { \ |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 204 | *t++=c;\ |
| 205 | if (t-target == talloced) {\ |
| 206 | target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\ |
| 207 | t = target+talloced;\ |
| 208 | talloced*=2;\ |
Marcus Meissner | 5c18f69 | 2000-07-31 20:56:52 +0000 | [diff] [blame] | 209 | }\ |
| 210 | } while (0) |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 211 | |
| 212 | if (from) { |
| 213 | f=from; |
| 214 | while (*f && !eos) { |
| 215 | if (*f=='%') { |
| 216 | int insertnr; |
| 217 | char *fmtstr,*x,*lastf; |
| 218 | DWORD *argliststart; |
| 219 | |
| 220 | fmtstr = NULL; |
| 221 | lastf = f; |
| 222 | f++; |
| 223 | if (!*f) { |
| 224 | ADD_TO_T('%'); |
| 225 | continue; |
| 226 | } |
| 227 | switch (*f) { |
| 228 | case '1':case '2':case '3':case '4':case '5': |
| 229 | case '6':case '7':case '8':case '9': |
| 230 | insertnr=*f-'0'; |
| 231 | switch (f[1]) { |
| 232 | case '0':case '1':case '2':case '3': |
| 233 | case '4':case '5':case '6':case '7': |
| 234 | case '8':case '9': |
| 235 | f++; |
| 236 | insertnr=insertnr*10+*f-'0'; |
| 237 | f++; |
| 238 | break; |
| 239 | default: |
| 240 | f++; |
| 241 | break; |
| 242 | } |
| 243 | if (*f=='!') { |
| 244 | f++; |
| 245 | if (NULL!=(x=strchr(f,'!'))) { |
| 246 | *x='\0'; |
| 247 | fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2); |
| 248 | sprintf(fmtstr,"%%%s",f); |
| 249 | f=x+1; |
| 250 | } else { |
| 251 | fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2); |
| 252 | sprintf(fmtstr,"%%%s",f); |
| 253 | f+=strlen(f); /*at \0*/ |
| 254 | } |
| 255 | } else |
| 256 | if(!args) |
| 257 | break; |
| 258 | else |
| 259 | fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s"); |
| 260 | if (args) { |
| 261 | int sz; |
| 262 | LPSTR b = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz = 100); |
| 263 | |
| 264 | if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) |
| 265 | argliststart=args+insertnr-1; |
| 266 | else |
| 267 | argliststart=(*(DWORD**)args)+insertnr-1; |
| 268 | |
| 269 | /* CMF - This makes a BIG assumption about va_list */ |
Marcus Meissner | 62f059f | 2000-07-29 14:35:32 +0000 | [diff] [blame] | 270 | while (vsnprintf(b, sz, fmtstr, (va_list) argliststart) < 0) { |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 271 | b = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, b, sz += 100); |
| 272 | } |
| 273 | for (x=b; *x; x++) ADD_TO_T(*x); |
| 274 | |
| 275 | HeapFree(GetProcessHeap(),0,b); |
| 276 | } else { |
| 277 | /* NULL args - copy formatstr |
| 278 | * (probably wrong) |
| 279 | */ |
| 280 | while ((lastf<f)&&(*lastf)) { |
| 281 | ADD_TO_T(*lastf++); |
| 282 | } |
| 283 | } |
| 284 | HeapFree(GetProcessHeap(),0,fmtstr); |
| 285 | break; |
| 286 | case 'n': |
| 287 | ADD_TO_T('\r'); |
| 288 | ADD_TO_T('\n'); |
| 289 | f++; |
| 290 | break; |
| 291 | case '0': |
| 292 | eos = TRUE; |
| 293 | f++; |
| 294 | break; |
| 295 | default: |
Marcus Meissner | 5c18f69 | 2000-07-31 20:56:52 +0000 | [diff] [blame] | 296 | ADD_TO_T(*f++); |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 297 | break; |
| 298 | } |
Andreas Mohr | eb38129 | 2000-08-07 17:09:58 +0000 | [diff] [blame] | 299 | } else { |
| 300 | ch = *f; |
| 301 | f++; |
| 302 | if (ch == '\r') |
| 303 | { |
| 304 | if (*f == '\n') |
| 305 | f++; |
| 306 | ADD_TO_T(' '); |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 307 | } |
Andreas Mohr | eb38129 | 2000-08-07 17:09:58 +0000 | [diff] [blame] | 308 | else |
| 309 | if (ch == '\n') |
| 310 | { |
| 311 | ADD_TO_T('\r'); |
| 312 | ADD_TO_T('\n'); |
| 313 | } |
| 314 | else |
| 315 | ADD_TO_T(ch); |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 316 | } |
| 317 | } |
| 318 | *t='\0'; |
| 319 | } |
| 320 | talloced = strlen(target)+1; |
| 321 | if (nSize && talloced<nSize) { |
| 322 | target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize); |
| 323 | } |
| 324 | TRACE("-- %s\n",debugstr_a(target)); |
| 325 | if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) { |
| 326 | *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,max(nSize, talloced)); |
| 327 | memcpy(*(LPSTR*)lpBuffer,target,talloced); |
| 328 | } else { |
| 329 | lstrcpynA(lpBuffer,target,nSize); |
| 330 | } |
| 331 | HeapFree(GetProcessHeap(),0,target); |
| 332 | if (from) HeapFree(GetProcessHeap(),0,from); |
Marcus Meissner | 62f059f | 2000-07-29 14:35:32 +0000 | [diff] [blame] | 333 | TRACE("-- returning %d\n", (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? strlen(*(LPSTR*)lpBuffer):strlen(lpBuffer)); |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 334 | return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? |
| 335 | strlen(*(LPSTR*)lpBuffer): |
| 336 | strlen(lpBuffer); |
| 337 | #else |
| 338 | return 0; |
| 339 | #endif /* __i386__ */ |
| 340 | } |
| 341 | #undef ADD_TO_T |
| 342 | |
| 343 | |
| 344 | /*********************************************************************** |
| 345 | * FormatMessageW (KERNEL32.138) |
| 346 | */ |
| 347 | DWORD WINAPI FormatMessageW( |
| 348 | DWORD dwFlags, |
| 349 | LPCVOID lpSource, |
| 350 | DWORD dwMessageId, |
| 351 | DWORD dwLanguageId, |
| 352 | LPWSTR lpBuffer, |
| 353 | DWORD nSize, |
| 354 | LPDWORD args /* va_list *args */ |
| 355 | ) { |
| 356 | #ifdef __i386__ |
| 357 | /* This implementation is completely dependant on the format of the va_list on x86 CPUs */ |
| 358 | LPSTR target,t; |
| 359 | DWORD talloced; |
| 360 | LPSTR from,f; |
| 361 | DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK; |
| 362 | BOOL eos = FALSE; |
| 363 | INT bufsize; |
| 364 | HMODULE hmodule = (HMODULE)lpSource; |
Andreas Mohr | eb38129 | 2000-08-07 17:09:58 +0000 | [diff] [blame] | 365 | CHAR ch; |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 366 | |
| 367 | TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n", |
| 368 | dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args); |
| 369 | if ((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) |
| 370 | && (dwFlags & FORMAT_MESSAGE_FROM_HMODULE)) return 0; |
| 371 | if ((dwFlags & FORMAT_MESSAGE_FROM_STRING) |
| 372 | &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) |
| 373 | || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0; |
| 374 | |
| 375 | if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK) |
| 376 | FIXME("line wrapping not supported.\n"); |
| 377 | from = NULL; |
| 378 | if (dwFlags & FORMAT_MESSAGE_FROM_STRING) { |
| 379 | from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource); |
| 380 | } |
| 381 | else { |
| 382 | dwMessageId &= 0xFFFF; |
| 383 | if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) |
| 384 | hmodule = GetModuleHandleA("kernel32"); |
| 385 | bufsize=load_messageA(hmodule,dwMessageId,dwLanguageId,NULL,100); |
| 386 | if (!bufsize) { |
| 387 | if (dwLanguageId) { |
| 388 | SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND); |
| 389 | return 0; |
| 390 | } |
| 391 | bufsize=load_messageA(hmodule,dwMessageId, |
| 392 | MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),NULL,100); |
| 393 | if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId, |
| 394 | MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),NULL,100); |
| 395 | if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId, |
| 396 | MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100); |
| 397 | if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId, |
| 398 | MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100); |
| 399 | if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId, |
| 400 | MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NULL,100); |
| 401 | if (!bufsize) { |
| 402 | SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND); |
| 403 | return 0; |
| 404 | } |
| 405 | } |
| 406 | from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 ); |
| 407 | load_messageA(hmodule,dwMessageId,dwLanguageId,from,bufsize+1); |
| 408 | } |
| 409 | target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 ); |
| 410 | t = target; |
| 411 | talloced= 100; |
| 412 | |
Marcus Meissner | 5c18f69 | 2000-07-31 20:56:52 +0000 | [diff] [blame] | 413 | #define ADD_TO_T(c) do {\ |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 414 | *t++=c;\ |
| 415 | if (t-target == talloced) {\ |
| 416 | target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\ |
| 417 | t = target+talloced;\ |
| 418 | talloced*=2;\ |
Marcus Meissner | 5c18f69 | 2000-07-31 20:56:52 +0000 | [diff] [blame] | 419 | } \ |
| 420 | } while (0) |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 421 | |
| 422 | if (from) { |
| 423 | f=from; |
| 424 | while (*f && !eos) { |
| 425 | if (*f=='%') { |
| 426 | int insertnr; |
| 427 | char *fmtstr,*sprintfbuf,*x; |
| 428 | DWORD *argliststart; |
| 429 | |
| 430 | fmtstr = NULL; |
| 431 | f++; |
| 432 | if (!*f) { |
| 433 | ADD_TO_T('%'); |
| 434 | continue; |
| 435 | } |
| 436 | switch (*f) { |
| 437 | case '1':case '2':case '3':case '4':case '5': |
| 438 | case '6':case '7':case '8':case '9': |
| 439 | insertnr=*f-'0'; |
| 440 | switch (f[1]) { |
| 441 | case '0':case '1':case '2':case '3': |
| 442 | case '4':case '5':case '6':case '7': |
| 443 | case '8':case '9': |
| 444 | f++; |
| 445 | insertnr=insertnr*10+*f-'0'; |
| 446 | f++; |
| 447 | break; |
| 448 | default: |
| 449 | f++; |
| 450 | break; |
| 451 | } |
| 452 | if (*f=='!') { |
| 453 | f++; |
| 454 | if (NULL!=(x=strchr(f,'!'))) |
| 455 | { |
| 456 | *x='\0'; |
| 457 | fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2); |
| 458 | sprintf(fmtstr,"%%%s",f); |
| 459 | f=x+1; |
| 460 | } else { |
| 461 | fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)); |
| 462 | sprintf(fmtstr,"%%%s",f); |
| 463 | f+=strlen(f); /*at \0*/ |
| 464 | } |
| 465 | } else |
| 466 | if(!args) |
| 467 | break; |
| 468 | else |
| 469 | fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s"); |
| 470 | if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) |
| 471 | argliststart=args+insertnr-1; |
| 472 | else |
| 473 | argliststart=(*(DWORD**)args)+insertnr-1; |
| 474 | |
| 475 | if (fmtstr[strlen(fmtstr)-1]=='s' && argliststart[0]) { |
| 476 | DWORD xarr[3]; |
| 477 | |
| 478 | xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0))); |
| 479 | /* possible invalid pointers */ |
| 480 | xarr[1]=*(argliststart+1); |
| 481 | xarr[2]=*(argliststart+2); |
Alexandre Julliard | c7e7df8 | 2000-08-14 14:41:19 +0000 | [diff] [blame] | 482 | sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlenW((LPWSTR)argliststart[0])*2+1); |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 483 | |
| 484 | /* CMF - This makes a BIG assumption about va_list */ |
| 485 | vsprintf(sprintfbuf, fmtstr, (va_list) xarr); |
| 486 | } else { |
| 487 | sprintfbuf=HeapAlloc(GetProcessHeap(),0,100); |
| 488 | |
| 489 | /* CMF - This makes a BIG assumption about va_list */ |
Marcus Meissner | 62f059f | 2000-07-29 14:35:32 +0000 | [diff] [blame] | 490 | vsprintf(sprintfbuf, fmtstr, (va_list) argliststart); |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 491 | } |
| 492 | x=sprintfbuf; |
| 493 | while (*x) { |
| 494 | ADD_TO_T(*x++); |
| 495 | } |
| 496 | HeapFree(GetProcessHeap(),0,sprintfbuf); |
| 497 | HeapFree(GetProcessHeap(),0,fmtstr); |
| 498 | break; |
| 499 | case 'n': |
| 500 | ADD_TO_T('\r'); |
| 501 | ADD_TO_T('\n'); |
| 502 | f++; |
| 503 | break; |
| 504 | case '0': |
| 505 | eos = TRUE; |
| 506 | f++; |
| 507 | break; |
| 508 | default: |
Marcus Meissner | 5c18f69 | 2000-07-31 20:56:52 +0000 | [diff] [blame] | 509 | ADD_TO_T(*f++); |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 510 | break; |
| 511 | } |
Andreas Mohr | eb38129 | 2000-08-07 17:09:58 +0000 | [diff] [blame] | 512 | } else { |
| 513 | ch = *f; |
| 514 | f++; |
| 515 | if (ch == '\r') |
| 516 | { |
| 517 | if (*f == '\n') |
| 518 | f++; |
| 519 | ADD_TO_T(' '); |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 520 | } |
Andreas Mohr | eb38129 | 2000-08-07 17:09:58 +0000 | [diff] [blame] | 521 | else |
| 522 | if (ch == '\n') |
| 523 | { |
| 524 | ADD_TO_T('\r'); |
| 525 | ADD_TO_T('\n'); |
| 526 | } |
| 527 | else |
| 528 | ADD_TO_T(ch); |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 529 | } |
| 530 | } |
| 531 | *t='\0'; |
| 532 | } |
| 533 | talloced = strlen(target)+1; |
| 534 | if (nSize && talloced<nSize) |
| 535 | target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize); |
| 536 | if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) { |
| 537 | /* nSize is the MINIMUM size */ |
| 538 | *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced*2+2); |
| 539 | lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced); |
| 540 | } else |
| 541 | lstrcpynAtoW(lpBuffer,target,nSize); |
| 542 | HeapFree(GetProcessHeap(),0,target); |
| 543 | if (from) HeapFree(GetProcessHeap(),0,from); |
| 544 | return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? |
Alexandre Julliard | c7e7df8 | 2000-08-14 14:41:19 +0000 | [diff] [blame] | 545 | strlenW(*(LPWSTR*)lpBuffer): |
| 546 | strlenW(lpBuffer); |
Dave Pickles | a64603d | 2000-07-25 17:53:58 +0000 | [diff] [blame] | 547 | #else |
| 548 | return 0; |
| 549 | #endif /* __i386__ */ |
| 550 | } |
| 551 | #undef ADD_TO_T |