Release 961222
[wine/gsoc-2012-control.git] / misc / lstr.c
blob82d68b053676f32a758c7a722c602f6c5302fbd5
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 "ldt.h"
16 #include "module.h"
17 #include "stddebug.h"
18 #include "debug.h"
19 #include "xmalloc.h"
20 #include "string32.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 IsCharAlpha16(CHAR ch)
31 return isalpha(ch); /* This is probably not right for NLS */
34 /* IsCharAlphanumeric USER 434 */
35 BOOL16 IsCharAlphanumeric16(CHAR ch)
37 return isalnum(ch);
40 /* IsCharUpper USER 435 */
41 BOOL16 IsCharUpper16(CHAR ch)
43 return isupper(ch);
46 /* IsCharLower USER 436 */
47 BOOL16 IsCharLower16(CHAR ch)
49 return islower(ch);
52 /***********************************************************************
53 * AnsiUpper (USER.431)
56 /* 16-bit version */
57 SEGPTR WIN16_AnsiUpper( SEGPTR strOrChar )
59 /* I am not sure if the locale stuff works with toupper, but then again
60 I am not sure if the Linux libc locale stuffs works at all */
62 /* uppercase only one char if strOrChar < 0x10000 */
63 if (HIWORD(strOrChar))
65 char *s = PTR_SEG_TO_LIN(strOrChar);
66 while (*s) {
67 *s = ToUpper( *s );
68 s++;
70 return strOrChar;
72 else return (SEGPTR)ToUpper( (int)strOrChar );
75 /* 32-bit version */
76 LPSTR AnsiUpper(LPSTR strOrChar)
78 char *s = strOrChar;
79 /* I am not sure if the locale stuff works with toupper, but then again
80 I am not sure if the Linux libc locale stuffs works at all */
82 while (*s) {
83 *s = ToUpper( *s );
84 s++;
86 return strOrChar;
90 /***********************************************************************
91 * AnsiUpperBuff (USER.437)
93 UINT AnsiUpperBuff(LPSTR str,UINT len)
95 int i;
96 len=(len==0)?65536:len;
98 for(i=0;i<len;i++)
99 str[i]=toupper(str[i]);
100 return i;
103 /***********************************************************************
104 * AnsiLower (USER.432)
107 /* 16-bit version */
108 SEGPTR WIN16_AnsiLower(SEGPTR strOrChar)
110 /* I am not sure if the locale stuff works with toupper, but then again
111 I am not sure if the Linux libc locale stuffs works at all */
113 /* lowercase only one char if strOrChar < 0x10000 */
114 if (HIWORD(strOrChar))
116 char *s = PTR_SEG_TO_LIN( strOrChar );
117 while (*s) {
118 *s = ToLower( *s );
119 s++;
121 return strOrChar;
123 else return (SEGPTR)ToLower( (int)strOrChar );
126 /* 32-bit version */
127 LPSTR AnsiLower(LPSTR strOrChar)
129 char *s = strOrChar;
130 /* I am not sure if the locale stuff works with toupper, but then again
131 I am not sure if the Linux libc locale stuffs works at all */
133 while (*s) {
134 *s = ToLower( *s );
135 s++;
137 return strOrChar;
141 /***********************************************************************
142 * AnsiLowerBuff (USER.438)
144 UINT AnsiLowerBuff(LPSTR str,UINT len)
146 int i;
147 len=(len==0)?65536:len;
148 i=0;
150 for(i=0;i<len;i++)
151 str[i]=tolower(str[i]);
153 return i;
157 /* AnsiNext USER.472 */
158 SEGPTR AnsiNext(SEGPTR current)
160 return (*(char *)PTR_SEG_TO_LIN(current)) ? current + 1 : current;
163 /* AnsiPrev USER.473 */
164 SEGPTR AnsiPrev( SEGPTR start, SEGPTR current)
166 return (current==start)?start:current-1;
170 /***********************************************************************
171 * OutputDebugString (KERNEL.115)
173 void OutputDebugString( LPCSTR str )
175 char *module;
176 char *p, *buffer = xmalloc( strlen(str)+1 );
177 /* Remove CRs */
178 for (p = buffer; *str; str++) if (*str != '\r') *p++ = *str;
179 *p = '\0';
180 if ((p > buffer) && (p[-1] == '\n')) p[1] = '\0'; /* Remove trailing \n */
181 module = MODULE_GetModuleName( GetExePtr(GetCurrentTask()) );
182 fprintf( stderr, "OutputDebugString: %s says '%s'\n",
183 module ? module : "???", buffer );
184 free( buffer );
187 /***********************************************************************
188 * CharNextA (USER32.28)
190 LPSTR CharNext32A(LPCSTR x)
192 if (*x) return (LPSTR)(x+1);
193 else return (LPSTR)x;
196 /***********************************************************************
197 * CharNextExA (USER32.29)
199 LPSTR CharNextEx32A(WORD codepage,LPCSTR x,DWORD flags)
201 /* FIXME: add DBCS / codepage stuff */
202 if (*x) return (LPSTR)(x+1);
203 else return (LPSTR)x;
206 /***********************************************************************
207 * CharNextExW (USER32.30)
209 LPWSTR CharNextEx32W(WORD codepage,LPCWSTR x,DWORD flags)
211 /* FIXME: add DBCS / codepage stuff */
212 if (*x) return (LPWSTR)(x+1);
213 else return (LPWSTR)x;
216 /***********************************************************************
217 * CharNextW (USER32.31)
219 LPWSTR CharNext32W(LPCWSTR x)
221 if (*x) return (LPWSTR)(x+1);
222 else return (LPWSTR)x;
225 /***********************************************************************
226 * CharPrevA (USER32.32)
228 LPSTR CharPrev32A(LPCSTR start,LPCSTR x)
230 if (x>start) return (LPSTR)(x-1);
231 else return (LPSTR)x;
234 /***********************************************************************
235 * CharPrevExA (USER32.33)
237 LPSTR CharPrevEx32A(WORD codepage,LPCSTR start,LPCSTR x,DWORD flags)
239 /* FIXME: add DBCS / codepage stuff */
240 if (x>start) return (LPSTR)(x-1);
241 else return (LPSTR)x;
244 /***********************************************************************
245 * CharPrevExW (USER32.34)
247 LPWSTR CharPrevEx32W(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
249 /* FIXME: add DBCS / codepage stuff */
250 if (x>start) return (LPWSTR)(x-1);
251 else return (LPWSTR)x;
254 /***********************************************************************
255 * CharPrevW (USER32.35)
257 LPWSTR CharPrev32W(LPCWSTR start,LPCWSTR x)
259 if (x>start) return (LPWSTR)(x-1);
260 else return (LPWSTR)x;
263 /***********************************************************************
264 * CharLowerA (USER32.24)
265 * FIXME: handle current locale
267 LPSTR CharLower32A(LPSTR x)
269 LPSTR s;
271 if (HIWORD(x))
273 s=x;
274 while (*s)
276 *s=tolower(*s);
277 s++;
279 return x;
281 else return (LPSTR)tolower(LOWORD(x));
284 /***********************************************************************
285 * CharLowerBuffA (USER32.25)
286 * FIXME: handle current locale
288 DWORD CharLowerBuff32A(LPSTR x,DWORD buflen)
290 DWORD done=0;
292 while (*x && (buflen--))
294 *x=tolower(*x);
295 x++;
296 done++;
298 return done;
301 /***********************************************************************
302 * CharLowerBuffW (USER32.26)
303 * FIXME: handle current locale
305 DWORD CharLowerBuff32W(LPWSTR x,DWORD buflen)
307 DWORD done=0;
309 while (*x && (buflen--))
311 *x=tolower(*x);
312 x++;
313 done++;
315 return done;
318 /***********************************************************************
319 * CharLowerW (USER32.27)
320 * FIXME: handle current locale
322 LPWSTR CharLower32W(LPWSTR x)
324 if (HIWORD(x))
326 LPWSTR s = x;
327 while (*s)
329 *s=tolower(*s);
330 s++;
332 return x;
334 else return (LPWSTR)tolower(LOWORD(x));
337 /***********************************************************************
338 * CharUpperA (USER32.40)
339 * FIXME: handle current locale
341 LPSTR CharUpper32A(LPSTR x)
343 if (HIWORD(x))
345 LPSTR s = x;
346 while (*s)
348 *s=toupper(*s);
349 s++;
351 return x;
353 else return (LPSTR)toupper(LOWORD(x));
356 /***********************************************************************
357 * CharUpperBuffA (USER32.41)
358 * FIXME: handle current locale
360 DWORD CharUpperBuff32A(LPSTR x,DWORD buflen)
362 DWORD done=0;
364 while (*x && (buflen--))
366 *x=toupper(*x);
367 x++;
368 done++;
370 return done;
373 /***********************************************************************
374 * CharUpperBuffW (USER32.42)
375 * FIXME: handle current locale
377 DWORD CharUpperBuff32W(LPWSTR x,DWORD buflen)
379 DWORD done=0;
381 while (*x && (buflen--))
383 *x=toupper(*x);
384 x++;
385 done++;
387 return done;
390 /***********************************************************************
391 * CharUpperW (USER32.43)
392 * FIXME: handle current locale
394 LPWSTR CharUpper32W(LPWSTR x)
396 if (HIWORD(x))
398 LPWSTR s = x;
399 while (*s)
401 *s=toupper(*s);
402 s++;
404 return x;
406 else return (LPWSTR)toupper(LOWORD(x));
409 /***********************************************************************
410 * IsCharAlphaA (USER32.330)
411 * FIXME: handle current locale
413 BOOL32 IsCharAlpha32A(CHAR x)
415 return isalpha(x);
418 /***********************************************************************
419 * IsCharAlphaNumericA (USER32.331)
420 * FIXME: handle current locale
422 BOOL32 IsCharAlphaNumeric32A(CHAR x)
424 return isalnum(x);
427 /***********************************************************************
428 * IsCharAlphaNumericW (USER32.332)
429 * FIXME: handle current locale
431 BOOL32 IsCharAlphaNumeric32W(WCHAR x)
433 return isalnum(x);
436 /***********************************************************************
437 * IsCharAlphaW (USER32.333)
438 * FIXME: handle current locale
440 BOOL32 IsCharAlpha32W(WCHAR x)
442 return isalpha(x);
445 /***********************************************************************
446 * IsCharLower32A (USER32.334)
447 * FIXME: handle current locale
449 BOOL32 IsCharLower32A(CHAR x)
451 return islower(x);
454 /***********************************************************************
455 * IsCharLower32W (USER32.335)
456 * FIXME: handle current locale
458 BOOL32 IsCharLower32W(WCHAR x)
460 return islower(x);
463 /***********************************************************************
464 * IsCharUpper32A (USER32.336)
465 * FIXME: handle current locale
467 BOOL32 IsCharUpper32A(CHAR x)
469 return isupper(x);
472 /***********************************************************************
473 * IsCharUpper32W (USER32.337)
474 * FIXME: handle current locale
476 BOOL32 IsCharUpper32W(WCHAR x)
478 return isupper(x);
481 /***********************************************************************
482 * FormatMessageA (KERNEL32.138) Library Version
483 * FIXME: missing wrap,FROM_SYSTEM message-loading,
485 DWORD
486 FormatMessage32A(
487 DWORD dwFlags,
488 LPCVOID lpSource,
489 DWORD dwMessageId,
490 DWORD dwLanguageId,
491 LPSTR lpBuffer,
492 DWORD nSize,
493 LPDWORD args /* va_list *args */
495 LPSTR target,t;
496 DWORD talloced;
497 LPSTR from,f;
498 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
499 DWORD nolinefeed = 0;
501 dprintf_resource(stddeb,
502 "FormatMessage32A(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
503 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args
505 if (width)
506 fprintf(stdnimp," - line wrapping not supported.\n");
507 from = NULL;
508 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
509 from = xstrdup((LPSTR)lpSource);
510 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
511 /* gather information from system message tables ... */
512 fprintf(stdnimp," - FORMAT_MESSAGE_FROM_SYSTEM not implemented.\n");
514 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
515 INT32 bufsize;
517 dwMessageId &= 0xFFFF;
518 bufsize=LoadMessage32A(0,dwMessageId,dwLanguageId,NULL,100);
519 if (bufsize) {
520 from = (char*)xmalloc(bufsize+1);
521 LoadMessage32A(0,dwMessageId,dwLanguageId,from,bufsize+1);
524 target = (char*)xmalloc(100);
525 t = target;
526 talloced= 100;
527 *t = 0;
529 #define ADD_TO_T(c) \
530 *t++=c;\
531 if (t-target == talloced) {\
532 target = (char*)xrealloc(target,talloced*2);\
533 t = target+talloced;\
534 talloced*=2;\
537 if (from) {
538 f=from;
539 while (*f) {
540 if (*f=='%') {
541 int insertnr;
542 char *fmtstr,*sprintfbuf,*x;
543 DWORD *argliststart;
545 fmtstr = NULL;
546 f++;
547 if (!*f) {
548 ADD_TO_T('%');
549 continue;
551 switch (*f) {
552 case '1':case '2':case '3':case '4':case '5':
553 case '6':case '7':case '8':case '9':
554 insertnr=*f-'0';
555 switch (f[1]) {
556 case '0':case '1':case '2':case '3':
557 case '4':case '5':case '6':case '7':
558 case '8':case '9':
559 f++;
560 insertnr=insertnr*10+*f-'0';
561 f++;
562 break;
563 default:
564 f++;
565 break;
567 if (*f=='!') {
568 f++;
569 if (NULL!=(x=strchr(f,'!'))) {
570 *x='\0';
571 fmtstr=(char*)xmalloc(strlen(f)+2);
572 sprintf(fmtstr,"%%%s",f);
573 f=x+1;
575 } else
576 fmtstr=strdup("%s");
577 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
578 argliststart=args+insertnr-1;
579 else
580 /* FIXME: not sure that this is
581 * correct for unix-c-varargs.
583 argliststart=((DWORD*)&args)+insertnr-1;
585 if (fmtstr[strlen(fmtstr)]=='s')
586 sprintfbuf=(char*)xmalloc(strlen((LPSTR)argliststart[0])+1);
587 else
588 sprintfbuf=(char*)xmalloc(100);
589 vsprintf(sprintfbuf,fmtstr,argliststart);
590 x=sprintfbuf;
591 while (*x) {
592 ADD_TO_T(*x++);
594 free(sprintfbuf);
595 free(fmtstr);
596 break;
597 case '0':
598 nolinefeed=1;
599 f++;
600 break;
601 default:ADD_TO_T(*f++)
602 break;
605 } else {
606 ADD_TO_T(*f++)
609 *t='\0';
611 if (!nolinefeed && t[-1]!='\n')
612 ADD_TO_T('\n');
613 talloced = strlen(target)+1;
614 if (nSize && talloced<nSize) {
615 target = (char*)xrealloc(target,nSize);
617 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
618 /* nSize is the MINIMUM size */
619 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced);
620 memcpy(*(LPSTR*)lpBuffer,target,talloced);
621 } else
622 strncpy(lpBuffer,target,nSize);
623 free(target);
624 if (from) free(from);
625 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
626 strlen(*(LPSTR*)lpBuffer):
627 strlen(lpBuffer);
630 /***********************************************************************
631 * FormatMessageA (KERNEL32.138) Emulator Version
633 DWORD
634 WIN32_FormatMessage32A(DWORD *args) {
635 DWORD dwFlags = args[0];
636 LPCVOID lpSource = (LPCVOID)args[1];
637 DWORD dwMessageId = args[2];
638 DWORD dwLanguageId = args[3];
639 LPSTR lpBuffer = (LPSTR)args[4];
640 DWORD nSize = args[5];
641 DWORD *xargs;
643 /* convert possible varargs to an argument array look-a-like */
645 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) {
646 xargs=(DWORD*)args[6];
647 } else {
648 /* args[6] is a pointer to a pointer to the start of
649 * a list of arguments.
651 if (args[6])
652 xargs=(DWORD*)(((DWORD*)args[6])[0]);
653 else
654 xargs=NULL;
655 dwFlags|=FORMAT_MESSAGE_ARGUMENT_ARRAY;
657 return FormatMessage32A(
658 dwFlags,
659 lpSource,
660 dwMessageId,
661 dwLanguageId,
662 lpBuffer,
663 nSize,
664 xargs
668 DWORD
669 FormatMessage32W(
670 DWORD dwFlags,
671 LPCVOID lpSource,
672 DWORD dwMessageId,
673 DWORD dwLanguageId,
674 LPWSTR lpBuffer,
675 DWORD nSize,
676 LPDWORD args /* va_list *args */
678 LPSTR target,t;
679 DWORD talloced;
680 LPSTR from,f;
681 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
682 DWORD nolinefeed = 0;
684 dprintf_resource(stddeb,
685 "FormatMessage32A(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
686 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args
688 if (width)
689 fprintf(stdnimp," - line wrapping not supported.\n");
690 from = NULL;
691 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
692 from = STRING32_DupUniToAnsi((LPWSTR)lpSource);
693 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
694 /* gather information from system message tables ... */
695 fprintf(stdnimp," - FORMAT_MESSAGE_FROM_SYSTEM not implemented.\n");
697 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
698 INT32 bufsize;
700 dwMessageId &= 0xFFFF;
701 bufsize=LoadMessage32A(0,dwMessageId,dwLanguageId,NULL,100);
702 if (bufsize) {
703 from = (char*)xmalloc(bufsize+1);
704 LoadMessage32A(0,dwMessageId,dwLanguageId,from,bufsize+1);
707 target = (char*)xmalloc(100);
708 t = target;
709 talloced= 100;
710 *t = 0;
712 #define ADD_TO_T(c) \
713 *t++=c;\
714 if (t-target == talloced) {\
715 target = (char*)xrealloc(target,talloced*2);\
716 t = target+talloced;\
717 talloced*=2;\
720 if (from) {
721 f=from;
722 while (*f) {
723 if (*f=='%') {
724 int insertnr;
725 char *fmtstr,*sprintfbuf,*x;
726 DWORD *argliststart;
728 fmtstr = NULL;
729 f++;
730 if (!*f) {
731 ADD_TO_T('%');
732 continue;
734 switch (*f) {
735 case '1':case '2':case '3':case '4':case '5':
736 case '6':case '7':case '8':case '9':
737 insertnr=*f-'0';
738 switch (f[1]) {
739 case '0':case '1':case '2':case '3':
740 case '4':case '5':case '6':case '7':
741 case '8':case '9':
742 f++;
743 insertnr=insertnr*10+*f-'0';
744 f++;
745 break;
746 default:
747 f++;
748 break;
750 if (*f=='!') {
751 f++;
752 if (NULL!=(x=strchr(f,'!'))) {
753 *x='\0';
754 fmtstr=(char*)xmalloc(strlen(f)+2);
755 sprintf(fmtstr,"%%%s",f);
756 f=x+1;
758 } else
759 fmtstr=strdup("%s");
760 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
761 argliststart=args+insertnr-1;
762 else
763 /* FIXME: not sure that this is
764 * correct for unix-c-varargs.
766 argliststart=((DWORD*)&args)+insertnr-1;
768 if (fmtstr[strlen(fmtstr)]=='s') {
769 DWORD xarr[3];
771 xarr[0]=(DWORD)STRING32_DupUniToAnsi((LPWSTR)(*(argliststart+0)));
772 /* possible invalid pointers */
773 xarr[1]=*(argliststart+1);
774 xarr[2]=*(argliststart+2);
775 sprintfbuf=(char*)xmalloc(lstrlen32W((LPWSTR)argliststart[0])*2+1);
776 vsprintf(sprintfbuf,fmtstr,xarr);
777 } else {
778 sprintfbuf=(char*)xmalloc(100);
779 vsprintf(sprintfbuf,fmtstr,argliststart);
781 x=sprintfbuf;
782 while (*x) {
783 ADD_TO_T(*x++);
785 free(sprintfbuf);
786 free(fmtstr);
787 break;
788 case '0':
789 nolinefeed=1;
790 f++;
791 break;
792 default:ADD_TO_T(*f++)
793 break;
796 } else {
797 ADD_TO_T(*f++)
800 *t='\0';
802 if (!nolinefeed && t[-1]!='\n')
803 ADD_TO_T('\n');
804 talloced = strlen(target)+1;
805 if (nSize && talloced<nSize)
806 target = (char*)xrealloc(target,nSize);
807 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
808 /* nSize is the MINIMUM size */
809 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced*2+2);
810 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
811 } else
812 lstrcpynAtoW(lpBuffer,target,nSize);
813 free(target);
814 if (from) free(from);
815 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
816 lstrlen32W(*(LPWSTR*)lpBuffer):
817 lstrlen32W(lpBuffer);
820 /***********************************************************************
821 * FormatMessageA (KERNEL32.138) Emulator Version
823 DWORD
824 WIN32_FormatMessage32W(DWORD *args) {
825 DWORD dwFlags = args[0];
826 LPCVOID lpSource = (LPCVOID)args[1];
827 DWORD dwMessageId = args[2];
828 DWORD dwLanguageId = args[3];
829 LPWSTR lpBuffer = (LPWSTR)args[4];
830 DWORD nSize = args[5];
831 DWORD *xargs;
833 /* convert possible varargs to an argument array look-a-like */
835 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) {
836 xargs=(DWORD*)args[6];
837 } else {
838 /* args[6] is a pointer to a pointer to the start of
839 * a list of arguments.
841 if (args[6])
842 xargs=(DWORD*)(((DWORD*)args[6])[0]);
843 else
844 xargs=NULL;
845 dwFlags|=FORMAT_MESSAGE_ARGUMENT_ARRAY;
847 return FormatMessage32W(
848 dwFlags,
849 lpSource,
850 dwMessageId,
851 dwLanguageId,
852 lpBuffer,
853 nSize,
854 xargs