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

Last change on this file since 3747 was 3747, checked in by sandervl, 25 years ago

wsprintf fix, menu accelerator fix

File size: 16.1 KB
Line 
1/* $Id: wsprintf.cpp,v 1.8 2000-06-23 19:04:13 sandervl Exp $ */
2
3/*
4 * Win32 misc user32 API functions for OS/2
5 * wsprintf functions
6 *
7 * Copyright 1996 Alexandre Julliard
8 * Copyright 1999 Patrick Haller
9 *
10 * Project Odin Software License can be found in LICENSE.TXT
11 */
12
13
14/****************************************************************************
15 * Includes *
16 ****************************************************************************/
17
18#include <odin.h>
19#include <odinwrap.h>
20#include <os2sel.h>
21#include <os2win.h>
22
23#include <stdarg.h>
24#include <string.h>
25#include "stackframe.h"
26#include "module.h"
27#include "global.h"
28#include "debugtools.h"
29
30#include <misc.h>
31
32#define DBG_LOCALLOG DBG_wsprintf
33#include "dbglocal.h"
34
35ODINDEBUGCHANNEL(USER32-WSPRINTF)
36
37
38/****************************************************************************
39 * Definitions & Structures *
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
50typedef 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
62typedef struct
63{
64 UINT flags;
65 UINT width;
66 UINT precision;
67 WPRINTF_TYPE type;
68} WPRINTF_FORMAT;
69
70typedef 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
79/****************************************************************************
80 * Module global variables *
81 ****************************************************************************/
82
83static const CHAR null_stringA[] = "(null)";
84static const WCHAR null_stringW[] = { '(', 'n', 'u', 'l', 'l', ')', 0 };
85
86
87/***********************************************************************
88 * WPRINTF_ParseFormatA
89 *
90 * Parse a format specification. A format specification has the form:
91 *
92 * [-][#][0][width][.precision]type
93 *
94 * Return value is the length of the format specification in characters.
95 */
96static INT WPRINTF_ParseFormatA( LPCSTR format, WPRINTF_FORMAT *res )
97{
98 LPCSTR p = format;
99
100 res->flags = 0;
101 res->width = 0;
102 res->precision = 0;
103 if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; }
104 if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; }
105 if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; }
106 while ((*p >= '0') && (*p <= '9')) /* width field */
107 {
108 res->width = res->width * 10 + *p - '0';
109 p++;
110 }
111 if (*p == '.') /* precision field */
112 {
113 p++;
114 while ((*p >= '0') && (*p <= '9'))
115 {
116 res->precision = res->precision * 10 + *p - '0';
117 p++;
118 }
119 }
120 if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; }
121 else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; }
122 else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; }
123 switch(*p)
124 {
125 case 'c':
126 res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
127 break;
128 case 'C':
129 res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
130 break;
131 case 'd':
132 case 'i':
133 res->type = WPR_SIGNED;
134 break;
135 case 's':
136 res->type = (res->flags & (WPRINTF_LONG |WPRINTF_WIDE))
137 ? WPR_WSTRING : WPR_STRING;
138 break;
139 case 'S':
140 res->type = (res->flags & (WPRINTF_SHORT|WPRINTF_WIDE))
141 ? WPR_STRING : WPR_WSTRING;
142 break;
143 case 'u':
144 res->type = WPR_UNSIGNED;
145 break;
146 case 'X':
147 res->flags |= WPRINTF_UPPER_HEX;
148 /* fall through */
149 case 'x':
150 res->type = WPR_HEXA;
151 break;
152 default: /* unknown format char */
153 res->type = WPR_UNKNOWN;
154 p--; /* print format as normal char */
155 break;
156 }
157 return (INT)(p - format) + 1;
158}
159
160
161/***********************************************************************
162 * WPRINTF_ParseFormatW
163 *
164 * Parse a format specification. A format specification has the form:
165 *
166 * [-][#][0][width][.precision]type
167 *
168 * Return value is the length of the format specification in characters.
169 */
170static INT WPRINTF_ParseFormatW( LPCWSTR format, WPRINTF_FORMAT *res )
171{
172 LPCWSTR p = format;
173
174 res->flags = 0;
175 res->width = 0;
176 res->precision = 0;
177 if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; }
178 if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; }
179 if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; }
180 while ((*p >= '0') && (*p <= '9')) /* width field */
181 {
182 res->width = res->width * 10 + *p - '0';
183 p++;
184 }
185 if (*p == '.') /* precision field */
186 {
187 p++;
188 while ((*p >= '0') && (*p <= '9'))
189 {
190 res->precision = res->precision * 10 + *p - '0';
191 p++;
192 }
193 }
194 if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; }
195 else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; }
196 else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; }
197 switch((CHAR)*p)
198 {
199 case 'c':
200 res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
201 break;
202 case 'C':
203 res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
204 break;
205 case 'd':
206 case 'i':
207 res->type = WPR_SIGNED;
208 break;
209 case 's':
210 res->type = ((res->flags & WPRINTF_SHORT) && !(res->flags & WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING;
211 break;
212 case 'S':
213 res->type = (res->flags & (WPRINTF_LONG|WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING;
214 break;
215 case 'u':
216 res->type = WPR_UNSIGNED;
217 break;
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 */
236static 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 if (format->flags & WPRINTF_PREFIX_HEX) {
271 len += 2;
272 format->width += 2;
273 }
274 break;
275 default:
276 return 0;
277 }
278 if (len > maxlen) len = maxlen;
279 if (format->precision < len) format->precision = len;
280 if (format->precision > maxlen) format->precision = maxlen;
281 if ((format->flags & WPRINTF_ZEROPAD) && (format->width > format->precision))
282 format->precision = format->width;
283 return len;
284}
285
286/***********************************************************************
287 * WPRINTF_ExtractVAPtr (Not a Windows API)
288 */
289static WPRINTF_DATA WPRINTF_ExtractVAPtr( WPRINTF_FORMAT *format, va_list* args )
290{
291 WPRINTF_DATA result;
292 switch(format->type)
293 {
294 case WPR_WCHAR:
295 result.wchar_view = va_arg( *args, WCHAR ); break;
296 case WPR_CHAR:
297 result.char_view = va_arg( *args, CHAR ); break;
298 case WPR_STRING:
299 result.lpcstr_view = va_arg( *args, LPCSTR); break;
300 case WPR_WSTRING:
301 result.lpcwstr_view = va_arg( *args, LPCWSTR); break;
302 case WPR_HEXA:
303 case WPR_SIGNED:
304 case WPR_UNSIGNED:
305 result.int_view = va_arg( *args, INT ); break;
306 default:
307 result.wchar_view = 0; break;
308 }
309 return result;
310}
311
312/***********************************************************************
313 * wvsnprintfA (Not a Windows API)
314 */
315INT WINAPI wvsnprintfA( LPSTR buffer, UINT maxlen, LPCSTR spec,
316 va_list args )
317{
318 WPRINTF_FORMAT format;
319 LPSTR p = buffer;
320 UINT i, len;
321 CHAR number[20];
322 WPRINTF_DATA argData;
323
324 while (spec && *spec && (maxlen > 1))
325 {
326 if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
327 spec++;
328 if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
329 spec += WPRINTF_ParseFormatA( spec, &format );
330 argData = WPRINTF_ExtractVAPtr( &format, &args );
331 len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 );
332 if (!(format.flags & WPRINTF_LEFTALIGN))
333 for (i = format.precision; i < format.width; i++, maxlen--)
334 *p++ = ' ';
335 switch(format.type)
336 {
337 case WPR_WCHAR:
338 *p = argData.wchar_view;
339 if (*p != '\0') p++;
340 else if (format.width > 1) *p++ = ' ';
341 else len = 0;
342 break;
343 case WPR_CHAR:
344 *p = argData.char_view;
345 if (*p != '\0') p++;
346 else if (format.width > 1) *p++ = ' ';
347 else len = 0;
348 break;
349 case WPR_STRING:
350 memcpy( p, argData.lpcstr_view, len );
351 p += len;
352 break;
353 case WPR_WSTRING:
354 {
355 LPCWSTR ptr = argData.lpcwstr_view;
356 for (i = 0; i < len; i++) *p++ = (CHAR)*ptr++;
357 }
358 break;
359 case WPR_HEXA:
360 if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
361 {
362 *p++ = '0';
363 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
364 maxlen -= 2;
365 len -= 2;
366 format.precision -= 2;
367 format.width -= 2;
368 }
369 /* fall through */
370 case WPR_SIGNED:
371 case WPR_UNSIGNED:
372 for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
373 memcpy( p, number, len );
374 p += len;
375 /* Go to the next arg */
376 break;
377 case WPR_UNKNOWN:
378 continue;
379 }
380 if (format.flags & WPRINTF_LEFTALIGN)
381 for (i = format.precision; i < format.width; i++, maxlen--)
382 *p++ = ' ';
383 maxlen -= len;
384 }
385 *p = 0;
386 TRACE("%s\n",buffer);
387 return (maxlen > 1) ? (INT)(p - buffer) : -1;
388}
389
390
391/***********************************************************************
392 * wvsnprintfW (Not a Windows API)
393 */
394INT WINAPI wvsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec,
395 va_list args )
396{
397 WPRINTF_FORMAT format;
398 LPWSTR p = buffer;
399 UINT i, len;
400 CHAR number[20];
401
402 while (spec && *spec && (maxlen > 1))
403 {
404 if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
405 spec++;
406 if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
407 spec += WPRINTF_ParseFormatW( spec, &format );
408 len = WPRINTF_GetLen( &format, (WPRINTF_DATA*)args, 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 = va_arg( args, WCHAR );
416 if (*p != '\0') p++;
417 else if (format.width > 1) *p++ = ' ';
418 else len = 0;
419 break;
420 case WPR_CHAR:
421 *p = (WCHAR)va_arg( args, CHAR );
422 if (*p != '\0') p++;
423 else if (format.width > 1) *p++ = ' ';
424 else len = 0;
425 break;
426 case WPR_STRING:
427 {
428 LPCSTR ptr = va_arg( args, LPCSTR );
429 for (i = 0; i < len; i++) *p++ = (WCHAR)*ptr++;
430 }
431 break;
432 case WPR_WSTRING:
433 if (len) memcpy( p, va_arg( args, LPCWSTR ), len * sizeof(WCHAR) );
434 p += len;
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 format.precision -= 2;
444 format.width -= 2;
445 }
446 /* fall through */
447 case WPR_SIGNED:
448 case WPR_UNSIGNED:
449 for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
450 for (i = 0; i < len; i++) *p++ = (WCHAR)number[i];
451 (void)va_arg( args, INT ); /* Go to the next arg */
452 break;
453 case WPR_UNKNOWN:
454 continue;
455 }
456 if (format.flags & WPRINTF_LEFTALIGN)
457 for (i = format.precision; i < format.width; i++, maxlen--)
458 *p++ = ' ';
459 maxlen -= len;
460 }
461 *p = 0;
462 return (maxlen > 1) ? (INT)(p - buffer) : -1;
463}
464
465
466/***********************************************************************
467 * wvsprintfA (USER32.587)
468 */
469ODINFUNCTION3(INT, wvsprintfA,
470 LPSTR, buffer,
471 LPCSTR, spec,
472 va_list,args )
473{
474 return wvsnprintfA( buffer, 0xffffffff, spec, args );
475}
476
477
478/***********************************************************************
479 * wvsprintfW (USER32.588)
480 */
481ODINFUNCTION3(INT, wvsprintfW,
482 LPWSTR, buffer,
483 LPCWSTR, spec,
484 va_list, args )
485{
486 return wvsnprintfW( buffer, 0xffffffff, spec, args );
487}
488
489
490/***********************************************************************
491 * wsprintfA (USER32.585)
492 */
493INT WINAPIV wsprintfA( LPSTR buffer, LPCSTR spec, ... )
494{
495 va_list valist;
496 INT res;
497
498 TRACE("for %p got:\n",buffer);
499 va_start( valist, spec );
500 res = wvsnprintfA( buffer, 0xffffffff, spec, valist );
501 va_end( valist );
502 return res;
503}
504
505
506/***********************************************************************
507 * wsprintfW (USER32.586)
508 */
509INT WINAPIV wsprintfW( LPWSTR buffer, LPCWSTR spec, ... )
510{
511 va_list valist;
512 INT res;
513
514 TRACE("wsprintfW for %p\n",buffer);
515 va_start( valist, spec );
516 res = wvsnprintfW( buffer, 0xffffffff, spec, valist );
517 va_end( valist );
518 return res;
519}
520
521
522/***********************************************************************
523 * wsnprintfA (Not a Windows API)
524 */
525INT WINAPIV wsnprintfA( LPSTR buffer, UINT maxlen, LPCSTR spec, ... )
526{
527 va_list valist;
528 INT res;
529
530 va_start( valist, spec );
531 res = wvsnprintfA( buffer, maxlen, spec, valist );
532 va_end( valist );
533 return res;
534}
535
536
537/***********************************************************************
538 * wsnprintfW (Not a Windows API)
539 */
540INT WINAPIV wsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec, ... )
541{
542 va_list valist;
543 INT res;
544
545 va_start( valist, spec );
546 res = wvsnprintfW( buffer, maxlen, spec, valist );
547 va_end( valist );
548 return res;
549}
550
551
552
553
554
Note: See TracBrowser for help on using the repository browser.