VirtualBox

source: kBuild/trunk/src/lib/msc_buffered_printf.c@ 3565

Last change on this file since 3565 was 3547, checked in by bird, 3 years ago

lib: Changed the console-optimization wrappers to use the get_crt_codepage() function as that's more appropriate than GetConsoleCP() for use with _cputws(). Also made them avoid the heap for smaller writes that could fit into a reasonable (2KiB) stack buffer.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.1 KB
Line 
1/* $Id: msc_buffered_printf.c 3547 2022-01-29 02:39:47Z bird $ */
2/** @file
3 * printf, vprintf, fprintf, puts, fputs console optimizations for Windows/MSC.
4 */
5
6/*
7 * Copyright (c) 2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 * IN THE SOFTWARE.
26 *
27 * Alternatively, the content of this file may be used under the terms of the
28 * GPL version 2 or later, or LGPL version 2.1 or later.
29 */
30
31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
35#include <Windows.h>
36#include <stdio.h>
37#include <stdarg.h>
38#include <io.h>
39#include <conio.h>
40#include <malloc.h>
41#include <locale.h>
42#include "console.h"
43
44#undef printf
45#undef vprintf
46#undef fprintf
47#undef puts
48#undef fputs
49#pragma warning(disable: 4273) /* inconsistent dll linkage*/
50
51#ifndef KWORKER
52# define DLL_IMPORT __declspec(dllexport)
53#else
54# define DLL_IMPORT
55#endif
56
57
58
59/**
60 * Replaces printf for MSC to speed up console output.
61 *
62 * @returns chars written on success, -1 and errno on failure.
63 * @param pszFormat The format string.
64 * @param ... Format arguments.
65 */
66DLL_IMPORT
67int __cdecl printf(const char *pszFormat, ...)
68{
69 int cchRet;
70 va_list va;
71 va_start(va, pszFormat);
72 cchRet = vprintf(pszFormat, va);
73 va_end(va);
74 return cchRet;
75}
76
77
78/**
79 * Replaces vprintf for MSC to speed up console output.
80 *
81 * @returns chars written on success, -1 and errno on failure.
82 * @param pszFormat The format string.
83 * @param va Format arguments.
84 */
85DLL_IMPORT
86int __cdecl vprintf(const char *pszFormat, va_list va)
87{
88 /*
89 * If it's a TTY, try format into a stack buffer and output using our
90 * console optimized fwrite wrapper.
91 */
92 if (*pszFormat != '\0')
93 {
94 int fd = fileno(stdout);
95 if (fd >= 0)
96 {
97 if (is_console(fd))
98 {
99 char *pszTmp = (char *)alloca(16384);
100 va_list va2 = va;
101 int cchRet = vsnprintf(pszTmp, 16384, pszFormat, va2);
102 if (cchRet < 16384 - 1)
103 return (int)maybe_con_fwrite(pszTmp, cchRet, 1, stdout);
104 }
105 }
106 }
107
108 /*
109 * Fallback.
110 */
111 return vfprintf(stdout, pszFormat, va);
112}
113
114
115/**
116 * Replaces fprintf for MSC to speed up console output.
117 *
118 * @returns chars written on success, -1 and errno on failure.
119 * @param pFile The output file/stream.
120 * @param pszFormat The format string.
121 * @param va Format arguments.
122 */
123DLL_IMPORT
124int __cdecl fprintf(FILE *pFile, const char *pszFormat, ...)
125{
126 va_list va;
127 int cchRet;
128
129 /*
130 * If it's a TTY, try format into a stack buffer and output using our
131 * console optimized fwrite wrapper.
132 */
133 if (*pszFormat != '\0')
134 {
135 int fd = fileno(pFile);
136 if (fd >= 0)
137 {
138 if (is_console(fd))
139 {
140 char *pszTmp = (char *)alloca(16384);
141 if (pszTmp)
142 {
143 va_start(va, pszFormat);
144 cchRet = vsnprintf(pszTmp, 16384, pszFormat, va);
145 va_end(va);
146 if (cchRet < 16384 - 1)
147 return (int)maybe_con_fwrite(pszTmp, cchRet, 1, pFile);
148 }
149 }
150 }
151 }
152
153 /*
154 * Fallback.
155 */
156 va_start(va, pszFormat);
157 cchRet = vfprintf(pFile, pszFormat, va);
158 va_end(va);
159 return cchRet;
160}
161
162
163/**
164 * Replaces puts for MSC to speed up console output.
165 *
166 * @returns Units written; 0 & errno on failure.
167 * @param pszString The string to write. (newline is appended)
168 */
169DLL_IMPORT
170int __cdecl puts(const char *pszString)
171{
172 /*
173 * If it's a TTY, we convert it to a wide char string with a newline
174 * appended right here. Going thru maybe_con_fwrite is just extra
175 * buffering due to the added newline.
176 */
177 size_t cchString = strlen(pszString);
178 size_t cch;
179 if (cchString > 0 && cchString < INT_MAX / 2)
180 {
181 int fd = fileno(stdout);
182 if (fd >= 0)
183 {
184 if (is_console(fd))
185 {
186 HANDLE hCon = (HANDLE)_get_osfhandle(fd);
187 if ( hCon != INVALID_HANDLE_VALUE
188 && hCon != NULL)
189 {
190 wchar_t awcBuf[1024];
191 wchar_t *pawcBuf;
192 wchar_t *pawcBufFree = NULL;
193 size_t cwcBuf = cchString * 2 + 16 + 1; /* +1 for added newline */
194 if (cwcBuf < sizeof(awcBuf) / sizeof(awcBuf[0]))
195 {
196 pawcBuf = awcBuf;
197 cwcBuf = sizeof(awcBuf) / sizeof(awcBuf[0]);
198 }
199 else
200 pawcBufFree = pawcBuf = (wchar_t *)malloc(cwcBuf * sizeof(wchar_t));
201 if (pawcBuf)
202 {
203 int cwcToWrite = MultiByteToWideChar(get_crt_codepage(), 0 /*dwFlags*/,
204 pszString, (int)cchString,
205 pawcBuf, (int)(cwcBuf - 1));
206 if (cwcToWrite > 0)
207 {
208 int rc;
209 pawcBuf[cwcToWrite++] = '\n';
210 pawcBuf[cwcToWrite] = '\0';
211
212 /* Let the CRT do the rest. At least the Visual C++ 2010 CRT
213 sources indicates _cputws will do the right thing. */
214 fflush(stdout);
215 rc = _cputws(pawcBuf);
216 if (pawcBufFree)
217 free(pawcBufFree);
218 if (rc >= 0)
219 return 0;
220 return -1;
221 }
222 free(pawcBufFree);
223 }
224 }
225 }
226 }
227 }
228
229 /*
230 * Fallback.
231 */
232 cch = fwrite(pszString, cchString, 1, stdout);
233 if (cch == cchString)
234 {
235 if (putc('\n', stdout) != EOF)
236 return 0;
237 }
238 return -1;
239}
240
241
242/**
243 * Replaces puts for MSC to speed up console output.
244 *
245 * @returns Units written; 0 & errno on failure.
246 * @param pszString The string to write (no newline added).
247 * @param pFile The output file.
248 */
249DLL_IMPORT
250int __cdecl fputs(const char *pszString, FILE *pFile)
251{
252 size_t cchString = strlen(pszString);
253 size_t cch = maybe_con_fwrite(pszString, cchString, 1, pFile);
254 if (cch == cchString)
255 return 0;
256 return -1;
257}
258
259
260
261void * const __imp_printf = (void *)(uintptr_t)printf;
262void * const __imp_vprintf = (void *)(uintptr_t)vprintf;
263void * const __imp_fprintf = (void *)(uintptr_t)fprintf;
264void * const __imp_puts = (void *)(uintptr_t)puts;
265void * const __imp_fputs = (void *)(uintptr_t)fputs;
266
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette