Changed DOS extended error handling to be based on SetLastError;
[wine/multimedia.git] / misc / lstr.c
blob2e1c9d88376b9f1cc96ffd4be03ec30e67f09a7a
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 "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"
34 extern const WORD OLE2NLS_CT_CType3_LUT[]; /* FIXME: does not belong here */
37 /* Funny to divide them between user and kernel. */
39 /* be careful: always use functions from wctype.h if character > 255 */
42 * Unicode case conversion routines ... these should be used where
43 * toupper/tolower are used for ASCII.
45 #ifndef HAVE_WCTYPE_H
46 /* FIXME: should probably get rid of wctype.h altogether */
47 #include "casemap.h"
49 WCHAR towupper(WCHAR code)
51 const WCHAR * ptr = uprtable[HIBYTE(code)];
52 return ptr ? ptr[LOBYTE(code)] : code;
55 WCHAR towlower(WCHAR code)
57 const WCHAR * ptr = lwrtable[HIBYTE(code)];
58 return ptr ? ptr[LOBYTE(code)] : code;
60 #endif /* HAVE_WCTYPE_H */
62 /***********************************************************************
63 * IsCharAlpha (USER.433)
65 BOOL16 WINAPI IsCharAlpha16(CHAR ch)
67 return isalpha(ch); /* This is probably not right for NLS */
70 /***********************************************************************
71 * IsCharAlphanumeric (USER.434)
73 BOOL16 WINAPI IsCharAlphaNumeric16(CHAR ch)
75 return isalnum(ch);
78 /***********************************************************************
79 * IsCharUpper (USER.435)
81 BOOL16 WINAPI IsCharUpper16(CHAR ch)
83 return isupper(ch);
86 /***********************************************************************
87 * IsCharLower (USER.436)
89 BOOL16 WINAPI IsCharLower16(CHAR ch)
91 return islower(ch);
94 /***********************************************************************
95 * AnsiUpper16 (USER.431)
97 SEGPTR WINAPI AnsiUpper16( SEGPTR strOrChar )
99 /* I am not sure if the locale stuff works with toupper, but then again
100 I am not sure if the Linux libc locale stuffs works at all */
102 /* uppercase only one char if strOrChar < 0x10000 */
103 if (HIWORD(strOrChar))
105 char *s;
106 for (s = PTR_SEG_TO_LIN(strOrChar); *s; s++) *s = toupper(*s);
107 return strOrChar;
109 else return toupper((char)strOrChar);
113 /***********************************************************************
114 * AnsiUpperBuff16 (USER.437)
116 UINT16 WINAPI AnsiUpperBuff16( LPSTR str, UINT16 len )
118 UINT32 count = len ? len : 65536;
119 for (; count; count--, str++) *str = toupper(*str);
120 return len;
123 /***********************************************************************
124 * AnsiLower16 (USER.432)
126 SEGPTR WINAPI AnsiLower16( SEGPTR strOrChar )
128 /* I am not sure if the locale stuff works with toupper, but then again
129 I am not sure if the Linux libc locale stuffs works at all */
131 /* lowercase only one char if strOrChar < 0x10000 */
132 if (HIWORD(strOrChar))
134 char *s;
135 for (s = PTR_SEG_TO_LIN( strOrChar ); *s; s++) *s = tolower( *s );
136 return strOrChar;
138 else return tolower((char)strOrChar);
142 /***********************************************************************
143 * AnsiLowerBuff16 (USER.438)
145 UINT16 WINAPI AnsiLowerBuff16( LPSTR str, UINT16 len )
147 UINT32 count = len ? len : 65536;
148 for (; count; count--, str++) *str = tolower(*str);
149 return len;
153 /***********************************************************************
154 * AnsiNext16 (USER.472)
156 SEGPTR WINAPI AnsiNext16(SEGPTR current)
158 return (*(char *)PTR_SEG_TO_LIN(current)) ? current + 1 : current;
162 /***********************************************************************
163 * AnsiPrev16 (USER.473)
165 SEGPTR WINAPI AnsiPrev16( SEGPTR start, SEGPTR current )
167 return (current == start) ? start : current - 1;
171 /***********************************************************************
172 * OutputDebugString16 (KERNEL.115)
174 void WINAPI OutputDebugString16( LPCSTR str )
176 char module[10];
177 if (!GetModuleName( GetCurrentTask(), module, sizeof(module) ))
178 strcpy( module, "???" );
180 DUMP( "%s says %s\n", module, debugstr_a(str) );
184 /***********************************************************************
185 * OutputDebugString32A (KERNEL32
187 void WINAPI OutputDebugString32A( LPCSTR str )
189 OutputDebugString16( str );
194 /***********************************************************************
195 * OutputDebugString32W (KERNEL32
197 void WINAPI OutputDebugString32W( LPCWSTR str )
199 LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
200 OutputDebugString32A( p );
201 HeapFree( GetProcessHeap(), 0, p );
206 /***********************************************************************
207 * CharNext32A (USER32.29)
209 LPSTR WINAPI CharNext32A( LPCSTR ptr )
211 if (!*ptr) return (LPSTR)ptr;
212 if (IsDBCSLeadByte32( *ptr )) return (LPSTR)(ptr + 2);
213 return (LPSTR)(ptr + 1);
217 /***********************************************************************
218 * CharNextEx32A (USER32.30)
220 LPSTR WINAPI CharNextEx32A( WORD codepage, LPCSTR ptr, DWORD flags )
222 if (!*ptr) return (LPSTR)ptr;
223 if (IsDBCSLeadByteEx( codepage, *ptr )) return (LPSTR)(ptr + 2);
224 return (LPSTR)(ptr + 1);
228 /***********************************************************************
229 * CharNextExW (USER32.31)
231 LPWSTR WINAPI CharNextEx32W(WORD codepage,LPCWSTR x,DWORD flags)
233 /* FIXME: add DBCS / codepage stuff */
234 if (*x) return (LPWSTR)(x+1);
235 else return (LPWSTR)x;
238 /***********************************************************************
239 * CharNextW (USER32.32)
241 LPWSTR WINAPI CharNext32W(LPCWSTR x)
243 if (*x) return (LPWSTR)(x+1);
244 else return (LPWSTR)x;
247 /***********************************************************************
248 * CharPrev32A (USER32.33)
250 LPSTR WINAPI CharPrev32A( LPCSTR start, LPCSTR ptr )
252 while (*start && (start < ptr))
254 LPCSTR next = CharNext32A( start );
255 if (next >= ptr) break;
256 start = next;
258 return (LPSTR)start;
262 /***********************************************************************
263 * CharPrevEx32A (USER32.34)
265 LPSTR WINAPI CharPrevEx32A( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
267 while (*start && (start < ptr))
269 LPCSTR next = CharNextEx32A( codepage, start, flags );
270 if (next > ptr) break;
271 start = next;
273 return (LPSTR)start;
277 /***********************************************************************
278 * CharPrevExW (USER32.35)
280 LPWSTR WINAPI CharPrevEx32W(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
282 /* FIXME: add DBCS / codepage stuff */
283 if (x>start) return (LPWSTR)(x-1);
284 else return (LPWSTR)x;
287 /***********************************************************************
288 * CharPrevW (USER32.36)
290 LPWSTR WINAPI CharPrev32W(LPCWSTR start,LPCWSTR x)
292 if (x>start) return (LPWSTR)(x-1);
293 else return (LPWSTR)x;
296 /***********************************************************************
297 * CharLowerA (USER32.25)
298 * FIXME: handle current locale
300 LPSTR WINAPI CharLower32A(LPSTR x)
302 LPSTR s;
304 if (HIWORD(x))
306 s=x;
307 while (*s)
309 *s=tolower(*s);
310 s++;
312 return x;
314 else return (LPSTR)tolower((char)(int)x);
317 /***********************************************************************
318 * CharLowerBuffA (USER32.26)
319 * FIXME: handle current locale
321 DWORD WINAPI CharLowerBuff32A(LPSTR x,DWORD buflen)
323 DWORD done=0;
325 if (!x) return 0; /* YES */
326 while (*x && (buflen--))
328 *x=tolower(*x);
329 x++;
330 done++;
332 return done;
335 /***********************************************************************
336 * CharLowerBuffW (USER32.27)
337 * FIXME: handle current locale
339 DWORD WINAPI CharLowerBuff32W(LPWSTR x,DWORD buflen)
341 DWORD done=0;
343 if (!x) return 0; /* YES */
344 while (*x && (buflen--))
346 *x=towlower(*x);
347 x++;
348 done++;
350 return done;
353 /***********************************************************************
354 * CharLowerW (USER32.28)
355 * FIXME: handle current locale
357 LPWSTR WINAPI CharLower32W(LPWSTR x)
359 if (HIWORD(x))
361 LPWSTR s = x;
362 while (*s)
364 *s=towlower(*s);
365 s++;
367 return x;
369 else return (LPWSTR)((UINT32)towlower(LOWORD(x)));
372 /***********************************************************************
373 * CharUpper32A (USER32.41)
374 * FIXME: handle current locale
376 LPSTR WINAPI CharUpper32A(LPSTR x)
378 if (HIWORD(x))
380 LPSTR s = x;
381 while (*s)
383 *s=toupper(*s);
384 s++;
386 return x;
388 return (LPSTR)toupper((char)(int)x);
391 /***********************************************************************
392 * CharUpperBuffA (USER32.42)
393 * FIXME: handle current locale
395 DWORD WINAPI CharUpperBuff32A(LPSTR x,DWORD buflen)
397 DWORD done=0;
399 if (!x) return 0; /* YES */
400 while (*x && (buflen--))
402 *x=toupper(*x);
403 x++;
404 done++;
406 return done;
409 /***********************************************************************
410 * CharUpperBuffW (USER32.43)
411 * FIXME: handle current locale
413 DWORD WINAPI CharUpperBuff32W(LPWSTR x,DWORD buflen)
415 DWORD done=0;
417 if (!x) return 0; /* YES */
418 while (*x && (buflen--))
420 *x=towupper(*x);
421 x++;
422 done++;
424 return done;
427 /***********************************************************************
428 * CharUpperW (USER32.44)
429 * FIXME: handle current locale
431 LPWSTR WINAPI CharUpper32W(LPWSTR x)
433 if (HIWORD(x))
435 LPWSTR s = x;
436 while (*s)
438 *s=towupper(*s);
439 s++;
441 return x;
443 else return (LPWSTR)((UINT32)towupper(LOWORD(x)));
446 /***********************************************************************
447 * IsCharAlphaA (USER32.331)
448 * FIXME: handle current locale
450 BOOL32 WINAPI IsCharAlpha32A(CHAR x)
452 return (OLE2NLS_CT_CType3_LUT[(unsigned char)x] & C3_ALPHA);
455 /***********************************************************************
456 * IsCharAlphaNumericA (USER32.332)
457 * FIXME: handle current locale
459 BOOL32 WINAPI IsCharAlphaNumeric32A(CHAR x)
461 return IsCharAlpha32A(x) || isdigit(x) ;
464 /***********************************************************************
465 * IsCharAlphaNumericW (USER32.333)
466 * FIXME: handle current locale
468 BOOL32 WINAPI IsCharAlphaNumeric32W(WCHAR x)
470 return iswalnum(x);
473 /***********************************************************************
474 * IsCharAlphaW (USER32.334)
475 * FIXME: handle current locale
477 BOOL32 WINAPI IsCharAlpha32W(WCHAR x)
479 return iswalpha(x);
482 /***********************************************************************
483 * IsCharLower32A (USER32.335)
484 * FIXME: handle current locale
486 BOOL32 WINAPI IsCharLower32A(CHAR x)
488 return islower(x);
491 /***********************************************************************
492 * IsCharLower32W (USER32.336)
493 * FIXME: handle current locale
495 BOOL32 WINAPI IsCharLower32W(WCHAR x)
497 return iswlower(x);
500 /***********************************************************************
501 * IsCharUpper32A (USER32.337)
502 * FIXME: handle current locale
504 BOOL32 WINAPI IsCharUpper32A(CHAR x)
506 return isupper(x);
509 /***********************************************************************
510 * IsCharUpper32W (USER32.338)
511 * FIXME: handle current locale
513 BOOL32 WINAPI IsCharUpper32W(WCHAR x)
515 return iswupper(x);
518 /***********************************************************************
519 * FormatMessage16 (USER.606)
521 DWORD WINAPI FormatMessage16(
522 DWORD dwFlags,
523 LPCVOID lpSource,
524 WORD dwMessageId,
525 WORD dwLanguageId,
526 LPSTR lpBuffer,
527 WORD nSize,
528 LPDWORD args /* va_list *args */
530 return FormatMessage32A(dwFlags, lpSource, (DWORD)dwMessageId, (DWORD)dwLanguageId, lpBuffer, (DWORD)nSize, args);
533 /***********************************************************************
534 * FormatMessage32A (KERNEL32.138)
535 * FIXME: missing wrap,FROM_SYSTEM message-loading,
537 DWORD WINAPI FormatMessage32A(
538 DWORD dwFlags,
539 LPCVOID lpSource,
540 DWORD dwMessageId,
541 DWORD dwLanguageId,
542 LPSTR lpBuffer,
543 DWORD nSize,
544 LPDWORD args /* va_list *args */
546 LPSTR target,t;
547 DWORD talloced;
548 LPSTR from,f;
549 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
550 DWORD nolinefeed = 0;
552 TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
553 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
554 if (width)
555 FIXME(resource,"line wrapping not supported.\n");
556 from = NULL;
557 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
558 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
559 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
560 from = HeapAlloc( GetProcessHeap(),0,200 );
561 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
563 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
564 INT32 bufsize;
566 dwMessageId &= 0xFFFF;
567 bufsize=LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,NULL,100);
568 if (bufsize) {
569 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
570 LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
573 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
574 t = target;
575 talloced= 100;
577 #define ADD_TO_T(c) \
578 *t++=c;\
579 if (t-target == talloced) {\
580 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
581 t = target+talloced;\
582 talloced*=2;\
585 if (from) {
586 f=from;
587 while (*f && !nolinefeed) {
588 if (*f=='%') {
589 int insertnr;
590 char *fmtstr,*sprintfbuf,*x,*lastf;
591 DWORD *argliststart;
593 fmtstr = NULL;
594 lastf = f;
595 f++;
596 if (!*f) {
597 ADD_TO_T('%');
598 continue;
600 switch (*f) {
601 case '1':case '2':case '3':case '4':case '5':
602 case '6':case '7':case '8':case '9':
603 insertnr=*f-'0';
604 switch (f[1]) {
605 case '0':case '1':case '2':case '3':
606 case '4':case '5':case '6':case '7':
607 case '8':case '9':
608 f++;
609 insertnr=insertnr*10+*f-'0';
610 f++;
611 break;
612 default:
613 f++;
614 break;
616 if (*f=='!') {
617 f++;
618 if (NULL!=(x=strchr(f,'!'))) {
619 *x='\0';
620 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
621 sprintf(fmtstr,"%%%s",f);
622 f=x+1;
623 } else {
624 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
625 sprintf(fmtstr,"%%%s",f);
626 f+=strlen(f); /*at \0*/
628 } else
629 if(!args)
630 break;
631 else
632 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
633 if (args) {
634 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
635 argliststart=args+insertnr-1;
636 else
637 argliststart=(*(DWORD**)args)+insertnr-1;
639 if (fmtstr[strlen(fmtstr)-1]=='s')
640 sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
641 else
642 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
644 /* CMF - This makes a BIG assumption about va_list */
645 wvsprintf32A(sprintfbuf, fmtstr, (va_list) argliststart);
646 x=sprintfbuf;
647 while (*x) {
648 ADD_TO_T(*x++);
650 HeapFree(GetProcessHeap(),0,sprintfbuf);
651 } else {
652 /* NULL args - copy formatstr
653 * (probably wrong)
655 while ((lastf<f)&&(*lastf)) {
656 ADD_TO_T(*lastf++);
659 HeapFree(GetProcessHeap(),0,fmtstr);
660 break;
661 case 'n':
662 /* FIXME: perhaps add \r too? */
663 ADD_TO_T('\n');
664 f++;
665 break;
666 case '0':
667 nolinefeed=1;
668 f++;
669 break;
670 default:ADD_TO_T(*f++)
671 break;
674 } else {
675 ADD_TO_T(*f++)
678 *t='\0';
680 if (!nolinefeed) {
681 /* add linefeed */
682 if(t==target || t[-1]!='\n')
683 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
685 talloced = strlen(target)+1;
686 if (nSize && talloced<nSize) {
687 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
689 TRACE(resource,"-- %s\n",debugstr_a(target));
690 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
691 /* nSize is the MINIMUM size */
692 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced);
693 memcpy(*(LPSTR*)lpBuffer,target,talloced);
694 } else
695 strncpy(lpBuffer,target,nSize);
696 HeapFree(GetProcessHeap(),0,target);
697 if (from) HeapFree(GetProcessHeap(),0,from);
698 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
699 strlen(*(LPSTR*)lpBuffer):
700 strlen(lpBuffer);
702 #undef ADD_TO_T
705 /***********************************************************************
706 * FormatMessage32W (KERNEL32.138)
708 DWORD WINAPI FormatMessage32W(
709 DWORD dwFlags,
710 LPCVOID lpSource,
711 DWORD dwMessageId,
712 DWORD dwLanguageId,
713 LPWSTR lpBuffer,
714 DWORD nSize,
715 LPDWORD args /* va_list *args */
717 LPSTR target,t;
718 DWORD talloced;
719 LPSTR from,f;
720 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
721 DWORD nolinefeed = 0;
723 TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
724 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
725 if (width)
726 FIXME(resource,"line wrapping not supported.\n");
727 from = NULL;
728 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
729 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
730 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
731 /* gather information from system message tables ... */
732 from = HeapAlloc( GetProcessHeap(),0,200 );
733 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
735 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
736 INT32 bufsize;
738 dwMessageId &= 0xFFFF;
739 bufsize=LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,NULL,100);
740 if (bufsize)
742 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
743 LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
746 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
747 t = target;
748 talloced= 100;
750 #define ADD_TO_T(c) \
751 *t++=c;\
752 if (t-target == talloced) {\
753 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
754 t = target+talloced;\
755 talloced*=2;\
758 if (from) {
759 f=from;
760 while (*f && !nolinefeed) {
761 if (*f=='%') {
762 int insertnr;
763 char *fmtstr,*sprintfbuf,*x;
764 DWORD *argliststart;
766 fmtstr = NULL;
767 f++;
768 if (!*f) {
769 ADD_TO_T('%');
770 continue;
772 switch (*f) {
773 case '1':case '2':case '3':case '4':case '5':
774 case '6':case '7':case '8':case '9':
775 insertnr=*f-'0';
776 switch (f[1]) {
777 case '0':case '1':case '2':case '3':
778 case '4':case '5':case '6':case '7':
779 case '8':case '9':
780 f++;
781 insertnr=insertnr*10+*f-'0';
782 f++;
783 break;
784 default:
785 f++;
786 break;
788 if (*f=='!') {
789 f++;
790 if (NULL!=(x=strchr(f,'!')))
792 *x='\0';
793 fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
794 sprintf(fmtstr,"%%%s",f);
795 f=x+1;
796 } else {
797 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
798 sprintf(fmtstr,"%%%s",f);
799 f+=strlen(f); /*at \0*/
801 } else
802 if(!args)
803 break;
804 else
805 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
806 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
807 argliststart=args+insertnr-1;
808 else
809 argliststart=(*(DWORD**)args)+insertnr-1;
811 if (fmtstr[strlen(fmtstr)-1]=='s') {
812 DWORD xarr[3];
814 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
815 /* possible invalid pointers */
816 xarr[1]=*(argliststart+1);
817 xarr[2]=*(argliststart+2);
818 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlen32W((LPWSTR)argliststart[0])*2+1);
820 /* CMF - This makes a BIG assumption about va_list */
821 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
822 } else {
823 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
825 /* CMF - This makes a BIG assumption about va_list */
826 wvsprintf32A(sprintfbuf, fmtstr, (va_list) argliststart);
828 x=sprintfbuf;
829 while (*x) {
830 ADD_TO_T(*x++);
832 HeapFree(GetProcessHeap(),0,sprintfbuf);
833 HeapFree(GetProcessHeap(),0,fmtstr);
834 break;
835 case 'n':
836 /* FIXME: perhaps add \r too? */
837 ADD_TO_T('\n');
838 f++;
839 break;
840 case '0':
841 nolinefeed=1;
842 f++;
843 break;
844 default:ADD_TO_T(*f++)
845 break;
848 } else {
849 ADD_TO_T(*f++)
852 *t='\0';
854 if (!nolinefeed) {
855 /* add linefeed */
856 if(t==target || t[-1]!='\n')
857 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
859 talloced = strlen(target)+1;
860 if (nSize && talloced<nSize)
861 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
862 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
863 /* nSize is the MINIMUM size */
864 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced*2+2);
865 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
866 } else
867 lstrcpynAtoW(lpBuffer,target,nSize);
868 HeapFree(GetProcessHeap(),0,target);
869 if (from) HeapFree(GetProcessHeap(),0,from);
870 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
871 lstrlen32W(*(LPWSTR*)lpBuffer):
872 lstrlen32W(lpBuffer);
874 #undef ADD_TO_T