Bug fix in GetLen.
[wine/hacks.git] / misc / lstr.c
blob048bb6bed376e7ebb126c70256e8f72c1e3d6c23
1 /*
2 * String functions
4 * Copyright 1993 Yngvi Sigurjonsson (yngvi@hafro.is)
5 * Copyright 1996 Marcus Meissner
6 */
8 #include "config.h"
10 #include <stdarg.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
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 */
25 #include "winbase.h"
26 #include "winnls.h"
27 #include "wine/winbase16.h"
28 #include "winuser.h"
29 #include "wine/winuser16.h"
30 #include "task.h"
31 #include "heap.h"
32 #include "ldt.h"
33 #include "stackframe.h"
34 #include "module.h"
35 #include "debug.h"
37 extern const WORD OLE2NLS_CT_CType3_LUT[]; /* FIXME: does not belong here */
40 /* Funny to divide them between user and kernel. */
42 /* be careful: always use functions from wctype.h if character > 255 */
45 * Unicode case conversion routines ... these should be used where
46 * toupper/tolower are used for ASCII.
48 #ifndef HAVE_WCTYPE_H
49 /* FIXME: should probably get rid of wctype.h altogether */
50 #include "casemap.h"
52 WCHAR towupper(WCHAR code)
54 const WCHAR * ptr = uprtable[HIBYTE(code)];
55 return ptr ? ptr[LOBYTE(code)] : code;
58 WCHAR towlower(WCHAR code)
60 const WCHAR * ptr = lwrtable[HIBYTE(code)];
61 return ptr ? ptr[LOBYTE(code)] : code;
63 #endif /* HAVE_WCTYPE_H */
65 /***********************************************************************
66 * IsCharAlpha (USER.433)
68 BOOL16 WINAPI IsCharAlpha16(CHAR ch)
70 return isalpha(ch); /* This is probably not right for NLS */
73 /***********************************************************************
74 * IsCharAlphanumeric (USER.434)
76 BOOL16 WINAPI IsCharAlphaNumeric16(CHAR ch)
78 return isalnum(ch);
81 /***********************************************************************
82 * IsCharUpper (USER.435)
84 BOOL16 WINAPI IsCharUpper16(CHAR ch)
86 return isupper(ch);
89 /***********************************************************************
90 * IsCharLower (USER.436)
92 BOOL16 WINAPI IsCharLower16(CHAR ch)
94 return islower(ch);
97 /***********************************************************************
98 * AnsiUpper16 (USER.431)
100 SEGPTR WINAPI AnsiUpper16( SEGPTR strOrChar )
102 /* I am not sure if the locale stuff works with toupper, but then again
103 I am not sure if the Linux libc locale stuffs works at all */
105 /* uppercase only one char if strOrChar < 0x10000 */
106 if (HIWORD(strOrChar))
108 char *s;
109 for (s = PTR_SEG_TO_LIN(strOrChar); *s; s++) *s = toupper(*s);
110 return strOrChar;
112 else return toupper((char)strOrChar);
116 /***********************************************************************
117 * AnsiUpperBuff16 (USER.437)
119 UINT16 WINAPI AnsiUpperBuff16( LPSTR str, UINT16 len )
121 UINT count = len ? len : 65536;
122 for (; count; count--, str++) *str = toupper(*str);
123 return len;
126 /***********************************************************************
127 * AnsiLower16 (USER.432)
129 SEGPTR WINAPI AnsiLower16( SEGPTR strOrChar )
131 /* I am not sure if the locale stuff works with toupper, but then again
132 I am not sure if the Linux libc locale stuffs works at all */
134 /* lowercase only one char if strOrChar < 0x10000 */
135 if (HIWORD(strOrChar))
137 char *s;
138 for (s = PTR_SEG_TO_LIN( strOrChar ); *s; s++) *s = tolower( *s );
139 return strOrChar;
141 else return tolower((char)strOrChar);
145 /***********************************************************************
146 * AnsiLowerBuff16 (USER.438)
148 UINT16 WINAPI AnsiLowerBuff16( LPSTR str, UINT16 len )
150 UINT count = len ? len : 65536;
151 for (; count; count--, str++) *str = tolower(*str);
152 return len;
156 /***********************************************************************
157 * AnsiNext16 (USER.472)
159 SEGPTR WINAPI AnsiNext16(SEGPTR current)
161 return (*(char *)PTR_SEG_TO_LIN(current)) ? current + 1 : current;
165 /***********************************************************************
166 * AnsiPrev16 (USER.473)
168 SEGPTR WINAPI AnsiPrev16( SEGPTR start, SEGPTR current )
170 return (current == start) ? start : current - 1;
174 /***********************************************************************
175 * OutputDebugString16 (KERNEL.115)
177 void WINAPI OutputDebugString16( LPCSTR str )
179 char module[10];
180 if (!GetModuleName16( GetCurrentTask(), module, sizeof(module) ))
181 strcpy( module, "???" );
183 DUMP( "%s says %s\n", module, debugstr_a(str) );
187 /***********************************************************************
188 * OutputDebugString32A (KERNEL32
190 void WINAPI OutputDebugStringA( LPCSTR str )
192 OutputDebugString16( str );
197 /***********************************************************************
198 * OutputDebugString32W (KERNEL32
200 void WINAPI OutputDebugStringW( LPCWSTR str )
202 LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
203 OutputDebugStringA( p );
204 HeapFree( GetProcessHeap(), 0, p );
209 /***********************************************************************
210 * CharNext32A (USER32.29)
212 LPSTR WINAPI CharNextA( LPCSTR ptr )
214 if (!*ptr) return (LPSTR)ptr;
215 if (IsDBCSLeadByte( *ptr )) return (LPSTR)(ptr + 2);
216 return (LPSTR)(ptr + 1);
220 /***********************************************************************
221 * CharNextEx32A (USER32.30)
223 LPSTR WINAPI CharNextExA( WORD codepage, LPCSTR ptr, DWORD flags )
225 if (!*ptr) return (LPSTR)ptr;
226 if (IsDBCSLeadByteEx( codepage, *ptr )) return (LPSTR)(ptr + 2);
227 return (LPSTR)(ptr + 1);
231 /***********************************************************************
232 * CharNextExW (USER32.31)
234 LPWSTR WINAPI CharNextExW(WORD codepage,LPCWSTR x,DWORD flags)
236 /* FIXME: add DBCS / codepage stuff */
237 if (*x) return (LPWSTR)(x+1);
238 else return (LPWSTR)x;
241 /***********************************************************************
242 * CharNextW (USER32.32)
244 LPWSTR WINAPI CharNextW(LPCWSTR x)
246 if (*x) return (LPWSTR)(x+1);
247 else return (LPWSTR)x;
250 /***********************************************************************
251 * CharPrev32A (USER32.33)
253 LPSTR WINAPI CharPrevA( LPCSTR start, LPCSTR ptr )
255 while (*start && (start < ptr))
257 LPCSTR next = CharNextA( start );
258 if (next >= ptr) break;
259 start = next;
261 return (LPSTR)start;
265 /***********************************************************************
266 * CharPrevEx32A (USER32.34)
268 LPSTR WINAPI CharPrevExA( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
270 while (*start && (start < ptr))
272 LPCSTR next = CharNextExA( codepage, start, flags );
273 if (next > ptr) break;
274 start = next;
276 return (LPSTR)start;
280 /***********************************************************************
281 * CharPrevExW (USER32.35)
283 LPWSTR WINAPI CharPrevExW(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
285 /* FIXME: add DBCS / codepage stuff */
286 if (x>start) return (LPWSTR)(x-1);
287 else return (LPWSTR)x;
290 /***********************************************************************
291 * CharPrevW (USER32.36)
293 LPWSTR WINAPI CharPrevW(LPCWSTR start,LPCWSTR x)
295 if (x>start) return (LPWSTR)(x-1);
296 else return (LPWSTR)x;
299 /***********************************************************************
300 * CharLowerA (USER32.25)
301 * FIXME: handle current locale
303 LPSTR WINAPI CharLowerA(LPSTR x)
305 LPSTR s;
307 if (HIWORD(x))
309 s=x;
310 while (*s)
312 *s=tolower(*s);
313 s++;
315 return x;
317 else return (LPSTR)tolower((char)(int)x);
320 /***********************************************************************
321 * CharLowerBuffA (USER32.26)
322 * FIXME: handle current locale
324 DWORD WINAPI CharLowerBuffA(LPSTR x,DWORD buflen)
326 DWORD done=0;
328 if (!x) return 0; /* YES */
329 while (*x && (buflen--))
331 *x=tolower(*x);
332 x++;
333 done++;
335 return done;
338 /***********************************************************************
339 * CharLowerBuffW (USER32.27)
340 * FIXME: handle current locale
342 DWORD WINAPI CharLowerBuffW(LPWSTR x,DWORD buflen)
344 DWORD done=0;
346 if (!x) return 0; /* YES */
347 while (*x && (buflen--))
349 *x=towlower(*x);
350 x++;
351 done++;
353 return done;
356 /***********************************************************************
357 * CharLowerW (USER32.28)
358 * FIXME: handle current locale
360 LPWSTR WINAPI CharLowerW(LPWSTR x)
362 if (HIWORD(x))
364 LPWSTR s = x;
365 while (*s)
367 *s=towlower(*s);
368 s++;
370 return x;
372 else return (LPWSTR)((UINT)towlower(LOWORD(x)));
375 /***********************************************************************
376 * CharUpper32A (USER32.41)
377 * FIXME: handle current locale
379 LPSTR WINAPI CharUpperA(LPSTR x)
381 if (HIWORD(x))
383 LPSTR s = x;
384 while (*s)
386 *s=toupper(*s);
387 s++;
389 return x;
391 return (LPSTR)toupper((char)(int)x);
394 /***********************************************************************
395 * CharUpperBuffA (USER32.42)
396 * FIXME: handle current locale
398 DWORD WINAPI CharUpperBuffA(LPSTR x,DWORD buflen)
400 DWORD done=0;
402 if (!x) return 0; /* YES */
403 while (*x && (buflen--))
405 *x=toupper(*x);
406 x++;
407 done++;
409 return done;
412 /***********************************************************************
413 * CharUpperBuffW (USER32.43)
414 * FIXME: handle current locale
416 DWORD WINAPI CharUpperBuffW(LPWSTR x,DWORD buflen)
418 DWORD done=0;
420 if (!x) return 0; /* YES */
421 while (*x && (buflen--))
423 *x=towupper(*x);
424 x++;
425 done++;
427 return done;
430 /***********************************************************************
431 * CharUpperW (USER32.44)
432 * FIXME: handle current locale
434 LPWSTR WINAPI CharUpperW(LPWSTR x)
436 if (HIWORD(x))
438 LPWSTR s = x;
439 while (*s)
441 *s=towupper(*s);
442 s++;
444 return x;
446 else return (LPWSTR)((UINT)towupper(LOWORD(x)));
449 /***********************************************************************
450 * IsCharAlphaA (USER32.331)
451 * FIXME: handle current locale
453 BOOL WINAPI IsCharAlphaA(CHAR x)
455 return (OLE2NLS_CT_CType3_LUT[(unsigned char)x] & C3_ALPHA);
458 /***********************************************************************
459 * IsCharAlphaNumericA (USER32.332)
460 * FIXME: handle current locale
462 BOOL WINAPI IsCharAlphaNumericA(CHAR x)
464 return IsCharAlphaA(x) || isdigit(x) ;
467 /***********************************************************************
468 * IsCharAlphaNumericW (USER32.333)
469 * FIXME: handle current locale
471 BOOL WINAPI IsCharAlphaNumericW(WCHAR x)
473 return iswalnum(x);
476 /***********************************************************************
477 * IsCharAlphaW (USER32.334)
478 * FIXME: handle current locale
480 BOOL WINAPI IsCharAlphaW(WCHAR x)
482 return iswalpha(x);
485 /***********************************************************************
486 * IsCharLower32A (USER32.335)
487 * FIXME: handle current locale
489 BOOL WINAPI IsCharLowerA(CHAR x)
491 return islower(x);
494 /***********************************************************************
495 * IsCharLower32W (USER32.336)
496 * FIXME: handle current locale
498 BOOL WINAPI IsCharLowerW(WCHAR x)
500 return iswlower(x);
503 /***********************************************************************
504 * IsCharUpper32A (USER32.337)
505 * FIXME: handle current locale
507 BOOL WINAPI IsCharUpperA(CHAR x)
509 return isupper(x);
512 /***********************************************************************
513 * IsCharUpper32W (USER32.338)
514 * FIXME: handle current locale
516 BOOL WINAPI IsCharUpperW(WCHAR x)
518 return iswupper(x);
521 /***********************************************************************
522 * FormatMessage16 (USER.606)
524 DWORD WINAPI FormatMessage16(
525 DWORD dwFlags,
526 LPCVOID lpSource,
527 WORD dwMessageId,
528 WORD dwLanguageId,
529 LPSTR lpBuffer,
530 WORD nSize,
531 LPDWORD args /* va_list *args */
533 return FormatMessageA(dwFlags, lpSource, (DWORD)dwMessageId, (DWORD)dwLanguageId, lpBuffer, (DWORD)nSize, args);
536 /***********************************************************************
537 * FormatMessage32A (KERNEL32.138)
538 * FIXME: missing wrap,FROM_SYSTEM message-loading,
540 DWORD WINAPI FormatMessageA(
541 DWORD dwFlags,
542 LPCVOID lpSource,
543 DWORD dwMessageId,
544 DWORD dwLanguageId,
545 LPSTR lpBuffer,
546 DWORD nSize,
547 LPDWORD args /* va_list *args */
549 #ifdef __i386__
550 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
551 LPSTR target,t;
552 DWORD talloced;
553 LPSTR from,f;
554 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
555 DWORD nolinefeed = 0;
557 TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
558 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
559 if (width)
560 FIXME(resource,"line wrapping not supported.\n");
561 from = NULL;
562 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
563 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
564 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
565 from = HeapAlloc( GetProcessHeap(),0,200 );
566 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
568 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
569 INT bufsize;
571 dwMessageId &= 0xFFFF;
572 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
573 if (bufsize) {
574 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
575 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
578 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
579 t = target;
580 talloced= 100;
582 #define ADD_TO_T(c) \
583 *t++=c;\
584 if (t-target == talloced) {\
585 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
586 t = target+talloced;\
587 talloced*=2;\
590 if (from) {
591 f=from;
592 while (*f && !nolinefeed) {
593 if (*f=='%') {
594 int insertnr;
595 char *fmtstr,*sprintfbuf,*x,*lastf;
596 DWORD *argliststart;
598 fmtstr = NULL;
599 lastf = f;
600 f++;
601 if (!*f) {
602 ADD_TO_T('%');
603 continue;
605 switch (*f) {
606 case '1':case '2':case '3':case '4':case '5':
607 case '6':case '7':case '8':case '9':
608 insertnr=*f-'0';
609 switch (f[1]) {
610 case '0':case '1':case '2':case '3':
611 case '4':case '5':case '6':case '7':
612 case '8':case '9':
613 f++;
614 insertnr=insertnr*10+*f-'0';
615 f++;
616 break;
617 default:
618 f++;
619 break;
621 if (*f=='!') {
622 f++;
623 if (NULL!=(x=strchr(f,'!'))) {
624 *x='\0';
625 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
626 sprintf(fmtstr,"%%%s",f);
627 f=x+1;
628 } else {
629 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
630 sprintf(fmtstr,"%%%s",f);
631 f+=strlen(f); /*at \0*/
633 } else
634 if(!args)
635 break;
636 else
637 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
638 if (args) {
639 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
640 argliststart=args+insertnr-1;
641 else
642 argliststart=(*(DWORD**)args)+insertnr-1;
644 if (fmtstr[strlen(fmtstr)-1]=='s')
645 sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
646 else
647 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
649 /* CMF - This makes a BIG assumption about va_list */
650 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
651 x=sprintfbuf;
652 while (*x) {
653 ADD_TO_T(*x++);
655 HeapFree(GetProcessHeap(),0,sprintfbuf);
656 } else {
657 /* NULL args - copy formatstr
658 * (probably wrong)
660 while ((lastf<f)&&(*lastf)) {
661 ADD_TO_T(*lastf++);
664 HeapFree(GetProcessHeap(),0,fmtstr);
665 break;
666 case 'n':
667 /* FIXME: perhaps add \r too? */
668 ADD_TO_T('\n');
669 f++;
670 break;
671 case '0':
672 nolinefeed=1;
673 f++;
674 break;
675 default:ADD_TO_T(*f++)
676 break;
679 } else {
680 ADD_TO_T(*f++)
683 *t='\0';
685 if (!nolinefeed) {
686 /* add linefeed */
687 if(t==target || t[-1]!='\n')
688 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
690 talloced = strlen(target)+1;
691 if (nSize && talloced<nSize) {
692 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
694 TRACE(resource,"-- %s\n",debugstr_a(target));
695 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
696 /* nSize is the MINIMUM size */
697 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced);
698 memcpy(*(LPSTR*)lpBuffer,target,talloced);
699 } else
700 strncpy(lpBuffer,target,nSize);
701 HeapFree(GetProcessHeap(),0,target);
702 if (from) HeapFree(GetProcessHeap(),0,from);
703 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
704 strlen(*(LPSTR*)lpBuffer):
705 strlen(lpBuffer);
706 #else
707 return 0;
708 #endif /* __i386__ */
710 #undef ADD_TO_T
713 /***********************************************************************
714 * FormatMessage32W (KERNEL32.138)
716 DWORD WINAPI FormatMessageW(
717 DWORD dwFlags,
718 LPCVOID lpSource,
719 DWORD dwMessageId,
720 DWORD dwLanguageId,
721 LPWSTR lpBuffer,
722 DWORD nSize,
723 LPDWORD args /* va_list *args */
725 #ifdef __i386__
726 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
727 LPSTR target,t;
728 DWORD talloced;
729 LPSTR from,f;
730 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
731 DWORD nolinefeed = 0;
733 TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
734 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
735 if (width)
736 FIXME(resource,"line wrapping not supported.\n");
737 from = NULL;
738 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
739 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
740 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
741 /* gather information from system message tables ... */
742 from = HeapAlloc( GetProcessHeap(),0,200 );
743 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
745 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
746 INT bufsize;
748 dwMessageId &= 0xFFFF;
749 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
750 if (bufsize)
752 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
753 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
756 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
757 t = target;
758 talloced= 100;
760 #define ADD_TO_T(c) \
761 *t++=c;\
762 if (t-target == talloced) {\
763 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
764 t = target+talloced;\
765 talloced*=2;\
768 if (from) {
769 f=from;
770 while (*f && !nolinefeed) {
771 if (*f=='%') {
772 int insertnr;
773 char *fmtstr,*sprintfbuf,*x;
774 DWORD *argliststart;
776 fmtstr = NULL;
777 f++;
778 if (!*f) {
779 ADD_TO_T('%');
780 continue;
782 switch (*f) {
783 case '1':case '2':case '3':case '4':case '5':
784 case '6':case '7':case '8':case '9':
785 insertnr=*f-'0';
786 switch (f[1]) {
787 case '0':case '1':case '2':case '3':
788 case '4':case '5':case '6':case '7':
789 case '8':case '9':
790 f++;
791 insertnr=insertnr*10+*f-'0';
792 f++;
793 break;
794 default:
795 f++;
796 break;
798 if (*f=='!') {
799 f++;
800 if (NULL!=(x=strchr(f,'!')))
802 *x='\0';
803 fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
804 sprintf(fmtstr,"%%%s",f);
805 f=x+1;
806 } else {
807 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
808 sprintf(fmtstr,"%%%s",f);
809 f+=strlen(f); /*at \0*/
811 } else
812 if(!args)
813 break;
814 else
815 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
816 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
817 argliststart=args+insertnr-1;
818 else
819 argliststart=(*(DWORD**)args)+insertnr-1;
821 if (fmtstr[strlen(fmtstr)-1]=='s') {
822 DWORD xarr[3];
824 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
825 /* possible invalid pointers */
826 xarr[1]=*(argliststart+1);
827 xarr[2]=*(argliststart+2);
828 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlenW((LPWSTR)argliststart[0])*2+1);
830 /* CMF - This makes a BIG assumption about va_list */
831 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
832 } else {
833 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
835 /* CMF - This makes a BIG assumption about va_list */
836 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
838 x=sprintfbuf;
839 while (*x) {
840 ADD_TO_T(*x++);
842 HeapFree(GetProcessHeap(),0,sprintfbuf);
843 HeapFree(GetProcessHeap(),0,fmtstr);
844 break;
845 case 'n':
846 /* FIXME: perhaps add \r too? */
847 ADD_TO_T('\n');
848 f++;
849 break;
850 case '0':
851 nolinefeed=1;
852 f++;
853 break;
854 default:ADD_TO_T(*f++)
855 break;
858 } else {
859 ADD_TO_T(*f++)
862 *t='\0';
864 if (!nolinefeed) {
865 /* add linefeed */
866 if(t==target || t[-1]!='\n')
867 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
869 talloced = strlen(target)+1;
870 if (nSize && talloced<nSize)
871 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
872 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
873 /* nSize is the MINIMUM size */
874 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced*2+2);
875 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
876 } else
877 lstrcpynAtoW(lpBuffer,target,nSize);
878 HeapFree(GetProcessHeap(),0,target);
879 if (from) HeapFree(GetProcessHeap(),0,from);
880 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
881 lstrlenW(*(LPWSTR*)lpBuffer):
882 lstrlenW(lpBuffer);
883 #else
884 return 0;
885 #endif /* __i386__ */
887 #undef ADD_TO_T