Release 971012
[wine/multimedia.git] / misc / lstr.c
blob2d7db18660ad42f445ff1902d5150b6c928260b0
1 /*
2 * String functions
4 * Copyright 1993 Yngvi Sigurjonsson (yngvi@hafro.is)
5 * Copyright 1996 Marcus Meissner
6 */
8 #include <stdio.h>
9 #include <stdarg.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
14 #include "windows.h"
15 #include "winnt.h" /* HEAP_ macros */
16 #include "heap.h"
17 #include "ldt.h"
18 #include "module.h"
19 #include "stddebug.h"
20 #include "debug.h"
22 #define ToUpper(c) toupper(c)
23 #define ToLower(c) tolower(c)
26 /* Funny to divide them between user and kernel. */
28 /* IsCharAlpha USER 433 */
29 BOOL16 WINAPI IsCharAlpha16(CHAR ch)
31 return isalpha(ch); /* This is probably not right for NLS */
34 /* IsCharAlphanumeric USER 434 */
35 BOOL16 WINAPI IsCharAlphaNumeric16(CHAR ch)
37 return isalnum(ch);
40 /* IsCharUpper USER 435 */
41 BOOL16 WINAPI IsCharUpper16(CHAR ch)
43 return isupper(ch);
46 /* IsCharLower USER 436 */
47 BOOL16 WINAPI IsCharLower16(CHAR ch)
49 return islower(ch);
52 /***********************************************************************
53 * AnsiUpper16 (USER.431)
55 SEGPTR WINAPI AnsiUpper16( SEGPTR strOrChar )
57 /* I am not sure if the locale stuff works with toupper, but then again
58 I am not sure if the Linux libc locale stuffs works at all */
60 /* uppercase only one char if strOrChar < 0x10000 */
61 if (HIWORD(strOrChar))
63 char *s;
64 for (s = PTR_SEG_TO_LIN(strOrChar); *s; s++) *s = toupper(*s);
65 return strOrChar;
67 else return (SEGPTR)ToUpper( (int)strOrChar );
71 /***********************************************************************
72 * AnsiUpperBuff16 (USER.437)
74 UINT16 WINAPI AnsiUpperBuff16( LPSTR str, UINT16 len )
76 UINT32 count = len ? len : 65536;
77 for (; count; count--, str++) *str = toupper(*str);
78 return len;
81 /***********************************************************************
82 * AnsiLower16 (USER.432)
84 SEGPTR WINAPI AnsiLower16( SEGPTR strOrChar )
86 /* I am not sure if the locale stuff works with toupper, but then again
87 I am not sure if the Linux libc locale stuffs works at all */
89 /* lowercase only one char if strOrChar < 0x10000 */
90 if (HIWORD(strOrChar))
92 char *s;
93 for (s = PTR_SEG_TO_LIN( strOrChar ); *s; s++) *s = tolower( *s );
94 return strOrChar;
96 else return (SEGPTR)tolower( (int)strOrChar );
100 /***********************************************************************
101 * AnsiLowerBuff16 (USER.438)
103 UINT16 WINAPI AnsiLowerBuff16( LPSTR str, UINT16 len )
105 UINT32 count = len ? len : 65536;
106 for (; count; count--, str++) *str = tolower(*str);
107 return len;
111 /***********************************************************************
112 * AnsiNext16 (USER.472)
114 SEGPTR WINAPI AnsiNext16(SEGPTR current)
116 return (*(char *)PTR_SEG_TO_LIN(current)) ? current + 1 : current;
120 /***********************************************************************
121 * AnsiPrev16 (USER.473)
123 SEGPTR WINAPI AnsiPrev16( SEGPTR start, SEGPTR current )
125 return (current == start) ? start : current - 1;
129 /***********************************************************************
130 * OutputDebugString16 (KERNEL.115)
132 void WINAPI OutputDebugString16( LPCSTR str )
134 char *module;
135 char *p, *buffer = HeapAlloc( GetProcessHeap(), 0, strlen(str)+2 );
136 /* Remove CRs */
137 for (p = buffer; *str; str++) if (*str != '\r') *p++ = *str;
138 *p = '\0';
139 if ((p > buffer) && (p[-1] == '\n')) p[1] = '\0'; /* Remove trailing \n */
140 module = MODULE_GetModuleName( GetCurrentTask() );
141 fprintf( stderr, "OutputDebugString: %s says '%s'\n",
142 module ? module : "???", buffer );
143 HeapFree( GetProcessHeap(), 0, buffer );
147 /***********************************************************************
148 * OutputDebugString32A (KERNEL32
150 void WINAPI OutputDebugString32A( LPCSTR str )
152 OutputDebugString16( str );
157 /***********************************************************************
158 * OutputDebugString32W (KERNEL32
160 void WINAPI OutputDebugString32W( LPCWSTR str )
162 LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
163 OutputDebugString32A( p );
164 HeapFree( GetProcessHeap(), 0, p );
169 /***********************************************************************
170 * CharNext32A (USER32.28)
172 LPSTR WINAPI CharNext32A( LPCSTR ptr )
174 if (!*ptr) return (LPSTR)ptr;
175 if (IsDBCSLeadByte32( *ptr )) return (LPSTR)(ptr + 2);
176 return (LPSTR)(ptr + 1);
180 /***********************************************************************
181 * CharNextEx32A (USER32.29)
183 LPSTR WINAPI CharNextEx32A( WORD codepage, LPCSTR ptr, DWORD flags )
185 if (!*ptr) return (LPSTR)ptr;
186 if (IsDBCSLeadByteEx( codepage, *ptr )) return (LPSTR)(ptr + 2);
187 return (LPSTR)(ptr + 1);
191 /***********************************************************************
192 * CharNextExW (USER32.30)
194 LPWSTR WINAPI CharNextEx32W(WORD codepage,LPCWSTR x,DWORD flags)
196 /* FIXME: add DBCS / codepage stuff */
197 if (*x) return (LPWSTR)(x+1);
198 else return (LPWSTR)x;
201 /***********************************************************************
202 * CharNextW (USER32.31)
204 LPWSTR WINAPI CharNext32W(LPCWSTR x)
206 if (*x) return (LPWSTR)(x+1);
207 else return (LPWSTR)x;
210 /***********************************************************************
211 * CharPrev32A (USER32.32)
213 LPSTR WINAPI CharPrev32A( LPCSTR start, LPCSTR ptr )
215 while (*start && (start < ptr))
217 LPCSTR next = CharNext32A( start );
218 if (next >= ptr) break;
219 start = next;
221 return (LPSTR)start;
225 /***********************************************************************
226 * CharPrevEx32A (USER32.33)
228 LPSTR WINAPI CharPrevEx32A( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
230 while (*start && (start < ptr))
232 LPCSTR next = CharNextEx32A( codepage, start, flags );
233 if (next > ptr) break;
234 start = next;
236 return (LPSTR)start;
240 /***********************************************************************
241 * CharPrevExW (USER32.34)
243 LPWSTR WINAPI CharPrevEx32W(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
245 /* FIXME: add DBCS / codepage stuff */
246 if (x>start) return (LPWSTR)(x-1);
247 else return (LPWSTR)x;
250 /***********************************************************************
251 * CharPrevW (USER32.35)
253 LPWSTR WINAPI CharPrev32W(LPCWSTR start,LPCWSTR x)
255 if (x>start) return (LPWSTR)(x-1);
256 else return (LPWSTR)x;
259 /***********************************************************************
260 * CharLowerA (USER32.24)
261 * FIXME: handle current locale
263 LPSTR WINAPI CharLower32A(LPSTR x)
265 LPSTR s;
267 if (HIWORD(x))
269 s=x;
270 while (*s)
272 *s=tolower(*s);
273 s++;
275 return x;
277 else return (LPSTR)tolower(LOWORD(x));
280 /***********************************************************************
281 * CharLowerBuffA (USER32.25)
282 * FIXME: handle current locale
284 DWORD WINAPI CharLowerBuff32A(LPSTR x,DWORD buflen)
286 DWORD done=0;
288 while (*x && (buflen--))
290 *x=tolower(*x);
291 x++;
292 done++;
294 return done;
297 /***********************************************************************
298 * CharLowerBuffW (USER32.26)
299 * FIXME: handle current locale
301 DWORD WINAPI CharLowerBuff32W(LPWSTR x,DWORD buflen)
303 DWORD done=0;
305 while (*x && (buflen--))
307 *x=tolower(*x);
308 x++;
309 done++;
311 return done;
314 /***********************************************************************
315 * CharLowerW (USER32.27)
316 * FIXME: handle current locale
318 LPWSTR WINAPI CharLower32W(LPWSTR x)
320 if (HIWORD(x))
322 LPWSTR s = x;
323 while (*s)
325 *s=tolower(*s);
326 s++;
328 return x;
330 else return (LPWSTR)tolower(LOWORD(x));
333 /***********************************************************************
334 * CharUpper32A (USER32.40)
335 * FIXME: handle current locale
337 LPSTR WINAPI CharUpper32A(LPSTR x)
339 if (HIWORD(x))
341 LPSTR s = x;
342 while (*s)
344 *s=toupper(*s);
345 s++;
347 return x;
349 else return (LPSTR)toupper(LOWORD(x));
352 /***********************************************************************
353 * CharUpperBuffA (USER32.41)
354 * FIXME: handle current locale
356 DWORD WINAPI CharUpperBuff32A(LPSTR x,DWORD buflen)
358 DWORD done=0;
360 while (*x && (buflen--))
362 *x=toupper(*x);
363 x++;
364 done++;
366 return done;
369 /***********************************************************************
370 * CharUpperBuffW (USER32.42)
371 * FIXME: handle current locale
373 DWORD WINAPI CharUpperBuff32W(LPWSTR x,DWORD buflen)
375 DWORD done=0;
377 while (*x && (buflen--))
379 *x=toupper(*x);
380 x++;
381 done++;
383 return done;
386 /***********************************************************************
387 * CharUpperW (USER32.43)
388 * FIXME: handle current locale
390 LPWSTR WINAPI CharUpper32W(LPWSTR x)
392 if (HIWORD(x))
394 LPWSTR s = x;
395 while (*s)
397 *s=toupper(*s);
398 s++;
400 return x;
402 else return (LPWSTR)toupper(LOWORD(x));
405 /***********************************************************************
406 * IsCharAlphaA (USER32.330)
407 * FIXME: handle current locale
409 BOOL32 WINAPI IsCharAlpha32A(CHAR x)
411 return isalpha(x);
414 /***********************************************************************
415 * IsCharAlphaNumericA (USER32.331)
416 * FIXME: handle current locale
418 BOOL32 WINAPI IsCharAlphaNumeric32A(CHAR x)
420 return isalnum(x);
423 /***********************************************************************
424 * IsCharAlphaNumericW (USER32.332)
425 * FIXME: handle current locale
427 BOOL32 WINAPI IsCharAlphaNumeric32W(WCHAR x)
429 return isalnum(x);
432 /***********************************************************************
433 * IsCharAlphaW (USER32.333)
434 * FIXME: handle current locale
436 BOOL32 WINAPI IsCharAlpha32W(WCHAR x)
438 return isalpha(x);
441 /***********************************************************************
442 * IsCharLower32A (USER32.334)
443 * FIXME: handle current locale
445 BOOL32 WINAPI IsCharLower32A(CHAR x)
447 return islower(x);
450 /***********************************************************************
451 * IsCharLower32W (USER32.335)
452 * FIXME: handle current locale
454 BOOL32 WINAPI IsCharLower32W(WCHAR x)
456 return islower(x);
459 /***********************************************************************
460 * IsCharUpper32A (USER32.336)
461 * FIXME: handle current locale
463 BOOL32 WINAPI IsCharUpper32A(CHAR x)
465 return isupper(x);
468 /***********************************************************************
469 * IsCharUpper32W (USER32.337)
470 * FIXME: handle current locale
472 BOOL32 WINAPI IsCharUpper32W(WCHAR x)
474 return isupper(x);
477 /***********************************************************************
478 * FormatMessage32A (KERNEL32.138)
479 * FIXME: missing wrap,FROM_SYSTEM message-loading,
481 DWORD WINAPI FormatMessage32A(
482 DWORD dwFlags,
483 LPCVOID lpSource,
484 DWORD dwMessageId,
485 DWORD dwLanguageId,
486 LPSTR lpBuffer,
487 DWORD nSize,
488 LPDWORD args /* va_list *args */
490 LPSTR target,t;
491 DWORD talloced;
492 LPSTR from,f;
493 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
494 DWORD nolinefeed = 0;
496 dprintf_resource(stddeb,
497 "FormatMessage32A(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
498 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args
500 if (width)
501 fprintf(stdnimp," - line wrapping not supported.\n");
502 from = NULL;
503 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
504 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
505 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
506 from = HeapAlloc( GetProcessHeap(),0,200 );
507 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
509 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
510 INT32 bufsize;
512 dwMessageId &= 0xFFFF;
513 bufsize=LoadMessage32A(0,dwMessageId,dwLanguageId,NULL,100);
514 if (bufsize) {
515 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
516 LoadMessage32A(0,dwMessageId,dwLanguageId,from,bufsize+1);
519 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
520 t = target;
521 talloced= 100;
523 #define ADD_TO_T(c) \
524 *t++=c;\
525 if (t-target == talloced) {\
526 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
527 t = target+talloced;\
528 talloced*=2;\
531 if (from) {
532 f=from;
533 while (*f) {
534 if (*f=='%') {
535 int insertnr;
536 char *fmtstr,*sprintfbuf,*x,*lastf;
537 DWORD *argliststart;
539 fmtstr = NULL;
540 lastf = f;
541 f++;
542 if (!*f) {
543 ADD_TO_T('%');
544 continue;
546 switch (*f) {
547 case '1':case '2':case '3':case '4':case '5':
548 case '6':case '7':case '8':case '9':
549 insertnr=*f-'0';
550 switch (f[1]) {
551 case '0':case '1':case '2':case '3':
552 case '4':case '5':case '6':case '7':
553 case '8':case '9':
554 f++;
555 insertnr=insertnr*10+*f-'0';
556 f++;
557 break;
558 default:
559 f++;
560 break;
562 if (*f=='!') {
563 f++;
564 if (NULL!=(x=strchr(f,'!'))) {
565 *x='\0';
566 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
567 sprintf(fmtstr,"%%%s",f);
568 f=x+1;
569 } else {
570 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
571 sprintf(fmtstr,"%%%s",f);
572 f+=strlen(f); /*at \0*/
574 } else
575 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
576 if (args) {
577 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
578 argliststart=args+insertnr-1;
579 else
580 argliststart=(*(DWORD**)args)+insertnr-1;
582 if (fmtstr[strlen(fmtstr)]=='s')
583 sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
584 else
585 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
587 /* CMF - This makes a BIG assumption about va_list */
588 vsprintf(sprintfbuf, fmtstr, (va_list) argliststart);
589 x=sprintfbuf;
590 while (*x) {
591 ADD_TO_T(*x++);
593 HeapFree(GetProcessHeap(),0,sprintfbuf);
594 } else {
595 /* NULL args - copy formatstr
596 * (probably wrong)
598 while (lastf<f) {
599 ADD_TO_T(*lastf++);
602 HeapFree(GetProcessHeap(),0,fmtstr);
603 break;
604 case 'n':
605 /* FIXME: perhaps add \r too? */
606 ADD_TO_T('\n');
607 f++;
608 break;
609 case '0':
610 nolinefeed=1;
611 f++;
612 break;
613 default:ADD_TO_T(*f++)
614 break;
617 } else {
618 ADD_TO_T(*f++)
621 *t='\0';
623 if (!nolinefeed && t[-1]!='\n')
624 ADD_TO_T('\n');
625 talloced = strlen(target)+1;
626 if (nSize && talloced<nSize) {
627 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
629 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
630 /* nSize is the MINIMUM size */
631 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced);
632 memcpy(*(LPSTR*)lpBuffer,target,talloced);
633 } else
634 strncpy(lpBuffer,target,nSize);
635 HeapFree(GetProcessHeap(),0,target);
636 if (from) HeapFree(GetProcessHeap(),0,from);
637 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
638 strlen(*(LPSTR*)lpBuffer):
639 strlen(lpBuffer);
641 #undef ADD_TO_T
644 /***********************************************************************
645 * FormatMessage32W (KERNEL32.138)
647 DWORD WINAPI FormatMessage32W(
648 DWORD dwFlags,
649 LPCVOID lpSource,
650 DWORD dwMessageId,
651 DWORD dwLanguageId,
652 LPWSTR lpBuffer,
653 DWORD nSize,
654 LPDWORD args /* va_list *args */
656 LPSTR target,t;
657 DWORD talloced;
658 LPSTR from,f;
659 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
660 DWORD nolinefeed = 0;
662 dprintf_resource(stddeb,
663 "FormatMessage32A(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
664 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args
666 if (width)
667 fprintf(stdnimp," - line wrapping not supported.\n");
668 from = NULL;
669 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
670 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
671 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
672 /* gather information from system message tables ... */
673 from = HeapAlloc( GetProcessHeap(),0,200 );
674 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
676 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
677 INT32 bufsize;
679 dwMessageId &= 0xFFFF;
680 bufsize=LoadMessage32A(0,dwMessageId,dwLanguageId,NULL,100);
681 if (bufsize)
683 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
684 LoadMessage32A(0,dwMessageId,dwLanguageId,from,bufsize+1);
687 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
688 t = target;
689 talloced= 100;
691 #define ADD_TO_T(c) \
692 *t++=c;\
693 if (t-target == talloced) {\
694 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
695 t = target+talloced;\
696 talloced*=2;\
699 if (from) {
700 f=from;
701 while (*f) {
702 if (*f=='%') {
703 int insertnr;
704 char *fmtstr,*sprintfbuf,*x;
705 DWORD *argliststart;
707 fmtstr = NULL;
708 f++;
709 if (!*f) {
710 ADD_TO_T('%');
711 continue;
713 switch (*f) {
714 case '1':case '2':case '3':case '4':case '5':
715 case '6':case '7':case '8':case '9':
716 insertnr=*f-'0';
717 switch (f[1]) {
718 case '0':case '1':case '2':case '3':
719 case '4':case '5':case '6':case '7':
720 case '8':case '9':
721 f++;
722 insertnr=insertnr*10+*f-'0';
723 f++;
724 break;
725 default:
726 f++;
727 break;
729 if (*f=='!') {
730 f++;
731 if (NULL!=(x=strchr(f,'!')))
733 *x='\0';
734 fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
735 sprintf(fmtstr,"%%%s",f);
736 f=x+1;
737 } else {
738 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
739 sprintf(fmtstr,"%%%s",f);
740 f+=strlen(f); /*at \0*/
742 } else
743 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
744 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
745 argliststart=args+insertnr-1;
746 else
747 argliststart=(*(DWORD**)args)+insertnr-1;
749 if (fmtstr[strlen(fmtstr)]=='s') {
750 DWORD xarr[3];
752 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
753 /* possible invalid pointers */
754 xarr[1]=*(argliststart+1);
755 xarr[2]=*(argliststart+2);
756 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlen32W((LPWSTR)argliststart[0])*2+1);
758 /* CMF - This makes a BIG assumption about va_list */
759 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
760 } else {
761 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
763 /* CMF - This makes a BIG assumption about va_list */
764 vsprintf(sprintfbuf, fmtstr, (va_list) argliststart);
766 x=sprintfbuf;
767 while (*x) {
768 ADD_TO_T(*x++);
770 HeapFree(GetProcessHeap(),0,sprintfbuf);
771 HeapFree(GetProcessHeap(),0,fmtstr);
772 break;
773 case 'n':
774 /* FIXME: perhaps add \r too? */
775 ADD_TO_T('\n');
776 f++;
777 break;
778 case '0':
779 nolinefeed=1;
780 f++;
781 break;
782 default:ADD_TO_T(*f++)
783 break;
786 } else {
787 ADD_TO_T(*f++)
790 *t='\0';
792 if (!nolinefeed && t[-1]!='\n')
793 ADD_TO_T('\n');
794 talloced = strlen(target)+1;
795 if (nSize && talloced<nSize)
796 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
797 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
798 /* nSize is the MINIMUM size */
799 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced*2+2);
800 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
801 } else
802 lstrcpynAtoW(lpBuffer,target,nSize);
803 HeapFree(GetProcessHeap(),0,target);
804 if (from) HeapFree(GetProcessHeap(),0,from);
805 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
806 lstrlen32W(*(LPWSTR*)lpBuffer):
807 lstrlen32W(lpBuffer);
809 #undef ADD_TO_T