Got rid of PROFILE_ functions, now accessing Wine config options
[wine.git] / misc / lstr.c
blob389b1f1dee110d5b9158e4661443cc09ce08a4e2
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 WCHAR towupper(WCHAR code)
58 const WCHAR * ptr = uprtable[HIBYTE(code)];
59 return ptr ? ptr[LOBYTE(code)] : code;
62 WCHAR towlower(WCHAR code)
64 const WCHAR * ptr = lwrtable[HIBYTE(code)];
65 return ptr ? ptr[LOBYTE(code)] : code;
67 #endif /* HAVE_WCTYPE_H */
69 /***********************************************************************
70 * IsCharAlpha (USER.433)
72 BOOL16 WINAPI IsCharAlpha16(CHAR ch)
74 return isalpha(ch); /* This is probably not right for NLS */
77 /***********************************************************************
78 * IsCharAlphanumeric (USER.434)
80 BOOL16 WINAPI IsCharAlphaNumeric16(CHAR ch)
82 return isalnum(ch);
85 /***********************************************************************
86 * IsCharUpper (USER.435)
88 BOOL16 WINAPI IsCharUpper16(CHAR ch)
90 return isupper(ch);
93 /***********************************************************************
94 * IsCharLower (USER.436)
96 BOOL16 WINAPI IsCharLower16(CHAR ch)
98 return islower(ch);
101 /***********************************************************************
102 * AnsiUpper16 (USER.431)
104 SEGPTR WINAPI AnsiUpper16( SEGPTR strOrChar )
106 /* I am not sure if the locale stuff works with toupper, but then again
107 I am not sure if the Linux libc locale stuffs works at all */
109 /* uppercase only one char if strOrChar < 0x10000 */
110 if (HIWORD(strOrChar))
112 char *s;
113 for (s = PTR_SEG_TO_LIN(strOrChar); *s; s++) *s = toupper(*s);
114 return strOrChar;
116 else return toupper((char)strOrChar);
120 /***********************************************************************
121 * AnsiUpperBuff16 (USER.437)
123 UINT16 WINAPI AnsiUpperBuff16( LPSTR str, UINT16 len )
125 UINT count = len ? len : 65536;
126 for (; count; count--, str++) *str = toupper(*str);
127 return len;
130 /***********************************************************************
131 * AnsiLower16 (USER.432)
133 SEGPTR WINAPI AnsiLower16( SEGPTR strOrChar )
135 /* I am not sure if the locale stuff works with toupper, but then again
136 I am not sure if the Linux libc locale stuffs works at all */
138 /* lowercase only one char if strOrChar < 0x10000 */
139 if (HIWORD(strOrChar))
141 char *s;
142 for (s = PTR_SEG_TO_LIN( strOrChar ); *s; s++) *s = tolower( *s );
143 return strOrChar;
145 else return tolower((char)strOrChar);
149 /***********************************************************************
150 * AnsiLowerBuff16 (USER.438)
152 UINT16 WINAPI AnsiLowerBuff16( LPSTR str, UINT16 len )
154 UINT count = len ? len : 65536;
155 for (; count; count--, str++) *str = tolower(*str);
156 return len;
160 /***********************************************************************
161 * AnsiNext16 (USER.472)
163 SEGPTR WINAPI AnsiNext16(SEGPTR current)
165 return (*(char *)PTR_SEG_TO_LIN(current)) ? current + 1 : current;
169 /***********************************************************************
170 * AnsiPrev16 (USER.473)
172 SEGPTR WINAPI AnsiPrev16( SEGPTR start, SEGPTR current )
174 return (current == start) ? start : current - 1;
178 /***********************************************************************
179 * CharNext32A (USER32.29)
181 LPSTR WINAPI CharNextA( LPCSTR ptr )
183 if (!*ptr) return (LPSTR)ptr;
184 if (IsDBCSLeadByte( *ptr )) return (LPSTR)(ptr + 2);
185 return (LPSTR)(ptr + 1);
189 /***********************************************************************
190 * CharNextEx32A (USER32.30)
192 LPSTR WINAPI CharNextExA( WORD codepage, LPCSTR ptr, DWORD flags )
194 if (!*ptr) return (LPSTR)ptr;
195 if (IsDBCSLeadByteEx( codepage, *ptr )) return (LPSTR)(ptr + 2);
196 return (LPSTR)(ptr + 1);
200 /***********************************************************************
201 * CharNextExW (USER32.31)
203 LPWSTR WINAPI CharNextExW(WORD codepage,LPCWSTR x,DWORD flags)
205 /* FIXME: add DBCS / codepage stuff */
206 if (*x) return (LPWSTR)(x+1);
207 else return (LPWSTR)x;
210 /***********************************************************************
211 * CharNextW (USER32.32)
213 LPWSTR WINAPI CharNextW(LPCWSTR x)
215 if (*x) return (LPWSTR)(x+1);
216 else return (LPWSTR)x;
219 /***********************************************************************
220 * CharPrev32A (USER32.33)
222 LPSTR WINAPI CharPrevA( LPCSTR start, LPCSTR ptr )
224 while (*start && (start < ptr))
226 LPCSTR next = CharNextA( start );
227 if (next >= ptr) break;
228 start = next;
230 return (LPSTR)start;
234 /***********************************************************************
235 * CharPrevEx32A (USER32.34)
237 LPSTR WINAPI CharPrevExA( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
239 while (*start && (start < ptr))
241 LPCSTR next = CharNextExA( codepage, start, flags );
242 if (next > ptr) break;
243 start = next;
245 return (LPSTR)start;
249 /***********************************************************************
250 * CharPrevExW (USER32.35)
252 LPWSTR WINAPI CharPrevExW(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
254 /* FIXME: add DBCS / codepage stuff */
255 if (x>start) return (LPWSTR)(x-1);
256 else return (LPWSTR)x;
259 /***********************************************************************
260 * CharPrevW (USER32.36)
262 LPWSTR WINAPI CharPrevW(LPCWSTR start,LPCWSTR x)
264 if (x>start) return (LPWSTR)(x-1);
265 else return (LPWSTR)x;
268 /***********************************************************************
269 * CharLowerA (USER32.25)
270 * FIXME: handle current locale
272 LPSTR WINAPI CharLowerA(LPSTR x)
274 LPSTR s;
276 if (HIWORD(x))
278 s=x;
279 while (*s)
281 *s=tolower(*s);
282 s++;
284 return x;
286 else return (LPSTR)tolower((char)(int)x);
289 /***********************************************************************
290 * CharLowerBuffA (USER32.26)
291 * FIXME: handle current locale
293 DWORD WINAPI CharLowerBuffA(LPSTR x,DWORD buflen)
295 DWORD done=0;
297 if (!x) return 0; /* YES */
298 while (*x && (buflen--))
300 *x=tolower(*x);
301 x++;
302 done++;
304 return done;
307 /***********************************************************************
308 * CharLowerBuffW (USER32.27)
309 * FIXME: handle current locale
311 DWORD WINAPI CharLowerBuffW(LPWSTR x,DWORD buflen)
313 DWORD done=0;
315 if (!x) return 0; /* YES */
316 while (*x && (buflen--))
318 *x=towlower(*x);
319 x++;
320 done++;
322 return done;
325 /***********************************************************************
326 * CharLowerW (USER32.28)
327 * FIXME: handle current locale
329 LPWSTR WINAPI CharLowerW(LPWSTR x)
331 if (HIWORD(x))
333 LPWSTR s = x;
334 while (*s)
336 *s=towlower(*s);
337 s++;
339 return x;
341 else return (LPWSTR)((UINT)towlower(LOWORD(x)));
344 /***********************************************************************
345 * CharUpper32A (USER32.41)
346 * FIXME: handle current locale
348 LPSTR WINAPI CharUpperA(LPSTR x)
350 if (HIWORD(x))
352 LPSTR s = x;
353 while (*s)
355 *s=toupper(*s);
356 s++;
358 return x;
360 return (LPSTR)toupper((char)(int)x);
363 /***********************************************************************
364 * CharUpperBuffA (USER32.42)
365 * FIXME: handle current locale
367 DWORD WINAPI CharUpperBuffA(LPSTR x,DWORD buflen)
369 DWORD done=0;
371 if (!x) return 0; /* YES */
372 while (*x && (buflen--))
374 *x=toupper(*x);
375 x++;
376 done++;
378 return done;
381 /***********************************************************************
382 * CharUpperBuffW (USER32.43)
383 * FIXME: handle current locale
385 DWORD WINAPI CharUpperBuffW(LPWSTR x,DWORD buflen)
387 DWORD done=0;
389 if (!x) return 0; /* YES */
390 while (*x && (buflen--))
392 *x=towupper(*x);
393 x++;
394 done++;
396 return done;
399 /***********************************************************************
400 * CharUpperW (USER32.44)
401 * FIXME: handle current locale
403 LPWSTR WINAPI CharUpperW(LPWSTR x)
405 if (HIWORD(x))
407 LPWSTR s = x;
408 while (*s)
410 *s=towupper(*s);
411 s++;
413 return x;
415 else return (LPWSTR)((UINT)towupper(LOWORD(x)));
418 /***********************************************************************
419 * IsCharAlphaA (USER32.331)
420 * FIXME: handle current locale
422 BOOL WINAPI IsCharAlphaA(CHAR x)
424 return (OLE2NLS_CT_CType3_LUT[(unsigned char)x] & C3_ALPHA);
427 /***********************************************************************
428 * IsCharAlphaNumericA (USER32.332)
429 * FIXME: handle current locale
431 BOOL WINAPI IsCharAlphaNumericA(CHAR x)
433 return IsCharAlphaA(x) || isdigit(x) ;
436 /***********************************************************************
437 * IsCharAlphaNumericW (USER32.333)
438 * FIXME: handle current locale
440 BOOL WINAPI IsCharAlphaNumericW(WCHAR x)
442 return iswalnum(x);
445 /***********************************************************************
446 * IsCharAlphaW (USER32.334)
447 * FIXME: handle current locale
449 BOOL WINAPI IsCharAlphaW(WCHAR x)
451 return iswalpha(x);
454 /***********************************************************************
455 * IsCharLower32A (USER32.335)
456 * FIXME: handle current locale
458 BOOL WINAPI IsCharLowerA(CHAR x)
460 return islower(x);
463 /***********************************************************************
464 * IsCharLower32W (USER32.336)
465 * FIXME: handle current locale
467 BOOL WINAPI IsCharLowerW(WCHAR x)
469 return iswlower(x);
472 /***********************************************************************
473 * IsCharUpper32A (USER32.337)
474 * FIXME: handle current locale
476 BOOL WINAPI IsCharUpperA(CHAR x)
478 return isupper(x);
481 /***********************************************************************
482 * IsCharUpper32W (USER32.338)
483 * FIXME: handle current locale
485 BOOL WINAPI IsCharUpperW(WCHAR x)
487 return iswupper(x);
490 /***********************************************************************
491 * FormatMessage16 (USER.606)
493 DWORD WINAPI FormatMessage16(
494 DWORD dwFlags,
495 SEGPTR lpSource, /*not always a valid pointer*/
496 WORD dwMessageId,
497 WORD dwLanguageId,
498 LPSTR lpBuffer, /* *((HLOCAL16*)) for FORMAT_MESSAGE_ALLOCATE_BUFFER*/
499 WORD nSize,
500 LPDWORD args /* va_list *args */
502 #ifdef __i386__
503 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
504 LPSTR target,t;
505 DWORD talloced;
506 LPSTR from,f;
507 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
508 BOOL eos = FALSE;
509 LPSTR allocstring = NULL;
511 TRACE("(0x%lx,%lx,%d,0x%x,%p,%d,%p)\n",
512 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
513 if (width)
514 FIXME("line wrapping not supported.\n");
515 from = NULL;
516 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
517 from = HEAP_strdupA( GetProcessHeap(), 0, PTR_SEG_TO_LIN(lpSource));
518 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
519 from = HeapAlloc( GetProcessHeap(),0,200 );
520 sprintf(from,"Systemmessage, messageid = 0x%08x\n",dwMessageId);
522 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
523 INT16 bufsize;
524 HINSTANCE16 hinst16 = ((HMODULE)lpSource & 0xffff);
526 dwMessageId &= 0xFFFF;
527 bufsize=LoadString16(hinst16,dwMessageId,NULL,0);
528 if (bufsize) {
529 from = HeapAlloc( GetProcessHeap(), 0, bufsize +1);
530 LoadString16(hinst16,dwMessageId,from,bufsize+1);
533 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
534 t = target;
535 talloced= 100;
537 #define ADD_TO_T(c) \
538 *t++=c;\
539 if (t-target == talloced) {\
540 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
541 t = target+talloced;\
542 talloced*=2;\
545 if (from) {
546 f=from;
547 while (*f && !eos) {
548 if (*f=='%') {
549 int insertnr;
550 char *fmtstr,*sprintfbuf,*x,*lastf;
551 DWORD *argliststart;
553 fmtstr = NULL;
554 lastf = f;
555 f++;
556 if (!*f) {
557 ADD_TO_T('%');
558 continue;
560 switch (*f) {
561 case '1':case '2':case '3':case '4':case '5':
562 case '6':case '7':case '8':case '9':
563 insertnr=*f-'0';
564 switch (f[1]) {
565 case '0':case '1':case '2':case '3':
566 case '4':case '5':case '6':case '7':
567 case '8':case '9':
568 f++;
569 insertnr=insertnr*10+*f-'0';
570 f++;
571 break;
572 default:
573 f++;
574 break;
576 if (*f=='!') {
577 f++;
578 if (NULL!=(x=strchr(f,'!'))) {
579 *x='\0';
580 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
581 sprintf(fmtstr,"%%%s",f);
582 f=x+1;
583 } else {
584 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
585 sprintf(fmtstr,"%%%s",f);
586 f+=strlen(f); /*at \0*/
588 } else
589 if(!args)
590 break;
591 else
592 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
593 if (args) {
594 argliststart=args+insertnr-1;
595 if (fmtstr[strlen(fmtstr)-1]=='s')
596 sprintfbuf=HeapAlloc(GetProcessHeap(),0,
597 strlen(PTR_SEG_TO_LIN(argliststart[0]))+1);
598 else
599 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
601 /* CMF - This makes a BIG assumption about va_list */
602 wvsprintf16(sprintfbuf, fmtstr, (va_list) argliststart);
603 x=sprintfbuf;
604 while (*x) {
605 ADD_TO_T(*x++);
607 HeapFree(GetProcessHeap(),0,sprintfbuf);
608 } else {
609 /* NULL args - copy formatstr
610 * (probably wrong)
612 while ((lastf<f)&&(*lastf)) {
613 ADD_TO_T(*lastf++);
616 HeapFree(GetProcessHeap(),0,fmtstr);
617 break;
618 case '0': /* Just stop processing format string */
619 eos = TRUE;
620 f++;
621 break;
622 case 'n': /* 16 bit version just outputs 'n' */
623 default:
624 ADD_TO_T(*f++);
625 break;
627 } else { /* '\n' or '\r' gets mapped to "\r\n" */
628 if(*f == '\n' || *f == '\r') {
629 ADD_TO_T('\r');
630 ADD_TO_T('\n');
631 if(*f++ == '\r' && *f == '\n')
632 f++;
633 } else {
634 ADD_TO_T(*f++);
638 *t='\0';
640 talloced = strlen(target)+1;
641 if (nSize && talloced<nSize) {
642 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
644 TRACE("-- %s\n",debugstr_a(target));
645 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
646 /* nSize is the MINIMUM size */
647 *((HLOCAL16*)lpBuffer)= LocalAlloc16(LPTR,talloced);
648 allocstring=PTR_SEG_OFF_TO_LIN(CURRENT_DS,*((HLOCAL16*)lpBuffer));
649 memcpy( allocstring,target,talloced);
650 } else
651 lstrcpynA(lpBuffer,target,nSize);
652 HeapFree(GetProcessHeap(),0,target);
653 if (from) HeapFree(GetProcessHeap(),0,from);
654 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
655 strlen(allocstring):
656 strlen(lpBuffer);
657 #else
658 return 0;
659 #endif /* __i386__ */
661 #undef ADD_TO_T
663 /***********************************************************************
664 * FormatMessageA (KERNEL32.138)
665 * FIXME: missing wrap,FROM_SYSTEM message-loading,
667 DWORD WINAPI FormatMessageA(
668 DWORD dwFlags,
669 LPCVOID lpSource,
670 DWORD dwMessageId,
671 DWORD dwLanguageId,
672 LPSTR lpBuffer,
673 DWORD nSize,
674 LPDWORD args /* va_list *args */
676 #ifdef __i386__
677 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
678 LPSTR target,t;
679 DWORD talloced;
680 LPSTR from,f;
681 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
682 BOOL eos = FALSE;
684 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
685 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
686 if (width)
687 FIXME("line wrapping not supported.\n");
688 from = NULL;
689 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
690 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
691 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
692 from = HeapAlloc( GetProcessHeap(),0,200 );
693 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
695 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
696 INT bufsize;
698 dwMessageId &= 0xFFFF;
699 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
700 if (bufsize) {
701 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
702 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
705 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
706 t = target;
707 talloced= 100;
709 #define ADD_TO_T(c) \
710 *t++=c;\
711 if (t-target == talloced) {\
712 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
713 t = target+talloced;\
714 talloced*=2;\
717 if (from) {
718 f=from;
719 while (*f && !eos) {
720 if (*f=='%') {
721 int insertnr;
722 char *fmtstr,*sprintfbuf,*x,*lastf;
723 DWORD *argliststart;
725 fmtstr = NULL;
726 lastf = f;
727 f++;
728 if (!*f) {
729 ADD_TO_T('%');
730 continue;
732 switch (*f) {
733 case '1':case '2':case '3':case '4':case '5':
734 case '6':case '7':case '8':case '9':
735 insertnr=*f-'0';
736 switch (f[1]) {
737 case '0':case '1':case '2':case '3':
738 case '4':case '5':case '6':case '7':
739 case '8':case '9':
740 f++;
741 insertnr=insertnr*10+*f-'0';
742 f++;
743 break;
744 default:
745 f++;
746 break;
748 if (*f=='!') {
749 f++;
750 if (NULL!=(x=strchr(f,'!'))) {
751 *x='\0';
752 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
753 sprintf(fmtstr,"%%%s",f);
754 f=x+1;
755 } else {
756 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
757 sprintf(fmtstr,"%%%s",f);
758 f+=strlen(f); /*at \0*/
760 } else
761 if(!args)
762 break;
763 else
764 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
765 if (args) {
766 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
767 argliststart=args+insertnr-1;
768 else
769 argliststart=(*(DWORD**)args)+insertnr-1;
771 if (fmtstr[strlen(fmtstr)-1]=='s' && argliststart[0])
772 sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
773 else
774 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
776 /* CMF - This makes a BIG assumption about va_list */
777 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
778 x=sprintfbuf;
779 while (*x) {
780 ADD_TO_T(*x++);
782 HeapFree(GetProcessHeap(),0,sprintfbuf);
783 } else {
784 /* NULL args - copy formatstr
785 * (probably wrong)
787 while ((lastf<f)&&(*lastf)) {
788 ADD_TO_T(*lastf++);
791 HeapFree(GetProcessHeap(),0,fmtstr);
792 break;
793 case 'n':
794 ADD_TO_T('\r');
795 ADD_TO_T('\n');
796 f++;
797 break;
798 case '0':
799 eos = TRUE;
800 f++;
801 break;
802 default:
803 ADD_TO_T(*f++)
804 break;
806 } else { /* '\n' or '\r' gets mapped to "\r\n" */
807 if(*f == '\n' || *f == '\r') {
808 ADD_TO_T('\r');
809 ADD_TO_T('\n');
810 if(*f++ == '\r' && *f == '\n')
811 f++;
812 } else {
813 ADD_TO_T(*f++);
817 *t='\0';
819 talloced = strlen(target)+1;
820 if (nSize && talloced<nSize) {
821 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
823 TRACE("-- %s\n",debugstr_a(target));
824 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
825 /* nSize is the MINIMUM size */
826 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced);
827 memcpy(*(LPSTR*)lpBuffer,target,talloced);
828 } else {
829 lstrcpynA(lpBuffer,target,nSize);
831 HeapFree(GetProcessHeap(),0,target);
832 if (from) HeapFree(GetProcessHeap(),0,from);
833 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
834 strlen(*(LPSTR*)lpBuffer):
835 strlen(lpBuffer);
836 #else
837 return 0;
838 #endif /* __i386__ */
840 #undef ADD_TO_T
843 /***********************************************************************
844 * FormatMessageW (KERNEL32.138)
846 DWORD WINAPI FormatMessageW(
847 DWORD dwFlags,
848 LPCVOID lpSource,
849 DWORD dwMessageId,
850 DWORD dwLanguageId,
851 LPWSTR lpBuffer,
852 DWORD nSize,
853 LPDWORD args /* va_list *args */
855 #ifdef __i386__
856 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
857 LPSTR target,t;
858 DWORD talloced;
859 LPSTR from,f;
860 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
861 BOOL eos = FALSE;
863 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
864 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
865 if (width)
866 FIXME("line wrapping not supported.\n");
867 from = NULL;
868 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
869 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
870 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
871 /* gather information from system message tables ... */
872 from = HeapAlloc( GetProcessHeap(),0,200 );
873 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
875 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
876 INT bufsize;
878 dwMessageId &= 0xFFFF;
879 bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100);
880 if (bufsize)
882 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
883 LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
886 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
887 t = target;
888 talloced= 100;
890 #define ADD_TO_T(c) \
891 *t++=c;\
892 if (t-target == talloced) {\
893 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
894 t = target+talloced;\
895 talloced*=2;\
898 if (from) {
899 f=from;
900 while (*f && !eos) {
901 if (*f=='%') {
902 int insertnr;
903 char *fmtstr,*sprintfbuf,*x;
904 DWORD *argliststart;
906 fmtstr = NULL;
907 f++;
908 if (!*f) {
909 ADD_TO_T('%');
910 continue;
912 switch (*f) {
913 case '1':case '2':case '3':case '4':case '5':
914 case '6':case '7':case '8':case '9':
915 insertnr=*f-'0';
916 switch (f[1]) {
917 case '0':case '1':case '2':case '3':
918 case '4':case '5':case '6':case '7':
919 case '8':case '9':
920 f++;
921 insertnr=insertnr*10+*f-'0';
922 f++;
923 break;
924 default:
925 f++;
926 break;
928 if (*f=='!') {
929 f++;
930 if (NULL!=(x=strchr(f,'!')))
932 *x='\0';
933 fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
934 sprintf(fmtstr,"%%%s",f);
935 f=x+1;
936 } else {
937 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
938 sprintf(fmtstr,"%%%s",f);
939 f+=strlen(f); /*at \0*/
941 } else
942 if(!args)
943 break;
944 else
945 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
946 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
947 argliststart=args+insertnr-1;
948 else
949 argliststart=(*(DWORD**)args)+insertnr-1;
951 if (fmtstr[strlen(fmtstr)-1]=='s' && argliststart[0]) {
952 DWORD xarr[3];
954 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
955 /* possible invalid pointers */
956 xarr[1]=*(argliststart+1);
957 xarr[2]=*(argliststart+2);
958 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlenW((LPWSTR)argliststart[0])*2+1);
960 /* CMF - This makes a BIG assumption about va_list */
961 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
962 } else {
963 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
965 /* CMF - This makes a BIG assumption about va_list */
966 wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart);
968 x=sprintfbuf;
969 while (*x) {
970 ADD_TO_T(*x++);
972 HeapFree(GetProcessHeap(),0,sprintfbuf);
973 HeapFree(GetProcessHeap(),0,fmtstr);
974 break;
975 case 'n':
976 ADD_TO_T('\r');
977 ADD_TO_T('\n');
978 f++;
979 break;
980 case '0':
981 eos = TRUE;
982 f++;
983 break;
984 default:
985 ADD_TO_T(*f++)
986 break;
988 } else { /* '\n' or '\r' gets mapped to "\r\n" */
989 if(*f == '\n' || *f == '\r') {
990 ADD_TO_T('\r');
991 ADD_TO_T('\n');
992 if(*f++ == '\r' && *f == '\n')
993 f++;
994 } else {
995 ADD_TO_T(*f++);
999 *t='\0';
1001 talloced = strlen(target)+1;
1002 if (nSize && talloced<nSize)
1003 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
1004 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
1005 /* nSize is the MINIMUM size */
1006 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(GMEM_ZEROINIT,talloced*2+2);
1007 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
1008 } else
1009 lstrcpynAtoW(lpBuffer,target,nSize);
1010 HeapFree(GetProcessHeap(),0,target);
1011 if (from) HeapFree(GetProcessHeap(),0,from);
1012 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
1013 lstrlenW(*(LPWSTR*)lpBuffer):
1014 lstrlenW(lpBuffer);
1015 #else
1016 return 0;
1017 #endif /* __i386__ */
1019 #undef ADD_TO_T