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