Added undocumented feature to InsertButtonA.
[wine.git] / misc / lstr.c
blob4f374c2aac2eee03b15a27f519d2e9dbd5907de1
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 */
24 #include "wine/winbase16.h"
25 #include "wine/winuser16.h"
26 #include "winbase.h"
27 #include "winuser.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 "debugtools.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 * CharNext32A (USER32.29)
178 LPSTR WINAPI CharNextA( LPCSTR ptr )
180 if (!*ptr) return (LPSTR)ptr;
181 if (IsDBCSLeadByte( *ptr )) return (LPSTR)(ptr + 2);
182 return (LPSTR)(ptr + 1);
186 /***********************************************************************
187 * CharNextEx32A (USER32.30)
189 LPSTR WINAPI CharNextExA( WORD codepage, LPCSTR ptr, DWORD flags )
191 if (!*ptr) return (LPSTR)ptr;
192 if (IsDBCSLeadByteEx( codepage, *ptr )) return (LPSTR)(ptr + 2);
193 return (LPSTR)(ptr + 1);
197 /***********************************************************************
198 * CharNextExW (USER32.31)
200 LPWSTR WINAPI CharNextExW(WORD codepage,LPCWSTR x,DWORD flags)
202 /* FIXME: add DBCS / codepage stuff */
203 if (*x) return (LPWSTR)(x+1);
204 else return (LPWSTR)x;
207 /***********************************************************************
208 * CharNextW (USER32.32)
210 LPWSTR WINAPI CharNextW(LPCWSTR x)
212 if (*x) return (LPWSTR)(x+1);
213 else return (LPWSTR)x;
216 /***********************************************************************
217 * CharPrev32A (USER32.33)
219 LPSTR WINAPI CharPrevA( LPCSTR start, LPCSTR ptr )
221 while (*start && (start < ptr))
223 LPCSTR next = CharNextA( start );
224 if (next >= ptr) break;
225 start = next;
227 return (LPSTR)start;
231 /***********************************************************************
232 * CharPrevEx32A (USER32.34)
234 LPSTR WINAPI CharPrevExA( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
236 while (*start && (start < ptr))
238 LPCSTR next = CharNextExA( codepage, start, flags );
239 if (next > ptr) break;
240 start = next;
242 return (LPSTR)start;
246 /***********************************************************************
247 * CharPrevExW (USER32.35)
249 LPWSTR WINAPI CharPrevExW(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
251 /* FIXME: add DBCS / codepage stuff */
252 if (x>start) return (LPWSTR)(x-1);
253 else return (LPWSTR)x;
256 /***********************************************************************
257 * CharPrevW (USER32.36)
259 LPWSTR WINAPI CharPrevW(LPCWSTR start,LPCWSTR x)
261 if (x>start) return (LPWSTR)(x-1);
262 else return (LPWSTR)x;
265 /***********************************************************************
266 * CharLowerA (USER32.25)
267 * FIXME: handle current locale
269 LPSTR WINAPI CharLowerA(LPSTR x)
271 LPSTR s;
273 if (HIWORD(x))
275 s=x;
276 while (*s)
278 *s=tolower(*s);
279 s++;
281 return x;
283 else return (LPSTR)tolower((char)(int)x);
286 /***********************************************************************
287 * CharLowerBuffA (USER32.26)
288 * FIXME: handle current locale
290 DWORD WINAPI CharLowerBuffA(LPSTR x,DWORD buflen)
292 DWORD done=0;
294 if (!x) return 0; /* YES */
295 while (*x && (buflen--))
297 *x=tolower(*x);
298 x++;
299 done++;
301 return done;
304 /***********************************************************************
305 * CharLowerBuffW (USER32.27)
306 * FIXME: handle current locale
308 DWORD WINAPI CharLowerBuffW(LPWSTR x,DWORD buflen)
310 DWORD done=0;
312 if (!x) return 0; /* YES */
313 while (*x && (buflen--))
315 *x=towlower(*x);
316 x++;
317 done++;
319 return done;
322 /***********************************************************************
323 * CharLowerW (USER32.28)
324 * FIXME: handle current locale
326 LPWSTR WINAPI CharLowerW(LPWSTR x)
328 if (HIWORD(x))
330 LPWSTR s = x;
331 while (*s)
333 *s=towlower(*s);
334 s++;
336 return x;
338 else return (LPWSTR)((UINT)towlower(LOWORD(x)));
341 /***********************************************************************
342 * CharUpper32A (USER32.41)
343 * FIXME: handle current locale
345 LPSTR WINAPI CharUpperA(LPSTR x)
347 if (HIWORD(x))
349 LPSTR s = x;
350 while (*s)
352 *s=toupper(*s);
353 s++;
355 return x;
357 return (LPSTR)toupper((char)(int)x);
360 /***********************************************************************
361 * CharUpperBuffA (USER32.42)
362 * FIXME: handle current locale
364 DWORD WINAPI CharUpperBuffA(LPSTR x,DWORD buflen)
366 DWORD done=0;
368 if (!x) return 0; /* YES */
369 while (*x && (buflen--))
371 *x=toupper(*x);
372 x++;
373 done++;
375 return done;
378 /***********************************************************************
379 * CharUpperBuffW (USER32.43)
380 * FIXME: handle current locale
382 DWORD WINAPI CharUpperBuffW(LPWSTR x,DWORD buflen)
384 DWORD done=0;
386 if (!x) return 0; /* YES */
387 while (*x && (buflen--))
389 *x=towupper(*x);
390 x++;
391 done++;
393 return done;
396 /***********************************************************************
397 * CharUpperW (USER32.44)
398 * FIXME: handle current locale
400 LPWSTR WINAPI CharUpperW(LPWSTR x)
402 if (HIWORD(x))
404 LPWSTR s = x;
405 while (*s)
407 *s=towupper(*s);
408 s++;
410 return x;
412 else return (LPWSTR)((UINT)towupper(LOWORD(x)));
415 /***********************************************************************
416 * IsCharAlphaA (USER32.331)
417 * FIXME: handle current locale
419 BOOL WINAPI IsCharAlphaA(CHAR x)
421 return (OLE2NLS_CT_CType3_LUT[(unsigned char)x] & C3_ALPHA);
424 /***********************************************************************
425 * IsCharAlphaNumericA (USER32.332)
426 * FIXME: handle current locale
428 BOOL WINAPI IsCharAlphaNumericA(CHAR x)
430 return IsCharAlphaA(x) || isdigit(x) ;
433 /***********************************************************************
434 * IsCharAlphaNumericW (USER32.333)
435 * FIXME: handle current locale
437 BOOL WINAPI IsCharAlphaNumericW(WCHAR x)
439 return iswalnum(x);
442 /***********************************************************************
443 * IsCharAlphaW (USER32.334)
444 * FIXME: handle current locale
446 BOOL WINAPI IsCharAlphaW(WCHAR x)
448 return iswalpha(x);
451 /***********************************************************************
452 * IsCharLower32A (USER32.335)
453 * FIXME: handle current locale
455 BOOL WINAPI IsCharLowerA(CHAR x)
457 return islower(x);
460 /***********************************************************************
461 * IsCharLower32W (USER32.336)
462 * FIXME: handle current locale
464 BOOL WINAPI IsCharLowerW(WCHAR x)
466 return iswlower(x);
469 /***********************************************************************
470 * IsCharUpper32A (USER32.337)
471 * FIXME: handle current locale
473 BOOL WINAPI IsCharUpperA(CHAR x)
475 return isupper(x);
478 /***********************************************************************
479 * IsCharUpper32W (USER32.338)
480 * FIXME: handle current locale
482 BOOL WINAPI IsCharUpperW(WCHAR x)
484 return iswupper(x);
487 /***********************************************************************
488 * FormatMessage16 (USER.606)
490 DWORD WINAPI FormatMessage16(
491 DWORD dwFlags,
492 SEGPTR lpSource, /*not always a valid pointer*/
493 WORD dwMessageId,
494 WORD dwLanguageId,
495 LPSTR lpBuffer, /* *((HLOCAL16*)) for FORMAT_MESSAGE_ALLOCATE_BUFFER*/
496 WORD nSize,
497 LPDWORD args /* va_list *args */
499 #ifdef __i386__
500 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
501 LPSTR target,t;
502 DWORD talloced;
503 LPSTR from,f;
504 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
505 BOOL eos = FALSE;
506 LPSTR allocstring = NULL;
508 TRACE("(0x%lx,%lx,%d,0x%x,%p,%d,%p)\n",
509 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
510 if (width)
511 FIXME("line wrapping not supported.\n");
512 from = NULL;
513 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
514 from = HEAP_strdupA( GetProcessHeap(), 0, PTR_SEG_TO_LIN(lpSource));
515 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
516 from = HeapAlloc( GetProcessHeap(),0,200 );
517 sprintf(from,"Systemmessage, messageid = 0x%08x\n",dwMessageId);
519 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
520 INT16 bufsize;
521 HINSTANCE16 hinst16 = ((HMODULE)lpSource & 0xffff);
523 dwMessageId &= 0xFFFF;
524 bufsize=LoadString16(hinst16,dwMessageId,NULL,0);
525 if (bufsize) {
526 from = HeapAlloc( GetProcessHeap(), 0, bufsize +1);
527 LoadString16(hinst16,dwMessageId,from,bufsize+1);
530 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
531 t = target;
532 talloced= 100;
534 #define ADD_TO_T(c) \
535 *t++=c;\
536 if (t-target == talloced) {\
537 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
538 t = target+talloced;\
539 talloced*=2;\
542 if (from) {
543 f=from;
544 while (*f && !eos) {
545 if (*f=='%') {
546 int insertnr;
547 char *fmtstr,*sprintfbuf,*x,*lastf;
548 DWORD *argliststart;
550 fmtstr = NULL;
551 lastf = f;
552 f++;
553 if (!*f) {
554 ADD_TO_T('%');
555 continue;
557 switch (*f) {
558 case '1':case '2':case '3':case '4':case '5':
559 case '6':case '7':case '8':case '9':
560 insertnr=*f-'0';
561 switch (f[1]) {
562 case '0':case '1':case '2':case '3':
563 case '4':case '5':case '6':case '7':
564 case '8':case '9':
565 f++;
566 insertnr=insertnr*10+*f-'0';
567 f++;
568 break;
569 default:
570 f++;
571 break;
573 if (*f=='!') {
574 f++;
575 if (NULL!=(x=strchr(f,'!'))) {
576 *x='\0';
577 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
578 sprintf(fmtstr,"%%%s",f);
579 f=x+1;
580 } else {
581 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
582 sprintf(fmtstr,"%%%s",f);
583 f+=strlen(f); /*at \0*/
585 } else
586 if(!args)
587 break;
588 else
589 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
590 if (args) {
591 argliststart=args+insertnr-1;
592 if (fmtstr[strlen(fmtstr)-1]=='s')
593 sprintfbuf=HeapAlloc(GetProcessHeap(),0,
594 strlen(PTR_SEG_TO_LIN(argliststart[0]))+1);
595 else
596 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
598 /* CMF - This makes a BIG assumption about va_list */
599 wvsprintf16(sprintfbuf, fmtstr, (va_list) argliststart);
600 x=sprintfbuf;
601 while (*x) {
602 ADD_TO_T(*x++);
604 HeapFree(GetProcessHeap(),0,sprintfbuf);
605 } else {
606 /* NULL args - copy formatstr
607 * (probably wrong)
609 while ((lastf<f)&&(*lastf)) {
610 ADD_TO_T(*lastf++);
613 HeapFree(GetProcessHeap(),0,fmtstr);
614 break;
615 case '0': /* Just stop processing format string */
616 eos = TRUE;
617 f++;
618 break;
619 case 'n': /* 16 bit version just outputs 'n' */
620 default:
621 ADD_TO_T(*f++);
622 break;
624 } else { /* '\n' or '\r' gets mapped to "\r\n" */
625 if(*f == '\n' || *f == '\r') {
626 ADD_TO_T('\r');
627 ADD_TO_T('\n');
628 if(*f++ == '\r' && *f == '\n')
629 f++;
630 } else {
631 ADD_TO_T(*f++);
635 *t='\0';
637 talloced = strlen(target)+1;
638 if (nSize && talloced<nSize) {
639 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
641 TRACE("-- %s\n",debugstr_a(target));
642 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
643 /* nSize is the MINIMUM size */
644 *((HLOCAL16*)lpBuffer)= LocalAlloc16(LPTR,talloced);
645 allocstring=PTR_SEG_OFF_TO_LIN(CURRENT_DS,*((HLOCAL16*)lpBuffer));
646 memcpy( allocstring,target,talloced);
647 } else
648 strncpy(lpBuffer,target,nSize);
649 HeapFree(GetProcessHeap(),0,target);
650 if (from) HeapFree(GetProcessHeap(),0,from);
651 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
652 strlen(allocstring):
653 strlen(lpBuffer);
654 #else
655 return 0;
656 #endif /* __i386__ */
658 #undef ADD_TO_T
660 /***********************************************************************
661 * FormatMessageA (KERNEL32.138)
662 * FIXME: missing wrap,FROM_SYSTEM message-loading,
664 DWORD WINAPI FormatMessageA(
665 DWORD dwFlags,
666 LPCVOID lpSource,
667 DWORD dwMessageId,
668 DWORD dwLanguageId,
669 LPSTR lpBuffer,
670 DWORD nSize,
671 LPDWORD args /* va_list *args */
673 #ifdef __i386__
674 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
675 LPSTR target,t;
676 DWORD talloced;
677 LPSTR from,f;
678 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
679 BOOL eos = FALSE;
681 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
682 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
683 if (width)
684 FIXME("line wrapping not supported.\n");
685 from = NULL;
686 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
687 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
688 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
689 from = HeapAlloc( GetProcessHeap(),0,200 );
690 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
692 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
693 INT bufsize;
695 dwMessageId &= 0xFFFF;
696 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
697 if (bufsize) {
698 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
699 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
702 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
703 t = target;
704 talloced= 100;
706 #define ADD_TO_T(c) \
707 *t++=c;\
708 if (t-target == talloced) {\
709 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
710 t = target+talloced;\
711 talloced*=2;\
714 if (from) {
715 f=from;
716 while (*f && !eos) {
717 if (*f=='%') {
718 int insertnr;
719 char *fmtstr,*sprintfbuf,*x,*lastf;
720 DWORD *argliststart;
722 fmtstr = NULL;
723 lastf = f;
724 f++;
725 if (!*f) {
726 ADD_TO_T('%');
727 continue;
729 switch (*f) {
730 case '1':case '2':case '3':case '4':case '5':
731 case '6':case '7':case '8':case '9':
732 insertnr=*f-'0';
733 switch (f[1]) {
734 case '0':case '1':case '2':case '3':
735 case '4':case '5':case '6':case '7':
736 case '8':case '9':
737 f++;
738 insertnr=insertnr*10+*f-'0';
739 f++;
740 break;
741 default:
742 f++;
743 break;
745 if (*f=='!') {
746 f++;
747 if (NULL!=(x=strchr(f,'!'))) {
748 *x='\0';
749 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
750 sprintf(fmtstr,"%%%s",f);
751 f=x+1;
752 } else {
753 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
754 sprintf(fmtstr,"%%%s",f);
755 f+=strlen(f); /*at \0*/
757 } else
758 if(!args)
759 break;
760 else
761 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
762 if (args) {
763 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
764 argliststart=args+insertnr-1;
765 else
766 argliststart=(*(DWORD**)args)+insertnr-1;
768 if (fmtstr[strlen(fmtstr)-1]=='s' && argliststart[0])
769 sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
770 else
771 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
773 /* CMF - This makes a BIG assumption about va_list */
774 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
775 x=sprintfbuf;
776 while (*x) {
777 ADD_TO_T(*x++);
779 HeapFree(GetProcessHeap(),0,sprintfbuf);
780 } else {
781 /* NULL args - copy formatstr
782 * (probably wrong)
784 while ((lastf<f)&&(*lastf)) {
785 ADD_TO_T(*lastf++);
788 HeapFree(GetProcessHeap(),0,fmtstr);
789 break;
790 case 'n':
791 ADD_TO_T('\r');
792 ADD_TO_T('\n');
793 f++;
794 break;
795 case '0':
796 eos = TRUE;
797 f++;
798 break;
799 default:
800 ADD_TO_T(*f++)
801 break;
803 } else { /* '\n' or '\r' gets mapped to "\r\n" */
804 if(*f == '\n' || *f == '\r') {
805 ADD_TO_T('\r');
806 ADD_TO_T('\n');
807 if(*f++ == '\r' && *f == '\n')
808 f++;
809 } else {
810 ADD_TO_T(*f++);
814 *t='\0';
816 talloced = strlen(target)+1;
817 if (nSize && talloced<nSize) {
818 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
820 TRACE("-- %s\n",debugstr_a(target));
821 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
822 /* nSize is the MINIMUM size */
823 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced);
824 memcpy(*(LPSTR*)lpBuffer,target,talloced);
825 } else
826 strncpy(lpBuffer,target,nSize);
827 HeapFree(GetProcessHeap(),0,target);
828 if (from) HeapFree(GetProcessHeap(),0,from);
829 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
830 strlen(*(LPSTR*)lpBuffer):
831 strlen(lpBuffer);
832 #else
833 return 0;
834 #endif /* __i386__ */
836 #undef ADD_TO_T
839 /***********************************************************************
840 * FormatMessageW (KERNEL32.138)
842 DWORD WINAPI FormatMessageW(
843 DWORD dwFlags,
844 LPCVOID lpSource,
845 DWORD dwMessageId,
846 DWORD dwLanguageId,
847 LPWSTR lpBuffer,
848 DWORD nSize,
849 LPDWORD args /* va_list *args */
851 #ifdef __i386__
852 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
853 LPSTR target,t;
854 DWORD talloced;
855 LPSTR from,f;
856 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
857 BOOL eos = FALSE;
859 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
860 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
861 if (width)
862 FIXME("line wrapping not supported.\n");
863 from = NULL;
864 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
865 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
866 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
867 /* gather information from system message tables ... */
868 from = HeapAlloc( GetProcessHeap(),0,200 );
869 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
871 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
872 INT bufsize;
874 dwMessageId &= 0xFFFF;
875 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
876 if (bufsize)
878 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
879 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
882 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
883 t = target;
884 talloced= 100;
886 #define ADD_TO_T(c) \
887 *t++=c;\
888 if (t-target == talloced) {\
889 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
890 t = target+talloced;\
891 talloced*=2;\
894 if (from) {
895 f=from;
896 while (*f && !eos) {
897 if (*f=='%') {
898 int insertnr;
899 char *fmtstr,*sprintfbuf,*x;
900 DWORD *argliststart;
902 fmtstr = NULL;
903 f++;
904 if (!*f) {
905 ADD_TO_T('%');
906 continue;
908 switch (*f) {
909 case '1':case '2':case '3':case '4':case '5':
910 case '6':case '7':case '8':case '9':
911 insertnr=*f-'0';
912 switch (f[1]) {
913 case '0':case '1':case '2':case '3':
914 case '4':case '5':case '6':case '7':
915 case '8':case '9':
916 f++;
917 insertnr=insertnr*10+*f-'0';
918 f++;
919 break;
920 default:
921 f++;
922 break;
924 if (*f=='!') {
925 f++;
926 if (NULL!=(x=strchr(f,'!')))
928 *x='\0';
929 fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
930 sprintf(fmtstr,"%%%s",f);
931 f=x+1;
932 } else {
933 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
934 sprintf(fmtstr,"%%%s",f);
935 f+=strlen(f); /*at \0*/
937 } else
938 if(!args)
939 break;
940 else
941 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
942 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
943 argliststart=args+insertnr-1;
944 else
945 argliststart=(*(DWORD**)args)+insertnr-1;
947 if (fmtstr[strlen(fmtstr)-1]=='s' && argliststart[0]) {
948 DWORD xarr[3];
950 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
951 /* possible invalid pointers */
952 xarr[1]=*(argliststart+1);
953 xarr[2]=*(argliststart+2);
954 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlenW((LPWSTR)argliststart[0])*2+1);
956 /* CMF - This makes a BIG assumption about va_list */
957 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
958 } else {
959 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
961 /* CMF - This makes a BIG assumption about va_list */
962 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
964 x=sprintfbuf;
965 while (*x) {
966 ADD_TO_T(*x++);
968 HeapFree(GetProcessHeap(),0,sprintfbuf);
969 HeapFree(GetProcessHeap(),0,fmtstr);
970 break;
971 case 'n':
972 ADD_TO_T('\r');
973 ADD_TO_T('\n');
974 f++;
975 break;
976 case '0':
977 eos = TRUE;
978 f++;
979 break;
980 default:
981 ADD_TO_T(*f++)
982 break;
984 } else { /* '\n' or '\r' gets mapped to "\r\n" */
985 if(*f == '\n' || *f == '\r') {
986 ADD_TO_T('\r');
987 ADD_TO_T('\n');
988 if(*f++ == '\r' && *f == '\n')
989 f++;
990 } else {
991 ADD_TO_T(*f++);
995 *t='\0';
997 talloced = strlen(target)+1;
998 if (nSize && talloced<nSize)
999 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
1000 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
1001 /* nSize is the MINIMUM size */
1002 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced*2+2);
1003 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
1004 } else
1005 lstrcpynAtoW(lpBuffer,target,nSize);
1006 HeapFree(GetProcessHeap(),0,target);
1007 if (from) HeapFree(GetProcessHeap(),0,from);
1008 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
1009 lstrlenW(*(LPWSTR*)lpBuffer):
1010 lstrlenW(lpBuffer);
1011 #else
1012 return 0;
1013 #endif /* __i386__ */
1015 #undef ADD_TO_T