Use the Unicode string functions from wine/unicode.h instead of the
[wine.git] / misc / lstr.c
blobd367ce0722476a8838ccd7fce4691baa4381f658
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 "ntddk.h"
30 #include "wine/winbase16.h"
31 #include "wine/winuser16.h"
32 #include "winnls.h"
33 #include "task.h"
34 #include "heap.h"
35 #include "ldt.h"
36 #include "stackframe.h"
37 #include "module.h"
38 #include "debugtools.h"
40 DEFAULT_DEBUG_CHANNEL(resource);
42 extern const WORD OLE2NLS_CT_CType3_LUT[]; /* FIXME: does not belong here */
44 /* Funny to divide them between user and kernel. */
46 /***********************************************************************
47 * IsCharAlpha (USER.433)
49 BOOL16 WINAPI IsCharAlpha16(CHAR ch)
51 return isalpha(ch); /* This is probably not right for NLS */
54 /***********************************************************************
55 * IsCharAlphaNumeric (USER.434)
57 BOOL16 WINAPI IsCharAlphaNumeric16(CHAR ch)
59 return isalnum(ch);
62 /***********************************************************************
63 * IsCharUpper (USER.435)
65 BOOL16 WINAPI IsCharUpper16(CHAR ch)
67 return isupper(ch);
70 /***********************************************************************
71 * IsCharLower (USER.436)
73 BOOL16 WINAPI IsCharLower16(CHAR ch)
75 return islower(ch);
78 /***********************************************************************
79 * AnsiUpper16 (USER.431)
81 SEGPTR WINAPI AnsiUpper16( SEGPTR strOrChar )
83 /* I am not sure if the locale stuff works with toupper, but then again
84 I am not sure if the Linux libc locale stuffs works at all */
86 /* uppercase only one char if strOrChar < 0x10000 */
87 if (HIWORD(strOrChar))
89 char *s;
90 for (s = PTR_SEG_TO_LIN(strOrChar); *s; s++) *s = toupper(*s);
91 return strOrChar;
93 else return toupper((char)strOrChar);
97 /***********************************************************************
98 * AnsiUpperBuff16 (USER.437)
100 UINT16 WINAPI AnsiUpperBuff16( LPSTR str, UINT16 len )
102 UINT count = len ? len : 65536;
103 for (; count; count--, str++) *str = toupper(*str);
104 return len;
107 /***********************************************************************
108 * AnsiLower16 (USER.432)
110 SEGPTR WINAPI AnsiLower16( 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 /* lowercase only one char if strOrChar < 0x10000 */
116 if (HIWORD(strOrChar))
118 char *s;
119 for (s = PTR_SEG_TO_LIN( strOrChar ); *s; s++) *s = tolower( *s );
120 return strOrChar;
122 else return tolower((char)strOrChar);
126 /***********************************************************************
127 * AnsiLowerBuff16 (USER.438)
129 UINT16 WINAPI AnsiLowerBuff16( LPSTR str, UINT16 len )
131 UINT count = len ? len : 65536;
132 for (; count; count--, str++) *str = tolower(*str);
133 return len;
137 /***********************************************************************
138 * AnsiNext16 (USER.472)
140 SEGPTR WINAPI AnsiNext16(SEGPTR current)
142 return (*(char *)PTR_SEG_TO_LIN(current)) ? current + 1 : current;
146 /***********************************************************************
147 * AnsiPrev16 (USER.473)
149 SEGPTR WINAPI AnsiPrev16( SEGPTR start, SEGPTR current )
151 return (current == start) ? start : current - 1;
155 /***********************************************************************
156 * CharNextA (USER32.29)
158 LPSTR WINAPI CharNextA( LPCSTR ptr )
160 if (!*ptr) return (LPSTR)ptr;
161 if (IsDBCSLeadByte( *ptr ) && (*(ptr+1) != 0) ) return (LPSTR)(ptr + 2);
162 return (LPSTR)(ptr + 1);
166 /***********************************************************************
167 * CharNextExA (USER32.30)
169 LPSTR WINAPI CharNextExA( WORD codepage, LPCSTR ptr, DWORD flags )
171 if (!*ptr) return (LPSTR)ptr;
172 if (IsDBCSLeadByteEx( codepage, *ptr ) && (*(ptr+1) != 0) ) return (LPSTR)(ptr + 2);
173 return (LPSTR)(ptr + 1);
177 /***********************************************************************
178 * CharNextExW (USER32.31)
180 LPWSTR WINAPI CharNextExW(WORD codepage,LPCWSTR x,DWORD flags)
182 /* FIXME: add DBCS / codepage stuff */
183 if (*x) return (LPWSTR)(x+1);
184 else return (LPWSTR)x;
187 /***********************************************************************
188 * CharNextW (USER32.32)
190 LPWSTR WINAPI CharNextW(LPCWSTR x)
192 if (*x) return (LPWSTR)(x+1);
193 else return (LPWSTR)x;
196 /***********************************************************************
197 * CharPrevA (USER32.33)
199 LPSTR WINAPI CharPrevA( LPCSTR start, LPCSTR ptr )
201 while (*start && (start < ptr))
203 LPCSTR next = CharNextA( start );
204 if (next >= ptr) break;
205 start = next;
207 return (LPSTR)start;
211 /***********************************************************************
212 * CharPrevExA (USER32.34)
214 LPSTR WINAPI CharPrevExA( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
216 while (*start && (start < ptr))
218 LPCSTR next = CharNextExA( codepage, start, flags );
219 if (next > ptr) break;
220 start = next;
222 return (LPSTR)start;
226 /***********************************************************************
227 * CharPrevExW (USER32.35)
229 LPWSTR WINAPI CharPrevExW(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
231 /* FIXME: add DBCS / codepage stuff */
232 if (x>start) return (LPWSTR)(x-1);
233 else return (LPWSTR)x;
236 /***********************************************************************
237 * CharPrevW (USER32.36)
239 LPWSTR WINAPI CharPrevW(LPCWSTR start,LPCWSTR x)
241 if (x>start) return (LPWSTR)(x-1);
242 else return (LPWSTR)x;
245 /***********************************************************************
246 * CharLowerA (USER32.25)
247 * FIXME: handle current locale
249 LPSTR WINAPI CharLowerA(LPSTR x)
251 LPSTR s;
253 if (HIWORD(x))
255 s=x;
256 while (*s)
258 *s=tolower(*s);
259 s++;
261 return x;
263 else return (LPSTR)tolower((char)(int)x);
266 /***********************************************************************
267 * CharLowerBuffA (USER32.26)
268 * FIXME: handle current locale
270 DWORD WINAPI CharLowerBuffA(LPSTR x,DWORD buflen)
272 DWORD done=0;
274 if (!x) return 0; /* YES */
275 while (*x && (buflen--))
277 *x=tolower(*x);
278 x++;
279 done++;
281 return done;
284 /***********************************************************************
285 * CharLowerBuffW (USER32.27)
286 * FIXME: handle current locale
288 DWORD WINAPI CharLowerBuffW(LPWSTR x,DWORD buflen)
290 DWORD done=0;
292 if (!x) return 0; /* YES */
293 while (*x && (buflen--))
295 *x=NTDLL_towlower(*x);
296 x++;
297 done++;
299 return done;
302 /***********************************************************************
303 * CharLowerW (USER32.28)
304 * FIXME: handle current locale
306 LPWSTR WINAPI CharLowerW(LPWSTR x)
308 if (HIWORD(x))
310 LPWSTR s = x;
311 while (*s)
313 *s=NTDLL_towlower(*s);
314 s++;
316 return x;
318 else return (LPWSTR)((UINT)NTDLL_towlower(LOWORD(x)));
321 /***********************************************************************
322 * CharUpperA (USER32.41)
323 * FIXME: handle current locale
325 LPSTR WINAPI CharUpperA(LPSTR x)
327 if (HIWORD(x))
329 LPSTR s = x;
330 while (*s)
332 *s=toupper(*s);
333 s++;
335 return x;
337 return (LPSTR)toupper((char)(int)x);
340 /***********************************************************************
341 * CharUpperBuffA (USER32.42)
342 * FIXME: handle current locale
344 DWORD WINAPI CharUpperBuffA(LPSTR x,DWORD buflen)
346 DWORD done=0;
348 if (!x) return 0; /* YES */
349 while (*x && (buflen--))
351 *x=toupper(*x);
352 x++;
353 done++;
355 return done;
358 /***********************************************************************
359 * CharUpperBuffW (USER32.43)
360 * FIXME: handle current locale
362 DWORD WINAPI CharUpperBuffW(LPWSTR x,DWORD buflen)
364 DWORD done=0;
366 if (!x) return 0; /* YES */
367 while (*x && (buflen--))
369 *x=NTDLL_towupper(*x);
370 x++;
371 done++;
373 return done;
376 /***********************************************************************
377 * CharUpperW (USER32.44)
378 * FIXME: handle current locale
380 LPWSTR WINAPI CharUpperW(LPWSTR x)
382 if (HIWORD(x))
384 LPWSTR s = x;
385 while (*s)
387 *s=NTDLL_towupper(*s);
388 s++;
390 return x;
392 else return (LPWSTR)((UINT)NTDLL_towupper(LOWORD(x)));
395 /***********************************************************************
396 * IsCharAlphaA (USER32.331)
397 * FIXME: handle current locale
399 BOOL WINAPI IsCharAlphaA(CHAR x)
401 return (OLE2NLS_CT_CType3_LUT[(unsigned char)x] & C3_ALPHA);
404 /***********************************************************************
405 * IsCharAlphaNumericA (USER32.332)
406 * FIXME: handle current locale
408 BOOL WINAPI IsCharAlphaNumericA(CHAR x)
410 return IsCharAlphaA(x) || isdigit(x) ;
413 /***********************************************************************
414 * IsCharAlphaNumericW (USER32.333)
415 * FIXME: handle current locale
417 BOOL WINAPI IsCharAlphaNumericW(WCHAR x)
419 return iswalnum(x);
422 /***********************************************************************
423 * IsCharAlphaW (USER32.334)
424 * FIXME: handle current locale
426 BOOL WINAPI IsCharAlphaW(WCHAR x)
428 return iswalpha(x);
431 /***********************************************************************
432 * IsCharLowerA (USER32.335)
433 * FIXME: handle current locale
435 BOOL WINAPI IsCharLowerA(CHAR x)
437 return islower(x);
440 /***********************************************************************
441 * IsCharLowerW (USER32.336)
442 * FIXME: handle current locale
444 BOOL WINAPI IsCharLowerW(WCHAR x)
446 return iswlower(x);
449 /***********************************************************************
450 * IsCharUpperA (USER32.337)
451 * FIXME: handle current locale
453 BOOL WINAPI IsCharUpperA(CHAR x)
455 return isupper(x);
458 /***********************************************************************
459 * IsCharUpperW (USER32.338)
460 * FIXME: handle current locale
462 BOOL WINAPI IsCharUpperW(WCHAR x)
464 return iswupper(x);
467 /***********************************************************************
468 * FormatMessage16 (USER.606)
470 DWORD WINAPI FormatMessage16(
471 DWORD dwFlags,
472 SEGPTR lpSource, /*not always a valid pointer*/
473 WORD dwMessageId,
474 WORD dwLanguageId,
475 LPSTR lpBuffer, /* *((HLOCAL16*)) for FORMAT_MESSAGE_ALLOCATE_BUFFER*/
476 WORD nSize,
477 LPDWORD args /* va_list *args */
479 #ifdef __i386__
480 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
481 LPSTR target,t;
482 DWORD talloced;
483 LPSTR from,f;
484 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
485 BOOL eos = FALSE;
486 LPSTR allocstring = NULL;
488 TRACE("(0x%lx,%lx,%d,0x%x,%p,%d,%p)\n",
489 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
490 if (width)
491 FIXME("line wrapping not supported.\n");
492 from = NULL;
493 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
494 from = HEAP_strdupA( GetProcessHeap(), 0, PTR_SEG_TO_LIN(lpSource));
495 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
496 from = HeapAlloc( GetProcessHeap(),0,200 );
497 sprintf(from,"Systemmessage, messageid = 0x%08x\n",dwMessageId);
499 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
500 INT16 bufsize;
501 HINSTANCE16 hinst16 = ((HMODULE)lpSource & 0xffff);
503 dwMessageId &= 0xFFFF;
504 bufsize=LoadString16(hinst16,dwMessageId,NULL,0);
505 if (bufsize) {
506 from = HeapAlloc( GetProcessHeap(), 0, bufsize +1);
507 LoadString16(hinst16,dwMessageId,from,bufsize+1);
510 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
511 t = target;
512 talloced= 100;
514 #define ADD_TO_T(c) \
515 *t++=c;\
516 if (t-target == talloced) {\
517 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
518 t = target+talloced;\
519 talloced*=2;\
522 if (from) {
523 f=from;
524 while (*f && !eos) {
525 if (*f=='%') {
526 int insertnr;
527 char *fmtstr,*sprintfbuf,*x,*lastf;
528 DWORD *argliststart;
530 fmtstr = NULL;
531 lastf = f;
532 f++;
533 if (!*f) {
534 ADD_TO_T('%');
535 continue;
537 switch (*f) {
538 case '1':case '2':case '3':case '4':case '5':
539 case '6':case '7':case '8':case '9':
540 insertnr=*f-'0';
541 switch (f[1]) {
542 case '0':case '1':case '2':case '3':
543 case '4':case '5':case '6':case '7':
544 case '8':case '9':
545 f++;
546 insertnr=insertnr*10+*f-'0';
547 f++;
548 break;
549 default:
550 f++;
551 break;
553 if (*f=='!') {
554 f++;
555 if (NULL!=(x=strchr(f,'!'))) {
556 *x='\0';
557 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
558 sprintf(fmtstr,"%%%s",f);
559 f=x+1;
560 } else {
561 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
562 sprintf(fmtstr,"%%%s",f);
563 f+=strlen(f); /*at \0*/
565 } else
566 if(!args)
567 break;
568 else
569 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
570 if (args) {
571 argliststart=args+insertnr-1;
572 if (fmtstr[strlen(fmtstr)-1]=='s')
573 sprintfbuf=HeapAlloc(GetProcessHeap(),0,
574 strlen(PTR_SEG_TO_LIN(argliststart[0]))+1);
575 else
576 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
578 /* CMF - This makes a BIG assumption about va_list */
579 wvsprintf16(sprintfbuf, fmtstr, (va_list) argliststart);
580 x=sprintfbuf;
581 while (*x) {
582 ADD_TO_T(*x++);
584 HeapFree(GetProcessHeap(),0,sprintfbuf);
585 } else {
586 /* NULL args - copy formatstr
587 * (probably wrong)
589 while ((lastf<f)&&(*lastf)) {
590 ADD_TO_T(*lastf++);
593 HeapFree(GetProcessHeap(),0,fmtstr);
594 break;
595 case '0': /* Just stop processing format string */
596 eos = TRUE;
597 f++;
598 break;
599 case 'n': /* 16 bit version just outputs 'n' */
600 default:
601 ADD_TO_T(*f++);
602 break;
604 } else { /* '\n' or '\r' gets mapped to "\r\n" */
605 if(*f == '\n' || *f == '\r') {
606 ADD_TO_T('\r');
607 ADD_TO_T('\n');
608 if(*f++ == '\r' && *f == '\n')
609 f++;
610 } else {
611 ADD_TO_T(*f++);
615 *t='\0';
617 talloced = strlen(target)+1;
618 if (nSize && talloced<nSize) {
619 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
621 TRACE("-- %s\n",debugstr_a(target));
622 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
623 /* nSize is the MINIMUM size */
624 *((HLOCAL16*)lpBuffer)= LocalAlloc16(LPTR,talloced);
625 allocstring=PTR_SEG_OFF_TO_LIN(CURRENT_DS,*((HLOCAL16*)lpBuffer));
626 memcpy( allocstring,target,talloced);
627 } else
628 lstrcpynA(lpBuffer,target,nSize);
629 HeapFree(GetProcessHeap(),0,target);
630 if (from) HeapFree(GetProcessHeap(),0,from);
631 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
632 strlen(allocstring):
633 strlen(lpBuffer);
634 #else
635 return 0;
636 #endif /* __i386__ */
638 #undef ADD_TO_T
640 /***********************************************************************
641 * FormatMessageA (KERNEL32.138)
642 * FIXME: missing wrap,FROM_SYSTEM message-loading,
644 DWORD WINAPI FormatMessageA(
645 DWORD dwFlags,
646 LPCVOID lpSource,
647 DWORD dwMessageId,
648 DWORD dwLanguageId,
649 LPSTR lpBuffer,
650 DWORD nSize,
651 LPDWORD args /* va_list *args */
653 #ifdef __i386__
654 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
655 LPSTR target,t;
656 DWORD talloced;
657 LPSTR from,f;
658 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
659 BOOL eos = FALSE;
661 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
662 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
663 if (width)
664 FIXME("line wrapping not supported.\n");
665 from = NULL;
666 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
667 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
668 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
669 from = HeapAlloc( GetProcessHeap(),0,200 );
670 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
672 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
673 INT bufsize;
675 dwMessageId &= 0xFFFF;
676 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
677 if (bufsize) {
678 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
679 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
682 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
683 t = target;
684 talloced= 100;
686 #define ADD_TO_T(c) \
687 *t++=c;\
688 if (t-target == talloced) {\
689 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
690 t = target+talloced;\
691 talloced*=2;\
694 if (from) {
695 f=from;
696 while (*f && !eos) {
697 if (*f=='%') {
698 int insertnr;
699 char *fmtstr,*sprintfbuf,*x,*lastf;
700 DWORD *argliststart;
702 fmtstr = NULL;
703 lastf = f;
704 f++;
705 if (!*f) {
706 ADD_TO_T('%');
707 continue;
709 switch (*f) {
710 case '1':case '2':case '3':case '4':case '5':
711 case '6':case '7':case '8':case '9':
712 insertnr=*f-'0';
713 switch (f[1]) {
714 case '0':case '1':case '2':case '3':
715 case '4':case '5':case '6':case '7':
716 case '8':case '9':
717 f++;
718 insertnr=insertnr*10+*f-'0';
719 f++;
720 break;
721 default:
722 f++;
723 break;
725 if (*f=='!') {
726 f++;
727 if (NULL!=(x=strchr(f,'!'))) {
728 *x='\0';
729 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
730 sprintf(fmtstr,"%%%s",f);
731 f=x+1;
732 } else {
733 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
734 sprintf(fmtstr,"%%%s",f);
735 f+=strlen(f); /*at \0*/
737 } else
738 if(!args)
739 break;
740 else
741 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
742 if (args) {
743 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
744 argliststart=args+insertnr-1;
745 else
746 argliststart=(*(DWORD**)args)+insertnr-1;
748 if (fmtstr[strlen(fmtstr)-1]=='s' && argliststart[0])
749 sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
750 else
751 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
753 /* CMF - This makes a BIG assumption about va_list */
754 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
755 x=sprintfbuf;
756 while (*x) {
757 ADD_TO_T(*x++);
759 HeapFree(GetProcessHeap(),0,sprintfbuf);
760 } else {
761 /* NULL args - copy formatstr
762 * (probably wrong)
764 while ((lastf<f)&&(*lastf)) {
765 ADD_TO_T(*lastf++);
768 HeapFree(GetProcessHeap(),0,fmtstr);
769 break;
770 case 'n':
771 ADD_TO_T('\r');
772 ADD_TO_T('\n');
773 f++;
774 break;
775 case '0':
776 eos = TRUE;
777 f++;
778 break;
779 default:
780 ADD_TO_T(*f++)
781 break;
783 } else { /* '\n' or '\r' gets mapped to "\r\n" */
784 if(*f == '\n' || *f == '\r') {
785 ADD_TO_T('\r');
786 ADD_TO_T('\n');
787 if(*f++ == '\r' && *f == '\n')
788 f++;
789 } else {
790 ADD_TO_T(*f++);
794 *t='\0';
796 talloced = strlen(target)+1;
797 if (nSize && talloced<nSize) {
798 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
800 TRACE("-- %s\n",debugstr_a(target));
801 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
802 /* nSize is the MINIMUM size */
803 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced);
804 memcpy(*(LPSTR*)lpBuffer,target,talloced);
805 } else {
806 lstrcpynA(lpBuffer,target,nSize);
808 HeapFree(GetProcessHeap(),0,target);
809 if (from) HeapFree(GetProcessHeap(),0,from);
810 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
811 strlen(*(LPSTR*)lpBuffer):
812 strlen(lpBuffer);
813 #else
814 return 0;
815 #endif /* __i386__ */
817 #undef ADD_TO_T
820 /***********************************************************************
821 * FormatMessageW (KERNEL32.138)
823 DWORD WINAPI FormatMessageW(
824 DWORD dwFlags,
825 LPCVOID lpSource,
826 DWORD dwMessageId,
827 DWORD dwLanguageId,
828 LPWSTR lpBuffer,
829 DWORD nSize,
830 LPDWORD args /* va_list *args */
832 #ifdef __i386__
833 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
834 LPSTR target,t;
835 DWORD talloced;
836 LPSTR from,f;
837 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
838 BOOL eos = FALSE;
840 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
841 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
842 if (width)
843 FIXME("line wrapping not supported.\n");
844 from = NULL;
845 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
846 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
847 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
848 /* gather information from system message tables ... */
849 from = HeapAlloc( GetProcessHeap(),0,200 );
850 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
852 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
853 INT bufsize;
855 dwMessageId &= 0xFFFF;
856 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
857 if (bufsize)
859 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
860 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
863 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
864 t = target;
865 talloced= 100;
867 #define ADD_TO_T(c) \
868 *t++=c;\
869 if (t-target == talloced) {\
870 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
871 t = target+talloced;\
872 talloced*=2;\
875 if (from) {
876 f=from;
877 while (*f && !eos) {
878 if (*f=='%') {
879 int insertnr;
880 char *fmtstr,*sprintfbuf,*x;
881 DWORD *argliststart;
883 fmtstr = NULL;
884 f++;
885 if (!*f) {
886 ADD_TO_T('%');
887 continue;
889 switch (*f) {
890 case '1':case '2':case '3':case '4':case '5':
891 case '6':case '7':case '8':case '9':
892 insertnr=*f-'0';
893 switch (f[1]) {
894 case '0':case '1':case '2':case '3':
895 case '4':case '5':case '6':case '7':
896 case '8':case '9':
897 f++;
898 insertnr=insertnr*10+*f-'0';
899 f++;
900 break;
901 default:
902 f++;
903 break;
905 if (*f=='!') {
906 f++;
907 if (NULL!=(x=strchr(f,'!')))
909 *x='\0';
910 fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
911 sprintf(fmtstr,"%%%s",f);
912 f=x+1;
913 } else {
914 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
915 sprintf(fmtstr,"%%%s",f);
916 f+=strlen(f); /*at \0*/
918 } else
919 if(!args)
920 break;
921 else
922 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
923 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
924 argliststart=args+insertnr-1;
925 else
926 argliststart=(*(DWORD**)args)+insertnr-1;
928 if (fmtstr[strlen(fmtstr)-1]=='s' && argliststart[0]) {
929 DWORD xarr[3];
931 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
932 /* possible invalid pointers */
933 xarr[1]=*(argliststart+1);
934 xarr[2]=*(argliststart+2);
935 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlenW((LPWSTR)argliststart[0])*2+1);
937 /* CMF - This makes a BIG assumption about va_list */
938 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
939 } else {
940 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
942 /* CMF - This makes a BIG assumption about va_list */
943 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
945 x=sprintfbuf;
946 while (*x) {
947 ADD_TO_T(*x++);
949 HeapFree(GetProcessHeap(),0,sprintfbuf);
950 HeapFree(GetProcessHeap(),0,fmtstr);
951 break;
952 case 'n':
953 ADD_TO_T('\r');
954 ADD_TO_T('\n');
955 f++;
956 break;
957 case '0':
958 eos = TRUE;
959 f++;
960 break;
961 default:
962 ADD_TO_T(*f++)
963 break;
965 } else { /* '\n' or '\r' gets mapped to "\r\n" */
966 if(*f == '\n' || *f == '\r') {
967 ADD_TO_T('\r');
968 ADD_TO_T('\n');
969 if(*f++ == '\r' && *f == '\n')
970 f++;
971 } else {
972 ADD_TO_T(*f++);
976 *t='\0';
978 talloced = strlen(target)+1;
979 if (nSize && talloced<nSize)
980 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
981 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
982 /* nSize is the MINIMUM size */
983 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced*2+2);
984 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
985 } else
986 lstrcpynAtoW(lpBuffer,target,nSize);
987 HeapFree(GetProcessHeap(),0,target);
988 if (from) HeapFree(GetProcessHeap(),0,from);
989 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
990 lstrlenW(*(LPWSTR*)lpBuffer):
991 lstrlenW(lpBuffer);
992 #else
993 return 0;
994 #endif /* __i386__ */
996 #undef ADD_TO_T