update for HEAD-2003091401
[reactos.git] / 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 <ddk/ntddk.h>
27
28 // #define NDEBUG
29 #include <kernel32/kernel32.h>
30 #include <kernel32/error.h>
31
32 #define USE_WINE_PORT
33
34 #ifdef USE_WINE_PORT
35
36 //#define NDEBUG
37 //#include <ntdll/ntdll.h>
38
39 //#define DPRINTF DPRINT
40 //#define ERR DPRINT
41 //#define SetLastError(x)
42 //#define WARN DPRINT
43 #define TRACE DPRINT
44 #define FIXME DPRINT
45
46 //#define MAKEINTRESOURCE(i)  (LPTSTR) ((DWORD) ((WORD) (i)))
47 //#define MAKEINTRESOURCEA(i)  (LPTSTR) ((DWORD) ((WORD) (i)))
48 //#define MAKEINTRESOURCEW(i)  (LPTSTR) ((DWORD) ((WORD) (i)))
49
50 //#define MAKEINTRESOURCEA(i) (LPSTR)((ULONG_PTR)((WORD)(i)))
51 //#define MAKEINTRESOURCEW(i) (LPWSTR)((ULONG_PTR)((WORD)(i)))
52 //#define MAKEINTRESOURCE WINELIB_NAME_AW(MAKEINTRESOURCE)
53
54
55
56 int HEAP_strdupWtoA(HANDLE hHeap, int flags, LPWSTR lpSource)
57 {
58     return 0;
59 }
60
61 /* INTERNAL */
62
63 //#include "config.h"
64
65 #include <stdio.h>
66 #include <string.h>
67
68 //#include "windef.h"
69 //#include "winbase.h"
70 //#include "winerror.h"
71 //#include "winuser.h"
72 //#include "winnls.h"
73 //#include "wine/unicode.h"
74 //#include "heap.h"
75 //#include "wine/debug.h"
76
77 //WINE_DEFAULT_DEBUG_CHANNEL(resource);
78
79 typedef struct tagMESSAGE_RESOURCE_ENTRY {
80         WORD    Length;
81         WORD    Flags;
82         BYTE    Text[1];
83 } MESSAGE_RESOURCE_ENTRY,*PMESSAGE_RESOURCE_ENTRY;
84 #define MESSAGE_RESOURCE_UNICODE        0x0001
85
86 typedef struct tagMESSAGE_RESOURCE_BLOCK {
87         DWORD   LowId;
88         DWORD   HighId;
89         DWORD   OffsetToEntries;
90 } MESSAGE_RESOURCE_BLOCK,*PMESSAGE_RESOURCE_BLOCK;
91
92 typedef struct tagMESSAGE_RESOURCE_DATA {
93         DWORD                   NumberOfBlocks;
94         MESSAGE_RESOURCE_BLOCK  Blocks[ 1 ];
95 } MESSAGE_RESOURCE_DATA,*PMESSAGE_RESOURCE_DATA;
96
97
98 //#define RT_RCDATAA         MAKEINTRESOURCEA(10)
99 //#define RT_RCDATAW         MAKEINTRESOURCEW(10)
100 ////#define RT_RCDATA            WINELIB_NAME_AW(RT_RCDATA)
101 //#define RT_MESSAGETABLEA   MAKEINTRESOURCEA(11)
102 //#define RT_MESSAGETABLEW   MAKEINTRESOURCEW(11)
103 ////#define RT_MESSAGETABLE       WINELIB_NAME_AW(RT_MESSAGETABLE)
104
105 /* Messages...used by FormatMessage32* (KERNEL32.something)
106  *
107  * They can be specified either directly or using a message ID and
108  * loading them from the resource.
109  *
110  * The resourcedata has following format:
111  * start:
112  * 0: DWORD nrofentries
113  * nrofentries * subentry:
114  *      0: DWORD firstentry
115  *      4: DWORD lastentry
116  *      8: DWORD offset from start to the stringentries
117  *
118  * (lastentry-firstentry) * stringentry:
119  * 0: WORD len (0 marks end)    [ includes the 4 byte header length ]
120  * 2: WORD flags
121  * 4: CHAR[len-4]
122  *      (stringentry i of a subentry refers to the ID 'firstentry+i')
123  *
124  * Yes, ANSI strings in win32 resources. Go figure.
125  */
126
127 /**********************************************************************
128  *      load_messageA           (internal)
129  */
130 static INT load_messageA( HMODULE instance, UINT id, WORD lang,
131                           LPSTR buffer, INT buflen )
132 {
133     HGLOBAL     hmem;
134     HRSRC       hrsrc;
135     PMESSAGE_RESOURCE_DATA      mrd;
136     PMESSAGE_RESOURCE_BLOCK     mrb;
137     PMESSAGE_RESOURCE_ENTRY     mre;
138     int         i,slen;
139
140     //TRACE("instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD)instance, (DWORD)id, buffer, (DWORD)buflen);
141
142     /*FIXME: I am not sure about the '1' ... But I've only seen those entries*/
143     hrsrc = FindResourceExW(instance,RT_MESSAGETABLEW,(LPWSTR)1,lang);
144     if (!hrsrc) return 0;
145     hmem = LoadResource( instance, hrsrc );
146     if (!hmem) return 0;
147
148     mrd = (PMESSAGE_RESOURCE_DATA)LockResource(hmem);
149     mre = NULL;
150     mrb = &(mrd->Blocks[0]);
151     for (i=mrd->NumberOfBlocks;i--;) {
152         if ((id>=mrb->LowId) && (id<=mrb->HighId)) {
153             mre = (PMESSAGE_RESOURCE_ENTRY)(((char*)mrd)+mrb->OffsetToEntries);
154             id  -= mrb->LowId;
155             break;
156         }
157         mrb++;
158     }
159     if (!mre)
160         return 0;
161     for (i=id;i--;) {
162         if (!mre->Length)
163                 return 0;
164         mre = (PMESSAGE_RESOURCE_ENTRY)(((char*)mre)+mre->Length);
165     }
166     slen=mre->Length;
167     //TRACE("   - strlen=%d\n",slen);
168     i = min(buflen - 1, slen);
169     if (buffer == NULL)
170         return slen;
171     if (i>0) {
172         if (mre->Flags & MESSAGE_RESOURCE_UNICODE)
173             WideCharToMultiByte( CP_ACP, 0, (LPWSTR)mre->Text, -1, buffer, i, NULL, NULL );
174         else
175             lstrcpynA(buffer, (LPSTR)mre->Text, i);
176         buffer[i]=0;
177     } else {
178         if (buflen>1) {
179             buffer[0]=0;
180             return 0;
181         }
182     }
183     if (buffer) {
184         //TRACE("'%s' copied !\n", buffer);
185         TRACE("'%s'\n", buffer);
186     }
187     return i;
188 }
189
190 #if 0  /* FIXME */
191 /**********************************************************************
192  *      load_messageW   (internal)
193  */
194 static INT load_messageW( HMODULE instance, UINT id, WORD lang,
195                           LPWSTR buffer, INT buflen )
196 {
197     INT retval;
198     LPSTR buffer2 = NULL;
199     if (buffer && buflen)
200         buffer2 = HeapAlloc( GetProcessHeap(), 0, buflen );
201     retval = load_messageA(instance,id,lang,buffer2,buflen);
202     if (buffer)
203     {
204         if (retval) {
205             lstrcpynAtoW( buffer, buffer2, buflen );
206             retval = lstrlenW( buffer );
207         }
208         HeapFree( GetProcessHeap(), 0, buffer2 );
209     }
210     return retval;
211 }
212 #endif
213
214
215 /***********************************************************************
216  *           FormatMessageA   (KERNEL32.@)
217  * FIXME: missing wrap,
218  */
219 DWORD WINAPI FormatMessageA(
220         DWORD   dwFlags,
221         LPCVOID lpSource,
222         DWORD   dwMessageId,
223         DWORD   dwLanguageId,
224         LPSTR   lpBuffer,
225         DWORD   nSize,
226         va_list* _args )
227 {
228     LPDWORD args=(LPDWORD)_args;
229 #if defined(__i386__) || defined(__sparc__)
230 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
231     LPSTR       target,t;
232     DWORD       talloced;
233     LPSTR       from,f;
234     DWORD       width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
235     BOOL    eos = FALSE;
236     INT bufsize;
237     HMODULE     hmodule = (HMODULE)lpSource;
238     CHAR        ch;
239
240     //TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n", dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
241     if ((dwFlags & FORMAT_MESSAGE_FROM_STRING)
242         &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
243            || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0;
244
245     if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK)
246         FIXME("line wrapping (%lu) not supported.\n", width);
247     from = NULL;
248     if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
249     {
250         from = RtlAllocateHeap(RtlGetProcessHeap(), 0, lstrlenA((LPSTR)lpSource)+1 );
251         strcpy( from, (LPSTR)lpSource );
252     }
253     else {
254         bufsize = 0;
255
256         if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE)
257         {
258            bufsize=load_messageA(hmodule,dwMessageId,dwLanguageId,NULL,100);
259            if ((!bufsize) && (!dwLanguageId)) {
260                 bufsize=load_messageA(hmodule,dwMessageId,
261                                       MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),NULL,100);
262                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
263                                                     MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),NULL,100);
264                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
265                                                     MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
266                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
267                                                     MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
268                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
269                                                     MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NULL,100);
270             }
271         }
272         if ((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) && (!bufsize))
273         {
274            hmodule = GetModuleHandleA("kernel32");
275            bufsize=load_messageA(hmodule,dwMessageId,dwLanguageId,NULL,100);
276            if ((!bufsize) && (!dwLanguageId)) {
277                 bufsize=load_messageA(hmodule,dwMessageId,
278                                       MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),NULL,100);
279                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
280                                                     MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),NULL,100);
281                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
282                                                     MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
283                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
284                                                     MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
285                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
286                                                     MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NULL,100);
287             }
288         }
289
290         if (!bufsize) {
291             SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND);
292             return 0;
293         }
294  
295         from = RtlAllocateHeap(RtlGetProcessHeap(), 0, bufsize + 1 );
296         load_messageA(hmodule,dwMessageId,dwLanguageId,from,bufsize+1);
297     }
298     target      = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 100);
299     t   = target;
300     talloced= 100;
301
302 #define ADD_TO_T(c) do { \
303         *t++=c;\
304         if (t-target == talloced) {\
305             target = (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
306             t = target+talloced;\
307             talloced*=2;\
308       }\
309 } while (0)
310
311     if (from) {
312         f=from;
313         if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) {
314             while (*f && !eos)
315                 ADD_TO_T(*f++);
316         }
317         else {
318             while (*f && !eos) {
319                 if (*f=='%') {
320                     int insertnr;
321                     char *fmtstr,*x,*lastf;
322                     DWORD *argliststart;
323
324                     fmtstr = NULL;
325                     lastf = f;
326                     f++;
327                     if (!*f) {
328                         ADD_TO_T('%');
329                         continue;
330                     }
331                     switch (*f) {
332                     case '1':case '2':case '3':case '4':case '5':
333                     case '6':case '7':case '8':case '9':
334                         insertnr=*f-'0';
335                         switch (f[1]) {
336                         case '0':case '1':case '2':case '3':
337                         case '4':case '5':case '6':case '7':
338                         case '8':case '9':
339                             f++;
340                             insertnr=insertnr*10+*f-'0';
341                             f++;
342                             break;
343                         default:
344                             f++;
345                             break;
346                         }
347                         if (*f=='!') {
348                             f++;
349                             if (NULL!=(x=strchr(f,'!'))) {
350                                 *x='\0';
351                                 fmtstr=RtlAllocateHeap(RtlGetProcessHeap(),0,lstrlenA(f)+2);
352                                 sprintf(fmtstr,"%%%s",f);
353                                 f=x+1;
354                             } else {
355                                 fmtstr=RtlAllocateHeap(RtlGetProcessHeap(),0,lstrlenA(f)+2);
356                                 sprintf(fmtstr,"%%%s",f);
357                                 f+=lstrlenA(f); /*at \0*/
358                             }
359                         } else {
360                             if(!args) break;
361                             fmtstr = RtlAllocateHeap(RtlGetProcessHeap(),0,3);
362                             strcpy( fmtstr, "%s" );
363                         }
364                         if (args) {
365                             int sz;
366                             LPSTR b;
367
368                             if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
369                                 argliststart=args+insertnr-1;
370                             else
371                                 argliststart=(*(DWORD**)args)+insertnr-1;
372
373                                 /* FIXME: precision and width components are not handled correctly */
374                             if ( (strcmp(fmtstr, "%ls") == 0) || (strcmp(fmtstr,"%S") == 0) ) {
375                                 sz = WideCharToMultiByte( CP_ACP, 0, *(WCHAR**)argliststart, -1, NULL, 0, NULL, NULL);
376                                 b = RtlAllocateHeap(RtlGetProcessHeap(), 0, sz);
377                                 WideCharToMultiByte( CP_ACP, 0, *(WCHAR**)argliststart, -1, b, sz, NULL, NULL);
378                             } else {
379                                 b = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sz = 1000);
380                                 /* CMF - This makes a BIG assumption about va_list */
381                                 TRACE("A BIG assumption\n");
382                                 //vsnprintf(b, sz, fmtstr, (va_list) argliststart);
383                             }
384                             for (x=b; *x; x++) ADD_TO_T(*x);
385
386                             RtlFreeHeap(RtlGetProcessHeap(),0,b);
387                         } else {
388                                 /* NULL args - copy formatstr
389                                  * (probably wrong)
390                                  */
391                             while ((lastf<f)&&(*lastf)) {
392                                 ADD_TO_T(*lastf++);
393                             }
394                         }
395                         RtlFreeHeap(GetProcessHeap(),0,fmtstr);
396                         break;
397                     case 'n':
398                         ADD_TO_T('\r');
399                         ADD_TO_T('\n');
400                         f++;
401                         break;
402                     case '0':
403                         eos = TRUE;
404                         f++;
405                         break;
406                     default:
407                         ADD_TO_T(*f++);
408                         break;
409                     }
410                 } else {
411                     ch = *f;
412                     f++;
413                     if (ch == '\r') {
414                         if (*f == '\n')
415                             f++;
416                         if(width)
417                             ADD_TO_T(' ');
418                         else
419                         {
420                             ADD_TO_T('\r');
421                             ADD_TO_T('\n');
422                         }
423                     } else {
424                         if (ch == '\n')
425                         {
426                             if(width)
427                                 ADD_TO_T(' ');
428                             else
429                             {
430                                 ADD_TO_T('\r');
431                                 ADD_TO_T('\n');
432                             }
433                         }
434                         else
435                             ADD_TO_T(ch);
436                     }
437                 }
438             }
439         }
440         *t='\0';
441     }
442     talloced = lstrlenA(target)+1;
443     if (nSize && talloced<nSize) {
444         target = (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
445     }
446     //TRACE("-- %s\n",debugstr_a(target));
447     if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
448         *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,max(nSize, talloced));
449         memcpy(*(LPSTR*)lpBuffer,target,talloced);
450     } else {
451         lstrcpynA(lpBuffer,target,nSize);
452     }
453     RtlFreeHeap(RtlGetProcessHeap(),0,target);
454     if (from) RtlFreeHeap(RtlGetProcessHeap(),0,from);
455     //TRACE("-- returning %d\n", (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?  lstrlenA(*(LPSTR*)lpBuffer):lstrlenA(lpBuffer));
456     return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
457         lstrlenA(*(LPSTR*)lpBuffer):
458             lstrlenA(lpBuffer);
459 #else
460     return 0;
461 #endif /* __i386__ */
462 }
463 #undef ADD_TO_T
464
465
466 /***********************************************************************
467  *           FormatMessageW   (KERNEL32.@)
468  */
469 DWORD WINAPI FormatMessageW(
470         DWORD   dwFlags,
471         LPCVOID lpSource,
472         DWORD   dwMessageId,
473         DWORD   dwLanguageId,
474         LPWSTR  lpBuffer,
475         DWORD   nSize,
476         va_list* _args)
477 {
478     LPDWORD args=(LPDWORD)_args;
479 #if defined(__i386__) || defined(__sparc__)
480 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
481     LPSTR target,t;
482     DWORD talloced;
483     LPSTR from,f;
484     DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
485     BOOL eos = FALSE;
486     INT bufsize;
487     HMODULE hmodule = (HMODULE)lpSource;
488     CHAR ch;
489
490     //TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n", dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
491     if ((dwFlags & FORMAT_MESSAGE_FROM_STRING)
492         &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
493            || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0;
494
495     if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK) {
496         FIXME("line wrapping not supported.\n");
497     }
498     from = NULL;
499     if (dwFlags & FORMAT_MESSAGE_FROM_STRING) {
500         from = (LPSTR)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
501     }
502     else {
503         bufsize = 0;
504
505         if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE)
506         {
507            bufsize=load_messageA(hmodule,dwMessageId,dwLanguageId,NULL,100);
508            if ((!bufsize) && (!dwLanguageId)) {
509                 bufsize=load_messageA(hmodule,dwMessageId,
510                                       MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),NULL,100);
511                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
512                                                     MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),NULL,100);
513                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
514                                                     MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
515                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
516                                                     MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
517                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
518                                                     MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NULL,100);
519             }
520         }
521         if ((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) && (!bufsize))
522         {
523            hmodule = GetModuleHandleA("kernel32");
524            bufsize=load_messageA(hmodule,dwMessageId,dwLanguageId,NULL,100);
525            if ((!bufsize) && (!dwLanguageId)) {
526                 bufsize=load_messageA(hmodule,dwMessageId,
527                                       MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),NULL,100);
528                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
529                                                     MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),NULL,100);
530                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
531                                                     MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
532                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
533                                                     MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT),NULL,100);
534                 if (!bufsize) bufsize=load_messageA(hmodule,dwMessageId,
535                                                     MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),NULL,100);
536             }
537         }
538
539         if (!bufsize) {
540             SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND);
541             return 0;
542         }
543  
544         from = RtlAllocateHeap(RtlGetProcessHeap(), 0, bufsize + 1 );
545         load_messageA(hmodule,dwMessageId,dwLanguageId,from,bufsize+1);
546     }
547     target = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
548     t = target;
549     talloced= 100;
550
551 #define ADD_TO_T(c)  do {\
552     *t++=c;\
553     if (t-target == talloced) {\
554         target = (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
555         t = target+talloced;\
556         talloced*=2;\
557     } \
558 } while (0)
559
560     if (from) {
561         f=from;
562         if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) {
563             while (*f && !eos)
564                 ADD_TO_T(*f++);
565         }
566         else {
567             while (*f && !eos) {
568                 if (*f=='%') {
569                     int insertnr;
570                     char *fmtstr,*sprintfbuf,*x;
571                     DWORD *argliststart;
572
573                     fmtstr = NULL;
574                     f++;
575                     if (!*f) {
576                         ADD_TO_T('%');
577                         continue;
578                     }
579
580                     switch (*f) {
581                     case '1':case '2':case '3':case '4':case '5':
582                     case '6':case '7':case '8':case '9':
583                         insertnr=*f-'0';
584                         switch (f[1]) {
585                         case '0':case '1':case '2':case '3':
586                         case '4':case '5':case '6':case '7':
587                         case '8':case '9':
588                             f++;
589                             insertnr=insertnr*10+*f-'0';
590                             f++;
591                             break;
592                         default:
593                             f++;
594                             break;
595                         }
596                         if (*f=='!') {
597                             f++;
598                             if (NULL!=(x=strchr(f,'!'))) {
599                                 *x='\0';
600                                 fmtstr=RtlAllocateHeap(RtlGetProcessHeap(), 0, lstrlenA(f)+2);
601                                 sprintf(fmtstr,"%%%s",f);
602                                 f=x+1;
603                             } else {
604                                 fmtstr=RtlAllocateHeap(RtlGetProcessHeap(),0,lstrlenA(f));
605                                 sprintf(fmtstr,"%%%s",f);
606                                 f+=lstrlenA(f); /*at \0*/
607                             }
608                         } else {
609                             if(!args) break;
610                             fmtstr = RtlAllocateHeap(RtlGetProcessHeap(),0,3);
611                             strcpy( fmtstr, "%s" );
612                         }
613                         if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
614                             argliststart=args+insertnr-1;
615                         else
616                             argliststart=(*(DWORD**)args)+insertnr-1;
617
618                         if (fmtstr[lstrlenA(fmtstr)-1]=='s' && argliststart[0]) {
619                             DWORD xarr[3];
620
621                             xarr[0]=(DWORD)HEAP_strdupWtoA(RtlGetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
622                             /* possible invalid pointers */
623                             xarr[1]=*(argliststart+1);
624                             xarr[2]=*(argliststart+2);
625                             sprintfbuf=RtlAllocateHeap(RtlGetProcessHeap(),0,lstrlenW((LPWSTR)argliststart[0])*2+1);
626
627                             /* CMF - This makes a BIG assumption about va_list */
628                             vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
629                             RtlFreeHeap(RtlGetProcessHeap(), 0, (LPVOID) xarr[0]);
630                         } else {
631                             sprintfbuf=RtlAllocateHeap(RtlGetProcessHeap(),0,100);
632
633                             /* CMF - This makes a BIG assumption about va_list */
634                             vsprintf(sprintfbuf, fmtstr, (va_list) argliststart);
635                         }
636                         x=sprintfbuf;
637                         while (*x) {
638                             ADD_TO_T(*x++);
639                         }
640                         RtlFreeHeap(RtlGetProcessHeap(),0,sprintfbuf);
641                         RtlFreeHeap(RtlGetProcessHeap(),0,fmtstr);
642                         break;
643                     case 'n':
644                         ADD_TO_T('\r');
645                         ADD_TO_T('\n');
646                         f++;
647                         break;
648                     case '0':
649                         eos = TRUE;
650                         f++;
651                         break;
652                     default:
653                         ADD_TO_T(*f++);
654                         break;
655                     }
656                 } else {
657                     ch = *f;
658                     f++;
659                     if (ch == '\r') {
660                         if (*f == '\n')
661                             f++;
662                         if(width)
663                             ADD_TO_T(' ');
664                         else
665                         {
666                             ADD_TO_T('\r');
667                             ADD_TO_T('\n');
668                         }
669                     } else {
670                         if (ch == '\n')
671                         {
672                             if(width)
673                                 ADD_TO_T(' ');
674                             else
675                             {
676                                 ADD_TO_T('\r');
677                                 ADD_TO_T('\n');
678                             }
679                         }
680                         else
681                             ADD_TO_T(ch);
682                     }
683                 }
684             }
685         }
686         *t='\0';
687     }
688     talloced = lstrlenA(target)+1;
689     if (nSize && talloced<nSize)
690         target = (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
691     if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
692         /* nSize is the MINIMUM size */
693         DWORD len = MultiByteToWideChar( CP_ACP, 0, target, -1, NULL, 0 );
694         *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,len*sizeof(WCHAR));
695         MultiByteToWideChar( CP_ACP, 0, target, -1, *(LPWSTR*)lpBuffer, len );
696     }
697     else
698     {
699         if (nSize > 0 && !MultiByteToWideChar( CP_ACP, 0, target, -1, lpBuffer, nSize ))
700             lpBuffer[nSize-1] = 0;
701     }
702     RtlFreeHeap(RtlGetProcessHeap(),0,target);
703     if (from) RtlFreeHeap(RtlGetProcessHeap(),0,from);
704     return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
705         lstrlenW(*(LPWSTR*)lpBuffer):
706             lstrlenW(lpBuffer);
707 #else
708     return 0;
709 #endif /* __i386__ */
710 }
711 #undef ADD_TO_T
712
713
714 #else
715
716 /* EXPORTED */
717
718 /*
719  * @unimplemented
720  */
721 DWORD
722 STDCALL
723 FormatMessageW(
724     DWORD    dwFlags,
725     LPCVOID  lpSource,
726     DWORD    dwMessageId,
727     DWORD    dwLanguageId,
728     LPWSTR   lpBuffer,
729     DWORD    nSize,
730     va_list* Arguments)
731 {
732
733 // RtlFormatMessage
734
735     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
736     return 0;
737 }
738
739
740 /*
741  * @unimplemented
742  */
743 DWORD
744 STDCALL
745 FormatMessageA(
746     DWORD    dwFlags,
747     LPCVOID  lpSource,
748     DWORD    dwMessageId,
749     DWORD    dwLanguageId,
750     LPSTR    lpBuffer,
751     DWORD    nSize,
752     va_list* Arguments)
753 {
754     HLOCAL pBuf = NULL;
755     //LPSTR pBuf = NULL;
756
757 #define MAX_MSG_STR_LEN 200
758
759     if (lpBuffer != NULL) {
760
761         if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
762             pBuf = LocalAlloc(LPTR, max(nSize, MAX_MSG_STR_LEN));
763             if (pBuf == NULL) {
764                 return 0;
765             }
766             *(LPSTR*)lpBuffer = pBuf;
767         } else {
768             pBuf = *(LPSTR*)lpBuffer;
769         }
770
771         if (dwFlags & FORMAT_MESSAGE_FROM_STRING) {
772         } else {
773         }
774
775 //FORMAT_MESSAGE_IGNORE_INSERTS
776 //FORMAT_MESSAGE_FROM_STRING
777 //FORMAT_MESSAGE_FROM_HMODULE
778 //FORMAT_MESSAGE_FROM_SYSTEM
779 //FORMAT_MESSAGE_ARGUMENT_ARRAY 
780
781     }
782 /*
783         if (FormatMessage(
784           FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
785           0,
786           error,
787           MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
788           (PTSTR)&msg,
789           0,
790           NULL)
791         )
792  */
793     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
794     return 0;
795 }
796
797 #endif
798
799 /* EOF */