[gnu.utils.bug] Make 3.56: Xenix patches and bug fixes

chip@ateng.ateng.com (Chip Salzenberg) (10/09/89)

Patches to GNU Make 3.56.  I really hope that these will be adopted into
the official GNU Make release, since there are a _lot_ of Xenix users out
there, and I'm tired of porting each Make version.  (:-))

Features:
    Port to SCO Xenix/386.
    Create new "dir.h" header, used for opendir() readdir() etc.
    Use Doug Gwyn's getcwd() replacement.  It's faster, and unlike
	the Xenix one, it doesn't break when SIGCLD is being caught.
    Support a command prefix (default: "\t" unless "-n" flag specified).
	Prefix is printed before each command.
    Pass all variables in the child environment only if VARS_IN_ENV is
	defined.  (Otherwise large variables overwhelm the environment.)
	Perhaps the default should be the current behavior; that's a
	small change.

Bug fixes:
    Fix core dump bug when NO_ARCHIVES is defined --
	$@ was being defined to an uninitialized pointer.
    Fix handling of multiple job slots --
	but it's still not completely right.
    Fix creation of MFLAGS and MAKEFLAGS in presence of multiple job slots --
	the presence of "-j" lopped off the rest of the flags.
    Change update_status to a short, since many compilers don't support
	signed bitfields.
    Line buffer standard output, so output of multiple makes processes
	interleave correctly.
    Fix core dump bug when numeric option has the value omitted.

# This file contains patches for GNU Make 3.56.
# (Be sure to use the "-p" option of patch.)
# Patches are enclosed for the following file(s):
#	commands.c
#	dir.c
#	dir.h
#	file.c
#	file.h
#	function.c
#	glob.c
#	job.c
#	main.c
#	make.h
#	remake.c
#	variable.c

Index: commands.c
***************
*** 120,124 ****
    /* If the target is an archive member `lib(member)',
       then $@ is `lib' and $% is `member'.  */
- 
    if (ar_name (file->name))
      {
--- 120,123 ----
***************
*** 129,132 ****
--- 128,132 ----
      }
    else
+ #endif
      {
        at = savestring (file->name, strlen (file->name));
***************
*** 133,137 ****
        percent = "";
      }
- #endif
  
    DEFINE_VARIABLE ("@", 1, at);
--- 133,136 ----
***************
*** 335,353 ****
      }
  
-   /* First set the automatic variables according to this file.  */
- 
-   initialize_file_variables (file);
- 
-   set_file_variables (file);
- 
    /* Chop the commands up into lines.  */
    if (cmds->command_lines == 0)
      chop_commands (cmds);
  
    if (job_slots > 0)
!     /* Wait for a job slot to be freed up.  */
!     while (job_slots_used == job_slots)
!       wait_for_children (1, 0);
  
    /* Start the command sequence, record it in a new
       `struct child', and add that to the chain.  */
--- 334,355 ----
      }
  
    /* Chop the commands up into lines.  */
+ 
    if (cmds->command_lines == 0)
      chop_commands (cmds);
  
+   /* Wait for a job slot to be freed up.  */
+ 
    if (job_slots > 0)
!     {
!       while (job_slots_used == job_slots)
! 	wait_for_children (1, 0);
!     }
  
+   /* Set the automatic variables according to this file.  */
+ 
+   initialize_file_variables (file);
+   set_file_variables (file);
+ 
    /* Start the command sequence, record it in a new
       `struct child', and add that to the chain.  */
***************
*** 370,383 ****
      }
  
!   unblock_children ();
! 
!   if (status)
      {
        free (c->commands);
        free ((char *) c);
- 
        file->update_status = (just_print_flag || touch_flag) ? 0 : 1;
      }
