/* popen.c * * Implementation of popen() / pclose for Atari ST (will eventually work for * MSDOS too). The pipe is simulated by a temporary file. If caller wants to * read the pipe, then execute the command in popen and return a descriptor * to the output delivered by the command. If caller wants to write to the * pipe, then preserve the callers output in a temp file and execute the * command on pclose. * Since it is necessary to keep some information from popen() up to the * pclose(), we keep all opened pipes in a list and fill up the entries as * needed. Pipes are identified by their FILE descriptor returned from the * fopen() call. * * Revision 1.2, jrb 08-15-89 applied kai's diffs * gcc-lib's system() now does re-direction. Changes to * for re-direction stuff because of this. * * Revision 1.1, kub 05-23-89 * written 89/05/23 by Kai-Uwe Bloem (I5110401@DBSTU1.BITNET for now) */ #include #include #include #include #include struct _pipe { char pmode; /* "r" or "w" to/from the pipe ? */ char *pcommand; /* cmd to execute (only for "w") */ int pstat; /* exit code of cmd (only for "r") */ char pname[32]; /* temp filename. 32 should be enough...*/ FILE *pfile; /* pipe identifier */ struct _pipe *pnext; /* next pipe in the list. */ }; static struct _pipe *__pipes = NULL; /* head of pipe list */ /* open a pipe to the command argument in the mode given by the type string. * If caller wants to read the pipe, redirect output and execute command, * then open the temp file and return that. If caller wants to write to * the pipe, create the temp file and return that. */ FILE *popen(command, type) const char *command, *type; { struct _pipe *p; /* the new pipe's list entry */ /* get space for the new pipe. If we can't get it then that's that */ p = (struct _pipe *) malloc(sizeof(struct _pipe)); if (p == NULL) return (FILE *) NULL; /* initialize the new pipe entry */ p->pmode = *type; p->pfile = (FILE *) NULL; (void)tmpnam(p->pname); /* make command line with appropriate re-direction */ if((p->pcommand = (char *)malloc(strlen(command)+strlen(p->pname)+4L)) == (char *)NULL) { /* no mem */ free(p); return (FILE *)NULL; } strcpy(p->pcommand, command); strcat(p->pcommand, (p->pmode == 'r')? " >" : " <"); strcat(p->pcommand, p->pname); /* Everything has now been set up to really execute the pipe request */ switch(p->pmode) { case 'r': /* reading */ /* execute the command, output redir. to tmp pipe file */ p->pstat = system(p->pcommand); if (p->pstat < 0) { unlink(p->pname); return (FILE *)NULL; } p->pfile = fopen(p->pname,"r"); /* now open the pipe */ break; case 'w': /* writing */ /* open tmp pipe file */ p->pfile = fopen(p->pname,"w"); /* open the pipe file */ break; } if (p->pfile) { /* pipe successfully established. Link it to the list */ p->pnext = __pipes; __pipes = p; return p->pfile; } else { /* if there is no pipe identifier then throw it away */ unlink(p->pname); free(p->pcommand); free(p); return (FILE *) NULL; } } /* close a pipe created by popen(). If caller wanted to read the pipe, then * just do the cleanup and return the command's status code. If caller wanted * to write to the pipe, the work has just started. Close the tempfile, call * the command with input redirected to the temp file and cleanup after that. */ int pclose(fp) FILE *fp; { struct _pipe *p, /* the pipe's list element */ *q; /* predecessor of p in the list */ int status = -1; /* return status of the command */ /* search the pipe list for a pipe matching the FILE descriptor */ for (p = __pipes, q = NULL; p && p->pfile != fp; q = p, p = p->pnext); if (p == NULL) /* Never had a popen() for this file... */ return status; /* this pclose call makes no sense ! */ fclose(p->pfile); /* close temp file */ switch(p->pmode) { case 'w': /* writing */ status = system(p->pcommand); /* execute the command */ break; case 'r': /* reading */ status = p->pstat; /* just get status code */ break; } unlink(p->pname); /* temp file no longer needed */ /* remove the pipe from the list */ if (q) /* not the first in the list, unlink it from previous pipe */ q->pnext = p->pnext; else /* first in the list, set new list head */ __pipes = __pipes->pnext; /* Now free the pipe entry */ free(p->pcommand); free(p); return status; }