From: ssclift@neumann.uwaterloo.ca (Simon Clift)
Subject: Re: Running Gnuplot from FORTRAN, (and C)
Summary: Use popen.
Organization: University of Waterloo
Date: Mon, 9 Nov 1992 14:49:31 GMT

I've noticed a few people trying to run Gnuplot from a program.  I looked
at this problem a few weeks ago, when I wanted plotted output to display
intermediate stage solutions from a fluid dynamics code.  After consulting
with local gurus, they pointed me to the Unix popen commands.  I wrote this
simple set of wrapper functions, meant to be linked to Sun 4/670 Fortran,
and called as SUBROUTINE's.  These will probably work with other Unix boxes.

I compiled the source with
  gcc -c pipeLib.c
which creates pipeLib.o.  Then I just link this with my Fortran program
  f77 -O2 myFortranSource.o pipeLib.o -o myProgramExecutable

What the library does is set up to 20 programs going (like gnuplot), then
allows you to send to them as if the program were typing on the command
line.  I've included a brief set of docs after the source code, in latex
format.  There is no facility to watch the output of a program.

Help yourself...

----------------------------Source Code, Cut here--------------------------
/*
  pipeLib.c

  by Simon Clift
  University of Waterloo, CS Dept., SciCom Group

  Use this at your own risk.

  A small library of functions to allow FORTRAN 77 on the Sun to use
  pipes to talk to other programs interactively.

*/

#include <stdio.h>


/*
  Allow an array of file descriptors
*/

#define	MaxPipes		20
#define	PipeOpen		-1
#define	PipeClosed		0

FILE		*pipes[MaxPipes];
int		pipes_open[MaxPipes];		/* status */

/*
  plinit_

  Initialize pipes system
*/

void plinit_( void )
{
	int 	i;

	for( i=0 ; i < MaxPipes ; i++ ) {
		pipes_open[i] = PipeClosed;
	}
}

/*
  plopen_

  Open a pipe to a program given the startup command, and either "r" or "w"

  Status variable   stat = Pipe number on successful open, -1 otherwise
*/

void plopen_( char * command, char * mode, int * stat )
{
	int	i;

	for( i=0 ; i < MaxPipes ; i++ ) {
		if( pipes_open[i] == PipeClosed ) {
			break;
		}
	}

	if( i == MaxPipes ) {
		*stat = -1;
	} else {
		pipes[i] = popen( command, mode );
		*stat = (i+1);
	}
}

/* 
  plwrit_

  Write a string to a pipe.

*/

void plwrit_( int * pipeNum, char * stringOut )
{
	fprintf( pipes[*pipeNum-1], "%s\n", stringOut );
}

/*
  plflus_

  Flush a pipe's output
*/

void plflus_( int *pipeNum )
{
	fflush( pipes[ *pipeNum - 1 ] );
}

/*
  plclos_

  Close a pipe
*/

void plclos_( int * pipeNum )
{
	pclose( pipes[*pipeNum-1] );
}
-------------------------End of Source Code, Cut here----------------------
-------------------------LaTeX Documentation, Cut here---------------------
\documentstyle[fullpage,11pt]{article}
\begin{document}

\title{A Small F77 Pipes Library}
\author{Simon Clift}
\date{September 25th, 1992}

\maketitle

\section{What PipeLib Does}

I recently encountered the problem of wanting my Fortran 77 programs to 
send instructions to other programs, in particular, the GnuPlot package.
After consulting with Ken Wellsch of MFCF he suggested I try to use the
Unix {\tt popen()} facilities, which allow one program to start another
and send to it, just as if it had been part of a traditional command
line pipe.

These functions cannot be used directly from Fortran, so I wrote a small
library of wrapper functions that are Fortran 77 callable.  It allows up
to 20 piped communications channels at the moment, and for the moment
only allows you to write to these channels.

\section{How to use PipeLib}

Using pipelib requires that you declare an INTEGER for each pipe you wish
to use, to work as a pipe number holder.  All accesses to the routines are
made as Fortran subroutine calls.

Before using the pipes you must call the initialization function.
\begin{verbatim}
      CALL plinit()
\end{verbatim}

To open a pipe you need to know what Bourne Shell ({\tt sh}) command
you want to pipe to.  You may store this as a character variable, or
use a literal string in the call.
\begin{verbatim}
C
C The COMMND string may be any length
C
      CHARACTER commnd*80
      INTEGER   pipnum

      CALL plopen( commnd, 'w', pipnum )
\end{verbatim}
The {\tt commnd} specified command will be started by the Bourne Shell.
The 'w' specifies that you wish to write to this pipe.  In future versions,
readable pipes may be implemented.  The pipe number you receive (1-20)
will be stored in {\tt pipnum}

To write to a pipe, use the the {\tt plwrit} function.
\begin{verbatim}
C
C The string can be any length
C
	CHARACTER string*80
	INTEGER   pipnum

	CALL plwrit( pipnum, string )
	CALL plwrit( pipnum, 'A literal string to send' )
\end{verbatim}
The variable {\tt pipnum} must contain the number of a a valid, open
pipe.  The contents of {\tt string} will be sent to the program being
piped to.  Note that the string may also be a literal.

The output of the {\tt plwrit} command won't be seen by the executed
command until either the output buffer is full, and Unix flushes it, or
until you issue the {\tt plflus} command.
\begin{verbatim}
	INTEGER   pipnum

	CALL plflus( pipnum )
\end{verbatim}
The {\tt pipnum} variable must contain the number of a valid, open pipe.

To close a pipe, use the {\tt plclos} command.
\begin{verbatim}
	INTEGER   pipnum

	CALL plclos( pipnum )
\end{verbatim}
This will close the open pipe whose number is in {\tt pipnum}, flushing
the output in the process.

\subsection{Linking PipeLib}

At present you use PipeLib by linking the {\tt .o} object file to your
Fortran Program.  The source code and object file are in the directory
{\tt /u/scicom/code/PipeLib}.

\section{A Sample Program}

This sample program is included in the same directory as the library code.
\begin{verbatim}
C
C  A Sample program for PipeLib
C
	INTEGER pipenum
	CHARACTER dummy*1
C
C Initialize the library
C
	CALL plinit()
C
C Open a stream to the GnuPlot program
C
	CALL plopen('gnuplot', 'w', pipenum)
	PRINT *,'Opened gnuplot pipe # ', pipenum
C
C Write some GnuPlot commands
C
	CALL plwrit(pipenum, 'set d s l')
	CALL plwrit(pipenum, 'plot sin(x)')
C
C Flush the output so that we will see the graph
C
	CALL plflus(pipenum)
C
C Wait for the user.
C
	PRINT *,'Enter a character and press return.'
	READ *,dummy
C
C Close the pipe
C
	CALL plclos(pipenum)
C
	END
\end{verbatim}

\end{document}
------------------------End of LaTeX Docs, Cut here-------------------
--
Simon Clift                    | "Wife is my status, not my job description." 
Scientific Computation Group   |                      Karen Clift
Department of Computer Science 
University of Waterloo,                      ssclift@neumann.uwaterloo.ca
Waterloo, Ontario, N2L 3G1                   (519) 885-1211 x3469