[BACK]Return to pgnuplot.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gnuplot / win

Annotation of OpenXM_contrib/gnuplot/win/pgnuplot.c, Revision 1.1.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>