www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1993/04/26/06:25:34

Date: Mon, 26 Apr 93 12:10:34 +0200
From: Divisione SINCON <sincon AT minsky DOT csata DOT it>
Subject: djgroff7
Apparently-To: djgpp AT sun DOT soe DOT clarkson DOT edu

Hi,
   Thanks for the interest.
I have been out of town for the job and i found  the following.
>From: DJ Delorie <dj AT ctron DOT com>
>To: sincon AT minsky DOT csata DOT it
>Subject: Re: groff-1.07
>
>(1) For future reference, please don't use "dj" in file names for
>stuff I didn't write.  You should use "mc" instead, since you wrote
>it.
first of all i should spend a word apologizing about the name i picked,
it seems i (unwillingly) stepped out of line.
It was supposed to mean "groff-1.07 ported to DJ's go32"
You can rename it at will i'm not sure of how to do that on omnigate.
>
>(2) What is it about your go32 that is different from 1.09?  How can
>the official one be improved to support your stuff as well?
The diffs -c3 where in my previous post about groff-1.06, they didn't change.
I am reposting them without uuencoding at the end of this message.
>
>DJ

>From: DJ Delorie <dj AT ctron DOT com>
>Subject: file naming conventions
>
>PLEASE PLEASE PLEASE Don't use "dj" as part of files you upload to
>omnigate.  You should use your own initials so that people can figure
>out who produced a given module.  The only files that should have "dj"
>on them are the ones that I wrote!
sorry again.
>
>Also: If you plan on distributing a modified copy of go32 along with a
>port you've done, please contact me first so that (1) I can try to
>work your new stuff into the official stuff in some generic way, and
>(2) maybe there's an alternate way of performing that function that
>uses the standard go32.  I'd like to avoid having non-standard go32's
>running around if at all possible.
I'm with you.
I'm sending the go32 diffs and lib sources at the end of this message.
If anyone wants me to elaborate please send separate mail.
>
>DJ
>
>Subject: Path handling under djgpp
>From: Stephen Turnbull <turnbull AT ecolan DOT sbs DOT ohio-state DOT edu>
>
>I have noticed that many ports (most recently groff-1.7) using djgpp
>specify things like "DOS-style multiple paths (path;path) not
>supported, use Unix-style (path:path) instead."  I am entirely in
>sympathy with the difficulties that porters face in getting these
>things running.  But as usual, some ports are "more friendly" than
>others.  For example, DEMACS accepts both DOS and Unix style pathnames
>in the environment variables (although not within the editor itself).
>    It ought to be possible to write and publish a small library of
>functions for handling things like paths in environment variables.  It
>would be much easier on users if everyone used it, and thus these
>program-to-environment interfaces were standardized.  Also, I don't
>really see what would get broken by accepting DOS-style in addition to
>or instead of Unix-style, but this approach would make it possible and
>worthwhile to add features like being able to turn strict Unix
>conformance on and off (a la the +compatibility switches that many GNU
>programs have).
>    Does anybody have such a collection of functions?  If not, I'm not
>volunteering to do this at this time, but the next time I do a port or
>a major program I will try to write such a self-contained library
>(assuming nobody has done it yet, or by then).
>--
>
>Stephen Turnbull
IMHO the problem with ports is to remain as close as possible to the
original code.
I tried to minimize the diffs from the standard FSF, so to be able to
upgrade easyly.
If it would be possible to merge the diffs in the original code that would
be, of course, different.
Should i send to FSF (where ?) the diffs and apply for inclusion in the
standard distribution (how ?) ?
I could use a word of advice.
I don't see any actual problem in supporting standard DOS paths (see later).

>? d
>Subject: Re: Path handling under djgpp
>From: Andrew Tucker <a_tucker AT paul DOT spu DOT edu>
>
>On Tue, 20 Apr 1993, Stephen Turnbull wrote:
>
>> program-to-environment interfaces were standardized.  Also, I don't
>> really see what would get broken by accepting DOS-style in addition to
>> or instead of Unix-style, but this approach would make it possible and
>> worthwhile to add features like being able to turn strict Unix
>> conformance on and off (a la the +compatibility switches that many GNU
>> programs have).
>
>It would become incompatible if DOS drive names were included.  The path
>parser would/could choke on the : after the drive letter, thinking it was
>a path separator.  A "compatability switch" as you suggested would solve
>that problem, but would be a little convoluted.  The last thing the world
>needs is another compiler switch!!  :) :)
>
>/* Andrew */
True, but not enough.
If you ban out the chance of paths consisting of a single char, you can
still distinguish the two cases.
The only useful path of a single char i can think of is ":.:" which could
easyly be a special case. ;-) :-) ;-)
>
>? d
>From: ag AT MuwiInfa DOT Geschichte DOT Uni-Mainz DOT DE (Albert Graef)
>Subject: Re: groff-1.07
>
>> Hi,
>>    here it is.
>> I uploaded djgroff7.tgz to omnigate.clarkson.edu in /pub/msdos/djgpp/pub.
>
>Very nice. Thanks.
>
>
>> the program usr/local/bin/ts.exe (with source) is not part of groff-1.07,
>> it is used to enable MKS man to format man pages on the fly.
>> MKS man calls 'ts -mmks <manpage>' when it needs to format a page, so this
>> redirects formatting to groff.
>
>Does anybody know about a PD version of man?
There's GNU man, i don't know if someone ported that, but it shouldn't be
difficult.
On the other hand if you have MKS is useful to be able to get the original
man pages along with the new ones, so use the original man, which looks in
the man.dbz.
>
>Albert
>
>Subject: Re: Path handling under djgpp
>From: ag AT MuwiInfa DOT Geschichte DOT Uni-Mainz DOT DE (Albert Graef)
>
>In my programs I usually use code like the following. Filename parsing is
>admittedly crude, and you might also wish to add support for things like
>recursive subdir searching. I'm sure many people have written similar, and
>better, routines; I post this one for those of you who may find it useful.
>
>This only requires stdio, strchr and strcpy, and therefore should be highly
>portable; according to my POSIX manual, you may have to replace strchr by
>index on older BSD systems.
>
>       [ code deleted ]
>
>Albert
As i said before, i was trying to keep the diffs to a minimum.
Your code, or something similar, can be easyly incuded.
There is only one place where the check is done, and i don't see any
difficulty in '#ifdef'-ing that part out.

>
>From: DJ Delorie <dj AT ctron DOT com>
>Subject: Re: Path handling under djgpp
>
>gcc, at least the 2.2.2 port I did, uses MS-DOS paths on MS-DOS
>systems and unix paths on unix systems.  Why?  Because the colon is a
>valid part of a DOS file name (c:/foo) so you can't use it as a
>separator.
Only in pos 2!!

>
>The use of slashes, on the other hand, is a little tougher.  Gcc
>*should* accept them, but as of 2.2.2 there was a bug in gcc (may have
>been fixed) whereby it thought they were quoting characters instead of
>path separators.  Best bet is to use Unix-style forward slashes when
>passing file names to gcc.  Go32 will accept both types of slashes.
How true!!
It has been a nightmare to set up my DOS environment, with every program
which has it's own ideas about slashes!
>
>
>Subject: Re: Path handling under djgpp
>From: Stephen Turnbull <turnbull AT ecolan DOT sbs DOT ohio-state DOT edu>
>
>(1) That was a bit dumb of me---of course it would be nearly
>impossible to get the drive letter stuff right with colon as the path
>list separator.  I guess the best you could do is something like
>:[a-pA-P]:\[-_a-zA-Z]+ -> new (one-level) path in list, and I can see
>several problems off the bat (one letter paths on default drive, path
one letter path, withouth slash? it would be relative to current dir,
and so you can always say "./x" which is valid.

>relative to default directory on specified drive, and so on).  I would
again you could use ":c:.:" which is a little awkward, but recognizable
(if you have a long string of those i bet that a parser is better than
a human at figuring what is meant), if you keep track of the ":"s.

