Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenwsprintf.c
Go to the documentation of this file.
00001 /* 00002 * wsprintf functions 00003 * 00004 * Copyright 1996 Alexandre Julliard 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 * 00020 * NOTE: 00021 * This code is duplicated in user32. If you change something here make sure 00022 * to change it in user32 too. 00023 */ 00024 00025 #include <stdarg.h> 00026 #include <string.h> 00027 #include <stdio.h> 00028 00029 #include "windef.h" 00030 #include "winbase.h" 00031 #define NO_SHLWAPI_REG 00032 #include "shlwapi.h" 00033 00034 #include "wine/debug.h" 00035 00036 WINE_DEFAULT_DEBUG_CHANNEL(string); 00037 00038 00039 #define WPRINTF_LEFTALIGN 0x0001 /* Align output on the left ('-' prefix) */ 00040 #define WPRINTF_PREFIX_HEX 0x0002 /* Prefix hex with 0x ('#' prefix) */ 00041 #define WPRINTF_ZEROPAD 0x0004 /* Pad with zeros ('0' prefix) */ 00042 #define WPRINTF_LONG 0x0008 /* Long arg ('l' prefix) */ 00043 #define WPRINTF_SHORT 0x0010 /* Short arg ('h' prefix) */ 00044 #define WPRINTF_UPPER_HEX 0x0020 /* Upper-case hex ('X' specifier) */ 00045 #define WPRINTF_WIDE 0x0040 /* Wide arg ('w' prefix) */ 00046 00047 typedef enum 00048 { 00049 WPR_UNKNOWN, 00050 WPR_CHAR, 00051 WPR_WCHAR, 00052 WPR_STRING, 00053 WPR_WSTRING, 00054 WPR_SIGNED, 00055 WPR_UNSIGNED, 00056 WPR_HEXA 00057 } WPRINTF_TYPE; 00058 00059 typedef struct 00060 { 00061 UINT flags; 00062 UINT width; 00063 UINT precision; 00064 WPRINTF_TYPE type; 00065 } WPRINTF_FORMAT; 00066 00067 typedef union { 00068 WCHAR wchar_view; 00069 CHAR char_view; 00070 LPCSTR lpcstr_view; 00071 LPCWSTR lpcwstr_view; 00072 INT int_view; 00073 } WPRINTF_DATA; 00074 00075 static const CHAR null_stringA[] = "(null)"; 00076 static const WCHAR null_stringW[] = { '(', 'n', 'u', 'l', 'l', ')', 0 }; 00077 00078 /*********************************************************************** 00079 * WPRINTF_ParseFormatA 00080 * 00081 * Parse a format specification. A format specification has the form: 00082 * 00083 * [-][#][0][width][.precision]type 00084 * 00085 * Return value is the length of the format specification in characters. 00086 */ 00087 static INT WPRINTF_ParseFormatA( LPCSTR format, WPRINTF_FORMAT *res ) 00088 { 00089 LPCSTR p = format; 00090 00091 res->flags = 0; 00092 res->width = 0; 00093 res->precision = 0; 00094 if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; } 00095 if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; } 00096 if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; } 00097 while ((*p >= '0') && (*p <= '9')) /* width field */ 00098 { 00099 res->width = res->width * 10 + *p - '0'; 00100 p++; 00101 } 00102 if (*p == '.') /* precision field */ 00103 { 00104 p++; 00105 while ((*p >= '0') && (*p <= '9')) 00106 { 00107 res->precision = res->precision * 10 + *p - '0'; 00108 p++; 00109 } 00110 } 00111 if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; } 00112 else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; } 00113 else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; } 00114 switch(*p) 00115 { 00116 case 'c': 00117 res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR; 00118 break; 00119 case 'C': 00120 res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR; 00121 break; 00122 case 'd': 00123 case 'i': 00124 res->type = WPR_SIGNED; 00125 break; 00126 case 's': 00127 res->type = (res->flags & (WPRINTF_LONG |WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING; 00128 break; 00129 case 'S': 00130 res->type = (res->flags & (WPRINTF_SHORT|WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING; 00131 break; 00132 case 'u': 00133 res->type = WPR_UNSIGNED; 00134 break; 00135 case 'X': 00136 res->flags |= WPRINTF_UPPER_HEX; 00137 /* fall through */ 00138 case 'x': 00139 res->type = WPR_HEXA; 00140 break; 00141 default: /* unknown format char */ 00142 res->type = WPR_UNKNOWN; 00143 p--; /* print format as normal char */ 00144 break; 00145 } 00146 return (INT)(p - format) + 1; 00147 } 00148 00149 00150 /*********************************************************************** 00151 * WPRINTF_ParseFormatW 00152 * 00153 * Parse a format specification. A format specification has the form: 00154 * 00155 * [-][#][0][width][.precision]type 00156 * 00157 * Return value is the length of the format specification in characters. 00158 */ 00159 static INT WPRINTF_ParseFormatW( LPCWSTR format, WPRINTF_FORMAT *res ) 00160 { 00161 LPCWSTR p = format; 00162 00163 res->flags = 0; 00164 res->width = 0; 00165 res->precision = 0; 00166 if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; } 00167 if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; } 00168 if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; } 00169 while ((*p >= '0') && (*p <= '9')) /* width field */ 00170 { 00171 res->width = res->width * 10 + *p - '0'; 00172 p++; 00173 } 00174 if (*p == '.') /* precision field */ 00175 { 00176 p++; 00177 while ((*p >= '0') && (*p <= '9')) 00178 { 00179 res->precision = res->precision * 10 + *p - '0'; 00180 p++; 00181 } 00182 } 00183 if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; } 00184 else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; } 00185 else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; } 00186 switch((CHAR)*p) 00187 { 00188 case 'c': 00189 res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR; 00190 break; 00191 case 'C': 00192 res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR; 00193 break; 00194 case 'd': 00195 case 'i': 00196 res->type = WPR_SIGNED; 00197 break; 00198 case 's': 00199 res->type = ((res->flags & WPRINTF_SHORT) && !(res->flags & WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING; 00200 break; 00201 case 'S': 00202 res->type = (res->flags & (WPRINTF_LONG|WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING; 00203 break; 00204 case 'u': 00205 res->type = WPR_UNSIGNED; 00206 break; 00207 case 'X': 00208 res->flags |= WPRINTF_UPPER_HEX; 00209 /* fall through */ 00210 case 'x': 00211 res->type = WPR_HEXA; 00212 break; 00213 default: 00214 res->type = WPR_UNKNOWN; 00215 p--; /* print format as normal char */ 00216 break; 00217 } 00218 return (INT)(p - format) + 1; 00219 } 00220 00221 00222 /*********************************************************************** 00223 * WPRINTF_GetLen 00224 */ 00225 static UINT WPRINTF_GetLen( WPRINTF_FORMAT *format, WPRINTF_DATA *arg, 00226 LPSTR number, UINT maxlen ) 00227 { 00228 UINT len; 00229 00230 if (format->flags & WPRINTF_LEFTALIGN) format->flags &= ~WPRINTF_ZEROPAD; 00231 if (format->width > maxlen) format->width = maxlen; 00232 switch(format->type) 00233 { 00234 case WPR_CHAR: 00235 case WPR_WCHAR: 00236 return (format->precision = 1); 00237 case WPR_STRING: 00238 if (!arg->lpcstr_view) arg->lpcstr_view = null_stringA; 00239 for (len = 0; !format->precision || (len < format->precision); len++) 00240 if (!*(arg->lpcstr_view + len)) break; 00241 if (len > maxlen) len = maxlen; 00242 return (format->precision = len); 00243 case WPR_WSTRING: 00244 if (!arg->lpcwstr_view) arg->lpcwstr_view = null_stringW; 00245 for (len = 0; !format->precision || (len < format->precision); len++) 00246 if (!*(arg->lpcwstr_view + len)) break; 00247 if (len > maxlen) len = maxlen; 00248 return (format->precision = len); 00249 case WPR_SIGNED: 00250 len = sprintf( number, "%d", arg->int_view ); 00251 break; 00252 case WPR_UNSIGNED: 00253 len = sprintf( number, "%u", (UINT)arg->int_view ); 00254 break; 00255 case WPR_HEXA: 00256 len = sprintf( number, 00257 (format->flags & WPRINTF_UPPER_HEX) ? "%X" : "%x", 00258 (UINT)arg->int_view); 00259 break; 00260 default: 00261 return 0; 00262 } 00263 if (len > maxlen) len = maxlen; 00264 if (format->precision < len) format->precision = len; 00265 if (format->precision > maxlen) format->precision = maxlen; 00266 if ((format->flags & WPRINTF_ZEROPAD) && (format->width > format->precision)) 00267 format->precision = format->width; 00268 if (format->flags & WPRINTF_PREFIX_HEX) len += 2; 00269 return len; 00270 } 00271 00272 00273 /*********************************************************************** 00274 * wvnsprintfA (SHLWAPI.@) 00275 * 00276 * Print formatted output to a string, up to a maximum number of chars. 00277 * 00278 * PARAMS 00279 * buffer [O] Destination for output string 00280 * maxlen [I] Maximum number of characters to write 00281 * spec [I] Format string 00282 * 00283 * RETURNS 00284 * Success: The number of characters written. 00285 * Failure: -1. 00286 */ 00287 INT WINAPI wvnsprintfA( LPSTR buffer, INT maxlen, LPCSTR spec, __ms_va_list args ) 00288 { 00289 WPRINTF_FORMAT format; 00290 LPSTR p = buffer; 00291 UINT i, len, sign; 00292 CHAR number[20]; 00293 WPRINTF_DATA argData; 00294 00295 TRACE("%p %u %s\n", buffer, maxlen, debugstr_a(spec)); 00296 00297 while (*spec && (maxlen > 1)) 00298 { 00299 if (*spec != '%') { *p++ = *spec++; maxlen--; continue; } 00300 spec++; 00301 if (*spec == '%') { *p++ = *spec++; maxlen--; continue; } 00302 spec += WPRINTF_ParseFormatA( spec, &format ); 00303 00304 switch(format.type) 00305 { 00306 case WPR_WCHAR: 00307 argData.wchar_view = (WCHAR)va_arg( args, int ); 00308 break; 00309 case WPR_CHAR: 00310 argData.char_view = (CHAR)va_arg( args, int ); 00311 break; 00312 case WPR_STRING: 00313 argData.lpcstr_view = va_arg( args, LPCSTR ); 00314 break; 00315 case WPR_WSTRING: 00316 argData.lpcwstr_view = va_arg( args, LPCWSTR ); 00317 break; 00318 case WPR_HEXA: 00319 case WPR_SIGNED: 00320 case WPR_UNSIGNED: 00321 argData.int_view = va_arg( args, INT ); 00322 break; 00323 default: 00324 argData.wchar_view = 0; 00325 break; 00326 } 00327 00328 len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 ); 00329 sign = 0; 00330 if (!(format.flags & WPRINTF_LEFTALIGN)) 00331 for (i = format.precision; i < format.width; i++, maxlen--) 00332 *p++ = ' '; 00333 switch(format.type) 00334 { 00335 case WPR_WCHAR: 00336 *p++ = argData.wchar_view; 00337 break; 00338 case WPR_CHAR: 00339 *p++ = argData.char_view; 00340 break; 00341 case WPR_STRING: 00342 memcpy( p, argData.lpcstr_view, len ); 00343 p += len; 00344 break; 00345 case WPR_WSTRING: 00346 { 00347 LPCWSTR ptr = argData.lpcwstr_view; 00348 for (i = 0; i < len; i++) *p++ = (CHAR)*ptr++; 00349 } 00350 break; 00351 case WPR_HEXA: 00352 if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3)) 00353 { 00354 *p++ = '0'; 00355 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x'; 00356 maxlen -= 2; 00357 len -= 2; 00358 } 00359 /* fall through */ 00360 case WPR_SIGNED: 00361 /* Transfer the sign now, just in case it will be zero-padded*/ 00362 if (number[0] == '-') 00363 { 00364 *p++ = '-'; 00365 sign = 1; 00366 } 00367 /* fall through */ 00368 case WPR_UNSIGNED: 00369 for (i = len; i < format.precision; i++, maxlen--) *p++ = '0'; 00370 memcpy( p, number + sign, len - sign ); 00371 p += len - sign; 00372 break; 00373 case WPR_UNKNOWN: 00374 continue; 00375 } 00376 if (format.flags & WPRINTF_LEFTALIGN) 00377 for (i = format.precision; i < format.width; i++, maxlen--) 00378 *p++ = ' '; 00379 maxlen -= len; 00380 } 00381 *p = 0; 00382 TRACE("%s\n",debugstr_a(buffer)); 00383 return (maxlen > 1) ? (INT)(p - buffer) : -1; 00384 } 00385 00386 00387 /*********************************************************************** 00388 * wvnsprintfW (SHLWAPI.@) 00389 * 00390 * See wvnsprintfA. 00391 */ 00392 INT WINAPI wvnsprintfW( LPWSTR buffer, INT maxlen, LPCWSTR spec, __ms_va_list args ) 00393 { 00394 WPRINTF_FORMAT format; 00395 LPWSTR p = buffer; 00396 UINT i, len, sign; 00397 CHAR number[20]; 00398 WPRINTF_DATA argData; 00399 00400 TRACE("%p %u %s\n", buffer, maxlen, debugstr_w(spec)); 00401 00402 while (*spec && (maxlen > 1)) 00403 { 00404 if (*spec != '%') { *p++ = *spec++; maxlen--; continue; } 00405 spec++; 00406 if (*spec == '%') { *p++ = *spec++; maxlen--; continue; } 00407 spec += WPRINTF_ParseFormatW( spec, &format ); 00408 00409 switch(format.type) 00410 { 00411 case WPR_WCHAR: 00412 argData.wchar_view = (WCHAR)va_arg( args, int ); 00413 break; 00414 case WPR_CHAR: 00415 argData.char_view = (CHAR)va_arg( args, int ); 00416 break; 00417 case WPR_STRING: 00418 argData.lpcstr_view = va_arg( args, LPCSTR ); 00419 break; 00420 case WPR_WSTRING: 00421 argData.lpcwstr_view = va_arg( args, LPCWSTR ); 00422 break; 00423 case WPR_HEXA: 00424 case WPR_SIGNED: 00425 case WPR_UNSIGNED: 00426 argData.int_view = va_arg( args, INT ); 00427 break; 00428 default: 00429 argData.wchar_view = 0; 00430 break; 00431 } 00432 00433 len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 ); 00434 sign = 0; 00435 if (!(format.flags & WPRINTF_LEFTALIGN)) 00436 for (i = format.precision; i < format.width; i++, maxlen--) 00437 *p++ = ' '; 00438 switch(format.type) 00439 { 00440 case WPR_WCHAR: 00441 *p++ = argData.wchar_view; 00442 break; 00443 case WPR_CHAR: 00444 *p++ = argData.char_view; 00445 break; 00446 case WPR_STRING: 00447 { 00448 LPCSTR ptr = argData.lpcstr_view; 00449 for (i = 0; i < len; i++) *p++ = (WCHAR)*ptr++; 00450 } 00451 break; 00452 case WPR_WSTRING: 00453 if (len) memcpy( p, argData.lpcwstr_view, len * sizeof(WCHAR) ); 00454 p += len; 00455 break; 00456 case WPR_HEXA: 00457 if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3)) 00458 { 00459 *p++ = '0'; 00460 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x'; 00461 maxlen -= 2; 00462 len -= 2; 00463 } 00464 /* fall through */ 00465 case WPR_SIGNED: 00466 /* Transfer the sign now, just in case it will be zero-padded*/ 00467 if (number[0] == '-') 00468 { 00469 *p++ = '-'; 00470 sign = 1; 00471 } 00472 /* fall through */ 00473 case WPR_UNSIGNED: 00474 for (i = len; i < format.precision; i++, maxlen--) *p++ = '0'; 00475 for (i = sign; i < len; i++) *p++ = (WCHAR)number[i]; 00476 break; 00477 case WPR_UNKNOWN: 00478 continue; 00479 } 00480 if (format.flags & WPRINTF_LEFTALIGN) 00481 for (i = format.precision; i < format.width; i++, maxlen--) 00482 *p++ = ' '; 00483 maxlen -= len; 00484 } 00485 *p = 0; 00486 TRACE("%s\n",debugstr_w(buffer)); 00487 return (maxlen > 1) ? (INT)(p - buffer) : -1; 00488 } 00489 00490 00491 /************************************************************************* 00492 * wnsprintfA (SHLWAPI.@) 00493 * 00494 * Print formatted output to a string, up to a maximum number of chars. 00495 * 00496 * PARAMS 00497 * lpOut [O] Destination for output string 00498 * cchLimitIn [I] Maximum number of characters to write 00499 * lpFmt [I] Format string 00500 * 00501 * RETURNS 00502 * Success: The number of characters written. 00503 * Failure: -1. 00504 */ 00505 int WINAPIV wnsprintfA(LPSTR lpOut, int cchLimitIn, LPCSTR lpFmt, ...) 00506 { 00507 __ms_va_list valist; 00508 INT res; 00509 00510 __ms_va_start( valist, lpFmt ); 00511 res = wvnsprintfA( lpOut, cchLimitIn, lpFmt, valist ); 00512 __ms_va_end( valist ); 00513 return res; 00514 } 00515 00516 00517 /************************************************************************* 00518 * wnsprintfW (SHLWAPI.@) 00519 * 00520 * See wnsprintfA. 00521 */ 00522 int WINAPIV wnsprintfW(LPWSTR lpOut, int cchLimitIn, LPCWSTR lpFmt, ...) 00523 { 00524 __ms_va_list valist; 00525 INT res; 00526 00527 __ms_va_start( valist, lpFmt ); 00528 res = wvnsprintfW( lpOut, cchLimitIn, lpFmt, valist ); 00529 __ms_va_end( valist ); 00530 return res; 00531 } Generated on Mon May 28 2012 04:26:10 for ReactOS by
1.7.6.1
|