!   else if (job_slots == 1)
      {
        /* Since there is only one job slot, make things run linearly.
--- 372,387 ----
      }
  
!   if (status == 0)
!     file->update_status = 0;
!   else
      {
        free (c->commands);
        free ((char *) c);
        file->update_status = (just_print_flag || touch_flag) ? 0 : 1;
      }
! 
!   unblock_children ();
! 
!   if (status == 0 && job_slots == 1)
      {
        /* Since there is only one job slot, make things run linearly.
***************
*** 385,390 ****
        while (file->command_state != cs_finished)
  	wait_for_children (1, 0);
- 
      }
    notice_finished_file (file);
  }
--- 389,394 ----
        while (file->command_state != cs_finished)
  	wait_for_children (1, 0);
      }
+ 
    notice_finished_file (file);
  }

Index: dir.c
***************
*** 18,43 ****
  
  #include "make.h"
  
- #if	defined(USGr3) || defined(DIRENT)
- 
- #include <dirent.h>
- #	if	!defined(d_ino) && !defined(d_fileno)
- #define	d_ino	d_fileno
- #	endif
- #define direct dirent
- #define	D_NAMLEN(d) strlen((d)->d_name)
- 
- #else	/* Not USGr3 and not DIRENT.  */
- 
- #define D_NAMLEN(d) ((d)->d_namlen)
- #	ifdef	USG
- #include "ndir.h"   /* Get ndir.h from the Emacs distribution.  */
- #	else	/* Not USG.  */
- #include <sys/dir.h>
- #	endif	/* USG.  */
- 
- #endif	/* USGr3 or DIRENT.  */
- 
- 
  /* Hash table of directories.  */
  
--- 18,24 ----
  
  #include "make.h"
+ #include "dir.h"
+ #include <errno.h>
  
  /* Hash table of directories.  */
  
***************
*** 385,386 ****
--- 366,556 ----
    printf (" impossibilities in %u directories.\n", dirs);
  }
