|
@@ -26,7 +26,242 @@
|
|
|
// 获取CodePage, 并将内存中utf-8字符串转换为对应编码输出
|
|
|
// cygwin环境下, 终端默认为uft-8
|
|
|
|
|
|
-static bool stdin_empty = true; // stdin读取内容遇到 \n, 用于检测stdin是否为空
|
|
|
+#define BUFF_SIZE (40960)
|
|
|
+static char buffer[BUFF_SIZE] = "";
|
|
|
+static size_t index = 0;
|
|
|
+static size_t next = 0;
|
|
|
+static size_t end = 0;
|
|
|
+
|
|
|
+static int setCursorPosition(HANDLE std_o, CONSOLE_SCREEN_BUFFER_INFO *info_, SHORT x_) {
|
|
|
+ CONSOLE_SCREEN_BUFFER_INFO info;
|
|
|
+ if (info_ == NULL) {
|
|
|
+ if (!GetConsoleScreenBufferInfo(std_o, &info))
|
|
|
+ return -1;
|
|
|
+ info_ = &info;
|
|
|
+ }
|
|
|
+ int x = info_->dwCursorPosition.X;
|
|
|
+ int y = info_->dwCursorPosition.Y;
|
|
|
+
|
|
|
+ x += x_;
|
|
|
+ while (x >= info_->dwSize.X) {
|
|
|
+ x -= info_->dwSize.X;
|
|
|
+ y++;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (x < 0) {
|
|
|
+ x += info_->dwSize.X;
|
|
|
+ y--;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (y < 0)
|
|
|
+ y = 0;
|
|
|
+ else if (y > info_->dwSize.Y)
|
|
|
+ y = info_->dwSize.Y;
|
|
|
+
|
|
|
+ SetConsoleCursorPosition(std_o, (COORD){.X=(SHORT)x, .Y=(SHORT)y});
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static int nextToEnd(HANDLE *std_o) {
|
|
|
+ CONSOLE_SCREEN_BUFFER_INFO info;
|
|
|
+ if (!GetConsoleScreenBufferInfo(std_o, &info))
|
|
|
+ return 0;
|
|
|
+ if (setCursorPosition(std_o, &info, (SHORT)(end - next)) == -1)
|
|
|
+ return 0;
|
|
|
+ next = end;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static int moveBuffer(void) {
|
|
|
+ if (index == 0)
|
|
|
+ return 0;
|
|
|
+ memmove(buffer, buffer + index, BUFF_SIZE - index);
|
|
|
+ end = end - index;
|
|
|
+ next = next - index;
|
|
|
+ index = 0;
|
|
|
+ memset(buffer + end, 0, BUFF_SIZE - end);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static int backChar(HANDLE std_o) {
|
|
|
+ if (index != next) { // 删除一个字符
|
|
|
+ if (setCursorPosition(std_o, NULL, -1) == -1) // 先一定位置在-1
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ CONSOLE_SCREEN_BUFFER_INFO info;
|
|
|
+ if (!GetConsoleScreenBufferInfo(std_o, &info))
|
|
|
+ return 0;
|
|
|
+ memmove(buffer + next - 1, buffer + next, end - next + 1);
|
|
|
+
|
|
|
+ SetConsoleCursorPosition(std_o, info.dwCursorPosition);
|
|
|
+ for (size_t n = next - 1; n < end; n++)
|
|
|
+ fputc(' ', stdout);
|
|
|
+
|
|
|
+ SetConsoleCursorPosition(std_o, info.dwCursorPosition);
|
|
|
+ fputs(buffer + next - 1, stdout);
|
|
|
+
|
|
|
+ SetConsoleCursorPosition(std_o, info.dwCursorPosition);
|
|
|
+ next--;
|
|
|
+ end--;
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static int enterChar(HANDLE std_o) {
|
|
|
+ if(!nextToEnd(std_o))
|
|
|
+ return 0;
|
|
|
+ buffer[end] = '\n';
|
|
|
+ end++;
|
|
|
+ next++;
|
|
|
+ fputc('\n', stdout);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * 函数名: newChar
|
|
|
+ * 目标: 记录字符并显示
|
|
|
+ * 返回1表示成功
|
|
|
+ * 返回0表示失败
|
|
|
+ */
|
|
|
+static int newChar(HANDLE std_i, char ch) {
|
|
|
+ if (ch == 0)
|
|
|
+ return 1;
|
|
|
+ if (end == BUFF_SIZE && !moveBuffer()) // 对比 end 而不是 next
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (next != end) { // insert 模式
|
|
|
+ CONSOLE_SCREEN_BUFFER_INFO info;
|
|
|
+ if (!GetConsoleScreenBufferInfo(std_i, &info))
|
|
|
+ return 0;
|
|
|
+ memmove(buffer + next + 1, buffer + next, end - next);
|
|
|
+ buffer[next] = ch;
|
|
|
+ fputs(buffer + next, stdout);
|
|
|
+ if (setCursorPosition(std_i, &info, 1) == -1)
|
|
|
+ return 0;
|
|
|
+ } else {
|
|
|
+ buffer[next] = ch;
|
|
|
+ fputc(ch, stdout);
|
|
|
+ }
|
|
|
+
|
|
|
+ next++;
|
|
|
+ end++;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * 函数名: checkNewInput
|
|
|
+ * 目标: 获取输入并且显示
|
|
|
+ * 返回-1表示遭遇错误
|
|
|
+ * 返回0表示未完成行读取
|
|
|
+ * 返回1表示完成行读取
|
|
|
+ */
|
|
|
+static int checkNewInput(HANDLE *std_i, HANDLE *std_o) {
|
|
|
+ DWORD len = 0;
|
|
|
+ DWORD oldm;
|
|
|
+ if (!GetConsoleMode(std_i, &oldm))
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if (!GetNumberOfConsoleInputEvents(std_i, &len))
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ for (int i = 0; i < len; i++) {
|
|
|
+ INPUT_RECORD record;
|
|
|
+ DWORD read_len;
|
|
|
+ if (!ReadConsoleInputA(std_i, &record, 1, &read_len) || read_len == 0)
|
|
|
+ return -1;
|
|
|
+ if (record.EventType == KEY_EVENT) {
|
|
|
+ if (!record.Event.KeyEvent.bKeyDown)
|
|
|
+ continue;
|
|
|
+ else if (record.Event.KeyEvent.wVirtualKeyCode == VK_BACK) { // 退格
|
|
|
+ if (backChar(std_o) == 0)
|
|
|
+ return -1;
|
|
|
+ continue;
|
|
|
+ } if (record.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) { // 回车
|
|
|
+ if (enterChar(std_o) == 0)
|
|
|
+ return -1;
|
|
|
+ return 1;
|
|
|
+ } else if (record.Event.KeyEvent.wVirtualKeyCode == VK_LEFT) { // 左
|
|
|
+ CONSOLE_SCREEN_BUFFER_INFO info;
|
|
|
+ if (!GetConsoleScreenBufferInfo(std_o, &info))
|
|
|
+ return -1;
|
|
|
+ if (next > index) {
|
|
|
+ next--;
|
|
|
+ if (setCursorPosition(std_o, NULL, -1) == -1)
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ } else if (record.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT) { // 右
|
|
|
+ if (next < end) {
|
|
|
+ next++;
|
|
|
+ if(setCursorPosition(std_o, NULL, 1) == -1)
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int r = record.Event.KeyEvent.wRepeatCount; r > 0; r--) {
|
|
|
+ if (newChar(std_o, record.Event.KeyEvent.uChar.AsciiChar) == 0)
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int fcheck_stdin(HANDLE *std_i, HANDLE *std_o) {
|
|
|
+ if (end == index || end == 0 || buffer[end - 1] != '\n')
|
|
|
+ return checkNewInput(std_i, std_o);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+int fgetc_stdin(void) {
|
|
|
+ HANDLE *std_i = GetStdHandle(STD_INPUT_HANDLE);
|
|
|
+ HANDLE *std_o = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
+ if (std_i == INVALID_HANDLE_VALUE || std_o == INVALID_HANDLE_VALUE)
|
|
|
+ return EOF;
|
|
|
+
|
|
|
+ for (int fs = 0; fs != 1 ; fs = fcheck_stdin(std_i, std_o)) { // 阻塞
|
|
|
+ if (fs == -1)
|
|
|
+ return EOF;
|
|
|
+ }
|
|
|
+
|
|
|
+ int re = (int)buffer[index];
|
|
|
+ index++;
|
|
|
+ return re;
|
|
|
+}
|
|
|
+
|
|
|
+char *fgets_stdin_(char *buf, size_t len) {
|
|
|
+ HANDLE *std_i = GetStdHandle(STD_INPUT_HANDLE);
|
|
|
+ HANDLE *std_o = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
+ if (std_i == INVALID_HANDLE_VALUE || std_o == INVALID_HANDLE_VALUE)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ for (int fs = 0; fs != 1 ; fs = fcheck_stdin(std_i, std_o)) { // 阻塞
|
|
|
+ if (fs == -1)
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ size_t len_ = len - 1;
|
|
|
+ if (end - index < len_)
|
|
|
+ len_ = end - index;
|
|
|
+ memcpy(buf, buffer+index, len_);
|
|
|
+ index += len_;
|
|
|
+ nextToEnd(std_o);
|
|
|
+ buf[len_] = '\0'; // 最后一位
|
|
|
+ return buf;
|
|
|
+}
|
|
|
+
|
|
|
+bool fclear_stdin(void) {
|
|
|
+ HANDLE *std_o = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
+ if (std_o == INVALID_HANDLE_VALUE)
|
|
|
+ return true;
|
|
|
+ nextToEnd(std_o);
|
|
|
+ index = 0;
|
|
|
+ end = 0;
|
|
|
+ next = 0;
|
|
|
+ memset(buffer, 0, BUFF_SIZE);
|
|
|
+ return false;
|
|
|
+}
|
|
|
|
|
|
static int convertMultiByte(char **dest, char *str, UINT from, UINT to) {
|
|
|
if (str == NULL || dest == NULL)
|
|
@@ -55,7 +290,7 @@ int fgets_stdin(char **dest, int len) {
|
|
|
char *wstr = calloc(len, sizeof(char));
|
|
|
int re = 0;
|
|
|
|
|
|
- if (!_isatty(fileno(stdin))) {
|
|
|
+ if (!_isatty(_fileno(stdin))) {
|
|
|
*dest = NEW_STR(len);
|
|
|
re = fgets(*dest, len, stdin) != NULL;
|
|
|
if (!re)
|
|
@@ -64,28 +299,25 @@ int fgets_stdin(char **dest, int len) {
|
|
|
}
|
|
|
|
|
|
UINT code_page = GetConsoleCP();
|
|
|
- if (fgets(wstr, len, stdin) != NULL)
|
|
|
+ if (fgets_stdin_(wstr, len) != NULL)
|
|
|
re = convertMultiByte(dest, wstr, code_page, CP_UTF8);
|
|
|
- if (strchr(wstr, '\n') != NULL)
|
|
|
- stdin_empty = true; // 没有读取到\n说明stdin还有内容
|
|
|
- else
|
|
|
- stdin_empty = false; // 没有读取到\n说明stdin还有内容
|
|
|
return re;
|
|
|
}
|
|
|
|
|
|
-int fgetchar_stdin(void) {
|
|
|
- int ch = getc(stdin);
|
|
|
- if (ch == '\n')
|
|
|
- stdin_empty = true;
|
|
|
- else
|
|
|
- stdin_empty = false;
|
|
|
- return ch;
|
|
|
-}
|
|
|
-
|
|
|
int fungetc_stdin(int ch) {
|
|
|
- int re = ungetc(ch, stdin);
|
|
|
- stdin_empty = false;
|
|
|
- return re;
|
|
|
+ if (ch == 0 || index == 0 && end == BUFF_SIZE)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (index != 0) {
|
|
|
+ index--;
|
|
|
+ buffer[index] = (char)ch;
|
|
|
+ } else if (end != BUFF_SIZE) { // index == 0;
|
|
|
+ memmove(buffer, buffer + 1, end); // 往回移动
|
|
|
+ end++;
|
|
|
+ next++;
|
|
|
+ buffer[0] = (char) ch;
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -95,11 +327,12 @@ int fungetc_stdin(int ch) {
|
|
|
* 无内容则返回false
|
|
|
*/
|
|
|
bool checkStdin(void) {
|
|
|
- if (!_isatty(fileno(stdin)))
|
|
|
- return true;
|
|
|
- if (!stdin_empty)
|
|
|
- return true;
|
|
|
- return _kbhit();
|
|
|
+ HANDLE *std_i = GetStdHandle(STD_INPUT_HANDLE);
|
|
|
+ HANDLE *std_o = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
+ int fs = fcheck_stdin(std_i, std_o);
|
|
|
+ if (fs == 0)
|
|
|
+ return false;
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
static int fputs_std_(char *str, FILE *std) {
|
|
@@ -115,14 +348,14 @@ static int fputs_std_(char *str, FILE *std) {
|
|
|
}
|
|
|
|
|
|
int fputs_stdout(char *str) {
|
|
|
- if (_isatty(fileno(stdout)))
|
|
|
+ if (_isatty(_fileno(stdout)))
|
|
|
return fputs_std_(str, stdout);
|
|
|
fputs(str, stdout);
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
int fputs_stderr(char *str) {
|
|
|
- if (_isatty(fileno(stderr)))
|
|
|
+ if (_isatty(_fileno(stderr)))
|
|
|
return fputs_std_(str, stderr);
|
|
|
fputs(str, stderr);
|
|
|
return 1;
|
|
@@ -141,13 +374,13 @@ static size_t vprintf_std_(FILE *std, size_t buf_len, char *format, va_list ap)
|
|
|
}
|
|
|
|
|
|
size_t vprintf_stdout(size_t buf_len, char *format, va_list ap) {
|
|
|
- if (_isatty(fileno(stdout)))
|
|
|
+ if (_isatty(_fileno(stdout)))
|
|
|
return vprintf_std_(stdout, buf_len, format, ap);
|
|
|
return vfprintf(stdout, format, ap);
|
|
|
}
|
|
|
|
|
|
size_t vprintf_stderr(size_t buf_len, char *format, va_list ap) {
|
|
|
- if (_isatty(fileno(stderr)))
|
|
|
+ if (_isatty(_fileno(stderr)))
|
|
|
return vprintf_std_(stderr, buf_len, format, ap);
|
|
|
return vfprintf(stderr, format, ap);
|
|
|
}
|
|
@@ -210,4 +443,22 @@ bool checkStdin(void) {
|
|
|
return re;
|
|
|
}
|
|
|
|
|
|
+bool fclear_stdin(void) {
|
|
|
+ if (!isatty(fileno(stdin)))
|
|
|
+ return true;
|
|
|
+ bool re = false;
|
|
|
+
|
|
|
+ int oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
|
|
|
+ fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
|
|
|
+
|
|
|
+ int ch;
|
|
|
+ do {
|
|
|
+ ch = fgetc(stdin);
|
|
|
+ CLEAR_FERROR(stdin);
|
|
|
+ } while (ch != EOF);
|
|
|
+
|
|
|
+ fcntl(STDIN_FILENO, F_SETFL, oldf);
|
|
|
+ return !ferror(stdin) && !feof(stdin);
|
|
|
+}
|
|
|
+
|
|
|
#endif
|