1 module libd.console.io;
2 
3 import libd.io.filesystem;
4 
5 __gshared FileStream g_stdout;
6 __gshared FileStream g_stderr;
7 __gshared FileStream g_stdin;
8 
9 void consoleWrite(Params...)(scope Params params) { consoleWriteImpl!g_stdout(params); }
10 void consoleWriteln(Params...)(scope Params params) { consoleWritelnImpl!g_stdout(params); }
11 bool consoleWritef(Params...)(scope bcstring spec, scope Params params) { return consoleWritefImpl!g_stdout(spec, params); }
12 bool consoleWritefln(Params...)(scope bcstring spec, scope Params params) { return consoleWriteflnImpl!g_stdout(spec, params); }
13 
14 bcstring consoleRead(scope char[] buffer)
15 {
16     if(!g_stdin.isOpen)
17         return null;
18 
19     const result = g_stdin.read(buffer);
20     if(!result.isValid)
21         return null;
22 
23     return buffer[0..result.value];
24 }
25 
26 String consoleRead(size_t maxInput = 512)()
27 {
28     char[maxInput] buffer;
29 
30     auto result = String(consoleRead(buffer[0..$]));
31     if(result.length && result[$-1] == '\n') // Remove the \n that usually comes through when the user presses ENTER
32         result.length = result.length - 1;
33 
34     return result;
35 }
36 
37 private void consoleWriteImpl(alias Stream, Params...)(scope Params params)
38 {
39     import libd.data.conv;
40     if(Stream.isOpen)
41     {
42         static foreach(i, param; params)
43         {{
44             alias ParamT = typeof(param);
45             static if(is(ParamT : bcstring))
46                 Stream.write(param);
47             else static if(is(ParamT : const String))
48                 Stream.write(params[i][0..$]);
49             else static if(is(ParamT == bool))
50                 Stream.write(param ? "true" : "false");
51             else static if(is(ParamT : const char))
52                 Stream.write((&params[i])[0..1]);
53             else
54                 Stream.write(params[i].to!String[0..$]);
55         }}
56     }
57 }
58 
59 private void consoleWritelnImpl(alias Stream, Params...)(scope Params params)
60 {
61     consoleWriteImpl!Stream(params);
62     Stream.write("\n");
63 }
64 
65 private bool consoleWritefImpl(alias Stream, Params...)(scope bcstring spec, scope Params params)
66 {
67     import libd.data.format;
68 
69     auto result = format(spec, params);
70     if(!result.isValid)
71     {
72         consoleWritelnImpl!Stream("Failed to format string.");
73         displayError(result.error);
74         return false;
75     }
76 
77     consoleWriteImpl!Stream(result.value[0..$]);
78     return true;
79 }
80 
81 private bool consoleWriteflnImpl(alias Stream, Params...)(scope bcstring spec, scope Params params)
82 {
83     const result = consoleWritefImpl!Stream(spec, params);
84     if(!result)
85         return false;
86 
87     Stream.write("\n");
88     return true;
89 }
90 
91 @("not for public use")
92 void _d_console_io_init()
93 {
94     version(Windows)
95     {
96         import runtime.system.windows;
97         void createStream(ref FileStream file, DWORD stdType, FileUsage usage)
98         {
99             const result = GetStdHandle(stdType);
100             if(result == INVALID_HANDLE_VALUE || !result)
101                 return;
102             file = FileStream(cast(HANDLE)result, usage);
103         }
104 
105         createStream(g_stdout, STD_OUTPUT_HANDLE, FileUsage.write);
106         createStream(g_stderr, STD_ERROR_HANDLE, FileUsage.write);
107         createStream(g_stdin, STD_INPUT_HANDLE, FileUsage.read);
108 
109         HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
110         DWORD mode = 0;
111         GetConsoleMode(stdOut, &mode);
112         mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
113         SetConsoleMode(stdOut, mode);
114     }
115 }