Branch setupapi
[reactos.git] / reactos / lib / kernel32 / misc / errormsg.c
1 /* $Id$
2 *
3 * reactos/lib/kernel32/misc/errormsg.c
4 *
5 */
6 /*
7 * FormatMessage implementation
8 *
9 * Copyright 1996 Marcus Meissner
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26 #include <k32.h>
27
28 #define NDEBUG
29 #include "../include/debug.h"
30
31 #define TRACE DPRINT
32 #define FIXME DPRINT
33
34 /* strdup macros */
35 /* DO NOT USE IT!! it will go away soon */
36 inline static LPSTR HEAP_strdupWtoA( HANDLE heap, DWORD flags, LPCWSTR str )
37 {
38 LPSTR ret;
39 INT len;
40
41 if (!str) return NULL;
42 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
43 ret = RtlAllocateHeap(RtlGetProcessHeap(), flags, len );
44 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
45 return ret;
46 }
47
48 /* Messages...used by FormatMessage32* (KERNEL32.something)
49 *
50 * They can be specified either directly or using a message ID and
51 * loading them from the resource.
52 *
53 * The resourcedata has following format:
54 * start:
55 * 0: DWORD nrofentries
56 * nrofentries * subentry:
57 * 0: DWORD firstentry
58 * 4: DWORD lastentry
59 * 8: DWORD offset from start to the stringentries
60 *
61 * (lastentry-firstentry) * stringentry:
62 * 0: WORD len (0 marks end) [ includes the 4 byte header length ]
63 * 2: WORD flags
64 * 4: CHAR[len-4]
65 * (stringentry i of a subentry refers to the ID 'firstentry+i')
66 *
67 * Yes, ANSI strings in win32 resources. Go figure.
68 */
69
70 /**********************************************************************
71 * load_messageA (internal)
72 */
73 static INT load_messageA( HMODULE instance, UINT id, WORD lang,
74 LPSTR buffer, INT buflen )
75 {
76 HGLOBAL hmem;
77 HRSRC hrsrc;
78 PMESSAGE_RESOURCE_DATA mrd;
79 PMESSAGE_RESOURCE_BLOCK mrb;
80 PMESSAGE_RESOURCE_ENTRY mre;
81 int i,slen;
82
83 //TRACE("instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD)instance, (DWORD)id, buffer, (DWORD)buflen);
84
85 /*FIXME: I am not sure about the '1' ... But I've only seen those entries*/
86 hrsrc = FindResourceExW(instance,(LPWSTR)RT_MESSAGETABLE,(LPWSTR)1,lang);
87 if (!hrsrc) return 0;
88 hmem = LoadResource( instance, hrsrc );
89 if (!hmem) return 0;
90
91 mrd = (PMESSAGE_RESOURCE_DATA)LockResource(hmem);
92 mre = NULL;
93 mrb = &(mrd->Blocks[0]);
94 for (i=mrd->NumberOfBlocks;i--;) {
95 if ((id>=mrb->LowId) && (id<=mrb->HighId)) {
96 mre = (PMESSAGE_RESOURCE_ENTRY)(((char*)mrd)+mrb->OffsetToEntries);
97 id -= mrb->LowId;
98 break;
99 }
100 mrb++;
101 }
102 if (!mre)
103 return 0;
104 for (i=id;i--;) {
105 if (!mre->Length)
106 return 0;
107 mre = (PMESSAGE_RESOURCE_ENTRY)(((char*)mre)+mre->Length);
108 }
109 slen=mre->Length;
110 //TRACE(" - strlen=%d\n",slen);
111 i = min(buflen - 1, slen);
112 if (buffer == NULL)
113 return slen;
114 if (i>0) {
115 if (mre->Flags & MESSAGE_RESOURCE_UNICODE)
116 WideCharToMultiByte( CP_ACP, 0, (LPWSTR)mre->Text, -1, buffer, i, NULL, NULL );
117 else
118 lstrcpynA(buffer, (LPSTR)mre->Text, i);
119 buffer[i]=0;
120 } else {
121 if (buflen>1) {
122 buffer[0]=0;
123 return 0;
124 }
125 }
126 if (buffer) {
127 //TRACE("'%s' copied !\n", buffer);
128 //TRACE("'%s'\n", buffer);
129 }
130 return i;
131 }
132
133 #if 0 /* FIXME */
134 /**********************************************************************
135 * load_messageW (internal)
136 */
137 static INT load_messageW( HMODULE instance, UINT id, WORD lang,
138 LPWSTR buffer, INT buflen )
139 {
140 INT retval;
141 LPSTR buffer2 = NULL;
142 if (buffer && buflen)
143 buffer2 = HeapAlloc( GetProcessHeap(), 0, buflen );
144 retval = load_messageA(instance,id,lang,buffer2,buflen);
145 if (buffer)
146 {
147 if (retval) {
148 lstrcpynAtoW( buffer, buffer2, buflen );
149 retval = lstrlenW( buffer );
150 }
151 HeapFree( GetProcessHeap(), 0, buffer2 );
152 }
153 return retval;
154 }
155 #endif
156
157
158 /***********************************************************************
159 * FormatMessageA (KERNEL32.@)
160 * FIXME: missing wrap,
161 *
162 * @implemented
163 */
164 DWORD WINAPI FormatMessageA(
165 DWORD dwFlags,
166 LPCVOID lpSource,
167 DWORD dwMessageId,
168 DWORD dwLanguageId,
169 LPSTR lpBuffer,
170 DWORD nSize,
171 va_list* _args )
172 {
173 LPDWORD args=(LPDWORD)_args;
174 #if defined(__i386__) || defined(__sparc__)
175 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
176 LPSTR target,t;
177 DWORD talloced;
178 LPSTR from,f;
179 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
180 BOOL eos = FALSE;
181 INT bufsize;
182 HMODULE hmodule = (HMODULE)lpSource;
183 CHAR ch;
184
185 //TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n", dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
186 if ((dwFlags & FORMAT_MESSAGE_FROM_STRING)
187 &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
188 || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0;
189
190 if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK)
191 //FIXME("line wrapping (%lu) not supported.\n", width);
192 from = NULL;
193 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
194 {
195 from = RtlAllocateHeap(RtlGetProcessHeap(), 0, lstrlenA((LPSTR)lpSource)+1 );
196 strcpy( from, (LPSTR)lpSource );
197 }
198 else {
199 bufsize = 0;
200
201 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE)
202 {
203 bufsize=load_messageA(hmodule,dwMessageId,dwLanguageId,NULL,100);
204 if ((!bufsize) && (!dwLanguageId)) {
205 bufsize=load_messageA(hmodule,dwMessageId,
206 MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),NULL,100);
207 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
208 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),NULL,100);
209 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
210 MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
211 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
212 MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
213 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
214 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NULL,100);
215 }
216 }
217 if ((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) && (!bufsize))
218 {
219 hmodule = GetModuleHandleA("kernel32");
220 bufsize=load_messageA(hmodule,dwMessageId,dwLanguageId,NULL,100);
221 if ((!bufsize) && (!dwLanguageId)) {
222 bufsize=load_messageA(hmodule,dwMessageId,
223 MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),NULL,100);
224 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
225 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),NULL,100);
226 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
227 MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
228 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
229 MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
230 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
231 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NULL,100);
232 }
233 }
234
235 if (!bufsize) {
236 TRACE("FormatMessageA: dwFlags=%#x hmodule=%#x dwMessageId=%#x - could not load message\n", dwFlags, hmodule, dwMessageId);
237 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND);
238 return 0;
239 }
240
241 from = RtlAllocateHeap(RtlGetProcessHeap(), 0, bufsize + 1 );
242 load_messageA(hmodule,dwMessageId,dwLanguageId,from,bufsize+1);
243 }
244 target = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 100);
245 t = target;
246 talloced= 100;
247
248 #define ADD_TO_T(c) do { \
249 *t++=c;\
250 if (t-target == talloced) {\
251 target = (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
252 t = target+talloced;\
253 talloced*=2;\
254 }\
255 } while (0)
256
257 if (from) {
258 f=from;
259 if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) {
260 while (*f && !eos)
261 ADD_TO_T(*f++);
262 }
263 else {
264 while (*f && !eos) {
265 if (*f=='%') {
266 int insertnr;
267 char *fmtstr,*x,*lastf;
268 DWORD *argliststart;
269
270 fmtstr = NULL;
271 lastf = f;
272 f++;
273 if (!*f) {
274 ADD_TO_T('%');
275 continue;
276 }
277 switch (*f) {
278 case '1':case '2':case '3':case '4':case '5':
279 case '6':case '7':case '8':case '9':
280 insertnr=*f-'0';
281 switch (f[1]) {
282 case '0':case '1':case '2':case '3':
283 case '4':case '5':case '6':case '7':
284 case '8':case '9':
285 f++;
286 insertnr=insertnr*10+*f-'0';
287 f++;
288 break;
289 default:
290 f++;
291 break;
292 }
293 if (*f=='!') {
294 f++;
295 if (NULL!=(x=strchr(f,'!'))) {
296 *x='\0';
297 fmtstr=RtlAllocateHeap(RtlGetProcessHeap(),0,lstrlenA(f)+2);
298 sprintf(fmtstr,"%%%s",f);
299 f=x+1;
300 } else {
301 fmtstr=RtlAllocateHeap(RtlGetProcessHeap(),0,lstrlenA(f)+2);
302 sprintf(fmtstr,"%%%s",f);
303 f+=lstrlenA(f); /*at \0*/
304 }
305 } else {
306 if(!args) break;
307 fmtstr = RtlAllocateHeap(RtlGetProcessHeap(),0,3);
308 strcpy( fmtstr, "%s" );
309 }
310 if (args) {
311 int sz;
312 LPSTR b;
313
314 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
315 argliststart=args+insertnr-1;
316 else
317 argliststart=(*(DWORD**)args)+insertnr-1;
318
319 /* FIXME: precision and width components are not handled correctly */
320 if ( (strcmp(fmtstr, "%ls") == 0) || (strcmp(fmtstr,"%S") == 0) ) {
321 sz = WideCharToMultiByte( CP_ACP, 0, *(WCHAR**)argliststart, -1, NULL, 0, NULL, NULL);
322 b = RtlAllocateHeap(RtlGetProcessHeap(), 0, sz);
323 WideCharToMultiByte( CP_ACP, 0, *(WCHAR**)argliststart, -1, b, sz, NULL, NULL);
324 } else {
325 b = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sz = 1000);
326 /* CMF - This makes a BIG assumption about va_list */
327 //TRACE("A BIG assumption\n");
328 _vsnprintf(b, sz, fmtstr, (va_list) argliststart);
329 }
330 for (x=b; *x; x++) ADD_TO_T(*x);
331
332 RtlFreeHeap(RtlGetProcessHeap(),0,b);
333 } else {
334 /* NULL args - copy formatstr
335 * (probably wrong)
336 */
337 while ((lastf<f)&&(*lastf)) {
338 ADD_TO_T(*lastf++);
339 }
340 }
341 RtlFreeHeap(GetProcessHeap(),0,fmtstr);
342 break;
343 case 'n':
344 ADD_TO_T('\r');
345 ADD_TO_T('\n');
346 f++;
347 break;
348 case '0':
349 eos = TRUE;
350 f++;
351 break;
352 default:
353 ADD_TO_T(*f++);
354 break;
355 }
356 } else {
357 ch = *f;
358 f++;
359 if (ch == '\r') {
360 if (*f == '\n')
361 f++;
362 if(width)
363 ADD_TO_T(' ');
364 else
365 {
366 ADD_TO_T('\r');
367 ADD_TO_T('\n');
368 }
369 } else {
370 if (ch == '\n')
371 {
372 if(width)
373 ADD_TO_T(' ');
374 else
375 {
376 ADD_TO_T('\r');
377 ADD_TO_T('\n');
378 }
379 }
380 else
381 ADD_TO_T(ch);
382 }
383 }
384 }
385 }
386 *t='\0';
387 }
388 talloced = lstrlenA(target)+1;
389 if (nSize && talloced<nSize) {
390 target = (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
391 }
392 //TRACE("-- %s\n",debugstr_a(target));
393 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
394 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,max(nSize, talloced));
395 memcpy(*(LPSTR*)lpBuffer,target,talloced);
396 } else {
397 lstrcpynA(lpBuffer,target,nSize);
398 }
399 RtlFreeHeap(RtlGetProcessHeap(),0,target);
400 if (from) RtlFreeHeap(RtlGetProcessHeap(),0,from);
401 //TRACE("-- returning %d\n", (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? lstrlenA(*(LPSTR*)lpBuffer):lstrlenA(lpBuffer));
402 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
403 lstrlenA(*(LPSTR*)lpBuffer):
404 lstrlenA(lpBuffer);
405 #else
406 FIXME("FormatMessageA: unimplemented\n");
407 return 0;
408 #endif /* __i386__ */
409 }
410 #undef ADD_TO_T
411
412
413 /***********************************************************************
414 * FormatMessageW (KERNEL32.@)
415 *
416 * @implemented
417 */
418 DWORD WINAPI FormatMessageW(
419 DWORD dwFlags,
420 LPCVOID lpSource,
421 DWORD dwMessageId,
422 DWORD dwLanguageId,
423 LPWSTR lpBuffer,
424 DWORD nSize,
425 va_list* _args)
426 {
427 LPDWORD args=(LPDWORD)_args;
428 #if defined(__i386__) || defined(__sparc__)
429 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
430 LPSTR target,t;
431 DWORD talloced;
432 LPSTR from,f;
433 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
434 BOOL eos = FALSE;
435 INT bufsize;
436 HMODULE hmodule = (HMODULE)lpSource;
437 CHAR ch;
438
439 //TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n", dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
440 if ((dwFlags & FORMAT_MESSAGE_FROM_STRING)
441 &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
442 || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0;
443
444 if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK) {
445 //FIXME("line wrapping not supported.\n");
446 }
447 from = NULL;
448 if (dwFlags & FORMAT_MESSAGE_FROM_STRING) {
449 from = (LPSTR)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
450 }
451 else {
452 bufsize = 0;
453
454 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE)
455 {
456 bufsize=load_messageA(hmodule,dwMessageId,dwLanguageId,NULL,100);
457 if ((!bufsize) && (!dwLanguageId)) {
458 bufsize=load_messageA(hmodule,dwMessageId,
459 MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),NULL,100);
460 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
461 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),NULL,100);
462 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
463 MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
464 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
465 MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
466 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
467 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NULL,100);
468 }
469 }
470 if ((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) && (!bufsize))
471 {
472 hmodule = GetModuleHandleA("kernel32");
473 bufsize=load_messageA(hmodule,dwMessageId,dwLanguageId,NULL,100);
474 if ((!bufsize) && (!dwLanguageId)) {
475 bufsize=load_messageA(hmodule,dwMessageId,
476 MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),NULL,100);
477 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
478 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),NULL,100);
479 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
480 MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
481 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
482 MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
483 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
484 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NULL,100);
485 }
486 }
487
488 if (!bufsize) {
489 TRACE("FormatMessageW: dwFlags=%#x hmodule=%#x dwMessageId=%#x - could not load message\n", dwFlags, hmodule, dwMessageId);
490 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND);
491 return 0;
492 }
493
494 from = RtlAllocateHeap(RtlGetProcessHeap(), 0, bufsize + 1 );
495 load_messageA(hmodule,dwMessageId,dwLanguageId,from,bufsize+1);
496 }
497 target = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
498 t = target;
499 talloced= 100;
500
501 #define ADD_TO_T(c) do {\
502 *t++=c;\
503 if (t-target == talloced) {\
504 target = (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
505 t = target+talloced;\
506 talloced*=2;\
507 } \
508 } while (0)
509
510 if (from) {
511 f=from;
512 if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) {
513 while (*f && !eos)
514 ADD_TO_T(*f++);
515 }
516 else {
517 while (*f && !eos) {
518 if (*f=='%') {
519 int insertnr;
520 char *fmtstr,*sprintfbuf,*x;
521 DWORD *argliststart;
522
523 fmtstr = NULL;
524 f++;
525 if (!*f) {
526 ADD_TO_T('%');
527 continue;
528 }
529
530 switch (*f) {
531 case '1':case '2':case '3':case '4':case '5':
532 case '6':case '7':case '8':case '9':
533 insertnr=*f-'0';
534 switch (f[1]) {
535 case '0':case '1':case '2':case '3':
536 case '4':case '5':case '6':case '7':
537 case '8':case '9':
538 f++;
539 insertnr=insertnr*10+*f-'0';
540 f++;
541 break;
542 default:
543 f++;
544 break;
545 }
546 if (*f=='!') {
547 f++;
548 if (NULL!=(x=strchr(f,'!'))) {
549 *x='\0';
550 fmtstr=RtlAllocateHeap(RtlGetProcessHeap(), 0, lstrlenA(f)+2);
551 sprintf(fmtstr,"%%%s",f);
552 f=x+1;
553 } else {
554 fmtstr=RtlAllocateHeap(RtlGetProcessHeap(),0,lstrlenA(f));
555 sprintf(fmtstr,"%%%s",f);
556 f+=lstrlenA(f); /*at \0*/
557 }
558 } else {
559 if(!args) break;
560 fmtstr = RtlAllocateHeap(RtlGetProcessHeap(),0,3);
561 strcpy( fmtstr, "%s" );
562 }
563 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
564 argliststart=args+insertnr-1;
565 else
566 argliststart=(*(DWORD**)args)+insertnr-1;
567
568 if (fmtstr[lstrlenA(fmtstr)-1]=='s' && argliststart[0]) {
569 DWORD xarr[3];
570
571 xarr[0]=(DWORD)HEAP_strdupWtoA(RtlGetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
572 /* possible invalid pointers */
573 xarr[1]=*(argliststart+1);
574 xarr[2]=*(argliststart+2);
575 sprintfbuf=RtlAllocateHeap(RtlGetProcessHeap(),0,lstrlenW((LPWSTR)argliststart[0])*2+1);
576
577 /* CMF - This makes a BIG assumption about va_list */
578 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
579 RtlFreeHeap(RtlGetProcessHeap(), 0, (LPVOID) xarr[0]);
580 } else {
581 sprintfbuf=RtlAllocateHeap(RtlGetProcessHeap(),0,100);
582
583 /* CMF - This makes a BIG assumption about va_list */
584 vsprintf(sprintfbuf, fmtstr, (va_list) argliststart);
585 }
586 x=sprintfbuf;
587 while (*x) {
588 ADD_TO_T(*x++);
589 }
590 RtlFreeHeap(RtlGetProcessHeap(),0,sprintfbuf);
591 RtlFreeHeap(RtlGetProcessHeap(),0,fmtstr);
592 break;
593 case 'n':
594 ADD_TO_T('\r');
595 ADD_TO_T('\n');
596 f++;
597 break;
598 case '0':
599 eos = TRUE;
600 f++;
601 break;
602 default:
603 ADD_TO_T(*f++);
604 break;
605 }
606 } else {
607 ch = *f;
608 f++;
609 if (ch == '\r') {
610 if (*f == '\n')
611 f++;
612 if(width)
613 ADD_TO_T(' ');
614 else
615 {
616 ADD_TO_T('\r');
617 ADD_TO_T('\n');
618 }
619 } else {
620 if (ch == '\n')
621 {
622 if(width)
623 ADD_TO_T(' ');
624 else
625 {
626 ADD_TO_T('\r');
627 ADD_TO_T('\n');
628 }
629 }
630 else
631 ADD_TO_T(ch);
632 }
633 }
634 }
635 }
636 *t='\0';
637 }
638 talloced = lstrlenA(target)+1;
639 if (nSize && talloced<nSize)
640 target = (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
641 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
642 /* nSize is the MINIMUM size */
643 DWORD len = MultiByteToWideChar( CP_ACP, 0, target, -1, NULL, 0 );
644 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,len*sizeof(WCHAR));
645 MultiByteToWideChar( CP_ACP, 0, target, -1, *(LPWSTR*)lpBuffer, len );
646 }
647 else
648 {
649 if (nSize > 0 && !MultiByteToWideChar( CP_ACP, 0, target, -1, lpBuffer, nSize ))
650 lpBuffer[nSize-1] = 0;
651 }
652 RtlFreeHeap(RtlGetProcessHeap(),0,target);
653 if (from) RtlFreeHeap(RtlGetProcessHeap(),0,from);
654 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
655 lstrlenW(*(LPWSTR*)lpBuffer):
656 lstrlenW(lpBuffer);
657 #else
658 FIXME("FormatMessageW: unimplemented\n");
659 return 0;
660 #endif /* __i386__ */
661 }
662 #undef ADD_TO_T