home *** CD-ROM | disk | FTP | other *** search
- /*
- ** popen.c
- ** Written by Rick Schaeffer (ricks@isc-br.isc-br.com)
- NAME
- popen, pclose - initiate I/O to/from a process
-
- SYNOPSIS
- #include <stdio.h>
-
- FILE *popen(command, type)
- char *command, *type;
-
- pclose(stream)
- FILE *stream;
-
- DESCRIPTION
- The arguments to popen are pointers to null-terminated
- strings containing respectively a command line and an
- I/O mode, either "r" for reading or "w" for writing. It
- creates a pipe between the calling process and the command
- to be executed. The value returned is a stream pointer that
- can be used (as appropriate) to write to the standard input
- of the command or read from its standard output.
-
- A stream opened by popen **MUST** be closed by pclose, which
- waits for the associated process to terminate and returns
- the exit status of the command.
-
- Because stdio files are shared, a type "r" command may be
- used as an input filter, and a type "w" as an output filter.
-
- DIAGNOSTICS
- Popen returns a null pointer if files or processes cannot be
- created.
-
- Pclose returns -1 if stream is not associated with a
- `popened' command.
-
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <dos/dos.h>
- #include <dos/dosextens.h>
- #include <dos/record.h>
- #include <dos/dostags.h>
-
- #include <proto/exec.h>
- #include <proto/dos.h>
-
- struct POmsg {
- struct Message POm;
- int rc;
- char *cmd;
- };
-
-
- struct pstruct {
- FILE *fptr;
- struct POmsg childmsg;
- };
-
- struct pstruct poarray[6];
-
- static struct Process *thistask;
-
- FILE *popen(cmd,mode)
- char *cmd;
- char *mode;
- {
- static char tempname[] = "pipe:pXXX.XXX";
- char *pname,redir[20],*mktemp();
- short i;
- int pmode;
- int childprocess();
- struct TagItem nptags[] = {
- {NP_Entry,(Tag) childprocess},
- {NP_Input,0},
- {NP_Output,0},
- {NP_CloseInput,0},
- {NP_CloseOutput,0},
- {NP_StackSize,40000},
- {NP_Cli,1},
- {TAG_DONE,0}
- };
- struct pstruct *poptr;
- BPTR pfd;
- struct Process *child;
- struct CommandLineInterface *cli;
-
- /* First, get pointers to our process and cli structs */
- if (thistask == NULL)
- thistask = (struct Process *) FindTask(NULL);
- cli = Cli();
- poptr = NULL;
-
- /* now find an open pipe (we currently only allow 6 simultaneously
- open pipes) */
- for (i=0; i<6; i++) {
- if (poarray[i].fptr == NULL) {
- poptr = &poarray[i];
- break;
- }
- }
- if (poptr == NULL) {
- fprintf(stderr,"popen: Unable to find an open pipe\n");
- return(NULL);
- }
- if (strcmp(mode,"r") == 0)
- pmode = MODE_NEWFILE;
- else if (strcmp(mode,"w") == 0)
- pmode = MODE_OLDFILE;
- else {
- fprintf(stderr,"popen: Mode must be 'r' or 'w'\n");
- return(NULL);
- }
-
- /* Try to make a guaranteed unique file name for the pipe */
- tempname[5] = 'a' + i;
- strcpy(redir,tempname);
- pname = mktemp(redir); /* set up a pipe: file name */
-
- /* Now get the child's stack and priority set up */
- if (thistask->pr_CLI)
- nptags[5].ti_Data = cli->cli_DefaultStack << 2;
- else
- nptags[5].ti_Data = thistask->pr_StackSize;
-
- /* Open the side of the pipe for the child */
- pfd = Open(pname,pmode);
- if (pfd == 0) {
- fprintf(stderr,"popen: Unable to open pipe file\n");
- return(NULL);
- }
-
- /* set up the tags for the new process */
- if (pmode == MODE_NEWFILE) {
- nptags[1].ti_Data = (Tag) Input();
- nptags[2].ti_Data = (Tag) pfd;
- nptags[3].ti_Data = FALSE;
- nptags[4].ti_Data = TRUE;
- }
- else {
- nptags[1].ti_Data = (Tag) pfd;
- nptags[2].ti_Data = (Tag) Output();
- nptags[3].ti_Data = TRUE;
- nptags[4].ti_Data = FALSE;
- }
-
- /* create the command. since the "System" function runs through
- the default shell, we need to tell it not to fail so that we
- ALWAYS get back the exit status. This wouldn't be necessary
- if the CLI created by the System function inherited the parent's
- FAILAT level
- */
- poptr->childmsg.cmd = malloc(strlen(cmd) + 15);
- strcpy(poptr->childmsg.cmd,"failat 9999\n");
- strcat(poptr->childmsg.cmd,cmd);
-
- /* Create a port that we can get the child's exit status through */
- poptr->childmsg.POm.mn_ReplyPort = CreatePort(NULL,0);
- poptr->childmsg.POm.mn_Node.ln_Type = NT_MESSAGE;
- poptr->childmsg.POm.mn_Node.ln_Pri = 0;
- if (poptr->childmsg.POm.mn_ReplyPort == 0) {
- fprintf(stderr,"popen: Couldn't create message port\n");
- return(NULL);
- }
-
- /* Now we can start the new process. NOTE: this is actually going
- to create a process consisting ONLY of the function "childprocess"
- which can be seen below. childprocess() then runs the command
- passed in the startup message.
- */
- child = CreateNewProc(nptags);
- /* now pass the child the startup message */
- PutMsg(&child->pr_MsgPort,(struct Message *) &poptr->childmsg);
-
- /* Now open our side of the pipe */
- poptr->fptr = fopen(pname,mode);
- if (poptr->fptr == NULL) {
- fprintf(stderr,"popen: Unable to open pipe file %s\n",pname);
- DeletePort(poptr->childmsg.POm.mn_ReplyPort);
- return(NULL);
- }
- return(poptr->fptr);
- }
-
- pclose(fptr)
- FILE *fptr;
- {
- short i;
-
- /* Figure out which pipe we used for this file */
- for (i=0; i<6; i++)
- if (poarray[i].fptr == fptr)
- break;
- if (i > 5) {
- fprintf(stderr,"popen: DISASTER...couldn't find file pointer in pclose\n");
- exit(1);
- }
-
- /* close the file */
- fclose(fptr);
-
- /* now wait for the exit status */
- WaitPort(poarray[i].childmsg.POm.mn_ReplyPort);
- poarray[i].fptr = NULL;
-
- /* clean things up */
- DeletePort(poarray[i].childmsg.POm.mn_ReplyPort);
- free(poarray[i].childmsg.cmd);
- return(poarray[i].childmsg.rc);
- }
-
- char *mktemp(template)
- char *template;
- {
- register char *cp;
- register unsigned long val;
-
- cp = template;
- cp += strlen(cp);
- for (val = (unsigned long) FindTask(0L) ; ; )
- if (*--cp == 'X') {
- *cp = val%10 + '0';
- val /= 10;
- } else if (*cp != '.')
- break;
-
- if (*++cp != 0) {
- *cp = 'A';
- while (access(template, 0) == 0) {
- if (*cp == 'Z') {
- *template = 0;
- break;
- }
- ++*cp;
- }
- } else {
- if (access(template, 0) == 0)
- *template = 0;
- }
- return template;
- }
-
- childprocess()
- {
- struct TagItem systags[] = {
- {TAG_DONE,0}
- };
- struct Process *me;
- struct POmsg *startupmsg;
- int i;
-
- /* find our process structure */
- me = (struct Process *) FindTask(NULL);
-
- /* Wait for the parent to kick us off */
- WaitPort(&me->pr_MsgPort);
-
- /* Get the command to execute */
- startupmsg = (struct POmsg *) GetMsg(&me->pr_MsgPort);
-
- /* Now run the command. stdin and stdout are already set up */
- i = System(startupmsg->cmd,systags);
- startupmsg->rc = i;
- /* pass the exit code back to the parent */
- ReplyMsg((struct Message *) startupmsg);
- return(0);
- }
-