>never have either of those problems, but the wuarchive.wustl.edu
>graphics archive uses single letter directories to keep the size of
>the .gif directories down a little bit, and I could imagine a
>situation where you wanted emacs to look for its config files relative
>to the current directory.
as i said the only real clash i see (it may be i'm a little short sighted)
is ":.:" which is single char AND a useful path.

>    One could insist on completely Unix or completely DOS path lists
>(semicolons with back slashes, colons with forward slashes) but I can
>see where that would break things.  (If I remember correctly, when
>DEmacs grabs a file relative to an environment variable, the forward
>and backward slashes are mixed.)
>    (2) When I suggested a "+compatibility" switch, I wasn't
>suggesting putting it into the *compiler*, because that would cause
>definite incompatibilities with standard GNU.  I was suggesting
>putting it into *applications*.  This might be useful for something
>like "make," for quick ports where paths are set in environment
>variables, say.  Then you wouldn't have to edit the makefile if you
>keep things in standard places.  I don't know how useful this would
>be.
>    It is *definitely* annoying to have to switch back and forth
>between forward and backward slashes when using DEmacs or gawk.
>    Thanks to those who have sent or posted replies, and especially code.
IMHO an environmnt variable could be more useful, if it proves impossible
to support both styles.
Anyway the real problem are the tons of programs which just do what
they please, without us having any way to interfere (and acting differently
from each other).
>--
>
>Stephen Turnbull
>
>From: ag AT MuwiInfa DOT Geschichte DOT Uni-Mainz DOT DE (Albert Graef)
>
>Two suggestions, however:
>
>- If you use a nonstandard go32.exe for groff exclusively, why don't make
>  it part of groff.exe? The first thing I did was to reconvert groff.exe
>  into a.out format and then prepend your go32.exe to it. Some people will
>  not like to have too many different versions of go32.exe around.
I hope to get the diffs back in the original go32, but i wanted it tested
before!
>
>- Please don't name the archive djXXX because some people who do not know
>  groff might wonder whether your archive is required for djgpp or not.
>
Ok. Ok! sorry again

here follows the diffs for go32:
-------------------------------------------------------------------------
----------------diff -bcrsw /DJGPP/GO32/debug32.lnk GROFFDOS/GO32/debug32.lnk
*** /DJGPP/GO32/debug32.lnk Sun Nov 01 07:54:54 1992
--- GROFFDOS/GO32/debug32.lnk Wed Dec 16 15:33:56 1992
***************
*** 1,4 ****
! c:\usr\lib\c0s+
  dcontrol+
  ddalloc+
  ddebug+
--- 1,4 ----
! c:\bc\lib\c0s+
  dcontrol+
  ddalloc+
  ddebug+
***************
*** 24,29 ****
  dvcpi
  debug32.exe
  
! udi\udi+c:\usr\lib\maths+
! c:\usr\lib\emu+
! c:\usr\lib\cs
--- 24,29 ----
  dvcpi
  debug32.exe
  
! c:\bc\lib\maths+
! c:\bc\lib\emu+
! c:\bc\lib\cs
diff -bcrsw /DJGPP/GO32/exphdlr.c GROFFDOS/GO32/exphdlr.c
*** /DJGPP/GO32/exphdlr.c Sun Nov 01 07:54:50 1992
--- GROFFDOS/GO32/exphdlr.c Wed Dec 16 20:05:10 1992
***************
*** 880,886 ****
        memput(p2+ARENA, &statbuf32, sizeof(statbuf32));
        break;
      case 7:
!       retrieve_string(p1+ARENA, transfer_buffer, 0);
        page_out_everything();
        uninit_controllers();
        sscanf(transfer_buffer, "%s%n", buf, &i);
--- 880,887 ----
        memput(p2+ARENA, &statbuf32, sizeof(statbuf32));
        break;
      case 7:
!       r = retrieve_string(p1+ARENA, transfer_buffer, 0);
!       if (r>1) {
  	page_out_everything();
  	uninit_controllers();
  	sscanf(transfer_buffer, "%s%n", buf, &i);
***************
*** 892,897 ****
--- 893,963 ----
  	  r = system(transfer_buffer);
  	init_controllers();
  	page_in_everything();
+       } else {
+ 	struct { char   flag; char   type; int filler;
+ 		 long   lena; long   lenp;
+ 		 word32 argv; word32 envp;
+ 	       } bfr;
+ 	memget(p1+ARENA, &bfr, sizeof(bfr));
+ 	if (bfr.lena > 128) {
+ 	  /* FIXME space only for 200 env vars; unchecked !!! */
+ 	  char *p=transfer_buffer, *v[200];
+ 	  FILE *fd; char comm[200];
+ 	  char fnam[20]; int nargs = 0, l; r=-1;
+ 
+ 	  memget(bfr.argv+ARENA, transfer_buffer, bfr.lena);
+ 	  strcpy(comm, transfer_buffer);
+ 	  strcpy(fnam+1,"gotmpXXXXXX");mktemp(fnam+1);
+ 	  fd = fopen(fnam+1, "w"); fnam[0] = '@';
+           p += strlen(p)+1;
+ 	  while (*p) {
+             fprintf(fd, "%s\n", p); p += strlen(p)+1;
+ 	  }
+ 	  fclose(fd);
+ 	  if (bfr.lenp) {
+ 	    memget(bfr.envp+ARENA, transfer_buffer, bfr.lenp);
+ 	    for (p=transfer_buffer;*p;p += strlen(p)+1) v[nargs++] = p;
+ 	  }
+ 	  v[nargs] = NULL;
+ 	  page_out_everything();
+ 	  uninit_controllers();
+ 	  switch (bfr.type) {
+ 	    case 0:    r = spawnl  (P_WAIT, comm, comm, fnam, 0);    break;
+ 	    case 1:    r = spawnlp (P_WAIT, comm, comm, fnam, 0);    break;
+             case 2:    r = spawnle (P_WAIT, comm, comm, fnam, 0, v); break;
+             case 3:    r = spawnlpe(P_WAIT, comm, comm, fnam, 0, v); break;
+ 	  }
+ 	  init_controllers();
+ 	  page_in_everything();
+ 	  unlink(fnam+1);
+ 	} else {
+ 	  /* FIXME space only for 64 args; unchecked !!! */
+ 	  char *p=transfer_buffer, **v=(char**)buf, **e;
+ 	  int nargs = 0, l; r=-1;
+ 	  memget(bfr.argv+ARENA, transfer_buffer, bfr.lena);
+ 	  while (*p) {
+ 	    v[nargs++] = p; p += strlen(p)+1;
+ 	  }
+ 	  v[nargs++] = NULL; e=v+nargs;
+ 	  if (bfr.lenp) {
+ 	    memget(bfr.envp+ARENA, transfer_buffer+bfr.lena, bfr.lenp);
+ 	    for (p=transfer_buffer+bfr.lena;*p;p += strlen(p)+1) {
+ 	      v[nargs++] = p;
+ 	    }
+ 	  }
+ 	  v[nargs] = NULL;
+ 	  page_out_everything();
+ 	  uninit_controllers();
+ 	  switch (bfr.type) {
+ 	    case 0:    r = spawnv  (P_WAIT, v[0], v);         break;
+ 	    case 1:    r = spawnvp (P_WAIT, v[0], v);         break;
+ 	    case 2:    r = spawnve (P_WAIT, v[0], v, e);      break;
+ 	    case 3:    r = spawnvpe(P_WAIT, v[0], v, e);      break;
+ 	  }
+ 	  init_controllers();
+ 	  page_in_everything();
+ 	}
+       }
        break;
      case 8:
        _BX=(int)p1;
Only in GROFFDOS/GO32: exphdlr.obj
diff -bcrsw /DJGPP/GO32/go32.lnk GROFFDOS/GO32/go32.lnk
*** /DJGPP/GO32/go32.lnk Sun Nov 01 07:54:54 1992
--- GROFFDOS/GO32/go32.lnk Wed Dec 16 15:34:02 1992
***************
*** 1,4 ****
! c:\usr\lib\c0s+
  control+
  dalloc+
  debug+
--- 1,4 ----
! c:\bc\lib\c0s+
  control+
  dalloc+
  debug+
***************
*** 24,29 ****
  vcpi
  go32t.exe
  
! udi\udi+c:\usr\lib\maths+
! c:\usr\lib\emu+
! c:\usr\lib\cs
--- 24,29 ----
  vcpi
  go32t.exe
  
! c:\bc\lib\maths+
! c:\bc\lib\emu+
! c:\bc\lib\cs
diff -bcrsw /DJGPP/GO32/makefile GROFFDOS/GO32/makefile
*** /DJGPP/GO32/makefile Sun Nov 01 07:54:56 1992
--- GROFFDOS/GO32/makefile Wed Dec 16 15:35:10 1992
***************
*** 1,18 ****
  # History:25,17
  
  AFLAGS = /mx /zi /zd
  #CFLAGS = -ms -M -DSUPPORT_UDI -Iudi
  CFLAGS = -ms -M
  
  .c.obj:
! 	tcc $(CFLAGS) -DDEBUGGER=1 -DTOPLINEINFO=1 -DSOURCE_LIST -c $*
  	mv $*.obj d$*.obj
! 	tcc $(CFLAGS) -DDEBUGGER=0 -DTOPLINEINFO=0 -c $*
  
  .asm.obj:
! 	tasm $(AFLAGS) /DDEBUGGER=1 /DTOPLINEINFO=1 $*;
  	mv $*.obj d$*.obj
! 	tasm $(AFLAGS) /DDEBUGGER=0 /DTOPLINEINFO=0 $*;
  
  OBJS =\
  	control.obj\
--- 1,21 ----
  # History:25,17
  
+ CC=bcc
+ AS=tasm
+ 
  AFLAGS = /mx /zi /zd
  #CFLAGS = -ms -M -DSUPPORT_UDI -Iudi
  CFLAGS = -ms -M
  
  .c.obj:
!         $(CC) $(CFLAGS) -DDEBUGGER=1 -DTOPLINEINFO=1 -DSOURCE_LIST -c $<
  	mv $*.obj d$*.obj
!         $(CC) $(CFLAGS) -DDEBUGGER=0 -DTOPLINEINFO=0 -c $<
  
  .asm.obj:
!         $(AS) $(AFLAGS) /DDEBUGGER=1 /DTOPLINEINFO=1 $<;
  	mv $*.obj d$*.obj
!         $(AS) $(AFLAGS) /DDEBUGGER=0 /DTOPLINEINFO=0 $<;
  
  OBJS =\
  	control.obj\
***************
*** 42,57 ****
  all : go32t.exe stub.exe aout2exe.exe exe2aout.exe
  
  stub.exe: stub.c
! 	tcc stub.c
  	tdstrip stub
  
  # Note: some tlinks require /3 here, some barf if you supply it.
  go32t.exe : $(OBJS) go32.lnk 
! 	tlink /l /c /v /s /m @go32.lnk
! 	tlink /l /c /v /s /m @debug32.lnk
  
  bin2byte.exe : bin2byte.c
! 	tcc bin2byte.c
  	-tdstrip bin2byte
  
  stubbyte.h : bin2byte.exe stub.exe
--- 45,60 ----
  all : go32t.exe stub.exe aout2exe.exe exe2aout.exe
  
  stub.exe: stub.c
!         $(CC) stub.c
  	tdstrip stub
  
  # Note: some tlinks require /3 here, some barf if you supply it.
  go32t.exe : $(OBJS) go32.lnk 
!         tlink /l /c /v /s /m /3 @go32.lnk
!         tlink /l /c /v /s /m /3 @debug32.lnk
  
  bin2byte.exe : bin2byte.c
!         $(CC) bin2byte.c
  	-tdstrip bin2byte
  
  stubbyte.h : bin2byte.exe stub.exe
***************
*** 58,68 ****
  	bin2byte stub.exe stub_bytes stubbyte.h
  
  aout2exe.exe : aout2exe.c stubbyte.h
! 	tcc aout2exe
  	-tdstrip aout2exe
  
  exe2aout.exe : exe2aout.c
! 	tcc exe2aout
  	-tdstrip exe2aout
  
  # DEPENDENCIES
--- 61,71 ----
  	bin2byte stub.exe stub_bytes stubbyte.h
  
  aout2exe.exe : aout2exe.c stubbyte.h
!         $(CC) aout2exe.c
  	-tdstrip aout2exe
  
  exe2aout.exe : exe2aout.c
!         $(CC) exe2aout.c
  	-tdstrip exe2aout
  
  # DEPENDENCIES
diff -bcrsw /DJGPP/GO32/mono.c GROFFDOS/GO32/mono.c
*** /DJGPP/GO32/mono.c Sun Nov 01 07:54:36 1992
--- GROFFDOS/GO32/mono.c Wed Dec 16 15:28:06 1992
***************
*** 66,72 ****
  {
    char buf[200];
    int i;
!   int n = vsprintf(buf, fmt, &...);
  #if 0
    for (i=0; buf[i]; i++)
    {
--- 66,72 ----
  {
    char buf[200];
    int i;
!   int n = vsprintf(buf, fmt, ...);
  #if 0
    for (i=0; buf[i]; i++)
    {
diff -bcrsw /DJGPP/GO32/turboc.cfg GROFFDOS/GO32/turboc.cfg
*** /DJGPP/GO32/turboc.cfg Sun Nov 01 07:54:28 1992
--- GROFFDOS/GO32/turboc.cfg Wed Dec 16 15:19:54 1992
***************
*** 8,12 ****
  -1
  -d
  -y
! -IC:\USR\INCLUDE
! -LC:\USR\LIB
--- 8,13 ----
  -1
  -d
  -y
! -P-
! -IC:\bc\INCLUDE
! -LC:\bc\LIB
---------------------------------------------------------
here you have the routines to be addes to  libc/c/sys
---------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <dir.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>

typedef struct PIPEQUE {
  struct PIPEQUE *next;
  FILE           *fd;
  char           *cmd;
  char           *nam;
  int             ret;
} PipeQue;

static PipeQue *head = NULL;

FILE *popen (const char *cmd, const char *mode) {
  PipeQue *p = calloc(1, sizeof(PipeQue));

  if (!p) return NULL;

  p->next = head;
  head= p;
  p->nam = mktemp(strdup("popXXXXXX"));

  if (strchr(mode, 'w') || strchr(mode, 'W')) {
    p->cmd = strdup(cmd);
    p->ret = -1;
  } else {
#if 1
    int nul, oldstdout;
    nul = open(p->nam, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
    oldstdout = dup(fileno(stdout));
    dup2(nul, fileno(stdout));
    close(nul);

    p->ret = system(cmd);

    dup2(oldstdout, fileno(stdout));
    close(oldstdout);

    if (p->ret == -1) {
      head = p->next;
      free(p);
      return NULL;
    }
#else
    char line[200];
    sprintf(line, "%s >%s", cmd, p->nam);
    if (system(line) == -1) {perror("system"); exit(1);}
#endif
  }
  p->fd = fopen(p->nam, mode);
  return p->fd;
}

int pclose(FILE *fd) {
  int retval = -1;
  PipeQue *p=NULL, *c=head;
  fclose(fd);
  while (c) {
    if (c->fd == fd) {
      if (p) p->next = c->next;
      else   head    = c->next;
      if (c->cmd) {
#if 1
        int nul, oldstdin;
        nul = open(c->nam, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
        oldstdin = dup(fileno(stdin));
        dup2(nul, fileno(stdin));
        close(nul);

        c->ret = system(c->cmd);

        dup2(oldstdin, fileno(stdin));
        close(oldstdin);

        /* if (c->ret == -1) {perror("system"); exit(1);} */
#else
        char line[200];
        sprintf(line, "%s <%s", c->cmd, c->nam);
        retval = system(line);
#endif
      }
      retval = c->ret;
      unlink(c->nam);
      free(c);
      break;
    }
    p = c; c = c->next;
  }
  return retval;
}

#ifdef TESTING
void main() {
  FILE *fi = popen("ls -l c:\\bc\\bin", "r");
  FILE *fo = popen("more", "w");
  if (fi && fo) {
    while( !feof(fi) ) {
      char s[500];
      fgets(s, 400, fi);
      fputs(s,fo);
    }
    pclose(fi);
    pclose(fo);
  }
}
#endif
-------------------------------------------------------------------------
#define DO_ENVIRON

#include <std.h>
#include <stdarg.h>

int spawnl(const int mode, const char *path, const char *arg0, ...) {
  return spawnv(mode, path, &arg0);
}
int spawnlp(const int mode, const char *path, const char *arg0, ...) {
  return spawnvp(mode, path, &arg0);
}

static char abuff[4096], pbuff[4096];
static struct {
  char     flag;
  char     type;
  int      lena;
  int      lenp;
  char    *argv;
  char    *envp;
} cbuff={0,0,0,0,abuff,pbuff};


static void setargv(const char *path, const char **argv) {
  char *p = abuff;
  while (*argv) {
    const char *q=*argv++; do {*p++=*q;} while (*q++);
  }
  *p++='\0';
  cbuff.lena = p-abuff;
}

int spawnv(const int mode, const char *path, const char **argv) {
  cbuff.type=0; cbuff.lenp=0;
  setargv(path, argv);
  return system((char*)&cbuff);
}

int spawnvp(const int mode, const char *path, const char **argv) {
  cbuff.type=1; cbuff.lenp=0;
  setargv(path, argv);
  return system((char*)&cbuff);
}

#ifdef DO_ENVIRON
static void setenvp(const char **envp) {
  char *p=pbuff;
  while (*envp) {
    const char *q=*envp++; do {*p++=*q;} while (*q++);
  }
  *p++='\0';
  cbuff.lenp = p-pbuff;
}

int spawnle(const int mode, const char *path, const char *arg0, ...) {
  va_list ap; va_start(ap, arg0); while (va_arg(ap, char *)) ;
  return spawnve(mode, path, &arg0, va_arg(ap, const char **));
}
int spawnlpe(const int mode, const char *path, const char *arg0, ...) {
  va_list ap; va_start(ap, arg0); while (va_arg(ap, char *)) ;
  return spawnvpe(mode, path, &arg0, va_arg(ap, const char **));
}
int spawnve(const int mode, const char *path, const char **argv, const char **env) {
  cbuff.type=2;
  setargv(path, argv);
  setenvp(env);
  return system((char*)&cbuff);
}
int spawnvpe(const int mode, const char *path, const char **argv, const char **env) {
  cbuff.type=3;
  setargv(path, argv);
  setenvp(env);
  return system((char*)&cbuff);
}
#endif /* DO_ENVIRON */

#ifdef TESTING
#include <stdio.h>
void main() {
  char *e[]={"Primo=1", "Secondo=2", "Terzo=3", NULL};
  printf("prima di spawnl\n");
  spawnl(0,"i:\\usr\\bin\\ls.exe", "i:\\usr\\bin\\ls.exe", "go32", 0);
  printf("prima di spawnle\n");
  spawnle(0,"i:\\usr\\bin\\ls.exe", "i:\\usr\\bin\\ls.exe", "go32", 0, &e);
  printf("prima di spawnlp\n");
  spawnlp(0,"eco.exe", "eco.exe", "una", "marea", "di","argomentazzi",
          "lunghissimissimi","che_servono_solo_ed_unicamente",
          "per_sconfinazzare","grgjnljdfvnluvnuycuygeregfxuq",
          "egfoueofebppbvcwpbrpbrperepb8rer8e","fyb8ryutn6ci8leconewiecw",
          "fine", 0);
  printf("prima di spawnlpe\n");
  spawnlpe(0,"command.com", "command.com", "/c set", 0, &e);
  printf("dopo la spawnlpe\n");
}
#endif /* TESTING */

-------------------------------------------------------------------------
/* #define TESTING */
#include <std.h>
#include <stdio.h>

#include <vfork.h>

#ifdef TESTING

static const char *c[] = {"eco", "sono", "il", "figlio", 0 };
int main() {
  int i = vfork();
  if (i) {                                 /* parent */
    printf("sono il padre di (%d)1\n", i);
  } else {                                 /* child */
    int j;
    printf("sono il figlio che sta per vfork-are\n");
    if (j=vfork()) {
      int k;
      printf("sono il padre di (%d) e vfork-o ancora\n", j);
      if (k=vfork()) {
        printf("sono il padre di (%d)3\n", k);
        exit(0);
      } else {
        printf("sono il figlio che fa la execl\n");
        execl("eco", "eco", "sono", "la execl",0);
      }
      exit(0);
    } else {
      printf("sono il figlio che fa la execvp\n");
      execvp(c[0], &c[0]);
    }
  }
  return 0;
}
#endif /* TESTING */


       jmp_buf __vfork_buff[20];
static int     __vfork_rets[20];
       int     __current_pid=0;
static int     __progres_pid=0;
static int     __waiting_pid=0;
static int     __stdin_fd=-1;
static int     __stdou_fd=-1;

void vfork_help(void) {
  if (__stdin_fd==-1) __stdin_fd=dup(0);
  if (__stdou_fd==-1) __stdou_fd=dup(1);
#ifdef DEBUGPRINT
  fprintf(stderr, "__vfork_help : [%d, %d]\n", __stdin_fd, __stdou_fd);
#endif /* DEBUGPRINT */
}
int  vfork_execl  (const char *c,const char *a, ...)
{return vfork_execv (c, &a);}
int  vfork_execlp (const char *c,const char *a, ...)
{return vfork_execvp(c, &a);}
int  vfork_execle (const char *c,const char *a, ...)
{ const char **p=&a; while(*p++); return vfork_execve (c, &a, p);}
int  vfork_execlpe(const char *c,const char *a, ...)
{ const char **p=&a; while(*p++); return vfork_execvpe(c, &a, p);}
int vfork_execv(const char *c, const char **a)
{
  int r=spawnv(0,c,a);
  if(r>=0) vfork_exit(r);
  return r;
}
int vfork_execvp(const char *c, const char **a)
{
  int r=spawnvp(0,c,a);
  if(r>=0) vfork_exit(r);
  return r;
}
int vfork_execve(const char *c, const char **a, const char **e)
{
  int r=spawnve(0,c,a,e);
  if(r>=0) vfork_exit(r);
  return r;
}
int vfork_execvpe(const char *c, const char **a, const char **e)
{
  int r=spawnvpe(0,c,a,e);
  if(r>=0) vfork_exit(r);
  return r;
}

#include <fcntl.h>
void vfork_exit(int n)
{
  if (__current_pid > 0) {
    --__current_pid;
    __vfork_rets[__progres_pid %20] = n;
    _fwalk(rewind);
    close(0);
#ifdef DEBUGPRINT
    {int k=dup(__stdin_fd); fprintf(stderr, "vfork_exit : dup(%d) is %d\n", __stdin_fd, k);}
#else  /* not DEBUGPRINT */
    dup(__stdin_fd);
#endif /* not DEBUGPRINT */
    close(1);
#ifdef DEBUGPRINT
    {int k=dup(__stdou_fd); fprintf(stderr, "vfork_exit : dup(%d) is %d\n", __stdou_fd, k);}
#else  /* not DEBUGPRINT */
    dup(__stdou_fd);
#endif /* not DEBUGPRINT */
    longjmp(__vfork_buff[__current_pid],++__progres_pid);
  } else {
    #ifdef exit
      #undef exit
    #endif
    exit(n);
  }
}

int vfork_wait(int *r) {
  if (__waiting_pid >= __progres_pid) return -1;
  *r = __vfork_rets[__waiting_pid++ % 20];
  return __waiting_pid;
}

#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>

#undef dup
#undef pipe
#undef close

typedef struct PIPE { struct PIPE *next; char name[80];
                      int descr; int descw; } PipeQue;
static PipeQue *PipeHead = NULL;
static int      PipeCount= 0;

int vfork_close(int d) {
  PipeQue *P, *q=NULL;
#ifdef DEBUGPRINT
fprintf(stderr,"close(%x) : ",d);
#endif /* not DEBUGPRINT */
  for (P=PipeHead;P;P=P->next) {
    if        (P->descr==d) {
#ifdef DEBUGPRINT
fprintf(stderr,"skipped\n");
#endif /* not DEBUGPRINT */
      return 0;
    } else if (P->descw==d) {
      close(d);
#ifdef DEBUGPRINT
fprintf(stderr,"done, deleting \"%s\"", P->name);
#endif /* not DEBUGPRINT */
      unlink(P->name);
      if (q) q->next  = P->next;
      else   PipeHead = P->next;
      free(P);
      return 0;
    } else {
      q = P;
    }
  }
#ifdef DEBUGPRINT
fprintf(stderr,"done\n");
#endif /* not DEBUGPRINT */
  return close(d);
}
int vfork_dup(int d) {
  if ((d & 0xff00000) == ('p'<<20)) {
    PipeQue *P;
#ifdef DEBUGPRINT
fprintf(stderr,"dup(%x) : ",d);
#endif /* not DEBUGPRINT */
    for (P=PipeHead;P;P=P->next) {
      if (P->descr==d) {
        d = open(P->name, O_RDWR);
        if (d < 0) {perror("bad read open"); return -1;}
#ifdef DEBUGPRINT
fprintf(stderr," opened \"%s\" to %d\n",P->name,d);
#endif /* not DEBUGPRINT */
        P->descw = d;
        return d;
      }
    }
  }
#ifdef DEBUGPRINT
fprintf(stderr,"dup(%x) : done\n",d);
#endif /* not DEBUGPRINT */
  return dup(d);
}

int vfork_pipe(int *p) {
  PipeQue *P = calloc(sizeof(PipeQue),1);
  if (!P) {errno= ENOMEM; return -1;}

  strcpy(P->name, getenv("TMPDIR"));
  strcat(P->name, "/$pXXXXXX");
  if (!mktemp(P->name)) {errno = EINVAL; free(P); return -1;}
  p[1] = open(P->name, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IREAD|S_IWRITE);
  if (P->descw < 0) {perror("bad write open"); free(P); return -1;}
  p[0] = P->descr = ('p'<<20) + PipeCount++;
  P->descw = -1;
#ifdef DEBUGPRINT
fprintf(stderr, "pipe : \"%s\" [%d, %d]\n", P->name, p[0], p[1]);
#endif /* DEBUGPRINT */
  P->next = PipeHead;
  PipeHead= P;
  return 0;
}


-------------------------------------------------------------------------
As you can see i left in the code ('#ifdef'ed out) simple test programs
i used, to serve as examples (i realize now some of the printsouts and
comments are in italian, bear with me).
In order to compile an to run configure i had to modify the make program
i use (dmake) to accept '@respfile' style long argument listand gcc16 to
produce a .exe file without need to call explicitly aout2exe.
I send the diffs for the relavant parts and the dmake.ini i use (escaped
to avoid '.' in first column).
Here follows the dmake patch:
-------------------------------------------------------------------------
*** dmake.org Thu Jan 23 22:26:58 1992
--- dmake.c Fri Apr 16 23:02:14 1993
***************
*** 165,187 ****
        char *q;
  
        if( *(p = *++argv) == '-' ) {
!          if( p[1] == '\0' ) Fatal("Missing option letter");
  
!          /* copy options to Buffer for $(MFLAGS), strip 'f' and 'C'*/
!          q = strchr(Buffer, '\0');
!          while (*p != '\0') {
  	    char c = (*q++ = *p++);
!             if( c == 'f' || c == 'C' ) q--;
  	 }
  
  	 if( *(q-1) == '-' )
  	    q--;
  	 else
!             *q++ = ' ';
  
  	 *q = '\0';
  
!          for( p = *argv+1; *p; p++) switch (*p) {
  	    case 'f':
  	       _do_f_flag( 'f', *++argv, &fil_name ); argc--;
  	       break;
--- 165,187 ----
        char *q;
  
        if( *(p = *++argv) == '-' ) {
! 	 if( p[1] == '\0' ) Fatal("Missing option letter");
  
! 	 /* copy options to Buffer for $(MFLAGS), strip 'f' and 'C'*/
! 	 q = strchr(Buffer, '\0');
! 	 while (*p != '\0') {
  	    char c = (*q++ = *p++);
! 	    if( c == 'f' || c == 'C' ) q--;
  	 }
  
  	 if( *(q-1) == '-' )
  	    q--;
  	 else
! 	    *q++ = ' ';
  
  	 *q = '\0';
  
! 	 for( p = *argv+1; *p; p++) switch (*p) {
  	    case 'f':
  	       _do_f_flag( 'f', *++argv, &fil_name ); argc--;
  	       break;
***************
*** 253,258 ****
--- 253,298 ----
  	    default:  Usage(TRUE);  break;
  	 }
        }
+ #ifdef MSDOS
+       else if( *p == '@') {
+          char*   rsp_line = NIL(char);
+          char*   rsp_ptr  = NIL(char);
+          char**  rsp_argv = NIL(char*);
+          FILE*   rsp_file = NIL(FILE);
+          int     rsp_argc = 0;
+ 
+          if( !(rsp_file = fopen(p+1, "rt")) )
+            Fatal("response file \"%s\" not found", p+1);
+          while (1) {
+ 	    rsp_line = malloc(1025);
+             if (!rsp_line)
+                Fatal("memory exhausted for rsp_line");
+             if (!fgets(rsp_line,1024, rsp_file)) {
+                free(rsp_line);
+                fclose(rsp_file);
+                break;
+             } else {
+                if ((rsp_ptr=strchr(rsp_line, '\n'))) *rsp_ptr = '\0';
+                rsp_line = realloc(rsp_line, rsp_ptr - rsp_line +1);
+                if (!rsp_line)
+                   Fatal("memory exhausted for realloc rsp_line");
+                rsp_argv = realloc(rsp_argv, ++rsp_argc * sizeof(rsp_line));
+                if (!rsp_argv)
+                   Fatal("memory exhausted for realloc rsp_argv");
+                rsp_argv[rsp_argc -1] = rsp_line;
+             }
+          }
+          // add old argv
+          rsp_argv = realloc(rsp_argv, (rsp_argc + argc) * sizeof(char *));
+          if (!rsp_argv)
+             Fatal("memory exhausted for realloc rsp_argv[2]");
+          while (--argc) {
+             rsp_argv[rsp_argc++] = *++argv;
+          }
+          argv = rsp_argv;
+          argc = rsp_argc;
+       }
+ #endif
        else if( (q = strchr(p, '=')) != NIL(char) ) {
  	 cmdmacs = _stradd( cmdmacs, _strdup2(p), TRUE );
  	 Parse_macro( p, (q[-1]!='+')?M_PRECIOUS:M_DEFAULT );
***************
*** 287,298 ****
        char *fname;
  
        if( (mkfil=Search_file("MAKESTARTUP", &fname)) != NIL(FILE) ) {
!          Parse(mkfil);
  	 Def_macro( "MAKESTARTUP", fname, M_EXPANDED|M_MULTI );
!          mkfil = NIL(FILE);
        }
        else
!          Fatal( "Configuration file `%s' not found", fname );
     }
  
     Target = ex_val;
--- 327,338 ----
        char *fname;
  
        if( (mkfil=Search_file("MAKESTARTUP", &fname)) != NIL(FILE) ) {
! 	 Parse(mkfil);
  	 Def_macro( "MAKESTARTUP", fname, M_EXPANDED|M_MULTI );
! 	 mkfil = NIL(FILE);
        }
        else
! 	 Fatal( "Configuration file `%s' not found", fname );
     }
  
     Target = ex_val;
***************
*** 310,339 ****
        cp = Def_cell( ".MAKEFILES" );
  
        if( (lp = cp->CE_PRQ) != NIL(LINK) ) {
!          int s_n, s_t, s_q;
  
!          s_n = Trace;
!          s_t = Touch;
!          s_q = Check;
  
!          Trace = Touch = Check = FALSE;
!          Makemkf = Wait_for_completion = TRUE;
!          mkfil = NIL(FILE);
  
!          for(;  lp != NIL(LINK) && mkfil == NIL(FILE); lp=lp->cl_next) {
  	    if( lp->cl_prq->ce_attr & A_FRINGE ) continue;
  
!             mkfil = Openfile( lp->cl_prq->CE_NAME, FALSE, FALSE );
  
!             if( mkfil == NIL(FILE) &&
  		Make(lp->cl_prq, NIL(CELL)) != -1 )
!                mkfil = Openfile( lp->cl_prq->CE_NAME, FALSE, FALSE );
!          }
  
!          Trace = s_n;
!          Touch = s_t;
!          Check = s_q;
!          Makemkf = Wait_for_completion = FALSE;
        }
     }
  
--- 350,379 ----
        cp = Def_cell( ".MAKEFILES" );
  
        if( (lp = cp->CE_PRQ) != NIL(LINK) ) {
! 	 int s_n, s_t, s_q;
  
! 	 s_n = Trace;
! 	 s_t = Touch;
! 	 s_q = Check;
  
! 	 Trace = Touch = Check = FALSE;
! 	 Makemkf = Wait_for_completion = TRUE;
! 	 mkfil = NIL(FILE);
  
! 	 for(;  lp != NIL(LINK) && mkfil == NIL(FILE); lp=lp->cl_next) {
  	    if( lp->cl_prq->ce_attr & A_FRINGE ) continue;
  
! 	    mkfil = Openfile( lp->cl_prq->CE_NAME, FALSE, FALSE );
  
! 	    if( mkfil == NIL(FILE) &&
  		Make(lp->cl_prq, NIL(CELL)) != -1 )
! 	       mkfil = Openfile( lp->cl_prq->CE_NAME, FALSE, FALSE );
! 	 }
  
! 	 Trace = s_n;
! 	 Touch = s_t;
! 	 Check = s_q;
! 	 Makemkf = Wait_for_completion = FALSE;
        }
     }
  
***************
*** 380,386 ****
  	 }
        }
     }
!  
     if( Buffer != NIL(char) ) {FREE( Buffer ); Buffer = NIL(char);}
     if( Trace ) Def_macro(".SEQUENTIAL", "y", M_EXPANDED);
     if( Glob_attr & A_SEQ ) Def_macro( "MAXPROCESS", "1", M_EXPANDED|M_FORCE );
--- 420,426 ----
  	 }
        }
     }
