Skip to content

Commit 6ac4404

Browse files
committed
Improved console output + implemented option to force explicit flushing.
1 parent 59788c7 commit 6ac4404

File tree

2 files changed

+60
-16
lines changed

2 files changed

+60
-16
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ A simple [**`tee`**](https://en.wikipedia.org/wiki/Tee_(command)) implementation
88
tee for Windows
99
1010
Usage:
11-
your_program.exe [options] | tee.exe [--append] <output_file>
11+
your_program.exe [options] | tee.exe [--append] [--flush] <output_file>
1212
```
1313

1414
## License

tee.c

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@
1919
#include <Windows.h>
2020
#include <ShellAPI.h>
2121

22-
#define BUFFSIZE 4096U
23-
2422
#define HANDLE_WRITE_ERROR(OFFSET) do \
2523
{ \
26-
print(hStdErr, "[tee] Error: Not all data could be written!\n\n"); \
24+
write_text(hStdErr, L"[tee] Error: Not all data could be written!\n\n"); \
2725
OFFSET = MAXDWORD; \
2826
} \
2927
while (0)
@@ -51,6 +49,8 @@ while (0)
5149
} \
5250
while (0)
5351

52+
#define BUFFSIZE 4096U
53+
5454
static volatile BOOL g_stopping = FALSE;
5555

5656
static BOOL WINAPI console_handler(const DWORD ctrlType)
@@ -60,18 +60,50 @@ static BOOL WINAPI console_handler(const DWORD ctrlType)
6060
case CTRL_C_EVENT:
6161
case CTRL_BREAK_EVENT:
6262
case CTRL_CLOSE_EVENT:
63-
MessageBoxW(NULL, L"CTRL_C_EVENT", NULL, MB_TOPMOST);
6463
g_stopping = TRUE;
6564
return TRUE;
6665
default:
6766
return FALSE;
6867
}
6968
}
7069

71-
static void print(const HANDLE handle, const char* const text)
70+
static char *utf16_to_utf8(const wchar_t *const input)
71+
{
72+
const int buff_size = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL);
73+
if (buff_size > 0)
74+
{
75+
char *const buffer = (char*)LocalAlloc(LPTR, buff_size);
76+
if (buffer)
77+
{
78+
const int result = WideCharToMultiByte(CP_UTF8, 0, input, -1, buffer, buff_size, NULL, NULL);
79+
if ((result > 0) && (result <= buff_size))
80+
{
81+
return buffer;
82+
}
83+
LocalFree(buffer);
84+
}
85+
}
86+
return NULL;
87+
}
88+
89+
static BOOL write_text(const HANDLE handle, const wchar_t *const text)
7290
{
91+
BOOL result = FALSE;
7392
DWORD written;
74-
WriteFile(handle, text, lstrlenA(text), &written, NULL);
93+
if (GetConsoleMode(handle, &written))
94+
{
95+
result = WriteConsoleW(handle, text, lstrlenW(text), &written, NULL);
96+
}
97+
else
98+
{
99+
char *const utf8_text = utf16_to_utf8(text);
100+
if (utf8_text)
101+
{
102+
result = WriteFile(handle, utf8_text, lstrlenA(utf8_text), &written, NULL);
103+
LocalFree(utf8_text);
104+
}
105+
}
106+
return result;
75107
}
76108

77109
int wmain(const int argc, const wchar_t *const argv[])
@@ -86,13 +118,13 @@ int wmain(const int argc, const wchar_t *const argv[])
86118

87119
if ((argc < 2) || (lstrcmpiW(argv[1], L"/?") == 0) || (lstrcmpiW(argv[1], L"--help") == 0))
88120
{
89-
print(hStdErr, "tee for Windows [" __DATE__ "]\n\n");
90-
print(hStdErr, "Usage:\n");
91-
print(hStdErr, " your_program.exe [options] | tee.exe [--append] <output_file>\n\n");
121+
write_text(hStdErr, L"tee for Windows [" TEXT(__DATE__) L"]\n\n");
122+
write_text(hStdErr, L"Usage:\n");
123+
write_text(hStdErr, L" your_program.exe [options] | tee.exe [--append] [--flush] <output_file>\n\n");
92124
return 1;
93125
}
94126

95-
BOOL append = FALSE;
127+
BOOL append = FALSE, flush = FALSE;
96128
int argOff = 1;
97129

98130
while (argOff < argc)
@@ -108,28 +140,34 @@ int wmain(const int argc, const wchar_t *const argv[])
108140
{
109141
append = TRUE;
110142
}
143+
else if (lstrcmpiW(option, L"flush") == 0)
144+
{
145+
flush = TRUE;
146+
}
111147
else
112148
{
113-
print(hStdErr, "[tee] Error: Invalid option encountered!\n\n");
149+
write_text(hStdErr, L"[tee] Error: Invalid option \"--");
150+
write_text(hStdErr, option);
151+
write_text(hStdErr, L"\" encountered!\n\n");
114152
return 1;
115153
}
116154
}
117155
else
118156
{
119-
break;
157+
break; /*stop option processing*/
120158
}
121159
}
122160

123161
if (argOff >= argc)
124162
{
125-
print(hStdErr, "[tee] Error: Output file name is missing!\n\n");
163+
write_text(hStdErr, L"[tee] Error: Output file name is missing!\n\n");
126164
return 1;
127165
}
128166

129167
const HANDLE hFile = CreateFileW(argv[argOff], GENERIC_WRITE, FILE_SHARE_READ, NULL, append ? OPEN_ALWAYS : CREATE_ALWAYS, 0U, NULL);
130168
if (hFile == INVALID_HANDLE_VALUE)
131169
{
132-
print(hStdErr, "[tee] Error: Failed to open the output file for writing!\n\n");
170+
write_text(hStdErr, L"[tee] Error: Failed to open the output file for writing!\n\n");
133171
return -1;
134172
}
135173

@@ -138,7 +176,7 @@ int wmain(const int argc, const wchar_t *const argv[])
138176
LARGE_INTEGER offset = { .QuadPart = 0LL };
139177
if (!SetFilePointerEx(hFile, offset, NULL, FILE_END))
140178
{
141-
print(hStdErr, "[tee] Error: Failed to move the file pointer to the end of the file!\n\n");
179+
write_text(hStdErr, L"[tee] Error: Failed to move the file pointer to the end of the file!\n\n");
142180
CloseHandle(hFile);
143181
return -1;
144182
}
@@ -160,12 +198,18 @@ int wmain(const int argc, const wchar_t *const argv[])
160198
{
161199
WRITE_DATA(hStdOut, offsetStdOut);
162200
WRITE_DATA(hFile, offsetFile);
201+
if (flush)
202+
{
203+
FlushFileBuffers(hFile);
204+
}
163205
}
164206
}
165207

166208
cleanup:
167209

210+
FlushFileBuffers(hFile);
168211
CloseHandle(hFile);
212+
169213
return 0;
170214
}
171215

0 commit comments

Comments
 (0)