Make the DllRegisterServer, DllRegisterServerEx, DllUnregisterServer,
[wine] / dlls / user / wsprintf.c
1 /*
2  * wsprintf functions
3  *
4  * Copyright 1996 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * NOTE:
21  * This code is duplicated in shlwapi. If you change something here make sure
22  * to change it in shlwapi too.
23  */
24
25 #include <stdarg.h>
26 #include <string.h>
27 #include <stdio.h>
28
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32
33 #include "wine/winbase16.h"
34 #include "wine/winuser16.h"
35 #include "stackframe.h"
36
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(string);
40
41
42 #define WPRINTF_LEFTALIGN   0x0001  /* Align output on the left ('-' prefix) */
43 #define WPRINTF_PREFIX_HEX  0x0002  /* Prefix hex with 0x ('#' prefix) */
44 #define WPRINTF_ZEROPAD     0x0004  /* Pad with zeros ('0' prefix) */
45 #define WPRINTF_LONG        0x0008  /* Long arg ('l' prefix) */
46 #define WPRINTF_SHORT       0x0010  /* Short arg ('h' prefix) */
47 #define WPRINTF_UPPER_HEX   0x0020  /* Upper-case hex ('X' specifier) */
48 #define WPRINTF_WIDE        0x0040  /* Wide arg ('w' prefix) */
49
50 typedef enum
51 {
52     WPR_UNKNOWN,
53     WPR_CHAR,
54     WPR_WCHAR,
55     WPR_STRING,
56     WPR_WSTRING,
57     WPR_SIGNED,
58     WPR_UNSIGNED,
59     WPR_HEXA
60 } WPRINTF_TYPE;
61
62 typedef struct
63 {
64     UINT         flags;
65     UINT         width;
66     UINT         precision;
67     WPRINTF_TYPE   type;
68 } WPRINTF_FORMAT;
69
70 typedef union {
71     WCHAR   wchar_view;
72     CHAR    char_view;
73     LPCSTR  lpcstr_view;
74     LPCWSTR lpcwstr_view;
75     INT     int_view;
76 } WPRINTF_DATA;
77
78 static const CHAR null_stringA[] = "(null)";
79 static const WCHAR null_stringW[] = { '(', 'n', 'u', 'l', 'l', ')', 0 };
80
81 /***********************************************************************
82  *           WPRINTF_ParseFormatA
83  *
84  * Parse a format specification. A format specification has the form:
85  *
86  * [-][#][0][width][.precision]type
87  *
88  * Return value is the length of the format specification in characters.
89  */
90 static INT WPRINTF_ParseFormatA( LPCSTR format, WPRINTF_FORMAT *res )
91 {
92     LPCSTR p = format;
93
94     res->flags = 0;
95     res->width = 0;
96     res->precision = 0;
97     if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; }
98     if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; }
99     if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; }
100     while ((*p >= '0') && (*p <= '9'))  /* width field */
101     {
102         res->width = res->width * 10 + *p - '0';
103         p++;
104     }
105     if (*p == '.')  /* precision field */
106     {
107         p++;
108         while ((*p >= '0') && (*p <= '9'))
109         {
110             res->precision = res->precision * 10 + *p - '0';
111             p++;
112         }
113     }
114     if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; }
115     else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; }
116     else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; }
117     switch(*p)
118     {
119     case 'c':
120         res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
121         break;
122     case 'C':
123         res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
124         break;
125     case 'd':
126     case 'i':
127         res->type = WPR_SIGNED;
128         break;
129     case 's':
130         res->type = (res->flags & (WPRINTF_LONG |WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING;
131         break;
132     case 'S':
133         res->type = (res->flags & (WPRINTF_SHORT|WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING;
134         break;
135     case 'u':
136         res->type = WPR_UNSIGNED;
137         break;
138     case 'p':
139         res->width = 8;
140         res->flags |= WPRINTF_ZEROPAD;
141         /* fall through */
142     case 'X':
143         res->flags |= WPRINTF_UPPER_HEX;
144         /* fall through */
145     case 'x':
146         res->type = WPR_HEXA;
147         break;
148     default: /* unknown format char */
149         res->type = WPR_UNKNOWN;
150         p--;  /* print format as normal char */
151         break;
152     }
153     return (INT)(p - format) + 1;
154 }
155
156
157 /***********************************************************************
158  *           WPRINTF_ParseFormatW
159  *
160  * Parse a format specification. A format specification has the form:
161  *
162  * [-][#][0][width][.precision]type
163  *
164  * Return value is the length of the format specification in characters.
165  */
166 static INT WPRINTF_ParseFormatW( LPCWSTR format, WPRINTF_FORMAT *res )
167 {
168     LPCWSTR p = format;
169
170     res->flags = 0;
171     res->width = 0;
172     res->precision = 0;
173     if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; }
174     if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; }
175     if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; }
176     while ((*p >= '0') && (*p <= '9'))  /* width field */
177     {
178         res->width = res->width * 10 + *p - '0';
179         p++;
180     }
181     if (*p == '.')  /* precision field */
182     {
183         p++;
184         while ((*p >= '0') && (*p <= '9'))
185         {
186             res->precision = res->precision * 10 + *p - '0';
187             p++;
188         }
189     }
190     if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; }
191     else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; }
192     else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; }
193     switch((CHAR)*p)
194     {
195     case 'c':
196         res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
197         break;
198     case 'C':
199         res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
200         break;
201     case 'd':
202     case 'i':
203         res->type = WPR_SIGNED;
204         break;
205     case 's':
206         res->type = ((res->flags & WPRINTF_SHORT) && !(res->flags & WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING;
207         break;
208     case 'S':
209         res->type = (res->flags & (WPRINTF_LONG|WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING;
210         break;
211     case 'u':
212         res->type = WPR_UNSIGNED;
213         break;
214     case 'p':
215         res->width = 8;
216         res->flags |= WPRINTF_ZEROPAD;
217         /* fall through */
218     case 'X':
219         res->flags |= WPRINTF_UPPER_HEX;
220         /* fall through */
221     case 'x':
222         res->type = WPR_HEXA;
223         break;
224     default:
225         res->type = WPR_UNKNOWN;
226         p--;  /* print format as normal char */
227         break;
228     }
229     return (INT)(p - format) + 1;
230 }
231
232
233 /***********************************************************************
234  *           WPRINTF_GetLen
235  */
236 static UINT WPRINTF_GetLen( WPRINTF_FORMAT *format, WPRINTF_DATA *arg,
237                               LPSTR number, UINT maxlen )
238 {
239     UINT len;
240
241     if (format->flags & WPRINTF_LEFTALIGN) format->flags &= ~WPRINTF_ZEROPAD;
242     if (format->width > maxlen) format->width = maxlen;
243     switch(format->type)
244     {
245     case WPR_CHAR:
246     case WPR_WCHAR:
247         return (format->precision = 1);
248     case WPR_STRING:
249         if (!arg->lpcstr_view) arg->lpcstr_view = null_stringA;
250         for (len = 0; !format->precision || (len < format->precision); len++)
251             if (!*(arg->lpcstr_view + len)) break;
252         if (len > maxlen) len = maxlen;
253         return (format->precision = len);
254     case WPR_WSTRING:
255         if (!arg->lpcwstr_view) arg->lpcwstr_view = null_stringW;
256         for (len = 0; !format->precision || (len < format->precision); len++)
257             if (!*(arg->lpcwstr_view + len)) break;
258         if (len > maxlen) len = maxlen;
259         return (format->precision = len);
260     case WPR_SIGNED:
261         len = sprintf( number, "%d", arg->int_view );
262         break;
263     case WPR_UNSIGNED:
264         len = sprintf( number, "%u", (UINT)arg->int_view );
265         break;
266     case WPR_HEXA:
267         len = sprintf( number,
268                        (format->flags & WPRINTF_UPPER_HEX) ? "%X" : "%x",
269                        (UINT)arg->int_view);
270         break;
271     default:
272         return 0;
273     }
274     if (len > maxlen) len = maxlen;
275     if (format->precision < len) format->precision = len;
276     if (format->precision > maxlen) format->precision = maxlen;
277     if ((format->flags & WPRINTF_ZEROPAD) && (format->width > format->precision))
278         format->precision = format->width;
279     if (format->flags & WPRINTF_PREFIX_HEX) len += 2;
280     return len;
281 }
282
283
284 /***********************************************************************
285  *           wvsnprintf16   (Not a Windows API)
286  */
287 static INT16 wvsnprintf16( LPSTR buffer, UINT16 maxlen, LPCSTR spec,
288                            LPCVOID args )
289 {
290     WPRINTF_FORMAT format;
291     LPSTR p = buffer;
292     UINT i, len, sign;
293     CHAR number[20];
294     WPRINTF_DATA cur_arg;
295     SEGPTR seg_str;
296
297     while (*spec && (maxlen > 1))
298     {
299         if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
300         spec++;
301         if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
302         spec += WPRINTF_ParseFormatA( spec, &format );
303         switch(format.type)
304         {
305         case WPR_WCHAR:  /* No Unicode in Win16 */
306         case WPR_CHAR:
307             cur_arg.char_view = VA_ARG16( args, CHAR );
308             break;
309         case WPR_WSTRING:  /* No Unicode in Win16 */
310         case WPR_STRING:
311             seg_str = VA_ARG16( args, SEGPTR );
312             if (IsBadReadPtr16(seg_str, 1 )) cur_arg.lpcstr_view = "";
313             else cur_arg.lpcstr_view = MapSL( seg_str );
314             break;
315         case WPR_SIGNED:
316             if (!(format.flags & WPRINTF_LONG))
317             {
318                 cur_arg.int_view = VA_ARG16( args, INT16 );
319                 break;
320             }
321             /* fall through */
322         case WPR_HEXA:
323         case WPR_UNSIGNED:
324             if (format.flags & WPRINTF_LONG)
325                 cur_arg.int_view = VA_ARG16( args, UINT );
326             else
327                 cur_arg.int_view = VA_ARG16( args, UINT16 );
328             break;
329         case WPR_UNKNOWN:
330             continue;
331         }
332         len = WPRINTF_GetLen( &format, &cur_arg, number, maxlen - 1 );
333         sign = 0;
334         if (!(format.flags & WPRINTF_LEFTALIGN))
335             for (i = format.precision; i < format.width; i++, maxlen--)
336                 *p++ = ' ';
337         switch(format.type)
338         {
339         case WPR_WCHAR:  /* No Unicode in Win16 */
340         case WPR_CHAR:
341             *p= cur_arg.char_view;
342             /* wsprintf16 (unlike wsprintf) ignores null characters */
343             if (*p != '\0') p++;
344             else if (format.width > 1) *p++ = ' ';
345             else len = 0;
346             break;
347         case WPR_WSTRING:  /* No Unicode in Win16 */
348         case WPR_STRING:
349             if (len) memcpy( p, cur_arg.lpcstr_view, len );
350             p += len;
351             break;
352         case WPR_HEXA:
353             if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
354             {
355                 *p++ = '0';
356                 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
357                 maxlen -= 2;
358                 len -= 2;
359             }
360             /* fall through */
361         case WPR_SIGNED:
362             /* Transfer the sign now, just in case it will be zero-padded*/
363             if (number[0] == '-')
364             {
365                 *p++ = '-';
366                 sign = 1;
367             }
368             /* fall through */
369         case WPR_UNSIGNED:
370             for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
371             if (len > sign) memcpy( p, number + sign, len - sign );
372             p += len;
373             break;
374         case WPR_UNKNOWN:
375             continue;
376         }
377         if (format.flags & WPRINTF_LEFTALIGN)
378             for (i = format.precision; i < format.width; i++, maxlen--)
379                 *p++ = ' ';
380         maxlen -= len;
381     }
382     *p = 0;
383     return (maxlen > 1) ? (INT)(p - buffer) : -1;
384 }
385
386
387 /***********************************************************************
388  *           wvsnprintfA   (internal)
389  */
390 static INT wvsnprintfA( LPSTR buffer, UINT maxlen, LPCSTR spec, va_list args )
391 {
392     WPRINTF_FORMAT format;
393     LPSTR p = buffer;
394     UINT i, len, sign;
395     CHAR number[20];
396     WPRINTF_DATA argData;
397
398     TRACE("%p %u %s\n", buffer, maxlen, debugstr_a(spec));
399
400     while (*spec && (maxlen > 1))
401     {
402         if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
403         spec++;
404         if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
405         spec += WPRINTF_ParseFormatA( spec, &format );
406
407         switch(format.type)
408         {
409         case WPR_WCHAR:
410             argData.wchar_view = (WCHAR)va_arg( args, int );
411             break;
412         case WPR_CHAR:
413             argData.char_view = (CHAR)va_arg( args, int );
414             break;
415         case WPR_STRING:
416             argData.lpcstr_view = va_arg( args, LPCSTR );
417             break;
418         case WPR_WSTRING:
419             argData.lpcwstr_view = va_arg( args, LPCWSTR );
420             break;
421         case WPR_HEXA:
422         case WPR_SIGNED:
423         case WPR_UNSIGNED:
424             argData.int_view = va_arg( args, INT );
425             break;
426         default:
427             argData.wchar_view = 0;
428             break;
429         }
430
431         len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 );
432         sign = 0;
433         if (!(format.flags & WPRINTF_LEFTALIGN))
434             for (i = format.precision; i < format.width; i++, maxlen--)
435                 *p++ = ' ';
436         switch(format.type)
437         {
438         case WPR_WCHAR:
439             *p++ = argData.wchar_view;
440             break;
441         case WPR_CHAR:
442             *p++ = argData.char_view;
443             break;
444         case WPR_STRING:
445             memcpy( p, argData.lpcstr_view, len );
446             p += len;
447             break;
448         case WPR_WSTRING:
449             {
450                 LPCWSTR ptr = argData.lpcwstr_view;
451                 for (i = 0; i < len; i++) *p++ = (CHAR)*ptr++;
452             }
453             break;
454         case WPR_HEXA:
455             if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
456             {
457                 *p++ = '0';
458                 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
459                 maxlen -= 2;
460                 len -= 2;
461             }
462             /* fall through */
463         case WPR_SIGNED:
464             /* Transfer the sign now, just in case it will be zero-padded*/
465             if (number[0] == '-')
466             {
467                 *p++ = '-';
468                 sign = 1;
469             }
470             /* fall through */
471         case WPR_UNSIGNED:
472             for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
473             memcpy( p, number + sign, len - sign  );
474             p += len - sign;
475             break;
476         case WPR_UNKNOWN:
477             continue;
478         }
479         if (format.flags & WPRINTF_LEFTALIGN)
480             for (i = format.precision; i < format.width; i++, maxlen--)
481                 *p++ = ' ';
482         maxlen -= len;
483     }
484     *p = 0;
485     TRACE("%s\n",debugstr_a(buffer));
486     return (maxlen > 1) ? (INT)(p - buffer) : -1;
487 }
488
489
490 /***********************************************************************
491  *           wvsnprintfW   (internal)
492  */
493 static INT wvsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec, va_list args )
494 {
495     WPRINTF_FORMAT format;
496     LPWSTR p = buffer;
497     UINT i, len, sign;
498     CHAR number[20];
499     WPRINTF_DATA argData;
500
501     TRACE("%p %u %s\n", buffer, maxlen, debugstr_w(spec));
502
503     while (*spec && (maxlen > 1))
504     {
505         if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
506         spec++;
507         if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
508         spec += WPRINTF_ParseFormatW( spec, &format );
509
510         switch(format.type)
511         {
512         case WPR_WCHAR:
513             argData.wchar_view = (WCHAR)va_arg( args, int );
514             break;
515         case WPR_CHAR:
516             argData.char_view = (CHAR)va_arg( args, int );
517             break;
518         case WPR_STRING:
519             argData.lpcstr_view = va_arg( args, LPCSTR );
520             break;
521         case WPR_WSTRING:
522             argData.lpcwstr_view = va_arg( args, LPCWSTR );
523             break;
524         case WPR_HEXA:
525         case WPR_SIGNED:
526         case WPR_UNSIGNED:
527             argData.int_view = va_arg( args, INT );
528             break;
529         default:
530             argData.wchar_view = 0;
531             break;
532         }
533
534         len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 );
535         sign = 0;
536         if (!(format.flags & WPRINTF_LEFTALIGN))
537             for (i = format.precision; i < format.width; i++, maxlen--)
538                 *p++ = ' ';
539         switch(format.type)
540         {
541         case WPR_WCHAR:
542             *p++ = argData.wchar_view;
543             break;
544         case WPR_CHAR:
545             *p++ = argData.char_view;
546             break;
547         case WPR_STRING:
548             {
549                 LPCSTR ptr = argData.lpcstr_view;
550                 for (i = 0; i < len; i++) *p++ = (WCHAR)*ptr++;
551             }
552             break;
553         case WPR_WSTRING:
554             if (len) memcpy( p, argData.lpcwstr_view, len * sizeof(WCHAR) );
555             p += len;
556             break;
557         case WPR_HEXA:
558             if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
559             {
560                 *p++ = '0';
561                 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
562                 maxlen -= 2;
563                 len -= 2;
564             }
565             /* fall through */
566         case WPR_SIGNED:
567             /* Transfer the sign now, just in case it will be zero-padded*/
568             if (number[0] == '-')
569             {
570                 *p++ = '-';
571                 sign = 1;
572             }
573             /* fall through */
574         case WPR_UNSIGNED:
575             for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
576             for (i = sign; i < len; i++) *p++ = (WCHAR)number[i];
577             break;
578         case WPR_UNKNOWN:
579             continue;
580         }
581         if (format.flags & WPRINTF_LEFTALIGN)
582             for (i = format.precision; i < format.width; i++, maxlen--)
583                 *p++ = ' ';
584         maxlen -= len;
585     }
586     *p = 0;
587     TRACE("%s\n",debugstr_w(buffer));
588     return (maxlen > 1) ? (INT)(p - buffer) : -1;
589 }
590
591
592 /***********************************************************************
593  *           wvsprintf   (USER.421)
594  */
595 INT16 WINAPI wvsprintf16( LPSTR buffer, LPCSTR spec, LPCVOID args )
596 {
597     INT16 res;
598
599     TRACE("for %p got:\n",buffer);
600     res = wvsnprintf16( buffer, 1024, spec, args );
601     return ( res == -1 ) ? 1024 : res;
602 }
603
604
605 /***********************************************************************
606  *           wvsprintfA   (USER32.@)
607  */
608 INT WINAPI wvsprintfA( LPSTR buffer, LPCSTR spec, va_list args )
609 {
610     INT res = wvsnprintfA( buffer, 1024, spec, args );
611     return ( res == -1 ) ? 1024 : res;
612 }
613
614
615 /***********************************************************************
616  *           wvsprintfW   (USER32.@)
617  */
618 INT WINAPI wvsprintfW( LPWSTR buffer, LPCWSTR spec, va_list args )
619 {
620     INT res = wvsnprintfW( buffer, 1024, spec, args );
621     return ( res == -1 ) ? 1024 : res;
622 }
623
624
625 /***********************************************************************
626  *           _wsprintf   (USER.420)
627  */
628 INT16 WINAPIV wsprintf16(void)
629 {
630     VA_LIST16 valist;
631     INT16 res;
632     SEGPTR buffer, spec;
633
634     VA_START16( valist );
635     buffer = VA_ARG16( valist, SEGPTR );
636     spec   = VA_ARG16( valist, SEGPTR );
637     res = wvsnprintf16( MapSL(buffer), 1024, MapSL(spec), valist );
638     VA_END16( valist );
639     return ( res == -1 ) ? 1024 : res;
640 }
641
642
643 /***********************************************************************
644  *           wsprintfA   (USER32.@)
645  */
646 INT WINAPIV wsprintfA( LPSTR buffer, LPCSTR spec, ... )
647 {
648     va_list valist;
649     INT res;
650
651     va_start( valist, spec );
652     res = wvsnprintfA( buffer, 1024, spec, valist );
653     va_end( valist );
654     return ( res == -1 ) ? 1024 : res;
655 }
656
657
658 /***********************************************************************
659  *           wsprintfW   (USER32.@)
660  */
661 INT WINAPIV wsprintfW( LPWSTR buffer, LPCWSTR spec, ... )
662 {
663     va_list valist;
664     INT res;
665
666     va_start( valist, spec );
667     res = wvsnprintfW( buffer, 1024, spec, valist );
668     va_end( valist );
669     return ( res == -1 ) ? 1024 : res;
670 }