2 * USER string functions
4 * Copyright 1993 Yngvi Sigurjonsson (yngvi@hafro.is)
5 * Copyright 1996 Alexandre Julliard
6 * Copyright 1996 Marcus Meissner
20 #include "wine/exception.h"
21 #include "wine/keyboard16.h"
22 #include "wine/unicode.h"
23 #include "wine/winbase16.h"
24 #include "wine/winuser16.h"
26 #include "debugtools.h"
28 DEFAULT_DEBUG_CHANNEL(resource);
30 /* filter for page-fault exceptions */
31 static WINE_EXCEPTION_FILTER(page_fault)
33 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ||
34 GetExceptionCode() == EXCEPTION_PRIV_INSTRUCTION)
35 return EXCEPTION_EXECUTE_HANDLER;
36 return EXCEPTION_CONTINUE_SEARCH;
39 /***********************************************************************
40 * AnsiToOem (KEYBOARD.5)
42 INT16 WINAPI AnsiToOem16( LPCSTR s, LPSTR d )
49 /***********************************************************************
50 * OemToAnsi (KEYBOARD.6)
52 INT16 WINAPI OemToAnsi16( LPCSTR s, LPSTR d )
59 /***********************************************************************
60 * AnsiToOemBuff (KEYBOARD.134)
62 void WINAPI AnsiToOemBuff16( LPCSTR s, LPSTR d, UINT16 len )
64 if (len != 0) CharToOemBuffA( s, d, len );
68 /***********************************************************************
69 * OemToAnsiBuff (KEYBOARD.135)
71 void WINAPI OemToAnsiBuff16( LPCSTR s, LPSTR d, UINT16 len )
73 if (len != 0) OemToCharBuffA( s, d, len );
77 /***********************************************************************
80 INT16 WINAPI lstrcmp16( LPCSTR str1, LPCSTR str2 )
82 return (INT16)strcmp( str1, str2 );
86 /***********************************************************************
87 * AnsiUpper (USER.431)
89 SEGPTR WINAPI AnsiUpper16( SEGPTR strOrChar )
91 /* uppercase only one char if strOrChar < 0x10000 */
92 if (HIWORD(strOrChar))
94 CharUpperA( MapSL(strOrChar) );
97 else return toupper((char)strOrChar);
101 /***********************************************************************
102 * AnsiLower (USER.432)
104 SEGPTR WINAPI AnsiLower16( SEGPTR strOrChar )
106 /* lowercase only one char if strOrChar < 0x10000 */
107 if (HIWORD(strOrChar))
109 CharLowerA( MapSL(strOrChar) );
112 else return tolower((char)strOrChar);
116 /***********************************************************************
117 * AnsiUpperBuff (USER.437)
119 UINT16 WINAPI AnsiUpperBuff16( LPSTR str, UINT16 len )
121 CharUpperBuffA( str, len ? len : 65536 );
126 /***********************************************************************
127 * AnsiLowerBuff (USER.438)
129 UINT16 WINAPI AnsiLowerBuff16( LPSTR str, UINT16 len )
131 CharLowerBuffA( str, len ? len : 65536 );
136 /***********************************************************************
137 * AnsiNext (USER.472)
139 SEGPTR WINAPI AnsiNext16(SEGPTR current)
141 char *ptr = MapSL(current);
142 return current + (CharNextA(ptr) - ptr);
146 /***********************************************************************
147 * AnsiPrev (USER.473)
149 SEGPTR WINAPI AnsiPrev16( LPCSTR start, SEGPTR current )
151 char *ptr = MapSL(current);
152 return current - (ptr - CharPrevA( start, ptr ));
156 /***********************************************************************
157 * CharNextA (USER32.@)
159 LPSTR WINAPI CharNextA( LPCSTR ptr )
161 if (!*ptr) return (LPSTR)ptr;
162 if (IsDBCSLeadByte( ptr[0] ) && ptr[1]) return (LPSTR)(ptr + 2);
163 return (LPSTR)(ptr + 1);
167 /***********************************************************************
168 * CharNextExA (USER32.@)
170 LPSTR WINAPI CharNextExA( WORD codepage, LPCSTR ptr, DWORD flags )
172 if (!*ptr) return (LPSTR)ptr;
173 if (IsDBCSLeadByteEx( codepage, ptr[0] ) && ptr[1]) return (LPSTR)(ptr + 2);
174 return (LPSTR)(ptr + 1);
178 /***********************************************************************
179 * CharNextExW (USER32.@)
181 LPWSTR WINAPI CharNextExW( WORD codepage, LPCWSTR ptr, DWORD flags )
183 /* doesn't make sense, there are no codepages for Unicode */
188 /***********************************************************************
189 * CharNextW (USER32.@)
191 LPWSTR WINAPI CharNextW(LPCWSTR x)
199 /***********************************************************************
200 * CharPrevA (USER32.@)
202 LPSTR WINAPI CharPrevA( LPCSTR start, LPCSTR ptr )
204 while (*start && (start < ptr))
206 LPCSTR next = CharNextA( start );
207 if (next >= ptr) break;
214 /***********************************************************************
215 * CharPrevExA (USER32.@)
217 LPSTR WINAPI CharPrevExA( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
219 while (*start && (start < ptr))
221 LPCSTR next = CharNextExA( codepage, start, flags );
222 if (next > ptr) break;
229 /***********************************************************************
230 * CharPrevExW (USER32.@)
232 LPSTR WINAPI CharPrevExW( WORD codepage, LPCWSTR start, LPCWSTR ptr, DWORD flags )
234 /* doesn't make sense, there are no codepages for Unicode */
239 /***********************************************************************
240 * CharPrevW (USER32.@)
242 LPWSTR WINAPI CharPrevW(LPCWSTR start,LPCWSTR x)
244 if (x>start) return (LPWSTR)(x-1);
245 else return (LPWSTR)x;
249 /***********************************************************************
250 * CharToOemA (USER32.@)
252 BOOL WINAPI CharToOemA( LPCSTR s, LPSTR d )
254 if ( !s || !d ) return TRUE;
255 return CharToOemBuffA( s, d, strlen( s ) + 1 );
259 /***********************************************************************
260 * CharToOemBuffA (USER32.@)
262 BOOL WINAPI CharToOemBuffA( LPCSTR s, LPSTR d, DWORD len )
266 bufW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
269 MultiByteToWideChar( CP_ACP, 0, s, len, bufW, len );
270 WideCharToMultiByte( CP_OEMCP, 0, bufW, len, d, len, NULL, NULL );
271 HeapFree( GetProcessHeap(), 0, bufW );
277 /***********************************************************************
278 * CharToOemBuffW (USER32.@)
280 BOOL WINAPI CharToOemBuffW( LPCWSTR s, LPSTR d, DWORD len )
282 if ( !s || !d ) return TRUE;
283 WideCharToMultiByte( CP_OEMCP, 0, s, len, d, len, NULL, NULL );
288 /***********************************************************************
289 * CharToOemW (USER32.@)
291 BOOL WINAPI CharToOemW( LPCWSTR s, LPSTR d )
293 return CharToOemBuffW( s, d, strlenW( s ) + 1 );
297 /***********************************************************************
298 * OemToCharA (USER32.@)
300 BOOL WINAPI OemToCharA( LPCSTR s, LPSTR d )
302 return OemToCharBuffA( s, d, strlen( s ) + 1 );
306 /***********************************************************************
307 * OemToCharBuffA (USER32.@)
309 BOOL WINAPI OemToCharBuffA( LPCSTR s, LPSTR d, DWORD len )
313 bufW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
316 MultiByteToWideChar( CP_OEMCP, 0, s, len, bufW, len );
317 WideCharToMultiByte( CP_ACP, 0, bufW, len, d, len, NULL, NULL );
318 HeapFree( GetProcessHeap(), 0, bufW );
324 /***********************************************************************
325 * OemToCharBuffW (USER32.@)
327 BOOL WINAPI OemToCharBuffW( LPCSTR s, LPWSTR d, DWORD len )
329 MultiByteToWideChar( CP_OEMCP, 0, s, len, d, len );
334 /***********************************************************************
335 * OemToCharW (USER32.@)
337 BOOL WINAPI OemToCharW( LPCSTR s, LPWSTR d )
339 return OemToCharBuffW( s, d, strlen( s ) + 1 );
343 /***********************************************************************
344 * CharLowerA (USER32.@)
345 * FIXME: handle current locale
347 LPSTR WINAPI CharLowerA(LPSTR x)
349 if (!HIWORD(x)) return (LPSTR)tolower((char)(int)x);
362 SetLastError( ERROR_INVALID_PARAMETER );
370 /***********************************************************************
371 * CharUpperA (USER32.@)
372 * FIXME: handle current locale
374 LPSTR WINAPI CharUpperA(LPSTR x)
376 if (!HIWORD(x)) return (LPSTR)toupper((char)(int)x);
389 SetLastError( ERROR_INVALID_PARAMETER );
397 /***********************************************************************
398 * CharLowerW (USER32.@)
400 LPWSTR WINAPI CharLowerW(LPWSTR x)
402 if (HIWORD(x)) return strlwrW(x);
403 else return (LPWSTR)((UINT)tolowerW(LOWORD(x)));
407 /***********************************************************************
408 * CharUpperW (USER32.@)
410 LPWSTR WINAPI CharUpperW(LPWSTR x)
412 if (HIWORD(x)) return struprW(x);
413 else return (LPWSTR)((UINT)toupperW(LOWORD(x)));
417 /***********************************************************************
418 * CharLowerBuffA (USER32.@)
420 DWORD WINAPI CharLowerBuffA( LPSTR str, DWORD len )
424 if (!str) return 0; /* YES */
426 lenW = MultiByteToWideChar(CP_ACP, 0, str, len, NULL, 0);
427 strW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
430 MultiByteToWideChar(CP_ACP, 0, str, len, strW, lenW);
431 CharLowerBuffW(strW, lenW);
432 len = WideCharToMultiByte(CP_ACP, 0, strW, lenW, str, len, NULL, NULL);
433 HeapFree(GetProcessHeap(), 0, strW);
440 /***********************************************************************
441 * CharLowerBuffW (USER32.@)
443 DWORD WINAPI CharLowerBuffW( LPWSTR str, DWORD len )
446 if (!str) return 0; /* YES */
447 for (; len; len--, str++) *str = tolowerW(*str);
452 /***********************************************************************
453 * CharUpperBuffA (USER32.@)
455 DWORD WINAPI CharUpperBuffA( LPSTR str, DWORD len )
459 if (!str) return 0; /* YES */
461 lenW = MultiByteToWideChar(CP_ACP, 0, str, len, NULL, 0);
462 strW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
465 MultiByteToWideChar(CP_ACP, 0, str, len, strW, lenW);
466 CharUpperBuffW(strW, lenW);
467 len = WideCharToMultiByte(CP_ACP, 0, strW, lenW, str, len, NULL, NULL);
468 HeapFree(GetProcessHeap(), 0, strW);
475 /***********************************************************************
476 * CharUpperBuffW (USER32.@)
478 DWORD WINAPI CharUpperBuffW( LPWSTR str, DWORD len )
481 if (!str) return 0; /* YES */
482 for (; len; len--, str++) *str = toupperW(*str);
487 /***********************************************************************
488 * IsCharLower (USER.436)
489 * IsCharLowerA (USER32.@)
491 BOOL WINAPI IsCharLowerA(CHAR x)
494 MultiByteToWideChar(CP_ACP, 0, &x, 1, &wch, 1);
495 return IsCharLowerW(wch);
499 /***********************************************************************
500 * IsCharLowerW (USER32.@)
502 BOOL WINAPI IsCharLowerW(WCHAR x)
504 return (get_char_typeW(x) & C1_LOWER) != 0;
508 /***********************************************************************
509 * IsCharUpper (USER.435)
510 * IsCharUpperA (USER32.@)
512 BOOL WINAPI IsCharUpperA(CHAR x)
515 MultiByteToWideChar(CP_ACP, 0, &x, 1, &wch, 1);
516 return IsCharUpperW(wch);
520 /***********************************************************************
521 * IsCharUpperW (USER32.@)
523 BOOL WINAPI IsCharUpperW(WCHAR x)
525 return (get_char_typeW(x) & C1_UPPER) != 0;
529 /***********************************************************************
530 * IsCharAlphaNumeric (USER.434)
531 * IsCharAlphaNumericA (USER32.@)
533 BOOL WINAPI IsCharAlphaNumericA(CHAR x)
536 MultiByteToWideChar(CP_ACP, 0, &x, 1, &wch, 1);
537 return IsCharAlphaNumericW(wch);
541 /***********************************************************************
542 * IsCharAlphaNumericW (USER32.@)
544 BOOL WINAPI IsCharAlphaNumericW(WCHAR x)
546 return (get_char_typeW(x) & (C1_ALPHA|C1_DIGIT)) != 0;
550 /***********************************************************************
551 * IsCharAlpha (USER.433)
552 * IsCharAlphaA (USER32.@)
554 BOOL WINAPI IsCharAlphaA(CHAR x)
557 MultiByteToWideChar(CP_ACP, 0, &x, 1, &wch, 1);
558 return IsCharAlphaW(wch);
562 /***********************************************************************
563 * IsCharAlphaW (USER32.@)
565 BOOL WINAPI IsCharAlphaW(WCHAR x)
567 return (get_char_typeW(x) & C1_ALPHA) != 0;
571 /***********************************************************************
572 * FormatMessage (USER.606)
574 DWORD WINAPI FormatMessage16(
576 SEGPTR lpSource, /* [in] NOTE: not always a valid pointer */
579 LPSTR lpBuffer, /* [out] NOTE: *((HLOCAL16*)) for FORMAT_MESSAGE_ALLOCATE_BUFFER*/
581 LPDWORD args /* [in] NOTE: va_list *args */
584 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
588 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
590 LPSTR allocstring = NULL;
592 TRACE("(0x%lx,%lx,%d,0x%x,%p,%d,%p)\n",
593 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
594 if ((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
595 && (dwFlags & FORMAT_MESSAGE_FROM_HMODULE)) return 0;
596 if ((dwFlags & FORMAT_MESSAGE_FROM_STRING)
597 &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
598 || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0;
600 if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK)
601 FIXME("line wrapping (%lu) not supported.\n", width);
603 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
605 char *source = MapSL(lpSource);
606 from = HeapAlloc( GetProcessHeap(), 0, strlen(source)+1 );
607 strcpy( from, source );
609 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
610 from = HeapAlloc( GetProcessHeap(),0,200 );
611 sprintf(from,"Systemmessage, messageid = 0x%08x\n",dwMessageId);
613 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
615 HINSTANCE16 hinst16 = ((HMODULE)lpSource & 0xffff);
617 dwMessageId &= 0xFFFF;
618 bufsize=LoadString16(hinst16,dwMessageId,NULL,0);
620 from = HeapAlloc( GetProcessHeap(), 0, bufsize +1);
621 LoadString16(hinst16,dwMessageId,from,bufsize+1);
624 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
628 #define ADD_TO_T(c) \
630 if (t-target == talloced) {\
631 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
632 t = target+talloced;\
641 char *fmtstr,*x,*lastf;
652 case '1':case '2':case '3':case '4':case '5':
653 case '6':case '7':case '8':case '9':
656 case '0':case '1':case '2':case '3':
657 case '4':case '5':case '6':case '7':
660 insertnr=insertnr*10+*f-'0';
669 if (NULL!=(x=strchr(f,'!'))) {
671 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
672 sprintf(fmtstr,"%%%s",f);
675 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
676 sprintf(fmtstr,"%%%s",f);
677 f+=strlen(f); /*at \0*/
683 fmtstr=HeapAlloc( GetProcessHeap(), 0, 3 );
684 strcpy( fmtstr, "%s" );
688 LPSTR b = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz = 100);
690 argliststart=args+insertnr-1;
692 /* CMF - This makes a BIG assumption about va_list */
693 while (vsnprintf(b, sz, fmtstr, (va_list) argliststart) < 0) {
694 b = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, b, sz += 100);
696 for (x=b; *x; x++) ADD_TO_T(*x);
698 /* NULL args - copy formatstr
701 while ((lastf<f)&&(*lastf)) {
705 HeapFree(GetProcessHeap(),0,fmtstr);
707 case '0': /* Just stop processing format string */
711 case 'n': /* 16 bit version just outputs 'n' */
716 } else { /* '\n' or '\r' gets mapped to "\r\n" */
717 if(*f == '\n' || *f == '\r') {
721 if(*f++ == '\r' && *f == '\n')
731 talloced = strlen(target)+1;
732 if (nSize && talloced<nSize) {
733 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
735 TRACE("-- %s\n",debugstr_a(target));
736 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
737 /* nSize is the MINIMUM size */
738 HLOCAL16 h = LocalAlloc16(LPTR,talloced);
739 SEGPTR ptr = LocalLock16(h);
740 allocstring = MapSL( ptr );
741 memcpy( allocstring,target,talloced);
743 *((HLOCAL16*)lpBuffer) = h;
745 lstrcpynA(lpBuffer,target,nSize);
746 HeapFree(GetProcessHeap(),0,target);
747 if (from) HeapFree(GetProcessHeap(),0,from);
748 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
753 #endif /* __i386__ */