! 
     if( Buffer != NIL(char) ) {FREE( Buffer ); Buffer = NIL(char);}
     if( Trace ) Def_macro(".SEQUENTIAL", "y", M_EXPANDED);
     if( Glob_attr & A_SEQ ) Def_macro( "MAXPROCESS", "1", M_EXPANDED|M_FORCE );
***************
*** 495,502 ****
--- 535,547 ----
     else
        fil = fopen( name, mode ? "w":"r" );
  
+ #ifdef ORIGINAL
     if( Verbose & V_FILE_IO )
        printf( "%s:  Openning [%s] for %s", Pname, name, mode?"write":"read" );
+ #else
+    if( Verbose & V_FILE_IO )
+       printf( "%s:  Opening [%s] for %s", Pname, name, mode?"write":"read" );
+ #endif
  
     if( fil == NIL(FILE) ) {
        if( Verbose & V_FILE_IO ) printf( " (fail)\n" );
-------------------------------------------------------------------------
*** expand.org Thu Jan 23 22:27:02 1992
--- expand.c Tue Dec 01 23:14:28 1992
***************
*** 377,383 ****
--- 377,435 ----
     DB_RETURN( res );
  }
  
+ #ifndef ORIGINAL
+ PUBLIC char*
+ Match( src, match )/*
+ =====================
+         Extract from the input of src only tokens containing the string match
  
+ 	When doing the tokenization, <sp>, <tab>, <nl>, and \<nl> all
+ 	constitute white space. */
+ 
+ char *src;
+ char *match;
+ {
+    TKSTR	tokens;
+    char		*tok;
+    char		*res;
+    int		first = TRUE;
+ 
+    DB_ENTER( "Tokenize" );
+ 
+    SET_TOKEN( &tokens, src );
+ 
+ 
+    /* map the escape codes in the separator string first */
+ 
+    for(tok=match; (tok = strchr(tok,ESCAPE_CHAR)) != NIL(char); tok++)
+       Map_esc( tok );
+ 
+    DB_PRINT( "exp", ("Match [%s]", match) );
+ 
+    /* Build the token list */
+    res = _strdup( "" );
+    while( *(tok = Get_token( &tokens, "", FALSE )) != '\0' ) {
+       DB_PRINT( "exp", ("Matching [%s]", tok) );
+ 
+       if( _strstr( tok, match ) )
+ 
+       if( first ) {
+ 	 FREE( res );
+ 	 res   = _strdup( tok );
+ 	 first = FALSE;
+       }
+       else {
+       	 char *x;
+          res = _strjoin(res, x =_strjoin(" ", tok, -1, FALSE), -1, TRUE);
+ 	 FREE( x );
+       }
+    }
+ 
+    FREE( src );
+    DB_RETURN( res );
+ }
+ 
+ #endif
  static char*
  _scan_token( s, ps )/*
  ======================
***************
*** 723,729 ****
  
  	       case 'T':
  	       case 't':
! 		  if( modifier_list ) {
  		     Warning( "Tokenize modifier must appear alone, ignored");
  		     modifier_list = 0;
  		  }
--- 775,781 ----
  
  	       case 'T':
  	       case 't':
!                   if( modifier_list ) {
  		     Warning( "Tokenize modifier must appear alone, ignored");
  		     modifier_list = 0;
  		  }
***************
*** 757,764 ****
  		     if( *s == ':' ) s++;
  		  }
  		  break;
  
! 	       case ':':
  		  if( modifier_list ) {
  		     result = Apply_modifiers( modifier_list, result );
  		     modifier_list = 0;
--- 809,854 ----
  		     if( *s == ':' ) s++;
  		  }
  		  break;
+ #ifndef ORIGINAL
+                case 'M':
+                case 'm':
+                   if( modifier_list ) {
+                      Warning( "Match modifier must appear alone, ignored");
+ 		     modifier_list = 0;
+ 		  }
+ 		  else {
+                      char *msg = "Match string must be quoted";
  
! 		     separator = *s++;
! 
! 		     if( separator != '\"' )
! 			Warning( msg );
! 		     else {
!                         /* we change the semantics to allow $(v:m")") */
! 			for (p = s; *p && *p != separator; p++)
! 			   if (*p == '\\')
! 			      if (p[1] == '\\' || p[1] == '"')
! 				 p++;
! 			if( *p == 0 )
!                            Fatal( "Unterminated match string" );
! 			else {
! 			   pat1 = _substr( s, p );
!                            result = Match( result, pat1 );
! 			   FREE( pat1 );
! 			}
! 			s = p;
! 		     }
! 
! 		     /* find the end of the macro spec, or the start of a new
! 		      * modifier list for further processing of the result */
! 
! 		     for( ; (*s != edelim) && (*s != ':'); s++ );
! 		     if( *s == ':' ) s++;
! 		  }
! 		  break;
! 
! #endif
!                case ':':
  		  if( modifier_list ) {
  		     result = Apply_modifiers( modifier_list, result );
  		     modifier_list = 0;
-------------------------------------------------------------------------
>SILENT := $(.SILENT)
>.SILENT:=YES
>
># CC in { bcc cl tcx gcc emx }
>CC            *:= bcc
>WINDOWS       *:= FALSE
>DEBUG         *:= FALSE
>PROFILE       *:= FALSE
>
>.IMPORT        :  TMPDIR
>TMPDIR         := $(TMPDIR:s,\,/)
>
>.IF $(MAKESTARTUP:m"i:")!=$(NULL)
>UNIX           := i:\usr
>BORLAND        := c:\bc
>MICROSOFT      := x:\msc
>LOGICAL        := i:\lsc
>WINDEV         := x:\windev
>TEX            := c:\tex
>.ELSE
>UNIX           := e:/.
>BORLAND        := c:\bc
>MICROSOFT      := c:\msc
>LOGICAL        := c:\lsc
>WINDEV         := c:\windev
>TEX            := c:\tex
>.END
>
>OBJDIR         := .
>
># Recipe execution configurations
>.IF TRUE==TRUE
>.IMPORT        :  COMSPEC
>SHELL          := $(COMSPEC)
>GROUPSHELL     := sh
>SHELLFLAGS     := /c
>GROUPFLAGS     := -0 -c
>SHELLMETAS     := <|>
>GROUPSUFFIX    := .sh
>DIRBRKSTR     *:= /\:
>DIRSEPSTR     *:= \\
>DIVFILE         = $(TMPFILE:s,/,\)
>.ELSE
>SHELL          := sh
>GROUPSHELL     := sh
>SHELLFLAGS     := -c
>GROUPFLAGS     :=
>SHELLMETAS     := *"?<>|()&][$$\#`'
>GROUPSUFFIX    := .sh
>.MKSARGS       := TRUE
>DIRBRKSTR     *:= /\:
>DIRSEPSTR     *:= /
>DIVFILE         = $(TMPFILE)
>.END
>.NOTABS        := TRUE
>AUGMAKE        := FALSE
>PREP           := 0
>
>#
>
>.IF $(CC)==bcc
>
>WINDEV   := $(BORLAND)
>MODEL    := c
>EXT      := .obj
>
>CFLAGS   := -I$(BORLAND)\include -wall
>#CFLAGS   := -2 -G -N- -O -X -Z -d -I$(BORLAND)\include -b- -j0 -g0 -wall \
>#            -Jg -k- # -Ogemvlbpi
>ASFLAGS  := /mx /t /w2
>LDFLAGS  := /c/n/L$(BORLAND)\lib
>RCFLAGS  := -I$(WINDEV)\include
>.IF $(WINDOWS)==TRUE
>CFLAGS  +:= -W -D__MSC -D_WINDOWS
>LDFLAGS +:= /x/e/Twe
>.ELSE
>#CFLAGS  +:= -r -u -k-
>LDFLAGS +:= /d
>.END
>.IF $(DEBUG)==TRUE
>CFLAGS  +:= -v -y
>ASFLAGS +:= /zi /zd
>LDFLAGS +:= /v /l
>.END
>
>%.obj: %.c
>  @+echo Compiling $< ...
>  @%$(BORLAND)\bin\bcc @$(mktmp,,$(DIVFILE) \
>    $(CFLAGS:s,\,\\)\n\
>    -I$(INCLUDE:s,\,\\)\n\
>  ) -m$(MODEL) -c -o$(OBJDIR)\$(@:f) $<
>
>%.obj: %.asm
>  @+echo Assembling $< ...
>  @%$(BORLAND)\bin\tasm $(ASFLAGS) $<,$(OBJDIR)\$(@:f);
>
>%.lib:! %.obj
>  @+echo Updating $< in $@ ...
>  @%$(BORLAND)\bin\tlib /C $@ -+$<
>
>.IF $(WINDOWS)==FALSE
>
>%.exe: %.obj
>  @+echo Linking to $@ ...
>  @%$(BORLAND)\bin\tlink $(LDFLAGS) @$(mktmp,,$(DIVFILE) \
>    c0$(MODEL)+\n\
>    $(&:s,\,\\,:t"+\n")\n\
>    $@\n\
>    $(@:s,\,\\,:s,.exe,.map)\n\
>    $(LDLIBS) emu+\n\
>    math$(MODEL) c$(MODEL)\n\
>  )
>.IF $(DEBUG)==TRUE
># @$(BORLAND)\bin\tdstrip -s $@
>.END
>
>.ELSE
>
>%.exe: %.obj
>  @+echo Linking to $@ ...
>  @%$(BORLAND)\bin\tlink $(LDFLAGS) @$(mktmp,,$(DIVFILE) \
>    c0w$(MODEL)+\n\
>    $(&:s,\,\\,:m".obj":t"+\n")\n\
>    $@\n\
>    $(@:s,\,\\,:s,.exe,.map)\n\
>    $(LDLIBS) import+\n\
>    mathw$(MODEL) cw$(MODEL)\n\
>    $(&:s,\,\\,:m".def")\n\
>  )
>  @%$(WINDEV)\bin\rc $(&:m".res") $@
>.IF $(DEBUG)==TRUE
>  @$(BORLAND)\bin\tdstrip -s $@
>.END
>
>.END
>
>.END
>
>#
>
>.IF $(CC)==cl
>
>MODEL    := C
>EXT      := .obj
>
>ASFLAGS  := /Mx /t
>CFLAGS   := -G2 -nologo -batch -W3
>LDFLAGS  := /NOL /B /SE:256
>LIB      := $(MICROSOFT)\lib
>RCFLAGS  := -I$(WINDEV)\include
>.IF $(WINDOWS)==TRUE
>CFLAGS  +:= -Os -Gw -Zp -I$(WINDEV)\include -D_WINDOWS
>LDFLAGS +:= /NOD
>LIB      := $(WINDEV)\lib
>.ELSE
>CFLAGS  +:= -Ox -Gs -I$(MICROSOFT)\include
>LDFLAGS +:= /NOE /NOI /E /FAR /PACKC
>LIB      := $(MICROSOFT)\lib
>.END
>.IF $(DEBUG)==TRUE
>CFLAGS  +:= -Zi -Zd
>ASFLAGS +:= /Zi /Zd
>LDFLAGS +:= /CO /L /M
>.END
>CL       := $(CFLAGS)
>
>%.obj: %.c
>  @+echo Compiling $< ...
>  @%$(MICROSOFT)\bin\cl -A$(MODEL) -c -Fo$(OBJDIR)\$(@:f) $<
>
>%.obj: %.asm
>  @+echo Assembling $< ...
>  @%$(MICROSOFT)\bin\masm $(ASFLAGS) $<,$(OBJDIR)\$(@:f);
>
>%.lib:! %.obj
>  @+echo Updating $< in $@ ...
>  @%$(MICROSOFT)\bin\lib /NOE /NOI /NOL $@ -+$<
>
>.IF $(WINDOWS)==FALSE
>
>%.exe: %.obj
>  @+echo Linking to $@ ...
>  @%$(MICROSOFT)\bin\link $(LDFLAGS) @$(mktmp,,$(DIVFILE) \
>    $(&:s,\,\\,:t"+\n")\n\
>    $(@:s,\,\\)\n\
>    $(@:s,\,\\,:s,.exe,.map)\n\
>    $(LDLIBS:s,\,\\) $(LIB)\\$(MODEL)libce\n\
>    ;\n\
>  )
>.IF $(DEBUG)==TRUE
>  @$(BORLAND)\bin\tdconvrt -c $@
>.END
>
>.ELSE
>
>%.exe: %.obj
>  @+echo Linking to $@ ...
>  @%$(MICROSOFT)\bin\link $(LDFLAGS) @$(mktmp,,$(DIVFILE) \
>    $(&:s,\,\\,:m".obj":t"+\n")\n\
>    $(@:s,\,\\)\n\
>    $(@:s,\,\\,:s,.exe,.map)\n\
>    $(LDLIBS:s,\,\\) $(LIB)\\$(MODEL)libcew $(LIB)\\libw\n\
>    $(&:s,\,\\,:m".def")\n\
>  )
>  @%$(WINDEV)\bin\rc $(&:m".res") $@
>.IF $(DEBUG)==TRUE
>  @$(BORLAND)\bin\tdconvrt -c $@
>.END
>
>.END
>
>.END
>
>#
>
>.IF $(CC)==tcx
>
>EXT := .pp
>
>%.pp: %.c
>  @+echo Preprocessing $< ...
>  @%$(LOGICAL)\bin\pp $< -d __STDC__ -I$(LOGICAL)\include -v -o $(OBJDIR)\$(@:f)
>
>%.tal: %.pp
>  @+echo Compiling $< ...
>  @%$(LOGICAL)\bin\tcx $< -c -f1 -p8 -w3 -v -o $(OBJDIR)\$(@:f)
>
>%.trl: %.tal
>  @+echo Assembling $< ...
>  @%$(LOGICAL)\bin\tal $< -c -t -v -q2 -o $(OBJDIR)\$(@:f)
>
>%.tll: %.trl
>  @+echo Updating $@ ...
>  @%$(LOGICAL)\bin\tplib $@ -u -v $?
>
>%.tld: %.trl
>  @+echo Linking to $@ ...
>  @%$(LOGICAL)\bin\vtlnk $(mktmp,$(@:b).tln,$(DIVFILE) \
>    FLAG c\n\
>    INPUT $(&:s,\,\\,:t"\nINPUT ")\n\
>    LIB $(LDLIBS:s,\,\\) $(LOGICAL)/lib/graphics\n\
>    LIB $(LOGICAL)/lib/conio\n\
>    LIB $(LOGICAL)/lib/t8lib\n\
>    OUTPUT $(@:s,\,\\)\n\
>  )
>
>.ENDIF
>
>#
>
>.IF $(CC)==gcc
>
>EXT     := .o
>
>COMPILER_PATH      := $(UNIX)/bin/dj
>C_INCLUDE_PATH     := $(UNIX)/include/dj
>CPLUS_INCLUDE_PATH := $(UNIX)/include/djplus
>LIBRARY_PATH       := $(UNIX)/lib/dj
>
>CFLAGS  := -W -Wall -O2 -fomit-frame-pointer
># -Wshadow -Wpointer-arith -Wcast-qual
># -Wcast-align -Wconversion -Waggregate-return -Winline
># -m486
>.IF $(DEBUG)==TRUE
>CFLAGS +:= -ggdb -fno-common
>.END
>.IF $(PROFILE)==TRUE
>CFLAGS +:= -pg
>.END
>
>%.o: %.c
>  @+echo Compiling $< ...
>  @%$(COMPILER_PATH)\gcc @$(mktmp,,$(TMPFILE) \
>    $(CFLAGS:t"\n")\n-Wtraditional\n\
>    -I $(C_INCLUDE_PATH)\n\
>  ) -c $< -o $(OBJDIR)\$(@:f)
>
>%.o: %.cc
>  @+echo Compiling $< ...
>  @%$(COMPILER_PATH)\gcc @$(mktmp,,$(TMPFILE) \
>    $(CFLAGS:t"\n")\n\
>    -I $(CPLUS_INCLUDE_PATH);$(C_INCLUDE_PATH)\n\
>  ) -c $< -o $(OBJDIR)\$(@:f)
>
>%.o: %.s
>  @+echo Assembling $< ...
>  @%$(COMPILER_PATH)\as $(ASFLAGS) $< -o $(OBJDIR)\$(@:f)
>
>%.a:! %.o
>  @+echo Updating $< in $@ ...
>  @%$(COMPILER_PATH)\ar ruv $@ -+$<
>
>%.exe: %.o
>  @+echo Linking to $@ ...
>.IF 0==0
>  @%$(COMPILER_PATH)\gcc @$(mktmp,,$(TMPFILE) \
>    $(!eq,$(LDFLAGS),$(NULL) $(LDFLAGS:t"\n")\n)\
>    $&\n\
>    $(!eq,$(LDLIBS),$(NULL) $(LDLIBS:t"\n")\n)\
>  ) -o $(@:d)$(@:b)
>.ELSE
>  @%$(COMPILER_PATH)\ld -v @$(mktmp,,$(TMPFILE) \
>    $(LDFLAGS) -L$(LIBRARY_PATH)\n\
>    $(LIBRARY_PATH)/$(eq,$(PROFILE),TRUE g)crt0.o $&\n\
>    -o $(@:d)$(@:b)\n\
>    $(!eq,$(LDLIBS),$(NULL) -l $(LDLIBS:t" -l ")) -l gcc$(eq,$(PROFILE),TRUE _p)\n\
>    -l g$(eq,$(PROFILE),TRUE _p) -l c$(eq,$(PROFILE),TRUE _p)\n\
>  )
>.END
>  @ $(COMPILER_PATH)\aout2exe $(@:d)$(@:b)
>  @ $(RM) $(RMFLAGS) $(@:d)$(@:b)
>
>%.exe: %
>  @ $(COMPILER_PATH)\aout2exe $< $@
>
>.END
>
>#
>
>.IF $(CC)==emx
>
>EXT     := .o
>
>COMPILER_PATH      := $(UNIX)/bin/emx
>C_INCLUDE_PATH     := $(UNIX)/include/emx
>CPLUS_INCLUDE_PATH := $(UNIX)/include/emxplus
>LIBRARY_PATH       := $(UNIX)/lib/emx
>
>CFLAGS  := -W -Wall -O2 -fomit-frame-pointer
># -Wshadow -Wpointer-arith -Wcast-qual
># -Wcast-align -Wconversion -Waggregate-return -Winline
># -m486
>.IF $(DEBUG)==TRUE
>CFLAGS +:= -ggdb -fno-common
>.END
>.IF $(PROFILE)==TRUE
>CFLAGS +:= -pg
>.END
>
>%.o: %.c
>  @+echo Compiling $< ...
>  @%$(COMPILER_PATH)\gcc @$(mktmp,,$(TMPFILE) \
>    $(CFLAGS:t"\n")\n-Wtraditional\n\
>    -I $(C_INCLUDE_PATH)\n\
>  ) -c $< -o $(OBJDIR)\$(@:f)
>
>%.o: %.cc
>  @+echo Compiling $< ...
>  @%$(COMPILER_PATH)\gcc @$(mktmp,,$(TMPFILE) \
>    $(CFLAGS:t"\n")\n\
>    -I $(CPLUS_INCLUDE_PATH);$(C_INCLUDE_PATH)\n\
>  ) -c $< -o $(OBJDIR)\$(@:f)
>
>%.o: %.s
>  @+echo Assembling $< ...
>  @%$(COMPILER_PATH)\as $(ASFLAGS) $< -o $(OBJDIR)\$(@:f)
>
>%.a:! %.o
>  @+echo Updating $< in $@ ...
>  @%$(COMPILER_PATH)\ar ruv $@ -+$<
>
>%.exe: %.o
>  @+echo Linking to $@ ...
>.IF 0==0
>  @%$(COMPILER_PATH)\gcc @$(mktmp,,$(TMPFILE) \
>    $(!eq,$(LDFLAGS),$(NULL) $(LDFLAGS:t"\n")\n)\
>    $&\n\
>    $(!eq,$(LDLIBS),$(NULL) $(LDLIBS:t"\n")\n)\
>  ) -o $(@:d)$(@:b)
>.ELSE
>  @%$(COMPILER_PATH)\ld -v @$(mktmp,,$(TMPFILE) \
>    $(LDFLAGS) -L$(LIBRARY_PATH)\n\
>    $(LIBRARY_PATH)/$(eq,$(PROFILE),TRUE g)crt0.o $&\n\
>    -o $(@:d)$(@:b)\n\
>    $(!eq,$(LDLIBS),$(NULL) -l $(LDLIBS:t" -l ")) -l gcc$(eq,$(PROFILE),TRUE _p)\n\
>    -l g$(eq,$(PROFILE),TRUE _p) -l c$(eq,$(PROFILE),TRUE _p)\n\
>  )
>.END
>  @ $(COMPILER_PATH)\emxbind $(@:d)$(@:b)
>  @ $(RM) $(RMFLAGS) $(@:d)$(@:b)
>
>%.exe: %
>  @ $(COMPILER_PATH)\emxbind $< $@
>
>.END
>
>#
>
># Language and Parser generation Tools and their flags
>BISON_SIMPLE := $(UNIX)/lib/bison/bison.simple
>BISON_HAIRY  := $(UNIX)/lib/bison/bison.hairy
>
>%.c: %.y
>  @+echo Building $(OBJDIR)\$(@:f) ...
>  @%$(UNIX)\bin\bison -o $(OBJDIR)\$(@:f) $<
>
>%.h: %.y
>  @+echo Building $(OBJDIR)\$(@:f) ...
>  @%$(UNIX)\bin\bison -d -o $(TEMP)/yytmp.c $<
>  @ $(UNIX)\bin\mv $(TEMP)/yytmp.h $(OBJDIR)\$(@:f)
>  @ $(RM) $(RMFLAGS) $(TEMP)/yytmp.c
>
>%.c: %.flx
>  @+echo Building $(OBJDIR)\$(@:f) ...
>  @%$(UNIX)\bin\flex -L -S$(UNIX)\lib\flex\flex.ske $<
>  @-$(UNIX)\bin\mv lexyy.c $(OBJDIR)\$(@:f)
>
># RCS support
>%: $$(@:d)RCS\$$(@:f)
>  @+echo Extracting $@
>  @ $(UNIX)\bin\co -q $@
>  @ $(UNIX)\bin\chmod +w $@
>
>.NOINFER: $$(@:d)RCS\$$(@:f)
>
># Other Tools and their flags
>%.res: %.rc
>  @+echo Building $(OBJDIR)\$(@:f) ...
>  @%$(WINDEV)\bin\rc -r $(RCFLAGS) -fo$(OBJDIR)\$(@:f) $<
>
>%.dvi: %.tex
>  @+echo Building $@ ...
>  @%$(TEX)\tex $<
>
>%.hlp: %.hpj
>  @%$(WINDEV)\bin\hc $<
>  @ $(RM) $(RMFLAGS) $(<:b).ph
>  @-$(UNIX)\bin\mv $(@:f) $@
>
>%.dep:
>  @[
>     echo Building $@ ...
>     awk -f $(MAKESTARTUP:d)dmakedep.awk -v EXT=$(EXT) `find . -name '*.c'` >$@
>   ]
>
># DMAKE uses this recipe to remove intermediate targets
>RM      := $(UNIX)\bin\rm
>RMFLAGS := -f
>
>.REMOVE: ;
>  @ $(RM) $(RMFLAGS) $<
>
># Definition of $(MAKE) macro for recursive makes.
>MAKE = $(MAKECMD) $(MFLAGS)
>
>#
>
># AUGMAKE extensions for SYSV compatibility
>@B   = $(@:b)
>@D   = $(@:d)
>@F   = $(@:f)
>"*B" = $(*:b)
>"*D" = $(*:d)
>"*F" = $(*:f)
><B   = $(<:b)
><D   = $(<:d)
><F   = $(<:f)
>?B   = $(?:b)
>?F   = $(?:f)
>?D   = $(?:d)
>
>.EXPORT: COMPILER_PATH      \
>         C_INCLUDE_PATH     \
>         CPLUS_INCLUDE_PATH \
>         LIBRARY_PATH       \
>         MAKEDIR            \
>         BISON_SIMPLE       \
>         BISON_HAIRY        \
>         CL                 \
>         TMPDIR
>
>.SILENT:=$(SILENT)
>
-------------------------------------------------------------------------
and here is the gcc16 patch:
it is a quick hack, i would like suggestions on exactly how such an option
should work, right now calling 'gcc16 -o xxx ...'  simply ends with both
xxx and xxx.exe, while it is enough for my purposes (running configure),
i'm not sure this is an acceptable behaviour.
-------------------------------------------------------------------------
*** SAV\gcc.c Mon Jul 06 20:50:22 1992
--- gcc.c Thu Apr 15 00:18:04 1993
***************
*** 35,43 ****
  #include <ctype.h>
  #include <signal.h>
  #include <sys/stat.h>
- #include <sys/file.h>   /* May get R_OK, etc. on some systems.  */
  
  #ifndef __TURBOC__
  #include "config.h"
  #include "gvarargs.h"
  #else
--- 35,43 ----
  #include <ctype.h>
  #include <signal.h>
  #include <sys/stat.h>
  
  #ifndef __TURBOC__
+ #include <sys/file.h>   /* May get R_OK, etc. on some systems.  */
  #include "config.h"
  #include "gvarargs.h"
  #else
***************
*** 532,542 ****
  	%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{trigraphs} \
          -undef -$ %{!undef:%p %P} -D__ASSEMBLER__ \
          %c %{O*:-D__OPTIMIZE__} %{traditional} %{ftraditional:-traditional}\
!         %{traditional-cpp:-traditional}\
  	%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C\
!         %i %{!M:%{!MM:%{!E:%{!pipe:%g.s}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n\
      %{!M:%{!MM:%{!E:%{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
!                     %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\
  		    %{!pipe:%g.s} %A\n }}}}"},
    /* Mark end of table */
    {0, 0}
--- 532,542 ----
  	%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{trigraphs} \
          -undef -$ %{!undef:%p %P} -D__ASSEMBLER__ \
          %c %{O*:-D__OPTIMIZE__} %{traditional} %{ftraditional:-traditional}\
! 	%{traditional-cpp:-traditional}\
  	%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C\
! 	%i %{!M:%{!MM:%{!E:%{!pipe:%g.s}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n\
      %{!M:%{!MM:%{!E:%{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
! 		    %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\
  		    %{!pipe:%g.s} %A\n }}}}"},
    /* Mark end of table */
    {0, 0}
***************
*** 559,570 ****
--- 559,589 ----
  			%{L*} %D %o %{!nostdlib:libgcc.a%s %L libgcc.a%s %{!A:%E}}\n }}}}}";
  #else
  /* Use -L and have the linker do the search for -lgcc.  */
+ #if 1
+ #if 1
  static char *link_command_spec = "\
  %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
  			%{r} %{s} %{T*} %{t} %{u*} %{x} %{z}\
  			%{!A:%{!nostdlib:%S}} \
+ 			%{L*} %D %o %{!nostdlib:-lgcc %L -lgcc %{!A:%E}}\n\
+ 			 aout2exe %{o*:%*}%{!o:a.out}\n }}}}}";
+ #else
+ static char *link_command_spec = "\
+ %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X -o %g.a %{A} %{d} %{e*} %{m} %{N} %{n} \
+ 			%{r} %{s} %{T*} %{t} %{u*} %{x} %{z}\
+ 			%{!A:%{!nostdlib:%S}} \
+ 			%{L*} %D %o %{!nostdlib:-lgcc %L -lgcc %{!A:%E}}\n\
+ 			 aout2exe %g.a\n\
+ 			 cp %g.exe %{o*}%{!o:aout.exe}\n }}}}}";
+ #endif
+ #else
+ static char *link_command_spec = "\
+ %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+ 			%{r} %{s} %{T*} %{t} %{u*} %{x} %{z}\
+ 			%{!A:%{!nostdlib:%S}} \
  			%{L*} %D %o %{!nostdlib:-lgcc %L -lgcc %{!A:%E}}\n }}}}}";
  #endif
