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