Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members | Related Pages | Examples

vos/corelibs/typechain/handlers/externaltypehandler.cc

Go to the documentation of this file.
00001 /* $Id: externaltypehandler.cc,v 1.9 2003/05/29 23:24:47 reed Exp $ */
00002 
00003 /*
00004 
00005     Copyright (C) 2001, 2002 Reed Hedges <reed@zerohour.net>
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Lesser General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Lesser General Public License for more details.
00016 
00017     You should have received a copy of the GNU Lesser General Public
00018     License along with this library; if not, write to the Free Software
00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00020 
00021 */
00022 
00023 #include "../typehandler.hh"
00024 #include "externaltypehandler.hh"
00025 
00026 #ifdef WIN32 // we don't have that forking stuff...
00027 
00028 
00029 int ExternalTypeHandler::exec_child_io(char *cmd, char **argv, FILE **readpipe, FILE **writepipe)
00030 {
00031    return (-1);
00032 }
00033 
00034 ExternalTypeHandler::ExternalTypeHandler(string name, char **decmd, char **encmd, string file_ext) : TypeHandler(name, file_ext) {
00035     encoder_command = 0;
00036 }
00037 
00038 ExternalTypeHandler::ExternalTypeHandler(string name, char *decmd, char *encmd, string file_ext) : TypeHandler(name, file_ext)  {
00039     encoder_command = 0;
00040 }
00041 
00042 ExternalTypeHandler::~ExternalTypeHandler() {
00043 }
00044 
00045 void ExternalTypeHandler::run_external(string& data, char **command) {
00046    throw TypeChain::DecodeError( "ExternalTypeHandler not supported on this platform", "(external)" );
00047 }
00048 
00049 
00050 #else
00051 
00052 /* for spawning program & piping data to and fro. */
00053 #include <stdio.h>
00054 #include <unistd.h>
00055 #include <stdlib.h>
00056 #include <sys/time.h>
00057 #include <sys/wait.h>
00058 #include <errno.h>
00059 
00060 /* exec_child_io, a private method of ExternalTypeHandler:
00061    Exec the named cmd as a child process, setting two pipes to communicate
00062    with the process, and returning the child's process ID.
00063    argv is a NULL-terminated list of arguments to pass to the command.  If
00064    there are no arguments, you can pass NULL. (this is the point of having
00065    both cmd and argv.)
00066    argv[0] is (by convention) the name of the command itself.
00067    I/O is block buffered by default (use setvbuf to change it).
00068    Use *readpipe  for reading the output of cmd, and *writepipe to write input
00069     to it.
00070    Uses execvp(), so you don't need to specify the full path: the PATH
00071    environment variable will be searched. Uses vfork() to fork, to conserve
00072    memory.
00073 
00074    example usage:
00075        childpid = exec_child_io("rot13", NULL, &in, &out);
00076        fputs("hello, world\n", out);
00077        fflush(out);
00078        fgets( buff, 50, in);
00079        printf("rot13(hello, world): %s\n", buff);
00080        fputc(EOF, out);
00081        waitpid(childpid);
00082 */
00083 
00084 int ExternalTypeHandler::exec_child_io(char *cmd, char **argv, FILE **readpipe, FILE **writepipe)
00085 {
00086    int childpid, pipe1[2], pipe2[2];
00087 
00088 
00089    /* create two pipes. */
00090    if ((pipe(pipe1) < 0) || (pipe(pipe2) < 0)) {
00091        fprintf(stderr, "error creating pipes: %s\n", strerror(errno));
00092        return -1;
00093    }
00094 
00095    /* fork. */
00096    if ((childpid = vfork()) < 0) {
00097        fprintf(stderr, "error forking!: %s\n", strerror(errno));
00098        return -1;
00099    } else if (childpid > 0) {
00100 
00101        /* We are parent. */
00102 
00103         // XXX TODO: waitpid(childpid, status, WNOHANG) and then check status??
00104 
00105        /* close reading half of pipe1, writing half of pipe2 */
00106        close(pipe1[0]);
00107        close(pipe2[1]);
00108 
00109 
00110        /* Write to child is pipe1[1], read from child is pipe2[0].  */
00111 
00112        *readpipe = fdopen(pipe2[0],"r");
00113        *writepipe = fdopen(pipe1[1],"w");
00114 
00115        /* set buffering mode on writepipe */
00116        //setlinebuf(*writepipe);
00117 
00118        return childpid;
00119 
00120    } else {
00121 
00122        /* We are the child. close writing half of pipe1, reading half of pipe2. */
00123        close(pipe1[1]);
00124        close(pipe2[0]);
00125 
00126        /* Read from parent is pipe1[0], write to  parent is pipe2[1].  the dup2
00127         * calls make the proper parts of the two pipes the same as this
00128         * process' stdin and stdout. when we exec, this will make the piping
00129         * work the way we want.*/
00130 
00131        dup2(pipe1[0],0);
00132        dup2(pipe2[1],1);
00133        close(pipe1[0]);
00134        close(pipe2[1]);
00135 
00136        /* exec  the command */
00137 
00138 
00139        if (execvp(cmd, argv) < 0) {
00140            //perror("execvp");
00141            fprintf(stderr, "external type handler: error executing command: %s\n", strerror(errno));
00142            close(pipe1[0]);
00143            close(pipe1[1]);
00144            close(pipe2[0]);
00145            close(pipe2[1]);
00146 
00147            // BUG: this will cause a SIGPIPE in the parent process!
00148            fprintf(stderr, "exiting.\n");
00149            exit(-1);
00150         }
00151 
00152        /* This half Never returns: send kill signal or EOF or something, and waitpid() for it in the parent. */
00153        return(-1);
00154    }
00155 
00156    return (-1);
00157 }
00158 
00159 
00160 
00161 ExternalTypeHandler::ExternalTypeHandler(string name, char **decmd, char **encmd, string file_ext) : TypeHandler(name, file_ext) {
00162 
00163 
00164    // duplicate decmd.
00165    int n = 0;
00166    int i;
00167    for(n = 0; decmd[n] != 0; n++);
00168    decoder_command = (char**)malloc(n * sizeof(char*) + 1);
00169    for(i = 0; i < n; i++) {
00170        decoder_command[i] = strdup(decmd[i]);
00171    }
00172 
00173    if(encmd != 0) {
00174        // duplicate encmd
00175        for(n = 0; encmd[n] != 0; n++);
00176        encoder_command = (char**)malloc(n * sizeof(char*) + 1);
00177        for(i = 0; i < n; i++) {
00178        encoder_command[i] = strdup(encmd[i]);
00179        }
00180    }
00181    else
00182        encoder_command = 0;
00183 }
00184 
00185 ExternalTypeHandler::ExternalTypeHandler(string name, char *decmd, char *encmd, string file_ext) : TypeHandler(name, file_ext)  {
00186    decoder_command = (char **)malloc(2 * sizeof(char*));
00187    decoder_command[0] = strdup(decmd);
00188    decoder_command[1] = 0;
00189    if(encmd != 0) {
00190        encoder_command = (char **)malloc(2 * sizeof(char*));
00191        encoder_command[0] = strdup(encmd);
00192        encoder_command[1] = 0;
00193    } else {
00194        encoder_command = 0;
00195    }
00196    needtofreecommands = true;
00197 }
00198 
00199 ExternalTypeHandler::~ExternalTypeHandler() {
00200    if(needtofreecommands) {
00201        if(decoder_command != 0) {
00202            while(*decoder_command != 0)
00203                free(*(decoder_command++));
00204            free(decoder_command);
00205            }
00206            if(encoder_command != 0) {
00207            while(*encoder_command != 0)
00208                free(*(encoder_command++));
00209            free(encoder_command);
00210        }
00211    }
00212 }
00213 
00214 void ExternalTypeHandler::run_external(string& data, char **command) {
00215 
00216    int child_pid;
00217    FILE* out;
00218    FILE* in;
00219    int c;
00220 
00221    printf("ExternalTypeHandler: running %s...\n", command[0]);
00222    child_pid = exec_child_io(command[0], command, &in, &out);
00223 
00224    if (child_pid < 0) {
00225        fprintf(stderr, "error executing external program '%s': %s\n", command[0], strerror(errno));
00226        throw TypeChain::DecodeError( string("Error executing external program ") + command[0] + ": " + strerror(errno), "(external)" );
00227    }
00228     else {
00229        fputs(data.c_str(), out);
00230        fclose(out);
00231        waitpid(child_pid, NULL, WNOHANG);
00232        data = "";
00233        while( (c = getc(in)) != EOF ) {
00234            data += c;
00235        }
00236        fclose(in);
00237    }
00238 }
00239 
00240 #endif
00241 
00242 
00243 void ExternalTypeHandler::decode(string& data, TypeParams& params) {
00244    run_external(data, decoder_command);
00245 }
00246 
00247 void ExternalTypeHandler::encode(string& data, TypeParams& params) {
00248     run_external(data, encoder_command);
00249 }
00250 

Generated on Tue Aug 12 03:55:38 2003 for Interreality Project - VOS by doxygen 1.3.2