File: pgnuplot.c

package info (click to toggle)
gnuplot 3.7.2-4
  • links: PTS
  • area: main
  • in suites: woody
  • size: 6,212 kB
  • ctags: 4,635
  • sloc: ansic: 43,538; cpp: 970; makefile: 883; lisp: 661; sh: 578; asm: 539; objc: 379; csh: 297; pascal: 192; perl: 138
file content (299 lines) | stat: -rw-r--r-- 10,756 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
/*
 * pgnuplot.c -- pipe stdin to wgnuplot
 * 
 * Version 0.3 -- 30 Jun 1999
 * 
 * This program is based on pgnuplot.c Copyright (C) 1999 Hans-Bernhard Broeker
 * with substantial modifications Copyright (C) 1999 Craig R. Schardt.
 *
 * The code is released to the public domain.
 *
 */

/* Comments from original pgnuplot.c */
/*
 * pgnuplot.c -- 'Pipe to gnuplot'  Version 990608
 *
 * A small program, to be compiled as a Win32 console mode application.
 * (NB: will not work on 16bit Windows, not even with Win32s installed).
 *
 * This program will accept commands on STDIN, and pipe them to an
 * active (or newly created) wgnuplot text window. Command line options
 * are passed on to wgnuplot.
 *
 * Effectively, this means `pgnuplot' is an almost complete substitute
 * for `wgnuplot', on the command line, with the added benefit that it
 * does accept commands from redirected stdin. (Being a Windows GUI
 * application, `wgnuplot' itself cannot read stdin at all.)
 *
 * Copyright (C) 1999 by Hans-Bernhard Broeker
 *                       (broeker@physik.rwth-aachen.de)
 * This file is in the public domain. It might become part of a future
 * distribution of gnuplot.
 *
 * based on a program posted to comp.graphics.apps.gnuplot in May 1998 by
 * jl Hamel <jlhamel@cea.fr>
 *
 * Changes relative to that original version:
 * -- doesn't start a new wgnuplot if one already is running.
 * -- doesn't end up in an endless loop if STDIN is not redirected.
 *    (refuses to read from STDIN at all, in that case).
 * -- doesn't stop the wgnuplot session at the end of
 *    stdin, if it didn't start wgnuplot itself.
 * -- avoids the usual buffer overrun problem with gets().
 *
 * For the record, I usually use MinGW32 to compile this, with a
 * command line looking like this:
 *
 *     gcc -o pgnuplot.exe pgnuplot.c -luser32 -s
 */

/*	Modifications by Craig R. Schardt (17 Jun 1999)
		
	Copyright (C) 1999 by Craig R. Schardt (craig@silica.mse.ufl.edu)

	Major changes: (See the explanation below for more information)
		+ Always starts a new instance of wgnuplot.
		+ If stdin isn't redirected then start wgnuplot and give it focus.
		+ Uses CreateProcess() instead of WinExec() to start wgnuplot when stdin
		  is redirected.
	
	Other changes:
		+ New technique for building the command line to pass to wgnuplot.exe
		  which is less complicated and seems to work more reliably than the old 
		  technique.
		+ Simplified message passing section of the code. 
		+ All printf(...) statements are now fprintf(stderr,...) so that errors 
		  are sent to the console, even if stdout is redirected.

	The previous version of pgnuplot would fail when more than one program
	tried to access wgnuplot simultaneously or when one program tried to start
	more than one wgnuplot session. Only a single instance of wgnuplot would be
	started and all input would be sent to that instance. When two or more programs
	tried to pipe input to wgnuplot, the two seperate input streams would be sent 
	to one wgnuplot window resulting in one very confused copy of wgnuplot. The only
	way to avoid this problem was to change pgnuplot so that it would start a 
	new instance of wgnuplot every time.

	Just starting a new instance of wgnuplot isn't enough. pgnuplot must also
	make sure that the data on each stdin pipe is sent to the proper wgnuplot 
	instance. This is achieved by using CreateProcess() which returns a handle 
	to the newly created process. Once the process has initialized, it can be 
	searched for the text window and then data can be routed correctly. The search 
	is carried out by the EnumThreadWindows() call and the data passing is carried 
	out by a rewritten version of the original code. With these changes, pgnuplot 
	now behaves in a manner consistent with the behavior of gnuplot on UNIX 
	computers.

	This program has been compiled using Microsoft Visual C++ 4.0 with the
	following command line:

		cl /O2 pgnuplot.c /link user32.lib

	The resulting program has been tested on WinNT and Win98 both by calling
	it directly from the command line with and without redirected input. The
	program also works on WinNT with a modified version of Gnuplot.py (a script
	for interactive control of Gnuplot from Python). 
	
	22 JUN 1999:
	+ Fixed command line code to behave properly when the first
	  item is quoted in the original command line.
	
	29 JUN 1999:
	+ Added some code to print the command line. This is for testing
	  only and should be removed before the general release. To enable, 
	  compile with SHOWCMDLINE defined.

	30 JUN 1999:
	+ New function FindUnquotedSpace() which replaces the earlier technique for
	  finding the command line arguments to send on to wgnuplot. Prior to this
	  the arguments were assumed to start after argv[0], however argv[0] is not
	  set the same by all combinitaions of compiler, command processor, and OS. 
	  The new method ignores argv completely and manually search the command line
	  string for the first space which isn't enclosed in double-quotes.

  */