+ 
+ /*
+     getcurdir -- get current working directory name
+ 		 (compatible with POSIX and SVID getcwd())
+   
+     last edit:      21-Sep-1987     D A Gwyn
+   
+     This public-domain getcurdir() routine can be used to replace the UNIX
+     System V library routine (which uses popen() to capture the output of
+     the "pwd" command).  Once that is done, "pwd" can be reimplemented as
+     just puts(getcurdir()).
+   
+     This implementation depends on every directory having entries for
+     "." and "..".  It also depends on the internals of the readdir()
+     data structures to some degree.
+   
+     I considered using chdir() to ascend the hierarchy, followed by a
+     final chdir() to the path being returned by getcurdir() to restore the
+     location, but decided that error recovery was too difficult that way.
+     The algorithm I settled on was inspired by my rewrite of the "pwd"
+     utility, combined with the dotdots[] array trick from the SVR2 shell.
+ */
+ 
+ char   *
+ getcurdir(buf, size)			/* returns pointer to CWD pathname */
+ char   *buf;				/* where to put name (NULL to malloc) */
+ int     size;				/* size of buf[] or malloc()ed memory */
+ {
+   static char dotdots[] =
+   "../../../../../../../../../../../../../../../../../../../../../../../../../..";
+   char   *dotdot;			/* -> dotdots[.], right to left */
+   DIR    *dirp;				/* -> parent directory stream */
+   struct direct *dir;			/* -> directory entry */
+   struct stat stat1,
+           stat2;			/* info from stat() */
+   struct stat *d = &stat1;		/* -> info about "." */
+   struct stat *dd = &stat2;		/* -> info about ".." */
+   register char *buffer;		/* local copy of buf, or malloc()ed */
+   char   *bufend;			/* -> buffer[size] */
+   register char *endp;			/* -> end of reversed string */
+   register char *dname;			/* entry name ("" for root) */
+   int     serrno = errno;		/* save entry errno */
+ 
+   if (size == 0)
+   {
+     errno = EINVAL;			/* invalid argument */
+     return NULL;
+   }
+ 
+   if ((buffer = buf) == NULL		/* wants us to malloc() the string */
+       && (buffer = (char *) malloc((unsigned) size)) == NULL)
+   {
+     errno = ENOMEM;			/* cannot malloc() specified size */
+     return NULL;
+   }
+ 
+   if (stat(".", dd) != 0)		/* prime the pump */
+     goto error;				/* errno already set */
+ 
+   endp = buffer;			/* initially, empty string */
+   bufend = &buffer[size];
+ 
+   for (dotdot = &dotdots[sizeof(dotdots)]; dotdot != dotdots;)
+   {
+     /* include one more "/.." section */
+     /* (first time is actually "..") */
+     dotdot -= 3;
+ 
+     /* swap stat() info buffers */
+     {
+       register struct stat *temp = d;
+ 
+       d = dd;				/* new current dir is old parent dir */
+       dd = temp;
+     }
+ 
+     if ((dirp = opendir(dotdot)) == NULL)	/* new parent */
+       goto error;			/* errno already set */
+ 
+     if (fstat(dirp->dd_fd, dd) != 0)
+     {
+       serrno = errno;			/* set by fstat() */
+       (void) closedir(dirp);
+       errno = serrno;			/* in case closedir() clobbered it */
+       goto error;
+     }
+ 
+     if (d->st_dev == dd->st_dev)
+     {
+       /* not crossing a mount point */
+ 
+       if (d->st_ino == dd->st_ino)
+       {
+ 	/* root directory */
+ 	dname = "";
+ 	goto append;
+       }
+ 
+       do
+       {
+ 	if ((dir = readdir(dirp)) == NULL)
+ 	{
+ 	  (void) closedir(dirp);
+ 	  errno = ENOENT;		/* missing entry */
+ 	  goto error;
+ 	}
+       } while (dir->d_ino != d->st_ino);
+     }
+     else
+     {					/* crossing a mount point */
+       struct stat t;			/* info re. test entry */
+       char    name[sizeof(dotdots) + 1 + MAXNAMLEN];
+ 
+       (void) strcpy(name, dotdot);
+       dname = &name[strlen(name)];
+       *dname++ = '/';
+ 
+       do
+       {
+ 	if ((dir = readdir(dirp)) == NULL)
+ 	{
+ 	  (void) closedir(dirp);
+ 	  errno = ENOENT;		/* missing entry */
+ 	  goto error;
+ 	}
+ 
+ 	(void) strcpy(dname, dir->d_name);
+ 	/* must fit if MAXNAMLEN is not a lie */
+       } while (stat(name, &t) != 0
+ 	       || t.st_ino != d->st_ino
+ 	       || t.st_dev != d->st_dev);
+     }
+ 
+     dname = dir->d_name;
+ 
+     /* append "/" and reversed dname string onto buffer */
+ append:
+     if (endp != buffer			/* avoid trailing / in final name */
+ 	|| dname[0] == '\0'		/* but allow "/" when CWD is root */
+ 	    )
+       *endp++ = '/';
+ 
+     {
+       register char *app;		/* traverses dname string */
+ 
+       for (app = dname; *app != '\0'; ++app)
+ 	;
+ 
+       if (app - dname >= bufend - endp)
+       {
+ 	(void) closedir(dirp);
+ 	errno = ERANGE;			/* won't fit allotted space */
+ 	goto error;
+       }
+ 
+       while (app != dname)
+ 	*endp++ = *--app;
+     }
+ 
+     (void) closedir(dirp);
+ 
+     if (dname[0] == '\0')
+     {					/* reached root; wrap it up */
+       register char *startp;		/* -> buffer[.] */
+ 
+       *endp = '\0';			/* plant null terminator */
+ 
+       /* straighten out reversed pathname string */
+       for (startp = buffer; --endp > startp; ++startp)
+       {
+ 	char    temp = *endp;
+ 
+ 	*endp = *startp;
+ 	*startp = temp;
+       }
+ 
+       errno = serrno;			/* restore entry errno */
+       return buffer;
+     }
+   }
+ 
+   errno = ENOMEM;			/* actually, algorithm failure */
+ 
+ error:
+   if (buf == NULL)
+     free((char *) buffer);
+ 
+   return NULL;
+ }

