.TH "FBB::Proc" "3bobcat" "2005\-2024" "libbobcat\-dev_6\&.06\&.02" "Running Child Processes" .PP .SH "NAME" FBB::Proc \- Runs external programs .PP .SH "SYNOPSIS" \fB#include \fP .br Linking option: \fI\-lbobcat\fP .PP .SH "DESCRIPTION" The \fBFBB::Proc\fP offers an alternative to the \fBFBB::Process\fP class\&. \fBFBB::Proc\fP offers an extensive interface to calling external programs and/or scripts from a \fBC++\fP program (so\-called \fIchild\-processes\fP)\&. The class offers an easy to use, stream\-based interface to communicate with the standard input, output and error streams of child processes\&. .PP Objects of the \fIclass Proc\fP use standard process\-executing functions, like members of the \fBexecl\fP(2) family or \fBsh\fP(1) to execute child processes\&. Thus, child processes can be executable programs or \fIshell\-scripts\fP\&. .PP The standard input, output and error streams of child processes may be accessed through their \fIProc\fP parent objects\&. Input expected by child processes can be inserted into \fIProc\fP objects\&. standard output and standard error generated by child processes are inserted into and further handled by \fIstd::ostream\fP objects, by default \fIstd::cout\fP and \fIstd::cerr\fP\&. .PP When using (output) redirection when executing child processes using the \fIUSE_SHELL\fP path specification (see below for the path and IOMode specifications), the \fIIGNORE_COUT IOMode\fP (and possibly \fIIGNORE_CERR\fP) should normally be specified (cf\&. section \fBENUMERATIONS\fP for a description of the \fIIOMode\fP enumeration)\&. .PP \fIProc\fP objects may repeatedly be used to execute the same or different child processes\&. Before the next child process is started, the \fIProc\fP object ensures that its currently active child process ends\&. Alternatively, a currently active child process ends if the \fIProc\fP object goes out of scope, if the allotted execution time of the child process has passed, if a new process is started using \fIProc\(cq\&s\fP assignment operator, or if its \fIstop\fP member is called\&. Otherwise child processes continue until completion when calling \fIfinish\fP or, if the child process reads its standard input stream, when the \fIeoi\fP manipulator is inserted into the \fIProc\fP object\&. .PP Programs called as child processes may be specified when constructing a \fIProc\fP object or by using \fIProc\(cq\&s setCommand\fP member\&. \fIProc\fP constructors (or \fIProc\(cq\&s setCommand\fP\-member) don\(cq\&t start child processes\&. To start child processes the \fIstart\fP members or the assignment operator must be used\&. .PP Child processes may receive information at their standard input streams through information inserted into \fIProc\fP objects\&. In those cases \fIProc\fP objects must inform their child processes that they have received all input\&. For this the \fIeoi\fP manipulator can be inserted into \fIProc\fP objects, or \fIProc\(cq\&s finish\fP member can be called\&. .PP If information sent to the child is not fully be processedd by the child process then the operating system issues a \fIBroken pipe\fP message, indicating that information in a pipe was lost, ending the program\&. The \fIProc\fP class\(cq\&s member \fIpipeSignal\fP can be used to suppress the \fIBroken pipe\fP message\&. .PP Arguments passed to child processes may be surrounded by double or single quotes\&. Arguments surrounded by double quotes have their double quotes removed, while interpreting any escape\-sequences that may have been used within\&. Arguments surrounded by single quotes have their single quotes removed, while accepting their content as\-is\&. In addition unquoted escape\-sequences may be specified: those escape sequences are evaluated and replaced by their intended characters (e\&.g\&., \fI\e100\fP is converted to \fI@\fP)\&. .PP A full command specification may also be surrounded by backtics (\fI`\fP\-characters)\&. These backtick characters are removed by the \fIProc\fP object when the command starts\&. .PP Child processes may be allotted a limited amount of time (in seconds) to complete\&. By default no time limit is imposed upon child processes\&. If a time limit is specified then the child process, if still running after the specified number of seconds, is ended by sending it a \fISIGTERM\fP signal, followed by a \fISIGKILL\fP signal (cf\&. \fBsignal\fP(7))\&. .PP By default the standard input, output and error streams of child processes are handled by their \fIProc\fP parent processes: information inserted into the \fIProc\fP object is forwarded to the child process\(cq\&s standard input stream, information sent by the child process to its standard output and error streams are either forwarded to the corresponding streams of the parent process, or they can be processed by streams, configured by the \fIProc\fP object\&. .PP Multiple \fIProc\fP processes can be combined using the pipe operator (i\&.e\&., the | operator)\&. When used, the standard output stream of the left\-hand side (lhs) \fIProc\fP object is used as the standard input stream of the right\-hand side (rhs) \fIProc\fP object\&. Since the \fIProc\fP objects start their own child processes, this effectively boils down to the output of the lhs\(cq\&s child process being used as the input of the rhs\(cq\&s child process\&. The leftmost \fIProc\fP object may also read its input (using the pipe operator) from an \fIistream\fP object or from a file whose name (path) is specified as the most lhs argument of a pipe expression\&. Likewise, the rightmost \fIProc\fP object may pipe its standard output to an existing \fIostream\fP object or to a file whose name (path) is specified as the most rhs argument of a pipe expression\&. .PP \fIProc\fP objects use \fIPipe\fP objects (cf\&. \fBpipe\fP(3bobcat)) for communication with their child processes\&. To ensure that these pipes are properly closed the members \fIwaitForChild, stop\fP or the \fIeoi\fP manipulator should be used\&. Once a \fIProc\fP object ceases to exist pipes to its child process are also closed\&. .PP .SH "NAMESPACE" \fBFBB\fP .br All constructors, members, operators and manipulators, mentioned in this man\-page, are defined in the namespace \fBFBB\fP\&. .PP .SH "INHERITS FROM" \fBFBB::Fork\fP(3bobcat) (private), .br \fBstd::ostream\fP .PP .SH "ENUMERATIONS" .PP The following enumerations are defined by the \fIProc\fP class: .PP \fBenum ProcType\fP: .br .PP The \fBenum ProcType\fP defines how a child proc is started or located\&. Its values are specified at constructor\-time or through the \fIsetProcType\fP member\&. This enumeration defines the following symbolic constants: .IP o \fBNO_PATH\fP: .br The program specified as child proc is started as specified, without searching the elements of the \fIPATH\fP environment variable\&. .IP o \fBUSE_PATH\fP: .br The elements of the \fIPATH\fP environment variable are used when locating the program specified as child proc\&. .IP o \fBUSE_SHELL\fP: .br The program specified as child proc is called using \fI/bin/sh \-c\fP\&. When (output) redirection is used with the specified command the \fIIGNORE_COUT IOMode\fP (and possibly also the \fIIGNORE_CERR IOMode\fP) should be specified\&. .PP \fBenum IOMode\fP: .br .PP Values of the \fIenum IOMode\fP are used to define which of the child proc\(cq\&s standard streams can be accessed through the \fIProc\fP object\&. Its symbolic constants may be combined using the \fIbit_or\fP operator\&. By default \fICIN | COUT | CERR\fP is used (see below)\&. .PP \fIIOMode\fP arguments may be combined using bit\-or operators\&. .PP The following symbolic constants are available: .IP o \fBALL\fP: .br Shortcut for \fBCIN | COUT | CERR\fP\&. .IP o \fBCIN\fP: .br Information inserted into the \fIProc\fP object is forwarded to its child proc\&. If this is not required then \fICIN\fP should not be specified\&. .IP o \fBCERR\fP: .br Information written by the child process to its standard error stream is made available as \fIProc\(cq\&s\fP standard error stream\&. If this is not required then \fICERR\fP should not be specified\&. .IP o \fBCOUT\fP: .br Information written by the child process to its standard output stream is made available as \fIProc\(cq\&s\fP standard output stream\&. If this is not required then \fICERR\fP should not be specified\&. .IP o \fBIGNORE_CERR\fP: .br Information written by the child proc to its standard error stream is ignored (i\&.e\&., not made available)\&. An \fIstd::invalid_argument\fP exception is thrown if this mode is specified in combination with \fBCERR, MERGE_COUT_CERR,\fP and/or \fBREPLACE\fP\&. .IP o \fBIGNORE_COUT\fP: .br Information written by the child proc to its standard output stream is ignored\&. An \fIstd::invalid_argument\fP exception is thrown if this mode is specified in combination with \fBCOUT, MERGE_COUT_CERR\fP and/or \fBREPLACE\fP\&. .IP o \fBIGNORE_COUT_CERR\fP: .br Shortcut for \fIIGNORE_CERR | IGNORE_COUT\fP\&. .IP o \fBMERGE_COUT_CERR\fP: .br Information written by the child process to its standard output and standard error streams is made available at the \fIProc\fP object\(cq\&s standard output stream\&. An \fIstd::invalid_argument\fP exception is thrown if this mode is specified in combination with \fBCOUT, CERR, IGNORE_COUT, IGNORE_CERR\fP or \fIREPLACE\fP\&. .IP o \fBNONE\fP: .br The \fIProc\fP object does not insert information into the standard input streams of its child process and information written by the child process to its standard output or error streams is not forwarded to the \fIProc\fP object\&. Instead, the child process processes its standard streams by itself\&. When this mode is specified in combination with other \fIIOMode\fP values it is silently ignored\&. .IP o \fBREPLACE\fP: .br When starting a child proc (see below at the member \fIstart\fP) the current process (i\&.e\&., the program defining the \fIProc\fP object) is replaced by the child process, inheriting the current process\(cq\&s standard input and output streams\&. If this mode is specified in combination with any other \fIIOMode\fP (except for \fINONE\fP, see below) an \fIstd::invalid_argument\fP exception is thrown\&. .PP .SH "CONSTRUCTOR" .PP Note that child processes are \fInot\fP started automatically following the construction of t(Proc) objects\&. A \fIstart\fP member or the assignment operator (see below) is used to start child processes\&. .PP Once a \fIProc\fP object has been constructed its parameters can be changed using \fIset\fP\-member functions or \fIstart\fP members\&. .PP .IP o \fBexplicit Proc(std::string const &command = \(dq\&\(dq\&, IOMode mode = ALL, ProcType type = NO_PATH, size_t bufSize = 200, size_t timeLimit = 0, bool pipeSignal = true)\fP: .br The parameter \fIbufSize\fP defines the size of the \fIstreambuf\fP buffers used by the \fIProc\fP object\&. The \fItimeLimit\fP specifies the maximum execution time of a child process in seconds; when \fItimeLimit == 0\fP no execution time limit is used\&. When \fIpipeSignal == true\fP incomplete processing of information sent to or read from the child process results in a \fIBroken pipe\fP exception, terminating the program\&. When specifying \fIfalse\fP the \fIBroken pipe\fP exception is suppressed, and the input and/or output streams do not have to be completely processed (see also \fIpipeSignal\(cq\&s\fP description)\&. .PP Copy and move constructors (and assignment operators) are not available\&. .PP .SH "OVERLOADED OPERATORS" .PP .IP o \fBProc &operator<<(Type value)\fP: .br This operator inserts \fIvalue\fP into the child\(cq\&s standard input stream\&. I\&.e\&., the child proc reads \fIvalue\fP from its standard input\&. A value of any type that can be inserted into an \fIostream\fP can be inserted into a \fIProc\fP object\&. Nothing happens if the member is used when the child proc has terminated\&. Manipulators like \fIstd::endl\fP are also supported\&. The behavior of this operator is undefined when \fIIOMode CIN\fP has not been specified\&. .IP .IP o \fBProc &operator+=(std::string const &)\fP: .br This operator adds the provided \fIstd::string\fP object to the currently defined command specification of a \fIProc\fP object\&. The member \fIoperator+=\fP does not add a separating blank space between the currently stored command specification and the text to append\&. It merely adds its right\-hand side string to the command stored so far\&. It does not affect a currently running child process\&. .IP .IP o \fBint operator=(std::string const &cmd)\fP: .br The \fIoperator=\fP member defines \fIcmd\fP as the stored command in a \fIProc\fP object, and thereupon starts `\fIcmd\fP\(cq\& as its child process\&. .IP Before starting the child process a possibly active child process is first stopped by calling \fIstop\fP\&. It returns \fIstop\fP\(cq\&s return value\&. Immediately after calling \fIstop\fP the new command (\fIcmd\fP) is started\&. If ending and restarting another command should be separate actions then use \fIfinish\fP or \fIstop\fP followed by \fIsetCommand\fP, followed by calling an appropriate overloaded version of the member \fIstart\fP\&. .IP .IP o \fBReturn operator|(Proc &lhs, Proc &rhs)\fP: .br This operator implements \fIpiping\fP\&. Information sent by \fIlhs\fP to its standard output is used as the standard input of the \fIrhs\fP\(cq\&s child process\&. The \fIReturn\fP value is \fIrhs\fP if the expression is followed by another pipe\-operator or it is \fIvoid\fP\&. .IP .IP o \fBReturn operator|(std::istream &in, Proc &proc)\fP: .br This operator implements \fIpiping\fP\&. Information read from \fIin\fP is read by \fIproc\(cq\&s\fP child process\&. The \fIReturn\fP value is \fIproc\fP if the expression is followed by another pipe\-operator or it is \fIvoid\fP\&. .IP .IP o \fBReturn operator|(std::string const &fname, Proc &proc)\fP: .br This operator implements \fIpiping\fP\&. information in the file whose file (path) name is \fIfname\fP is read by \fIproc\(cq\&s\fP child process\&. The \fIReturn\fP value is \fIproc\fP if the expression is followed by another pipe\-operator or it is \fIvoid\fP\&. .IP .IP o \fBvoid operator|(Proc &proc, std::ostream &out)\fP: .br This operator implements \fIpiping\fP\&. Information sent by \fIproc\(cq\&s\fP child process to its standard output stream is written to \fIout\fP\&. .IP .IP o \fBvoid operator|(Proc &proc, std::string &fname)\fP: .br This operator implements \fIpiping\fP\&. Information sent by \fIproc\(cq\&s\fP child process to its standard output stream is written to the file whose file (path) name is \fIfname\fP\&. .PP The pipe (|) operator mimics the pipe\-operator supported by most command\-shell programs and should not be confused with the \fIbit\-or\fP operator\&. The pipe operator allows constructions like .nf p1 | p2 | p3 // piping 3 Proc objects cin | p1 | p2 | cout // p1 reads cin, p2 writes cout inName | p1 | outName // inName: file name of the file // read by p1, outName: file name // of the file written by p1 .fi When using the pipe operator \fIProc\fP objects reading input automatically specify their \fICIN\fP modes, while \fIProc\fP objects writing their standard output automatically specify their \fICOUT\fP modes\&. Following the pipe\-expression the \fIIOMode\fP specifications which were specified before the pipe\-expression are restored\&. .PP .SH "MEMBERS" .PP .IP o \fBbool active()\fP: .br If the child proc is currently running \fItrue\fP is returned and and \fIfalse\fP if not\&. .IP .IP o \fBvoid cerrMode(char const *lab) const\fP: .br The label \fIlab\fP, followed by the a textual representation of the currently configured \fIIOMode\fP is inserted into \fIstd::cerr\fP\&. .IP .IP o \fBvoid cerrPipes(char const *lab) const\fP: .br The text \fIProc\fP, followed by the \fIProc\(cq\&s\fP id, followed by label \fIlab\fP, followed by the currently active read and write file descriptors of the pipes currently used by the \fIProc\fP object are inserted into \fIstd::cerr\fP\&. .IP .IP o \fBstd::string const &cmd() const\fP: .br The currently specified child\-process starting command is returned\&. .IP .IP o \fBint exitStatus() const\fP: .br The last child\-process\(cq\&s exit\-status is returned\&. If a child process is currently running or if no child process has yet been started \-1 is returned\&. .IP .IP o \fBint finish()\fP: .br Waits until a currently active child process has ended and returns its exit status\&. If the child process isn\(cq\&t currently running \-1 is returned\&. .IP .IP o \fBIOMode ioMode() const\fP: .br The \fIIOMode\fP currently used by the \fIProc\fP object is returned\&. .IP .IP o \fBstd::string mode() const\fP: .br The \fIIOMode\fP currently used by the \fIProc\fP object is returned as a text\-string\&. .IP .IP o \fBint pid() const\fP: .br The child process\(cq\&s process\-id is returned\&. The returned value is undefined if no child process has yet been started\&. If the child process has already completed the last child process\(cq\&s id is returned\&. .IP .IP o \fBvoid pipeSignal(bool on)\fP: .br When incompletely forwarding information to a child process or incompletely reading information from a child process a \fIBroken pipe\fP may result, ending the currently running program\&. To avoid this, \fIpipeSignal(false)\fP can be called\&. To reactivate recognizing broken pipes \fIpipeSignal(true)\fP can be called\&. After using \fIpipeSignal(false)\fP failing insertions into a \fIProc\fP object result in its member \fIgood\fP returning \fIfalse\fP, and its members \fIbad\fP and \fIfail\fP returning \fItrue\fP\&. .IP .IP o \fBsize_t procIdx() const\fP: .br Every constructed \fIProc\fP object receives its own construction\-order index\&. The first \fIProc\fP object constructed in a program gets index value 0\&. .IP .IP o \fBProcType procType() const\fP: .br The \fIProcType\fP used when starting child processes is returned\&. .IP .IP o \fBvoid setBufSize(size_t bufSize)\fP: .br The stream buffer size in bytes used by streams communicating with child processes is set to \fIbufSize\fP\&. A zero byte buffer size is silently changed into one\&. .IP .IP o \fBvoid setCommand(std::string const &cmd)\fP: .br The (initial part of a) child process command specification is set to \fIcmd\fP\&. After calling this member \fIoperator+=\fP can be used to append additional text to the command specification\&. .IP .IP o \fBvoid setIOMode(IOMode mode)\fP: .br The \fIIOMode\fP used when calling child processes is set to \fImode\fP\&. Note that pipe\-expressions may modify the \fImode\fP of \fIProc\fP objects while the pipe\-expression is executed\&. For details see the end of the \fBOVERLOADED OPERATORS\fP section\&. .IP .IP o \fBvoid setProcType(ProcType type)\fP: .br The \fIProcType\fP used when starting child processes is set to \fItype\fP\&. .IP .IP o \fBvoid setTimeLimit(size_t timeLimit)\fP: .br The execution time limit of child processes is set to \fItimeLimit\fP (in seconds)\&. No time limit is used when \fItimeLimit 0\fP is specified\&. The time limit set by \fIsetTimeLimit\fP is used when starting the next child process\&. When calling \fIsetTimeLimit\fP then \fIpipeSignal(timeLimit == 0)\fP is automatically called\&. If that\(cq\&s not intended, then explicitly call \fIpipeSignal\fP after calling \fIsetTimeLimit\fP\&. .IP .IP o \fBvoid start(size_t timeLimit, IOMode mode = ALL, ProcType type = NO_PATH, size_t bufSize = 200)\fP: .br The currently specified command is started using the specified \fItimeLimit, IOMode, ProcType\fP and \fIbufSize\fP arguments\&. The \fIstart\fP members do not alter the currently configured default values of their arguments\&. .IP If a child process is still active when \fIstart\fP is called it first calls \fIstop\fP to end the currently running child process .IP .IP o \fBvoid start(IOMode mode, ProcType type = NO_PATH, size_t bufSize = 200)\fP: .br Same as the previous \fIstart\fP member, but using the currently configured \fItimeLimit\fP and requiring the specification of the \fIIOMode\fP to use\&. .IP .IP o \fBvoid start()\fP: .br Same as the first \fIstart\fP member, but using the currently configured \fItimeLimit, IOMode, ProcType\fP and \fIbufSize\fP values\&. .IP .IP o \fBint stop()\fP: .br A currently active child process is ended by calling \fIFork::endChild\fP (see also \fBfork\fP(3bobcat))\&. .IP .IP o \fBvoid system(size_t timeLimit, IOMode mode = ALL, size_t bufSize = 200)\fP: .br The currently stored command is executed as a command of \fBsh\fP(1), using the specified process\-arguments\&. .IP .IP o \fBvoid system(IOMode mode = ALL, size_t bufSize = 200)\fP: .br Same as the previous \fIsystem\fP command, but using the default \fItimeLimit\fP specification\&. .IP .IP o \fBsize_t timeLimit() const\fP: .br The currently configured execution time limit of \fIProc\(cq\&s\fP child process is returned\&. The return value zero indicates that no time limit is used\&. .IP .IP o \fBvoid useErr(std::ostream &out)\fP: .br The standard error output produced by the child process is sent to \fIout\fP\&. If the \fIProc\fP object had specified \fIIGNORE_CERR\fP then that \fIIOMode\fP is unset, and the \fICERR\fP mode is set\&. .IP .IP o \fBvoid useErr(std::string const &fname)\fP: .br Same as the previous member, but the child\(cq\&s standard error output is written to the file (path) \fIfname\fP\&. .IP .IP o \fBvoid useMerge(std::ostream &out)\fP: .br The standard output and standard error output produced by the child process is sent to \fIout\fP\&. If the \fIProc\fP object had specified \fICERR, COUT, IGNORE_CERR\fP, or \fIIGNORE_COUT\fP then those \fIIOModes\fP are unset, and the \fIMERGE_COUT_CERR\fP mode is set\&. .IP .IP o \fBvoid useMerge(std::string const &fname)\fP: .br Same as the previous member, but the child\(cq\&s standard output and standard error output is written to the file (path) \fIfname\fP\&. .IP .IP o \fBvoid useOut(std::ostream &out)\fP: .br The standard output produced by the child process is sent to \fIout\fP\&. If the \fIProc\fP object had specified \fIIGNORE_COUT\fP then that \fIIOMode\fP is unset, and the \fICOUT\fP mode is set\&. .IP .IP o \fBvoid useOut(std::string const &fname)\fP: .br Same as the previous member, but the child\(cq\&s standard output is written to the file (path) \fIfname\fP\&. .IP .IP o \fBint waitForChild()\fP: .br This member calls the identically named member from the class \fIFBB::Fork\fP, waiting for a child process to end\&. When calling \fIfinish\fP or using pipe\-expressions \fIwaitForChild\fP is automatically called\&. .PP .SH "EXAMPLES" .PP All examples should start with: .nf #include #include using namespace std; using namespace FBB; .fi .PP The first example illustrates how a program only producing output can be called\&. Its child proc simply is \fI/bin/ls\fP: .nf int main() { Proc proc(\(dq\&/bin/ls \-Fla\(dq\&, Proc::COUT); proc\&.start(); } .fi .PP The next example illustrates a child program that\(cq\&s given a limited amount of execution time: lines entered at the keyboard are echoed to the standard output stream for at most 5 seconds: .nf int main() { Proc proc(\(dq\&/bin/cat\(dq\&, Proc::CIN | Proc::COUT); proc\&.setTimeLimit(5); proc\&.start(); while (true) { cout << \(dq\&? \(dq\&; string line; if (not getline(cin, line)) return 0; proc << line << endl; // to /bin/cat if (not proc\&.good()) { cout << \(dq\&child time limit exceeded\en\(dq\&; break; } } cout << \(dq\&/bin/cat time limit of 5 seconds reached: child proc ended\en\(dq\&; } .fi .PP Piping is illustrated next: information at the program\(cq\&s standard input is piped to a second \fIProc\fP object, writing its standard output to the program\(cq\&s standard output stream: .nf int main() { Proc proc1{ \(dq\&/bin/cat\(dq\& }; Proc proc2{ \(dq\&/bin/cat\(dq\& }; cin | proc1 | proc2; // By default piping to cout\&. To do that // explicitly use \(cq\&\&.\&.\&. | proc2 | cout\(cq\& } .fi .PP .SH "FILES" \fIbobcat/proc\fP \- defines the class interface .PP .SH "SEE ALSO" \fBbobcat\fP(7), \fBexecle\fP(3), \fBfork\fP(3bobcat), \fBprocess\fP(3bobcat), \fBostream\fP(3fork), \fBsh\fP(1) .PP .SH "BUGS" .PP .SH "BOBCAT PROJECT FILES" .PP .IP o \fIhttps://fbb\-git\&.gitlab\&.io/bobcat/\fP: gitlab project page; .IP o \fIbobcat_6\&.06\&.02\-x\&.dsc\fP: detached signature; .IP o \fIbobcat_6\&.06\&.02\-x\&.tar\&.gz\fP: source archive; .IP o \fIbobcat_6\&.06\&.02\-x_i386\&.changes\fP: change log; .IP o \fIlibbobcat1_6\&.06\&.02\-x_*\&.deb\fP: debian package containing the libraries; .IP o \fIlibbobcat1\-dev_6\&.06\&.02\-x_*\&.deb\fP: debian package containing the libraries, headers and manual pages; .PP .SH "BOBCAT" Bobcat is an acronym of `Brokken\(cq\&s Own Base Classes And Templates\(cq\&\&. .PP .SH "COPYRIGHT" This is free software, distributed under the terms of the GNU General Public License (GPL)\&. .PP .SH "AUTHOR" Frank B\&. Brokken (\fBf\&.b\&.brokken@rug\&.nl\fP)\&. .PP