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