Fixed other bugs within MMIO implementation. Now, it's possible to
[wine/multimedia.git] / misc / lstr.c
blobf3ecd7bc04a9fc154acabe659e12c61418188e25
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 <stdio.h>
13 #include <string.h>
14 #include <ctype.h>
16 #ifdef HAVE_WCTYPE_H
17 # include <wctype.h>
18 #else
19 # define iswalnum(c) isalnum(c)
20 # define iswalpha(c) isalpha(c)
21 # define iswupper(c) isupper(c)
22 # define iswlower(c) islower(c)
23 #endif /* HAVE_WCTYPE_H */
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "wine/winbase16.h"
30 #include "wine/winuser16.h"
31 #include "winnls.h"
32 #include "task.h"
33 #include "heap.h"
34 #include "ldt.h"
35 #include "stackframe.h"
36 #include "module.h"
37 #include "debugtools.h"
39 DEFAULT_DEBUG_CHANNEL(resource);
41 extern const WORD OLE2NLS_CT_CType3_LUT[]; /* FIXME: does not belong here */
44 /* Funny to divide them between user and kernel. */
46 /* be careful: always use functions from wctype.h if character > 255 */
49 * Unicode case conversion routines ... these should be used where
50 * toupper/tolower are used for ASCII.
52 #ifndef HAVE_WCTYPE_H
53 /* FIXME: should probably get rid of wctype.h altogether */
54 #include "casemap.h"
56 /***********************************************************************
57 * towupper
59 WCHAR towupper(WCHAR code)
61 const WCHAR * ptr = uprtable[HIBYTE(code)];
62 return ptr ? ptr[LOBYTE(code)] : code;
65 /***********************************************************************
66 * towlower
68 WCHAR towlower(WCHAR code)
70 const WCHAR * ptr = lwrtable[HIBYTE(code)];
71 return ptr ? ptr[LOBYTE(code)] : code;
73 #endif /* HAVE_WCTYPE_H */
75 /***********************************************************************
76 * IsCharAlpha (USER.433)
78 BOOL16 WINAPI IsCharAlpha16(CHAR ch)
80 return isalpha(ch); /* This is probably not right for NLS */
83 /***********************************************************************
84 * IsCharAlphaNumeric (USER.434)
86 BOOL16 WINAPI IsCharAlphaNumeric16(CHAR ch)
88 return isalnum(ch);
91 /***********************************************************************
92 * IsCharUpper (USER.435)
94 BOOL16 WINAPI IsCharUpper16(CHAR ch)
96 return isupper(ch);
99 /***********************************************************************
100 * IsCharLower (USER.436)
102 BOOL16 WINAPI IsCharLower16(CHAR ch)
104 return islower(ch);
107 /***********************************************************************
108 * AnsiUpper16 (USER.431)
110 SEGPTR WINAPI AnsiUpper16( SEGPTR strOrChar )
112 /* I am not sure if the locale stuff works with toupper, but then again
113 I am not sure if the Linux libc locale stuffs works at all */
115 /* uppercase only one char if strOrChar < 0x10000 */
116 if (HIWORD(strOrChar))
118 char *s;
119 for (s = PTR_SEG_TO_LIN(strOrChar); *s; s++) *s = toupper(*s);
120 return strOrChar;
122 else return toupper((char)strOrChar);
126 /***********************************************************************
127 * AnsiUpperBuff16 (USER.437)
129 UINT16 WINAPI AnsiUpperBuff16( LPSTR str, UINT16 len )
131 UINT count = len ? len : 65536;
132 for (; count; count--, str++) *str = toupper(*str);
133 return len;
136 /***********************************************************************
137 * AnsiLower16 (USER.432)
139 SEGPTR WINAPI AnsiLower16( SEGPTR strOrChar )
141 /* I am not sure if the locale stuff works with toupper, but then again
142 I am not sure if the Linux libc locale stuffs works at all */
144 /* lowercase only one char if strOrChar < 0x10000 */
145 if (HIWORD(strOrChar))
147 char *s;
148 for (s = PTR_SEG_TO_LIN( strOrChar ); *s; s++) *s = tolower( *s );
149 return strOrChar;
151 else return tolower((char)strOrChar);
155 /***********************************************************************
156 * AnsiLowerBuff16 (USER.438)
158 UINT16 WINAPI AnsiLowerBuff16( LPSTR str, UINT16 len )
160 UINT count = len ? len : 65536;
161 for (; count; count--, str++) *str = tolower(*str);
162 return len;
166 /***********************************************************************
167 * AnsiNext16 (USER.472)
169 SEGPTR WINAPI AnsiNext16(SEGPTR current)
171 return (*(char *)PTR_SEG_TO_LIN(current)) ? current + 1 : current;
175 /***********************************************************************
176 * AnsiPrev16 (USER.473)
178 SEGPTR WINAPI AnsiPrev16( SEGPTR start, SEGPTR current )
180 return (current == start) ? start : current - 1;
184 /***********************************************************************
185 * CharNextA (USER32.29)
187 LPSTR WINAPI CharNextA( LPCSTR ptr )
189 if (!*ptr) return (LPSTR)ptr;
190 if (IsDBCSLeadByte( *ptr ) && (*(ptr+1) != 0) ) return (LPSTR)(ptr + 2);
191 return (LPSTR)(ptr + 1);
195 /***********************************************************************
196 * CharNextExA (USER32.30)
198 LPSTR WINAPI CharNextExA( WORD codepage, LPCSTR ptr, DWORD flags )
200 if (!*ptr) return (LPSTR)ptr;
201 if (IsDBCSLeadByteEx( codepage, *ptr ) && (*(ptr+1) != 0) ) return (LPSTR)(ptr + 2);
202 return (LPSTR)(ptr + 1);
206 /***********************************************************************
207 * CharNextExW (USER32.31)
209 LPWSTR WINAPI CharNextExW(WORD codepage,LPCWSTR x,DWORD flags)
211 /* FIXME: add DBCS / codepage stuff */
212 if (*x) return (LPWSTR)(x+1);
213 else return (LPWSTR)x;
216 /***********************************************************************
217 * CharNextW (USER32.32)
219 LPWSTR WINAPI CharNextW(LPCWSTR x)
221 if (*x) return (LPWSTR)(x+1);
222 else return (LPWSTR)x;
225 /***********************************************************************
226 * CharPrevA (USER32.33)
228 LPSTR WINAPI CharPrevA( LPCSTR start, LPCSTR ptr )
230 while (*start && (start < ptr))
232 LPCSTR next = CharNextA( start );
233 if (next >= ptr) break;
234 start = next;
236 return (LPSTR)start;
240 /***********************************************************************
241 * CharPrevExA (USER32.34)
243 LPSTR WINAPI CharPrevExA( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
245 while (*start && (start < ptr))
247 LPCSTR next = CharNextExA( codepage, start, flags );
248 if (next > ptr) break;
249 start = next;
251 return (LPSTR)start;
255 /***********************************************************************
256 * CharPrevExW (USER32.35)
258 LPWSTR WINAPI CharPrevExW(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
260 /* FIXME: add DBCS / codepage stuff */
261 if (x>start) return (LPWSTR)(x-1);
262 else return (LPWSTR)x;
265 /***********************************************************************
266 * CharPrevW (USER32.36)
268 LPWSTR WINAPI CharPrevW(LPCWSTR start,LPCWSTR x)
270 if (x>start) return (LPWSTR)(x-1);
271 else return (LPWSTR)x;
274 /***********************************************************************
275 * CharLowerA (USER32.25)
276 * FIXME: handle current locale
278 LPSTR WINAPI CharLowerA(LPSTR x)
280 LPSTR s;
282 if (HIWORD(x))
284 s=x;
285 while (*s)
287 *s=tolower(*s);
288 s++;
290 return x;
292 else return (LPSTR)tolower((char)(int)x);
295 /***********************************************************************
296 * CharLowerBuffA (USER32.26)
297 * FIXME: handle current locale
299 DWORD WINAPI CharLowerBuffA(LPSTR x,DWORD buflen)
301 DWORD done=0;
303 if (!x) return 0; /* YES */
304 while (*x && (buflen--))
306 *x=tolower(*x);
307 x++;
308 done++;
310 return done;
313 /***********************************************************************
314 * CharLowerBuffW (USER32.27)
315 * FIXME: handle current locale
317 DWORD WINAPI CharLowerBuffW(LPWSTR x,DWORD buflen)
319 DWORD done=0;
321 if (!x) return 0; /* YES */
322 while (*x && (buflen--))
324 *x=towlower(*x);
325 x++;
326 done++;
328 return done;
331 /***********************************************************************
332 * CharLowerW (USER32.28)
333 * FIXME: handle current locale
335 LPWSTR WINAPI CharLowerW(LPWSTR x)
337 if (HIWORD(x))
339 LPWSTR s = x;
340 while (*s)
342 *s=towlower(*s);
343 s++;
345 return x;
347 else return (LPWSTR)((UINT)towlower(LOWORD(x)));
350 /***********************************************************************
351 * CharUpperA (USER32.41)
352 * FIXME: handle current locale
354 LPSTR WINAPI CharUpperA(LPSTR x)
356 if (HIWORD(x))
358 LPSTR s = x;
359 while (*s)
361 *s=toupper(*s);
362 s++;
364 return x;
366 return (LPSTR)toupper((char)(int)x);
369 /***********************************************************************
370 * CharUpperBuffA (USER32.42)
371 * FIXME: handle current locale
373 DWORD WINAPI CharUpperBuffA(LPSTR x,DWORD buflen)
375 DWORD done=0;
377 if (!x) return 0; /* YES */
378 while (*x && (buflen--))
380 *x=toupper(*x);
381 x++;
382 done++;
384 return done;
387 /***********************************************************************
388 * CharUpperBuffW (USER32.43)
389 * FIXME: handle current locale
391 DWORD WINAPI CharUpperBuffW(LPWSTR x,DWORD buflen)
393 DWORD done=0;
395 if (!x) return 0; /* YES */
396 while (*x && (buflen--))
398 *x=towupper(*x);
399 x++;
400 done++;
402 return done;
405 /***********************************************************************
406 * CharUpperW (USER32.44)
407 * FIXME: handle current locale
409 LPWSTR WINAPI CharUpperW(LPWSTR x)
411 if (HIWORD(x))
413 LPWSTR s = x;
414 while (*s)
416 *s=towupper(*s);
417 s++;
419 return x;
421 else return (LPWSTR)((UINT)towupper(LOWORD(x)));
424 /***********************************************************************
425 * IsCharAlphaA (USER32.331)
426 * FIXME: handle current locale
428 BOOL WINAPI IsCharAlphaA(CHAR x)
430 return (OLE2NLS_CT_CType3_LUT[(unsigned char)x] & C3_ALPHA);
433 /***********************************************************************
434 * IsCharAlphaNumericA (USER32.332)
435 * FIXME: handle current locale
437 BOOL WINAPI IsCharAlphaNumericA(CHAR x)
439 return IsCharAlphaA(x) || isdigit(x) ;
442 /***********************************************************************
443 * IsCharAlphaNumericW (USER32.333)
444 * FIXME: handle current locale
446 BOOL WINAPI IsCharAlphaNumericW(WCHAR x)
448 return iswalnum(x);
451 /***********************************************************************
452 * IsCharAlphaW (USER32.334)
453 * FIXME: handle current locale
455 BOOL WINAPI IsCharAlphaW(WCHAR x)
457 return iswalpha(x);
460 /***********************************************************************
461 * IsCharLowerA (USER32.335)
462 * FIXME: handle current locale
464 BOOL WINAPI IsCharLowerA(CHAR x)
466 return islower(x);
469 /***********************************************************************
470 * IsCharLowerW (USER32.336)
471 * FIXME: handle current locale
473 BOOL WINAPI IsCharLowerW(WCHAR x)
475 return iswlower(x);
478 /***********************************************************************
479 * IsCharUpperA (USER32.337)
480 * FIXME: handle current locale
482 BOOL WINAPI IsCharUpperA(CHAR x)
484 return isupper(x);
487 /***********************************************************************
488 * IsCharUpperW (USER32.338)
489 * FIXME: handle current locale
491 BOOL WINAPI IsCharUpperW(WCHAR x)
493 return iswupper(x);
496 /***********************************************************************
497 * FormatMessage16 (USER.606)
499 DWORD WINAPI FormatMessage16(
500 DWORD dwFlags,
501 SEGPTR lpSource, /*not always a valid pointer*/
502 WORD dwMessageId,
503 WORD dwLanguageId,
504 LPSTR lpBuffer, /* *((HLOCAL16*)) for FORMAT_MESSAGE_ALLOCATE_BUFFER*/
505 WORD nSize,
506 LPDWORD args /* va_list *args */
508 #ifdef __i386__
509 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
510 LPSTR target,t;
511 DWORD talloced;
512 LPSTR from,f;
513 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
514 BOOL eos = FALSE;
515 LPSTR allocstring = NULL;
517 TRACE("(0x%lx,%lx,%d,0x%x,%p,%d,%p)\n",
518 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
519 if (width)
520 FIXME("line wrapping not supported.\n");
521 from = NULL;
522 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
523 from = HEAP_strdupA( GetProcessHeap(), 0, PTR_SEG_TO_LIN(lpSource));
524 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
525 from = HeapAlloc( GetProcessHeap(),0,200 );
526 sprintf(from,"Systemmessage, messageid = 0x%08x\n",dwMessageId);
528 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
529 INT16 bufsize;
530 HINSTANCE16 hinst16 = ((HMODULE)lpSource & 0xffff);
532 dwMessageId &= 0xFFFF;
533 bufsize=LoadString16(hinst16,dwMessageId,NULL,0);
534 if (bufsize) {
535 from = HeapAlloc( GetProcessHeap(), 0, bufsize +1);
536 LoadString16(hinst16,dwMessageId,from,bufsize+1);
539 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
540 t = target;
541 talloced= 100;
543 #define ADD_TO_T(c) \
544 *t++=c;\
545 if (t-target == talloced) {\
546 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
547 t = target+talloced;\
548 talloced*=2;\
551 if (from) {
552 f=from;
553 while (*f && !eos) {
554 if (*f=='%') {
555 int insertnr;
556 char *fmtstr,*sprintfbuf,*x,*lastf;
557 DWORD *argliststart;
559 fmtstr = NULL;
560 lastf = f;
561 f++;
562 if (!*f) {
563 ADD_TO_T('%');
564 continue;
566 switch (*f) {
567 case '1':case '2':case '3':case '4':case '5':
568 case '6':case '7':case '8':case '9':
569 insertnr=*f-'0';
570 switch (f[1]) {
571 case '0':case '1':case '2':case '3':
572 case '4':case '5':case '6':case '7':
573 case '8':case '9':
574 f++;
575 insertnr=insertnr*10+*f-'0';
576 f++;
577 break;
578 default:
579 f++;
580 break;
582 if (*f=='!') {
583 f++;
584 if (NULL!=(x=strchr(f,'!'))) {
585 *x='\0';
586 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
587 sprintf(fmtstr,"%%%s",f);
588 f=x+1;
589 } else {
590 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
591 sprintf(fmtstr,"%%%s",f);
592 f+=strlen(f); /*at \0*/
594 } else
595 if(!args)
596 break;
597 else
598 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
599 if (args) {
600 argliststart=args+insertnr-1;
601 if (fmtstr[strlen(fmtstr)-1]=='s')
602 sprintfbuf=HeapAlloc(GetProcessHeap(),0,
603 strlen(PTR_SEG_TO_LIN(argliststart[0]))+1);
604 else
605 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
607 /* CMF - This makes a BIG assumption about va_list */
608 wvsprintf16(sprintfbuf, fmtstr, (va_list) argliststart);
609 x=sprintfbuf;
610 while (*x) {
611 ADD_TO_T(*x++);
613 HeapFree(GetProcessHeap(),0,sprintfbuf);
614 } else {
615 /* NULL args - copy formatstr
616 * (probably wrong)
618 while ((lastf<f)&&(*lastf)) {
619 ADD_TO_T(*lastf++);
622 HeapFree(GetProcessHeap(),0,fmtstr);
623 break;
624 case '0': /* Just stop processing format string */
625 eos = TRUE;
626 f++;
627 break;
628 case 'n': /* 16 bit version just outputs 'n' */
629 default:
630 ADD_TO_T(*f++);
631 break;
633 } else { /* '\n' or '\r' gets mapped to "\r\n" */
634 if(*f == '\n' || *f == '\r') {
635 ADD_TO_T('\r');
636 ADD_TO_T('\n');
637 if(*f++ == '\r' && *f == '\n')
638 f++;
639 } else {
640 ADD_TO_T(*f++);
644 *t='\0';
646 talloced = strlen(target)+1;
647 if (nSize && talloced<nSize) {
648 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
650 TRACE("-- %s\n",debugstr_a(target));
651 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
652 /* nSize is the MINIMUM size */
653 *((HLOCAL16*)lpBuffer)= LocalAlloc16(LPTR,talloced);
654 allocstring=PTR_SEG_OFF_TO_LIN(CURRENT_DS,*((HLOCAL16*)lpBuffer));
655 memcpy( allocstring,target,talloced);
656 } else
657 lstrcpynA(lpBuffer,target,nSize);
658 HeapFree(GetProcessHeap(),0,target);
659 if (from) HeapFree(GetProcessHeap(),0,from);
660 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
661 strlen(allocstring):
662 strlen(lpBuffer);
663 #else
664 return 0;
665 #endif /* __i386__ */
667 #undef ADD_TO_T
669 /***********************************************************************
670 * FormatMessageA (KERNEL32.138)
671 * FIXME: missing wrap,FROM_SYSTEM message-loading,
673 DWORD WINAPI FormatMessageA(
674 DWORD dwFlags,
675 LPCVOID lpSource,
676 DWORD dwMessageId,
677 DWORD dwLanguageId,
678 LPSTR lpBuffer,
679 DWORD nSize,
680 LPDWORD args /* va_list *args */
682 #ifdef __i386__
683 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
684 LPSTR target,t;
685 DWORD talloced;
686 LPSTR from,f;
687 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
688 BOOL eos = FALSE;
690 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
691 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
692 if (width)
693 FIXME("line wrapping not supported.\n");
694 from = NULL;
695 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
696 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
697 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
698 from = HeapAlloc( GetProcessHeap(),0,200 );
699 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
701 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
702 INT bufsize;
704 dwMessageId &= 0xFFFF;
705 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
706 if (bufsize) {
707 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
708 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
711 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
712 t = target;
713 talloced= 100;
715 #define ADD_TO_T(c) \
716 *t++=c;\
717 if (t-target == talloced) {\
718 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
719 t = target+talloced;\
720 talloced*=2;\
723 if (from) {
724 f=from;
725 while (*f && !eos) {
726 if (*f=='%') {
727 int insertnr;
728 char *fmtstr,*sprintfbuf,*x,*lastf;
729 DWORD *argliststart;
731 fmtstr = NULL;
732 lastf = f;
733 f++;
734 if (!*f) {
735 ADD_TO_T('%');
736 continue;
738 switch (*f) {
739 case '1':case '2':case '3':case '4':case '5':
740 case '6':case '7':case '8':case '9':
741 insertnr=*f-'0';
742 switch (f[1]) {
743 case '0':case '1':case '2':case '3':
744 case '4':case '5':case '6':case '7':
745 case '8':case '9':
746 f++;
747 insertnr=insertnr*10+*f-'0';
748 f++;
749 break;
750 default:
751 f++;
752 break;
754 if (*f=='!') {
755 f++;
756 if (NULL!=(x=strchr(f,'!'))) {
757 *x='\0';
758 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
759 sprintf(fmtstr,"%%%s",f);
760 f=x+1;
761 } else {
762 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
763 sprintf(fmtstr,"%%%s",f);
764 f+=strlen(f); /*at \0*/
766 } else
767 if(!args)
768 break;
769 else
770 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
771 if (args) {
772 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
773 argliststart=args+insertnr-1;
774 else
775 argliststart=(*(DWORD**)args)+insertnr-1;
777 if (fmtstr[strlen(fmtstr)-1]=='s' && argliststart[0])
778 sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
779 else
780 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
782 /* CMF - This makes a BIG assumption about va_list */
783 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
784 x=sprintfbuf;
785 while (*x) {
786 ADD_TO_T(*x++);
788 HeapFree(GetProcessHeap(),0,sprintfbuf);
789 } else {
790 /* NULL args - copy formatstr
791 * (probably wrong)
793 while ((lastf<f)&&(*lastf)) {
794 ADD_TO_T(*lastf++);
797 HeapFree(GetProcessHeap(),0,fmtstr);
798 break;
799 case 'n':
800 ADD_TO_T('\r');
801 ADD_TO_T('\n');
802 f++;
803 break;
804 case '0':
805 eos = TRUE;
806 f++;
807 break;
808 default:
809 ADD_TO_T(*f++)
810 break;
812 } else { /* '\n' or '\r' gets mapped to "\r\n" */
813 if(*f == '\n' || *f == '\r') {
814 ADD_TO_T('\r');
815 ADD_TO_T('\n');
816 if(*f++ == '\r' && *f == '\n')
817 f++;
818 } else {
819 ADD_TO_T(*f++);
823 *t='\0';
825 talloced = strlen(target)+1;
826 if (nSize && talloced<nSize) {
827 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
829 TRACE("-- %s\n",debugstr_a(target));
830 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
831 /* nSize is the MINIMUM size */
832 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced);
833 memcpy(*(LPSTR*)lpBuffer,target,talloced);
834 } else {
835 lstrcpynA(lpBuffer,target,nSize);
837 HeapFree(GetProcessHeap(),0,target);
838 if (from) HeapFree(GetProcessHeap(),0,from);
839 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
840 strlen(*(LPSTR*)lpBuffer):
841 strlen(lpBuffer);
842 #else
843 return 0;
844 #endif /* __i386__ */
846 #undef ADD_TO_T
849 /***********************************************************************
850 * FormatMessageW (KERNEL32.138)
852 DWORD WINAPI FormatMessageW(
853 DWORD dwFlags,
854 LPCVOID lpSource,
855 DWORD dwMessageId,
856 DWORD dwLanguageId,
857 LPWSTR lpBuffer,
858 DWORD nSize,
859 LPDWORD args /* va_list *args */
861 #ifdef __i386__
862 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
863 LPSTR target,t;
864 DWORD talloced;
865 LPSTR from,f;
866 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
867 BOOL eos = FALSE;
869 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
870 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
871 if (width)
872 FIXME("line wrapping not supported.\n");
873 from = NULL;
874 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
875 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
876 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
877 /* gather information from system message tables ... */
878 from = HeapAlloc( GetProcessHeap(),0,200 );
879 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
881 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
882 INT bufsize;
884 dwMessageId &= 0xFFFF;
885 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
886 if (bufsize)
888 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
889 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
892 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
893 t = target;
894 talloced= 100;
896 #define ADD_TO_T(c) \
897 *t++=c;\
898 if (t-target == talloced) {\
899 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
900 t = target+talloced;\
901 talloced*=2;\
904 if (from) {
905 f=from;
906 while (*f && !eos) {
907 if (*f=='%') {
908 int insertnr;
909 char *fmtstr,*sprintfbuf,*x;
910 DWORD *argliststart;
912 fmtstr = NULL;
913 f++;
914 if (!*f) {
915 ADD_TO_T('%');
916 continue;
918 switch (*f) {
919 case '1':case '2':case '3':case '4':case '5':
920 case '6':case '7':case '8':case '9':
921 insertnr=*f-'0';
922 switch (f[1]) {
923 case '0':case '1':case '2':case '3':
924 case '4':case '5':case '6':case '7':
925 case '8':case '9':
926 f++;
927 insertnr=insertnr*10+*f-'0';
928 f++;
929 break;
930 default:
931 f++;
932 break;
934 if (*f=='!') {
935 f++;
936 if (NULL!=(x=strchr(f,'!')))
938 *x='\0';
939 fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
940 sprintf(fmtstr,"%%%s",f);
941 f=x+1;
942 } else {
943 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
944 sprintf(fmtstr,"%%%s",f);
945 f+=strlen(f); /*at \0*/
947 } else
948 if(!args)
949 break;
950 else
951 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
952 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
953 argliststart=args+insertnr-1;
954 else
955 argliststart=(*(DWORD**)args)+insertnr-1;
957 if (fmtstr[strlen(fmtstr)-1]=='s' && argliststart[0]) {
958 DWORD xarr[3];
960 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
961 /* possible invalid pointers */
962 xarr[1]=*(argliststart+1);
963 xarr[2]=*(argliststart+2);
964 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlenW((LPWSTR)argliststart[0])*2+1);
966 /* CMF - This makes a BIG assumption about va_list */
967 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
968 } else {
969 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
971 /* CMF - This makes a BIG assumption about va_list */
972 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
974 x=sprintfbuf;
975 while (*x) {
976 ADD_TO_T(*x++);
978 HeapFree(GetProcessHeap(),0,sprintfbuf);
979 HeapFree(GetProcessHeap(),0,fmtstr);
980 break;
981 case 'n':
982 ADD_TO_T('\r');
983 ADD_TO_T('\n');
984 f++;
985 break;
986 case '0':
987 eos = TRUE;
988 f++;
989 break;
990 default:
991 ADD_TO_T(*f++)
992 break;
994 } else { /* '\n' or '\r' gets mapped to "\r\n" */
995 if(*f == '\n' || *f == '\r') {
996 ADD_TO_T('\r');
997 ADD_TO_T('\n');
998 if(*f++ == '\r' && *f == '\n')
999 f++;
1000 } else {
1001 ADD_TO_T(*f++);
1005 *t='\0';
1007 talloced = strlen(target)+1;
1008 if (nSize && talloced<nSize)
1009 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
1010 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
1011 /* nSize is the MINIMUM size */
1012 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced*2+2);
1013 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
1014 } else
1015 lstrcpynAtoW(lpBuffer,target,nSize);
1016 HeapFree(GetProcessHeap(),0,target);
1017 if (from) HeapFree(GetProcessHeap(),0,from);
1018 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
1019 lstrlenW(*(LPWSTR*)lpBuffer):
1020 lstrlenW(lpBuffer);
1021 #else
1022 return 0;
1023 #endif /* __i386__ */
1025 #undef ADD_TO_T