Index: dir.h
***************
*** 1,0 ****
--- 1,45 ----
+ /* Copyright (C) 1988, 1989 Free Software Foundation, Inc.
+ This file is part of GNU Make.
+ 
+ GNU Make is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+ 
+ GNU Make is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GNU Make; see the file COPYING.  If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+ 
+ #if     defined(M_XENIX)
+ 
+ #include <sys/ndir.h>
+ #define D_NAMLEN(d) ((d)->d_namlen)
+ 
+ #else   /* Not Xenix */
+ 
+ #if	defined(USGr3) || defined(DIRENT)
+ 
+ #include <dirent.h>
+ #	if	!defined(d_ino) && !defined(d_fileno)
+ #define	d_ino	d_fileno
+ #	endif
+ #define direct dirent
+ #define	D_NAMLEN(d) strlen((d)->d_name)
+ 
+ #else   /* Not Xenix, not USGr3 and not DIRENT.  */
+ 
+ #define D_NAMLEN(d) ((d)->d_namlen)
+ #	ifdef	USG
+ #include "ndir.h"   /* Get ndir.h from the Emacs distribution.  */
+ #	else	/* Not USG.  */
+ #include <sys/dir.h>
+ #	endif	/* USG.  */
+ 
+ #endif	/* USGr3 or DIRENT.  */
+ 
+ #endif  /* Xenix */

Index: file.c
***************
*** 225,228 ****
--- 225,229 ----
  	      else if (!silent_flag && !just_print_flag)
  		{
+ 		  fputs (command_prefix, stdout);
  		  if (!doneany)
  		    {

Index: file.h
***************
*** 51,55 ****
        } command_state ENUM_BITFIELD (2);
  
!     int update_status:2;	/* Status of the last attempt to update,
  				   or -1 if none has been made.  */
      unsigned int double_colon:1;/* Nonzero for double-colon entry */
--- 51,55 ----
        } command_state ENUM_BITFIELD (2);
  
!     short update_status;        /* Status of the last attempt to update,
  				   or -1 if none has been made.  */
      unsigned int double_colon:1;/* Nonzero for double-colon entry */

Index: function.c
***************
*** 420,428 ****
  		   newlines in its output with spaces, and put
  		   that in the variable output buffer.  */
! 		if (buffer[i - 1] == '\n')
  		  --i;
! 		for (p = buffer; p < buffer + i; ++p)
! 		  if (*p == '\n')
! 		    *p = ' ';
  		o = variable_buffer_output (o, buffer, i);
  	      }
--- 420,428 ----
  		   newlines in its output with spaces, and put
  		   that in the variable output buffer.  */
! 		if (i > 0 && buffer[i - 1] == '\n')
  		  --i;
! 		buffer[i] = '\0';
! 		for (p = buffer; (p = index(p, '\n')) != NULL; ++p)
! 		  *p = ' ';
  		o = variable_buffer_output (o, buffer, i);
  	      }

Index: glob.c
***************
*** 21,45 ****
  
  #include <sys/types.h>
  
- #if	defined(USGr3) || defined(DIRENT)
- 
- #include <dirent.h>
- #	if	!defined(d_ino) && !defined(d_fileno)
- #define	d_ino	d_fileno
- #	endif
- #define direct dirent
- #define	D_NAMLEN(d) strlen((d)->d_name)
- 
- #else	/* Not USGr3 and not DIRENT.  */
- 
- #define D_NAMLEN(d) ((d)->d_namlen)
- #	ifdef	USG
- #include "ndir.h"   /* Get ndir.h from the Emacs distribution.  */
- #	else	/* Not USG.  */
- #include <sys/dir.h>
- #	endif	/* USG.  */
- 
- #endif	/* USGr3 or DIRENT.  */
- 
  #ifdef USG
  #include <memory.h>
--- 21,26 ----
  
  #include <sys/types.h>
+ #include "dir.h"
  
  #ifdef USG
  #include <memory.h>

Index: job.c
***************
*** 489,493 ****
  
    if (just_print_flag || (!noprint && !silent_flag))
!     puts (p);
  
    /* If -n was given, recurse to get the next line in the sequence.  */
--- 489,496 ----
  
    if (just_print_flag || (!noprint && !silent_flag))
!     {
!       fputs (command_prefix, stdout);
!       puts (p);
!     }
  
    /* If -n was given, recurse to get the next line in the sequence.  */

Index: main.c
***************
*** 247,250 ****
--- 247,254 ----
  char *program;
  
+ /* The string to print before each command. */
+ 
+ char *command_prefix = "\t";
+ 
  /* Value of the MAKELEVEL variable at startup (or 0).  */
  
***************
*** 332,335 ****
--- 336,351 ----
  #endif
  
