[comp.os.msdos.apps] MSDOS Patch: more patches

aas@brolga.cc.uq.oz.au (Alex Sergejew) (07/15/90)

The following are comments and patches to the patches to Larry Wall's patch
program (patchlevel 12) recently submitted by ward@sneezy.cs.wisc.edu
(Michael Ward) to allow compilation with Turbo C 2.0 and to run under MSDOS.

I have addressed a couple of recent bug reports and also re-enabled the
use of ed scripts (given a working MSDOS ed program, of which simtel20
has several that are compatible with unix V7 ed).

New files are:
popen    c      10579   7-15-90   3:58p
popen    h         69   3-08-88   8:08p
getswitc c        290   3-08-88   8:08p
popentst mak      303   7-15-90   3:43p

These provide the popen() functionality and were snarfed from simtel20
in `pd1:<msdos.turbo-c>popen.arc'.  The original author's name is not given.
Try `make -fpopentst' to check-out the DEMO mode (see popen.c) but
remember to delete popen.obj and getswitc.obj from this trial before
compiling the merged/patched version of patch.

Alex A Sergejew
University of Queensland Neuro-Psychiatric Institute
aas@cc.uq.oz.au

---------------------------
weisen@eniac.seas.upenn.edu (Neil Weisenfeld) reports getting a run-time
error of the form:
	patch: couldn't create D:\/patchpxxxxxx

