- New implementation of SendMessage, ReceiveMessage, ReplyMessage functions
[wine] / misc / lstr.c
1 /*
2  * String functions
3  *
4  * Copyright 1993 Yngvi Sigurjonsson (yngvi@hafro.is)
5  * Copyright 1996 Marcus Meissner
6  */
7
8 #include "config.h"
9
10 #include <stdarg.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14
15 #ifdef HAVE_WCTYPE_H
16 # include <wctype.h>
17 #else
18 # define iswalnum(c) isalnum(c)
19 # define iswalpha(c) isalpha(c)
20 # define iswupper(c) isupper(c)
21 # define iswlower(c) islower(c)
22 #endif  /* HAVE_WCTYPE_H */
23
24
25 #include "windows.h"
26 #include "winnt.h"      /* HEAP_ macros */
27 #include "task.h"
28 #include "heap.h"
29 #include "ldt.h"
30 #include "stackframe.h"
31 #include "module.h"
32 #include "debug.h"
33
34 extern const WORD OLE2NLS_CT_CType3_LUT[]; /* FIXME: does not belong here */
35
36
37 /* Funny to divide them between user and kernel. */
38
39 /* be careful: always use functions from wctype.h if character > 255 */
40
41 /*
42  * Unicode case conversion routines ... these should be used where
43  * toupper/tolower are used for ASCII.
44  */
45 #ifndef HAVE_WCTYPE_H
46 /* FIXME: should probably get rid of wctype.h altogether */
47 #include "casemap.h"
48
49 WCHAR towupper(WCHAR code)
50 {
51     const WCHAR * ptr = uprtable[HIBYTE(code)];
52     return ptr ? ptr[LOBYTE(code)] : code;
53 }
54
55 WCHAR towlower(WCHAR code)
56 {
57     const WCHAR * ptr = lwrtable[HIBYTE(code)];
58     return ptr ? ptr[LOBYTE(code)] : code;
59 }
60 #endif  /* HAVE_WCTYPE_H */
61
62 /***********************************************************************
63  *              IsCharAlpha (USER.433)
64  */
65 BOOL16 WINAPI IsCharAlpha16(CHAR ch)
66 {
67   return isalpha(ch);   /* This is probably not right for NLS */
68 }
69
70 /***********************************************************************
71  *              IsCharAlphanumeric (USER.434)
72  */
73 BOOL16 WINAPI IsCharAlphaNumeric16(CHAR ch)
74 {
75     return isalnum(ch);
76 }
77
78 /***********************************************************************
79  *              IsCharUpper (USER.435)
80  */
81 BOOL16 WINAPI IsCharUpper16(CHAR ch)
82 {
83   return isupper(ch);
84 }
85
86 /***********************************************************************
87  *              IsCharLower (USER.436)
88  */
89 BOOL16 WINAPI IsCharLower16(CHAR ch)
90 {
91   return islower(ch);
92 }
93
94 /***********************************************************************
95  *           AnsiUpper16   (USER.431)
96  */
97 SEGPTR WINAPI AnsiUpper16( SEGPTR strOrChar )
98 {
99   /* I am not sure if the locale stuff works with toupper, but then again 
100      I am not sure if the Linux libc locale stuffs works at all */
101
102     /* uppercase only one char if strOrChar < 0x10000 */
103     if (HIWORD(strOrChar))
104     {
105         char *s;
106         for (s = PTR_SEG_TO_LIN(strOrChar); *s; s++) *s = toupper(*s);
107         return strOrChar;
108     }
109     else return toupper((char)strOrChar);
110 }
111
112
113 /***********************************************************************
114  *           AnsiUpperBuff16   (USER.437)
115  */
116 UINT16 WINAPI AnsiUpperBuff16( LPSTR str, UINT16 len )
117 {
118     UINT32 count = len ? len : 65536;
119     for (; count; count--, str++) *str = toupper(*str);
120     return len;
121 }
122
123 /***********************************************************************
124  *           AnsiLower16   (USER.432)
125  */
126 SEGPTR WINAPI AnsiLower16( SEGPTR strOrChar )
127 {
128   /* I am not sure if the locale stuff works with toupper, but then again 
129      I am not sure if the Linux libc locale stuffs works at all */
130
131     /* lowercase only one char if strOrChar < 0x10000 */
132     if (HIWORD(strOrChar))
133     {
134         char *s;
135         for (s = PTR_SEG_TO_LIN( strOrChar ); *s; s++) *s = tolower( *s );
136         return strOrChar;
137     }
138     else return tolower((char)strOrChar);
139 }
140
141
142 /***********************************************************************
143  *           AnsiLowerBuff16   (USER.438)
144  */
145 UINT16 WINAPI AnsiLowerBuff16( LPSTR str, UINT16 len )
146 {
147     UINT32 count = len ? len : 65536;
148     for (; count; count--, str++) *str = tolower(*str);
149     return len;
150 }
151
152
153 /***********************************************************************
154  *           AnsiNext16   (USER.472)
155  */
156 SEGPTR WINAPI AnsiNext16(SEGPTR current)
157 {
158     return (*(char *)PTR_SEG_TO_LIN(current)) ? current + 1 : current;
159 }
160
161
162 /***********************************************************************
163  *           AnsiPrev16   (USER.473)
164  */
165 SEGPTR WINAPI AnsiPrev16( SEGPTR start, SEGPTR current )
166 {
167     return (current == start) ? start : current - 1;
168 }
169
170
171 /***********************************************************************
172  *           OutputDebugString16   (KERNEL.115)
173  */
174 void WINAPI OutputDebugString16( LPCSTR str )
175 {
176     char module[10];
177     if (!GetModuleName( GetCurrentTask(), module, sizeof(module) ))
178         strcpy( module, "???" );
179
180     DUMP( "%s says %s\n", module, debugstr_a(str) );
181 }
182
183
184 /***********************************************************************
185  *           OutputDebugString32A   (KERNEL32
186  */
187 void WINAPI OutputDebugString32A( LPCSTR str )
188 {
189     OutputDebugString16( str );
190 }
191
192
193
194 /***********************************************************************
195  *           OutputDebugString32W   (KERNEL32
196  */
197 void WINAPI OutputDebugString32W( LPCWSTR str )
198 {
199     LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
200     OutputDebugString32A( p );
201     HeapFree( GetProcessHeap(), 0, p );
202 }
203
204
205
206 /***********************************************************************
207  *           CharNext32A   (USER32.29)
208  */
209 LPSTR WINAPI CharNext32A( LPCSTR ptr )
210 {
211     if (!*ptr) return (LPSTR)ptr;
212     if (IsDBCSLeadByte32( *ptr )) return (LPSTR)(ptr + 2);
213     return (LPSTR)(ptr + 1);
214 }
215
216
217 /***********************************************************************
218  *           CharNextEx32A   (USER32.30)
219  */
220 LPSTR WINAPI CharNextEx32A( WORD codepage, LPCSTR ptr, DWORD flags )
221 {
222     if (!*ptr) return (LPSTR)ptr;
223     if (IsDBCSLeadByteEx( codepage, *ptr )) return (LPSTR)(ptr + 2);
224     return (LPSTR)(ptr + 1);
225 }
226
227
228 /***********************************************************************
229  *           CharNextExW   (USER32.31)
230  */
231 LPWSTR WINAPI CharNextEx32W(WORD codepage,LPCWSTR x,DWORD flags)
232 {
233     /* FIXME: add DBCS / codepage stuff */
234     if (*x) return (LPWSTR)(x+1);
235     else return (LPWSTR)x;
236 }
237
238 /***********************************************************************
239  *           CharNextW   (USER32.32)
240  */
241 LPWSTR WINAPI CharNext32W(LPCWSTR x)
242 {
243     if (*x) return (LPWSTR)(x+1);
244     else return (LPWSTR)x;
245 }
246
247 /***********************************************************************
248  *           CharPrev32A   (USER32.33)
249  */
250 LPSTR WINAPI CharPrev32A( LPCSTR start, LPCSTR ptr )
251 {
252     while (*start && (start < ptr))
253     {
254         LPCSTR next = CharNext32A( start );
255         if (next >= ptr) break;
256         start = next;
257     }
258     return (LPSTR)start;
259 }
260
261
262 /***********************************************************************
263  *           CharPrevEx32A   (USER32.34)
264  */
265 LPSTR WINAPI CharPrevEx32A( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
266 {
267     while (*start && (start < ptr))
268     {
269         LPCSTR next = CharNextEx32A( codepage, start, flags );
270         if (next > ptr) break;
271         start = next;
272     }
273     return (LPSTR)start;
274 }
275
276
277 /***********************************************************************
278  *           CharPrevExW   (USER32.35)
279  */
280 LPWSTR WINAPI CharPrevEx32W(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
281 {
282     /* FIXME: add DBCS / codepage stuff */
283     if (x>start) return (LPWSTR)(x-1);
284     else return (LPWSTR)x;
285 }
286
287 /***********************************************************************
288  *           CharPrevW   (USER32.36)
289  */
290 LPWSTR WINAPI CharPrev32W(LPCWSTR start,LPCWSTR x)
291 {
292     if (x>start) return (LPWSTR)(x-1);
293     else return (LPWSTR)x;
294 }
295
296 /***********************************************************************
297  *           CharLowerA   (USER32.25)
298  * FIXME: handle current locale
299  */
300 LPSTR WINAPI CharLower32A(LPSTR x)
301 {
302     LPSTR       s;
303
304     if (HIWORD(x))
305     {
306         s=x;
307         while (*s)
308         {
309             *s=tolower(*s);
310             s++;
311         }
312         return x;
313     }
314     else return (LPSTR)tolower((char)(int)x);
315 }
316
317 /***********************************************************************
318  *           CharLowerBuffA   (USER32.26)
319  * FIXME: handle current locale
320  */
321 DWORD WINAPI CharLowerBuff32A(LPSTR x,DWORD buflen)
322 {
323     DWORD done=0;
324
325     if (!x) return 0; /* YES */
326     while (*x && (buflen--))
327     {
328         *x=tolower(*x);
329         x++;
330         done++;
331     }
332     return done;
333 }
334
335 /***********************************************************************
336  *           CharLowerBuffW   (USER32.27)
337  * FIXME: handle current locale
338  */
339 DWORD WINAPI CharLowerBuff32W(LPWSTR x,DWORD buflen)
340 {
341     DWORD done=0;
342
343     if (!x) return 0; /* YES */
344     while (*x && (buflen--))
345     {
346         *x=towlower(*x);
347         x++;
348         done++;
349     }
350     return done;
351 }
352
353 /***********************************************************************
354  *           CharLowerW   (USER32.28)
355  * FIXME: handle current locale
356  */
357 LPWSTR WINAPI CharLower32W(LPWSTR x)
358 {
359     if (HIWORD(x))
360     {
361         LPWSTR s = x;
362         while (*s)
363         {
364             *s=towlower(*s);
365             s++;
366         }
367         return x;
368     }
369     else return (LPWSTR)((UINT32)towlower(LOWORD(x)));
370 }
371
372 /***********************************************************************
373  *           CharUpper32A   (USER32.41)
374  * FIXME: handle current locale
375  */
376 LPSTR WINAPI CharUpper32A(LPSTR x)
377 {
378     if (HIWORD(x))
379     {
380         LPSTR s = x;
381         while (*s)
382         {
383             *s=toupper(*s);
384             s++;
385         }
386         return x;
387     }
388     return (LPSTR)toupper((char)(int)x);
389 }
390
391 /***********************************************************************
392  *           CharUpperBuffA   (USER32.42)
393  * FIXME: handle current locale
394  */
395 DWORD WINAPI CharUpperBuff32A(LPSTR x,DWORD buflen)
396 {
397     DWORD done=0;
398
399     if (!x) return 0; /* YES */
400     while (*x && (buflen--))
401     {
402         *x=toupper(*x);
403         x++;
404         done++;
405     }
406     return done;
407 }
408
409 /***********************************************************************
410  *           CharUpperBuffW   (USER32.43)
411  * FIXME: handle current locale
412  */
413 DWORD WINAPI CharUpperBuff32W(LPWSTR x,DWORD buflen)
414 {
415     DWORD done=0;
416
417     if (!x) return 0; /* YES */
418     while (*x && (buflen--))
419     {
420         *x=towupper(*x);
421         x++;
422         done++;
423     }
424     return done;
425 }
426
427 /***********************************************************************
428  *           CharUpperW   (USER32.44)
429  * FIXME: handle current locale
430  */
431 LPWSTR WINAPI CharUpper32W(LPWSTR x)
432 {
433     if (HIWORD(x))
434     {
435         LPWSTR s = x;
436         while (*s)
437         {
438             *s=towupper(*s);
439             s++;
440         }
441         return x;
442     }
443     else return (LPWSTR)((UINT32)towupper(LOWORD(x)));
444 }
445
446 /***********************************************************************
447  *           IsCharAlphaA   (USER32.331)
448  * FIXME: handle current locale
449  */
450 BOOL32 WINAPI IsCharAlpha32A(CHAR x)
451 {
452     return (OLE2NLS_CT_CType3_LUT[(unsigned char)x] & C3_ALPHA);
453 }
454
455 /***********************************************************************
456  *           IsCharAlphaNumericA   (USER32.332)
457  * FIXME: handle current locale
458  */
459 BOOL32 WINAPI IsCharAlphaNumeric32A(CHAR x)
460 {
461     return IsCharAlpha32A(x) || isdigit(x) ;
462 }
463
464 /***********************************************************************
465  *           IsCharAlphaNumericW   (USER32.333)
466  * FIXME: handle current locale
467  */
468 BOOL32 WINAPI IsCharAlphaNumeric32W(WCHAR x)
469 {
470     return iswalnum(x);
471 }
472
473 /***********************************************************************
474  *           IsCharAlphaW   (USER32.334)
475  * FIXME: handle current locale
476  */
477 BOOL32 WINAPI IsCharAlpha32W(WCHAR x)
478 {
479     return iswalpha(x);
480 }
481
482 /***********************************************************************
483  *           IsCharLower32A   (USER32.335)
484  * FIXME: handle current locale
485  */
486 BOOL32 WINAPI IsCharLower32A(CHAR x)
487 {
488     return islower(x);
489 }
490
491 /***********************************************************************
492  *           IsCharLower32W   (USER32.336)
493  * FIXME: handle current locale
494  */
495 BOOL32 WINAPI IsCharLower32W(WCHAR x)
496 {
497     return iswlower(x);
498 }
499
500 /***********************************************************************
501  *           IsCharUpper32A   (USER32.337)
502  * FIXME: handle current locale
503  */
504 BOOL32 WINAPI IsCharUpper32A(CHAR x)
505 {
506     return isupper(x);
507 }
508
509 /***********************************************************************
510  *           IsCharUpper32W   (USER32.338)
511  * FIXME: handle current locale
512  */
513 BOOL32 WINAPI IsCharUpper32W(WCHAR x)
514 {
515     return iswupper(x);
516 }
517
518 /***********************************************************************
519  *           FormatMessage16   (USER.606)
520  */
521 DWORD WINAPI FormatMessage16(
522     DWORD   dwFlags,
523     LPCVOID lpSource,
524     WORD   dwMessageId,
525     WORD   dwLanguageId,
526     LPSTR   lpBuffer,
527     WORD   nSize,
528     LPDWORD args /* va_list *args */
529 ) {
530     return FormatMessage32A(dwFlags, lpSource, (DWORD)dwMessageId, (DWORD)dwLanguageId, lpBuffer, (DWORD)nSize, args);
531 }
532
533 /***********************************************************************
534  *           FormatMessage32A   (KERNEL32.138)
535  * FIXME: missing wrap,FROM_SYSTEM message-loading,
536  */
537 DWORD WINAPI FormatMessage32A(
538         DWORD   dwFlags,
539         LPCVOID lpSource,
540         DWORD   dwMessageId,
541         DWORD   dwLanguageId,
542         LPSTR   lpBuffer,
543         DWORD   nSize,
544         LPDWORD args /* va_list *args */
545 ) {
546 #ifdef __i386__
547 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
548         LPSTR   target,t;
549         DWORD   talloced;
550         LPSTR   from,f;
551         DWORD   width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
552         DWORD   nolinefeed = 0;
553
554         TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
555                      dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
556         if (width) 
557                 FIXME(resource,"line wrapping not supported.\n");
558         from = NULL;
559         if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
560                 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
561         if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
562                 from = HeapAlloc( GetProcessHeap(),0,200 );
563                 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
564         }
565         if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
566                 INT32   bufsize;
567
568                 dwMessageId &= 0xFFFF;
569                 bufsize=LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,NULL,100);
570                 if (bufsize) {
571                         from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
572                         LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
573                 }
574         }
575         target  = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
576         t       = target;
577         talloced= 100;
578
579 #define ADD_TO_T(c) \
580         *t++=c;\
581         if (t-target == talloced) {\
582                 target  = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
583                 t       = target+talloced;\
584                 talloced*=2;\
585         }
586
587         if (from) {
588                 f=from;
589                 while (*f && !nolinefeed) {
590                         if (*f=='%') {
591                                 int     insertnr;
592                                 char    *fmtstr,*sprintfbuf,*x,*lastf;
593                                 DWORD   *argliststart;
594
595                                 fmtstr = NULL;
596                                 lastf = f;
597                                 f++;
598                                 if (!*f) {
599                                         ADD_TO_T('%');
600                                         continue;
601                                 }
602                                 switch (*f) {
603                                 case '1':case '2':case '3':case '4':case '5':
604                                 case '6':case '7':case '8':case '9':
605                                         insertnr=*f-'0';
606                                         switch (f[1]) {
607                                         case '0':case '1':case '2':case '3':
608                                         case '4':case '5':case '6':case '7':
609                                         case '8':case '9':
610                                                 f++;
611                                                 insertnr=insertnr*10+*f-'0';
612                                                 f++;
613                                                 break;
614                                         default:
615                                                 f++;
616                                                 break;
617                                         }
618                                         if (*f=='!') {
619                                                 f++;
620                                                 if (NULL!=(x=strchr(f,'!'))) {
621                                                         *x='\0';
622                                                         fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
623                                                         sprintf(fmtstr,"%%%s",f);
624                                                         f=x+1;
625                                                 } else {
626                                                         fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
627                                                         sprintf(fmtstr,"%%%s",f);
628                                                         f+=strlen(f); /*at \0*/
629                                                 }
630                                         } else
631                                                 if(!args) 
632                                                   break;
633                                         else
634                                                 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
635                                         if (args) {
636                                                 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
637                                                         argliststart=args+insertnr-1;
638                                                 else
639                                                     argliststart=(*(DWORD**)args)+insertnr-1;
640
641                                                 if (fmtstr[strlen(fmtstr)-1]=='s')
642                                                         sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
643                                                 else
644                                                         sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
645
646                                                 /* CMF - This makes a BIG assumption about va_list */
647                                                 wvsprintf32A(sprintfbuf, fmtstr, (va_list) argliststart);
648                                                 x=sprintfbuf;
649                                                 while (*x) {
650                                                         ADD_TO_T(*x++);
651                                                 }
652                                                 HeapFree(GetProcessHeap(),0,sprintfbuf);
653                                         } else {
654                                                 /* NULL args - copy formatstr 
655                                                  * (probably wrong)
656                                                  */
657                                                 while ((lastf<f)&&(*lastf)) {
658                                                         ADD_TO_T(*lastf++);
659                                                 }
660                                         }
661                                         HeapFree(GetProcessHeap(),0,fmtstr);
662                                         break;
663                                 case 'n':
664                                         /* FIXME: perhaps add \r too? */
665                                         ADD_TO_T('\n');
666                                         f++;
667                                         break;
668                                 case '0':
669                                         nolinefeed=1;
670                                         f++;
671                                         break;
672                                 default:ADD_TO_T(*f++)
673                                         break;
674
675                                 }
676                         } else {
677                                 ADD_TO_T(*f++)
678                         }
679                 }
680                 *t='\0';
681         }
682         if (!nolinefeed) {
683             /* add linefeed */
684             if(t==target || t[-1]!='\n')
685                 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
686         }
687         talloced = strlen(target)+1;
688         if (nSize && talloced<nSize) {
689                 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
690         }
691     TRACE(resource,"-- %s\n",debugstr_a(target));
692         if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
693                 /* nSize is the MINIMUM size */
694                 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced);
695                 memcpy(*(LPSTR*)lpBuffer,target,talloced);
696         } else
697                 strncpy(lpBuffer,target,nSize);
698         HeapFree(GetProcessHeap(),0,target);
699         if (from) HeapFree(GetProcessHeap(),0,from);
700         return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? 
701                         strlen(*(LPSTR*)lpBuffer):
702                         strlen(lpBuffer);
703 #else
704         return 0;
705 #endif /* __i386__ */
706 }
707 #undef ADD_TO_T
708
709
710 /***********************************************************************
711  *           FormatMessage32W   (KERNEL32.138)
712  */
713 DWORD WINAPI FormatMessage32W(
714         DWORD   dwFlags,
715         LPCVOID lpSource,
716         DWORD   dwMessageId,
717         DWORD   dwLanguageId,
718         LPWSTR  lpBuffer,
719         DWORD   nSize,
720         LPDWORD args /* va_list *args */
721 ) {
722 #ifdef __i386__
723 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
724         LPSTR   target,t;
725         DWORD   talloced;
726         LPSTR   from,f;
727         DWORD   width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
728         DWORD   nolinefeed = 0;
729
730         TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
731                      dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
732         if (width) 
733                 FIXME(resource,"line wrapping not supported.\n");
734         from = NULL;
735         if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
736                 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
737         if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
738                 /* gather information from system message tables ... */
739                 from = HeapAlloc( GetProcessHeap(),0,200 );
740                 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
741         }
742         if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
743                 INT32   bufsize;
744
745                 dwMessageId &= 0xFFFF;
746                 bufsize=LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,NULL,100);
747                 if (bufsize)
748                 {
749                     from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
750                     LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
751                 }
752         }
753         target  = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
754         t       = target;
755         talloced= 100;
756
757 #define ADD_TO_T(c) \
758         *t++=c;\
759         if (t-target == talloced) {\
760                 target  = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
761                 t       = target+talloced;\
762                 talloced*=2;\
763         }
764
765         if (from) {
766                 f=from;
767                 while (*f && !nolinefeed) {
768                         if (*f=='%') {
769                                 int     insertnr;
770                                 char    *fmtstr,*sprintfbuf,*x;
771                                 DWORD   *argliststart;
772
773                                 fmtstr = NULL;
774                                 f++;
775                                 if (!*f) {
776                                         ADD_TO_T('%');
777                                         continue;
778                                 }
779                                 switch (*f) {
780                                 case '1':case '2':case '3':case '4':case '5':
781                                 case '6':case '7':case '8':case '9':
782                                         insertnr=*f-'0';
783                                         switch (f[1]) {
784                                         case '0':case '1':case '2':case '3':
785                                         case '4':case '5':case '6':case '7':
786                                         case '8':case '9':
787                                                 f++;
788                                                 insertnr=insertnr*10+*f-'0';
789                                                 f++;
790                                                 break;
791                                         default:
792                                                 f++;
793                                                 break;
794                                         }
795                                         if (*f=='!') {
796                                                 f++;
797                                                 if (NULL!=(x=strchr(f,'!')))
798                                                 {
799                                                     *x='\0';
800                                                     fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
801                                                         sprintf(fmtstr,"%%%s",f);
802                                                         f=x+1;
803                                                 } else {
804                                                         fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
805                                                         sprintf(fmtstr,"%%%s",f);
806                                                         f+=strlen(f); /*at \0*/
807                                                 }
808                                         } else
809                                                 if(!args)
810                                                   break;
811                                         else
812                                                 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
813                                         if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
814                                                 argliststart=args+insertnr-1;
815                                         else
816                                                 argliststart=(*(DWORD**)args)+insertnr-1;
817
818                                         if (fmtstr[strlen(fmtstr)-1]=='s') {
819                                                 DWORD   xarr[3];
820
821                                                 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
822                                                 /* possible invalid pointers */
823                                                 xarr[1]=*(argliststart+1);
824                                                 xarr[2]=*(argliststart+2);
825                                                 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlen32W((LPWSTR)argliststart[0])*2+1);
826
827                                                 /* CMF - This makes a BIG assumption about va_list */
828                                                 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
829                                         } else {
830                                                 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
831
832                                                 /* CMF - This makes a BIG assumption about va_list */
833                                                 wvsprintf32A(sprintfbuf, fmtstr, (va_list) argliststart);
834                                         }
835                                         x=sprintfbuf;
836                                         while (*x) {
837                                                 ADD_TO_T(*x++);
838                                         }
839                                         HeapFree(GetProcessHeap(),0,sprintfbuf);
840                                         HeapFree(GetProcessHeap(),0,fmtstr);
841                                         break;
842                                 case 'n':
843                                         /* FIXME: perhaps add \r too? */
844                                         ADD_TO_T('\n');
845                                         f++;
846                                         break;
847                                 case '0':
848                                         nolinefeed=1;
849                                         f++;
850                                         break;
851                                 default:ADD_TO_T(*f++)
852                                         break;
853
854                                 }
855                         } else {
856                                 ADD_TO_T(*f++)
857                         }
858                 }
859                 *t='\0';
860         }
861         if (!nolinefeed) {
862             /* add linefeed */
863             if(t==target || t[-1]!='\n')
864                 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
865         }
866         talloced = strlen(target)+1;
867         if (nSize && talloced<nSize)
868                 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
869         if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
870                 /* nSize is the MINIMUM size */
871                 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced*2+2);
872                 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
873         } else
874                 lstrcpynAtoW(lpBuffer,target,nSize);
875         HeapFree(GetProcessHeap(),0,target);
876         if (from) HeapFree(GetProcessHeap(),0,from);
877         return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? 
878                         lstrlen32W(*(LPWSTR*)lpBuffer):
879                         lstrlen32W(lpBuffer);
880 #else
881         return 0;
882 #endif /* __i386__ */
883 }
884 #undef ADD_TO_T