Move excpt.h out of include/msvcrt/ as it does not conflict with any
[wine] / dlls / user / lstr.c
1 /*
2  * USER string functions
3  *
4  * Copyright 1993 Yngvi Sigurjonsson (yngvi@hafro.is)
5  * Copyright 1996 Alexandre Julliard
6  * Copyright 1996 Marcus Meissner
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include <ctype.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "winbase.h"
32 #include "winerror.h"
33
34 #include "wine/exception.h"
35 #include "wine/unicode.h"
36 #include "wine/winbase16.h"
37 #include "wine/winuser16.h"
38
39 #include "excpt.h"
40
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(resource);
44
45 /* filter for page-fault exceptions */
46 static WINE_EXCEPTION_FILTER(page_fault)
47 {
48     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ||
49         GetExceptionCode() == EXCEPTION_PRIV_INSTRUCTION)
50         return EXCEPTION_EXECUTE_HANDLER;
51     return EXCEPTION_CONTINUE_SEARCH;
52 }
53
54 /***********************************************************************
55  *           AnsiToOem   (KEYBOARD.5)
56  */
57 INT16 WINAPI AnsiToOem16( LPCSTR s, LPSTR d )
58 {
59     CharToOemA( s, d );
60     return -1;
61 }
62
63
64 /***********************************************************************
65  *           OemToAnsi   (KEYBOARD.6)
66  */
67 INT16 WINAPI OemToAnsi16( LPCSTR s, LPSTR d )
68 {
69     OemToCharA( s, d );
70     return -1;
71 }
72
73
74 /***********************************************************************
75  *           AnsiToOemBuff   (KEYBOARD.134)
76  */
77 void WINAPI AnsiToOemBuff16( LPCSTR s, LPSTR d, UINT16 len )
78 {
79     if (len != 0) CharToOemBuffA( s, d, len );
80 }
81
82
83 /***********************************************************************
84  *           OemToAnsiBuff   (KEYBOARD.135)
85  */
86 void WINAPI OemToAnsiBuff16( LPCSTR s, LPSTR d, UINT16 len )
87 {
88     if (len != 0) OemToCharBuffA( s, d, len );
89 }
90
91
92 /***********************************************************************
93  *           lstrcmp   (USER.430)
94  */
95 INT16 WINAPI lstrcmp16( LPCSTR str1, LPCSTR str2 )
96 {
97     return (INT16)strcmp( str1, str2 );
98 }
99
100
101 /***********************************************************************
102  *           AnsiUpper   (USER.431)
103  */
104 SEGPTR WINAPI AnsiUpper16( SEGPTR strOrChar )
105 {
106     /* uppercase only one char if strOrChar < 0x10000 */
107     if (HIWORD(strOrChar))
108     {
109         CharUpperA( MapSL(strOrChar) );
110         return strOrChar;
111     }
112     else return toupper((char)strOrChar);
113 }
114
115
116 /***********************************************************************
117  *           AnsiLower   (USER.432)
118  */
119 SEGPTR WINAPI AnsiLower16( SEGPTR strOrChar )
120 {
121     /* lowercase only one char if strOrChar < 0x10000 */
122     if (HIWORD(strOrChar))
123     {
124         CharLowerA( MapSL(strOrChar) );
125         return strOrChar;
126     }
127     else return tolower((char)strOrChar);
128 }
129
130
131 /***********************************************************************
132  *           AnsiUpperBuff   (USER.437)
133  */
134 UINT16 WINAPI AnsiUpperBuff16( LPSTR str, UINT16 len )
135 {
136     CharUpperBuffA( str, len ? len : 65536 );
137     return len;
138 }
139
140
141 /***********************************************************************
142  *           AnsiLowerBuff   (USER.438)
143  */
144 UINT16 WINAPI AnsiLowerBuff16( LPSTR str, UINT16 len )
145 {
146     CharLowerBuffA( str, len ? len : 65536 );
147     return len;
148 }
149
150
151 /***********************************************************************
152  *           AnsiNext   (USER.472)
153  */
154 SEGPTR WINAPI AnsiNext16(SEGPTR current)
155 {
156     char *ptr = MapSL(current);
157     return current + (CharNextA(ptr) - ptr);
158 }
159
160
161 /***********************************************************************
162  *           AnsiPrev   (USER.473)
163  */
164 SEGPTR WINAPI AnsiPrev16( LPCSTR start, SEGPTR current )
165 {
166     char *ptr = MapSL(current);
167     return current - (ptr - CharPrevA( start, ptr ));
168 }
169
170
171 /***********************************************************************
172  *           CharNextA   (USER32.@)
173  */
174 LPSTR WINAPI CharNextA( LPCSTR ptr )
175 {
176     if (!*ptr) return (LPSTR)ptr;
177     if (IsDBCSLeadByte( ptr[0] ) && ptr[1]) return (LPSTR)(ptr + 2);
178     return (LPSTR)(ptr + 1);
179 }
180
181
182 /***********************************************************************
183  *           CharNextExA   (USER32.@)
184  */
185 LPSTR WINAPI CharNextExA( WORD codepage, LPCSTR ptr, DWORD flags )
186 {
187     if (!*ptr) return (LPSTR)ptr;
188     if (IsDBCSLeadByteEx( codepage, ptr[0] ) && ptr[1]) return (LPSTR)(ptr + 2);
189     return (LPSTR)(ptr + 1);
190 }
191
192
193 /***********************************************************************
194  *           CharNextExW   (USER32.@)
195  */
196 LPWSTR WINAPI CharNextExW( WORD codepage, LPCWSTR ptr, DWORD flags )
197 {
198     /* doesn't make sense, there are no codepages for Unicode */
199     return NULL;
200 }
201
202
203 /***********************************************************************
204  *           CharNextW   (USER32.@)
205  */
206 LPWSTR WINAPI CharNextW(LPCWSTR x)
207 {
208     if (*x) x++;
209
210     return (LPWSTR)x;
211 }
212
213
214 /***********************************************************************
215  *           CharPrevA   (USER32.@)
216  */
217 LPSTR WINAPI CharPrevA( LPCSTR start, LPCSTR ptr )
218 {
219     while (*start && (start < ptr))
220     {
221         LPCSTR next = CharNextA( start );
222         if (next >= ptr) break;
223         start = next;
224     }
225     return (LPSTR)start;
226 }
227
228
229 /***********************************************************************
230  *           CharPrevExA   (USER32.@)
231  */
232 LPSTR WINAPI CharPrevExA( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
233 {
234     while (*start && (start < ptr))
235     {
236         LPCSTR next = CharNextExA( codepage, start, flags );
237         if (next > ptr) break;
238         start = next;
239     }
240     return (LPSTR)start;
241 }
242
243
244 /***********************************************************************
245  *           CharPrevExW   (USER32.@)
246  */
247 LPSTR WINAPI CharPrevExW( WORD codepage, LPCWSTR start, LPCWSTR ptr, DWORD flags )
248 {
249     /* doesn't make sense, there are no codepages for Unicode */
250     return NULL;
251 }
252
253
254 /***********************************************************************
255  *           CharPrevW   (USER32.@)
256  */
257 LPWSTR WINAPI CharPrevW(LPCWSTR start,LPCWSTR x)
258 {
259     if (x>start) return (LPWSTR)(x-1);
260     else return (LPWSTR)x;
261 }
262
263
264 /***********************************************************************
265  *           CharToOemA   (USER32.@)
266  */
267 BOOL WINAPI CharToOemA( LPCSTR s, LPSTR d )
268 {
269     if ( !s || !d ) return TRUE;
270     return CharToOemBuffA( s, d, strlen( s ) + 1 );
271 }
272
273
274 /***********************************************************************
275  *           CharToOemBuffA   (USER32.@)
276  */
277 BOOL WINAPI CharToOemBuffA( LPCSTR s, LPSTR d, DWORD len )
278 {
279     WCHAR *bufW;
280
281     bufW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
282     if( bufW )
283     {
284         MultiByteToWideChar( CP_ACP, 0, s, len, bufW, len );
285         WideCharToMultiByte( CP_OEMCP, 0, bufW, len, d, len, NULL, NULL );
286         HeapFree( GetProcessHeap(), 0, bufW );
287     }
288     return TRUE;
289 }
290
291
292 /***********************************************************************
293  *           CharToOemBuffW   (USER32.@)
294  */
295 BOOL WINAPI CharToOemBuffW( LPCWSTR s, LPSTR d, DWORD len )
296 {
297    if ( !s || !d ) return TRUE;
298     WideCharToMultiByte( CP_OEMCP, 0, s, len, d, len, NULL, NULL );
299     return TRUE;
300 }
301
302
303 /***********************************************************************
304  *           CharToOemW   (USER32.@)
305  */
306 BOOL WINAPI CharToOemW( LPCWSTR s, LPSTR d )
307 {
308     return CharToOemBuffW( s, d, strlenW( s ) + 1 );
309 }
310
311
312 /***********************************************************************
313  *           OemToCharA   (USER32.@)
314  */
315 BOOL WINAPI OemToCharA( LPCSTR s, LPSTR d )
316 {
317     return OemToCharBuffA( s, d, strlen( s ) + 1 );
318 }
319
320
321 /***********************************************************************
322  *           OemToCharBuffA   (USER32.@)
323  */
324 BOOL WINAPI OemToCharBuffA( LPCSTR s, LPSTR d, DWORD len )
325 {
326     WCHAR *bufW;
327
328     bufW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
329     if( bufW )
330     {
331         MultiByteToWideChar( CP_OEMCP, 0, s, len, bufW, len );
332         WideCharToMultiByte( CP_ACP, 0, bufW, len, d, len, NULL, NULL );
333         HeapFree( GetProcessHeap(), 0, bufW );
334     }
335     return TRUE;
336 }
337
338
339 /***********************************************************************
340  *           OemToCharBuffW   (USER32.@)
341  */
342 BOOL WINAPI OemToCharBuffW( LPCSTR s, LPWSTR d, DWORD len )
343 {
344     MultiByteToWideChar( CP_OEMCP, 0, s, len, d, len );
345     return TRUE;
346 }
347
348
349 /***********************************************************************
350  *           OemToCharW   (USER32.@)
351  */
352 BOOL WINAPI OemToCharW( LPCSTR s, LPWSTR d )
353 {
354     return OemToCharBuffW( s, d, strlen( s ) + 1 );
355 }
356
357
358 /***********************************************************************
359  *           CharLowerA   (USER32.@)
360  * FIXME: handle current locale
361  */
362 LPSTR WINAPI CharLowerA(LPSTR x)
363 {
364     if (!HIWORD(x)) return (LPSTR)tolower((char)(int)x);
365
366     __TRY
367     {
368         LPSTR s = x;
369         while (*s)
370         {
371             *s=tolower(*s);
372             s++;
373         }
374     }
375     __EXCEPT(page_fault)
376     {
377         SetLastError( ERROR_INVALID_PARAMETER );
378         return NULL;
379     }
380     __ENDTRY
381     return x;
382 }
383
384
385 /***********************************************************************
386  *           CharUpperA   (USER32.@)
387  * FIXME: handle current locale
388  */
389 LPSTR WINAPI CharUpperA(LPSTR x)
390 {
391     if (!HIWORD(x)) return (LPSTR)toupper((char)(int)x);
392
393     __TRY
394     {
395         LPSTR s = x;
396         while (*s)
397         {
398             *s=toupper(*s);
399             s++;
400         }
401     }
402     __EXCEPT(page_fault)
403     {
404         SetLastError( ERROR_INVALID_PARAMETER );
405         return NULL;
406     }
407     __ENDTRY
408     return x;
409 }
410
411
412 /***********************************************************************
413  *           CharLowerW   (USER32.@)
414  */
415 LPWSTR WINAPI CharLowerW(LPWSTR x)
416 {
417     if (HIWORD(x)) return strlwrW(x);
418     else return (LPWSTR)((UINT)tolowerW(LOWORD(x)));
419 }
420
421
422 /***********************************************************************
423  *           CharUpperW   (USER32.@)
424  */
425 LPWSTR WINAPI CharUpperW(LPWSTR x)
426 {
427     if (HIWORD(x)) return struprW(x);
428     else return (LPWSTR)((UINT)toupperW(LOWORD(x)));
429 }
430
431
432 /***********************************************************************
433  *           CharLowerBuffA   (USER32.@)
434  */
435 DWORD WINAPI CharLowerBuffA( LPSTR str, DWORD len )
436 {
437     DWORD lenW;
438     WCHAR *strW;
439     if (!str) return 0; /* YES */
440
441     lenW = MultiByteToWideChar(CP_ACP, 0, str, len, NULL, 0);
442     strW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
443     if(strW)
444     {
445         MultiByteToWideChar(CP_ACP, 0, str, len, strW, lenW);
446         CharLowerBuffW(strW, lenW);
447         len = WideCharToMultiByte(CP_ACP, 0, strW, lenW, str, len, NULL, NULL);
448         HeapFree(GetProcessHeap(), 0, strW);
449         return len;
450     }
451     return 0;
452 }
453
454
455 /***********************************************************************
456  *           CharLowerBuffW   (USER32.@)
457  */
458 DWORD WINAPI CharLowerBuffW( LPWSTR str, DWORD len )
459 {
460     DWORD ret = len;
461     if (!str) return 0; /* YES */
462     for (; len; len--, str++) *str = tolowerW(*str);
463     return ret;
464 }
465
466
467 /***********************************************************************
468  *           CharUpperBuffA   (USER32.@)
469  */
470 DWORD WINAPI CharUpperBuffA( LPSTR str, DWORD len )
471 {
472     DWORD lenW;
473     WCHAR *strW;
474     if (!str) return 0; /* YES */
475
476     lenW = MultiByteToWideChar(CP_ACP, 0, str, len, NULL, 0);
477     strW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
478     if(strW)
479     {
480         MultiByteToWideChar(CP_ACP, 0, str, len, strW, lenW);
481         CharUpperBuffW(strW, lenW);
482         len = WideCharToMultiByte(CP_ACP, 0, strW, lenW, str, len, NULL, NULL);
483         HeapFree(GetProcessHeap(), 0, strW);
484         return len;
485     }
486     return 0;
487 }
488
489
490 /***********************************************************************
491  *           CharUpperBuffW   (USER32.@)
492  */
493 DWORD WINAPI CharUpperBuffW( LPWSTR str, DWORD len )
494 {
495     DWORD ret = len;
496     if (!str) return 0; /* YES */
497     for (; len; len--, str++) *str = toupperW(*str);
498     return ret;
499 }
500
501
502 /***********************************************************************
503  *           IsCharLower    (USER.436)
504  *           IsCharLowerA   (USER32.@)
505  */
506 BOOL WINAPI IsCharLowerA(CHAR x)
507 {
508     WCHAR wch;
509     MultiByteToWideChar(CP_ACP, 0, &x, 1, &wch, 1);
510     return IsCharLowerW(wch);
511 }
512
513
514 /***********************************************************************
515  *           IsCharLowerW   (USER32.@)
516  */
517 BOOL WINAPI IsCharLowerW(WCHAR x)
518 {
519     return (get_char_typeW(x) & C1_LOWER) != 0;
520 }
521
522
523 /***********************************************************************
524  *           IsCharUpper    (USER.435)
525  *           IsCharUpperA   (USER32.@)
526  */
527 BOOL WINAPI IsCharUpperA(CHAR x)
528 {
529     WCHAR wch;
530     MultiByteToWideChar(CP_ACP, 0, &x, 1, &wch, 1);
531     return IsCharUpperW(wch);
532 }
533
534
535 /***********************************************************************
536  *           IsCharUpperW   (USER32.@)
537  */
538 BOOL WINAPI IsCharUpperW(WCHAR x)
539 {
540     return (get_char_typeW(x) & C1_UPPER) != 0;
541 }
542
543
544 /***********************************************************************
545  *           IsCharAlphaNumeric    (USER.434)
546  *           IsCharAlphaNumericA   (USER32.@)
547  */
548 BOOL WINAPI IsCharAlphaNumericA(CHAR x)
549 {
550     WCHAR wch;
551     MultiByteToWideChar(CP_ACP, 0, &x, 1, &wch, 1);
552     return IsCharAlphaNumericW(wch);
553 }
554
555
556 /***********************************************************************
557  *           IsCharAlphaNumericW   (USER32.@)
558  */
559 BOOL WINAPI IsCharAlphaNumericW(WCHAR x)
560 {
561     return (get_char_typeW(x) & (C1_ALPHA|C1_DIGIT)) != 0;
562 }
563
564
565 /***********************************************************************
566  *           IsCharAlpha    (USER.433)
567  *           IsCharAlphaA   (USER32.@)
568  */
569 BOOL WINAPI IsCharAlphaA(CHAR x)
570 {
571     WCHAR wch;
572     MultiByteToWideChar(CP_ACP, 0, &x, 1, &wch, 1);
573     return IsCharAlphaW(wch);
574 }
575
576
577 /***********************************************************************
578  *           IsCharAlphaW   (USER32.@)
579  */
580 BOOL WINAPI IsCharAlphaW(WCHAR x)
581 {
582     return (get_char_typeW(x) & C1_ALPHA) != 0;
583 }
584
585
586 /***********************************************************************
587  *           FormatMessage   (USER.606)
588  */
589 DWORD WINAPI FormatMessage16(
590     DWORD   dwFlags,
591     SEGPTR lpSource,     /* [in] NOTE: not always a valid pointer */
592     WORD   dwMessageId,
593     WORD   dwLanguageId,
594     LPSTR  lpBuffer,     /* [out] NOTE: *((HLOCAL16*)) for FORMAT_MESSAGE_ALLOCATE_BUFFER*/
595     WORD   nSize,
596     LPDWORD args         /* [in] NOTE: va_list *args */
597 ) {
598 #ifdef __i386__
599 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
600     LPSTR       target,t;
601     DWORD       talloced;
602     LPSTR       from,f;
603     DWORD       width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
604     BOOL        eos = FALSE;
605     LPSTR       allocstring = NULL;
606
607     TRACE("(0x%lx,%lx,%d,0x%x,%p,%d,%p)\n",
608           dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
609         if ((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
610                 && (dwFlags & FORMAT_MESSAGE_FROM_HMODULE)) return 0;
611         if ((dwFlags & FORMAT_MESSAGE_FROM_STRING)
612                 &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
613                         || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0;
614
615     if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK)
616         FIXME("line wrapping (%lu) not supported.\n", width);
617     from = NULL;
618     if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
619     {
620         char *source = MapSL(lpSource);
621         from = HeapAlloc( GetProcessHeap(), 0, strlen(source)+1 );
622         strcpy( from, source );
623     }
624     if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
625         from = HeapAlloc( GetProcessHeap(),0,200 );
626         sprintf(from,"Systemmessage, messageid = 0x%08x\n",dwMessageId);
627     }
628     if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
629         INT16   bufsize;
630         HINSTANCE16 hinst16 = ((HINSTANCE16)lpSource & 0xffff);
631
632         dwMessageId &= 0xFFFF;
633         bufsize=LoadString16(hinst16,dwMessageId,NULL,0);
634         if (bufsize) {
635             from = HeapAlloc( GetProcessHeap(), 0, bufsize +1);
636             LoadString16(hinst16,dwMessageId,from,bufsize+1);
637         }
638     }
639     target      = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
640     t   = target;
641     talloced= 100;
642
643 #define ADD_TO_T(c) \
644         *t++=c;\
645         if (t-target == talloced) {\
646                 target  = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
647                 t       = target+talloced;\
648                 talloced*=2;\
649         }
650
651     if (from) {
652         f=from;
653         while (*f && !eos) {
654             if (*f=='%') {
655                 int     insertnr;
656                 char    *fmtstr,*x,*lastf;
657                 DWORD   *argliststart;
658
659                 fmtstr = NULL;
660                 lastf = f;
661                 f++;
662                 if (!*f) {
663                     ADD_TO_T('%');
664                     continue;
665                 }
666                 switch (*f) {
667                 case '1':case '2':case '3':case '4':case '5':
668                 case '6':case '7':case '8':case '9':
669                     insertnr=*f-'0';
670                     switch (f[1]) {
671                     case '0':case '1':case '2':case '3':
672                     case '4':case '5':case '6':case '7':
673                     case '8':case '9':
674                         f++;
675                         insertnr=insertnr*10+*f-'0';
676                         f++;
677                         break;
678                     default:
679                         f++;
680                         break;
681                     }
682                     if (*f=='!') {
683                         f++;
684                         if (NULL!=(x=strchr(f,'!'))) {
685                             *x='\0';
686                             fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
687                             sprintf(fmtstr,"%%%s",f);
688                             f=x+1;
689                         } else {
690                             fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
691                             sprintf(fmtstr,"%%%s",f);
692                             f+=strlen(f); /*at \0*/
693                         }
694                     }
695                     else
696                     {
697                         if(!args) break;
698                         fmtstr=HeapAlloc( GetProcessHeap(), 0, 3 );
699                         strcpy( fmtstr, "%s" );
700                     }
701                     if (args) {
702                         int     ret;
703                         int     sz;
704                         LPSTR   b = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz = 100);
705
706                         argliststart=args+insertnr-1;
707
708                         /* CMF - This makes a BIG assumption about va_list */
709                         while ((ret = vsnprintf(b, sz, fmtstr, (va_list) argliststart) < 0) || (ret >= sz)) {
710                             sz = (ret == -1 ? sz + 100 : ret + 1);
711                             b = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, b, sz);
712                         }
713                         for (x=b; *x; x++) ADD_TO_T(*x);
714                         HeapFree(GetProcessHeap(), 0, b);
715                     } else {
716                         /* NULL args - copy formatstr
717                          * (probably wrong)
718                          */
719                         while ((lastf<f)&&(*lastf)) {
720                             ADD_TO_T(*lastf++);
721                         }
722                     }
723                     HeapFree(GetProcessHeap(),0,fmtstr);
724                     break;
725                 case '0': /* Just stop processing format string */
726                     eos = TRUE;
727                     f++;
728                     break;
729                 case 'n': /* 16 bit version just outputs 'n' */
730                 default:
731                     ADD_TO_T(*f++);
732                     break;
733                 }
734             } else { /* '\n' or '\r' gets mapped to "\r\n" */
735                 if(*f == '\n' || *f == '\r') {
736                     if (width == 0) {
737                         ADD_TO_T('\r');
738                         ADD_TO_T('\n');
739                         if(*f++ == '\r' && *f == '\n')
740                             f++;
741                     }
742                 } else {
743                     ADD_TO_T(*f++);
744                 }
745             }
746         }
747         *t='\0';
748     }
749     talloced = strlen(target)+1;
750     if (nSize && talloced<nSize) {
751         target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
752     }
753     TRACE("-- %s\n",debugstr_a(target));
754     if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
755         /* nSize is the MINIMUM size */
756         HLOCAL16 h = LocalAlloc16(LPTR,talloced);
757         SEGPTR ptr = LocalLock16(h);
758         allocstring = MapSL( ptr );
759         memcpy( allocstring,target,talloced);
760         LocalUnlock16( h );
761         *((HLOCAL16*)lpBuffer) = h;
762     } else
763         lstrcpynA(lpBuffer,target,nSize);
764     HeapFree(GetProcessHeap(),0,target);
765     if (from) HeapFree(GetProcessHeap(),0,from);
766     return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
767         strlen(allocstring):
768         strlen(lpBuffer);
769 #else
770         return 0;
771 #endif /* __i386__ */
772 }
773 #undef ADD_TO_T