This is due to having the TMP environment variable set to "D:\"
(note that a lot of MSDOS software actually wants the trailing "\").
Patch as distributed blindly concatenates /patch?xxxxxx strings and the
"\/" juxtaposition causes strife to MSDOS.  The problem does not arise using
other shells such as ms_sh or ksh. A temporary workaround is to re-set the
TMP environment variable without the trailing "\".

This has been repaired in the appended patches.

---------------------------
mlord@bwdls58.UUCP correctly observes that:
>>In file INP.C, there is a procedure called rev_in_string() at the bottom.

>>This procedure declares a local variable "s", which is then used without
>>first being given a value.  This instance of "s" should be replaced with
>>the parameter "string" instead on that one line.

This has also been repaired in the appended patches.

---------------------------
There are still warnings reported by Turbo C in compiling the distribution:

In pch.c:
243: Possible use of 'fcntl_line' before definition ...
the variable concerned is not in fact used before definition and the warning
can be safely ignored.

In popen.c there appear 3 warnings of the type:
xxx: 'lineno' is assigned a value which is never used in function ...
which can also be ignored (the variable is used in DEMO mode).

In util.c:
177: possibly incorrect assignment ....
the message is misleading (see the Turbo C User Manual).

---------------------------
*** makefile	Sat Jun 02 16:13:34 1990
--- makefile.new	Sun Jul 15 15:59:34 1990
***************
*** 1,8 ****
  CC = tcc
  CFLAGS = -N -ml -DTURBOC20
  
! c = patch.c pch.c inp.c version.c util.c
! obj = patch.obj pch.obj inp.obj util.obj version.obj
  
  .c.obj:
  	$(CC) -c $(CFLAGS) $(LARGE) $*.c
--- 1,8 ----
  CC = tcc
  CFLAGS = -N -ml -DTURBOC20
  
! c = patch.c pch.c inp.c version.c util.c popen.c getswitc.c
! obj = patch.obj pch.obj inp.obj version.obj util.obj popen.obj getswitc.obj
  
  .c.obj:
  	$(CC) -c $(CFLAGS) $(LARGE) $*.c
***************
*** 12,18 ****
  
  patch.obj: config.h common.h patch.c inp.h pch.h util.h version.h
  
! pch.obj: config.h common.h pch.c pch.h util.h
  
  inp.obj: config.h common.h inp.c inp.h util.h
  
--- 12,18 ----
  
  patch.obj: config.h common.h patch.c inp.h pch.h util.h version.h
  
! pch.obj: config.h common.h pch.c pch.h util.h popen.h
  
  inp.obj: config.h common.h inp.c inp.h util.h
  
***************
*** 19,21 ****
--- 19,25 ----
  util.obj: config.h common.h util.c util.h
  
  version.obj: config.h common.h version.c version.h patchlevel.h util.h
+ 
+ popen.obj: popen.c popen.h
+ 
+ getswitc.obj: getswitc.c
*** inp.c	Sun Jul 15 12:41:14 1990
--- inp.new	Sun Jul 15 13:50:30 1990
***************
*** 1,6 ****
! /* $Header: inp.c,v 2.0.1.2 90/05/30 11:30:00 mward $
   *
   * $Log:	inp.c,v $
   * Revision 2.0.1.2  90/05/30  11:30:00 mward
   * if TURBOC20 have plan_a check against MAXMEMBLK before mallocs
   * if TURBOC20 have plan_b use binary mode io for tmp file
--- 1,10 ----
! /* $Header: inp.c,v 2.0.1.3 90/07/15 13:52:00 aas $
   *
   * $Log:	inp.c,v $
+  * Revision 2.0.1.3  90/07/15  13:52:00 aas
+  * include bugfix reported by mlord@bwdls58.bnr.ca in rev_in_string()
+  * regarding parameter string[] typo in first strnEQ() line
+  *
   * Revision 2.0.1.2  90/05/30  11:30:00 mward
   * if TURBOC20 have plan_a check against MAXMEMBLK before mallocs
   * if TURBOC20 have plan_b use binary mode io for tmp file
***************
*** 323,329 ****
      if (revision == Nullch)
  	return TRUE;
      patlen = strlen(revision);
!     if (strnEQ(string,revision,patlen) && isspace(s[patlen]))
  	return TRUE;
      for (s = string; *s; s++) {
  	if (isspace(*s) && strnEQ(s+1, revision, patlen) && 
--- 327,333 ----
      if (revision == Nullch)
  	return TRUE;
      patlen = strlen(revision);
!     if (strnEQ(string,revision,patlen) && isspace(string[patlen]))
  	return TRUE;
      for (s = string; *s; s++) {
  	if (isspace(*s) && strnEQ(s+1, revision, patlen) && 
*** patch.c	Sun Jul 15 12:46:42 1990
--- patch.new	Sun Jul 15 14:02:18 1990
***************
*** 1,5 ****
  char rcsid[] =
! 	"$Header: patch.c,v 2.0.1.7 90/05/30 11:30:00 mward $";
  
  /* patch - a program to apply diffs to original files
   *
--- 1,5 ----
  char rcsid[] =
! 	"$Header: patch.c,v 2.0.1.8 90/07/15 14:00:00 aas $";
  
  /* patch - a program to apply diffs to original files
   *
***************
*** 9,14 ****
--- 9,17 ----
   * money off of it, or pretend that you wrote it.
   *
   * $Log:	patch.c,v $
+  * Revision 2.0.1.7  90/07/15  14:00:00  aas
+  * made init temp file names a little more MS-DOS aware
+  *
   * Revision 2.0.1.7  90/05/30  11:30:00  mward
   * Added usage message vars and routines: use_msg, progname, usage, fname
   * Check environment for TMP and init temp file names
***************
*** 206,212 ****
      int i;
      char tmpdir[MAXPATH];
      char *tmpenv;
! 
  
      progname = (*argv[0]?argv[0]:"patch");
      setbuf(stderr, serrbuf);
--- 209,215 ----
      int i;
      char tmpdir[MAXPATH];
      char *tmpenv;
!     char c;
  
      progname = (*argv[0]?argv[0]:"patch");
      setbuf(stderr, serrbuf);
***************
*** 216,222 ****
      /* initialize temp file names */
      tmpenv = getenv("TMP");
      strcpy(tmpdir,(tmpenv!=NULL?tmpenv:""));
!     if (strlen(tmpdir) && tmpdir[strlen(tmpdir)-1]!='/') strcat(tmpdir,"/");
      TMPOUTNAME = strcat(strcpy(malloc(MAXPATH),tmpdir),fname(TMPOUTNAME));
      TMPINNAME  = strcat(strcpy(malloc(MAXPATH),tmpdir),fname(TMPINNAME));
      TMPREJNAME = strcat(strcpy(malloc(MAXPATH),tmpdir),fname(TMPREJNAME));
--- 219,227 ----
      /* initialize temp file names */
      tmpenv = getenv("TMP");
      strcpy(tmpdir,(tmpenv!=NULL?tmpenv:""));
!     if (strlen(tmpdir))
! 	if((c=tmpdir[strlen(tmpdir)-1])!='/' && c!='\\')
! 	    strcat(tmpdir,"/");
      TMPOUTNAME = strcat(strcpy(malloc(MAXPATH),tmpdir),fname(TMPOUTNAME));
      TMPINNAME  = strcat(strcpy(malloc(MAXPATH),tmpdir),fname(TMPINNAME));
      TMPREJNAME = strcat(strcpy(malloc(MAXPATH),tmpdir),fname(TMPREJNAME));
*** pch.c	Sun Jul 15 12:41:50 1990
--- pch.new	Sun Jul 15 15:23:00 1990
***************
*** 1,6 ****
! /* $Header: pch.c,v 2.0.1.7 90/05/30 11:30:00 mward $
   *
   * $Log:	pch.c,v $
   * Revision 2.0.1.8  90/05/30  11:30:00  mward
   * replace do_ed_script with stub
   * modify calls to read, write to detect error on return value of -1
--- 1,9 ----
! /* $Header: pch.c,v 2.0.1.9 90/07/15 15:27:00 aas $
   *
   * $Log:	pch.c,v $
+  * Revision 2.0.1.9  90/07/15  15:27:00  aas
+  * put do_ed_script() back the way it was and slot-in MSDOS popen/pclose
+  *
   * Revision 2.0.1.8  90/05/30  11:30:00  mward
   * replace do_ed_script with stub
   * modify calls to read, write to detect error on return value of -1
***************
*** 38,43 ****
--- 41,49 ----
  #include "util.h"
  #include "INTERN.h"
  #include "pch.h"
+ #ifdef TURBOC20
+ #include "popen.h"
+ #endif
  
  /* Patch (diff listing) abstract type. */
  
***************
*** 1062,1077 ****
      return p_hunk_beg;
  }
  
