+#ifdef _WIN32
+
+typedef struct {
+ unsigned char buf[1024];
+ size_t ptr, len;
+} in_buffer;
+
+static int
+in_return_bytes(in_buffer *bb, unsigned char *buf, size_t len)
+{
+ if (bb->ptr < bb->len) {
+ size_t clen;
+
+ if (buf == NULL) {
+ return 1;
+ }
+ clen = bb->len - bb->ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(buf, bb->buf + bb->ptr, clen);
+ bb->ptr += clen;
+ if (bb->ptr == bb->len) {
+ bb->ptr = bb->len = 0;
+ }
+ return (int)clen;
+ }
+ return 0;
+}
+
+/*
+ * A buffered version of in_read(), using a buffer to return only
+ * full lines when feasible.
+ */
+static int
+in_read_buffered(HANDLE h_in, in_buffer *bb, unsigned char *buf, size_t len)
+{
+ int n;
+
+ if (len == 0) {
+ return 0;
+ }
+ n = in_return_bytes(bb, buf, len);
+ if (n != 0) {
+ return n;
+ }
+ for (;;) {
+ INPUT_RECORD inrec;
+ DWORD v;
+
+ if (!PeekConsoleInput(h_in, &inrec, 1, &v)) {
+ fprintf(stderr, "ERROR: PeekConsoleInput()"
+ " failed with 0x%08lX\n",
+ (unsigned long)GetLastError());
+ return -1;
+ }
+ if (v == 0) {
+ return 0;
+ }
+ if (!ReadConsoleInput(h_in, &inrec, 1, &v)) {
+ fprintf(stderr, "ERROR: ReadConsoleInput()"
+ " failed with 0x%08lX\n",
+ (unsigned long)GetLastError());
+ return -1;
+ }
+ if (v == 0) {
+ return 0;
+ }
+ if (inrec.EventType == KEY_EVENT
+ && inrec.Event.KeyEvent.bKeyDown)
+ {
+ int c;
+
+ c = inrec.Event.KeyEvent.uChar.AsciiChar;
+ if (c == '\n' || c == '\r' || c == '\t'
+ || (c >= 32 && c != 127))
+ {
+ if (c == '\r') {
+ c = '\n';
+ }
+ bb->buf[bb->ptr ++] = (unsigned char)c;
+ printf("%c", c);
+ fflush(stdout);
+ bb->len = bb->ptr;
+ if (bb->len == sizeof bb->buf || c == '\n') {
+ bb->ptr = 0;
+ return in_return_bytes(bb, buf, len);
+ }
+ }
+ }
+ }
+}
+
+static int
+in_avail_buffered(HANDLE h_in, in_buffer *bb)
+{
+ return in_read_buffered(h_in, bb, NULL, 1);
+}
+
+#endif
+