🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: gnu.gcc.help
Article #50181

Re: gcc equivalent of spawn (MSDOS)

#50181
From: Marty Leisner 25733
Date: Thu, 11 Nov 1993 14:22
843 lines
21547 bytes
I ported gnu make to Ms/Dos a number of years ago...

What I do is:
	1) use the small model for everything
	2) have a fork which works
	3) I stripped out all the builtins to gmake and it fit...

This is for Aztec C...

Let me know if its useful...I may package it and distribute it...


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  exec.c execl.c execlp.c execv.c execve.c execvp.c
#   frkmagic.asm fork.c
# Wrapped by leisner@gnu on Thu Nov 11 09:20:11 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'exec.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'exec.c'\"
else
echo shar: Extracting \"'exec.c'\" \(1635 characters\)
sed "s/^X//" >'exec.c' <<'END_OF_FILE'
X
X/* 
X * If do_spawn, use out DOS exec function, freeing the enviornment on the way
X  *out.
X * If execing, massage the environment (i.e. if no environment, free out environment
X * and set psp to use new environment
X * Then call Aztec Exec function.
X * $Log:	exec.c $
X * Revision 1.1  88/12/04  14:49:12  marty
X * Initialization
X * 
X */
X
X
X#include <dos/exec.h>
X
X
X#define FAR_PTR(seg, off)       ((void far *) (((long) seg << 16L) + (long) off))
X 
Xint do_spawn = 0;
X 
Xsetup_exec(filename, argv, env_segment)
Xchar *filename;
Xchar **argv;
Xshort env_segment;
X{
X	
X	int result = -1;
X	char fcb1[16],  fcb2[16];
X	char buffer[130];
X	char *cp;
X	char *xp;
X	int fd;
X	struct exe exe_header;
X	extern unsigned _PSP;
X	unsigned far *psp_env;
X	
X	
X	if(do_spawn) {
X		result =  dos_exec(filename, argv, env_segment);
X		do_spawn = 0;
X	} else {
X		psp_env = FAR_PTR(_PSP, 0x2c);
X		
X		/* need to prepare for exec */
X		if((fd = open(filename, 0)) < 0) 
X			return -1;
X	
X		if(read(fd, &exe_header, sizeof exe_header) != sizeof exe_header)
X			exe_header.exec_magic = 0;
X
X		/* if this environment is not the current one, free the old one and use this */
X		if(*psp_env != env_segment) {
X			free_dos_memory(*psp_env);
X			*psp_env = env_segment;
X		}
X		
X		/* copied this code from aztec execv.c */
X		argv++;	/* skip first arg */
X		cp = buffer + 1;
X		while(xp = *argv++) {
X			*cp++ = ' ';
X			while(*xp) {
X				if(cp >= buffer + 128)
X					goto done;
X				*cp++ = *xp++;
X			}
X		}
X		
Xdone:
X		*cp = 0xd;	/* need this to be dos compatbile -- marty added */
X		buffer[0] = cp - (buffer + 1);
X		exec(fd, buffer, fcb1, fcb2, &exe_header);
X				
X
X
X
X	}
X
X	return result;
X	
X		
X		
X	
X	
X	
X}
END_OF_FILE
if test 1635 -ne `wc -c <'exec.c'`; then
    echo shar: \"'exec.c'\" unpacked with wrong size!
fi
# end of 'exec.c'
fi
if test -f 'execl.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'execl.c'\"
else
echo shar: Extracting \"'execl.c'\" \(157 characters\)
sed "s/^X//" >'execl.c' <<'END_OF_FILE'
X/* $Log:	execl.c $
X * Revision 1.1  88/12/04  14:49:14  marty
X * Initialization
X *  */
X
Xexecl(file, args)
Xchar *file, *args;
X{
X	return execv(file, &args);
X}
END_OF_FILE
if test 157 -ne `wc -c <'execl.c'`; then
    echo shar: \"'execl.c'\" unpacked with wrong size!
fi
# end of 'execl.c'
fi
if test -f 'execlp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'execlp.c'\"
else
echo shar: Extracting \"'execlp.c'\" \(163 characters\)
sed "s/^X//" >'execlp.c' <<'END_OF_FILE'
X/* $Log:	execlp.c $
X * Revision 1.1  88/12/04  14:49:16  marty
X * Initialization
X *  */
X
Xexeclp(name, args)
Xchar *name, *args;
X{
X
X	return  execvp(name, &args);
X}
X
END_OF_FILE
if test 163 -ne `wc -c <'execlp.c'`; then
    echo shar: \"'execlp.c'\" unpacked with wrong size!
