source: trunk/src/user32/wsprintf.cpp@ 6823

Last change on this file since 6823 was 6707, checked in by sandervl, 24 years ago

* empty log message *

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