Annotation of OpenXM_contrib/gnuplot/win/pgnuplot.c, Revision 1.1.1.2
1.1 maekawa 1: /*
2: * pgnuplot.c -- pipe stdin to wgnuplot
3: *
4: * Version 0.3 -- 30 Jun 1999
5: *
6: * This program is based on pgnuplot.c Copyright (C) 1999 Hans-Bernhard Broeker
7: * with substantial modifications Copyright (C) 1999 Craig R. Schardt.
8: *
9: * The code is released to the public domain.
10: *
11: */
12:
13: /* Comments from original pgnuplot.c */
14: /*
15: * pgnuplot.c -- 'Pipe to gnuplot' Version 990608
16: *
17: * A small program, to be compiled as a Win32 console mode application.
18: * (NB: will not work on 16bit Windows, not even with Win32s installed).
19: *
20: * This program will accept commands on STDIN, and pipe them to an
21: * active (or newly created) wgnuplot text window. Command line options
22: * are passed on to wgnuplot.
23: *
24: * Effectively, this means `pgnuplot' is an almost complete substitute
25: * for `wgnuplot', on the command line, with the added benefit that it
26: * does accept commands from redirected stdin. (Being a Windows GUI
27: * application, `wgnuplot' itself cannot read stdin at all.)
28: *
29: * Copyright (C) 1999 by Hans-Bernhard Broeker
30: * (broeker@physik.rwth-aachen.de)
31: * This file is in the public domain. It might become part of a future
32: * distribution of gnuplot.
33: *
34: * based on a program posted to comp.graphics.apps.gnuplot in May 1998 by
35: * jl Hamel <jlhamel@cea.fr>
36: *
37: * Changes relative to that original version:
38: * -- doesn't start a new wgnuplot if one already is running.
39: * -- doesn't end up in an endless loop if STDIN is not redirected.
40: * (refuses to read from STDIN at all, in that case).
41: * -- doesn't stop the wgnuplot session at the end of
42: * stdin, if it didn't start wgnuplot itself.
43: * -- avoids the usual buffer overrun problem with gets().
44: *
45: * For the record, I usually use MinGW32 to compile this, with a
46: * command line looking like this:
47: *
48: * gcc -o pgnuplot.exe pgnuplot.c -luser32 -s
49: */
50:
51: /* Modifications by Craig R. Schardt (17 Jun 1999)
52:
53: Copyright (C) 1999 by Craig R. Schardt (craig@silica.mse.ufl.edu)
54:
55: Major changes: (See the explanation below for more information)
56: + Always starts a new instance of wgnuplot.
57: + If stdin isn't redirected then start wgnuplot and give it focus.
58: + Uses CreateProcess() instead of WinExec() to start wgnuplot when stdin
59: is redirected.
60:
61: Other changes:
62: + New technique for building the command line to pass to wgnuplot.exe
63: which is less complicated and seems to work more reliably than the old
64: technique.
65: + Simplified message passing section of the code.
66: + All printf(...) statements are now fprintf(stderr,...) so that errors
67: are sent to the console, even if stdout is redirected.
68:
69: The previous version of pgnuplot would fail when more than one program
70: tried to access wgnuplot simultaneously or when one program tried to start
71: more than one wgnuplot session. Only a single instance of wgnuplot would be
72: started and all input would be sent to that instance. When two or more programs
73: tried to pipe input to wgnuplot, the two seperate input streams would be sent
74: to one wgnuplot window resulting in one very confused copy of wgnuplot. The only
75: way to avoid this problem was to change pgnuplot so that it would start a
76: new instance of wgnuplot every time.
77:
78: Just starting a new instance of wgnuplot isn't enough. pgnuplot must also
79: make sure that the data on each stdin pipe is sent to the proper wgnuplot
80: instance. This is achieved by using CreateProcess() which returns a handle
81: to the newly created process. Once the process has initialized, it can be
82: searched for the text window and then data can be routed correctly. The search
83: is carried out by the EnumThreadWindows() call and the data passing is carried
84: out by a rewritten version of the original code. With these changes, pgnuplot
85: now behaves in a manner consistent with the behavior of gnuplot on UNIX
86: computers.
87:
88: This program has been compiled using Microsoft Visual C++ 4.0 with the
89: following command line:
90:
91: cl /O2 pgnuplot.c /link user32.lib
92:
93: The resulting program has been tested on WinNT and Win98 both by calling
94: it directly from the command line with and without redirected input. The
95: program also works on WinNT with a modified version of Gnuplot.py (a script
96: for interactive control of Gnuplot from Python).
97:
98: 22 JUN 1999:
99: + Fixed command line code to behave properly when the first
100: item is quoted in the original command line.
101:
102: 29 JUN 1999:
103: + Added some code to print the command line. This is for testing
104: only and should be removed before the general release. To enable,
105: compile with SHOWCMDLINE defined.
106:
107: 30 JUN 1999:
108: + New function FindUnquotedSpace() which replaces the earlier technique for
109: finding the command line arguments to send on to wgnuplot. Prior to this
110: the arguments were assumed to start after argv[0], however argv[0] is not
111: set the same by all combinitaions of compiler, command processor, and OS.
112: The new method ignores argv completely and manually search the command line
113: string for the first space which isn't enclosed in double-quotes.
114:
115: */
116:
117: #include <io.h>
118: #include <conio.h>
119: #include <fcntl.h>
120: #include <stdio.h>
121: #include <string.h>
122: #include <stdlib.h>
123: #include <windows.h>
124:
125: #ifndef _O_BINARY
126: # define _O_BINARY O_BINARY
127: #endif
128: #if (__BORLANDC__ >= 0x450) /* about BCBuilder 1.0 */
129: # define _setmode setmode
130: #endif
131:
132: /* Customize this path if needed */
133: #define PROGNAME "wgnuplot.exe"
134: /* CRS: The value given above will work correctly as long as pgnuplot.exe
135: * is in the same directory as wgnuplot.exe or the directory containing
136: * wgnuplot.exe is included in the path. I would recommend placing the
137: * pgnuplot.exe executable in the same directory as wgnuplot.exe and
138: * leaving this definition alone.
139: */
140:
141: #define WINDOWNAME "gnuplot"
142: #define PARENTCLASS "wgnuplot_parent"
143: #define TEXTCLASS "wgnuplot_text"
144: #define GRAPHWINDOW "gnuplot graph"
145: #define GRAPHCLASS "wgnuplot_graph"
146: #define BUFFER_SIZE 80
147:
148: /* GLOBAL Variables */
149: HWND hwndParent = NULL;
150: HWND hwndText = NULL;
151:
152: PROCESS_INFORMATION piProcInfo;
153: STARTUPINFO siStartInfo;
154:
155: /* CRS: Callback for the EnumThreadWindows function */
156: BOOL CALLBACK cbGetTextWindow(HWND hwnd, LPARAM lParam )
157: {
158: /* save the value of the parent window */
159: hwndParent = hwnd;
160: /* check to see if it has a child text window */
161: hwndText = FindWindowEx(hwnd, NULL, TEXTCLASS, NULL );
162:
163: /* if the text window was found, stop looking */
1.1.1.2 ! ohara 164: return ( hwndText == NULL );
1.1 maekawa 165: }
166:
167: /* sends a string to the specified window */
168: /* CRS: made this into a function call */
169: void PostString(HWND hwnd, char *pc)
170: {
171: while( *pc ){
172: PostMessage( hwnd, WM_CHAR, *pc, 1L );
173: /* CRS: should add a check of return code on PostMessage. If 0, the
174: message que was full and the message wasn't posted. */
175: pc++;
176: }
177: }
178:
179: /* FindUnquotedSpace(): Search a string for the first space not enclosed in quotes.
180: * Returns a pointer to the space, or the empty string if no space is found.
181: * -CRS 30061999
182: */
183: char* FindUnquotedSpace( char *pc )
184: {
185: while ( (*pc) && (*pc != ' ') && (*pc != '\t') ){
186: if ( *pc == '"' ){
187: do {
188: pc++;
189: } while ( (pc[1]) && (*pc != '"') );
190: }
191: pc++;
192: }
193: return pc;
194: }
195:
196: int main (int argc, char *argv[])
197: {
198: char psBuffer[BUFFER_SIZE];
199: char psGnuplotCommandLine[MAX_PATH] = PROGNAME;
200: LPTSTR psCmdLine;
201: BOOL bSuccess;
202:
203: /* HBB 19990325, to allow pgnuplot < script > output.gif */
204: _setmode(fileno(stdout), _O_BINARY);
205:
206: /* CRS: create the new command line, passing all of the command
207: * line options to wgnuplot so that it can process them:
208: * first, get the command line,
209: * then move past the name of the program (e.g., 'pgnuplot'),
210: * finally, add what's left of the line onto the gnuplot command line. */
211: psCmdLine = GetCommandLine();
212:
213: #ifdef SHOWCMDLINE
214: fprintf(stderr,"CmdLine: %s\n", psCmdLine);
215: fprintf(stderr,"argv[0]: %s\n",argv[0]);
216: #endif
217:
218: /* CRS 30061999: Search for the first unquoted space. This should
219: separate the program name from the arguments. */
220: psCmdLine = FindUnquotedSpace( psCmdLine );
221:
222: strncat(psGnuplotCommandLine, psCmdLine, MAX_PATH - strlen(psGnuplotCommandLine));
223:
224: #ifdef SHOWCMDLINE
225: fprintf(stderr,"Arguments: %s\n", psCmdLine);
226: fprintf(stderr,"GnuplotCommandLine: %s\n",psGnuplotCommandLine);
227: #endif
228:
229: /* CRS: if stdin isn't redirected then just launch wgnuplot normally
230: * and exit. */
231: if ( isatty(fileno(stdin)) ) {
232: if ( WinExec(psGnuplotCommandLine, SW_SHOWDEFAULT) > 31 ){
233: exit(EXIT_SUCCESS);
234: }
235: fprintf(stderr,"ERROR %u: Couldn't execute: \"%s\"\n",
236: GetLastError(), psGnuplotCommandLine);
237: exit(EXIT_FAILURE);
238: }
239:
240: /* CRS: initialize the STARTUPINFO and call CreateProcess(). */
241: siStartInfo.cb = sizeof(STARTUPINFO);
242: siStartInfo.lpReserved = NULL;
243: siStartInfo.lpReserved2 = NULL;
244: siStartInfo.cbReserved2 = 0;
245: siStartInfo.lpDesktop = NULL;
246: siStartInfo.dwFlags = STARTF_USESHOWWINDOW;
247: siStartInfo.wShowWindow = SW_SHOWMINIMIZED;
248:
249: bSuccess = CreateProcess(
250: NULL, /* pointer to name of executable module */
251: psGnuplotCommandLine, /* pointer to command line string */
252: NULL, /* pointer to process security attributes */
253: NULL, /* pointer to thread security attributes */
254: FALSE, /* handle inheritance flag */
255: 0, /* creation flags */
256: NULL, /* pointer to new environment block */
257: NULL, /* pointer to current directory name */
258: &siStartInfo, /* pointer to STARTUPINFO */
259: &piProcInfo /* pointer to PROCESS_INFORMATION */
260: );
261:
262: /* if CreateProcess() failed, print a warning and exit. */
263: if ( ! bSuccess ) {
264: fprintf(stderr,"ERROR %u: Couldn't execute: \"%s\"\n",
265: GetLastError(), psGnuplotCommandLine);
266: exit(EXIT_FAILURE);
267: }
268:
269: /* CRS: give gnuplot enough time to start (1 sec.) */
270: if ( WaitForInputIdle(piProcInfo.hProcess, 1000) ) {
271: fprintf(stderr, "Timeout: gnuplot is not ready\n");
272: exit(EXIT_FAILURE);
273: }
274:
275: /* CRS: get the HWND of the parent window and text windows */
276: EnumThreadWindows(piProcInfo.dwThreadId, cbGetTextWindow, 0);
277:
278: /* CRS: free the process and thread handles */
279: CloseHandle(piProcInfo.hProcess);
280: CloseHandle(piProcInfo.hThread);
281:
282: if ( ! hwndParent || ! hwndText ) {
283: /* Still no gnuplot window? Problem! */
284: fprintf(stderr, "Can't find the gnuplot window");
285: exit(EXIT_FAILURE);
286: }
287:
288: /* wait for commands on stdin, and pass them on to the wgnuplot text
289: * window */
290: while ( fgets(psBuffer, BUFFER_SIZE, stdin) != NULL ) {
291: PostString(hwndText, psBuffer);
292: }
293:
294: /* exit gracefully */
295: /* CRS: Add a test to see if gnuplot is still running? */
296: PostString(hwndText, "\nexit\n");
297:
298: return EXIT_SUCCESS;
299: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>