git subrepo clone https://github.com/libretro/libretro-common.git deps/libretro-common
[pcsx_rearmed.git] / deps / libretro-common / streams / stdin_stream.c
1 /* Copyright  (C) 2010-2020 The RetroArch team
2  *
3  * ---------------------------------------------------------------------------------------
4  * The following license statement only applies to this file (stdin_stream.c).
5  * ---------------------------------------------------------------------------------------
6  *
7  * Permission is hereby granted, free of charge,
8  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <ctype.h>
27
28 #ifdef _WIN32
29 #ifndef _XBOX
30 #include <windows.h>
31 #endif
32 #include <direct.h>
33 #else
34 #include <unistd.h>
35 #endif
36
37 #include <boolean.h>
38 #include <retro_environment.h>
39 #include <streams/stdin_stream.h>
40
41 #if (defined(_WIN32) && defined(_XBOX)) || defined(__WINRT__) || !defined(__PSL1GHT__) && defined(__PS3__)
42 size_t read_stdin(char *buf, size_t size)
43 {
44    /* Not implemented. */
45    return 0;
46 }
47 #elif defined(_WIN32)
48 size_t read_stdin(char *buf, size_t size)
49 {
50    DWORD i;
51    DWORD has_read = 0;
52    DWORD avail    = 0;
53    bool echo      = false;
54    HANDLE hnd     = GetStdHandle(STD_INPUT_HANDLE);
55
56    if (hnd == INVALID_HANDLE_VALUE)
57       return 0;
58
59    /* Check first if we're a pipe
60     * (not console). */
61
62    /* If not a pipe, check if we're running in a console. */
63    if (!PeekNamedPipe(hnd, NULL, 0, NULL, &avail, NULL))
64    {
65       INPUT_RECORD recs[256];
66       bool has_key   = false;
67       DWORD mode     = 0;
68       DWORD has_read = 0;
69
70       if (!GetConsoleMode(hnd, &mode))
71          return 0;
72
73       if ((mode & (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))
74             && !SetConsoleMode(hnd,
75                mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)))
76          return 0;
77
78       /* Win32, Y U NO SANE NONBLOCK READ!? */
79       if (!PeekConsoleInput(hnd, recs,
80                sizeof(recs) / sizeof(recs[0]), &has_read))
81          return 0;
82
83       for (i = 0; i < has_read; i++)
84       {
85          /* Very crude, but should get the job done. */
86          if (recs[i].EventType == KEY_EVENT &&
87                recs[i].Event.KeyEvent.bKeyDown &&
88                (isgraph(recs[i].Event.KeyEvent.wVirtualKeyCode) ||
89                 recs[i].Event.KeyEvent.wVirtualKeyCode == VK_RETURN))
90          {
91             has_key = true;
92             echo    = true;
93             avail   = size;
94             break;
95          }
96       }
97
98       if (!has_key)
99       {
100          FlushConsoleInputBuffer(hnd);
101          return 0;
102       }
103    }
104
105    if (!avail)
106       return 0;
107
108    if (avail > size)
109       avail = size;
110
111    if (!ReadFile(hnd, buf, avail, &has_read, NULL))
112       return 0;
113
114    for (i = 0; i < has_read; i++)
115       if (buf[i] == '\r')
116          buf[i] = '\n';
117
118    /* Console won't echo for us while in non-line mode,
119     * so do it manually ... */
120    if (echo)
121    {
122       HANDLE hnd_out = GetStdHandle(STD_OUTPUT_HANDLE);
123       if (hnd_out != INVALID_HANDLE_VALUE)
124       {
125          DWORD has_written;
126          WriteConsole(hnd_out, buf, has_read, &has_written, NULL);
127       }
128    }
129
130    return has_read;
131 }
132 #else
133 size_t read_stdin(char *buf, size_t size)
134 {
135    size_t has_read = 0;
136
137    while (size)
138    {
139       ssize_t ret = read(STDIN_FILENO, buf, size);
140
141       if (ret <= 0)
142          break;
143
144       buf      += ret;
145       has_read += ret;
146       size     -= ret;
147    }
148
149    return has_read;
150 }
151 #endif