Release 980503
[wine/hacks.git] / misc / lstr.c
blob98d87488a75e6c17585191d593083e58b6e604c1
1 /*
2 * String functions
4 * Copyright 1993 Yngvi Sigurjonsson (yngvi@hafro.is)
5 * Copyright 1996 Marcus Meissner
6 */
8 #include "config.h"
10 #include <stdio.h>
11 #include <stdarg.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
16 #ifdef HAVE_WCTYPE_H
17 # include <wctype.h>
18 #else
19 # define towlower(c) tolower(c)
20 # define towupper(c) toupper(c)
21 # define iswalnum(c) isalnum(c)
22 # define iswalpha(c) isalpha(c)
23 # define iswupper(c) isupper(c)
24 # define iswlower(c) islower(c)
25 #endif /* HAVE_WCTYPE_H */
28 #include "windows.h"
29 #include "winnt.h" /* HEAP_ macros */
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 /* Funny to divide them between user and kernel. */
39 /* be careful: always use functions from wctype.h if character > 255 */
41 /***********************************************************************
42 * IsCharAlpha (USER.433)
44 BOOL16 WINAPI IsCharAlpha16(CHAR ch)
46 return isalpha(ch); /* This is probably not right for NLS */
49 /***********************************************************************
50 * IsCharAlphanumeric (USER.434)
52 BOOL16 WINAPI IsCharAlphaNumeric16(CHAR ch)
54 return isalnum(ch);
57 /***********************************************************************
58 * IsCharUpper (USER.435)
60 BOOL16 WINAPI IsCharUpper16(CHAR ch)
62 return isupper(ch);
65 /***********************************************************************
66 * IsCharLower (USER.436)
68 BOOL16 WINAPI IsCharLower16(CHAR ch)
70 return islower(ch);
73 /***********************************************************************
74 * AnsiUpper16 (USER.431)
76 SEGPTR WINAPI AnsiUpper16( SEGPTR strOrChar )
78 /* I am not sure if the locale stuff works with toupper, but then again
79 I am not sure if the Linux libc locale stuffs works at all */
81 /* uppercase only one char if strOrChar < 0x10000 */
82 if (HIWORD(strOrChar))
84 char *s;
85 for (s = PTR_SEG_TO_LIN(strOrChar); *s; s++) *s = toupper(*s);
86 return strOrChar;
88 else return toupper((char)strOrChar);
92 /***********************************************************************
93 * AnsiUpperBuff16 (USER.437)
95 UINT16 WINAPI AnsiUpperBuff16( LPSTR str, UINT16 len )
97 UINT32 count = len ? len : 65536;
98 for (; count; count--, str++) *str = toupper(*str);
99 return len;
102 /***********************************************************************
103 * AnsiLower16 (USER.432)
105 SEGPTR WINAPI AnsiLower16( SEGPTR strOrChar )
107 /* I am not sure if the locale stuff works with toupper, but then again
108 I am not sure if the Linux libc locale stuffs works at all */
110 /* lowercase only one char if strOrChar < 0x10000 */
111 if (HIWORD(strOrChar))
113 char *s;
114 for (s = PTR_SEG_TO_LIN( strOrChar ); *s; s++) *s = tolower( *s );
115 return strOrChar;
117 else return tolower((char)strOrChar);
121 /***********************************************************************
122 * AnsiLowerBuff16 (USER.438)
124 UINT16 WINAPI AnsiLowerBuff16( LPSTR str, UINT16 len )
126 UINT32 count = len ? len : 65536;
127 for (; count; count--, str++) *str = tolower(*str);
128 return len;
132 /***********************************************************************
133 * AnsiNext16 (USER.472)
135 SEGPTR WINAPI AnsiNext16(SEGPTR current)
137 return (*(char *)PTR_SEG_TO_LIN(current)) ? current + 1 : current;
141 /***********************************************************************
142 * AnsiPrev16 (USER.473)
144 SEGPTR WINAPI AnsiPrev16( SEGPTR start, SEGPTR current )
146 return (current == start) ? start : current - 1;
150 /***********************************************************************
151 * OutputDebugString16 (KERNEL.115)
153 void WINAPI OutputDebugString16( LPCSTR str )
155 char *module;
156 char *p, *buffer = HeapAlloc( GetProcessHeap(), 0, strlen(str)+2 );
157 /* Remove CRs */
158 for (p = buffer; *str; str++) if (*str != '\r') *p++ = *str;
159 *p = '\0';
160 if ((p > buffer) && (p[-1] == '\n')) p[1] = '\0'; /* Remove trailing \n */
161 module = MODULE_GetModuleName( GetCurrentTask() );
162 TRACE(resource, "%s says '%s'\n",
163 module ? module : "???", buffer );
164 HeapFree( GetProcessHeap(), 0, buffer );
168 /***********************************************************************
169 * OutputDebugString32A (KERNEL32
171 void WINAPI OutputDebugString32A( LPCSTR str )
173 OutputDebugString16( str );
178 /***********************************************************************
179 * OutputDebugString32W (KERNEL32
181 void WINAPI OutputDebugString32W( LPCWSTR str )
183 LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
184 OutputDebugString32A( p );
185 HeapFree( GetProcessHeap(), 0, p );
190 /***********************************************************************
191 * CharNext32A (USER32.29)
193 LPSTR WINAPI CharNext32A( LPCSTR ptr )
195 if (!*ptr) return (LPSTR)ptr;
196 if (IsDBCSLeadByte32( *ptr )) return (LPSTR)(ptr + 2);
197 return (LPSTR)(ptr + 1);
201 /***********************************************************************
202 * CharNextEx32A (USER32.30)
204 LPSTR WINAPI CharNextEx32A( WORD codepage, LPCSTR ptr, DWORD flags )
206 if (!*ptr) return (LPSTR)ptr;
207 if (IsDBCSLeadByteEx( codepage, *ptr )) return (LPSTR)(ptr + 2);
208 return (LPSTR)(ptr + 1);
212 /***********************************************************************
213 * CharNextExW (USER32.31)
215 LPWSTR WINAPI CharNextEx32W(WORD codepage,LPCWSTR x,DWORD flags)
217 /* FIXME: add DBCS / codepage stuff */
218 if (*x) return (LPWSTR)(x+1);
219 else return (LPWSTR)x;
222 /***********************************************************************
223 * CharNextW (USER32.32)
225 LPWSTR WINAPI CharNext32W(LPCWSTR x)
227 if (*x) return (LPWSTR)(x+1);
228 else return (LPWSTR)x;
231 /***********************************************************************
232 * CharPrev32A (USER32.33)
234 LPSTR WINAPI CharPrev32A( LPCSTR start, LPCSTR ptr )
236 while (*start && (start < ptr))
238 LPCSTR next = CharNext32A( start );
239 if (next >= ptr) break;
240 start = next;
242 return (LPSTR)start;
246 /***********************************************************************
247 * CharPrevEx32A (USER32.34)
249 LPSTR WINAPI CharPrevEx32A( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
251 while (*start && (start < ptr))
253 LPCSTR next = CharNextEx32A( codepage, start, flags );
254 if (next > ptr) break;
255 start = next;
257 return (LPSTR)start;
261 /***********************************************************************
262 * CharPrevExW (USER32.35)
264 LPWSTR WINAPI CharPrevEx32W(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
266 /* FIXME: add DBCS / codepage stuff */
267 if (x>start) return (LPWSTR)(x-1);
268 else return (LPWSTR)x;
271 /***********************************************************************
272 * CharPrevW (USER32.36)
274 LPWSTR WINAPI CharPrev32W(LPCWSTR start,LPCWSTR x)
276 if (x>start) return (LPWSTR)(x-1);
277 else return (LPWSTR)x;
280 /***********************************************************************
281 * CharLowerA (USER32.25)
282 * FIXME: handle current locale
284 LPSTR WINAPI CharLower32A(LPSTR x)
286 LPSTR s;
288 if (HIWORD(x))
290 s=x;
291 while (*s)
293 *s=tolower(*s);
294 s++;
296 return x;
298 else return (LPSTR)tolower((char)(int)x);
301 /***********************************************************************
302 * CharLowerBuffA (USER32.26)
303 * FIXME: handle current locale
305 DWORD WINAPI CharLowerBuff32A(LPSTR x,DWORD buflen)
307 DWORD done=0;
309 if (!x) return 0; /* YES */
310 while (*x && (buflen--))
312 *x=tolower(*x);
313 x++;
314 done++;
316 return done;
319 /***********************************************************************
320 * CharLowerBuffW (USER32.27)
321 * FIXME: handle current locale
323 DWORD WINAPI CharLowerBuff32W(LPWSTR x,DWORD buflen)
325 DWORD done=0;
327 if (!x) return 0; /* YES */
328 while (*x && (buflen--))
330 *x=towlower(*x);
331 x++;
332 done++;
334 return done;
337 /***********************************************************************
338 * CharLowerW (USER32.28)
339 * FIXME: handle current locale
341 LPWSTR WINAPI CharLower32W(LPWSTR x)
343 if (HIWORD(x))
345 LPWSTR s = x;
346 while (*s)
348 *s=towlower(*s);
349 s++;
351 return x;
353 else return (LPWSTR)towlower(LOWORD(x));
356 /***********************************************************************
357 * CharUpper32A (USER32.41)
358 * FIXME: handle current locale
360 LPSTR WINAPI CharUpper32A(LPSTR x)
362 if (HIWORD(x))
364 LPSTR s = x;
365 while (*s)
367 *s=toupper(*s);
368 s++;
370 return x;
372 return (LPSTR)toupper((char)(int)x);
375 /***********************************************************************
376 * CharUpperBuffA (USER32.42)
377 * FIXME: handle current locale
379 DWORD WINAPI CharUpperBuff32A(LPSTR x,DWORD buflen)
381 DWORD done=0;
383 if (!x) return 0; /* YES */
384 while (*x && (buflen--))
386 *x=toupper(*x);
387 x++;
388 done++;
390 return done;
393 /***********************************************************************
394 * CharUpperBuffW (USER32.43)
395 * FIXME: handle current locale
397 DWORD WINAPI CharUpperBuff32W(LPWSTR x,DWORD buflen)
399 DWORD done=0;
401 if (!x) return 0; /* YES */
402 while (*x && (buflen--))
404 *x=towupper(*x);
405 x++;
406 done++;
408 return done;
411 /***********************************************************************
412 * CharUpperW (USER32.44)
413 * FIXME: handle current locale
415 LPWSTR WINAPI CharUpper32W(LPWSTR x)
417 if (HIWORD(x))
419 LPWSTR s = x;
420 while (*s)
422 *s=towupper(*s);
423 s++;
425 return x;
427 else return (LPWSTR)towupper(LOWORD(x));
430 /***********************************************************************
431 * IsCharAlphaA (USER32.331)
432 * FIXME: handle current locale
434 BOOL32 WINAPI IsCharAlpha32A(CHAR x)
436 return isalpha(x);
439 /***********************************************************************
440 * IsCharAlphaNumericA (USER32.332)
441 * FIXME: handle current locale
443 BOOL32 WINAPI IsCharAlphaNumeric32A(CHAR x)
445 return isalnum(x);
448 /***********************************************************************
449 * IsCharAlphaNumericW (USER32.333)
450 * FIXME: handle current locale
452 BOOL32 WINAPI IsCharAlphaNumeric32W(WCHAR x)
454 return iswalnum(x);
457 /***********************************************************************
458 * IsCharAlphaW (USER32.334)
459 * FIXME: handle current locale
461 BOOL32 WINAPI IsCharAlpha32W(WCHAR x)
463 return iswalpha(x);
466 /***********************************************************************
467 * IsCharLower32A (USER32.335)
468 * FIXME: handle current locale
470 BOOL32 WINAPI IsCharLower32A(CHAR x)
472 return islower(x);
475 /***********************************************************************
476 * IsCharLower32W (USER32.336)
477 * FIXME: handle current locale
479 BOOL32 WINAPI IsCharLower32W(WCHAR x)
481 return iswlower(x);
484 /***********************************************************************
485 * IsCharUpper32A (USER32.337)
486 * FIXME: handle current locale
488 BOOL32 WINAPI IsCharUpper32A(CHAR x)
490 return isupper(x);
493 /***********************************************************************
494 * IsCharUpper32W (USER32.338)
495 * FIXME: handle current locale
497 BOOL32 WINAPI IsCharUpper32W(WCHAR x)
499 return iswupper(x);
502 /***********************************************************************
503 * FormatMessage32A (KERNEL32.138)
504 * FIXME: missing wrap,FROM_SYSTEM message-loading,
506 DWORD WINAPI FormatMessage32A(
507 DWORD dwFlags,
508 LPCVOID lpSource,
509 DWORD dwMessageId,
510 DWORD dwLanguageId,
511 LPSTR lpBuffer,
512 DWORD nSize,
513 LPDWORD args /* va_list *args */
515 LPSTR target,t;
516 DWORD talloced;
517 LPSTR from,f;
518 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
519 DWORD nolinefeed = 0;
521 TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
522 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
523 if (width)
524 FIXME(resource,"line wrapping not supported.\n");
525 from = NULL;
526 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
527 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
528 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
529 from = HeapAlloc( GetProcessHeap(),0,200 );
530 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
532 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
533 INT32 bufsize;
535 dwMessageId &= 0xFFFF;
536 bufsize=LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,NULL,100);
537 if (bufsize) {
538 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
539 LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
542 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
543 t = target;
544 talloced= 100;
546 #define ADD_TO_T(c) \
547 *t++=c;\
548 if (t-target == talloced) {\
549 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
550 t = target+talloced;\
551 talloced*=2;\
554 if (from) {
555 f=from;
556 while (*f) {
557 if (*f=='%') {
558 int insertnr;
559 char *fmtstr,*sprintfbuf,*x,*lastf;
560 DWORD *argliststart;
562 fmtstr = NULL;
563 lastf = f;
564 f++;
565 if (!*f) {
566 ADD_TO_T('%');
567 continue;
569 switch (*f) {
570 case '1':case '2':case '3':case '4':case '5':
571 case '6':case '7':case '8':case '9':
572 insertnr=*f-'0';
573 switch (f[1]) {
574 case '0':case '1':case '2':case '3':
575 case '4':case '5':case '6':case '7':
576 case '8':case '9':
577 f++;
578 insertnr=insertnr*10+*f-'0';
579 f++;
580 break;
581 default:
582 f++;
583 break;
585 if (*f=='!') {
586 f++;
587 if (NULL!=(x=strchr(f,'!'))) {
588 *x='\0';
589 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
590 sprintf(fmtstr,"%%%s",f);
591 f=x+1;
592 } else {
593 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
594 sprintf(fmtstr,"%%%s",f);
595 f+=strlen(f); /*at \0*/
597 } else
598 if(!args)
599 break;
600 else
601 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
602 if (args) {
603 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
604 argliststart=args+insertnr-1;
605 else
606 argliststart=(*(DWORD**)args)+insertnr-1;
608 if (fmtstr[strlen(fmtstr)-1]=='s')
609 sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
610 else
611 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
613 /* CMF - This makes a BIG assumption about va_list */
614 wvsprintf32A(sprintfbuf, fmtstr, (va_list) argliststart);
615 x=sprintfbuf;
616 while (*x) {
617 ADD_TO_T(*x++);
619 HeapFree(GetProcessHeap(),0,sprintfbuf);
620 } else {
621 /* NULL args - copy formatstr
622 * (probably wrong)
624 while ((lastf<f)&&(*lastf)) {
625 ADD_TO_T(*lastf++);
628 HeapFree(GetProcessHeap(),0,fmtstr);
629 break;
630 case 'n':
631 /* FIXME: perhaps add \r too? */
632 ADD_TO_T('\n');
633 f++;
634 break;
635 case '0':
636 nolinefeed=1;
637 f++;
638 break;
639 default:ADD_TO_T(*f++)
640 break;
643 } else {
644 ADD_TO_T(*f++)
647 *t='\0';
649 if (nolinefeed) {
650 /* remove linefeed */
651 if(t>target && t[-1]=='\n') {
652 *--t=0;
653 if(t>target && t[-1]=='\r')
654 *--t=0;
656 } else {
657 /* add linefeed */
658 if(t==target || t[-1]!='\n')
659 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
661 talloced = strlen(target)+1;
662 if (nSize && talloced<nSize) {
663 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
665 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
666 /* nSize is the MINIMUM size */
667 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced);
668 memcpy(*(LPSTR*)lpBuffer,target,talloced);
669 } else
670 strncpy(lpBuffer,target,nSize);
671 HeapFree(GetProcessHeap(),0,target);
672 if (from) HeapFree(GetProcessHeap(),0,from);
673 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
674 strlen(*(LPSTR*)lpBuffer):
675 strlen(lpBuffer);
677 #undef ADD_TO_T
680 /***********************************************************************
681 * FormatMessage32W (KERNEL32.138)
683 DWORD WINAPI FormatMessage32W(
684 DWORD dwFlags,
685 LPCVOID lpSource,
686 DWORD dwMessageId,
687 DWORD dwLanguageId,
688 LPWSTR lpBuffer,
689 DWORD nSize,
690 LPDWORD args /* va_list *args */
692 LPSTR target,t;
693 DWORD talloced;
694 LPSTR from,f;
695 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
696 DWORD nolinefeed = 0;
698 TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
699 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
700 if (width)
701 FIXME(resource,"line wrapping not supported.\n");
702 from = NULL;
703 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
704 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
705 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
706 /* gather information from system message tables ... */
707 from = HeapAlloc( GetProcessHeap(),0,200 );
708 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
710 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
711 INT32 bufsize;
713 dwMessageId &= 0xFFFF;
714 bufsize=LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,NULL,100);
715 if (bufsize)
717 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
718 LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
721 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
722 t = target;
723 talloced= 100;
725 #define ADD_TO_T(c) \
726 *t++=c;\
727 if (t-target == talloced) {\
728 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
729 t = target+talloced;\
730 talloced*=2;\
733 if (from) {
734 f=from;
735 while (*f) {
736 if (*f=='%') {
737 int insertnr;
738 char *fmtstr,*sprintfbuf,*x;
739 DWORD *argliststart;
741 fmtstr = NULL;
742 f++;
743 if (!*f) {
744 ADD_TO_T('%');
745 continue;
747 switch (*f) {
748 case '1':case '2':case '3':case '4':case '5':
749 case '6':case '7':case '8':case '9':
750 insertnr=*f-'0';
751 switch (f[1]) {
752 case '0':case '1':case '2':case '3':
753 case '4':case '5':case '6':case '7':
754 case '8':case '9':
755 f++;
756 insertnr=insertnr*10+*f-'0';
757 f++;
758 break;
759 default:
760 f++;
761 break;
763 if (*f=='!') {
764 f++;
765 if (NULL!=(x=strchr(f,'!')))
767 *x='\0';
768 fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
769 sprintf(fmtstr,"%%%s",f);
770 f=x+1;
771 } else {
772 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
773 sprintf(fmtstr,"%%%s",f);
774 f+=strlen(f); /*at \0*/
776 } else
777 if(!args)
778 break;
779 else
780 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
781 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
782 argliststart=args+insertnr-1;
783 else
784 argliststart=(*(DWORD**)args)+insertnr-1;
786 if (fmtstr[strlen(fmtstr)-1]=='s') {
787 DWORD xarr[3];
789 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
790 /* possible invalid pointers */
791 xarr[1]=*(argliststart+1);
792 xarr[2]=*(argliststart+2);
793 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlen32W((LPWSTR)argliststart[0])*2+1);
795 /* CMF - This makes a BIG assumption about va_list */
796 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
797 } else {
798 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
800 /* CMF - This makes a BIG assumption about va_list */
801 wvsprintf32A(sprintfbuf, fmtstr, (va_list) argliststart);
803 x=sprintfbuf;
804 while (*x) {
805 ADD_TO_T(*x++);
807 HeapFree(GetProcessHeap(),0,sprintfbuf);
808 HeapFree(GetProcessHeap(),0,fmtstr);
809 break;
810 case 'n':
811 /* FIXME: perhaps add \r too? */
812 ADD_TO_T('\n');
813 f++;
814 break;
815 case '0':
816 nolinefeed=1;
817 f++;
818 break;
819 default:ADD_TO_T(*f++)
820 break;
823 } else {
824 ADD_TO_T(*f++)
827 *t='\0';
829 if (nolinefeed) {
830 /* remove linefeed */
831 if(t>target && t[-1]=='\n') {
832 *--t=0;
833 if(t>target && t[-1]=='\r')
834 *--t=0;
836 } else {
837 /* add linefeed */
838 if(t==target || t[-1]!='\n')
839 ADD_TO_T('\n'); /* FIXME: perhaps add \r too? */
841 talloced = strlen(target)+1;
842 if (nSize && talloced<nSize)
843 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
844 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
845 /* nSize is the MINIMUM size */
846 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced*2+2);
847 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
848 } else
849 lstrcpynAtoW(lpBuffer,target,nSize);
850 HeapFree(GetProcessHeap(),0,target);
851 if (from) HeapFree(GetProcessHeap(),0,from);
852 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
853 lstrlen32W(*(LPWSTR*)lpBuffer):
854 lstrlen32W(lpBuffer);
856 #undef ADD_TO_T