fi
# end of 'execlp.c'
fi
if test -f 'execv.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'execv.c'\"
else
echo shar: Extracting \"'execv.c'\" \(192 characters\)
sed "s/^X//" >'execv.c' <<'END_OF_FILE'
X
X/* $Log:	execv.c $
X * Revision 1.1  88/12/04  14:49:18  marty
X * Initialization
X *  */
Xextern char **environ;
X
Xexecv(file, argv)
Xchar *file, **argv;
X{
X	return execve(file, argv, environ);
X}
X
END_OF_FILE
if test 192 -ne `wc -c <'execv.c'`; then
    echo shar: \"'execv.c'\" unpacked with wrong size!
fi
# end of 'execv.c'
fi
if test -f 'execve.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'execve.c'\"
else
echo shar: Extracting \"'execve.c'\" \(4625 characters\)
sed "s/^X//" >'execve.c' <<'END_OF_FILE'
X
X/* 
X * Implmentation of execve for ms/Dos.
X * A segment aligned environment is constructed here and passed on.
X *
X * MKS and Aztec argument expansion (in the environment) are also performed here.
X *
X * $Log:	execve.c,v $
X * Revision 1.1  89/09/16  12:13:17  marty
X * Initial revision
X * 
X *  
X * $Id$
X */
X
X#include <errno.h>
X
X
X#define FAR_PTR(seg, off)       ((void far *) (((long) seg << 16L) + (long) off))
X
Xextern int use_mks_cmd;
Xextern int use_aztec_cmd;
X
Xstatic char far *next_env_string;	/* where to put next environment string */
X
X/* build mks args adds the MKS argument format (~arg) to the environment, startign a
X * next_env_string (which should be the start of the environment).
X */
Xstatic void build_mks_args(argv)
Xchar **argv;
X{
X	register char *cp;
X	
X	if(use_mks_cmd) 
X	    while(*argv) {
X		    *next_env_string++ = '~';
X		    cp = *argv++;
X		    /* copy whole string with NULL terminator */
X		    while(*next_env_string++ = *cp++)
X			    ;
X	    }
X		
X}	
X
X/* concatenate the arguments into the Aztec format (=arg0 arg1 arg2 ) */
Xstatic void build_aztec_args(argv)
Xchar **argv;
X{
X	register char *cp;
X	
X	if(use_aztec_cmd) {
X		*next_env_string++ = '=';	/* aztec starts its environment string with '=' */
X		
X		while(*argv) {
X		    	cp = *argv++;
X			while(*cp)
X				*next_env_string++ = *cp++;
X			*next_env_string++ = ' ';
X		}
X		*next_env_string++ = '\0';
X	}
X}
X
X/* If envp is non-NULL, copy this into the environment, otherwise just copy the default DOS
X * environment (obtained from the PSP)
X */
Xstatic void copy_environment(envp)
Xchar **envp;	/* environment */		  
X{
X	if(envp) {
X		char *cp;
X		
X		while(*envp) {
X			cp = *envp++;
X			while(*next_env_string++ = *cp++)
X				;
X		}
X	} else {
X		/* copy DOS environment from psp */
X		char far *psp_environ_start();
X		char far *dos_envp =  	psp_environ_start();
X		
X		while(*dos_envp) 
X			while(*next_env_string++ = *dos_envp++)
X				;
X	}
X	
X}
X		
X/* add up size of argc/argv, adding 2 characters to each length if
X * use_mks_cmd is true (i.e. each string is of form ~argument.
X */
Xstatic int compute_mks_arg_size(argv)
Xchar **argv;
X{
X	int count = 0;
X	
X	if(use_mks_cmd) {
X		while(*argv) 
X			count += strlen(*argv++) + 2;
X	}
X
X#ifdef PRINT_SIZES	
X	printf("MKS arg size = %d\n", count);
X#endif
X	return count;
X			
X}
X
X/* compute size of Aztec command line -- i.e. add 1 space to each argument, 1 for
X * the = and one for the NULL at the end
X */
Xstatic int compute_aztec_arg_size(argv)
Xregister char **argv;
X{
X	register int count = 0;
X	
X	if(use_aztec_cmd) {
X		while(*argv)
X			count += strlen(*argv++) + 1;
X		count++;	/* for = */
X	}
X
X#ifdef PRINT_SIZES	
X	printf("aztec size = %d\n", count);
X	
X#endif
X	return count;
X}
X
X/* compute size of DOS environment -- if environ is NULL use default environment */
Xstatic int compute_dos_environment_size(environ)
Xchar **environ;
X{
X	int count = 0;
X	
X	if(environ)  {
X		while(*environ) 
X			count += strlen(*environ++) + 1;
X	} else {
X		/* look at DOS environment */
X		extern char far *psp_environ_start();
X		char far *dos_envp = psp_environ_start();
X		
X		while(*dos_envp) {
X			do {
X				count++;
X			} while(*dos_envp++);
X		}
X	}
X	
X	return count;
X	
X	
X}
X
X
X
X/* all execs trap through hear to exec with an environment --
X * if envp is NULL, use default environment (via psp).
X * Otherwise dynmaically build environment from environ table.
X * Attach MKS and/or Aztec cmd lines as appropriate to the environment
X */
Xint execve(file, argv, envp)
Xchar *file;
Xchar **argv;
Xchar **envp;	/* pointer to environ table */ 
X{
X	extern unsigned _PSP;
X        unsigned environ_seg;	/* segment to use for environment */
X	/* need to set environment here and expand AZtec and MKS command strings, 
X	 * also set MKS file name
X	 */
X	
X	if(!envp && !use_aztec_cmd && !use_mks_cmd) 
X		environ_seg = peekw(0x2c, _PSP);	/* don't do anything -- just
X							 * use the incoming environment
X							 */
X	else {
X		/* need to construct environment */
X		unsigned environ_size;
X		int old_strategy;
X		
X		environ_size = compute_mks_arg_size(argv) + compute_aztec_arg_size(argv) +
X			       compute_dos_environment_size(envp) + 1;
X		
X		old_strategy = get_dos_malloc_strategy();
X		set_dos_malloc_strategy(2);		/* put environment at top of memory */
X		
X		environ_seg = malloc_dos_memory((environ_size >> 4) + 3);	/* round up in clicks */
X		set_dos_malloc_strategy(old_strategy);
X		
X		if(!environ_seg) {
X			errno = ENOMEM;
X			return -1;
X		}
X		
X		next_env_string = FAR_PTR(environ_seg, 0);
X		
X		build_mks_args(argv);
X		copy_environment(envp);
X		build_aztec_args(argv);
X
X		*next_env_string = '\0';	/* add NULL to signify end of environment */
X
X	}
X		
X	return setup_exec(file, argv, environ_seg);
X}
X
END_OF_FILE
if test 4625 -ne `wc -c <'execve.c'`; then
    echo shar: \"'execve.c'\" unpacked with wrong size!