#include <io.h>
#include <conio.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>

#ifndef _O_BINARY
# define _O_BINARY O_BINARY
#endif
#if (__BORLANDC__ >= 0x450) /* about BCBuilder 1.0 */
# define _setmode setmode
#endif

/* Customize this path if needed */
#define PROGNAME "wgnuplot.exe"
/* CRS: The value given above will work correctly as long as pgnuplot.exe
 * is in the same directory as wgnuplot.exe or the directory containing
 * wgnuplot.exe is included in the path. I would recommend placing the 
 * pgnuplot.exe executable in the same directory as wgnuplot.exe and 
 * leaving this definition alone.
 */

#define WINDOWNAME "gnuplot"
#define PARENTCLASS "wgnuplot_parent"
#define TEXTCLASS "wgnuplot_text"
#define GRAPHWINDOW "gnuplot graph"
#define GRAPHCLASS "wgnuplot_graph"
#define BUFFER_SIZE 80

/* GLOBAL Variables */
HWND hwndParent = NULL;
HWND hwndText = NULL;

PROCESS_INFORMATION piProcInfo; 
STARTUPINFO         siStartInfo; 

/* CRS: Callback for the EnumThreadWindows function */
BOOL CALLBACK cbGetTextWindow(HWND  hwnd, LPARAM  lParam )
{
	/* save the value of the parent window */
	hwndParent = hwnd;
	/* check to see if it has a child text window */
	hwndText = FindWindowEx(hwnd, NULL, TEXTCLASS, NULL );

	/* if the text window was found, stop looking */
	return ( hwndText == NULL );
}

/* sends a string to the specified window */
/* CRS: made this into a function call */
void PostString(HWND hwnd, char *pc)
{
	while( *pc ){
		PostMessage( hwnd, WM_CHAR, *pc, 1L );
		/* CRS: should add a check of return code on PostMessage. If 0, the 
		   message que was full and the message wasn't posted. */
		pc++;
	}
}

/* FindUnquotedSpace(): Search a string for the first space not enclosed in quotes.
 *   Returns a pointer to the space, or the empty string if no space is found. 
 *   -CRS 30061999  
 */
char* FindUnquotedSpace( char *pc )
{
	while ( (*pc) && (*pc != ' ') && (*pc != '\t') ){
		if ( *pc == '"' ){
			do {
				pc++;
			} while ( (pc[1]) && (*pc != '"') );
		}
		pc++;
	}
	return pc;
}