+   /* Line buffer stdout. */
+ 
+ #ifdef USGr3
+   setvbuf(stdout, (char *)0, _IOLBF, BUFSIZ);
+ #else
+ #ifdef USG
+   setvbuf(stdout, _IOLBF, (char *)0, BUFSIZ);
+ #else
+   setlinebuf(stdout);
+ #endif
+ #endif
+ 
    /* Figure out where this program lives.  */
  
***************
*** 376,379 ****
--- 392,400 ----
      print_version ();
  
+   /* If we're just printing commands, then we omit the prefix. */
+ 
+   if (just_print_flag)
+     command_prefix = "";
+ 
    /* Construct the list of include directories to search.  */
  
***************
*** 909,913 ****
  		      break;
  		    case string:
! 		      if (*sw == '\0')
  			arg = argv[++i];
  		      else
--- 930,934 ----
  		      break;
  		    case string:
! 		      if ((*sw == '\0') && (i + 1) < argc)
  			arg = argv[++i];
  		      else
***************
*** 943,947 ****
  
  		    case positive_int:
! 		      if (*sw == '\0')
  			arg = argv[++i];
  		      else
--- 964,968 ----
  
  		    case positive_int:
! 		      if ((*sw == '\0') && (i + 1) < argc)
  			arg = argv[++i];
  		      else
***************
*** 979,983 ****
  
  		    case floating:
! 		      if (*sw == '\0')
  			arg = argv[++i];
  		      else
--- 1000,1004 ----
  
  		    case floating:
! 		      if ((*sw == '\0') && (i + 1) < argc)
  			arg = argv[++i];
  		      else
***************
*** 1108,1115 ****
  
    i = 0;
-   flags[i++] = '-';
  
    for (cs = switches; cs->c != '\0'; ++cs)
!     if (cs->toenv)
        switch (cs->type)
  	{
--- 1129,1139 ----
  
    i = 0;
  
    for (cs = switches; cs->c != '\0'; ++cs)
!     {
!       if (! cs->toenv)
! 	continue;
!       if (i == 0 || flags[i - 1] == ' ')
! 	flags[i++] = '-';
        switch (cs->type)
  	{
***************
*** 1142,1153 ****
  		{
  		  strcpy (&flags[i], "j1 ");
! 		  i += 5;
  		}
  	      else
  		{
! 		  char *p = &flags[i];
! 		  sprintf (p, "%c%u ", cs->c,
  			   *(unsigned int *) cs->value_ptr);
! 		  i += strlen (p);
  		}
  	    }
--- 1166,1176 ----
  		{
  		  strcpy (&flags[i], "j1 ");
! 		  i += strlen (&flags[i]);
  		}
  	      else
  		{
! 		  sprintf (&flags[i], "%c%u ", cs->c,
  			   *(unsigned int *) cs->value_ptr);
! 		  i += strlen (&flags[i]);
  		}
  	    }
***************
*** 1174,1177 ****
--- 1197,1201 ----
  	  break;
  	}
+     }
  
    if (i == 0)

Index: make.h
***************
*** 89,92 ****
--- 89,93 ----
  extern struct dep *copy_dep_chain ();
  extern char *find_percent ();
+ extern char *getcurdir ();
  
  #ifndef	NO_ARCHIVES
***************
*** 131,142 ****
  extern char **environ;
  
! #ifdef	USG
! extern char *getcwd ();
! #define	getwd(buf)	getcwd (buf, MAXPATHLEN - 2)
! #else	/* Not USG.  */
! extern char *getwd ();
! #endif	/* USG.  */
  
- 
  extern char *reading_filename;
  extern unsigned int *reading_lineno_ptr;
--- 132,137 ----
  extern char **environ;
  
! #define getwd(buf)      getcurdir (buf, MAXPATHLEN - 2)
  
  extern char *reading_filename;
  extern unsigned int *reading_lineno_ptr;
***************
*** 151,154 ****
--- 146,150 ----
  
  extern char *program;
+ extern char *command_prefix;
  
  extern unsigned int makelevel;

Index: remake.c
***************
*** 578,582 ****
    if (!silent_flag)
      {
!       printf ("touch %s\n", file->name);
        fflush (stdout);
      }