fi
# end of 'execve.c'
fi
if test -f 'execvp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'execvp.c'\"
else
echo shar: Extracting \"'execvp.c'\" \(1868 characters\)
sed "s/^X//" >'execvp.c' <<'END_OF_FILE'
X
X
X/* implementation of execvp for ms/dos -- parses off PATH environment 
X * variable.
X * $Log:	execvp.c $
X * Revision 1.1  88/12/04  14:49:21  marty
X * Initialization
X * 
X */
X#define MAX_PATH		128
X
Xstatic  try_exec(name, argv)
Xchar *name;
Xchar **argv;
X{
X	char buffer[MAX_PATH];
X	register char *end;
X	char *last_slash, *last_dot;
X
X	strcpy(buffer, name);
X	end = buffer + strlen(buffer);
X
X	last_slash = rindex(buffer, '/');
X	last_dot   = rindex(buffer, '.');
X
X	if( (last_dot && !last_slash) || 	/* must be extension without path */
X	    (last_dot && last_slash && last_dot > last_slash)) {
X	    				/* must be extension at end of a path */
X		/* see if this is an exec file */
X		return execv(buffer, argv);
X	}
X
X	/* try to exec exe file */
X	strcpy(end, ".exe");
X	if(!access(buffer, 1))
X		return execv(buffer, argv);
X
X	/* .exe didn't work, not try com */
X	strcpy(end, ".com");
X	if(!access(buffer, 1))
X		return execv(buffer, argv);
X	return 	-1;	/* nothing to exec */
X
X}
X
X
Xexecvp(name, argv)
Xchar *name, **argv;
X{
X	char *path;
X	char path_buffer[MAX_PATH*4];
X	char buffer[MAX_PATH];
X	register char *cp;		/* component in path currently working on */
X	char *tmp;
X
X	/* is full path starting at root specified? */
X	if(!(path = getenv("PATH")) || *name == '/' || *name == '.' ) 
X		return try_exec(name, argv);
X
X
X	/* now try to chop up path */
X	strcpy(path_buffer, path);
X	path = &path_buffer;
X	while(*path) {
X		/* get next path entry */
X		cp = index(path, ';');
X		if(cp) {
X			*cp = '\0';		/* null terminate this component */
X			strcpy(&buffer, path);
X			path = cp + 1;		/* get past ';' */
X		}   else {
X			strcpy(&buffer, path);
X			*path = 0;
X		}
X
X		if(buffer[strlen(buffer)] != '/')
X			strcat(buffer, "/");
X		strcat(buffer, name);
X
X		cp = buffer + strlen(buffer);		/* cp points to end passed name */
X		if(!try_exec(buffer, argv))
X			return 0;
X	}
X	return -1;		/* file not found */
X}
END_OF_FILE
if test 1868 -ne `wc -c <'execvp.c'`; then
    echo shar: \"'execvp.c'\" unpacked with wrong size!
