Fixed error messages.
[wine.git] / misc / lstr.c
blob625e469b6e25ea2f8ee381c3f562ca75c998166b
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 /* Funny to divide them between user and kernel. */
36 /* be careful: always use functions from wctype.h if character > 255 */
39 * Unicode case conversion routines ... these should be used where
40 * toupper/tolower are used for ASCII.
42 #ifndef HAVE_WCTYPE_H
43 /* FIXME: should probably get rid of wctype.h altogether */
44 #include "casemap.h"
46 WCHAR towupper(WCHAR code)
48 const WCHAR * ptr = uprtable[HIBYTE(code)];
49 return ptr ? ptr[LOBYTE(code)] : code;
52 WCHAR towlower(WCHAR code)
54 const WCHAR * ptr = lwrtable[HIBYTE(code)];
55 return ptr ? ptr[LOBYTE(code)] : code;
57 #endif /* HAVE_WCTYPE_H */
59 /***********************************************************************
60 * IsCharAlpha (USER.433)
62 BOOL16 WINAPI IsCharAlpha16(CHAR ch)
64 return isalpha(ch); /* This is probably not right for NLS */
67 /***********************************************************************
68 * IsCharAlphanumeric (USER.434)
70 BOOL16 WINAPI IsCharAlphaNumeric16(CHAR ch)
72 return isalnum(ch);
75 /***********************************************************************
76 * IsCharUpper (USER.435)
78 BOOL16 WINAPI IsCharUpper16(CHAR ch)
80 return isupper(ch);
83 /***********************************************************************
84 * IsCharLower (USER.436)
86 BOOL16 WINAPI IsCharLower16(CHAR ch)
88 return islower(ch);
91 /***********************************************************************
92 * AnsiUpper16 (USER.431)
94 SEGPTR WINAPI AnsiUpper16( SEGPTR strOrChar )
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 */
99 /* uppercase only one char if strOrChar < 0x10000 */
100 if (HIWORD(strOrChar))
102 char *s;
103 for (s = PTR_SEG_TO_LIN(strOrChar); *s; s++) *s = toupper(*s);
104 return strOrChar;
106 else return toupper((char)strOrChar);
110 /***********************************************************************
111 * AnsiUpperBuff16 (USER.437)
113 UINT16 WINAPI AnsiUpperBuff16( LPSTR str, UINT16 len )
115 UINT32 count = len ? len : 65536;
116 for (; count; count--, str++) *str = toupper(*str);
117 return len;
120 /***********************************************************************
121 * AnsiLower16 (USER.432)
123 SEGPTR WINAPI AnsiLower16( SEGPTR strOrChar )
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 */
128 /* lowercase only one char if strOrChar < 0x10000 */
129 if (HIWORD(strOrChar))
131 char *s;
132 for (s = PTR_SEG_TO_LIN( strOrChar ); *s; s++) *s = tolower( *s );
133 return strOrChar;
135 else return tolower((char)strOrChar);
139 /***********************************************************************
140 * AnsiLowerBuff16 (USER.438)
142 UINT16 WINAPI AnsiLowerBuff16( LPSTR str, UINT16 len )
144 UINT32 count = len ? len : 65536;
145 for (; count; count--, str++) *str = tolower(*str);
146 return len;
150 /***********************************************************************
151 * AnsiNext16 (USER.472)
153 SEGPTR WINAPI AnsiNext16(SEGPTR current)
155 return (*(char *)PTR_SEG_TO_LIN(current)) ? current + 1 : current;
159 /***********************************************************************
160 * AnsiPrev16 (USER.473)
162 SEGPTR WINAPI AnsiPrev16( SEGPTR start, SEGPTR current )
164 return (current == start) ? start : current - 1;
168 /***********************************************************************
169 * OutputDebugString16 (KERNEL.115)
171 void WINAPI OutputDebugString16( LPCSTR str )
173 char module[10];
174 if (!GetModuleName( GetCurrentTask(), module, sizeof(module) ))
175 strcpy( module, "???" );
177 DUMP( "%s says %s\n", module, debugstr_a(str) );
181 /***********************************************************************
182 * OutputDebugString32A (KERNEL32
184 void WINAPI OutputDebugString32A( LPCSTR str )
186 OutputDebugString16( str );
191 /***********************************************************************
192 * OutputDebugString32W (KERNEL32
194 void WINAPI OutputDebugString32W( LPCWSTR str )
196 LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
197 OutputDebugString32A( p );
198 HeapFree( GetProcessHeap(), 0, p );
203 /***********************************************************************
204 * CharNext32A (USER32.29)
206 LPSTR WINAPI CharNext32A( LPCSTR ptr )
208 if (!*ptr) return (LPSTR)ptr;
209 if (IsDBCSLeadByte32( *ptr )) return (LPSTR)(ptr + 2);
210 return (LPSTR)(ptr + 1);
214 /***********************************************************************
215 * CharNextEx32A (USER32.30)
217 LPSTR WINAPI CharNextEx32A( WORD codepage, LPCSTR ptr, DWORD flags )
219 if (!*ptr) return (LPSTR)ptr;
220 if (IsDBCSLeadByteEx( codepage, *ptr )) return (LPSTR)(ptr + 2);
221 return (LPSTR)(ptr + 1);
225 /***********************************************************************
226 * CharNextExW (USER32.31)
228 LPWSTR WINAPI CharNextEx32W(WORD codepage,LPCWSTR x,DWORD flags)
230 /* FIXME: add DBCS / codepage stuff */
231 if (*x) return (LPWSTR)(x+1);
232 else return (LPWSTR)x;
235 /***********************************************************************
236 * CharNextW (USER32.32)
238 LPWSTR WINAPI CharNext32W(LPCWSTR x)
240 if (*x) return (LPWSTR)(x+1);
241 else return (LPWSTR)x;
244 /***********************************************************************
245 * CharPrev32A (USER32.33)
247 LPSTR WINAPI CharPrev32A( LPCSTR start, LPCSTR ptr )
249 while (*start && (start < ptr))
251 LPCSTR next = CharNext32A( start );
252 if (next >= ptr) break;
253 start = next;
255 return (LPSTR)start;
259 /***********************************************************************
260 * CharPrevEx32A (USER32.34)
262 LPSTR WINAPI CharPrevEx32A( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
264 while (*start && (start < ptr))
266 LPCSTR next = CharNextEx32A( codepage, start, flags );
267 if (next > ptr) break;
268 start = next;
270 return (LPSTR)start;
274 /***********************************************************************
275 * CharPrevExW (USER32.35)
277 LPWSTR WINAPI CharPrevEx32W(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
279 /* FIXME: add DBCS / codepage stuff */
280 if (x>start) return (LPWSTR)(x-1);
281 else return (LPWSTR)x;
284 /***********************************************************************
285 * CharPrevW (USER32.36)
287 LPWSTR WINAPI CharPrev32W(LPCWSTR start,LPCWSTR x)
289 if (x>start) return (LPWSTR)(x-1);
290 else return (LPWSTR)x;
293 /***********************************************************************
294 * CharLowerA (USER32.25)
295 * FIXME: handle current locale
297 LPSTR WINAPI CharLower32A(LPSTR x)
299 LPSTR s;
301 if (HIWORD(x))
303 s=x;
304 while (*s)
306 *s=tolower(*s);
307 s++;
309 return x;
311 else return (LPSTR)tolower((char)(int)x);
314 /***********************************************************************
315 * CharLowerBuffA (USER32.26)
316 * FIXME: handle current locale
318 DWORD WINAPI CharLowerBuff32A(LPSTR x,DWORD buflen)
320 DWORD done=0;
322 if (!x) return 0; /* YES */
323 while (*x && (buflen--))
325 *x=tolower(*x);
326 x++;
327 done++;
329 return done;
332 /***********************************************************************
333 * CharLowerBuffW (USER32.27)
334 * FIXME: handle current locale
336 DWORD WINAPI CharLowerBuff32W(LPWSTR x,DWORD buflen)
338 DWORD done=0;
340 if (!x) return 0; /* YES */
341 while (*x && (buflen--))
343 *x=towlower(*x);
344 x++;
345 done++;
347 return done;
350 /***********************************************************************
351 * CharLowerW (USER32.28)
352 * FIXME: handle current locale
354 LPWSTR WINAPI CharLower32W(LPWSTR x)
356 if (HIWORD(x))
358 LPWSTR s = x;
359 while (*s)
361 *s=towlower(*s);
362 s++;
364 return x;
366 else return (LPWSTR)((UINT32)towlower(LOWORD(x)));
369 /***********************************************************************
370 * CharUpper32A (USER32.41)
371 * FIXME: handle current locale
373 LPSTR WINAPI CharUpper32A(LPSTR x)
375 if (HIWORD(x))
377 LPSTR s = x;
378 while (*s)
380 *s=toupper(*s);
381 s++;
383 return x;
385 return (LPSTR)toupper((char)(int)x);
388 /***********************************************************************
389 * CharUpperBuffA (USER32.42)
390 * FIXME: handle current locale
392 DWORD WINAPI CharUpperBuff32A(LPSTR x,DWORD buflen)
394 DWORD done=0;
396 if (!x) return 0; /* YES */
397 while (*x && (buflen--))
399 *x=toupper(*x);
400 x++;
401 done++;
403 return done;
406 /***********************************************************************
407 * CharUpperBuffW (USER32.43)
408 * FIXME: handle current locale
410 DWORD WINAPI CharUpperBuff32W(LPWSTR x,DWORD buflen)
412 DWORD done=0;
414 if (!x) return 0; /* YES */
415 while (*x && (buflen--))
417 *x=towupper(*x);
418 x++;
419 done++;
421 return done;
424 /***********************************************************************
425 * CharUpperW (USER32.44)
426 * FIXME: handle current locale
428 LPWSTR WINAPI CharUpper32W(LPWSTR x)
430 if (HIWORD(x))
432 LPWSTR s = x;
433 while (*s)
435 *s=towupper(*s);
436 s++;
438 return x;
440 else return (LPWSTR)((UINT32)towupper(LOWORD(x)));
443 /***********************************************************************
444 * IsCharAlphaA (USER32.331)
445 * FIXME: handle current locale
447 BOOL32 WINAPI IsCharAlpha32A(CHAR x)
449 return isalpha(x);
452 /***********************************************************************
453 * IsCharAlphaNumericA (USER32.332)
454 * FIXME: handle current locale
456 BOOL32 WINAPI IsCharAlphaNumeric32A(CHAR x)
458 return isalnum(x);
461 /***********************************************************************
462 * IsCharAlphaNumericW (USER32.333)
463 * FIXME: handle current locale
465 BOOL32 WINAPI IsCharAlphaNumeric32W(WCHAR x)
467 return iswalnum(x);
470 /***********************************************************************
471 * IsCharAlphaW (USER32.334)
472 * FIXME: handle current locale
474 BOOL32 WINAPI IsCharAlpha32W(WCHAR x)
476 return iswalpha(x);
479 /***********************************************************************
480 * IsCharLower32A (USER32.335)
481 * FIXME: handle current locale
483 BOOL32 WINAPI IsCharLower32A(CHAR x)
485 return islower(x);
488 /***********************************************************************
489 * IsCharLower32W (USER32.336)
490 * FIXME: handle current locale
492 BOOL32 WINAPI IsCharLower32W(WCHAR x)
494 return iswlower(x);
497 /***********************************************************************
498 * IsCharUpper32A (USER32.337)
499 * FIXME: handle current locale
501 BOOL32 WINAPI IsCharUpper32A(CHAR x)
503 return isupper(x);
506 /***********************************************************************
507 * IsCharUpper32W (USER32.338)
508 * FIXME: handle current locale
510 BOOL32 WINAPI IsCharUpper32W(WCHAR x)
512 return iswupper(x);
515 /***********************************************************************
516 * FormatMessage16 (USER.606)
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 */
527 return FormatMessage32A(dwFlags, lpSource, (DWORD)dwMessageId, (DWORD)dwLanguageId, lpBuffer, (DWORD)nSize, args);
530 /***********************************************************************
531 * FormatMessage32A (KERNEL32.138)
532 * FIXME: missing wrap,FROM_SYSTEM message-loading,
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 */
543 LPSTR target,t;
544 DWORD talloced;
545 LPSTR from,f;
546 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
547 DWORD nolinefeed = 0;
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);
560 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
561 INT32 bufsize;
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);
570 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
571 t = target;
572 talloced= 100;
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;\
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;
590 fmtstr = NULL;
591 lastf = f;
592 f++;
593 if (!*f) {
594 ADD_TO_T('%');
595 continue;
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;
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*/
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;
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);
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++);
647 HeapFree(GetProcessHeap(),0,sprintfbuf);
648 } else {
649 /* NULL args - copy formatstr
650 * (probably wrong)
652 while ((lastf<f)&&(*lastf)) {
653 ADD_TO_T(*lastf++);
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;
671 } else {
672 ADD_TO_T(*f++)
675 *t='\0';
677 if (!nolinefeed) {
678 /* add linefeed */
679 if(t==target || t[-1]!='\n')
680 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
682 talloced = strlen(target)+1;
683 if (nSize && talloced<nSize) {
684 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
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);
699 #undef ADD_TO_T
702 /***********************************************************************
703 * FormatMessage32W (KERNEL32.138)
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 */
714 LPSTR target,t;
715 DWORD talloced;
716 LPSTR from,f;
717 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
718 DWORD nolinefeed = 0;
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);
732 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
733 INT32 bufsize;
735 dwMessageId &= 0xFFFF;
736 bufsize=LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,NULL,100);
737 if (bufsize)
739 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
740 LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
743 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
744 t = target;
745 talloced= 100;
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;\
755 if (from) {
756 f=from;
757 while (*f && !nolinefeed) {
758 if (*f=='%') {
759 int insertnr;
760 char *fmtstr,*sprintfbuf,*x;
761 DWORD *argliststart;
763 fmtstr = NULL;
764 f++;
765 if (!*f) {
766 ADD_TO_T('%');
767 continue;
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;
785 if (*f=='!') {
786 f++;
787 if (NULL!=(x=strchr(f,'!')))
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*/
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;
808 if (fmtstr[strlen(fmtstr)-1]=='s') {
809 DWORD xarr[3];
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);
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);
822 /* CMF - This makes a BIG assumption about va_list */
823 wvsprintf32A(sprintfbuf, fmtstr, (va_list) argliststart);
825 x=sprintfbuf;
826 while (*x) {
827 ADD_TO_T(*x++);
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;
845 } else {
846 ADD_TO_T(*f++)
849 *t='\0';
851 if (!nolinefeed) {
852 /* add linefeed */
853 if(t==target || t[-1]!='\n')
854 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
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);
871 #undef ADD_TO_T