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