1 | #include <windows.h>
|
2 |
|
3 | #include <assert.h>
|
4 | #include <stdint.h>
|
5 | #include <stdlib.h>
|
6 |
|
7 | #include <string>
|
8 | #include <vector>
|
9 |
|
10 | static std::wstring mbsToWcs(const std::string &s) {
|
11 | const size_t len = mbstowcs(nullptr, s.c_str(), 0);
|
12 | if (len == static_cast<size_t>(-1)) {
|
13 | assert(false && "mbsToWcs: invalid string");
|
14 | }
|
15 | std::wstring ret;
|
16 | ret.resize(len);
|
17 | const size_t len2 = mbstowcs(&ret[0], s.c_str(), len);
|
18 | assert(len == len2);
|
19 | return ret;
|
20 | }
|
21 |
|
22 | uint32_t parseHex(wchar_t ch, bool &invalid) {
|
23 | if (ch >= L'0' && ch <= L'9') {
|
24 | return ch - L'0';
|
25 | } else if (ch >= L'a' && ch <= L'f') {
|
26 | return ch - L'a' + 10;
|
27 | } else if (ch >= L'A' && ch <= L'F') {
|
28 | return ch - L'A' + 10;
|
29 | } else {
|
30 | invalid = true;
|
31 | return 0;
|
32 | }
|
33 | }
|
34 |
|
35 | int main(int argc, char *argv[]) {
|
36 | std::vector<std::wstring> args;
|
37 | for (int i = 1; i < argc; ++i) {
|
38 | args.push_back(mbsToWcs(argv[i]));
|
39 | }
|
40 |
|
41 | std::wstring out;
|
42 | for (const auto &arg : args) {
|
43 | if (!out.empty()) {
|
44 | out.push_back(L' ');
|
45 | }
|
46 | for (size_t i = 0; i < arg.size(); ++i) {
|
47 | wchar_t ch = arg[i];
|
48 | wchar_t nch = i + 1 < arg.size() ? arg[i + 1] : L'\0';
|
49 | if (ch == L'\\') {
|
50 | switch (nch) {
|
51 | case L'a': ch = L'\a'; ++i; break;
|
52 | case L'b': ch = L'\b'; ++i; break;
|
53 | case L'e': ch = L'\x1b'; ++i; break;
|
54 | case L'f': ch = L'\f'; ++i; break;
|
55 | case L'n': ch = L'\n'; ++i; break;
|
56 | case L'r': ch = L'\r'; ++i; break;
|
57 | case L't': ch = L'\t'; ++i; break;
|
58 | case L'v': ch = L'\v'; ++i; break;
|
59 | case L'\\': ch = L'\\'; ++i; break;
|
60 | case L'\'': ch = L'\''; ++i; break;
|
61 | case L'\"': ch = L'\"'; ++i; break;
|
62 | case L'\?': ch = L'\?'; ++i; break;
|
63 | case L'x':
|
64 | if (i + 3 < arg.size()) {
|
65 | bool invalid = false;
|
66 | uint32_t d1 = parseHex(arg[i + 2], invalid);
|
67 | uint32_t d2 = parseHex(arg[i + 3], invalid);
|
68 | if (!invalid) {
|
69 | i += 3;
|
70 | ch = (d1 << 4) | d2;
|
71 | }
|
72 | }
|
73 | break;
|
74 | case L'u':
|
75 | if (i + 5 < arg.size()) {
|
76 | bool invalid = false;
|
77 | uint32_t d1 = parseHex(arg[i + 2], invalid);
|
78 | uint32_t d2 = parseHex(arg[i + 3], invalid);
|
79 | uint32_t d3 = parseHex(arg[i + 4], invalid);
|
80 | uint32_t d4 = parseHex(arg[i + 5], invalid);
|
81 | if (!invalid) {
|
82 | i += 5;
|
83 | ch = (d1 << 24) | (d2 << 16) | (d3 << 8) | d4;
|
84 | }
|
85 | }
|
86 | break;
|
87 | default: break;
|
88 | }
|
89 | }
|
90 | out.push_back(ch);
|
91 | }
|
92 | }
|
93 |
|
94 | DWORD actual = 0;
|
95 | if (!WriteConsoleW(
|
96 | GetStdHandle(STD_OUTPUT_HANDLE),
|
97 | out.c_str(),
|
98 | out.size(),
|
99 | &actual,
|
100 | nullptr)) {
|
101 | fprintf(stderr, "WriteConsole failed (is stdout a console?)\n");
|
102 | exit(1);
|
103 | }
|
104 |
|
105 | return 0;
|
106 | }
|