+ #endif
  
  /* A vector of options to give to the linker.
     These options are accumulated by %x
***************
*** 1386,1394 ****
  #ifdef __MSDOS__
  
  /* Declare these to avoid compilation error.  They won't be called.  */
! int execv(const char *a, const char **b){}
! int execvp(const char *a, const char **b){}
  
  static int
  pexecute (search_flag, program, argv, not_last)
       int search_flag;
--- 1405,1415 ----
  #ifdef __MSDOS__
  
  /* Declare these to avoid compilation error.  They won't be called.  */
! //int execv(const char *a, const char **b){}
! //int execvp(const char *a, const char **b){}
  
+ #include <process.h>
+ 
  static int
  pexecute (search_flag, program, argv, not_last)
       int search_flag;
***************
*** 1396,1403 ****
--- 1417,1458 ----
       char *argv[];
       int not_last;
  {
+ #if 1
    char *scmd;
    FILE *argfile;
+   int i, l;
+ 
+   l=strlen(program)+1;
+   for (i=1; argv[i]; i++) l+=strlen(argv[i])+1;
+   if (l <= 128) { // max dos line length
+     i = spawnvp(P_WAIT, program, argv);
+   } else {
+     scmd = (char *)malloc (strlen (program) + strlen (temp_filename) + 6);
+     sprintf (scmd, "%s @%s.gp", program, temp_filename);
+     argfile = fopen (scmd+strlen (program) + 2, "w");
+     if (argfile == 0)
+       pfatal_with_name (scmd + strlen (program) + 2);
+ 
+     for (i=1; argv[i]; i++) {
+       char *cp;
+       for (cp = argv[i]; *cp; cp++) {
+ 	if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
+ 	  fputc ('\\', argfile);
+ 	fputc (*cp, argfile);
+ 	}
+       fputc ('\n', argfile);
+     }
+     fclose (argfile);
+ 
+     i = system (scmd);
+ 
+     remove (scmd + strlen (program) + 2);
+     free(scmd);
+   }
+   return i << 8;
+ #else
+   char *scmd;
+   FILE *argfile;
    int i;
  
    scmd = (char *)malloc (strlen (program) + strlen (temp_filename) + 6);
***************
*** 1423,1428 ****
--- 1478,1484 ----
  
    remove (scmd + strlen (program) + 2);
    return i << 8;
+ #endif
  }
  
  #else /* not __MSDOS__ */
-------------------------------------------------------------------------
I'm packing the sources of 'xx'groff7 to upload them to omnigate, i'm
delayed by the fact the make doesn't work really well, or should i say
'ar'?
The problem is that, if i change a source which is in a library, it gets
compiled 'ar -r' is called, but the lib seems unchanged. in order to change
it (and link the modified code) i have to delete it by hand. Any idea ?

As i have written before my main aim is to set up an environment where
make ports from UNIX source with the less possible hassle. so i'm working
more on the environment than on the sources themselves.
An important missing part is the shell, for which i don't have the sources.
Does anyone know the location of the sources of ms-sh200? or, in suborder,
does anyone know a good, PD, (korn)shell with sources??
Thanks!

Best Regards
Mauro Condarelli
sincon AT minsky DOT csata DOT it


- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019