- #ifdef TURBOC20 
- /* Ignore an ed script. */
- 
- void
- do_ed_script()
- {
-     say1("Sorry, can't do ed scripts yet!\n");
-     say1("Use ed to do this one yourself!\n");
- }
- #else
  /* Apply an ed script by feeding ed itself. */
  
  void
--- 1068,1073 ----
***************
*** 1086,1095 ****
--- 1082,1095 ----
      if (!skip_rest_of_patch) {
  	Unlink(TMPOUTNAME);
  	copy_file(filearg[0], TMPOUTNAME);
+ #ifdef TURBOC20
+ 	Sprintf(buf, "ed %s", TMPOUTNAME);
+ #else
  	if (verbose)
  	    Sprintf(buf, "/bin/ed %s", TMPOUTNAME);
  	else
  	    Sprintf(buf, "/bin/ed - %s", TMPOUTNAME);
+ #endif
  	pipefp = popen(buf, "w");
      }
      for (;;) {
***************
*** 1135,1138 ****
  	chmod(outname, filemode);
      set_signals(1);
  }
! #endif
--- 1135,1138 ----
  	chmod(outname, filemode);
      set_signals(1);
  }
! 
*** /dev/null
--- popen.h	Tue Mar 08 20:08:36 1988
***************
*** 0 ****
--- 1,2 ----
+ extern FILE *popen( char *, char * );
+ extern int pclose( FILE * );
*** /dev/null
--- popen.c	Sun Jul 15 15:58:08 1990
***************
*** 0 ****
--- 1,339 ----
+ /* popen/pclose:
+  *
+  * simple MS-DOS piping scheme to imitate UNIX pipes
+  *
+  * $Log:	popen.c,v $
+  * Revision 1.0.1  90/07/15  14:05:00  aas
+  * fix assumption of trailing "/" in popen()
+  *
+  * Revision 1.0.0  88/08/03  20:08:00  ???
+  * original distribution: author unknown
+  * found on simtel20 as pd1:<msdos.turbo-c>popen.arc
+  *
+  */
+ 
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <alloc.h>
+ #include <string.h>
+ #include <errno.h>
+ #include <setjmp.h>
+ #include <process.h>
+ 
+ #include "popen.h"
+ 
+ extern char *getenv( char * );
+ 
+ #ifndef	_NFILE
+ # define	_NFILE	OPEN_MAX	/* Number of open files */
+ #endif	_NFILE
+ 
+ #define READIT	1			/* Read pipe */
+ #define WRITEIT	2			/* Write pipe */
+ 
+ static char *prgname[ _NFILE ];		/* program name if write pipe */
+ static int pipetype[ _NFILE ];		/* 1=read 2=write */
+ static char *pipename[ _NFILE ];	/* pipe file name */
+ 
+ /*
+  *------------------------------------------------------------------------
+  * stoupper: Convert string to uppercase (in place)
+  *------------------------------------------------------------------------
+  */
+ 
+ static void
+ stoupper( s )
+ char *s;
+ {
+    int c;
+    for( ; (c = *s) != '\0'; ++s ) {
+       if( islower( c ) ) *s = _toupper( c );
+    }
+ }
+ 
+ /*
+  *------------------------------------------------------------------------
+  * strsave: Copy string into malloc'ed memory and return address
+  *------------------------------------------------------------------------
+  */
+  
+ static char *
+ strsave( s )
+ char *s;
+ {
+    char *sp = malloc( strlen( s ) + 1 );
+    if( sp != (char *) NULL ) (void) strcpy( sp, s );
+    return( sp );
+ }
+ 
+ /*
+  *------------------------------------------------------------------------
+  * strfree: Returm strsave'd string memory
+  *------------------------------------------------------------------------
+  */
+ 
+ static void
+ strfree( s )
+ char *s;
+ {
+    if( s != (char *) NULL ) free( s );
+ }
+ 
+ /*
+  *------------------------------------------------------------------------
+  * run: Execute command via SHELL or COMSPEC
+  *------------------------------------------------------------------------
+  */
+ 
+ static int
+ run( command )
+ char *command;
+ {
+    jmp_buf panic;			/* How to recover from errors */
+    int lineno;				/* Line number where panic happened */
+    char *shell;				/* Command processor */
+    char *s = (char *) NULL;		/* Holds the command */
+    int s_is_malloced = 0;		/* True if need to free 's' */
+    static char *command_com = "COMMAND.COM";
+    int status;				/* Return codes */
+    char *shellpath;			/* Full command processor path */
+    char *bp;				/* Generic string pointer */
+    static char dash_c[ 3 ] = { '?', 'c', '\0' };
+    if( (lineno = setjmp( panic )) != 0 ) {
+       int E = errno;
+ #ifdef	DEMO
+       fprintf( stderr, "RUN panic on line %d: %d\n", lineno, E );
+ #endif	DEMO
+       if( s_is_malloced && (s != (char *) NULL) ) strfree( s );
+       errno = E;
+       return( -1 );
+    }
+    if( (s = strsave( command )) == (char *) NULL ) longjmp( panic, __LINE__ );
+    /* Determine the command processor */
+    if( ((shell = getenv( "SHELL" )) == (char *) NULL) &&
+        ((shell = getenv( "COMSPEC" )) == (char *) NULL) ) shell = command_com;
+    stoupper( shell );
+    shellpath = shell;
+    /* Strip off any leading backslash directories */
+    shell = strrchr( shellpath, '\\' );
+    if( shell != (char *) NULL ) ++shell;
+    else                         shell = shellpath;
+    /* Strip off any leading slash directories */
+    bp = strrchr( shell, '/'  );
+    if( bp != (char *) NULL ) shell = ++bp;
+    if( strcmp( shell, command_com ) != 0 ) {
+       /* MKS Shell needs quoted argument */
+       char *bp;
+       if( (bp = s = malloc( strlen( command ) + 3 )) == (char *) NULL ) 
+ 	 longjmp( panic, __LINE__ );
+       *bp++ = '\'';
+       while( (*bp++ = *command++) != '\0' );
+       *(bp - 1) = '\'';
+       *bp = '\0';
+       s_is_malloced = 1;
+    } else s = command;
+    dash_c[ 0 ] = getswitch();
+    /* Run the program */
+ #ifdef	DEMO
+    fprintf( stderr, "Running: (%s) %s %s %s\n", shellpath, shell, dash_c, s );
+ #endif	DEMO
+    status = spawnl( P_WAIT, shellpath, shell, dash_c, s, (char *) NULL );
+    if( s_is_malloced ) free( s );
+    return( status );
+ }
+ 
+ /* 
+  *------------------------------------------------------------------------
+  * uniquepipe: returns a unique file name 
+  *------------------------------------------------------------------------
+  */
+ 
+ static char *
+ uniquepipe()
+ { 
+    static char name[ 14 ];
+    static short int num = 0;
+    (void) sprintf( name, "pipe%05d.tmp", num++ );
+    return( name );
+ }
+ 
+ /*
+  *------------------------------------------------------------------------
+  * resetpipe: Private routine to cancel a pipe
+  *------------------------------------------------------------------------
+  */
+ 
+ static void
+ resetpipe( fd )
+ int fd;
+ {
+    char *bp;
+    if( (fd >= 0) && (fd < _NFILE) ) {
+       pipetype[ fd ] = 0;
+       if( (bp = pipename[ fd ]) != (char *) NULL ) {
+ 	 (void) unlink( bp );
+ 	 strfree( bp );
+ 	 pipename[ fd ] = (char *) NULL;
+       }
+       if( (bp = prgname[ fd ]) != (char *) NULL ) {
+ 	 strfree( bp );
+ 	 prgname[ fd ] = (char *) NULL;
+       }
+    }
+ }
+ 
+ /* 
+  *------------------------------------------------------------------------
+  * popen: open a pipe 
+  *------------------------------------------------------------------------
+  */
+ 
+ FILE *popen( prg, type )
+ char *prg;			/* The command to be run */
+ char *type;			/* "w" or "r" */
+ { 
+    FILE *p = (FILE *) NULL;	/* Where we open the pipe */
+    int ostdin;			/* Where our stdin is now */
+    int pipefd = -1;		/* fileno( p ) -- for convenience */
+    char tmpfile[ BUFSIZ ];	/* Holds name of pipe file */
+    char *tmpdir;		/* Points to directory prefix of pipe */
+    jmp_buf panic;		/* Where to go if there's an error */
+    int lineno;			/* Line number where panic happened */
+    char c;							/* aas */
+    /* Find out where we should put temporary files */
+    if( (tmpdir = getenv( "TMPDIR" )) == (char *) NULL ) 
+       tmpdir = getenv( "TMP" );
+    if( tmpdir != (char *) NULL ) {
+       /* Use temporary directory if available */
+       (void) strcpy( tmpfile, tmpdir );
+       if((c=tmpfile[strlen(tmpfile)-1])!='/' && c!='\\')	/* aas */
+ 	 (void) strcat( tmpfile, "/" );
+    } else *tmpfile = '\0';
+    /* Get a unique pipe file name */
+    (void) strcat( tmpfile, uniquepipe() );
+    if( (lineno = setjmp( panic )) != 0 ) {
+       /* An error has occurred, so clean up */
+       int E = errno;
+ #ifdef	DEMO
+       fprintf( stderr, "POPEN panic on line %d: %d\n", lineno, E );
+ #endif	DEMO
+       if( p != (FILE *) NULL ) (void) fclose( p );
+       resetpipe( pipefd );
+       errno = E;
+       return( (FILE *) NULL );
+    }
+    if( strcmp( type, "w" ) == 0 ) {
+       /* for write style pipe, pclose handles program execution */
+       if( (p = fopen( tmpfile, "w" )) != (FILE *) NULL ) {
+ 	 pipefd = fileno( p );
+ 	 pipetype[ pipefd ] = WRITEIT;
+ 	 pipename[ pipefd ] = strsave( tmpfile );
+ 	 prgname[ pipefd ]  = strsave( prg );
+ 	 if( !pipename[ pipefd ] || !prgname[ pipefd ] ) longjmp( panic, __LINE__ );
+       }
+    } else if( strcmp( type, "r" ) == 0 ) {
+       /* read pipe must create tmp file, set up stdout to point to the temp
+       * file, and run the program.  note that if the pipe file cannot be
+       * opened, it'll return a condition indicating pipe failure, which is
+       * fine.
+       */
+       if( (p = fopen( tmpfile, "w" )) != (FILE *) NULL ) {
+ 	 int ostdout;
+ 	 pipefd = fileno( p );
+ 	 pipetype[ pipefd ]= READIT;
+ 	 if( (pipename[ pipefd ] = strsave( tmpfile )) == (char *) NULL ) 
+ 	    longjmp( panic, __LINE__ );
+ 	 /* Redirect stdin for the new command */
+ 	 ostdout = dup( fileno( stdout ) );
+ 	 if( dup2( fileno( stdout ), pipefd ) < 0 ) {
+ 	    int E = errno;
+ 	    (void) dup2( fileno( stdout ), ostdout );
+ 	    errno = E;
+ 	    longjmp( panic, __LINE__ );
+ 	 }
+ 	 if( run( prg ) != 0 ) longjmp( panic, __LINE__ );
+ 	 if( dup2( fileno( stdout ), ostdout ) < 0 ) longjmp( panic, __LINE__ );
+ 	 if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
+ 	 if( (p = fopen( tmpfile, "r" )) == (FILE *) NULL ) longjmp( panic, __LINE__ );
+       }
+    } else {
+       /* screwy call or unsupported type */
+       errno = EINVFNC;
+       longjmp( panic, __LINE__ );
+    }
+    return( p );
+ }
+ 
+ /* close a pipe */
+ 
+ int
+ pclose( p )
+ FILE *p;
+ {
+    int pipefd = -1;		/* Fildes where pipe is opened */
+    int ostdout;			/* Where our stdout points now */
+    int ostdin;			/* Where our stdin points now */
+    jmp_buf panic;		/* Context to return to if error */
+    int lineno;			/* Line number where panic happened */
+    if( (lineno = setjmp( panic )) != 0 ) {
+       /* An error has occurred, so clean up and return */
+       int E = errno;
+ #ifdef	DEMO
+       fprintf( stderr, "POPEN panic on line %d: %d\n", lineno, E );
+ #endif	DEMO
+       if( p != (FILE *) NULL ) (void) fclose( p );
+       resetpipe( pipefd );
+       errno = E;
+       return( -1 );
+    }
+    pipefd = fileno( p );
+    if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
+    switch( pipetype[ pipefd ] ) {
+       case WRITEIT:
+ 	 /* open the temp file again as read, redirect stdin from that
+ 	  * file, run the program, then clean up.
+ 	  */
+       if( (p = fopen( pipename[ pipefd ],"r" )) == (FILE *) NULL ) 
+ 	 longjmp( panic, __LINE__ );
+       ostdin = dup( fileno( stdin ));
+       if( dup2( fileno( stdin ), fileno( p ) ) < 0 ) longjmp( panic, __LINE__ );
+       if( run( prgname[ pipefd ] ) != 0 ) longjmp( panic, __LINE__ );
+       if( dup2( fileno( stdin ), ostdin ) < 0 ) longjmp( panic, __LINE__ );
+       if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
+       resetpipe( pipefd );
+       break;
+    case READIT:
+       /* close the temp file and remove it */
+       resetpipe( pipefd );
+       break;
+    default:
+       errno = EINVFNC;
+       longjmp( panic, __LINE__ );
+       /*NOTREACHED*/
+    }
+    return( 0 );
+ }
+ 
+ #ifdef	DEMO
+ int
+ main( argc, argv )
+ int argc;
+ char **argv;
+ {
+    FILE *pipe;
+    char buf[ BUFSIZ ];
+    int n;
+    *buf = '\0';
+    for( n = 1; n < argc; ++n ) {
+       (void) strcat( buf, argv[ n ] );
+       (void) strcat( buf, " " );
+    }
+    if( (pipe = popen( buf, "r" )) != (FILE *) NULL ) {
+       while( fgets( buf, sizeof( buf ), pipe ) != (char *) NULL ) 
+ 	 (void) fputs( buf, stdout );
+       if( pclose( pipe ) != 0 ) fprintf( stderr, "error closing pipe!\n" );
+    } else fprintf( stderr, "it didn't work!\n" );
+    exit( 0 );
+    /*NOTREACHED*/
+ }
+ #endif	DEMO
*** /dev/null
--- getswitc.c	Tue Mar 08 20:08:04 1988
***************
*** 0 ****
--- 1,16 ----
+ #include <stdio.h>
+ #include <dos.h>
+  
+ static	char	SW = 0;		/* DOS switch character, either '-' or '/' */
+ 
+ int
+ getswitch()
+ {
+    if (SW == 0) {
+       /* get SW using dos call 0x37 */
+       _AX = 0x3700;
+       geninterrupt(0x21);
+       SW = _DL;
+    }
+    return( SW & 0xFF );
+ }
*** /dev/null
--- popentst.mak	Sun Jul 15 15:43:08 1990
***************
*** 0 ****
--- 1,18 ----
+ popen.exe: popen.obj getswitch.obj
+ 	tcc -epopen popen.obj getswitch.obj
+ 
+ popen.obj: popen.c popen.h
+ 	tcc -c -DDEMO popen.c
+ 
+ getswitch.obj: getswitch.c
+ 	tcc -c getswitch.c
+ 
+ clean:
+ 	rm -f *.obj core *.map
+ 
+ clobber: clean
+ 	rm -f *.exe install
+ 	
+ install:
+ 	tcc -c popen.c
+ 	@echo What next?