1 /*
2 * $Id: conterm.c,v 1.1 2005-09-18 22:05:37 dhmunro Exp $
3 * console specific part of wstdio.c
4 */
5 /* Copyright (c) 2005, The Regents of the University of California.
6 * All rights reserved.
7 * This file is part of yorick (http://yorick.sourceforge.net).
8 * Read the accompanying LICENSE file for details.
9 */
10
11 #include "playw.h"
12
13 static void con_sender(void *context);
14
15 static HANDLE w_hin = INVALID_HANDLE_VALUE;
16 static HANDLE w_hout = INVALID_HANDLE_VALUE;
17 static HANDLE w_herr = INVALID_HANDLE_VALUE;
18 static int w_oeinit = 0;
19 static HANDLE stdin_ready = 0;
20 static HANDLE stdin_accepted = 0;
21 static DWORD WINAPI stdin_main(LPVOID lp);
22
23 int
con_stdinit(void (** wout)(char *,long),void (** werr)(char *,long))24 con_stdinit(void (**wout)(char*,long), void (**werr)(char*,long))
25 {
26 HANDLE h;
27 *wout = con_stdout;
28 *werr = con_stderr;
29 /* documentation for MsgWaitForMultipleObjects says:
30 * Windows 95: No handle may be a duplicate of another handle
31 * created using DuplicateHandle.
32 * - except for true console input, files are not on the list
33 * of things any of the wait functions can wait for
34 * - apparently, emacs uses the recommended procedure for starting
35 * a subprocess with redirected stdin, which involves DuplicateHandle
36 * - in any event, just using w_hin to w_add_input fails in
37 * Win95 for use with emacs shell mode */
38 w_hin = GetStdHandle(STD_INPUT_HANDLE);
39 w_hout = GetStdHandle(STD_OUTPUT_HANDLE);
40 if (w_hin==INVALID_HANDLE_VALUE || w_hout==INVALID_HANDLE_VALUE)
41 return 1;
42 w_herr = GetStdHandle(STD_ERROR_HANDLE);
43 if (w_herr == INVALID_HANDLE_VALUE) w_herr = w_hout;
44 w_oeinit = 3;
45 stdin_ready = CreateEvent(0,0,0,0);
46 stdin_accepted = CreateEvent(0,0,0,0);
47 if (stdin_ready && stdin_accepted &&
48 w_hin!=INVALID_HANDLE_VALUE && w_hout!=INVALID_HANDLE_VALUE) {
49 UINT id;
50 h = CreateThread(0,0, stdin_main, 0, 0, (void *)&id);
51 if (h) {
52 w_add_input(stdin_ready, con_sender, 0);
53 Sleep(0);
54 CloseHandle(h);
55 } else {
56 CloseHandle(stdin_ready);
57 CloseHandle(stdin_accepted);
58 }
59 }
60 return 0;
61 }
62
63 /* separate thread blocks waiting for stdin, signals on arrival */
64 static DWORD WINAPI
stdin_main(LPVOID lp)65 stdin_main(LPVOID lp)
66 {
67 int i = 0;
68 DWORD n = 0;
69 DWORD sz = 256;
70 char *buf = w_sendbuf(sz);
71 char tmp[256];
72 int ii, no_wait = 1;
73 for (;; i=0,sz=256) {
74 for (;;) {
75 if (!ReadFile(w_hin, tmp, 256, &n, 0))
76 return 1; /* serious error -- stdin unreadable */
77 if (tmp[0] == '\03') {
78 /* stdin_ready was set -- reset may avoid calling con_sender */
79 if (!no_wait) ResetEvent(stdin_ready);
80 w_sigint(1);
81 /* be sure stdin_accepted is set whether or not con_sender called */
82 if (!no_wait) SetEvent(stdin_accepted);
83 i = 0;
84 break;
85 }
86 if (no_wait || WaitForSingleObject(stdin_accepted, 0)==WAIT_OBJECT_0) {
87 no_wait = 1;
88 for (ii=0 ; (unsigned int)ii<n ; ii++) buf[i+ii] = tmp[ii];
89 i += ii;
90 if (!i || buf[i-1]=='\n') break;
91 } else {
92 MessageBeep(MB_OK);
93 }
94 if ((unsigned int)i+256 >= sz) {
95 sz += sz;
96 buf = w_sendbuf(sz);
97 }
98 }
99 buf[i] = '\0';
100 if (i) {
101 SetEvent(stdin_ready);
102 no_wait = 0;
103 }
104 if (i>=256) w_sendbuf(256);
105 }
106 return 0;
107 }
108
109 /* ARGSUSED */
110 static void
con_sender(void * context)111 con_sender(void *context)
112 {
113 SetEvent(stdin_accepted);
114 w_deliver(w_sendbuf(-1));
115 }
116
117 void
con_stdout(char * line,long len)118 con_stdout(char *line, long len)
119 {
120 DWORD n;
121 if (w_hout == INVALID_HANDLE_VALUE) {
122 if (w_oeinit & 1) return;
123 w_hout = GetStdHandle(STD_OUTPUT_HANDLE);
124 w_oeinit |= 1;
125 if (w_hout == INVALID_HANDLE_VALUE) return;
126 }
127 WriteFile(w_hout, line, len, &n, 0);
128 FlushFileBuffers(w_hout);
129 }
130
131 void
con_stderr(char * line,long len)132 con_stderr(char *line, long len)
133 {
134 DWORD n;
135 if (w_herr == INVALID_HANDLE_VALUE) {
136 if (w_oeinit & 2) return;
137 w_herr = GetStdHandle(STD_ERROR_HANDLE);
138 w_oeinit |= 2;
139 if (w_herr == INVALID_HANDLE_VALUE) return;
140 }
141 WriteFile(w_herr, line, len, &n, 0);
142 FlushFileBuffers(w_hout);
143 }
144