Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbejy@wpi.edu>
[wine/multimedia.git] / misc / lstr.c
blob7f2e674a7224393b2a2dcdd303a49aead2901fbe
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 "winuser.h"
27 #include "wine/winbase16.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 "debug.h"
36 DEFAULT_DEBUG_CHANNEL(resource)
38 extern const WORD OLE2NLS_CT_CType3_LUT[]; /* FIXME: does not belong here */
41 /* Funny to divide them between user and kernel. */
43 /* be careful: always use functions from wctype.h if character > 255 */
46 * Unicode case conversion routines ... these should be used where
47 * toupper/tolower are used for ASCII.
49 #ifndef HAVE_WCTYPE_H
50 /* FIXME: should probably get rid of wctype.h altogether */
51 #include "casemap.h"
53 WCHAR towupper(WCHAR code)
55 const WCHAR * ptr = uprtable[HIBYTE(code)];
56 return ptr ? ptr[LOBYTE(code)] : code;
59 WCHAR towlower(WCHAR code)
61 const WCHAR * ptr = lwrtable[HIBYTE(code)];
62 return ptr ? ptr[LOBYTE(code)] : code;
64 #endif /* HAVE_WCTYPE_H */
66 /***********************************************************************
67 * IsCharAlpha (USER.433)
69 BOOL16 WINAPI IsCharAlpha16(CHAR ch)
71 return isalpha(ch); /* This is probably not right for NLS */
74 /***********************************************************************
75 * IsCharAlphanumeric (USER.434)
77 BOOL16 WINAPI IsCharAlphaNumeric16(CHAR ch)
79 return isalnum(ch);
82 /***********************************************************************
83 * IsCharUpper (USER.435)
85 BOOL16 WINAPI IsCharUpper16(CHAR ch)
87 return isupper(ch);
90 /***********************************************************************
91 * IsCharLower (USER.436)
93 BOOL16 WINAPI IsCharLower16(CHAR ch)
95 return islower(ch);
98 /***********************************************************************
99 * AnsiUpper16 (USER.431)
101 SEGPTR WINAPI AnsiUpper16( SEGPTR strOrChar )
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 */
106 /* uppercase only one char if strOrChar < 0x10000 */
107 if (HIWORD(strOrChar))
109 char *s;
110 for (s = PTR_SEG_TO_LIN(strOrChar); *s; s++) *s = toupper(*s);
111 return strOrChar;
113 else return toupper((char)strOrChar);
117 /***********************************************************************
118 * AnsiUpperBuff16 (USER.437)
120 UINT16 WINAPI AnsiUpperBuff16( LPSTR str, UINT16 len )
122 UINT count = len ? len : 65536;
123 for (; count; count--, str++) *str = toupper(*str);
124 return len;
127 /***********************************************************************
128 * AnsiLower16 (USER.432)
130 SEGPTR WINAPI AnsiLower16( SEGPTR strOrChar )
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 */
135 /* lowercase only one char if strOrChar < 0x10000 */
136 if (HIWORD(strOrChar))
138 char *s;
139 for (s = PTR_SEG_TO_LIN( strOrChar ); *s; s++) *s = tolower( *s );
140 return strOrChar;
142 else return tolower((char)strOrChar);
146 /***********************************************************************
147 * AnsiLowerBuff16 (USER.438)
149 UINT16 WINAPI AnsiLowerBuff16( LPSTR str, UINT16 len )
151 UINT count = len ? len : 65536;
152 for (; count; count--, str++) *str = tolower(*str);
153 return len;
157 /***********************************************************************
158 * AnsiNext16 (USER.472)
160 SEGPTR WINAPI AnsiNext16(SEGPTR current)
162 return (*(char *)PTR_SEG_TO_LIN(current)) ? current + 1 : current;
166 /***********************************************************************
167 * AnsiPrev16 (USER.473)
169 SEGPTR WINAPI AnsiPrev16( SEGPTR start, SEGPTR current )
171 return (current == start) ? start : current - 1;
175 /***********************************************************************
176 * OutputDebugString16 (KERNEL.115)
178 void WINAPI OutputDebugString16( LPCSTR str )
180 char module[10];
181 if (!GetModuleName16( GetCurrentTask(), module, sizeof(module) ))
182 strcpy( module, "???" );
184 DUMP( "%s says %s\n", module, debugstr_a(str) );
188 /***********************************************************************
189 * OutputDebugString32A (KERNEL32
191 void WINAPI OutputDebugStringA( LPCSTR str )
193 OutputDebugString16( str );
198 /***********************************************************************
199 * OutputDebugString32W (KERNEL32
201 void WINAPI OutputDebugStringW( LPCWSTR str )
203 LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
204 OutputDebugStringA( p );
205 HeapFree( GetProcessHeap(), 0, p );
210 /***********************************************************************
211 * CharNext32A (USER32.29)
213 LPSTR WINAPI CharNextA( LPCSTR ptr )
215 if (!*ptr) return (LPSTR)ptr;
216 if (IsDBCSLeadByte( *ptr )) return (LPSTR)(ptr + 2);
217 return (LPSTR)(ptr + 1);
221 /***********************************************************************
222 * CharNextEx32A (USER32.30)
224 LPSTR WINAPI CharNextExA( WORD codepage, LPCSTR ptr, DWORD flags )
226 if (!*ptr) return (LPSTR)ptr;
227 if (IsDBCSLeadByteEx( codepage, *ptr )) return (LPSTR)(ptr + 2);
228 return (LPSTR)(ptr + 1);
232 /***********************************************************************
233 * CharNextExW (USER32.31)
235 LPWSTR WINAPI CharNextExW(WORD codepage,LPCWSTR x,DWORD flags)
237 /* FIXME: add DBCS / codepage stuff */
238 if (*x) return (LPWSTR)(x+1);
239 else return (LPWSTR)x;
242 /***********************************************************************
243 * CharNextW (USER32.32)
245 LPWSTR WINAPI CharNextW(LPCWSTR x)
247 if (*x) return (LPWSTR)(x+1);
248 else return (LPWSTR)x;
251 /***********************************************************************
252 * CharPrev32A (USER32.33)
254 LPSTR WINAPI CharPrevA( LPCSTR start, LPCSTR ptr )
256 while (*start && (start < ptr))
258 LPCSTR next = CharNextA( start );
259 if (next >= ptr) break;
260 start = next;
262 return (LPSTR)start;
266 /***********************************************************************
267 * CharPrevEx32A (USER32.34)
269 LPSTR WINAPI CharPrevExA( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
271 while (*start && (start < ptr))
273 LPCSTR next = CharNextExA( codepage, start, flags );
274 if (next > ptr) break;
275 start = next;
277 return (LPSTR)start;
281 /***********************************************************************
282 * CharPrevExW (USER32.35)
284 LPWSTR WINAPI CharPrevExW(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
286 /* FIXME: add DBCS / codepage stuff */
287 if (x>start) return (LPWSTR)(x-1);
288 else return (LPWSTR)x;
291 /***********************************************************************
292 * CharPrevW (USER32.36)
294 LPWSTR WINAPI CharPrevW(LPCWSTR start,LPCWSTR x)
296 if (x>start) return (LPWSTR)(x-1);
297 else return (LPWSTR)x;
300 /***********************************************************************
301 * CharLowerA (USER32.25)
302 * FIXME: handle current locale
304 LPSTR WINAPI CharLowerA(LPSTR x)
306 LPSTR s;
308 if (HIWORD(x))
310 s=x;
311 while (*s)
313 *s=tolower(*s);
314 s++;
316 return x;
318 else return (LPSTR)tolower((char)(int)x);
321 /***********************************************************************
322 * CharLowerBuffA (USER32.26)
323 * FIXME: handle current locale
325 DWORD WINAPI CharLowerBuffA(LPSTR x,DWORD buflen)
327 DWORD done=0;
329 if (!x) return 0; /* YES */
330 while (*x && (buflen--))
332 *x=tolower(*x);
333 x++;
334 done++;
336 return done;
339 /***********************************************************************
340 * CharLowerBuffW (USER32.27)
341 * FIXME: handle current locale
343 DWORD WINAPI CharLowerBuffW(LPWSTR x,DWORD buflen)
345 DWORD done=0;
347 if (!x) return 0; /* YES */
348 while (*x && (buflen--))
350 *x=towlower(*x);
351 x++;
352 done++;
354 return done;
357 /***********************************************************************
358 * CharLowerW (USER32.28)
359 * FIXME: handle current locale
361 LPWSTR WINAPI CharLowerW(LPWSTR x)
363 if (HIWORD(x))
365 LPWSTR s = x;
366 while (*s)
368 *s=towlower(*s);
369 s++;
371 return x;
373 else return (LPWSTR)((UINT)towlower(LOWORD(x)));
376 /***********************************************************************
377 * CharUpper32A (USER32.41)
378 * FIXME: handle current locale
380 LPSTR WINAPI CharUpperA(LPSTR x)
382 if (HIWORD(x))
384 LPSTR s = x;
385 while (*s)
387 *s=toupper(*s);
388 s++;
390 return x;
392 return (LPSTR)toupper((char)(int)x);
395 /***********************************************************************
396 * CharUpperBuffA (USER32.42)
397 * FIXME: handle current locale
399 DWORD WINAPI CharUpperBuffA(LPSTR x,DWORD buflen)
401 DWORD done=0;
403 if (!x) return 0; /* YES */
404 while (*x && (buflen--))
406 *x=toupper(*x);
407 x++;
408 done++;
410 return done;
413 /***********************************************************************
414 * CharUpperBuffW (USER32.43)
415 * FIXME: handle current locale
417 DWORD WINAPI CharUpperBuffW(LPWSTR x,DWORD buflen)
419 DWORD done=0;
421 if (!x) return 0; /* YES */
422 while (*x && (buflen--))
424 *x=towupper(*x);
425 x++;
426 done++;
428 return done;
431 /***********************************************************************
432 * CharUpperW (USER32.44)
433 * FIXME: handle current locale
435 LPWSTR WINAPI CharUpperW(LPWSTR x)
437 if (HIWORD(x))
439 LPWSTR s = x;
440 while (*s)
442 *s=towupper(*s);
443 s++;
445 return x;
447 else return (LPWSTR)((UINT)towupper(LOWORD(x)));
450 /***********************************************************************
451 * IsCharAlphaA (USER32.331)
452 * FIXME: handle current locale
454 BOOL WINAPI IsCharAlphaA(CHAR x)
456 return (OLE2NLS_CT_CType3_LUT[(unsigned char)x] & C3_ALPHA);
459 /***********************************************************************
460 * IsCharAlphaNumericA (USER32.332)
461 * FIXME: handle current locale
463 BOOL WINAPI IsCharAlphaNumericA(CHAR x)
465 return IsCharAlphaA(x) || isdigit(x) ;
468 /***********************************************************************
469 * IsCharAlphaNumericW (USER32.333)
470 * FIXME: handle current locale
472 BOOL WINAPI IsCharAlphaNumericW(WCHAR x)
474 return iswalnum(x);
477 /***********************************************************************
478 * IsCharAlphaW (USER32.334)
479 * FIXME: handle current locale
481 BOOL WINAPI IsCharAlphaW(WCHAR x)
483 return iswalpha(x);
486 /***********************************************************************
487 * IsCharLower32A (USER32.335)
488 * FIXME: handle current locale
490 BOOL WINAPI IsCharLowerA(CHAR x)
492 return islower(x);
495 /***********************************************************************
496 * IsCharLower32W (USER32.336)
497 * FIXME: handle current locale
499 BOOL WINAPI IsCharLowerW(WCHAR x)
501 return iswlower(x);
504 /***********************************************************************
505 * IsCharUpper32A (USER32.337)
506 * FIXME: handle current locale
508 BOOL WINAPI IsCharUpperA(CHAR x)
510 return isupper(x);
513 /***********************************************************************
514 * IsCharUpper32W (USER32.338)
515 * FIXME: handle current locale
517 BOOL WINAPI IsCharUpperW(WCHAR x)
519 return iswupper(x);
522 /***********************************************************************
523 * FormatMessage16 (USER.606)
525 DWORD WINAPI FormatMessage16(
526 DWORD dwFlags,
527 LPCVOID lpSource,
528 WORD dwMessageId,
529 WORD dwLanguageId,
530 LPSTR lpBuffer,
531 WORD nSize,
532 LPDWORD args /* va_list *args */
534 return FormatMessageA(dwFlags, lpSource, (DWORD)dwMessageId, (DWORD)dwLanguageId, lpBuffer, (DWORD)nSize, args);
537 /***********************************************************************
538 * FormatMessage32A (KERNEL32.138)
539 * FIXME: missing wrap,FROM_SYSTEM message-loading,
541 DWORD WINAPI FormatMessageA(
542 DWORD dwFlags,
543 LPCVOID lpSource,
544 DWORD dwMessageId,
545 DWORD dwLanguageId,
546 LPSTR lpBuffer,
547 DWORD nSize,
548 LPDWORD args /* va_list *args */
550 #ifdef __i386__
551 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
552 LPSTR target,t;
553 DWORD talloced;
554 LPSTR from,f;
555 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
556 DWORD nolinefeed = 0;
558 TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
559 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
560 if (width)
561 FIXME(resource,"line wrapping not supported.\n");
562 from = NULL;
563 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
564 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
565 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
566 from = HeapAlloc( GetProcessHeap(),0,200 );
567 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
569 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
570 INT bufsize;
572 dwMessageId &= 0xFFFF;
573 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
574 if (bufsize) {
575 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
576 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
579 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
580 t = target;
581 talloced= 100;
583 #define ADD_TO_T(c) \
584 *t++=c;\
585 if (t-target == talloced) {\
586 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
587 t = target+talloced;\
588 talloced*=2;\
591 if (from) {
592 f=from;
593 while (*f && !nolinefeed) {
594 if (*f=='%') {
595 int insertnr;
596 char *fmtstr,*sprintfbuf,*x,*lastf;
597 DWORD *argliststart;
599 fmtstr = NULL;
600 lastf = f;
601 f++;
602 if (!*f) {
603 ADD_TO_T('%');
604 continue;
606 switch (*f) {
607 case '1':case '2':case '3':case '4':case '5':
608 case '6':case '7':case '8':case '9':
609 insertnr=*f-'0';
610 switch (f[1]) {
611 case '0':case '1':case '2':case '3':
612 case '4':case '5':case '6':case '7':
613 case '8':case '9':
614 f++;
615 insertnr=insertnr*10+*f-'0';
616 f++;
617 break;
618 default:
619 f++;
620 break;
622 if (*f=='!') {
623 f++;
624 if (NULL!=(x=strchr(f,'!'))) {
625 *x='\0';
626 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
627 sprintf(fmtstr,"%%%s",f);
628 f=x+1;
629 } else {
630 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
631 sprintf(fmtstr,"%%%s",f);
632 f+=strlen(f); /*at \0*/
634 } else
635 if(!args)
636 break;
637 else
638 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
639 if (args) {
640 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
641 argliststart=args+insertnr-1;
642 else
643 argliststart=(*(DWORD**)args)+insertnr-1;
645 if (fmtstr[strlen(fmtstr)-1]=='s')
646 sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
647 else
648 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
650 /* CMF - This makes a BIG assumption about va_list */
651 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
652 x=sprintfbuf;
653 while (*x) {
654 ADD_TO_T(*x++);
656 HeapFree(GetProcessHeap(),0,sprintfbuf);
657 } else {
658 /* NULL args - copy formatstr
659 * (probably wrong)
661 while ((lastf<f)&&(*lastf)) {
662 ADD_TO_T(*lastf++);
665 HeapFree(GetProcessHeap(),0,fmtstr);
666 break;
667 case 'n':
668 /* FIXME: perhaps add \r too? */
669 ADD_TO_T('\n');
670 f++;
671 break;
672 case '0':
673 nolinefeed=1;
674 f++;
675 break;
676 default:ADD_TO_T(*f++)
677 break;
680 } else {
681 ADD_TO_T(*f++)
684 *t='\0';
686 if (!nolinefeed) {
687 /* add linefeed */
688 if(t==target || t[-1]!='\n')
689 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
691 talloced = strlen(target)+1;
692 if (nSize && talloced<nSize) {
693 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
695 TRACE(resource,"-- %s\n",debugstr_a(target));
696 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
697 /* nSize is the MINIMUM size */
698 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced);
699 memcpy(*(LPSTR*)lpBuffer,target,talloced);
700 } else
701 strncpy(lpBuffer,target,nSize);
702 HeapFree(GetProcessHeap(),0,target);
703 if (from) HeapFree(GetProcessHeap(),0,from);
704 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
705 strlen(*(LPSTR*)lpBuffer):
706 strlen(lpBuffer);
707 #else
708 return 0;
709 #endif /* __i386__ */
711 #undef ADD_TO_T
714 /***********************************************************************
715 * FormatMessage32W (KERNEL32.138)
717 DWORD WINAPI FormatMessageW(
718 DWORD dwFlags,
719 LPCVOID lpSource,
720 DWORD dwMessageId,
721 DWORD dwLanguageId,
722 LPWSTR lpBuffer,
723 DWORD nSize,
724 LPDWORD args /* va_list *args */
726 #ifdef __i386__
727 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
728 LPSTR target,t;
729 DWORD talloced;
730 LPSTR from,f;
731 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
732 DWORD nolinefeed = 0;
734 TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
735 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
736 if (width)
737 FIXME(resource,"line wrapping not supported.\n");
738 from = NULL;
739 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
740 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
741 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
742 /* gather information from system message tables ... */
743 from = HeapAlloc( GetProcessHeap(),0,200 );
744 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
746 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
747 INT bufsize;
749 dwMessageId &= 0xFFFF;
750 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
751 if (bufsize)
753 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
754 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
757 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
758 t = target;
759 talloced= 100;
761 #define ADD_TO_T(c) \
762 *t++=c;\
763 if (t-target == talloced) {\
764 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
765 t = target+talloced;\
766 talloced*=2;\
769 if (from) {
770 f=from;
771 while (*f && !nolinefeed) {
772 if (*f=='%') {
773 int insertnr;
774 char *fmtstr,*sprintfbuf,*x;
775 DWORD *argliststart;
777 fmtstr = NULL;
778 f++;
779 if (!*f) {
780 ADD_TO_T('%');
781 continue;
783 switch (*f) {
784 case '1':case '2':case '3':case '4':case '5':
785 case '6':case '7':case '8':case '9':
786 insertnr=*f-'0';
787 switch (f[1]) {
788 case '0':case '1':case '2':case '3':
789 case '4':case '5':case '6':case '7':
790 case '8':case '9':
791 f++;
792 insertnr=insertnr*10+*f-'0';
793 f++;
794 break;
795 default:
796 f++;
797 break;
799 if (*f=='!') {
800 f++;
801 if (NULL!=(x=strchr(f,'!')))
803 *x='\0';
804 fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
805 sprintf(fmtstr,"%%%s",f);
806 f=x+1;
807 } else {
808 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
809 sprintf(fmtstr,"%%%s",f);
810 f+=strlen(f); /*at \0*/
812 } else
813 if(!args)
814 break;
815 else
816 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
817 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
818 argliststart=args+insertnr-1;
819 else
820 argliststart=(*(DWORD**)args)+insertnr-1;
822 if (fmtstr[strlen(fmtstr)-1]=='s') {
823 DWORD xarr[3];
825 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
826 /* possible invalid pointers */
827 xarr[1]=*(argliststart+1);
828 xarr[2]=*(argliststart+2);
829 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlenW((LPWSTR)argliststart[0])*2+1);
831 /* CMF - This makes a BIG assumption about va_list */
832 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
833 } else {
834 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
836 /* CMF - This makes a BIG assumption about va_list */
837 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
839 x=sprintfbuf;
840 while (*x) {
841 ADD_TO_T(*x++);
843 HeapFree(GetProcessHeap(),0,sprintfbuf);
844 HeapFree(GetProcessHeap(),0,fmtstr);
845 break;
846 case 'n':
847 /* FIXME: perhaps add \r too? */
848 ADD_TO_T('\n');
849 f++;
850 break;
851 case '0':
852 nolinefeed=1;
853 f++;
854 break;
855 default:ADD_TO_T(*f++)
856 break;
859 } else {
860 ADD_TO_T(*f++)
863 *t='\0';
865 if (!nolinefeed) {
866 /* add linefeed */
867 if(t==target || t[-1]!='\n')
868 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
870 talloced = strlen(target)+1;
871 if (nSize && talloced<nSize)
872 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
873 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
874 /* nSize is the MINIMUM size */
875 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced*2+2);
876 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
877 } else
878 lstrcpynAtoW(lpBuffer,target,nSize);
879 HeapFree(GetProcessHeap(),0,target);
880 if (from) HeapFree(GetProcessHeap(),0,from);
881 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
882 lstrlenW(*(LPWSTR*)lpBuffer):
883 lstrlenW(lpBuffer);
884 #else
885 return 0;
886 #endif /* __i386__ */
888 #undef ADD_TO_T