Annotation of OpenXM_contrib/gnuplot/win/pgnuplot.c, Revision 1.1
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 */
! 164: return ( hwndText != NULL );
! 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>