Allow the size of bitmaps to be changed after toolbar buttons have
[wine.git] / misc / lstr.c
blobd5141d33c53d6d4245100935c452d48418b9b05c
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 "wine/unicode.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)
287 DWORD WINAPI CharLowerBuffW(LPWSTR x,DWORD buflen)
289 DWORD done=0;
291 if (!x) return 0; /* YES */
292 while (*x && (buflen--))
294 *x=tolowerW(*x);
295 x++;
296 done++;
298 return done;
301 /***********************************************************************
302 * CharLowerW (USER32.28)
303 * FIXME: handle current locale
305 LPWSTR WINAPI CharLowerW(LPWSTR x)
307 if (HIWORD(x))
309 LPWSTR s = x;
310 while (*s)
312 *s = tolowerW(*s);
313 s++;
315 return x;
317 else return (LPWSTR)((UINT)tolowerW(LOWORD(x)));
320 /***********************************************************************
321 * CharUpperA (USER32.41)
322 * FIXME: handle current locale
324 LPSTR WINAPI CharUpperA(LPSTR x)
326 if (HIWORD(x))
328 LPSTR s = x;
329 while (*s)
331 *s=toupper(*s);
332 s++;
334 return x;
336 return (LPSTR)toupper((char)(int)x);
339 /***********************************************************************
340 * CharUpperBuffA (USER32.42)
341 * FIXME: handle current locale
343 DWORD WINAPI CharUpperBuffA(LPSTR x,DWORD buflen)
345 DWORD done=0;
347 if (!x) return 0; /* YES */
348 while (*x && (buflen--))
350 *x=toupper(*x);
351 x++;
352 done++;
354 return done;
357 /***********************************************************************
358 * CharUpperBuffW (USER32.43)
359 * FIXME: handle current locale
361 DWORD WINAPI CharUpperBuffW(LPWSTR x,DWORD buflen)
363 DWORD done=0;
365 if (!x) return 0; /* YES */
366 while (*x && (buflen--))
368 *x=toupperW(*x);
369 x++;
370 done++;
372 return done;
375 /***********************************************************************
376 * CharUpperW (USER32.44)
377 * FIXME: handle current locale
379 LPWSTR WINAPI CharUpperW(LPWSTR x)
381 if (HIWORD(x))
383 LPWSTR s = x;
384 while (*s)
386 *s = toupperW(*s);
387 s++;
389 return x;
391 else return (LPWSTR)((UINT)toupperW(LOWORD(x)));
394 /***********************************************************************
395 * IsCharAlphaA (USER32.331)
396 * FIXME: handle current locale
398 BOOL WINAPI IsCharAlphaA(CHAR x)
400 return (OLE2NLS_CT_CType3_LUT[(unsigned char)x] & C3_ALPHA);
403 /***********************************************************************
404 * IsCharAlphaNumericA (USER32.332)
405 * FIXME: handle current locale
407 BOOL WINAPI IsCharAlphaNumericA(CHAR x)
409 return IsCharAlphaA(x) || isdigit(x) ;
412 /***********************************************************************
413 * IsCharAlphaNumericW (USER32.333)
414 * FIXME: handle current locale
416 BOOL WINAPI IsCharAlphaNumericW(WCHAR x)
418 return iswalnum(x);
421 /***********************************************************************
422 * IsCharAlphaW (USER32.334)
423 * FIXME: handle current locale
425 BOOL WINAPI IsCharAlphaW(WCHAR x)
427 return iswalpha(x);
430 /***********************************************************************
431 * IsCharLowerA (USER32.335)
432 * FIXME: handle current locale
434 BOOL WINAPI IsCharLowerA(CHAR x)
436 return islower(x);
439 /***********************************************************************
440 * IsCharLowerW (USER32.336)
441 * FIXME: handle current locale
443 BOOL WINAPI IsCharLowerW(WCHAR x)
445 return iswlower(x);
448 /***********************************************************************
449 * IsCharUpperA (USER32.337)
450 * FIXME: handle current locale
452 BOOL WINAPI IsCharUpperA(CHAR x)
454 return isupper(x);
457 /***********************************************************************
458 * IsCharUpperW (USER32.338)
459 * FIXME: handle current locale
461 BOOL WINAPI IsCharUpperW(WCHAR x)
463 return iswupper(x);
466 /***********************************************************************
467 * FormatMessage16 (USER.606)
469 DWORD WINAPI FormatMessage16(
470 DWORD dwFlags,
471 SEGPTR lpSource, /*not always a valid pointer*/
472 WORD dwMessageId,
473 WORD dwLanguageId,
474 LPSTR lpBuffer, /* *((HLOCAL16*)) for FORMAT_MESSAGE_ALLOCATE_BUFFER*/
475 WORD nSize,
476 LPDWORD args /* va_list *args */
478 #ifdef __i386__
479 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
480 LPSTR target,t;
481 DWORD talloced;
482 LPSTR from,f;
483 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
484 BOOL eos = FALSE;
485 LPSTR allocstring = NULL;
487 TRACE("(0x%lx,%lx,%d,0x%x,%p,%d,%p)\n",
488 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
489 if (width)
490 FIXME("line wrapping not supported.\n");
491 from = NULL;
492 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
493 from = HEAP_strdupA( GetProcessHeap(), 0, PTR_SEG_TO_LIN(lpSource));
494 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
495 from = HeapAlloc( GetProcessHeap(),0,200 );
496 sprintf(from,"Systemmessage, messageid = 0x%08x\n",dwMessageId);
498 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
499 INT16 bufsize;
500 HINSTANCE16 hinst16 = ((HMODULE)lpSource & 0xffff);
502 dwMessageId &= 0xFFFF;
503 bufsize=LoadString16(hinst16,dwMessageId,NULL,0);
504 if (bufsize) {
505 from = HeapAlloc( GetProcessHeap(), 0, bufsize +1);
506 LoadString16(hinst16,dwMessageId,from,bufsize+1);
509 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
510 t = target;
511 talloced= 100;
513 #define ADD_TO_T(c) \
514 *t++=c;\
515 if (t-target == talloced) {\
516 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
517 t = target+talloced;\
518 talloced*=2;\
521 if (from) {
522 f=from;
523 while (*f && !eos) {
524 if (*f=='%') {
525 int insertnr;
526 char *fmtstr,*sprintfbuf,*x,*lastf;
527 DWORD *argliststart;
529 fmtstr = NULL;
530 lastf = f;
531 f++;
532 if (!*f) {
533 ADD_TO_T('%');
534 continue;
536 switch (*f) {
537 case '1':case '2':case '3':case '4':case '5':
538 case '6':case '7':case '8':case '9':
539 insertnr=*f-'0';
540 switch (f[1]) {
541 case '0':case '1':case '2':case '3':
542 case '4':case '5':case '6':case '7':
543 case '8':case '9':
544 f++;
545 insertnr=insertnr*10+*f-'0';
546 f++;
547 break;
548 default:
549 f++;
550 break;
552 if (*f=='!') {
553 f++;
554 if (NULL!=(x=strchr(f,'!'))) {
555 *x='\0';
556 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
557 sprintf(fmtstr,"%%%s",f);
558 f=x+1;
559 } else {
560 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
561 sprintf(fmtstr,"%%%s",f);
562 f+=strlen(f); /*at \0*/
564 } else
565 if(!args)
566 break;
567 else
568 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
569 if (args) {
570 argliststart=args+insertnr-1;
571 if (fmtstr[strlen(fmtstr)-1]=='s')
572 sprintfbuf=HeapAlloc(GetProcessHeap(),0,
573 strlen(PTR_SEG_TO_LIN(argliststart[0]))+1);
574 else
575 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
577 /* CMF - This makes a BIG assumption about va_list */
578 wvsprintf16(sprintfbuf, fmtstr, (va_list) argliststart);
579 x=sprintfbuf;
580 while (*x) {
581 ADD_TO_T(*x++);
583 HeapFree(GetProcessHeap(),0,sprintfbuf);
584 } else {
585 /* NULL args - copy formatstr
586 * (probably wrong)
588 while ((lastf<f)&&(*lastf)) {
589 ADD_TO_T(*lastf++);
592 HeapFree(GetProcessHeap(),0,fmtstr);
593 break;
594 case '0': /* Just stop processing format string */
595 eos = TRUE;
596 f++;
597 break;
598 case 'n': /* 16 bit version just outputs 'n' */
599 default:
600 ADD_TO_T(*f++);
601 break;
603 } else { /* '\n' or '\r' gets mapped to "\r\n" */
604 if(*f == '\n' || *f == '\r') {
605 ADD_TO_T('\r');
606 ADD_TO_T('\n');
607 if(*f++ == '\r' && *f == '\n')
608 f++;
609 } else {
610 ADD_TO_T(*f++);
614 *t='\0';
616 talloced = strlen(target)+1;
617 if (nSize && talloced<nSize) {
618 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
620 TRACE("-- %s\n",debugstr_a(target));
621 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
622 /* nSize is the MINIMUM size */
623 *((HLOCAL16*)lpBuffer)= LocalAlloc16(LPTR,talloced);
624 allocstring=PTR_SEG_OFF_TO_LIN(CURRENT_DS,*((HLOCAL16*)lpBuffer));
625 memcpy( allocstring,target,talloced);
626 } else
627 lstrcpynA(lpBuffer,target,nSize);
628 HeapFree(GetProcessHeap(),0,target);
629 if (from) HeapFree(GetProcessHeap(),0,from);
630 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
631 strlen(allocstring):
632 strlen(lpBuffer);
633 #else
634 return 0;
635 #endif /* __i386__ */
637 #undef ADD_TO_T
639 /***********************************************************************
640 * FormatMessageA (KERNEL32.138)
641 * FIXME: missing wrap,FROM_SYSTEM message-loading,
643 DWORD WINAPI FormatMessageA(
644 DWORD dwFlags,
645 LPCVOID lpSource,
646 DWORD dwMessageId,
647 DWORD dwLanguageId,
648 LPSTR lpBuffer,
649 DWORD nSize,
650 LPDWORD args /* va_list *args */
652 #ifdef __i386__
653 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
654 LPSTR target,t;
655 DWORD talloced;
656 LPSTR from,f;
657 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
658 BOOL eos = FALSE;
660 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
661 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
662 if (width)
663 FIXME("line wrapping not supported.\n");
664 from = NULL;
665 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
666 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
667 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
668 from = HeapAlloc( GetProcessHeap(),0,200 );
669 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
671 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
672 INT bufsize;
674 dwMessageId &= 0xFFFF;
675 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
676 if (bufsize) {
677 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
678 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
681 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
682 t = target;
683 talloced= 100;
685 #define ADD_TO_T(c) \
686 *t++=c;\
687 if (t-target == talloced) {\
688 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
689 t = target+talloced;\
690 talloced*=2;\
693 if (from) {
694 f=from;
695 while (*f && !eos) {
696 if (*f=='%') {
697 int insertnr;
698 char *fmtstr,*sprintfbuf,*x,*lastf;
699 DWORD *argliststart;
701 fmtstr = NULL;
702 lastf = f;
703 f++;
704 if (!*f) {
705 ADD_TO_T('%');
706 continue;
708 switch (*f) {
709 case '1':case '2':case '3':case '4':case '5':
710 case '6':case '7':case '8':case '9':
711 insertnr=*f-'0';
712 switch (f[1]) {
713 case '0':case '1':case '2':case '3':
714 case '4':case '5':case '6':case '7':
715 case '8':case '9':
716 f++;
717 insertnr=insertnr*10+*f-'0';
718 f++;
719 break;
720 default:
721 f++;
722 break;
724 if (*f=='!') {
725 f++;
726 if (NULL!=(x=strchr(f,'!'))) {
727 *x='\0';
728 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
729 sprintf(fmtstr,"%%%s",f);
730 f=x+1;
731 } else {
732 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
733 sprintf(fmtstr,"%%%s",f);
734 f+=strlen(f); /*at \0*/
736 } else
737 if(!args)
738 break;
739 else
740 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
741 if (args) {
742 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
743 argliststart=args+insertnr-1;
744 else
745 argliststart=(*(DWORD**)args)+insertnr-1;
747 if (fmtstr[strlen(fmtstr)-1]=='s' && argliststart[0])
748 sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
749 else
750 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
752 /* CMF - This makes a BIG assumption about va_list */
753 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
754 x=sprintfbuf;
755 while (*x) {
756 ADD_TO_T(*x++);
758 HeapFree(GetProcessHeap(),0,sprintfbuf);
759 } else {
760 /* NULL args - copy formatstr
761 * (probably wrong)
763 while ((lastf<f)&&(*lastf)) {
764 ADD_TO_T(*lastf++);
767 HeapFree(GetProcessHeap(),0,fmtstr);
768 break;
769 case 'n':
770 ADD_TO_T('\r');
771 ADD_TO_T('\n');
772 f++;
773 break;
774 case '0':
775 eos = TRUE;
776 f++;
777 break;
778 default:
779 ADD_TO_T(*f++)
780 break;
782 } else { /* '\n' or '\r' gets mapped to "\r\n" */
783 if(*f == '\n' || *f == '\r') {
784 ADD_TO_T('\r');
785 ADD_TO_T('\n');
786 if(*f++ == '\r' && *f == '\n')
787 f++;
788 } else {
789 ADD_TO_T(*f++);
793 *t='\0';
795 talloced = strlen(target)+1;
796 if (nSize && talloced<nSize) {
797 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
799 TRACE("-- %s\n",debugstr_a(target));
800 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
801 /* nSize is the MINIMUM size */
802 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced);
803 memcpy(*(LPSTR*)lpBuffer,target,talloced);
804 } else {
805 lstrcpynA(lpBuffer,target,nSize);
807 HeapFree(GetProcessHeap(),0,target);
808 if (from) HeapFree(GetProcessHeap(),0,from);
809 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
810 strlen(*(LPSTR*)lpBuffer):
811 strlen(lpBuffer);
812 #else
813 return 0;
814 #endif /* __i386__ */
816 #undef ADD_TO_T
819 /***********************************************************************
820 * FormatMessageW (KERNEL32.138)
822 DWORD WINAPI FormatMessageW(
823 DWORD dwFlags,
824 LPCVOID lpSource,
825 DWORD dwMessageId,
826 DWORD dwLanguageId,
827 LPWSTR lpBuffer,
828 DWORD nSize,
829 LPDWORD args /* va_list *args */
831 #ifdef __i386__
832 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
833 LPSTR target,t;
834 DWORD talloced;
835 LPSTR from,f;
836 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
837 BOOL eos = FALSE;
839 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
840 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
841 if (width)
842 FIXME("line wrapping not supported.\n");
843 from = NULL;
844 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
845 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
846 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
847 /* gather information from system message tables ... */
848 from = HeapAlloc( GetProcessHeap(),0,200 );
849 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
851 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
852 INT bufsize;
854 dwMessageId &= 0xFFFF;
855 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
856 if (bufsize)
858 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
859 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
862 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
863 t = target;
864 talloced= 100;
866 #define ADD_TO_T(c) \
867 *t++=c;\
868 if (t-target == talloced) {\
869 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
870 t = target+talloced;\
871 talloced*=2;\
874 if (from) {
875 f=from;
876 while (*f && !eos) {
877 if (*f=='%') {
878 int insertnr;
879 char *fmtstr,*sprintfbuf,*x;
880 DWORD *argliststart;
882 fmtstr = NULL;
883 f++;
884 if (!*f) {
885 ADD_TO_T('%');
886 continue;
888 switch (*f) {
889 case '1':case '2':case '3':case '4':case '5':
890 case '6':case '7':case '8':case '9':
891 insertnr=*f-'0';
892 switch (f[1]) {
893 case '0':case '1':case '2':case '3':
894 case '4':case '5':case '6':case '7':
895 case '8':case '9':
896 f++;
897 insertnr=insertnr*10+*f-'0';
898 f++;
899 break;
900 default:
901 f++;
902 break;
904 if (*f=='!') {
905 f++;
906 if (NULL!=(x=strchr(f,'!')))
908 *x='\0';
909 fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
910 sprintf(fmtstr,"%%%s",f);
911 f=x+1;
912 } else {
913 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
914 sprintf(fmtstr,"%%%s",f);
915 f+=strlen(f); /*at \0*/
917 } else
918 if(!args)
919 break;
920 else
921 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
922 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
923 argliststart=args+insertnr-1;
924 else
925 argliststart=(*(DWORD**)args)+insertnr-1;
927 if (fmtstr[strlen(fmtstr)-1]=='s' && argliststart[0]) {
928 DWORD xarr[3];
930 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
931 /* possible invalid pointers */
932 xarr[1]=*(argliststart+1);
933 xarr[2]=*(argliststart+2);
934 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlenW((LPWSTR)argliststart[0])*2+1);
936 /* CMF - This makes a BIG assumption about va_list */
937 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
938 } else {
939 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
941 /* CMF - This makes a BIG assumption about va_list */
942 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
944 x=sprintfbuf;
945 while (*x) {
946 ADD_TO_T(*x++);
948 HeapFree(GetProcessHeap(),0,sprintfbuf);
949 HeapFree(GetProcessHeap(),0,fmtstr);
950 break;
951 case 'n':
952 ADD_TO_T('\r');
953 ADD_TO_T('\n');
954 f++;
955 break;
956 case '0':
957 eos = TRUE;
958 f++;
959 break;
960 default:
961 ADD_TO_T(*f++)
962 break;
964 } else { /* '\n' or '\r' gets mapped to "\r\n" */
965 if(*f == '\n' || *f == '\r') {
966 ADD_TO_T('\r');
967 ADD_TO_T('\n');
968 if(*f++ == '\r' && *f == '\n')
969 f++;
970 } else {
971 ADD_TO_T(*f++);
975 *t='\0';
977 talloced = strlen(target)+1;
978 if (nSize && talloced<nSize)
979 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
980 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
981 /* nSize is the MINIMUM size */
982 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced*2+2);
983 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
984 } else
985 lstrcpynAtoW(lpBuffer,target,nSize);
986 HeapFree(GetProcessHeap(),0,target);
987 if (from) HeapFree(GetProcessHeap(),0,from);
988 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
989 lstrlenW(*(LPWSTR*)lpBuffer):
990 lstrlenW(lpBuffer);
991 #else
992 return 0;
993 #endif /* __i386__ */
995 #undef ADD_TO_T