mcr@julie.UUCP (Michael Richardson) (12/07/89)
When I finally got annoyed at the silliness of command line passing, program launching (with exit codes) and the pr_CLI structure in general [this was at least 6 months ago] I began to build an alternate launching scheme, much more similar to the way the workbench startup message works. I based it on Leo Shwab's wblaunch code. (I'm not sure if Peter, Leo or myself that had this thought first. I think we all came up with it independently...) In order deal with who closes file descriptors, etc.. I wound up passing a bitmap to the sub-process telling it which file handles it can close. [Actually, I can also pass the `ToolWindow' field, and although I haven't done it yet, I always put 0 in the place where the Workbench message's `number of arguments' is so I could in fact be launched from Workbench...] I'd like this field eventually to be $ffffffff. (I can pass any number of FileHandles though. They are installed in the Manx `_devtab' structure.) The point: I want a Popen call that works properly, and for which each end has it's own filehandle. PIP: seemed to be the thing, except that I can't seem to get it work. [My popen call takes an argv/argv rather than a string. My `RogueStart' (there is a book named Rogue Star by Frederik Pohl) shell is too simple at present to bother feeding it through that.] I tried a simple test program: #include <stdio.h> #include <fcntl.h> #include <exec/memory.h> #include <libraries/dos.h> #include <libraries/dosextens.h> #include "bcpl.h" extern void *AllocMem(); extern struct FileHandle *Open(); extern FILE *fdopen(); extern void *CreatePort(); extern void *GetMsg(); main() { struct FileHandle *pin,*pout,*ret,*temp; int i; char buf[100],buf2[100]; if((pin=AllocMem(sizeof(struct FileHandle),MEMF_PUBLIC|MEMF_CLEAR))==NULL) { return(NULL); } if((pout=Open("PIP:4096",2000L))==NULL) { FreeMem(pin,sizeof(struct FileHandle)); return(NULL); } temp=(struct FileHandle*)BTOC(pout); (*pin)=(*temp); pin=(struct FileHandle*)CTOB(pin); printf("Created two handles: %08x and %08x\n",pin,pout); printf("Please type a line: "); fgets(buf,100,stdin); printf("Got %s\n",buf); i=Write(pin,buf,strlen(buf)); printf("Wrote string (%d)\n",i); i=Read(pout,buf2,100); buf2[i]='\0'; printf("Read (%d) %s\n",i,buf2); Close(pin); i=Read(pout,buf2,100); buf2[i]='\0'; printf("Read (%d) %s\n",i,buf2); Close(pout); } While this seemed to work --- it didn't always work twice, it seemed that I could crash it by allocating pout, and opening pin rather than the reverse. I can understand this. It also seemed that the order in which I closed them was significant. I haven't run this program in awhile (I've been procrastinating this posting for at least a couple of months... But today I'm home sick, and don't feel like bashing any of my other projects...) so I'm sorry if I am a bit vague --- but there is no way that I can guarantee that the two ends of the pipe will be closed by the two processes in the right order. Processes are quite asynchronous in nature... I pretty sure that it is the order in which I close them that is causing the guru --- sometimes when I run a little test it crashes. Sometimes not. If I run two of them sequencially or concurrently, I get the same results... FILE * popenv(ac,av,mode,pp) int ac; char *av[]; char *mode; struct MsgPort **pp; { struct FileHandle *in,*out,*err; struct FileHandle *pin,*pout,*ret,*temp; struct MsgPort *p; struct RogueStartup *r; FILE *rf; int code; long mask; int i; in=RogueInput(); out=RogueOutput(); err=RogueError(); if(mode[0]!='r' && mode[0]!='w') return(NULL); if((pin=AllocMem(sizeof(struct FileHandle),MEMF_PUBLIC|MEMF_CLEAR))==NULL) { return(NULL); } if((pout=Open("PIP:4096",2000L))==NULL) { FreeMem(pin,sizeof(struct FileHandle)); return(NULL); } temp=(struct FileHandle*)BTOC(pout); (*pin)=(*temp); pin=(struct FileHandle*)CTOB(pin); if(mode[0]='r') { out=pin; ret=pout; mask=(1L << 1); } else { in=pout; ret=pin; mask=(1L << 0); } /* Now set up the _devtab structure. */ for(i=0; i<_numdev; i++) { if(_devtab[i].fd==NULL) { break; } } if(i==_numdev) { Close(pin); Close(pout); return(NULL); } _devtab[i].fd=(long)ret; _devtab[i].mode=(mode[0]=='r' ? O_RDONLY : O_WRONLY); if((rf=(FILE *)fdopen(i,mode))==NULL) { _devtab[i].fd=NULL; Close(pin); Close(pout); return(NULL); } if((p=(struct MsgPort *)CreatePort(NULL,NULL))==NULL) { if(ret==pin) Close(pout); else Close(pin); fclose(rf); return(NULL); } if((r=RogueLaunch(p,av[0],av,ac,NULL,0,NULL,10000,in,out,err,mask))==NULL) { /* RogueLaunch(rport, name, argv, argc, env, pri, win, stack, in, out, err) -- * launch a program. * * RogueLaunch builds a startup message, loads a program, and launches it. * * Arguments: * rport -- reply port to receive startup message back when the program * finishes. * name -- File name for the program to load. * argv -- list of filenames to pass to loaded program. * argc -- length of argument list. * env -- list of environment variables (local) * pri -- priority of the new process. * win -- ToolWindow for the new process, or NULL. * stack -- Stack size for the new process. * in -- Where to find Standard input \ Only taking * out -- Where to find Standard output > three is * err -- Where to find Standard error / arbitrary. * mask -- bitmap of file descriptors to close. * * argv[0] should be the same as the program. pri should normally be 0. * stack should normally be at least 4K. */ if(ret==pin) Close(pout); else Close(pin); fclose(rf); DeletePort(p); return(NULL); } *pp=p; return(rf); } int pclose(f,pp) FILE *f; struct MsgPort **pp; { struct MsgPort *p; struct RogueStart *rs; int code; if(f==NULL||pp==NULL) return(-1); p=*pp; if(p==NULL) return(-2); WaitPort(p); rs=GetMsg(p); if(rs) { code=RogueFreeStartup(rs); } fclose(f); /* Close our end of the pipe */ return(code); } I also somewhat suspect the fclose() call, but I believe I have tried converting everything to FileHandle level... BTW: Programs compiled with the Rogue Startup code can continue to run from CLI, and if I ever make the WorkBench modification from the workbench as well. Many parts of the uucp system that this is being posted with runs via RogueLaunch. Specifially I've rewritten uux/uuxqt/unbatchfc/rmail. Rmail has also be modified a large amount -- it adds Received:, collapses From_ [yuck], and adds a Message-Id: if there isn't one. I called it smail because I'll eventually add `smart-host' to it. It also calls uux with the `-a' option (however, I haven't figured out what uux should really do with it in terms of the X. file.). [Lots more to say -- but mail me. An AmigaNet (not to me confused with FidoNet despite that we run software that seems to be compatible :-)) /AmigaUUCP mailing list has existed for about year as amiga-mailer@doe.carleton.ca and amiga-mailer@fts1.UUCP (doe doesn't like .UUCP addresses that much...). The list is fairly dead right now, due in part because much of the activity has moved to an echo called AMIGASTAND.] The rewrite of the rest [and the posting to Bob Page] awaits pipes so that I can get rid of some of the temporary files. I don't like temporary files. -- :!mcr!: Michael Richardson Amiga v--------+ HOME: mcr@julie.UUCP | SCHOOL: mcr@doe.carleton.ca Fido: 1:163/109.10<--+ WORK: michael@fts1.UUCP
peter@sugar.hackercorp.com (Peter da Silva) (12/07/89)
In article <1610.AA1610@julie> mcr@julie.UUCP (Michael Richardson) writes: > When I finally got annoyed at the silliness of command line > passing, program launching (with exit codes) and the pr_CLI structure > in general [this was at least 6 months ago] I began to build an > alternate launching scheme, much more similar to the way the > workbench startup message works. Good for you. > I based it on Leo Shwab's wblaunch > code. Leo's? Not mine? What's Leo's look like? > In order deal with who closes file descriptors, etc.. I wound > up passing a bitmap to the sub-process telling it which file handles > it can close. Where in the Startup message? > [Actually, I can also pass the `ToolWindow' field, > and although I haven't done it yet, I always put 0 in the place > where the Workbench message's `number of arguments' is so I could > in fact be launched from Workbench...] What's the point of this? Workbench will pass variable numbers of arguments, and usually at least one (dirlock & name of the program itself). > I'd like this field eventually > to be $ffffffff. (I can pass any number of FileHandles though. > They are installed in the Manx `_devtab' structure.) More details, please. > if((pin=AllocMem(sizeof(struct FileHandle),MEMF_PUBLIC|MEMF_CLEAR))==NULL) { > return(NULL); > } > if((pout=Open("PIP:4096",2000L))==NULL) { > FreeMem(pin,sizeof(struct FileHandle)); > return(NULL); > } > temp=(struct FileHandle*)BTOC(pout); > (*pin)=(*temp); > pin=(struct FileHandle*)CTOB(pin); You're copying the file handles? Interesting. I wouldn't have expected that to work... I don't think there's any guarantee of that. (too bad there's no DupFH call. Commodore? Are you there Commodore? How about for 1.4?) > BTW: Programs compiled with the Rogue Startup code can continue to run > from CLI, and if I ever make the WorkBench modification from the workbench > as well. Sounds good. Where's the code? > The rewrite of the rest [and the posting to Bob Page] awaits pipes > so that I can get rid of some of the temporary files. I don't like > temporary files. Why don't you do this? sprintf(PipeName, "%s:rogue%dpipe%d", PipeDevice, ProcessId, Sequence++); pin = Open(PipeName, MODE_NEWFILE); pout = Open(PipeName, MODE_OLDFILE); This way you won't have to depend on anyone having PIP:, and won't be playing unportable games... -- Peter "Have you hugged your wolf today" da Silva <peter@sugar.hackercorp.com> `-_-' 'U` "Really, a video game is nothing more than a Skinner box." -- Peter Merel <pete@basser.oz>
mcr@julie.UUCP (Michael Richardson) (12/16/89)
>In article <1610.AA1610@julie> mcr@julie.UUCP (Michael Richardson) writes: >> alternate launching scheme, much more similar to the way the >> workbench startup message works. > >Good for you. > >> I based it on Leo Shwab's wblaunch >> code. > >Leo's? Not mine? What's Leo's look like? I honestly don't remember. Rest assured that I refered to some code that you posted at some point too. >Where in the Startup message? /* fast:exp/src/include/roguestar.h */ struct RogueStartup { struct Message rs_Message; struct MsgPort *rs_Process; BPTR rs_Segment; LONG rs_dummy; /* ALWAYS 0 -- would be NumArgs in WBStartup */ char *rs_ToolWindow; /* Usually NULL */ int rs_argc; char **rs_argv; int rs_fhc; /* Number of file handles to install */ long *rs_fhv; int rs_exitcode; BPTR rs_CurrentDir; char **rs_environ; /* Arguments of environment space */ int rs_envcount; /* Number of variables */ char *rs_envspace; /* Buffer containing variables */ int rs_envsize; /* Size of buffer */ long rs_closebits[2]; /* Close this filehandle (major kludge) */ }; Hmm... Guess I put in 64 bits for FileHandles... From boot:install/aztecc/include/workbench/startup.h: struct WBStartup { struct Message sm_Message; struct MsgPort * sm_Process; BPTR sm_Segment; LONG sm_NumArgs; char * sm_ToolWindow; struct WBArg * sm_ArgList; }; >What's the point of this? Workbench will pass variable numbers of arguments, >and usually at least one (dirlock & name of the program itself). I don't want the locks. I pass the full file names. A possible modification would use exec List instead of an array to hold the arguments. Note: the RogueLaunch program allocates memory for the argv and envp, and copies. The child does own them. They are cleaned up by the cleanup process. In order to provide the ability to invoke an synchronous task and later decide to make it asynchronous (just don't close your window!) I'll eventually turn this into rogue.library, and have it CreateProc() an `init' process that will actually wait on the subprocesses, deallocate storage and return error codes when you `RogueWait()' (or don't wait) [who was it that was working on Edition 7 under AmigaDOS --- Doug Merrit no? How is it going?] >More details, please. fast:exp/src/rogue/_main.c: /* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */ [ What I'm to do about that line, I'm not sure yet. ] [blayh blah blah] pp = _FindTask(0L); if(alen) { _cli_parse(pp, alen, aptr); argc=_argc; argv=_argv; Enable_Abort = 1; _devtab[0].mode |= O_STDIO; /* shouldn't close if CLI */ _devtab[1].mode |= O_STDIO; goto normsetup; } else { int i; char *window; long wind; struct FileHandle *fhp; _WaitPort(&pp->pr_MsgPort); RogueStartMsg = (struct RogueStartup *)GetMsg(&pp->pr_MsgPort); if(RogueStartMsg->rs_dummy==0) { argv=RogueStartMsg->rs_argv; argc=RogueStartMsg->rs_argc; environ=RogueStartMsg->rs_environ; pp->pr_CurrentDir=RogueStartMsg->rs_CurrentDir; CurrentDir(RogueStartMsg->rs_CurrentDir); if(window=RogueStartMsg->rs_ToolWindow) { if(wind = _Open(window, MODE_OLDFILE)) { fhp = (struct FileHandle *) (wind << 2); pp->pr_ConsoleTask = (APTR) fhp->fh_Type; pp->pr_CIS = (BPTR)wind; pp->pr_COS = (BPTR)_Open("*", MODE_OLDFILE); goto normsetup; } } else if(RogueStartMsg->rs_fhc) { for(i=0; i<RogueStartMsg->rs_fhc; i++) { _devtab[i].fd=RogueStartMsg->rs_fhv[i]; if(i<32) { if((RogueStartMsg->rs_closebits[0]&(1L << i))==0) { _devtab[i].mode |= O_STDIO; /* shouldn't close if CLI */ } } } pp->pr_CIS=_devtab[0].fd; pp->pr_COS=_devtab[1].fd; } else { normsetup: _devtab[0].fd = _Input(); if(_devtab[1].fd = _Output()) _devtab[2].fd = _Open("*", MODE_OLDFILE); } } else { /* We'd do the normal Workbench thing here */ /* I suspect that this branch crashes. I don't run workbench and draw icons often enough to have every tried it.*/ _exit(254); } } _exit(main(argc, argv)); /* so much for `void main()' :-) */ } > if((pin=AllocMem(sizeof(struct FileHandle),MEMF_PUBLIC|MEMF_CLEAR))==NULL) { > return(NULL); > } > if((pout=Open("PIP:4096",2000L))==NULL) { ^^^^^ man:util/ConMan.doc: ConMan V1.3 Copyright (c) 1987, 1988 by William S. Hawes .... ConMan is also a pipe-handler responding to the name PIP:NNNN, where NNNN is the "capacity" of the pipe. It must be opened using a private packet called ACTION_DOUBLE (value 2000L), and the filehandle you get from a call to Open("PIP:",2000) counts for two and so can be cloned by your program. After allocating a filehandle structure (using the AmigaDOS memory conventions), just copy the filehandle from Open() into the new structure --- and don't forget to Close() both of them! My WShell command shell uses the ConMan PIP: device as its pipe handler. Does this follow better now? >(too bad there's no DupFH call. Commodore? Are you there Commodore? How about > for 1.4?) YES. PLEASE. I believe that Colin Plumb had some other things to peeves having to do with getting path names from FileHandles. I think they deserve to be repeated... (Colin: remember that `message' you wrote me concerning CRCs? All 22k of it? I posted it as crcinfo.zoo on 1:163/109 [aka atronx.UUCP, soon to be amiga.ottawa.on.ca]. The download count is quite respectable...) >Sounds good. Where's the code? Coming. I want a working popen() call and I have to write the environment variable stuff... >Why don't you do this? > > sprintf(PipeName, "%s:rogue%dpipe%d", PipeDevice, ProcessId, Sequence++); > pin = Open(PipeName, MODE_NEWFILE); > pout = Open(PipeName, MODE_OLDFILE); My last resort. Pipe: doesn't like. I've spent hours running dnet both here to school, and between myself and other people, and I've _never_ gotten the scli server to work the DPIPE:, or Matt's original pipe, or the 1.3 pipe... It took me three days to run Markus Wandel's exec disassembly because I couldn't get the pipes to work. They just don't like me. -- :!mcr!: Michael Richardson Amiga v--------+ HOME: mcr@julie.UUCP | SCHOOL: mcr@doe.carleton.ca Fido: 1:163/109.10<--+ WORK: michael@fts1.UUCP
peter@sugar.hackercorp.com (Peter da Silva) (12/17/89)
In article <1718.AA1718@julie> mcr@julie.UUCP (Michael Richardson) writes: > /* fast:exp/src/include/roguestar.h */ > struct RogueStartup { > struct Message rs_Message; > struct MsgPort *rs_Process; > BPTR rs_Segment; > LONG rs_dummy; /* ALWAYS 0 -- would be NumArgs in WBStartup */ Probably should be OK. > char *rs_ToolWindow; /* Usually NULL */ I'd leave in sm_ArgList as well. > int rs_argc; > char **rs_argv; So far so good. > int rs_fhc; /* Number of file handles to install */ > long *rs_fhv; Not sure about this part. UNIXY, to be sure. But is it useful to get that far ahead of AmigaDOS? > int rs_exitcode; Good. > BPTR rs_CurrentDir; Good. But I'd put this in sm_ArgList[0]. And put in the real program name in there too. Keep compatability with WB stuff. > char **rs_environ; /* Arguments of environment space */ > int rs_envcount; /* Number of variables */ Not a good idea. You want to co-operate with AmigaDOS, and that means using env:. > char *rs_envspace; /* Buffer containing variables */ > int rs_envsize; /* Size of buffer */ > long rs_closebits[2]; /* Close this filehandle (major kludge) */ Why is this a kludge? It fits in well with rs_fhc/rs_fhv. Of course, you should probably not do this unless you know you have a Rogue program. > I don't want the locks. I pass the full file names. A possible modification > would use exec List instead of an array to hold the arguments. There's a point to both. It'd be cooler to make RogueStartup a full superset of WBStartup. Using some magic token to distinguish them. > ConMan is also a pipe-handler responding to the name PIP:NNNN... Please don't make it depend on CONMAN, anyway. > > sprintf(PipeName, "%s:rogue%dpipe%d", PipeDevice, ProcessId, Sequence++); > > pin = Open(PipeName, MODE_NEWFILE); > > pout = Open(PipeName, MODE_OLDFILE); > My last resort. Pipe: doesn't like. I can't parse this statement. PIPE: doesn't like what? > I've spent hours running dnet both here to school, and between myself and > other people, and I've _never_ gotten the scli server to work the DPIPE:, > or Matt's original pipe, or the 1.3 pipe... You can make "PipeDevice" "PIP:" if you know you need that. I don't use ConMan (irrational prejudice... it just feels icky to REPLACE con:), so I could use P:, PIPE:, whatever... What order are you opening the pipes in? -- Peter "Have you hugged your wolf today" da Silva <peter@sugar.hackercorp.com> `-_-' 'U` "I haven't lost my mind, it's backed up on tape somewhere"
tell@oscar.cs.unc.edu (Stephen Tell) (12/17/89)
In article <4778@sugar.hackercorp.com> peter@sugar.hackercorp.com (Peter da Silva) writes: >In article <1718.AA1718@julie> mcr@julie.UUCP (Michael Richardson) writes: >> /* fast:exp/src/include/roguestar.h */ >> char **rs_environ; /* Arguments of environment space */ >> int rs_envcount; /* Number of variables */ > Not a good idea. You want to co-operate with AmigaDOS, and that means > using env:. But env: is deficient in that its "global" and therefore you can't have more than one environment. Consider a 2-user system (using AUX: or dnet:) or a multi-user BBS; each user may need his own environment. I'm sure there are other more mundane examples. Now if we were all to use env:<process-id>/variable, and use links where only a small part of the environment (or none at all) changed between a parent and its child... (What? no links? aren't they "in there" too?) >There's a point to both. It'd be cooler to make RogueStartup a full superset >of WBStartup. Using some magic token to distinguish them. In general, this looks like a good idea. CBM seems more likely to adopt it as a standard somday (1.5?) if it fits well with existing stuff. >Peter "Have you hugged your wolf today" da Silva <peter@sugar.hackercorp.com> >`-_-' > 'U` "I haven't lost my mind, it's backed up on tape somewhere" -------------------------------------------------------------------- Steve Tell tell@wsmail.cs.unc.edu CS Grad Student, UNC Chapel Hill.
peter@sugar.hackercorp.com (Peter da Silva) (12/17/89)
In article <11223@thorin.cs.unc.edu> tell@oscar.cs.unc.edu (Stephen Tell) writes: > In article <4778@sugar.hackercorp.com> peter@sugar.hackercorp.com (Peter da Silva) writes: > >In article <1718.AA1718@julie> mcr@julie.UUCP (Michael Richardson) writes: > >> /* fast:exp/src/include/roguestar.h */ > >> char **rs_environ; /* Arguments of environment space */ > >> int rs_envcount; /* Number of variables */ > > Not a good idea. You want to co-operate with AmigaDOS, and that means > > using env:. > But env: is deficient in that its "global" and therefore you can't have > more than one environment. I understand this. However you should retain compatibility with the system as it exists. Similarly, your programs should use AmigaDOS keyword argument handling rather than UNIX -option style, and they should work properly under the Workbench and CLI as well as RogueStartup. If Getenv returns a different value depending on whether the program is started from RogueStartup and CLI that's a bad thing. > >There's a point to both. It'd be cooler to make RogueStartup a full superset > >of WBStartup. Using some magic token to distinguish them. > In general, this looks like a good idea. CBM seems more likely to adopt it > as a standard somday (1.5?) if it fits well with existing stuff. Also people are more likely to use it today. -- Peter "Have you hugged your wolf today" da Silva <peter@sugar.hackercorp.com> `-_-' 'U` "I haven't lost my mind, it's backed up on tape somewhere"
ricks@eagle.iscs.com (Rick Schaeffer 99) (12/18/89)
I've been following the discussion on using pipes with interest. Recently I hacked this small routine which uses the ARP 1.3 AsyncRun() function and AmigaDos 1.3 pipes to provide a Unix-like popen() function. It seems to work fine on anything I've tried (including standard AmigaDos programs like type and list that were written in BCPL). It probably has some bugs but, since it's short and *does* seem to work I thought I'd post it. Comments, improvements, and whatnot welcome. It was compiled with Lattice 5.04 but shouldn't be too tough to make with Aztec. /* ** 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 <string.h> #include <proto/dos.h> #include <proto/exec.h> #include <arp/arpbase.h> #include <ios1.h> struct ArpBase *ArpBase; static struct Process *thistask; static struct ProcessControlBlock pcb; struct pstruct { FILE *fptr; struct ZombieMsg exitmsg; }; struct pstruct poarray[6]; FILE *popen(cmd,mode) char *cmd; char *mode; { char *parms; static char tempname[] = "pipe:pXXX.XXX"; char *pname,redir[20],*mktemp(); short i; int pmode; struct pstruct *poptr; BPTR pfd; if (thistask == NULL) thistask = (struct Process *) FindTask(NULL); if (ArpBase == NULL) ArpBase = (struct ArpBase *) OpenLibrary(ArpName,ArpVersion); if (ArpBase == NULL) { fprintf(stderr,"Arp Open Failed\n"); return(NULL); } poptr = NULL; 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); } tempname[5] = 'a' + i; strcpy(redir,tempname); pname = mktemp(redir); /* set up a pipe: file name */ setmem(&pcb, sizeof(struct ProcessControlBlock), 0); /* Now get the child's stack and priority set up */ if (thistask->pr_CLI) { struct CommandLineInterface *cli; cli = (struct CommandLineInterface *) BADDR(thistask->pr_CLI); pcb.pcb_StackSize = cli->cli_DefaultStack << 2; } else pcb.pcb_StackSize = thistask->pr_StackSize; pcb.pcb_Pri = thistask->pr_Task.tc_Node.ln_Pri; /* 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); } if (pmode == MODE_NEWFILE) pcb.pcb_Output = pfd; else pcb.pcb_Input = pfd; /* Locate the break between command and parameters */ parms = strpbrk(cmd," \t"); if (parms) { *parms++ = 0; parms = stpblk(parms); if (parms && *parms == 0) parms = NULL; } /* Create a port for the child's exit message */ poptr->exitmsg.zm_ExecMessage.mn_ReplyPort = CreatePort(NULL,0); if (poptr->exitmsg.zm_ExecMessage.mn_ReplyPort == 0) { fprintf(stderr,"popen: Couldn't create message port\n"); return(NULL); } pcb.pcb_LastGasp = &poptr->exitmsg; if (ASyncRun(cmd,parms,&pcb) < 0) { fprintf(stderr,"popen: AsyncRun failed\n"); DeletePort(poptr->exitmsg.zm_ExecMessage.mn_ReplyPort); return(NULL); } /* 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->exitmsg.zm_ExecMessage.mn_ReplyPort); return(NULL); } return(poptr->fptr); } pclose(fptr) FILE *fptr; { short i; 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); } fclose(fptr); WaitPort(poarray[i].exitmsg.zm_ExecMessage.mn_ReplyPort); poarray[i].fptr = NULL; DeletePort(poarray[i].exitmsg.zm_ExecMessage.mn_ReplyPort); return(poarray[i].exitmsg.zm_ReturnCode); } 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; } -- Rick Schaeffer UUCP: uunet!isc-br.isc-br.com!ricks ISC-Bunker Ramo ricks@isc-br.isc-br.com Box TAF-C8 Phone: (509)927-5114 Spokane, WA 99220
kim@uts.amdahl.com (Kim DeVaughn) (12/20/89)
In article <4780@sugar.hackercorp.com>, peter@sugar.hackercorp.com (Peter da Silva) writes: > In article <11223@thorin.cs.unc.edu> tell@oscar.cs.unc.edu (Stephen Tell) writes: > > In article <4778@sugar.hackercorp.com> peter@sugar.hackercorp.com (Peter da Silva) writes: > > >In article <1718.AA1718@julie> mcr@julie.UUCP (Michael Richardson) writes: > > >> /* fast:exp/src/include/roguestar.h */ > > > >> char **rs_environ; /* Arguments of environment space */ > > >> int rs_envcount; /* Number of variables */ > > > Not a good idea. You want to co-operate with AmigaDOS, and that means > > > using env:. > > > But env: is deficient in that its "global" and therefore you can't have > > more than one environment. > > I understand this. However you should retain compatibility with the system > as it exists. Similarly, your programs should use AmigaDOS keyword argument > handling rather than UNIX -option style, and they should work properly under > the Workbench and CLI as well as RogueStartup. If you opt for compatibility as Peter suggests, could you please make it settable. Alot of people prefer -option style specifications. Similarly with a solution to the env: problem. /kim -- UUCP: kim@amdahl.amdahl.com or: {sun,decwrl,hplabs,pyramid,uunet,oliveb,ames}!amdahl!kim DDD: 408-746-8462 USPS: Amdahl Corp. M/S 249, 1250 E. Arques Av, Sunnyvale, CA 94086 BIX: kdevaughn GEnie: K.DEVAUGHN CIS: 76535,25