LOGICAL and CHARACTER types are
represented in terms of basic machine types. Furthermore, since C
implements call-by-value argument passing semantics, whereas FORTRAN
uses pass-by-reference, there is the added complication that literal
values must be sent indirectly by way of references to dummy
variables.The CPGPLOT library adds an intermediate level of wrapper functions between C programs and the PGPLOT library. These functions hide the system dependencies of calling PGPLOT behind a system-independent interface.
It is essential when using the CPGPLOT interface library to include
the library header file cpgplot.h
at the top of all C files containing calls to the library. Without
this file, the functions will not be correctly prototyped and your
code will not work.
The CPGPLOT library can be used only with an ANSI-compatible C compiler that understands C function prototypes.
c and
written in lower case, e.g., PGTEXT becomes
cpgtext.
The header file cpgplot.h
declares the types of the arguments of each CPGPLOT routine. The types
can usually be deduced from the FORTRAN subroutine descriptions in Appendix A, as described below, but
cpgplot.h should be consulted in
case of doubt.
REAL or
INTEGER argument, supply the C routine with a
float or int argument as appropriate. If the
Fortran routine uses the argument for input only, it should be passed
by value; but if it is used to return a value, supply a pointer to a
variable of the appropriate type. If the FORTRAN argument
is an array, the C argument should be a pointer to an array. For
two-dimensional arrays, supply a pointer to a one-dimensional C array
in which the elements are packed with the first index changing fastest
(see example below).
LOGICAL argument, the
C routine requires an int argument. Zero is interpreted
as FORTRAN .FALSE. and non-zero as FORTRAN
.TRUE., e.g.,
FORTRAN call C equivalent call(s)
PGASK(.FALSE.) cpgask(0)
PGASK(.TRUE.) cpgask(1) or cpgask(2) etc.
CHARACTER argument for
input, the C routine takes a normal C pointer to a nul-terminated
string (char array, with end-of string marked by
'\0').
Arguments that are used to return FORTRAN character strings must be
treated with care. FORTRAN doesn't understand '\0'
termination of strings and instead requires that the dimension of the
character array be specified along with the array. The interface
handles this transparently for input-only strings by using
strlen() to determine the length of the string, but for
return string arguments it needs to be told the length available in
the passed char array. Fortunately all PGPLOT routines
that return such strings also have an argument to return the unpadded
length of the return string. In CPGPLOT, you must initialize this
argument with the dimension of the string array that has been sent. In
the prototypes listed in cpgplot.h the length arguments are
distinguishable by virtue of their having the name of the string to
which they relate, postfixed with _length. For example,
the PGPLOT routine PGQINF() is prototyped as
void cpgqinf(char *item, char *value, int *value_length);
where the value_length argument is the length argument
for the string argument value.For example, to write a C function to return 1 if a PGPLOT device is open, or 0 otherwise, one could write.
#include "cpgplot.h"
int pgplot_is_open(void)
{
char answer[10]; /* The PGQINF return string */
int answer_len = sizeof(answer); /* allocated size of answer[] */
cpgqinf("STATE", answer, &answer_len);
return strcmp(answer, "YES") == 0;
}
Note that the dimension, sent as the third argument, is the total
number of characters allocated to the answer[] array. The
interface function actually subtracts one from this when it tells
PGPLOT how long the string is. This leaves room for the interface
function to terminate the returned string with a
'\0'. All returned strings are terminated in this manner
at the length returned by PGPLOT in the length argument.
SUBROUTINEs or
FUNCTIONs as arguments (e.g., PGFUNX,
PGCONX) are not represented in the CPGPLOT library. Such
procedures cannot be handled on most systems.
When you mix languages, it is usually necessary to include system support libraries for each language. Again, you will need to consult the documentation for your operating system and compilers to determine what libaries are needed and where they are located.
On UNIX systems, the compiler usually invokes the linker/loader itself, specifying the necessary libraries. However, with this method the linker/lodaer will not automatically find the libraries required by the other compilers involved.
Since FORTRAN usually has to be linked with a lot of support
libraries, it is usually most convenient to use the FORTRAN compiler
to link your C program. If your compiler is not the system-supplied
compiler, then it is unlikely that the FORTRAN compiler will cite the
correct C run-time library to the linker. This means that you will
have to do it yourself (e.g., the gcc compiler requires
programs to be linked with libgcc.a, e.g.,
gcc -c blob.c f77 -o blob blob.o -lcpgplot -lpgplot -lX11 -lgcc -lm
f77
to do the link:
cc -c -I/usr/local/pgplot ctest.c f77 -o ctest ctest.o -L/usr/local/pgplot -lcpgplot -lpgplot(Replace
/usr/local/pgplot with your PGPLOT directory.)A C++ program calling PGPLOT; in this case we need both Fortran and C++ libraries, and it is easiest to use CC to do the link and to provide the Fortran libraries explicitly:
CC -c c++test.C CC c++test.o -L/usr/local/pgplot -lcpgplot -lpgplot \ /usr/local/lang/SUNWspro/SC3.0.1/lib/libM77.a -lX11 -lF77Note that the names and locations of the Fortran libraries will depend on the version of the compiler in use.
cc -c -I/usr/local/pgplot ctest.c f77 -o ctest ctest.o -L/usr/local/pgplot -lcpgplot -lpgplot -lX11 -lm -nofor_mainNote the use of
f77 to do the link step, and the use of
the -nofor_main switch.
#include "cpgplot.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int i;
static float xs[] = {1.0, 2.0, 3.0, 4.0, 5.0 };
static float ys[] = {1.0, 4.0, 9.0, 16.0, 25.0 };
float xr[60], yr[60];
int n = sizeof(xr) / sizeof(xr[0]);
/*
* Call PGBEG to initiate PGPLOT and open the output device; PGBEG
* will prompt the user to supply the device name and type.
*/
if(cpgbeg(0, "?", 1, 1) != 1)
return EXIT_FAILURE;
/*
* Call PGENV to specify the range of the axes and to draw a box, and
* PGLAB to label it. The x-axis runs from 0 to 10, and y from 0 to 20.
*/
cpgenv(0.0, 10.0, 0.0, 20.0, 0, 1);
cpglab("(x)", "(y)", "PGPLOT Example 1: y = x\\u2\\d");
/*
* Mark five points (coordinates in arrays XS and YS), using symbol
* number 9.
*/
cpgpt(5, xs, ys, 9);
/*
* Compute the function at 'n=60' points, and use PGLINE to draw it.
*/
for(i=0; i<n; i++) {
xr[i] = 0.1*i;
yr[i] = xr[i]*xr[i];
}
cpgline(n, xr, yr);
/*
* Finally, call PGEND to terminate things properly.
*/
cpgend();
return EXIT_SUCCESS;
}
A second example shows how a two-dimensional FORTRAN array should be
handled:
#include "cpgplot.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
static int nx = 40, ny = 40;
int i, j, k, lw, ci, ls;
float f[1600], fmin, fmax, alev;
double x, y;
static float tr[6] = {0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
printf("Demonstration of PGPLOT contouring routines\n");
/* Compute a suitable function. A C array is used to emulate
a 2D fortran array f(nx,ny). */
fmin = fmax = 0.0;
for (j=1; j<=ny; j++) {
for (i=1; i<=ny; i++) {
k = (j-1)*nx + (i-1); /* Fortran convention */
x = tr[0] + tr[1]*i + tr[2]*j;
y = tr[3] + tr[4]*i + tr[5]*j;
f[k] = cos(0.3*sqrt(x*2)-0.13333*y)*cos(0.13333*x)+
(x-y)/(double)nx;
if (f[k] < fmin) fmin = f[k];
if (f[k] > fmax) fmax = f[k];
}
}
/* Call PGBEG to initiate PGPLOT and open the output device; PGBEG
* will prompt the user to supply the device name and type. */
if(cpgbeg(0, "?", 1, 1) != 1)
return EXIT_FAILURE;
/* Clear the screen. Set up window and viewport. */
cpgpage();
cpgsvp(0.05, 0.95, 0.05, 0.95);
cpgswin(1.0, (float) nx, 1.0, (float) ny);
cpgbox("bcts", 0.0, 0, "bcts", 0.0, 0);
cpgmtxt("t", 1.0, 0.0, 0.0, "Contouring using PGCONT");
/* Draw the map. PGCONT is called once for each contour, using
different line attributes to distinguish contour levels. */
cpgbbuf();
for (i=1; i<21; i++) {
alev = fmin + i*(fmax-fmin)/20.0;
lw = (i%5 == 0) ? 3 : 1;
ci = (i < 10) ? 2 : 3;
ls = (i < 10) ? 2 : 1;
cpgslw(lw);
cpgsci(ci);
cpgsls(ls);
cpgcont(f, nx, ny, 1, nx, 1, ny, &alev, -1, tr);
}
cpgslw(1);
cpgsls(1);
cpgsci(1);
cpgebuf();
/*
* Finally, call PGEND to terminate things properly.
*/
cpgend();
return EXIT_SUCCESS;
}