int main (int argc, char *argv[])
{
	char    psBuffer[BUFFER_SIZE];
	char    psGnuplotCommandLine[MAX_PATH] = PROGNAME;
	LPTSTR  psCmdLine;
	BOOL    bSuccess;
	
	/* HBB 19990325, to allow pgnuplot < script > output.gif */
	_setmode(fileno(stdout), _O_BINARY);

	/* CRS: create the new command line, passing all of the command
	 * line options to wgnuplot so that it can process them:
	 * first, get the command line,
	 * then move past the name of the program (e.g., 'pgnuplot'),
	 * finally, add what's left of the line onto the gnuplot command line. */
	psCmdLine = GetCommandLine();

#ifdef SHOWCMDLINE
	fprintf(stderr,"CmdLine: %s\n", psCmdLine);
	fprintf(stderr,"argv[0]: %s\n",argv[0]);
#endif

	/* CRS 30061999: Search for the first unquoted space. This should 
	   separate the program name from the arguments. */
	psCmdLine = FindUnquotedSpace( psCmdLine );

	strncat(psGnuplotCommandLine, psCmdLine, MAX_PATH - strlen(psGnuplotCommandLine));

#ifdef SHOWCMDLINE
	fprintf(stderr,"Arguments: %s\n", psCmdLine);
	fprintf(stderr,"GnuplotCommandLine: %s\n",psGnuplotCommandLine);
#endif

	/* CRS: if stdin isn't redirected then just launch wgnuplot normally
	 * and exit. */
	if ( isatty(fileno(stdin)) ) {
		if ( WinExec(psGnuplotCommandLine, SW_SHOWDEFAULT) > 31 ){
			exit(EXIT_SUCCESS);
		}
		fprintf(stderr,"ERROR %u: Couldn't execute: \"%s\"\n", 
			    GetLastError(), psGnuplotCommandLine);
		exit(EXIT_FAILURE);
	}

	/* CRS: initialize the STARTUPINFO and call CreateProcess(). */ 
	siStartInfo.cb = sizeof(STARTUPINFO); 
	siStartInfo.lpReserved = NULL; 
	siStartInfo.lpReserved2 = NULL; 
	siStartInfo.cbReserved2 = 0; 
	siStartInfo.lpDesktop = NULL; 
	siStartInfo.dwFlags = STARTF_USESHOWWINDOW;
	siStartInfo.wShowWindow = SW_SHOWMINIMIZED;

	bSuccess = CreateProcess( 
			NULL,                   /* pointer to name of executable module   */
			psGnuplotCommandLine,   /* pointer to command line string         */
			NULL,                   /* pointer to process security attributes */
			NULL,                   /* pointer to thread security attributes  */
			FALSE,                  /* handle inheritance flag                */
			0,                      /* creation flags                         */
			NULL,                   /* pointer to new environment block       */
			NULL,                   /* pointer to current directory name      */
			&siStartInfo,           /* pointer to STARTUPINFO                 */
			&piProcInfo             /* pointer to PROCESS_INFORMATION         */
			);

	/* if CreateProcess() failed, print a warning and exit. */
	if ( ! bSuccess ) {
		fprintf(stderr,"ERROR %u: Couldn't execute: \"%s\"\n", 
						GetLastError(), psGnuplotCommandLine);
		exit(EXIT_FAILURE);
	}

	/* CRS: give gnuplot enough time to start (1 sec.) */
	if ( WaitForInputIdle(piProcInfo.hProcess, 1000) ) {
		fprintf(stderr, "Timeout: gnuplot is not ready\n");
		exit(EXIT_FAILURE);
	}

	/* CRS: get the HWND of the parent window and text windows */
	EnumThreadWindows(piProcInfo.dwThreadId, cbGetTextWindow, 0);

	/* CRS: free the process and thread handles */
	CloseHandle(piProcInfo.hProcess);
	CloseHandle(piProcInfo.hThread);

	if ( ! hwndParent || ! hwndText ) {
	/* Still no gnuplot window? Problem! */
		fprintf(stderr, "Can't find the gnuplot window");
		exit(EXIT_FAILURE);
	}

	/* wait for commands on stdin, and pass them on to the wgnuplot text
	 * window */
	while ( fgets(psBuffer, BUFFER_SIZE, stdin) != NULL ) {
		PostString(hwndText, psBuffer);
	}
	
	/* exit gracefully */
	/* CRS: Add a test to see if gnuplot is still running? */
	PostString(hwndText, "\nexit\n");

	return EXIT_SUCCESS;
}