Updated Finnish language support.
[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  *           FormatMessage16   (USER.606)
517  */
518 DWORD WINAPI FormatMessage16(
519     DWORD   dwFlags,
520     LPCVOID lpSource,
521     WORD   dwMessageId,
522     WORD   dwLanguageId,
523     LPSTR   lpBuffer,
524     WORD   nSize,
525     LPDWORD args /* va_list *args */
526 ) {
527     return FormatMessage32A(dwFlags, lpSource, (DWORD)dwMessageId, (DWORD)dwLanguageId, lpBuffer, (DWORD)nSize, args);
528 }
529
530 /***********************************************************************
531  *           FormatMessage32A   (KERNEL32.138)
532  * FIXME: missing wrap,FROM_SYSTEM message-loading,
533  */
534 DWORD WINAPI FormatMessage32A(
535         DWORD   dwFlags,
536         LPCVOID lpSource,
537         DWORD   dwMessageId,
538         DWORD   dwLanguageId,
539         LPSTR   lpBuffer,
540         DWORD   nSize,
541         LPDWORD args /* va_list *args */
542 ) {
543         LPSTR   target,t;
544         DWORD   talloced;
545         LPSTR   from,f;
546         DWORD   width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
547         DWORD   nolinefeed = 0;
548
549         TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
550                      dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
551         if (width) 
552                 FIXME(resource,"line wrapping not supported.\n");
553         from = NULL;
554         if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
555                 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
556         if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
557                 from = HeapAlloc( GetProcessHeap(),0,200 );
558                 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
559         }
560         if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
561                 INT32   bufsize;
562
563                 dwMessageId &= 0xFFFF;
564                 bufsize=LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,NULL,100);
565                 if (bufsize) {
566                         from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
567                         LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
568                 }
569         }
570         target  = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
571         t       = target;
572         talloced= 100;
573
574 #define ADD_TO_T(c) \
575         *t++=c;\
576         if (t-target == talloced) {\
577                 target  = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
578                 t       = target+talloced;\
579                 talloced*=2;\
580         }
581
582         if (from) {
583                 f=from;
584                 while (*f && !nolinefeed) {
585                         if (*f=='%') {
586                                 int     insertnr;
587                                 char    *fmtstr,*sprintfbuf,*x,*lastf;
588                                 DWORD   *argliststart;
589
590                                 fmtstr = NULL;
591                                 lastf = f;
592                                 f++;
593                                 if (!*f) {
594                                         ADD_TO_T('%');
595                                         continue;
596                                 }
597                                 switch (*f) {
598                                 case '1':case '2':case '3':case '4':case '5':
599                                 case '6':case '7':case '8':case '9':
600                                         insertnr=*f-'0';
601                                         switch (f[1]) {
602                                         case '0':case '1':case '2':case '3':
603                                         case '4':case '5':case '6':case '7':
604                                         case '8':case '9':
605                                                 f++;
606                                                 insertnr=insertnr*10+*f-'0';
607                                                 f++;
608                                                 break;
609                                         default:
610                                                 f++;
611                                                 break;
612                                         }
613                                         if (*f=='!') {
614                                                 f++;
615                                                 if (NULL!=(x=strchr(f,'!'))) {
616                                                         *x='\0';
617                                                         fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
618                                                         sprintf(fmtstr,"%%%s",f);
619                                                         f=x+1;
620                                                 } else {
621                                                         fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
622                                                         sprintf(fmtstr,"%%%s",f);
623                                                         f+=strlen(f); /*at \0*/
624                                                 }
625                                         } else
626                                                 if(!args) 
627                                                   break;
628                                         else
629                                                 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
630                                         if (args) {
631                                                 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
632                                                         argliststart=args+insertnr-1;
633                                                 else
634                                                     argliststart=(*(DWORD**)args)+insertnr-1;
635
636                                                 if (fmtstr[strlen(fmtstr)-1]=='s')
637                                                         sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
638                                                 else
639                                                         sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
640
641                                                 /* CMF - This makes a BIG assumption about va_list */
642                                                 wvsprintf32A(sprintfbuf, fmtstr, (va_list) argliststart);
643                                                 x=sprintfbuf;
644                                                 while (*x) {
645                                                         ADD_TO_T(*x++);
646                                                 }
647                                                 HeapFree(GetProcessHeap(),0,sprintfbuf);
648                                         } else {
649                                                 /* NULL args - copy formatstr 
650                                                  * (probably wrong)
651                                                  */
652                                                 while ((lastf<f)&&(*lastf)) {
653                                                         ADD_TO_T(*lastf++);
654                                                 }
655                                         }
656                                         HeapFree(GetProcessHeap(),0,fmtstr);
657                                         break;
658                                 case 'n':
659                                         /* FIXME: perhaps add \r too? */
660                                         ADD_TO_T('\n');
661                                         f++;
662                                         break;
663                                 case '0':
664                                         nolinefeed=1;
665                                         f++;
666                                         break;
667                                 default:ADD_TO_T(*f++)
668                                         break;
669
670                                 }
671                         } else {
672                                 ADD_TO_T(*f++)
673                         }
674                 }
675                 *t='\0';
676         }
677         if (!nolinefeed) {
678             /* add linefeed */
679             if(t==target || t[-1]!='\n')
680                 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
681         }
682         talloced = strlen(target)+1;
683         if (nSize && talloced<nSize) {
684                 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
685         }
686     TRACE(resource,"-- %s\n",debugstr_a(target));
687         if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
688                 /* nSize is the MINIMUM size */
689                 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced);
690                 memcpy(*(LPSTR*)lpBuffer,target,talloced);
691         } else
692                 strncpy(lpBuffer,target,nSize);
693         HeapFree(GetProcessHeap(),0,target);
694         if (from) HeapFree(GetProcessHeap(),0,from);
695         return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? 
696                         strlen(*(LPSTR*)lpBuffer):
697                         strlen(lpBuffer);
698 }
699 #undef ADD_TO_T
700
701
702 /***********************************************************************
703  *           FormatMessage32W   (KERNEL32.138)
704  */
705 DWORD WINAPI FormatMessage32W(
706         DWORD   dwFlags,
707         LPCVOID lpSource,
708         DWORD   dwMessageId,
709         DWORD   dwLanguageId,
710         LPWSTR  lpBuffer,
711         DWORD   nSize,
712         LPDWORD args /* va_list *args */
713 ) {
714         LPSTR   target,t;
715         DWORD   talloced;
716         LPSTR   from,f;
717         DWORD   width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
718         DWORD   nolinefeed = 0;
719
720         TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
721                      dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
722         if (width) 
723                 FIXME(resource,"line wrapping not supported.\n");
724         from = NULL;
725         if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
726                 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
727         if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
728                 /* gather information from system message tables ... */
729                 from = HeapAlloc( GetProcessHeap(),0,200 );
730                 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
731         }
732         if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
733                 INT32   bufsize;
734
735                 dwMessageId &= 0xFFFF;
736                 bufsize=LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,NULL,100);
737                 if (bufsize)
738                 {
739                     from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
740                     LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
741                 }
742         }
743         target  = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
744         t       = target;
745         talloced= 100;
746
747 #define ADD_TO_T(c) \
748         *t++=c;\
749         if (t-target == talloced) {\
750                 target  = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
751                 t       = target+talloced;\
752                 talloced*=2;\
753         }
754
755         if (from) {
756                 f=from;
757                 while (*f && !nolinefeed) {
758                         if (*f=='%') {
759                                 int     insertnr;
760                                 char    *fmtstr,*sprintfbuf,*x;
761                                 DWORD   *argliststart;
762
763                                 fmtstr = NULL;
764                                 f++;
765                                 if (!*f) {
766                                         ADD_TO_T('%');
767                                         continue;
768                                 }
769                                 switch (*f) {
770                                 case '1':case '2':case '3':case '4':case '5':
771                                 case '6':case '7':case '8':case '9':
772                                         insertnr=*f-'0';
773                                         switch (f[1]) {
774                                         case '0':case '1':case '2':case '3':
775                                         case '4':case '5':case '6':case '7':
776                                         case '8':case '9':
777                                                 f++;
778                                                 insertnr=insertnr*10+*f-'0';
779                                                 f++;
780                                                 break;
781                                         default:
782                                                 f++;
783                                                 break;
784                                         }
785                                         if (*f=='!') {
786                                                 f++;
787                                                 if (NULL!=(x=strchr(f,'!')))
788                                                 {
789                                                     *x='\0';
790                                                     fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
791                                                         sprintf(fmtstr,"%%%s",f);
792                                                         f=x+1;
793                                                 } else {
794                                                         fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
795                                                         sprintf(fmtstr,"%%%s",f);
796                                                         f+=strlen(f); /*at \0*/
797                                                 }
798                                         } else
799                                                 if(!args)
800                                                   break;
801                                         else
802                                                 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
803                                         if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
804                                                 argliststart=args+insertnr-1;
805                                         else
806                                                 argliststart=(*(DWORD**)args)+insertnr-1;
807
808                                         if (fmtstr[strlen(fmtstr)-1]=='s') {
809                                                 DWORD   xarr[3];
810
811                                                 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
812                                                 /* possible invalid pointers */
813                                                 xarr[1]=*(argliststart+1);
814                                                 xarr[2]=*(argliststart+2);
815                                                 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlen32W((LPWSTR)argliststart[0])*2+1);
816
817                                                 /* CMF - This makes a BIG assumption about va_list */
818                                                 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
819                                         } else {
820                                                 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
821
822                                                 /* CMF - This makes a BIG assumption about va_list */
823                                                 wvsprintf32A(sprintfbuf, fmtstr, (va_list) argliststart);
824                                         }
825                                         x=sprintfbuf;
826                                         while (*x) {
827                                                 ADD_TO_T(*x++);
828                                         }
829                                         HeapFree(GetProcessHeap(),0,sprintfbuf);
830                                         HeapFree(GetProcessHeap(),0,fmtstr);
831                                         break;
832                                 case 'n':
833                                         /* FIXME: perhaps add \r too? */
834                                         ADD_TO_T('\n');
835                                         f++;
836                                         break;
837                                 case '0':
838                                         nolinefeed=1;
839                                         f++;
840                                         break;
841                                 default:ADD_TO_T(*f++)
842                                         break;
843
844                                 }
845                         } else {
846                                 ADD_TO_T(*f++)
847                         }
848                 }
849                 *t='\0';
850         }
851         if (!nolinefeed) {
852             /* add linefeed */
853             if(t==target || t[-1]!='\n')
854                 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
855         }
856         talloced = strlen(target)+1;
857         if (nSize && talloced<nSize)
858                 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
859         if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
860                 /* nSize is the MINIMUM size */
861                 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced*2+2);
862                 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
863         } else
864                 lstrcpynAtoW(lpBuffer,target,nSize);
865         HeapFree(GetProcessHeap(),0,target);
866         if (from) HeapFree(GetProcessHeap(),0,from);
867         return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? 
868                         lstrlen32W(*(LPWSTR*)lpBuffer):
869                         lstrlen32W(lpBuffer);
870 }
871 #undef ADD_TO_T