fi
# end of 'execvp.c'
fi
if test -f 'frkmagic.asm' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'frkmagic.asm'\"
else
echo shar: Extracting \"'frkmagic.asm'\" \(1799 characters\)
sed "s/^X//" >'frkmagic.asm' <<'END_OF_FILE'
X; $Log:	frkmagic.asm $
X; Revision 1.1  88/12/04  14:48:26  marty
X; Initialization
X; 
Xmod186
Xdataseg segment public para 'data'
X	extrn _PSP_:word
X	extrn we_have_forked_:word
Xdataseg ends
X	extrn setpid_:near
X	include lmacros.h
X
X; define a far return
Xretf	macro
X	db	0cbH
X	endm
X	
Xold_ss		dw	?	; old stack segment
Xold_sp		dw 	?	; old stack pointer
Xold_ds		dw 	?	; parents data segment
Xold_es		dw	?	; parents stack segment
Xold_bp		dw 	?	; parent's bp
Xtarget_jmp	dw	?	; target jmp address
X		dw	?
X
X; forkmagic(child_pid, new_cs, new_ds) sets up childs return 
X; address in the PSP at the appropriate
X; point in frkmagic (to return 	to the parent with the child parent
X; process id.
X; Will execute a far jmp into the new program after pushing the
X; current return address onto the stack
X; needs to ES, DS and SS in code segment before jumping to child
X	procdef forkmagic,<<child_pid,word>,<new_cs,word>,<new_ds,word>>
X	; save parents segment registers
X	mov	cs:old_ss,ss
X	mov	cs:old_ds,ds
X	mov	cs:old_es,es
X	mov	cs:old_sp,sp
X	mov	cs:old_bp,bp
X	
X	; change process ids
X	mov	ax,child_pid
X	push	ax
X	call	setpid_
X	pop	ax
X	
X	; leave return address in bx (so child can jmp [bx])
X	mov	bx,[bp+2]
X	
X	mov	ax,new_cs
X	mov	target_jmp+2,ax
X	mov	ax,offset child_returns
X	mov	target_jmp,ax
X	
X	mov	ds,new_ds
X	pop	bp		; bp is already saved
X	mov	ax,ds
X	mov	ss,ax
X	mov	es,ax
X	jmp	dword	ptr 	[target_jmp]	
X		
Xchild_returns:
X	mov	ds:we_have_forked_,1		; indicate fork occurred
X	mov	ax,0
X	jmp	bx
X	
X	public	parent_returns_	
Xparent_returns_:
X	; return from child --restore segment registers
X	mov	ss,cs:old_ss
X	mov	sp,cs:old_sp
X	mov	es,cs:old_es
X	mov	ds,cs:old_ds
X	mov	bp,cs:old_bp
X	
X	; change id back to child
X	mov	ax,ds:_PSP_
X	push	ax
X	call	setpid_
X	pop	ax
X	
X	mov	ax,child_pid	; return childs id
X	pret
X
X	
X	pend	forkmagic
X	finish
X	end
END_OF_FILE
if test 1799 -ne `wc -c <'frkmagic.asm'`; then
    echo shar: \"'frkmagic.asm'\" unpacked with wrong size!
fi
# end of 'frkmagic.asm'
fi
if test -f 'fork.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'fork.c'\"
else
echo shar: Extracting \"'fork.c'\" \(4967 characters\)
sed "s/^X//" >'fork.c' <<'END_OF_FILE'
X
X/* An implementation of fork for ms/dos
X *
X * $Log:	fork.c,v $
X * Revision 1.4  89/12/06  07:36:27  marty
X * played with memory allocation strategy
X * 
X * Revision 1.3  89/09/22  16:59:12  marty
X * Various modifications.
X * 
X * Revision 1.2  89/02/11  01:04:55  marty
X * Took out fprintfs diagnostics
X * 
X * Revision 1.1  88/12/04  14:49:26  marty
X * Initialization
X * 
X */
X
X#include <stdio.h>
X#include <regs.h>
X
X
X#define FAR_PTR(seg, off)       ((void far *) (((long) seg << 16L) + (long) off))
Xextern char **environ;
X
X
Xextern unsigned _PSP, _dsval, _csval;
Xextern far *psp_environ_start();
X
X/* copy the environment from src to dest, removing any special strings
X * along the way.
X * Null environment strings (begin with '=') are for aztec C.
X * Strings of form _= and ~= are for MKS shell
X */
Xcopy_environment(src, dest)
Xchar far *src, *dest;
X{
X	/* copy till end of environment */
X	while(*src) {
X		switch(*src) {
X			case '_':
X			case '~':
X			case '=':
X				/* don't copy -- just reach end of string */
X				while(*src++)
X					;
X				break;
X			default:
X				/* copy string */
X				while(*dest++ = *src++)
X					;
X				break;
X		}
X	}
X	*dest = 0;	/* second null to mark end of environment */
X}
X
Xstatic unsigned get_environment_size(penv)
Xregister char far *penv;
X{
X	register unsigned num_bytes = 0;
X
X	while(*penv) {
X		while(*penv++)
X			num_bytes++;
X		num_bytes++;	/* null terminator is one byte */
X	}
X	return num_bytes;
X}
X
X
X	
X/* setup_environment() copies the current environment into a block of memory, removing
X * the '=' variable if present to avoid confusion between the parent and child.
X * Returns 0 for error, otherwise click environment is at
X */
Xstatic int setup_environment()
X{
X	char far * old_environ;		/* environment address in clicks */
X	char far * new_environ;		/* dos block for where to put environment --
X						 * owned by parent process?
X						 */ 
X	unsigned sizeof_environment;		/* size in bytes	         */
X	register char *cp;
X	int seg;
X	int old_strategy;
X       
X	/* determine orignal environment address */
X	
X	old_environ = psp_environ_start();
X	
X	sizeof_environment = get_environment_size(old_environ);
X	
X	old_strategy = get_dos_malloc_strategy();
X	set_dos_malloc_strategy(2);  /* put environment on top of memory */
X	seg = malloc_dos_memory(sizeof_environment/16 + 4);
X	
X	set_dos_malloc_strategy(old_strategy);
X       
X	if(!seg)
X		return 0;
X	new_environ = FAR_PTR(seg, 0);
X
X	copy_environment(old_environ, new_environ);
X
X	return seg;
X	
X
X}
X
X
Xsetpid(process_id)
Xint process_id;
X{
X	REGS regs;
X	
X	regs.AX = 0x5000;
X	regs.BX = process_id;
X	if(dos_interrupt(&regs)) {
X		return -1;
X	}
X	else return 0;
X	
X}
X
Xstatic int make_child_psp(num_clicks)
Xunsigned num_clicks;
X{
X	REGS regs;
X	
X	regs.AX = 0x5500;
X	regs.DX = num_clicks;
X	if(dos_interrupt(&regs)) {
X		return -1;
X		
X	}
X	else {
X		/* set up block so it belongs to this process */
X		pokew(0x1, num_clicks - 1, num_clicks);
X		return 0;
X	}
X}
X
X
X/* fork for MS/DOS --
X * Returns 0 to child,
X * Returns segment of childs psp to parent or -1 if it fails
X */
Xfork()
X{
X	
X	int prog_size_clicks;
X	unsigned new_csval;
X	unsigned new_dsval;
X	extern unsigned _mtop, _Cend;
X	unsigned child_memory_block;	/* first block alloced from dos */
X	unsigned second_memory_block;   /* should be equal to child_memory_block */
X	unsigned parent_pid;
X	extern void parent_returns();
X	unsigned new_environ_click;
X
X	/* check to see if we want to copy psps environment.	*/
X	new_environ_click = setup_environment();	/* make a copy of the environment */
X
X
X	/* allocate enough space for current programs  code, data segment, stack and
X	 * psp
X	 */
X	 parent_pid = getpid();
X	 
X	 prog_size_clicks = 0x10;	/* for psp */
X#ifdef COPYCODE
X	 prog_size_clicks += ((unsigned) &_Cend/16) + 1;
X#endif
X	 prog_size_clicks += (_mtop/16) + 1;
X	 if(!(child_memory_block = malloc_dos_memory(prog_size_clicks))) {
X		return -1;
X	 }
X	  make_child_psp(child_memory_block);
X
X	  /* copy code and data (stack/bss/data) segments to child */
X#ifdef COPYCODE
X	  new_csval =  child_memory_block + 0x10;
X	  new_dsval = new_csval + (_dsval - _csval);
X#else
X	  new_csval = _csval;
X	  new_dsval = child_memory_block + 0x10;
X#endif
X	  
X
X#ifdef COPYCODE	
X	  movblock(0, _csval, 0, new_csval, &_Cend);
X#endif
X	  movblock(0, _dsval, 0, new_dsval, _mtop);
X	  
X	  /* patch child's _PSP, _csval, _dsval	*/
X	  pokew(&_dsval, new_dsval, new_dsval);
X	  pokew(&_csval, new_dsval, new_csval);
X	  pokew(&_PSP,	 new_dsval, child_memory_block);
X	  
X	  
X	  /* set up terminate address of child to cs:parent_returns */
X	  pokew(0xa, child_memory_block, &parent_returns);
X	  pokew(0xc, child_memory_block, _csval);
X	  if(new_environ_click) { 
X		/* change ownership of environment block  to child */
X		pokew(0x1, new_environ_click - 1, child_memory_block);	
X		pokew(0x2c, child_memory_block, new_environ_click);
X	  }
X	  /* does magic to set up fork -- returns child process id or
X	   * 0, depending on context.
X	    */
X	  return forkmagic(child_memory_block, new_csval, new_dsval);		
X		
X	
X	 
X}
X
X		
END_OF_FILE
if test 4967 -ne `wc -c <'fork.c'`; then
    echo shar: \"'fork.c'\" unpacked with wrong size!
fi
# end of 'fork.c'
fi
echo shar: End of shell archive.
exit 0

--
marty
leisner@eso.mc.xerox.com leisner.henr801c@xerox.com 
Member of the League for Programming Freedom
"I just know I'm a better manager when I have Joe DiMaggio in center field" -- Casey Stengel
Technical Details
Message-ID: <1993Nov11.142206.19348@spectrum.xerox.com>
Path: arc1-ca.pugleaf.net!gmd.de!newsserver.jvnc.net!yale.edu!spool.mu.edu!howland.reston.ans.net!noc.near.net!das-news.harvard.edu!honeydew.srv.cs.cmu.edu!rochester!rocksanne!draco!leisner
References: <munk.752354944@prles6b>

Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: 11318c,95c41416cafe7368
X-Google-Attributes: gid11318c,public
X-Google-ArrivalTime: 1993-11-11 17:35:36 PST
Newsgroups: gnu.gcc.help
Path: arc1-ca.pugleaf.net!gmd.de!newsserver.jvnc.net!yale.edu!spool.mu.edu!howland.reston.ans.net!noc.near.net!das-news.harvard.edu!honeydew.srv.cs.cmu.edu!rochester!rocksanne!draco!leisner
From: leisner@draco (Marty Leisner 25733)
Subject: Re: gcc equivalent of spawn (MSDOS)
Message-ID: <1993Nov11.142206.19348@spectrum.xerox.com>
Sender: news@spectrum.xerox.com
Reply-To: leisner@eso.mc.xerox.com
Organization: Xerox
X-Newsreader: TIN [version 1.2 PL2]
References: <munk.752354944@prles6b>
Date: Thu, 11 Nov 1993 14:22:06 GMT
Lines: 843