--- 578,585 ----
    if (!silent_flag)
      {
!       fputs (command_prefix, stdout);
!       fputs ("touch ", stdout);
!       fputs (file->name, stdout);
!       fputc ('\n', stdout);
        fflush (stdout);
      }
***************
*** 630,633 ****
--- 633,638 ----
       struct file *file;
  {
+   int has_commands = 0;
+ 
    if (file->cmds == 0 && !(touch_flag && !file->is_target))
      {
***************
*** 664,672 ****
  	}
        else
! 	execute_file_commands (file);
      }
  
!   file->command_state = cs_finished;
!   notice_finished_file (file);
  }
  
--- 669,683 ----
  	}
        else
! 	{
! 	  execute_file_commands (file);
! 	  has_commands = 1;
! 	}
      }
  
!   if (!has_commands)
!     {
!       file->command_state = cs_finished;
!       notice_finished_file (file);
!     }
  }
  

Index: variable.c
***************
*** 383,389 ****
  	      register char *p = v->name;
  
! 	      if (v->origin == o_default
! 		  || streq (p, "MAKELEVEL"))
  		continue;
  
  	      if (*p != '_' && (*p < 'A' || *p > 'Z')
--- 383,395 ----
  	      register char *p = v->name;
  
! #ifdef VARS_IN_ENV
! 	      if (v->origin == o_default)
  		continue;
+ #else
+ 	      if ((v->origin != o_env) && (v->origin != o_env_override))
+ 		continue;
+ #endif
+ 	      if (streq (p, "MAKELEVEL"))
+ 		continue;
  
  	      if (*p != '_' && (*p < 'A' || *p > 'Z')

jtc@tessera.UUCP (J.T. Conklin) (10/10/89)

In article <m0gE0aU-0006HMC@ateng.ateng.com> chip@ateng.ateng.com (Chip Salzenberg) writes:
>
>Features:
>    Support a command prefix (default: "\t" unless "-n" flag specified).
>	Prefix is printed before each command.

This is disgusting!  Can you give me one good reason why GNU make's behavior
should changed to match SCO's broken make?  In my opinion, not printing the
tab is a feature, not a bug.

A word of warning: I'll personally strangle the first person that "fixes" gcc
so it prints the name of the file as it compiles it.

    --jtc

-- 
J.T. Conklin
	...!{ubc-cs,uunet}!van-bc!tessera!jtc

ronald@ibmpcug.co.uk (Ronald Khoo) (10/16/89)

In article <m0gE0aU-0006HMC@ateng.ateng.com> chip@ateng.ateng.com (Chip Salzenberg) writes:
> Patches to GNU Make 3.56.  I really hope that these will be adopted into
> the official GNU Make release, since there are a _lot_ of Xenix users out
> there, and I'm tired of porting each Make version.  (:-))
> 
> Features:
>     Port to SCO Xenix/386.

Hmm...  there seem to be a lot of M_XENIX defines in arscan.c already,
but I had to add  this one as well:

*** arscan.c	Mon Jun 19 22:37:37 1989
--- foo.c	Sun Oct 15 21:20:47 1989
***************
*** 176,184 ****
--- 176,190 ----
  	fnval =
  	  (*function) (desc, name, member_offset,
  		       member_offset + sizeof (member_header), eltsize,
+ #ifdef M_XENIX
+ 		       member_header.ar_date,
+ 		       member_header.ar_uid,
+ 		       member_header.ar_gid,
+ #else
  		       atol (member_header.ar_date),
  		       atoi (member_header.ar_uid),
  		       atoi (member_header.ar_gid),
+ #endif
  		       eltmode, arg);
  
  	if (fnval)

Someone *please* reply and tell me I'm not going mad !

-- 
Ronald.Khoo@ibmpcug.CO.UK (The IBM PC User Group, PO Box 360, Harrow HA1 4LQ)
Path: ...!ukc!slxsys!ibmpcug!ronald Phone: +44-1-863 1191 Fax: +44-1-863 6095
$Header: /users/ronald/.signature,v 1.1 89/09/03 23:36:16 ronald Exp $ :-)