[llvm-commits] [parallel] CVS: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/LICENSE.TXT Makefile ar.c arscan.c commands.c commands.h default.c dep.h dir.c expand.c file.c file.h function.c implicit.c job.c job.h load.c main.c make.h misc.c read.c remake.c remote-stub.c remote.c rule.c rule.h variable.c variable.h version.c vpath.c
Misha Brukman
brukman at cs.uiuc.edu
Mon Mar 1 19:05:54 PST 2004
Changes in directory llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make:
LICENSE.TXT added (r1.1.2.1)
Makefile added (r1.2.2.1)
ar.c added (r1.1.2.1)
arscan.c added (r1.1.2.1)
commands.c added (r1.1.2.1)
commands.h added (r1.1.2.1)
default.c added (r1.1.2.1)
dep.h added (r1.1.2.1)
dir.c added (r1.1.2.1)
expand.c added (r1.1.2.1)
file.c added (r1.1.2.1)
file.h added (r1.1.2.1)
function.c added (r1.1.2.1)
implicit.c added (r1.1.2.1)
job.c added (r1.1.2.1)
job.h added (r1.1.2.1)
load.c added (r1.1.2.1)
main.c added (r1.2.2.1)
make.h added (r1.1.2.1)
misc.c added (r1.1.2.1)
read.c added (r1.1.2.1)
remake.c added (r1.1.2.1)
remote-stub.c added (r1.1.2.1)
remote.c added (r1.1.2.1)
rule.c added (r1.1.2.1)
rule.h added (r1.1.2.1)
variable.c added (r1.1.2.1)
variable.h added (r1.1.2.1)
version.c added (r1.1.2.1)
vpath.c added (r1.1.2.1)
---
Log message:
Merge from trunk
---
Diffs of the changes: (+13068 -0)
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/LICENSE.TXT
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/LICENSE.TXT:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/LICENSE.TXT Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,10 ----
+ make - Part of the Malloc Benchmark Suite
+ -------------------------------------------------------------------------------
+ All files are licensed under the LLVM license with the following additions:
+
+ These files are licensed to you under the GNU General Public License (version
+ 2). Redistribution must follow the additional restrictions required by
+ the GPL.
+
+ Please see individiual files for additional copyright information.
+
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/Makefile
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/Makefile:1.2.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/Makefile Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,9 ----
+ LEVEL = ../../../../../..
+ PROG = make
+ CPPFLAGS += -DHAVE_SIGLIST -DNO_LDAV -DNOMEMOPT
+ Source=commands.c job.c dir.c file.c load.c misc.c main.c read.c \
+ remake.c remote.c rule.c implicit.c default.c variable.c expand.c \
+ function.c vpath.c version.c arscan.c ar.c
+
+ RUN_OPTIONS = -n -f $(BUILD_SRC_DIR)/INPUT/GNUmakefile.make USEROPT=BWGC VPATH=$(BUILD_SRC_DIR)
+ include ../../../Makefile.multisrc
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/ar.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/ar.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/ar.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,172 ----
+ /* Copyright (C) 1988-1991 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 2, 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. */
+
+ #include "make.h"
+ #include "file.h"
+
+
+ /* Defined in arscan.c. */
+ extern long int ar_scan ();
+ extern int ar_member_touch ();
+ extern int ar_name_equal ();
+
+
+ /* Return nonzero if NAME is an archive-member reference, zero if not.
+ An archive-member reference is a name like `lib(member)'.
+ If a name like `lib((entry))' is used, a fatal error is signaled at
+ the attempt to use this unsupported feature. */
+
+ int
+ ar_name (name)
+ char *name;
+ {
+ char *p = index (name, '('), *end = name + strlen (name) - 1;
+
+ if (p == 0 || p == name || *end != ')')
+ return 0;
+
+ if (p[1] == '(' && end[-1] == ')')
+ fatal ("attempt to use unsupported feature: `%s'", name);
+
+ return 1;
+ }
+
+
+ /* Parse the archive-member reference NAME into the archive and member names.
+ Put the malloc'd archive name in *ARNAME_P if ARNAME_P is non-nil;
+ put the malloc'd member name in *MEMNAME_P if MEMNAME_P is non-nil. */
+
+ void
+ ar_parse_name (name, arname_p, memname_p)
+ char *name, **arname_p, **memname_p;
+ {
+ char *p = index (name, '('), *end = name + strlen (name) - 1;
+
+ if (arname_p != 0)
+ *arname_p = savestring (name, p - name);
+
+ if (memname_p != 0)
+ *memname_p = savestring (p + 1, end - (p + 1));
+ }
+
+ static long int ar_member_date_1 ();
+
+ /* Return the modtime of NAME. */
+
+ time_t
+ ar_member_date (name)
+ char *name;
+ {
+ char *arname;
+ int arname_used = 0;
+ char *memname;
+ long int val;
+
+ ar_parse_name (name, &arname, &memname);
+
+ /* Make sure we know the modtime of the archive itself because
+ we are likely to be called just before commands to remake a
+ member are run, and they will change the archive itself. */
+ {
+ struct file *arfile;
+ arfile = lookup_file (arname);
+ if (arfile == 0)
+ {
+ arfile = enter_file (arname);
+ arname_used = 1;
+ }
+
+ (void) f_mtime (arfile, 0);
+ }
+
+ val = ar_scan (arname, ar_member_date_1, (long int) memname);
+
+ if (!arname_used)
+ free (arname);
+ free (memname);
+
+ return (val <= 0 ? (time_t) -1 : (time_t) val);
+ }
+
+ /* This function is called by `ar_scan' to find which member to look at. */
+
+ /* ARGSUSED */
+ static long int
+ ar_member_date_1 (desc, mem, hdrpos, datapos, size, date, uid, gid, mode, name)
+ int desc;
+ char *mem;
+ long int hdrpos, datapos, size, date;
+ int uid, gid, mode;
+ char *name;
+ {
+ return ar_name_equal (name, mem) ? date : 0;
+ }
+
+ /* Set the archive-member NAME's modtime to now. */
+
+ int
+ ar_touch (name)
+ char *name;
+ {
+ char *arname, *memname;
+ int arname_used = 0;
+ register int val;
+
+ ar_parse_name (name, &arname, &memname);
+
+ /* Make sure we know the modtime of the archive itself before we
+ touch the member, since this will change the archive itself. */
+ {
+ struct file *arfile;
+ arfile = lookup_file (arname);
+ if (arfile == 0)
+ {
+ arfile = enter_file (arname);
+ arname_used = 1;
+ }
+
+ (void) f_mtime (arfile, 0);
+ }
+
+ val = 1;
+ switch (ar_member_touch (arname, memname))
+ {
+ case -1:
+ error ("touch: Archive `%s' does not exist", arname);
+ break;
+ case -2:
+ error ("touch: `%s' is not a valid archive", arname);
+ break;
+ case -3:
+ perror_with_name ("touch: ", arname);
+ break;
+ case 1:
+ error ("touch: Member `%s' does not exist in `%s'", memname, arname);
+ break;
+ case 0:
+ val = 0;
+ break;
+ default:
+ error ("touch: Bad return code from ar_member_touch on `%s'", name);
+ }
+
+ if (!arname_used)
+ free (arname);
+ free (memname);
+
+ return val;
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/arscan.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/arscan.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/arscan.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,477 ----
+ /* Library function for scanning an archive file.
+ Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
+
+ This program 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 2, or (at your option)
+ any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+ /* On the sun386i and in System V rel 3, ar.h defines two different archive
+ formats depending upon whether you have defined PORTAR (normal) or PORT5AR
+ (System V Release 1). There is no default, one or the other must be defined
+ to have a nonzero value. */
+
+ #if (defined(sun386) || defined(USGr3) || defined(HPUX) \
+ && !defined(PORTAR) && !defined(PORT5AR))
+ #define PORTAR 1
+ #endif
+
+ #include <ar.h>
+ #include <stdio.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+
+ #if defined (USG) || defined (POSIX)
+ #include <fcntl.h>
+ #else
+ #include <sys/file.h>
+ #endif
+
+ #if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) \
+ || defined (POSIX))
+ #include <stdlib.h>
+ #include <string.h>
+ #define ANSI_STRING
+ #else /* No standard headers. */
+
+ #ifdef USG
+
+ #include <string.h>
+ #include <memory.h>
+ #define ANSI_STRING
+
+ #else /* Not USG. */
+ #include <strings.h>
+
+ #ifndef bcmp
+ extern int bcmp ();
+ #endif
+ #ifndef bzero
+ extern void bzero ();
+ #endif
+ #ifndef bcopy
+ extern void bcopy ();
+ #endif
+
+ #endif /* USG. */
+
+ extern char *malloc (), *realloc ();
+ extern void free ();
+
+ #endif /* Standard headers. */
+
+ #ifdef ANSI_STRING
+ #define index(s, c) strchr((s), (c))
+ #define rindex(s, c) strrchr((s), (c))
+
+ #define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
+ #define bzero(s, n) memset ((s), 0, (n))
+ #define bcopy(s, d, n) memcpy ((d), (s), (n))
+ #endif ANSI_STRING
+ #undef ANSI_STRING
+
+
+ #ifndef AIAMAG
+ #if (defined(APOLLO) || defined(HPUX) || defined(hpux) || \
+ (PORTAR == 1 && (defined(USGr3) || defined(u3b2) || defined(sun386))))
+ #define AR_NAMELEN 14
+ #define AR_TRAILING_SLASH /* Member names have a trailing slash. */
+ #else
+ #define AR_NAMELEN 15
+ #endif
+ #else /* AIX. */
+ #define AR_NAMELEN 255
+ #endif
+
+ #if defined(__GNU_LIBRARY__) || defined(POSIX) || defined(_IBMR2)
+ #include <unistd.h>
+ #else
+ extern int read (), open (), close (), write (), fstat ();
+ extern long int lseek (), atol ();
+ extern int atoi ();
+ #endif
+
+ /* Takes three arguments ARCHIVE, FUNCTION and ARG.
+
+ Open the archive named ARCHIVE, find its members one by one,
+ and for each one call FUNCTION with the following arguments:
+ archive file descriptor for reading the data,
+ member name,
+ member header position in file,
+ member data position in file,
+ member data size,
+ member date,
+ member uid,
+ member gid,
+ member protection mode,
+ ARG.
+
+ The descriptor is poised to read the data of the member
+ when FUNCTION is called. It does not matter how much
+ data FUNCTION reads.
+
+ If FUNCTION returns nonzero, we immediately return
+ what FUNCTION returned.
+
+ Returns -1 if archive does not exist,
+ Returns -2 if archive has invalid format.
+ Returns 0 if have scanned successfully. */
+
+ long int
+ ar_scan (archive, function, arg)
+ char *archive;
+ long int (*function) ();
+ long int arg;
+ {
+ #ifdef AIAMAG
+ FL_HDR fl_header;
+ #endif
+ register int desc = open (archive, O_RDONLY, 0);
+ if (desc < 0)
+ return -1;
+ #ifdef SARMAG
+ {
+ char buf[SARMAG];
+ register int nread = read (desc, buf, SARMAG);
+ if (nread != SARMAG || bcmp (buf, ARMAG, SARMAG))
+ {
+ (void) close (desc);
+ return -2;
+ }
+ }
+ #else
+ #ifdef AIAMAG
+ {
+ register int nread = read (desc, &fl_header, FL_HSZ);
+ if (nread != FL_HSZ || bcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
+ {
+ (void) close (desc);
+ return -2;
+ }
+ }
+ #else
+ {
+ #ifndef M_XENIX
+ int buf;
+ #else
+ unsigned short int buf;
+ #endif
+ register int nread = read(desc, &buf, sizeof (buf));
+ if (nread != sizeof (buf) || buf != ARMAG)
+ {
+ (void) close (desc);
+ return -2;
+ }
+ }
+ #endif
+ #endif
+
+ /* Now find the members one by one. */
+ {
+ #ifdef SARMAG
+ register long int member_offset = SARMAG;
+ #else
+ #ifdef AIAMAG
+ long int member_offset;
+ long int last_member_offset;
+
+ sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
+ sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
+ #else
+ #ifndef M_XENIX
+ register long int member_offset = sizeof (int);
+ #else /* Xenix. */
+ register long int member_offset = sizeof (unsigned short int);
+ #endif /* Not Xenix. */
+ #endif
+ #endif
+
+ while (1)
+ {
+ register int nread;
+ struct ar_hdr member_header;
+ #ifdef AIAMAG
+ char name[AR_NAMELEN + 1];
+ int name_len;
+ long int dateval;
+ int uidval, gidval;
+ long int data_offset;
+ #else
+ char name[sizeof member_header.ar_name + 1];
+ #endif
+ long int eltsize;
+ int eltmode;
+ long int fnval;
+
+ if (lseek (desc, member_offset, 0) < 0)
+ {
+ (void) close (desc);
+ return -2;
+ }
+
+ #ifdef AIAMAG
+ #define AR_MEMHDR \
+ (sizeof (member_header) - sizeof (member_header._ar_name))
+ nread = read (desc, (char *) &member_header, AR_MEMHDR);
+
+ if (nread != AR_MEMHDR)
+ {
+ (void) close (desc);
+ return -2;
+ }
+
+ sscanf (member_header.ar_namlen, "%4d", &name_len);
+ nread = read (desc, name, name_len);
+
+ if (nread != name_len)
+ {
+ (void) close (desc);
+ return -2;
+ }
+
+ name[name_len] = 0;
+
+ sscanf (member_header.ar_date, "%12ld", &dateval);
+ sscanf (member_header.ar_uid, "%12d", &uidval);
+ sscanf (member_header.ar_gid, "%12d", &gidval);
+ sscanf (member_header.ar_mode, "%12o", &eltmode);
+ sscanf (member_header.ar_size, "%12ld", &eltsize);
+
+ if ((data_offset = member_offset + AR_MEMHDR + name_len + 2) % 2)
+ ++data_offset;
+
+ fnval =
+ (*function) (desc, name, member_offset, data_offset, eltsize,
+ dateval, uidval, gidval,
+ eltmode, arg);
+
+ #else
+ nread = read (desc, (char *) &member_header, sizeof (struct ar_hdr));
+ if (nread == 0)
+ /* No data left means end of file; that is OK. */
+ break;
+
+ if (nread != sizeof (member_header)
+ #ifdef ARFMAG
+ || bcmp (member_header.ar_fmag, ARFMAG, 2)
+ #endif
+ )
+ {
+ (void) close (desc);
+ return -2;
+ }
+
+ bcopy (member_header.ar_name, name, sizeof member_header.ar_name);
+ {
+ register char *p = name + sizeof member_header.ar_name;
+ while (p > name && *--p == ' ')
+ *p = '\0';
+ #ifdef AR_TRAILING_SLASH
+ if (*p == '/')
+ *p = '\0';
+ #endif
+ }
+
+ #ifndef M_XENIX
+ sscanf (member_header.ar_mode, "%o", &eltmode);
+ eltsize = atol (member_header.ar_size);
+ #else /* Xenix. */
+ eltmode = (unsigned short int) member_header.ar_mode;
+ eltsize = member_header.ar_size;
+ #endif /* Not Xenix. */
+
+ fnval =
+ (*function) (desc, name, member_offset,
+ member_offset + sizeof (member_header), eltsize,
+ #ifndef M_XENIX
+ atol (member_header.ar_date),
+ atoi (member_header.ar_uid),
+ atoi (member_header.ar_gid),
+ #else /* Xenix. */
+ member_header.ar_date,
+ member_header.ar_uid,
+ member_header.ar_gid,
+ #endif /* Not Xenix. */
+ eltmode, arg);
+
+ #endif /* Not AIAMAG */
+
+ if (fnval)
+ {
+ (void) close (desc);
+ return fnval;
+ }
+
+ #ifdef AIAMAG
+ if (member_offset == last_member_offset) /* end of chain? */
+ break;
+
+ sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
+
+ if (lseek (desc, member_offset, 0) != member_offset)
+ {
+ (void) close (desc);
+ return -2;
+ }
+ #else
+ member_offset += sizeof (member_header) + eltsize;
+ if (member_offset & 1) member_offset++;
+ #endif
+ }
+ }
+
+ close (desc);
+ return 0;
+ }
+
+ /* Return nonzero iff NAME matches MEM. If NAME is longer than
+ sizeof (struct ar_hdr.ar_name), MEM may be the truncated version. */
+
+ int
+ ar_name_equal (name, mem)
+ char *name, *mem;
+ {
+ char *p;
+
+ p = rindex (name, '/');
+ if (p != 0)
+ name = p + 1;
+
+ #ifndef APOLLO
+
+ if (!strncmp (name, mem, AR_NAMELEN))
+ return 1;
+
+ if (!strncmp (name, mem, AR_NAMELEN - 2))
+ {
+ unsigned int namelen, memlen;
+
+ namelen = strlen (name);
+ memlen = strlen (mem);
+
+ if (memlen == AR_NAMELEN
+ && mem[AR_NAMELEN - 2] == '.' && mem[AR_NAMELEN - 1] == 'o'
+ && name[namelen - 2] == '.' && name[namelen -1] == 'o')
+ return 1;
+ }
+ return 0;
+
+ #else /* APOLLO. */
+ return !strcmp (name, mem);
+ #endif
+ }
+
+ /* ARGSUSED */
+ static long int
+ ar_member_pos (desc, mem, hdrpos, datapos, size, date, uid, gid, mode, name)
+ int desc;
+ char *mem;
+ long int hdrpos, datapos, size, date;
+ int uid, gid, mode;
+ char *name;
+ {
+ if (!ar_name_equal (name, mem))
+ return 0;
+ return hdrpos;
+ }
+
+ /* Set date of member MEMNAME in archive ARNAME to current time.
+ Returns 0 if successful,
+ -1 if file ARNAME does not exist,
+ -2 if not a valid archive,
+ -3 if other random system call error (including file read-only),
+ 1 if valid but member MEMNAME does not exist. */
+
+ int
+ ar_member_touch (arname, memname)
+ char *arname, *memname;
+ {
+ register long int pos = ar_scan (arname, ar_member_pos, (long int) memname);
+ register int fd;
+ struct ar_hdr ar_hdr;
+ register int i;
+ extern int errno;
+ struct stat statbuf;
+
+ if (pos < 0)
+ return (int) pos;
+ if (!pos)
+ return 1;
+
+ fd = open (arname, O_RDWR, 0666);
+ if (fd < 0)
+ return -3;
+ /* Read in this member's header */
+ if (lseek (fd, pos, 0) < 0)
+ goto lose;
+ if (sizeof ar_hdr != read (fd, (char *) &ar_hdr, sizeof ar_hdr))
+ goto lose;
+ /* Write back the header, thus touching the archive file. */
+ if (lseek (fd, pos, 0) < 0)
+ goto lose;
+ if (sizeof ar_hdr != write (fd, (char *) &ar_hdr, sizeof ar_hdr))
+ goto lose;
+ /* The file's mtime is the time we we want. */
+ fstat (fd, &statbuf);
+ #if defined(ARFMAG) || defined(AIAMAG)
+ /* Advance member's time to that time */
+ for (i = 0; i < sizeof ar_hdr.ar_date; i++)
+ ar_hdr.ar_date[i] = ' ';
+ sprintf (ar_hdr.ar_date, "%ld", (long int) statbuf.st_mtime);
+ #ifdef AIAMAG
+ ar_hdr.ar_date[strlen(ar_hdr.ar_date)] = ' ';
+ #endif
+ #else
+ ar_hdr.ar_date = statbuf.st_mtime;
+ #endif
+ /* Write back this member's header */
+ if (lseek (fd, pos, 0) < 0)
+ goto lose;
+ if (sizeof ar_hdr != write (fd, (char *) &ar_hdr, sizeof ar_hdr))
+ goto lose;
+ close (fd);
+ return 0;
+
+ lose:
+ i = errno;
+ close (fd);
+ errno = i;
+ return -3;
+ }
+
+ #ifdef TEST
+
+ long int
+ describe_member (desc, name, hdrpos, datapos, size, date, uid, gid, mode)
+ int desc;
+ char *name;
+ long int hdrpos, datapos, size, date;
+ int uid, gid, mode;
+ {
+ extern char *ctime ();
+
+ printf ("Member %s: %ld bytes at %ld (%ld).\n", name, size, hdrpos, datapos);
+ printf (" Date %s", ctime (&date));
+ printf (" uid = %d, gid = %d, mode = 0%o.\n", uid, gid, mode);
+
+ return 0;
+ }
+
+ main (argc, argv)
+ int argc;
+ char **argv;
+ {
+ ar_scan (argv[1], describe_member);
+ return 0;
+ }
+
+ #endif /* TEST. */
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/commands.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/commands.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/commands.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,478 ----
+ /* Command processing for GNU Make.
+ Copyright (C) 1988, 1989, 1991 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 2, 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. */
+
+ #include "make.h"
+ #include "dep.h"
+ #include "commands.h"
+ #include "file.h"
+ #include "variable.h"
+ #include "job.h"
+
+ extern int remote_kill ();
+
+ #if !defined(POSIX) && !defined(__GNU_LIBRARY__)
+ extern int getpid ();
+ #endif
+
+ /* Set FILE's automatic variables up. */
+
+ static void
+ set_file_variables (file)
+ register struct file *file;
+ {
+ register char *p;
+ char *at, *percent, *star, *less;
+
+ #define DEFINE_VARIABLE(name, len, value) \
+ (void) define_variable_for_file (name, len, value, o_automatic, 0, file)
+
+ #ifndef NO_ARCHIVES
+ /* If the target is an archive member `lib(member)',
+ then $@ is `lib' and $% is `member'. */
+
+ if (ar_name (file->name))
+ {
+ p = index (file->name, '(');
+ at = savestring (file->name, p - file->name);
+ ++p;
+ percent = savestring (p, strlen (p) - 1);
+ }
+ else
+ #endif /* NO_ARCHIVES. */
+ {
+ at = savestring (file->name, strlen (file->name));
+ percent = "";
+ }
+
+ DEFINE_VARIABLE ("@", 1, at);
+ DEFINE_VARIABLE ("%", 1, percent);
+
+ #define LASTSLASH(s) rindex ((s), '/')
+ #define FILEONLY(s) (p != 0 ? p + 1 : (s))
+ #define DIRONLY(s) (p == 0 ? "./" : p == (s) ? "/" \
+ : savestring ((s), (p - (s)) + 1))
+
+ /* $* is the stem from an implicit or static pattern rule. */
+ if (file->stem == 0)
+ {
+ /* In Unix make, $* is set to the target name with
+ any suffix in the .SUFFIXES list stripped off for
+ explicit rules. We store this in the `stem' member. */
+ register struct dep *d;
+ for (d = enter_file (".SUFFIXES")->deps; d != 0; d = d->next)
+ {
+ unsigned int len = strlen (file->name);
+ unsigned int slen = strlen (dep_name (d));
+ if (len > slen && streq (dep_name (d), file->name + len - slen))
+ {
+ file->stem = savestring (file->name, len - slen);
+ break;
+ }
+ }
+ if (d == 0)
+ file->stem = "";
+ }
+ star = file->stem;
+
+ DEFINE_VARIABLE ("*", 1, star);
+
+ /* $< is the first dependency. */
+ less = file->deps != 0 ? dep_name (file->deps) : "";
+
+ if (file->cmds == default_file->cmds)
+ /* This file got its commands from .DEFAULT.
+ In this case $< is the same as $@. */
+ less = at;
+
+ DEFINE_VARIABLE ("<", 1, less);
+
+ /* Set up the D and F versions. */
+ p = LASTSLASH (at);
+ DEFINE_VARIABLE ("@D", 2, DIRONLY (at));
+ DEFINE_VARIABLE ("@F", 2, FILEONLY (at));
+ p = LASTSLASH (star);
+ DEFINE_VARIABLE ("*D", 2, DIRONLY (star));
+ DEFINE_VARIABLE ("*F", 2, FILEONLY (star));
+ p = LASTSLASH (less);
+ DEFINE_VARIABLE ("<D", 2, DIRONLY (less));
+ DEFINE_VARIABLE ("<F", 2, FILEONLY (less));
+ p = LASTSLASH (percent);
+ DEFINE_VARIABLE ("%D", 2, DIRONLY (percent));
+ DEFINE_VARIABLE ("%F", 2, FILEONLY (percent));
+
+ /* Compute the values for $^ and $? and their F and D versions. */
+
+ {
+ register unsigned int caret_len, qmark_len;
+ char *caret_value, *caretD_value, *caretF_value;
+ register char *cp, *cDp, *cFp;
+ char *qmark_value, *qmarkD_value, *qmarkF_value;
+ register char *qp, *qDp, *qFp;
+ register struct dep *d;
+ unsigned int len;
+
+ caret_len = qmark_len = 0;
+ for (d = file->deps; d != 0; d = d->next)
+ {
+ register unsigned int i = strlen (dep_name (d)) + 1;
+ caret_len += i;
+ if (d->changed)
+ qmark_len += i;
+ }
+
+ len = caret_len == 0 ? 1 : caret_len;
+ cp = caret_value = (char *) xmalloc (len);
+ cDp = caretD_value = (char *) xmalloc (len);
+ cFp = caretF_value = (char *) xmalloc (len);
+ len = qmark_len == 0 ? 1 : qmark_len;
+ qp = qmark_value = (char *) xmalloc (len);
+ qDp = qmarkD_value = (char *) xmalloc (len);
+ qFp = qmarkF_value = (char *) xmalloc (len);
+
+ for (d = file->deps; d != 0; d = d->next)
+ {
+ char *c, *cD, *cF;
+ unsigned int Dlen, Flen;
+
+ c = dep_name (d);
+ len = strlen (c);
+ bcopy (c, cp, len);
+ cp += len;
+ *cp++ = ' ';
+
+ p = LASTSLASH (c);
+ if (p == 0)
+ {
+ cF = c;
+ Flen = len;
+ cD = "./";
+ Dlen = 2;
+ }
+ else if (p == c)
+ {
+ cD = c;
+ Dlen = 1;
+ cF = c + 1;
+ Flen = len - 1;
+ }
+ else
+ {
+ cF = p + 1;
+ Flen = len - (p + 1 - c);
+ cD = c;
+ Dlen = p - c;
+ }
+ bcopy (cD, cDp, Dlen);
+ cDp += Dlen;
+ *cDp++ = ' ';
+ bcopy (cF, cFp, Flen);
+ cFp += Flen;
+ *cFp++ = ' ';
+
+ if (d->changed)
+ {
+ bcopy (c, qp, len);
+ qp += len;
+ *qp++ = ' ';
+ bcopy (cD, qDp, Dlen);
+ qDp += Dlen;
+ *qDp++ = ' ';
+ bcopy (cF, qFp, Flen);
+ qFp += Flen;
+ *qFp++ = ' ';
+ }
+ }
+
+ /* Kill the last spaces and define the variables. */
+
+ cp[cp > caret_value ? -1 : 0] = '\0';
+ DEFINE_VARIABLE ("^", 1, caret_value);
+ cDp[cDp > caretD_value ? -1 : 0] = '\0';
+ DEFINE_VARIABLE ("^D", 2, caretD_value);
+ cFp[cFp > caretF_value ? -1 : 0] = '\0';
+ DEFINE_VARIABLE ("^F", 2, caretF_value);
+
+ qp[qp > qmark_value ? -1 : 0] = '\0';
+ DEFINE_VARIABLE ("?", 1, qmark_value);
+ qDp[qDp > qmarkD_value ? -1 : 0] = '\0';
+ DEFINE_VARIABLE ("?D", 2, qmarkD_value);
+ qFp[qFp > qmarkF_value ? -1 : 0] = '\0';
+ DEFINE_VARIABLE ("?F", 2, qmarkF_value);
+ }
+
+ #undef LASTSLASH
+ #undef FILEONLY
+ #undef DIRONLY
+
+ #undef DEFINE_VARIABLE
+ }
+
+ /* Chop CMDS up into individual command lines if necessary. */
+
+ void
+ chop_commands (cmds)
+ register struct commands *cmds;
+ {
+ if (cmds != 0 && cmds->command_lines == 0)
+ {
+ /* Chop CMDS->commands up into lines in CMDS->command_lines.
+ Also set the corresponding CMDS->lines_recurse elements,
+ and the CMDS->any_recurse flag. */
+ register char *p;
+ unsigned int nlines, idx;
+ char **lines;
+
+ nlines = 5;
+ lines = (char **) xmalloc (5 * sizeof (char *));
+ idx = 0;
+ p = cmds->commands;
+ while (*p != '\0')
+ {
+ char *end = p;
+ find_end:;
+ end = index (end, '\n');
+ if (end == 0)
+ end = p + strlen (p);
+ else if (end > p && end[-1] == '\\')
+ {
+ int backslash = 1;
+ register char *b;
+ for (b = end - 2; b >= p && *b == '\\'; --b)
+ backslash = !backslash;
+ if (backslash)
+ {
+ ++end;
+ goto find_end;
+ }
+ }
+
+ if (idx == nlines)
+ {
+ nlines += 2;
+ lines = (char **) xrealloc ((char *) lines,
+ nlines * sizeof (char *));
+ }
+ lines[idx++] = savestring (p, end - p);
+ p = end;
+ if (*p != '\0')
+ ++p;
+ }
+
+ if (idx != nlines)
+ {
+ nlines = idx;
+ lines = (char **) xrealloc ((char *) lines,
+ nlines * sizeof (char *));
+ }
+
+ cmds->ncommand_lines = nlines;
+ cmds->command_lines = lines;
+
+ cmds->any_recurse = 0;
+ cmds->lines_recurse = (char *) xmalloc (nlines);
+ for (idx = 0; idx < nlines; ++idx)
+ {
+ unsigned int len;
+ int recursive;
+ p = lines[idx];
+ len = strlen (p);
+ recursive = (sindex (p, len, "$(MAKE)", 7) != 0
+ || sindex (p, len, "${MAKE}", 7) != 0);
+ cmds->lines_recurse[idx] = recursive;
+ cmds->any_recurse |= recursive;
+ }
+ }
+ }
+
+ /* Execute the commands to remake FILE. If they are currently executing,
+ return or have already finished executing, just return. Otherwise,
+ fork off a child process to run the first command line in the sequence. */
+
+ void
+ execute_file_commands (file)
+ struct file *file;
+ {
+ register char *p;
+
+ /* Don't go through all the preparations if
+ the commands are nothing but whitespace. */
+
+ for (p = file->cmds->commands; *p != '\0'; ++p)
+ if (!isspace (*p) && *p != '-' && *p != '@')
+ break;
+ if (*p == '\0')
+ {
+ file->update_status = 0;
+ notice_finished_file (file);
+ return;
+ }
+
+ /* First set the automatic variables according to this file. */
+
+ initialize_file_variables (file);
+
+ set_file_variables (file);
+
+ /* Start the commands running. */
+ new_job (file);
+ }
+
+ #define PROPAGATED_SIGNAL_MASK \
+ (sigmask (SIGTERM) | sigmask (SIGINT) | sigmask (SIGHUP) | sigmask (SIGQUIT))
+
+ /* Handle fatal signals. */
+
+ int
+ fatal_error_signal (sig)
+ int sig;
+ {
+ signal (sig, SIG_DFL);
+ #ifndef USG
+ (void) sigsetmask (0);
+ #endif
+
+ /* A termination signal won't be sent to the entire
+ process group, but it means we want to kill the children. */
+
+ if (sig == SIGTERM)
+ {
+ register struct child *c;
+ push_signals_blocked_p (1);
+ for (c = children; c != 0; c = c->next)
+ if (!c->remote)
+ (void) kill (c->pid, SIGTERM);
+ pop_signals_blocked_p ();
+ }
+
+ /* If we got a signal that means the user
+ wanted to kill make, remove pending targets. */
+
+ if (PROPAGATED_SIGNAL_MASK & sigmask (sig))
+ {
+ register struct child *c;
+ push_signals_blocked_p (1);
+
+ /* Remote children won't automatically get signals sent
+ to the process group, so we must send them. */
+ for (c = children; c != 0; c = c->next)
+ if (c->remote)
+ (void) remote_kill (c->pid, sig);
+
+ for (c = children; c != 0; c = c->next)
+ delete_child_targets (c);
+
+ pop_signals_blocked_p ();
+
+ /* Clean up the children. We don't just use the call below because
+ we don't want to print the "Waiting for children" message. */
+ wait_for_children (0, 0);
+ }
+ else
+ /* Wait for our children to die. */
+ wait_for_children (0, 1);
+
+ /* Delete any non-precious intermediate files that were made. */
+
+ remove_intermediates (1);
+
+ if (sig == SIGQUIT)
+ /* We don't want to send ourselves SIGQUIT, because it will
+ cause a core dump. Just exit instead. */
+ exit (1);
+
+ /* Signal the same code; this time it will really be fatal. */
+ if (kill (getpid (), sig) < 0)
+ /* It shouldn't return, but if it does, die anyway. */
+ pfatal_with_name ("kill");
+
+ return 0;
+ }
+
+ /* Delete all non-precious targets of CHILD unless they were already deleted.
+ Set the flag in CHILD to say they've been deleted. */
+
+ void
+ delete_child_targets (child)
+ struct child *child;
+ {
+ struct stat st;
+ struct dep *d;
+
+ if (child->deleted)
+ return;
+
+ /* Delete the file unless it's precious. */
+ if (!child->file->precious
+ && stat (child->file->name, &st) == 0
+ && S_ISREG (st.st_mode)
+ && (time_t) st.st_mtime != child->file->last_mtime)
+ {
+ error ("*** Deleting file `%s'", child->file->name);
+ if (unlink (child->file->name) < 0)
+ perror_with_name ("unlink: ", child->file->name);
+ }
+
+ /* Also remove any non-precious targets listed
+ in the `also_make' member. */
+ for (d = child->file->also_make; d != 0; d = d->next)
+ if (!d->file->precious)
+ if (stat (d->file->name, &st) == 0
+ && S_ISREG (st.st_mode)
+ && (time_t) st.st_mtime != d->file->last_mtime)
+ {
+ error ("*** [%s] Deleting file `%s'", child->file->name,
+ d->file->name);
+ if (unlink (d->file->name) < 0)
+ perror_with_name ("unlink: ", d->file->name);
+ }
+
+ child->deleted = 1;
+ }
+
+ /* Print out the commands in CMDS. */
+
+ void
+ print_commands (cmds)
+ register struct commands *cmds;
+ {
+ register char *s;
+
+ fputs ("# commands to execute", stdout);
+
+ if (cmds->filename == 0)
+ puts (" (built-in):");
+ else
+ printf (" (from `%s', line %u):\n", cmds->filename, cmds->lineno);
+
+ s = cmds->commands;
+ while (*s != '\0')
+ {
+ char *end;
+
+ while (isspace (*s))
+ ++s;
+
+ end = index (s, '\n');
+ if (end == 0)
+ end = s + strlen (s);
+
+ printf ("\t%.*s\n", end - s, s);
+
+ s = end;
+ }
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/commands.h
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/commands.h:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/commands.h Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,36 ----
+ /* Copyright (C) 1988, 1989, 1991 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 2, 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. */
+
+ /* Structure that gives the commands to make a file
+ and information about where these commands came from. */
+
+ struct commands
+ {
+ char *filename; /* File that contains commands. */
+ unsigned int lineno; /* Line number in file. */
+ char *commands; /* Commands text. */
+ unsigned int ncommand_lines;/* Number of command lines. */
+ char **command_lines; /* Commands chopped up into lines. */
+ char *lines_recurse; /* One flag for each line. */
+ char any_recurse; /* Nonzero if any `lines_recurse' elt is. */
+ };
+
+
+ extern void execute_file_commands ();
+ extern void print_commands ();
+ extern void delete_child_targets ();
+ extern void chop_commands ();
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/default.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/default.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/default.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,323 ----
+ /* Data base of default implicit rules for GNU Make.
+ Copyright (C) 1988-1991 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 2, 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. */
+
+ #include "make.h"
+ #include "rule.h"
+ #include "dep.h"
+ #include "file.h"
+ #include "commands.h"
+ #include "variable.h"
+
+
+ /* This is the default list of suffixes for suffix rules.
+ `.s' must come last, so that a `.o' file will be made from
+ a `.c' or `.p' or ... file rather than from a .s file. */
+
+ static char default_suffixes[]
+ = ".out .a .ln .o .c .cc .C .p .f .F .r .y .l .s .S \
+ .mod .sym .def .h .info .dvi .tex .texinfo .texi .cweb .web .sh .elc .el";
+
+ static struct pspec default_pattern_rules[] =
+ {
+ "(%)", "%",
+ "$(AR) $(ARFLAGS) $@ $<",
+
+ /* The X.out rules are only in BSD's default set because
+ BSD Make has no null-suffix rules, so `foo.out' and
+ `foo' are the same thing. */
+ "%.out", "%",
+ "@rm -f $@ \n cp $< $@",
+
+ 0, 0, 0
+ };
+
+ static struct pspec default_terminal_rules[] =
+ {
+ /* RCS. */
+ "%", "%,v",
+ "test -f $@ || $(CO) $(COFLAGS) $< $@",
+ "%", "RCS/%,v",
+ "test -f $@ || $(CO) $(COFLAGS) $< $@",
+
+ /* SCCS. */
+ "%", "s.%",
+ "$(GET) $(GFLAGS) $<",
+ "%", "SCCS/s.%",
+ "$(GET) $(GFLAGS) $<",
+
+ 0, 0, 0
+ };
+
+ static char *default_suffix_rules[] =
+ {
+ ".o",
+ "$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@",
+ ".s",
+ "$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@",
+ ".S",
+ "$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@",
+ ".c",
+ "$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@",
+ ".cc",
+ "$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@",
+ ".C",
+ "$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@",
+ ".f",
+ "$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@",
+ ".p",
+ "$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@",
+ ".F",
+ "$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@",
+ ".r",
+ "$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@",
+ ".mod",
+ "$(COMPILE.mod) -o $@ -e $@ $^",
+
+ ".def.sym",
+ "$(COMPILE.def) -o $@ $<",
+
+ ".sh",
+ "cat $< >$@ \n chmod a+x $@",
+
+ ".s.o",
+ #if !defined(M_XENIX) || defined(__GNUC__)
+ "$(COMPILE.s) -o $@ $<",
+ #else /* Xenix. */
+ "$(COMPILE.s) -o$@ $<",
+ #endif /* Not Xenix. */
+ ".S.o",
+ #if !defined(M_XENIX) || defined(__GNUC__)
+ "$(COMPILE.S) -o $@ $<",
+ #else /* Xenix. */
+ "$(COMPILE.S) -o$@ $<",
+ #endif /* Not Xenix. */
+ ".c.o",
+ "$(COMPILE.c) $< $(OUTPUT_OPTION)",
+ ".cc.o",
+ "$(COMPILE.cc) $< $(OUTPUT_OPTION)",
+ ".C.o",
+ "$(COMPILE.C) $< $(OUTPUT_OPTION)",
+ ".f.o",
+ "$(COMPILE.f) $< $(OUTPUT_OPTION)",
+ ".p.o",
+ "$(COMPILE.p) $< $(OUTPUT_OPTION)",
+ ".F.o",
+ "$(COMPILE.F) $< $(OUTPUT_OPTION)",
+ ".r.o",
+ "$(COMPILE.r) $< $(OUTPUT_OPTION)",
+ ".mod.o",
+ "$(COMPILE.mod) -o $@ $<",
+
+ ".c.ln",
+ "$(LINT.c) -C$* $<",
+ ".y.ln",
+ "$(YACC.y) $< \n $(LINT.c) -C$* y.tab.c \n $(RM) y.tab.c",
+ ".l.ln",
+ "@$(RM) $*.c \n $(LEX.l) $< > $*.c \n\
+ $(LINT.c) -i $*.c -o $@ \n $(RM) $*.c",
+
+ ".y.c",
+ "$(YACC.y) $< \n mv -f y.tab.c $@",
+ ".l.c",
+ "@$(RM) $@ \n $(LEX.l) $< > $@",
+
+ ".F.f",
+ "$(PREPROCESS.F) $< $(OUTPUT_OPTION)",
+ ".r.f",
+ "$(PREPROCESS.r) $< $(OUTPUT_OPTION)",
+
+ /* This might actually make lex.yy.c if there's no %R%
+ directive in $*.l, but in that case why were you
+ trying to make $*.r anyway? */
+ ".l.r",
+ "$(LEX.l) $< > $@ \n mv -f lex.yy.r $@",
+
+ ".S.s",
+ "$(PREPROCESS.S) $< > $@",
+
+ ".texinfo.info",
+ "$(MAKEINFO) $<",
+
+ ".texi.info",
+ "$(MAKEINFO) $<",
+
+ ".tex.dvi",
+ "$(TEX) $<",
+
+ ".texinfo.dvi",
+ "$(TEXI2DVI) $<",
+
+ ".texi.dvi",
+ "$(TEXI2DVI) $<",
+
+ ".cweb.c",
+ "$(CTANGLE) $<",
+
+ ".web.p",
+ "$(TANGLE) $<",
+
+ ".cweb.tex",
+ "$(CWEAVE) $<",
+
+ ".web.tex",
+ "$(WEAVE) $<",
+
+ 0}
+ ;
+
+ static char *default_variables[] =
+ {
+ "AR", "ar",
+ "ARFLAGS", "rv",
+ "AS", "as",
+ "CC", "cc",
+ "C++", "g++",
+ "CO", "co",
+ "CPP", "$(CC) -E",
+ "FC", "f77",
+ /* System V uses these, so explicit rules using them should work.
+ However, there is no way to make implicit rules use them and FC. */
+ "F77", "$(FC)",
+ "F77FLAGS", "$(FFLAGS)",
+ #ifdef USG
+ "GET", "get",
+ #else
+ "GET", "/usr/sccs/get",
+ #endif
+ "LD", "ld",
+ "LEX", "lex",
+ "LINT", "lint",
+ "M2C", "m2c",
+ #ifdef pyr
+ "PC", "pascal",
+ #else
+ "PC", "pc",
+ #endif
+ "YACC", "yacc", /* Or "bison -y" */
+ "MAKEINFO", "makeinfo",
+ "TEX", "tex",
+ "TEXI2DVI", "texi2dvi",
+ "WEAVE", "weave",
+ "CWEAVE", "cweave",
+ "TANGLE", "tangle",
+ "CTANGLE", "ctangle",
+
+ "RM", "rm -f",
+
+ "LINK.o", "$(CC) $(LDFLAGS) $(TARGET_ARCH)",
+ "COMPILE.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c",
+ "LINK.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)",
+ "COMPILE.cc", "$(C++) $(C++FLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c",
+ "COMPILE.C", "$(COMPILE.cc)",
+ "LINK.cc", "$(C++) $(C++FLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)",
+ "LINK.C", "$(LINK.cc)",
+ "YACC.y", "$(YACC) $(YFLAGS)",
+ "LEX.l", "$(LEX) $(LFLAGS) -t",
+ "COMPILE.f", "$(FC) $(FFLAGS) $(TARGET_ARCH) -c",
+ "LINK.f", "$(FC) $(FFLAGS) $(LDFLAGS) $(TARGET_ARCH)",
+ "COMPILE.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c",
+ "LINK.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)",
+ "COMPILE.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -c",
+ "LINK.r", "$(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) $(TARGET_ARCH)",
+ "COMPILE.def", "$(M2C) $(M2FLAGS) $(DEFFLAGS) $(TARGET_ARCH)",
+ "COMPILE.mod", "$(M2C) $(M2FLAGS) $(MODFLAGS) $(TARGET_ARCH)",
+ "COMPILE.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c",
+ "LINK.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)",
+ "LINK.s", "$(CC) $(ASFLAGS) $(LDFLAGS) $(TARGET_MACH)",
+ "COMPILE.s", "$(AS) $(ASFLAGS) $(TARGET_MACH)",
+ "LINK.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)",
+ "COMPILE.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c",
+ #if !defined(M_XENIX) || defined(__GNUC__)
+ "PREPROCESS.S", "$(CC) -E $(CPPFLAGS)",
+ #else /* Xenix. */
+ "PREPROCESS.S", "$(CC) -EP $(CPPFLAGS)",
+ #endif /* Not Xenix. */
+ "PREPROCESS.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F",
+ "PREPROCESS.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F",
+ "LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
+
+ #ifndef NO_MINUS_C_MINUS_O
+ #if !defined(M_XENIX) || defined(__GNUC__)
+ "OUTPUT_OPTION", "-o $@",
+ #else /* Xenix. */
+ "OUTPUT_OPTION", "-Fo$@",
+ #endif /* Not Xenix. */
+ #endif
+
+ 0, 0
+ };
+
+ /* Set up the default .SUFFIXES list. */
+
+ void
+ set_default_suffixes ()
+ {
+ suffix_file = enter_file (".SUFFIXES");
+
+ if (no_builtin_rules_flag)
+ (void) define_variable ("SUFFIXES", 8, "", o_default, 0);
+ else
+ {
+ char *p = default_suffixes;
+ suffix_file->deps = (struct dep *)
+ multi_glob (parse_file_seq (&p, '\0', sizeof (struct dep)),
+ sizeof (struct dep));
+ (void) define_variable ("SUFFIXES", 8, default_suffixes, o_default, 0);
+ }
+ }
+
+ /* Install the default pattern rules and enter
+ the default suffix rules as file rules. */
+
+ void
+ install_default_implicit_rules ()
+ {
+ register struct pspec *p;
+ register char **s;
+
+ if (no_builtin_rules_flag)
+ return;
+
+ for (p = default_pattern_rules; p->target != 0; ++p)
+ install_pattern_rule (p, 0);
+
+ for (p = default_terminal_rules; p->target != 0; ++p)
+ install_pattern_rule (p, 1);
+
+ for (s = default_suffix_rules; *s != 0; s += 2)
+ {
+ register struct file *f = enter_file (s[0]);
+ /* Don't clobber cmds given in a makefile if there were any. */
+ if (f->cmds == 0)
+ {
+ f->cmds = (struct commands *) xmalloc (sizeof (struct commands));
+ f->cmds->filename = 0;
+ f->cmds->commands = s[1];
+ f->cmds->command_lines = 0;
+ }
+ }
+ }
+
+ void
+ define_default_variables ()
+ {
+ register char **s;
+
+ for (s = default_variables; *s != 0; s += 2)
+ (void) define_variable (s[0], strlen (s[0]), s[1], o_default, 1);
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/dep.h
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/dep.h:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/dep.h Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,50 ----
+ /* Copyright (C) 1988, 1989, 1991 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 2, 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. */
+
+ /* Structure representing one dependency of a file.
+ Each struct file's `deps' points to a chain of these,
+ chained through the `next'.
+
+ Note that the first three words of this match a struct nameseq. */
+
+ struct dep
+ {
+ struct dep *next;
+ char *name;
+ struct file *file;
+ int changed;
+ };
+
+
+ /* Structure used in chains of names, for parsing and globbing */
+
+ struct nameseq
+ {
+ struct nameseq *next;
+ char *name;
+ };
+
+
+ extern struct nameseq *multi_glob (), *parse_file_seq ();
+
+
+ #ifndef iAPX286
+ #define dep_name(d) ((d)->name == 0 ? (d)->file->name : (d)->name)
+ #else
+ /* Buggy compiler can't hack this. */
+ extern char *dep_name ();
+ #endif
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/dir.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/dir.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/dir.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,401 ----
+ /* Directory hashing for GNU Make.
+ Copyright (C) 1988, 1989, 1991 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 2, 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. */
+
+ #include "make.h"
+
+ #if defined (USGr3) && !defined (DIRENT)
+ #define DIRENT
+ #endif /* USGr3 */
+ #if defined (Xenix) && !defined (SYSNDIR)
+ #define SYSNDIR
+ #endif /* Xenix */
+
+ #if defined (POSIX) || defined (DIRENT) || defined (__GNU_LIBRARY__)
+ #include <dirent.h>
+ #define direct dirent
+ #define D_NAMLEN(d) strlen((d)->d_name)
+ #else /* not POSIX or DIRENT */
+ #define D_NAMLEN(d) ((d)->d_namlen)
+ #if defined (USG) && !defined (sgi)
+ #if defined (SYSNDIR)
+ #include <sys/ndir.h>
+ #else /* SYSNDIR */
+ #include "ndir.h"
+ #endif /* not SYSNDIR */
+ #else /* not USG */
+ #include <sys/dir.h>
+ #endif /* USG */
+ #endif /* POSIX or DIRENT or __GNU_LIBRARY__ */
+
+ #if defined (POSIX) && !defined (__GNU_LIBRARY__)
+ /* Posix does not require that the d_ino field be present, and some
+ systems do not provide it. */
+ #define REAL_DIR_ENTRY(dp) 1
+ #else
+ #define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
+ #endif /* POSIX */
+
+ /* Hash table of directories. */
+
+ struct directory
+ {
+ struct directory *next;
+ char *name; /* Name of the directory. */
+ struct dirfile **files; /* Files in this directory. */
+ DIR *dirstream; /* Stream reading this directory. */
+ };
+
+ #ifndef DIRECTORY_BUCKETS
+ #define DIRECTORY_BUCKETS 23
+ #endif
+
+ static struct directory *directories[DIRECTORY_BUCKETS];
+
+
+ /* Never have more than this many directories open at once. */
+
+ #define MAX_OPEN_DIRECTORIES 10
+
+ static unsigned int open_directories = 0;
+
+
+ /* Hash table of files in each directory. */
+
+ struct dirfile
+ {
+ struct dirfile *next;
+ char *name; /* Name of the file. */
+ char impossible; /* This file is impossible. */
+ };
+
+ #ifndef DIRFILE_BUCKETS
+ #define DIRFILE_BUCKETS 1007
+ #endif
+
+ /* Find the directory named NAME and return its `struct directory'. */
+
+ static struct directory *
+ find_directory (name)
+ register char *name;
+ {
+ register unsigned int hash = 0;
+ register char *p;
+ register struct directory *dir;
+
+ for (p = name; *p != '\0'; ++p)
+ HASH (hash, *p);
+ hash %= DIRECTORY_BUCKETS;
+
+ for (dir = directories[hash]; dir != 0; dir = dir->next)
+ if (streq (dir->name, name))
+ break;
+
+ if (dir == 0)
+ {
+ /* The directory was not found. Create a new entry
+ for it and start its directory stream reading. */
+ dir = (struct directory *) xmalloc (sizeof (struct directory));
+ dir->next = directories[hash];
+ directories[hash] = dir;
+ dir->name = savestring (name, p - name);
+ dir->dirstream = opendir (name);
+ if (dir->dirstream == 0)
+ /* Couldn't open the directory. Mark this by
+ setting the `files' member to a nil pointer. */
+ dir->files = 0;
+ else
+ {
+ /* Allocate an array of hash buckets for files and zero it. */
+ dir->files = (struct dirfile **)
+ xmalloc (sizeof (struct dirfile) * DIRFILE_BUCKETS);
+ bzero ((char *) dir->files,
+ sizeof (struct dirfile) * DIRFILE_BUCKETS);
+
+ /* Keep track of how many directories are open. */
+ ++open_directories;
+ if (open_directories == MAX_OPEN_DIRECTORIES)
+ /* Read the entire directory and then close it. */
+ (void) dir_file_exists_p (dir->name, (char *) 0);
+ }
+ }
+
+ return dir;
+ }
+
+ /* Return 1 if the name FILENAME in directory DIRNAME
+ is entered in the dir hash table.
+ FILENAME must contain no slashes. */
+
+ int
+ dir_file_exists_p (dirname, filename)
+ register char *dirname;
+ register char *filename;
+ {
+ register unsigned int hash;
+ register char *p;
+ register struct directory *dir;
+ register struct dirfile *df;
+ register struct direct *d;
+ dir = find_directory (dirname);
+
+ if (dir->files == 0)
+ /* The directory could not be opened. */
+ return 0;
+
+ hash = 0;
+ if (filename != 0)
+ {
+ if (*filename == '\0')
+ /* Checking if the directory exists. */
+ return 1;
+
+ for (p = filename; *p != '\0'; ++p)
+ HASH (hash, *p);
+ hash %= DIRFILE_BUCKETS;
+
+ /* Search the list of hashed files. */
+
+ for (df = dir->files[hash]; df != 0; df = df->next)
+ if (streq (df->name, filename))
+ return !df->impossible;
+ }
+
+ /* The file was not found in the hashed list.
+ Try to read the directory further. */
+
+ if (dir->dirstream == 0)
+ /* The directory has been all read in. */
+ return 0;
+
+ while ((d = readdir (dir->dirstream)) != 0)
+ {
+ /* Enter the file in the hash table. */
+ register unsigned int newhash = 0;
+ register unsigned int i;
+
+ if (!REAL_DIR_ENTRY (d))
+ continue;
+
+ for (i = 0; i < D_NAMLEN(d); ++i)
+ HASH (newhash, d->d_name[i]);
+ newhash %= DIRFILE_BUCKETS;
+
+ df = (struct dirfile *) xmalloc (sizeof (struct dirfile));
+ df->next = dir->files[newhash];
+ dir->files[newhash] = df;
+ df->name = savestring (d->d_name, D_NAMLEN(d));
+ df->impossible = 0;
+
+ /* Check if the name matches the one we're searching for. */
+ if (filename != 0
+ && newhash == hash && streq (d->d_name, filename))
+ return 1;
+ }
+
+ /* If the directory has been completely read in,
+ close the stream and reset the pointer to nil. */
+ if (d == 0)
+ {
+ --open_directories;
+ closedir (dir->dirstream);
+ dir->dirstream = 0;
+ }
+
+ return 0;
+ }
+
+ /* Return 1 if the file named NAME exists. */
+
+ int
+ file_exists_p (name)
+ register char *name;
+ {
+ char *dirend;
+ char *dirname;
+
+ #ifndef NO_ARCHIVES
+ if (ar_name (name))
+ return ar_member_date (name) != (time_t) -1;
+ #endif
+
+ dirend = rindex (name, '/');
+ if (dirend == 0)
+ return dir_file_exists_p (".", name);
+
+ dirname = (char *) alloca (dirend - name + 1);
+ bcopy (name, dirname, dirend - name);
+ dirname[dirend - name] = '\0';
+ return dir_file_exists_p (dirname, dirend + 1);
+ }
+
+ /* Mark FILENAME as `impossible' for `file_impossible_p'.
+ This means an attempt has been made to search for FILENAME
+ as an intermediate file, and it has failed. */
+
+ void
+ file_impossible (filename)
+ register char *filename;
+ {
+ char *dirend;
+ register char *p = filename;
+ register unsigned int hash;
+ register struct directory *dir;
+ register struct dirfile *new;
+
+ dirend = rindex (p, '/');
+ if (dirend == 0)
+ dir = find_directory (".");
+ else
+ {
+ char *dirname = (char *) alloca (dirend - p + 1);
+ bcopy (p, dirname, dirend - p);
+ dirname[dirend - p] = '\0';
+ dir = find_directory (dirname);
+ filename = p = dirend + 1;
+ }
+
+ for (hash = 0; *p != '\0'; ++p)
+ HASH (hash, *p);
+ hash %= DIRFILE_BUCKETS;
+
+ if (dir->files == 0)
+ {
+ /* The directory was not opened; we must allocate the hash buckets. */
+ dir->files = (struct dirfile **)
+ xmalloc (sizeof (struct dirfile) * DIRFILE_BUCKETS);
+ bzero ((char *) dir->files, sizeof (struct dirfile) * DIRFILE_BUCKETS);
+ }
+
+ /* Make a new entry and put it in the table. */
+
+ new = (struct dirfile *) xmalloc (sizeof (struct dirfile));
+ new->next = dir->files[hash];
+ dir->files[hash] = new;
+ new->name = savestring (filename, strlen (filename));
+ new->impossible = 1;
+ }
+
+ /* Return nonzero if FILENAME has been marked impossible. */
+
+ int
+ file_impossible_p (filename)
+ char *filename;
+ {
+ char *dirend;
+ register char *p = filename;
+ register unsigned int hash;
+ register struct directory *dir;
+ register struct dirfile *next;
+
+ dirend = rindex (filename, '/');
+ if (dirend == 0)
+ dir = find_directory (".");
+ else
+ {
+ char *dirname = (char *) alloca (dirend - filename + 1);
+ bcopy (p, dirname, dirend - p);
+ dirname[dirend - p] = '\0';
+ dir = find_directory (dirname);
+ p = dirend + 1;
+ }
+
+ if (dir->files == 0)
+ /* There are no files entered for this directory. */
+ return 0;
+
+ for (hash = 0; *p != '\0'; ++p)
+ HASH (hash, *p);
+ hash %= DIRFILE_BUCKETS;
+
+ for (next = dir->files[hash]; next != 0; next = next->next)
+ if (streq (filename, next->name))
+ return next->impossible;
+
+ return 0;
+ }
+
+ /* Return the already allocated name in the
+ directory hash table that matches DIR. */
+
+ char *
+ dir_name (dir)
+ char *dir;
+ {
+ return find_directory (dir)->name;
+ }
+
+ /* Print the data base of directories. */
+
+ void
+ print_dir_data_base ()
+ {
+ register unsigned int i, dirs, files, impossible;
+ register struct directory *dir;
+
+ puts ("\n# Directories\n");
+
+ dirs = files = impossible = 0;
+ for (i = 0; i < DIRECTORY_BUCKETS; ++i)
+ for (dir = directories[i]; dir != 0; dir = dir->next)
+ {
+ ++dirs;
+ if (dir->files == 0)
+ printf ("# %s: could not be opened.\n", dir->name);
+ else
+ {
+ register unsigned int f = 0, im = 0;
+ register unsigned int j;
+ register struct dirfile *df;
+ for (j = 0; j < DIRFILE_BUCKETS; ++j)
+ for (df = dir->files[j]; df != 0; df = df->next)
+ if (df->impossible)
+ ++im;
+ else
+ ++f;
+ printf ("# %s: ", dir->name);
+ if (f == 0)
+ fputs ("No", stdout);
+ else
+ printf ("%u", f);
+ fputs (" files, ", stdout);
+ if (im == 0)
+ fputs ("no", stdout);
+ else
+ printf ("%u", im);
+ fputs (" impossibilities", stdout);
+ if (dir->dirstream == 0)
+ puts (".");
+ else
+ puts (" so far.");
+ files += f;
+ impossible += im;
+ }
+ }
+
+ fputs ("\n# ", stdout);
+ if (files == 0)
+ fputs ("No", stdout);
+ else
+ printf ("%u", files);
+ fputs (" files, ", stdout);
+ if (impossible == 0)
+ fputs ("no", stdout);
+ else
+ printf ("%u", impossible);
+ printf (" impossibilities in %u directories.\n", dirs);
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/expand.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/expand.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/expand.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,342 ----
+ /* Variable expansion functions for GNU Make.
+ Copyright (C) 1988, 1989, 1991 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 2, 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. */
+
+ #include "make.h"
+ #include "commands.h"
+ #include "file.h"
+ #include "variable.h"
+
+
+ /* Recursively expand V. The returned string is malloc'd. */
+
+ static char *
+ recursively_expand (v)
+ register struct variable *v;
+ {
+ char *value;
+
+ if (v->expanding)
+ {
+ /* Expanding V causes infinite recursion. Lose. */
+ if (reading_filename == 0)
+ fatal ("Recursive variable `%s' references itself (eventually)",
+ v->name);
+ else
+ makefile_fatal
+ (reading_filename, *reading_lineno_ptr,
+ "Recursive variable `%s' references itself (eventually)",
+ v->name);
+ }
+
+ v->expanding = 1;
+ value = allocated_variable_expand (v->value);
+ v->expanding = 0;
+
+ return value;
+ }
+
+ /* Scan LINE for variable references and expansion-function calls.
+ Build in `variable_buffer' the result of expanding the references and calls.
+ Return the address of the resulting string, which is null-terminated
+ and is valid only until the next time this function is called. */
+
+ char *
+ variable_expand (line)
+ register char *line;
+ {
+ register struct variable *v;
+ register char *p, *o, *p1;
+
+ p = line;
+ o = initialize_variable_output ();
+
+ while (1)
+ {
+ /* Copy all following uninteresting chars all at once to the
+ variable output buffer, and skip them. Uninteresting chars end
+ at the next $ or the end of the input. */
+
+ p1 = index (p, '$');
+
+ o = variable_buffer_output (o, p, p1 != 0 ? p1 - p : strlen (p) + 1);
+
+ if (p1 == 0)
+ break;
+ p = p1 + 1;
+
+ /* Dispatch on the char that follows the $. */
+
+ switch (*p)
+ {
+ case '$':
+ /* $$ seen means output one $ to the variable output buffer. */
+ o = variable_buffer_output (o, p, 1);
+ break;
+
+ case '(':
+ case '{':
+ /* $(...) or ${...} is the general case of substitution. */
+ {
+ char openparen = *p;
+ char closeparen = (openparen == '(') ? ')' : '}';
+ register char *beg = p + 1;
+ char *op, *begp;
+ char *end;
+
+ op = o;
+ begp = p;
+ if (handle_function (&op, &begp))
+ {
+ o = op;
+ p = begp;
+ break;
+ }
+
+ /* Is there a variable reference inside the parens or braces?
+ If so, expand it before expanding the entire reference. */
+
+ p1 = index (beg, closeparen);
+ if (p1 != 0)
+ p1 = lindex (beg, p1, '$');
+ if (p1 != 0)
+ {
+ /* BEG now points past the opening paren or brace.
+ Count parens or braces until it is matched. */
+ int count = 0;
+ for (p = beg; *p != '\0'; ++p)
+ {
+ if (*p == openparen)
+ ++count;
+ else if (*p == closeparen && --count < 0)
+ break;
+ }
+ /* If count is >= 0, there were unmatched opening parens
+ or braces, so we go to the simple case of a variable name
+ such as `$($(a)'. */
+ if (count < 0)
+ {
+ char *name = expand_argument (beg, p);
+ static char start[3] = { '$', }, end[2];
+ start[1] = openparen;
+ end[0] = closeparen;
+ p1 = concat (start, name, end);
+ free (name);
+ name = allocated_variable_expand (p1);
+ o = variable_buffer_output (o, name, strlen (name));
+ free (name);
+ break;
+ }
+ }
+
+ /* This is not a reference to a built-in function and
+ it does not contain any variable references inside.
+ There are several things it could be. */
+
+ p = index (beg, ':');
+ if (p != 0 && lindex (beg, p, closeparen) == 0)
+ {
+ /* This is a substitution reference: $(FOO:A=B). */
+ int count;
+ char *subst_beg, *replace_beg;
+ unsigned int subst_len, replace_len;
+
+ v = lookup_variable (beg, p - beg);
+
+ subst_beg = p + 1;
+ count = 0;
+ for (p = subst_beg; *p != '\0'; ++p)
+ {
+ if (*p == openparen)
+ ++count;
+ else if (*p == closeparen)
+ --count;
+ else if (*p == '=' && count <= 0)
+ break;
+ }
+ if (count > 0)
+ /* There were unmatched opening parens. */
+ return initialize_variable_output ();
+ subst_len = p - subst_beg;
+
+ replace_beg = p + 1;
+ count = 0;
+ for (p = replace_beg; *p != '\0'; ++p)
+ {
+ if (*p == openparen)
+ ++count;
+ else if (*p == closeparen && --count < 0)
+ break;
+ }
+ if (count > 0)
+ /* There were unmatched opening parens. */
+ return initialize_variable_output ();
+ end = p;
+ replace_len = p - replace_beg;
+
+ if (v != 0 && *v->value != '\0')
+ {
+ char *value = (v->recursive ? recursively_expand (v)
+ : v->value);
+ if (lindex (subst_beg, subst_beg + subst_len, '%') != 0)
+ {
+ p = savestring (subst_beg, subst_len);
+ p1 = savestring (replace_beg, replace_len);
+ o = patsubst_expand (o, value, p, p1,
+ index (p, '%'), index (p1, '%'));
+ free (p);
+ free (p1);
+ }
+ else
+ o = subst_expand (o, value, subst_beg, replace_beg,
+ subst_len, replace_len, 0, 1);
+ if (v->recursive)
+ free (value);
+ }
+ }
+
+ /* No, this must be an ordinary variable reference. */
+ else
+ {
+ /* Look up the value of the variable. */
+ end = index (beg, closeparen);
+ if (end == 0)
+ return initialize_variable_output ();
+ v = lookup_variable (beg, end - beg);
+
+ if (v != 0 && *v->value != '\0')
+ {
+ char *value = (v->recursive ? recursively_expand (v)
+ : v->value);
+ o = variable_buffer_output (o, value, strlen (value));
+ if (v->recursive)
+ free (value);
+ }
+ }
+
+ /* Advance p past the variable reference to resume scan. */
+ p = end;
+ }
+ break;
+
+ case '\0':
+ break;
+
+ default:
+ if (isblank (p[-1]))
+ break;
+
+ /* A $ followed by a random char is a variable reference:
+ $a is equivalent to $(a). */
+ {
+ /* We could do the expanding here, but this way
+ avoids code repetition at a small performance cost. */
+ char name[5];
+ name[0] = '$';
+ name[1] = '(';
+ name[2] = *p;
+ name[3] = ')';
+ name[4] = '\0';
+ p1 = allocated_variable_expand (name);
+ o = variable_buffer_output (o, p1, strlen (p1));
+ free (p1);
+ }
+
+ break;
+ }
+
+ if (*p == '\0')
+ break;
+ else
+ ++p;
+ }
+
+ (void) variable_buffer_output (o, "", 1);
+ return initialize_variable_output ();
+ }
+
+ /* Expand an argument for an expansion function.
+ The text starting at STR and ending at END is variable-expanded
+ into a null-terminated string that is returned as the value.
+ This is done without clobbering `variable_buffer' or the current
+ variable-expansion that is in progress. */
+
+ char *
+ expand_argument (str, end)
+ char *str, *end;
+ {
+ char *tmp = savestring (str, end - str);
+ char *value = allocated_variable_expand (tmp);
+
+ free (tmp);
+
+ return value;
+ }
+
+ /* Expand LINE for FILE. Error messages refer to the file and line where
+ FILE's commands were found. Expansion uses FILE's variable set list. */
+
+ char *
+ variable_expand_for_file (line, file)
+ char *line;
+ register struct file *file;
+ {
+ char *result;
+ struct variable_set_list *save;
+
+ if (file == 0)
+ return variable_expand (line);
+
+ save = current_variable_set_list;
+ current_variable_set_list = file->variables;
+ reading_filename = file->cmds->filename;
+ reading_lineno_ptr = &file->cmds->lineno;
+ result = variable_expand (line);
+ current_variable_set_list = save;
+ reading_filename = 0;
+ reading_lineno_ptr = 0;
+
+ return result;
+ }
+
+ /* Like variable_expand, but the returned string is malloc'd. */
+ char *
+ allocated_variable_expand (line)
+ char *line;
+ {
+ return allocated_variable_expand_for_file (line, (struct file *) 0);
+ }
+
+ /* Like variable_expand_for_file, but the returned string is malloc'd. */
+
+ char *
+ allocated_variable_expand_for_file (line, file)
+ char *line;
+ struct file *file;
+ {
+ char *save;
+ char *value;
+
+ save = save_variable_output ();
+
+ value = variable_expand_for_file (line, file);
+ value = savestring (value, strlen (value));
+
+ restore_variable_output (save);
+
+ return value;
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/file.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/file.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/file.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,472 ----
+ /* Copyright (C) 1988, 1989, 1990, 1991 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 2, 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. */
+
+ #include "make.h"
+ #include "commands.h"
+ #include "dep.h"
+ #include "file.h"
+ #include "variable.h"
+ #include <errno.h>
+
+
+ extern int errno;
+
+
+ /* Hash table of files the makefile knows how to make. */
+
+ #ifndef FILE_BUCKETS
+ #define FILE_BUCKETS 1007
+ #endif
+ static struct file *files[FILE_BUCKETS];
+
+ /* Number of files with the `intermediate' flag set. */
+
+ unsigned int num_intermediates = 0;
+
+
+ /* Access the hash table of all file records.
+ lookup_file given a name, return the struct file * for that name,
+ or nil if there is none.
+ enter_file similar, but create one if there is none. */
+
+ struct file *
+ lookup_file (name)
+ char *name;
+ {
+ register struct file *f;
+ register char *n;
+ register unsigned int hashval;
+
+ if (*name == '\0')
+ abort ();
+
+ while (name[0] == '.' && name[1] == '/' && name[2] != '\0')
+ name += 2;
+
+ hashval = 0;
+ for (n = name; *n != '\0'; ++n)
+ HASH (hashval, *n);
+ hashval %= FILE_BUCKETS;
+
+ for (f = files[hashval]; f != 0; f = f->next)
+ if (streq (f->name, name))
+ return f;
+ return 0;
+ }
+
+ struct file *
+ enter_file (name)
+ char *name;
+ {
+ register struct file *f, *new;
+ register char *n;
+ register unsigned int hashval;
+
+ if (*name == '\0')
+ abort ();
+
+ while (name[0] == '.' && name[1] == '/' && name[2] != '\0')
+ name += 2;
+
+ hashval = 0;
+ for (n = name; *n != '\0'; ++n)
+ HASH (hashval, *n);
+ hashval %= FILE_BUCKETS;
+
+ for (f = files[hashval]; f != 0; f = f->next)
+ if (streq (f->name, name))
+ break;
+
+ if (f != 0 && !f->double_colon)
+ return f;
+
+ new = (struct file *) xmalloc (sizeof (struct file));
+ bzero ((char *) new, sizeof (struct file));
+ new->name = name;
+ new->update_status = -1;
+
+ if (f == 0)
+ {
+ /* This is a completely new file. */
+ new->next = files[hashval];
+ files[hashval] = new;
+ }
+ else
+ {
+ /* There is already a double-colon entry for this file. */
+ while (f->prev != 0)
+ f = f->prev;
+ f->prev = new;
+ }
+
+ return new;
+ }
+
+ /* Rename FILE to NAME. This is not as simple as resetting
+ the `name' member, since it must be put in a new hash bucket,
+ and possibly merged with an existing file called NAME. */
+
+ void
+ rename_file (file, name)
+ register struct file *file;
+ char *name;
+ {
+ char *oldname = file->name;
+ register unsigned int oldhash, newhash;
+ register char *n;
+ register struct file *f;
+ struct file *oldfile;
+
+ /* Find the hash values of the old and new names. */
+
+ oldhash = 0;
+ for (n = oldname; *n != '\0'; ++n)
+ HASH (oldhash, *n);
+ oldhash %= FILE_BUCKETS;
+
+ newhash = 0;
+ for (n = name; *n != '\0'; ++n)
+ HASH (newhash, *n);
+ newhash %= FILE_BUCKETS;
+
+ /* Look for an existing file under the new name. */
+
+ for (oldfile = files[newhash]; oldfile != 0; oldfile = oldfile->next)
+ if (streq (oldfile->name, name))
+ break;
+
+ if (newhash != oldhash || oldfile != 0)
+ {
+ /* Remove FILE from its hash bucket. */
+
+ struct file *lastf = 0;
+
+ for (f = files[oldhash]; f != file; f = f->next)
+ lastf = f;
+
+ if (lastf == 0)
+ files[oldhash] = f->next;
+ else
+ lastf->next = f->next;
+ }
+
+ /* Give FILE its new name. */
+
+ for (f = file; f != 0; f = f->prev)
+ f->name = name;
+
+ if (oldfile == 0)
+ {
+ /* There is no existing file with the new name. */
+
+ if (newhash != oldhash)
+ {
+ /* Put FILE in its new hash bucket. */
+ file->next = files[newhash];
+ files[newhash] = file;
+ }
+ }
+ else
+ {
+ /* There is an existing file with the new name.
+ We must merge FILE into the existing file. */
+
+ register struct dep *d;
+
+ if (file->cmds != 0)
+ {
+ if (oldfile->cmds == 0)
+ oldfile->cmds = file->cmds;
+ else if (file->cmds != oldfile->cmds)
+ {
+ /* We have two sets of commands. We will go with the
+ one given in the rule explicitly mentioning this name,
+ but give a message to let the user know what's going on. */
+ makefile_error (file->cmds->filename, file->cmds->lineno,
+ "Commands were specified for file `%s' at %s:%u,",
+ oldname, oldfile->cmds->filename, oldfile->cmds->lineno);
+ makefile_error (file->cmds->filename, file->cmds->lineno,
+ "but `%s' is now considered the same file \
+ as `%s'.",
+ oldname, name);
+ makefile_error (file->cmds->filename, file->cmds->lineno,
+ "Commands for `%s' will be ignored \
+ in favor of those for `%s'.",
+ name, oldname);
+ }
+ }
+
+ /* Merge the dependencies of the two files. */
+
+ d = oldfile->deps;
+ if (d == 0)
+ oldfile->deps = file->deps;
+ else
+ {
+ while (d->next != 0)
+ d = d->next;
+ d->next = file->deps;
+ uniquize_deps (oldfile->deps);
+ }
+
+ merge_variable_set_lists (&oldfile->variables, file->variables);
+
+ if (oldfile->double_colon && !file->double_colon)
+ fatal ("can't rename single-colon `%s' to double-colon `%s'",
+ oldname, name);
+ if (!oldfile->double_colon && file->double_colon)
+ fatal ("can't rename double-colon `%s' to single-colon `%s'",
+ oldname, name);
+
+ if (file->last_mtime > oldfile->last_mtime)
+ /* %%% Kludge so -W wins on a file that gets vpathized. */
+ oldfile->last_mtime = file->last_mtime;
+
+ #define MERGE(field) oldfile->field |= file->field
+ MERGE (precious);
+ MERGE (tried_implicit);
+ MERGE (updating);
+ MERGE (updated);
+ MERGE (is_target);
+ MERGE (cmd_target);
+ MERGE (phony);
+ #undef MERGE
+
+ file->renamed = oldfile;
+ }
+ }
+
+ /* Remove all nonprecious intermediate files.
+ If SIG is nonzero, this was caused by a fatal signal,
+ meaning that a different message will be printed, and
+ the message will go to stderr rather than stdout. */
+
+ void
+ remove_intermediates (sig)
+ int sig;
+ {
+ register int i;
+ register struct file *f;
+ char doneany;
+
+ if (!sig && just_print_flag)
+ return;
+
+ doneany = 0;
+ for (i = 0; i < FILE_BUCKETS; ++i)
+ for (f = files[i]; f != 0; f = f->next)
+ if (f->intermediate && (f->dontcare || !f->precious))
+ {
+ int status;
+ if (just_print_flag)
+ status = 0;
+ else
+ {
+ status = unlink (f->name);
+ if (status < 0 && errno == ENOENT)
+ continue;
+ }
+ if (!f->dontcare)
+ {
+ if (sig)
+ error ("*** Deleting file `%s'", f->name);
+ else if (!silent_flag && !just_print_flag)
+ {
+ if (!doneany)
+ {
+ fputs ("rm ", stdout);
+ doneany = 1;
+ }
+ putchar (' ');
+ fputs (f->name, stdout);
+ fflush (stdout);
+ }
+ if (status < 0)
+ perror_with_name ("unlink: ", f->name);
+ }
+ }
+
+ if (doneany && !sig)
+ {
+ putchar ('\n');
+ fflush (stdout);
+ }
+ }
+
+ /* For each dependency of each file, make the `struct dep' point
+ at the appropriate `struct file' (which may have to be created).
+
+ Also mark the files depended on by .PRECIOUS and .PHONY. */
+
+ void
+ snap_deps ()
+ {
+ register struct file *f, *f2;
+ register struct dep *d;
+ register int i;
+
+ /* Enter each dependency name as a file. */
+ for (i = 0; i < FILE_BUCKETS; ++i)
+ for (f = files[i]; f != 0; f = f->next)
+ for (f2 = f; f2 != 0; f2 = f2->prev)
+ for (d = f2->deps; d != 0; d = d->next)
+ if (d->name != 0)
+ {
+ d->file = lookup_file (d->name);
+ if (d->file == 0)
+ d->file = enter_file (d->name);
+ else
+ free (d->name);
+ d->name = 0;
+ }
+
+ for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev)
+ for (d = f->deps; d != 0; d = d->next)
+ for (f2 = d->file; f2 != 0; f2 = f2->prev)
+ f2->precious = 1;
+
+ for (f = lookup_file (".PHONY"); f != 0; f = f->prev)
+ for (d = f->deps; d != 0; d = d->next)
+ for (f2 = d->file; f2 != 0; f2 = f2->prev)
+ {
+ /* Mark this file as phony and nonexistent. */
+ f2->phony = 1;
+ f2->last_mtime = (time_t) -1;
+ }
+ }
+
+ /* Print the data base of files. */
+
+ void
+ print_file_data_base ()
+ {
+ register unsigned int i, nfiles, per_bucket;
+ register struct file *file;
+ register struct dep *d;
+
+ puts ("\n# Files");
+
+ per_bucket = nfiles = 0;
+ for (i = 0; i < FILE_BUCKETS; ++i)
+ {
+ register unsigned int this_bucket = 0;
+
+ for (file = files[i]; file != 0; file = file->next)
+ {
+ register struct file *f;
+
+ ++this_bucket;
+
+ for (f = file; f != 0; f = f->prev)
+ {
+ putchar ('\n');
+ if (!f->is_target)
+ puts ("# Not a target:");
+ printf ("%s:%s", f->name, f->double_colon ? ":" : "");
+
+ for (d = f->deps; d != 0; d = d->next)
+ printf (" %s", dep_name (d));
+ putchar ('\n');
+
+ if (f->precious)
+ puts ("# Precious file (dependency of .PRECIOUS).");
+ if (f->phony)
+ puts ("# Phony target (dependency of .PHONY).");
+ if (f->cmd_target)
+ puts ("# Command-line target.");
+ if (f->dontcare)
+ puts ("# A default or MAKEFILES makefile.");
+ printf ("# Implicit rule search has%s been done.\n",
+ f->tried_implicit ? "" : " not");
+ if (f->stem != 0)
+ printf ("# Implicit/static pattern stem: `%s'\n", f->stem);
+ if (f->intermediate)
+ puts ("# File is an intermediate dependency.");
+ if (f->also_make != 0)
+ {
+ fputs ("# Also makes:", stdout);
+ for (d = f->also_make; d != 0; d = d->next)
+ printf (" %s", dep_name (d));
+ putchar ('\n');
+ }
+ if (f->last_mtime == (time_t) 0)
+ puts ("# Modification time never checked.");
+ else if (f->last_mtime == (time_t) -1)
+ puts ("# File does not exist.");
+ else
+ printf ("# Last modified %.24s (%ld)\n",
+ ctime (&f->last_mtime), (long int) f->last_mtime);
+ printf ("# File has%s been updated.\n",
+ f->updated ? "" : " not");
+ switch (f->command_state)
+ {
+ case cs_running:
+ puts ("# Commands currently running (?!).");
+ break;
+ case cs_deps_running:
+ puts ("# Dependencies currently being made (?!).");
+ break;
+ case cs_not_started:
+ case cs_finished:
+ switch (f->update_status)
+ {
+ case -1:
+ break;
+ case 0:
+ puts ("# Successfully updated.");
+ break;
+ case 1:
+ puts ("# Failed to be updated.");
+ break;
+ default:
+ puts ("# Invalid value in `update_status' member!");
+ fflush (stdout);
+ fflush (stderr);
+ abort ();
+ }
+ break;
+ default:
+ puts ("# Invalid value in `command_state' member!");
+ fflush (stdout);
+ fflush (stderr);
+ abort ();
+ }
+
+ if (f->variables != 0)
+ print_file_variables (file);
+
+ if (f->cmds != 0)
+ print_commands (f->cmds);
+ }
+ }
+
+ nfiles += this_bucket;
+ if (this_bucket > per_bucket)
+ per_bucket = this_bucket;
+ }
+
+ if (nfiles == 0)
+ puts ("\n# No files.");
+ else
+ {
+ printf ("\n# %u files in %u hash buckets.\n", nfiles, FILE_BUCKETS);
+ #ifndef NO_FLOAT
+ printf ("# average %.1f files per bucket, max %u files in one bucket.\n",
+ ((double) FILE_BUCKETS) / ((double) nfiles) * 100.0, per_bucket);
+ #endif
+ }
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/file.h
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/file.h:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/file.h Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,94 ----
+ /* Copyright (C) 1988, 1989, 1990, 1991 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 2, 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. */
+
+ /* Structure that represents the info on one file
+ that the makefile says how to make.
+ All of these are chained together through `next'. */
+
+ struct file
+ {
+ struct file *next;
+ char *name;
+ struct dep *deps;
+ struct commands *cmds; /* Commands to execute for this target */
+ char *stem; /* Implicit stem, if an implicit
+ rule has been used */
+ struct dep *also_make; /* Targets that are made by making this. */
+ time_t last_mtime; /* File's modtime, if already known. */
+ struct file *prev; /* Previous entry for same file name;
+ used when there are multiple double-colon
+ entries for the same file. */
+
+ /* File that this file was renamed to. After any time that a
+ file could be renamed, call `check_renamed' (below). */
+ struct file *renamed;
+
+ /* List of variable sets used for this file. */
+ struct variable_set_list *variables;
+
+ /* Immediate dependent that caused this target to be remade,
+ or nil if there isn't one. */
+ struct file *parent;
+
+ short int update_status; /* Status of the last attempt to update,
+ or -1 if none has been made. */
+
+ enum /* State of the commands. */
+ { /* Note: It is important that cs_not_started be zero. */
+ cs_not_started, /* Not yet started. */
+ cs_deps_running, /* Dep commands running. */
+ cs_running, /* Commands running. */
+ cs_finished /* Commands finished. */
+ } command_state ENUM_BITFIELD (2);
+
+ unsigned int double_colon:1;/* Nonzero for double-colon entry */
+ unsigned int precious:1; /* Non-0 means don't delete file on quit */
+ unsigned int tried_implicit:1;/* Nonzero if have searched
+ for implicit rule for making
+ this file; don't search again. */
+ unsigned int updating:1; /* Nonzero while updating deps of this file */
+ unsigned int updated:1; /* Nonzero if this file has been remade. */
+ unsigned int is_target:1; /* Nonzero if file is described as target. */
+ unsigned int cmd_target:1; /* Nonzero if file was given on cmd line. */
+ unsigned int phony:1; /* Nonzero if this is a phony file
+ ie, a dependent of .PHONY. */
+ unsigned int intermediate:1;/* Nonzero if this is an intermediate file. */
+ unsigned int dontcare:1; /* Nonzero if no complaint is to be made if
+ this target cannot be remade. */
+ };
+
+ /* Number of intermediate files entered. */
+
+ extern unsigned int num_intermediates;
+
+ extern struct file *default_goal_file, *suffix_file, *default_file;
+
+
+ extern struct file *lookup_file (), *enter_file ();
+ extern void remove_intermediates (), snap_deps ();
+ extern void rename_file ();
+
+
+ extern time_t f_mtime ();
+ #define file_mtime_1(f, v) \
+ ((f)->last_mtime != (time_t) 0 ? (f)->last_mtime : f_mtime ((f), v))
+ #define file_mtime(f) file_mtime_1 ((f), 1)
+ #define file_mtime_no_search(f) file_mtime_1 ((f), 0)
+
+
+ #define check_renamed(file) \
+ while ((file)->renamed != 0) (file) = (file)->renamed /* No ; here. */
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/function.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/function.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/function.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,1193 ----
+ /* Variable function expansion for GNU Make.
+ Copyright (C) 1988, 1989, 1991 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 2, 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. */
+
+ #include "make.h"
+ #include "variable.h"
+ #include "dep.h"
+ #include "commands.h"
+ #include "job.h"
+ #include <errno.h>
+
+ extern int errno;
+
+ static char *string_glob ();
+
+ /* Store into VARIABLE_BUFFER at O the result of scanning TEXT and replacing
+ each occurrence of SUBST with REPLACE. TEXT is null-terminated. SLEN is
+ the length of SUBST and RLEN is the length of REPLACE. If BY_WORD is
+ nonzero, substitutions are done only on matches which are complete
+ whitespace-delimited words. If SUFFIX_ONLY is nonzero, substitutions are
+ done only at the ends of whitespace-delimited words. */
+
+ char *
+ subst_expand (o, text, subst, replace, slen, rlen, by_word, suffix_only)
+ char *o;
+ char *text;
+ char *subst, *replace;
+ unsigned int slen, rlen;
+ int by_word, suffix_only;
+ {
+ register char *t = text;
+ register char *p;
+
+ if (slen == 0 && !by_word && !suffix_only)
+ {
+ /* The first occurrence of "" in any string is its end. */
+ o = variable_buffer_output (o, t, strlen (t));
+ if (rlen > 0)
+ o = variable_buffer_output (o, replace, rlen);
+ return o;
+ }
+
+ while ((p = sindex (t, 0, subst, slen)) != 0)
+ {
+ /* Output everything before this occurrence of the string to replace. */
+ if (p > t)
+ o = variable_buffer_output (o, t, p - t);
+
+ /* If we're substituting only by fully matched words,
+ or only at the ends of words, check that this case qualifies. */
+ if ((by_word
+ && ((p > t && !isblank (p[-1]))
+ || (p[slen] != '\0' && !isblank (p[slen]))))
+ || (suffix_only
+ && (p[slen] != '\0' && !isblank (p[slen]))))
+ /* Struck out. Output the rest of the string that is
+ no longer to be replaced. */
+ o = variable_buffer_output (o, subst, slen);
+ else if (rlen > 0)
+ /* Output the replacement string. */
+ o = variable_buffer_output (o, replace, rlen);
+
+ /* Advance T past the string to be replaced. */
+ t = p + slen;
+ }
+
+ /* Output everything left on the end. */
+ if (*t != '\0')
+ o = variable_buffer_output (o, t, strlen (t));
+
+ return o;
+ }
+
+
+ /* Store into VARIABLE_BUFFER at O the result of scanning TEXT
+ and replacing strings matching PATTERN with REPLACE.
+ If PATTERN_PERCENT is not nil, PATTERN has already been
+ run through find_percent, and PATTERN_PERCENT is the result.
+ If REPLACE_PERCENT is not nil, REPLACE has already been
+ run through find_percent, and REPLACE_PERCENT is the result. */
+
+ char *
+ patsubst_expand (o, text, pattern, replace, pattern_percent, replace_percent)
+ char *o;
+ char *text;
+ register char *pattern, *replace;
+ register char *pattern_percent, *replace_percent;
+ {
+ register int pattern_prepercent_len, pattern_postpercent_len;
+ register int replace_prepercent_len, replace_postpercent_len;
+ register char *t;
+ unsigned int len;
+ int doneany = 0;
+
+ /* We call find_percent on REPLACE before checking PATTERN so that REPLACE
+ will be collapsed before we call subst_expand if PATTERN has no %. */
+ if (replace_percent == 0)
+ replace_percent = find_percent (replace);
+ if (replace_percent != 0)
+ {
+ /* Record the length of REPLACE before and after the % so
+ we don't have to compute these lengths more than once. */
+ replace_prepercent_len = replace_percent - replace;
+ replace_postpercent_len = strlen (replace_percent + 1);
+ }
+ else
+ /* We store the length of the replacement
+ so we only need to compute it once. */
+ replace_prepercent_len = strlen (replace);
+
+ if (pattern_percent == 0)
+ pattern_percent = find_percent (pattern);
+ if (pattern_percent == 0)
+ /* With no % in the pattern, this is just a simple substitution. */
+ return subst_expand (o, text, pattern, replace,
+ strlen (pattern), strlen (replace), 1, 0);
+
+ /* Record the length of PATTERN before and after the %
+ so we don't have to compute it more than once. */
+ pattern_prepercent_len = pattern_percent - pattern;
+ pattern_postpercent_len = strlen (pattern_percent + 1);
+
+ while (t = find_next_token (&text, &len))
+ {
+ int fail = 0;
+
+ /* Is it big enough to match? */
+ if (len < pattern_prepercent_len + pattern_postpercent_len)
+ fail = 1;
+
+ /* Does the prefix match? */
+ if (!fail && pattern_prepercent_len > 0
+ && (*t != *pattern
+ || t[pattern_prepercent_len - 1] != pattern_percent[-1]
+ || strncmp (t + 1, pattern + 1, pattern_prepercent_len - 1)))
+ fail = 1;
+
+ /* Does the suffix match? */
+ if (!fail && pattern_postpercent_len > 0
+ && (t[len - 1] != pattern_percent[pattern_postpercent_len]
+ || t[len - pattern_postpercent_len] != pattern_percent[1]
+ || strncmp (&t[len - pattern_postpercent_len],
+ &pattern_percent[1], pattern_postpercent_len - 1)))
+ fail = 1;
+
+ if (fail)
+ /* It didn't match. Output the string. */
+ o = variable_buffer_output (o, t, len);
+ else
+ {
+ /* It matched. Output the replacement. */
+
+ /* Output the part of the replacement before the %. */
+ o = variable_buffer_output (o, replace, replace_prepercent_len);
+
+ if (replace_percent != 0)
+ {
+ /* Output the part of the matched string that
+ matched the % in the pattern. */
+ o = variable_buffer_output (o, t + pattern_prepercent_len,
+ len - (pattern_prepercent_len
+ + pattern_postpercent_len));
+ /* Output the part of the replacement after the %. */
+ o = variable_buffer_output (o, replace_percent + 1,
+ replace_postpercent_len);
+ }
+ }
+
+ /* Output a space, but not if the replacement is "". */
+ if (fail || replace_prepercent_len > 0
+ || (replace_percent != 0 && len + replace_postpercent_len > 0))
+ {
+ o = variable_buffer_output (o, " ", 1);
+ doneany = 1;
+ }
+ }
+ if (doneany)
+ /* Kill the last space. */
+ --o;
+
+ return o;
+ }
+
+ /* Handle variable-expansion-time functions such as $(dir foo/bar) ==> foo/ */
+
+ /* These enumeration constants distinguish the
+ various expansion-time built-in functions. */
+
+ enum function
+ {
+ function_subst,
+ function_addsuffix,
+ function_addprefix,
+ function_dir,
+ function_notdir,
+ function_suffix,
+ function_basename,
+ function_wildcard,
+ function_firstword,
+ function_word,
+ function_words,
+ function_findstring,
+ function_strip,
+ function_join,
+ function_patsubst,
+ function_filter,
+ function_filter_out,
+ function_foreach,
+ function_sort,
+ function_origin,
+ function_shell,
+ function_invalid
+ };
+
+ /* Greater than the length of any function name. */
+ #define MAXFUNCTIONLEN 11
+
+ /* The function names and lengths of names, for looking them up. */
+
+ static struct
+ {
+ char *name;
+ unsigned int len;
+ enum function function;
+ } function_table[] =
+ {
+ { "subst", 5, function_subst },
+ { "addsuffix", 9, function_addsuffix },
+ { "addprefix", 9, function_addprefix },
+ { "dir", 3, function_dir },
+ { "notdir", 6, function_notdir },
+ { "suffix", 6, function_suffix },
+ { "basename", 8, function_basename },
+ { "wildcard", 8, function_wildcard },
+ { "firstword", 9, function_firstword },
+ { "word", 4, function_word },
+ { "words", 5, function_words },
+ { "findstring", 10, function_findstring },
+ { "strip", 5, function_strip },
+ { "join", 4, function_join },
+ { "patsubst", 8, function_patsubst },
+ { "filter", 6, function_filter },
+ { "filter-out", 10, function_filter_out },
+ { "foreach", 7, function_foreach },
+ { "sort", 4, function_sort },
+ { "origin", 6, function_origin },
+ { "shell", 5, function_shell },
+ { 0, 0, function_invalid }
+ };
+
+ /* Return 1 if PATTERN matches WORD, 0 if not. */
+
+ int
+ pattern_matches (pattern, percent, word)
+ register char *pattern, *percent, *word;
+ {
+ unsigned int len;
+
+ if (percent == 0)
+ {
+ unsigned int len = strlen (pattern) + 1;
+ char *new = (char *) alloca (len);
+ bcopy (pattern, new, len);
+ pattern = new;
+ percent = find_percent (pattern);
+ if (percent == 0)
+ return streq (pattern, word);
+ }
+
+ len = strlen (percent + 1);
+
+ if (strlen (word) < (percent - pattern) + len
+ || strncmp (pattern, word, percent - pattern))
+ return 0;
+
+ return !strcmp (percent + 1, word + (strlen (word) - len));
+ }
+
+ int shell_function_pid = 0, shell_function_completed;
+
+ /* Perform the function specified by FUNCTION on the text at TEXT.
+ END is points to the end of the argument text (exclusive).
+ The output is written into VARIABLE_BUFFER starting at O. */
+
+ /* Note this absorbs a semicolon and is safe to use in conditionals. */
+ #define BADARGS(func) \
+ if (reading_filename != 0) \
+ makefile_fatal (reading_filename, *reading_lineno_ptr, \
+ "insufficient arguments to function `%s'", \
+ func); \
+ else \
+ fatal ("insufficient arguments to function `%s'", func)
+
+ static char *
+ expand_function (o, function, text, end)
+ char *o;
+ enum function function;
+ char *text;
+ char *end;
+ {
+ char *p, *p2, *p3;
+ unsigned int i, len;
+ int doneany = 0;
+ int count;
+ char endparen = *end, startparen = *end == ')' ? '(' : '{';
+
+ switch (function)
+ {
+ default:
+ abort ();
+ break;
+
+ case function_shell:
+ {
+ extern int fork ();
+ extern int pipe ();
+ char **argv;
+ char *error_prefix;
+ int pipedes[2];
+ int pid;
+
+ /* Expand the command line. */
+ text = expand_argument (text, end);
+
+ /* Construct the argument list. */
+ argv = construct_command_argv (text, (char *) NULL, (struct file *) 0);
+ if (argv == 0)
+ break;
+
+ /* For error messages. */
+ if (reading_filename != 0)
+ {
+ error_prefix = (char *) alloca (strlen (reading_filename) + 100);
+ sprintf (error_prefix,
+ "%s:%u: ", reading_filename, *reading_lineno_ptr);
+ }
+ else
+ error_prefix = "";
+
+ if (pipe (pipedes) < 0)
+ {
+ perror_with_name (error_prefix, "pipe");
+ break;
+ }
+
+ push_signals_blocked_p (1);
+
+ pid = fork ();
+ if (pid < 0)
+ perror_with_name (error_prefix, "fork");
+ else if (pid == 0)
+ child_execute_job (0, pipedes[1], argv, environ);
+ else
+ {
+ /* We are the parent. Set up and read from the pipe. */
+ char *buffer = (char *) xmalloc (201);
+ unsigned int maxlen = 200;
+ int cc;
+
+ /* Record the PID for child_handler. */
+ shell_function_pid = pid;
+ shell_function_completed = 0;
+
+ /* Close the write side of the pipe. */
+ (void) close (pipedes[1]);
+
+ /* Read from the pipe until it gets EOF. */
+ i = 0;
+ do
+ {
+ if (i == maxlen)
+ {
+ maxlen += 512;
+ buffer = (char *) xrealloc (buffer, maxlen + 1);
+ }
+
+ errno = 0;
+ cc = read (pipedes[0], &buffer[i], maxlen - i);
+ if (cc > 0)
+ i += cc;
+ }
+ #ifdef EINTR
+ while (cc > 0 || errno == EINTR);
+ #else
+ while (cc > 0);
+ #endif
+
+ /* Close the read side of the pipe. */
+ (void) close (pipedes[0]);
+
+ /* Loop until child_handler sets shell_function_completed
+ to the status of our child shell. */
+ while (shell_function_completed == 0)
+ wait_for_children (1, 0);
+
+ shell_function_pid = 0;
+
+ /* The child_handler function will set shell_function_completed
+ to 1 when the child dies normally, or to -1 if it
+ dies with status 127, which is most likely an exec fail. */
+
+ if (shell_function_completed == -1)
+ {
+ /* This most likely means that the execvp failed,
+ so we should just write out the error message
+ that came in over the pipe from the child. */
+ fputs (buffer, stderr);
+ fflush (stderr);
+ }
+ else
+ {
+ /* The child finished normally. Replace all
+ newlines in its output with spaces, and put
+ that in the variable output buffer. */
+ if (i > 0)
+ {
+ if (buffer[i - 1] == '\n')
+ buffer[--i] = '\0';
+ p = buffer;
+ while ((p = index (p, '\n')) != 0)
+ *p++ = ' ';
+ o = variable_buffer_output (o, buffer, i);
+ }
+ }
+
+ free (argv[0]);
+ free ((char *) argv);
+ free (buffer);
+ }
+
+ pop_signals_blocked_p ();
+
+ free (text);
+ break;
+ }
+
+ case function_origin:
+ /* Expand the argument. */
+ text = expand_argument (text, end);
+
+ {
+ register struct variable *v = lookup_variable (text, strlen (text));
+ if (v == 0)
+ o = variable_buffer_output (o, "undefined", 9);
+ else
+ switch (v->origin)
+ {
+ default:
+ case o_invalid:
+ abort ();
+ break;
+ case o_default:
+ o = variable_buffer_output (o, "default", 7);
+ break;
+ case o_env:
+ o = variable_buffer_output (o, "environment", 11);
+ break;
+ case o_file:
+ o = variable_buffer_output (o, "file", 4);
+ break;
+ case o_env_override:
+ o = variable_buffer_output (o, "environment override", 20);
+ break;
+ case o_command:
+ o = variable_buffer_output (o, "command line", 12);
+ break;
+ case o_override:
+ o = variable_buffer_output (o, "override", 8);
+ break;
+ case o_automatic:
+ o = variable_buffer_output (o, "automatic", 9);
+ break;
+ }
+ }
+
+ free (text);
+ break;
+
+ case function_sort:
+ /* Expand the argument. */
+ text = expand_argument (text, end);
+
+ {
+ char **words = (char **) xmalloc (10 * sizeof (char *));
+ unsigned int nwords = 10;
+ register unsigned int wordi = 0;
+ char *t;
+
+ /* Chop TEXT into words and put them in WORDS. */
+ t = text;
+ while (p = find_next_token (&t, &len))
+ {
+ if (wordi >= nwords - 1)
+ {
+ nwords += 5;
+ words = (char **) xrealloc ((char *) words,
+ nwords * sizeof (char *));
+ }
+ words[wordi++] = savestring (p, len);
+ }
+
+ if (wordi > 0)
+ {
+ /* Now sort the list of words. */
+ qsort ((char *) words, wordi, sizeof (char *), alpha_compare);
+
+ /* Now write the sorted list. */
+ for (i = 0; i < wordi; ++i)
+ {
+ len = strlen (words[i]);
+ if (i == wordi - 1 || strlen (words[i + 1]) != len
+ || strcmp (words[i], words[i + 1]))
+ {
+ o = variable_buffer_output (o, words[i], len);
+ o = variable_buffer_output (o, " ", 1);
+ }
+ free (words[i]);
+ }
+ /* Kill the last space. */
+ --o;
+ }
+
+ free ((char *) words);
+ }
+
+ free (text);
+ break;
+
+ case function_foreach:
+ {
+ /* Get three comma-separated arguments but
+ expand only the first two. */
+ char *var, *list;
+ register struct variable *v;
+
+ count = 0;
+ for (p = text; p < end; ++p)
+ {
+ if (*p == startparen)
+ ++count;
+ else if (*p == endparen)
+ --count;
+ else if (*p == ',' && count <= 0)
+ break;
+ }
+ if (p == end)
+ BADARGS ("foreach");
+ var = expand_argument (text, p);
+
+ p2 = p + 1;
+ count = 0;
+ for (p = p2; p < end; ++p)
+ {
+ if (*p == startparen)
+ ++count;
+ else if (*p == endparen)
+ --count;
+ else if (*p == ',' && count <= 0)
+ break;
+ }
+ if (p == end)
+ BADARGS ("foreach");
+ list = expand_argument (p2, p);
+
+ ++p;
+ text = savestring (p, end - p);
+
+ push_new_variable_scope ();
+ v = define_variable (var, strlen (var), "", o_automatic, 0);
+ p3 = list;
+ while ((p = find_next_token (&p3, &len)) != 0)
+ {
+ char *result;
+ char save = p[len];
+ p[len] = '\0';
+ v->value = p;
+ result = allocated_variable_expand (text);
+ p[len] = save;
+
+ o = variable_buffer_output (o, result, strlen (result));
+ o = variable_buffer_output (o, " ", 1);
+ doneany = 1;
+ free (result);
+ }
+ if (doneany)
+ /* Kill the last space. */
+ --o;
+
+ pop_variable_scope ();
+
+ free (var);
+ free (list);
+ free (text);
+ }
+ break;
+
+ case function_filter:
+ case function_filter_out:
+ {
+ struct word
+ {
+ struct word *next;
+ char *word;
+ int matched;
+ } *words, *wordtail, *wp;
+
+ /* Get two comma-separated arguments and expand each one. */
+ count = 0;
+ for (p = text; p < end; ++p)
+ {
+ if (*p == startparen)
+ ++count;
+ else if (*p == endparen)
+ --count;
+ else if (*p == ',' && count <= 0)
+ break;
+ }
+ if (p == end)
+ BADARGS (function == function_filter ? "filter" : "filter-out");
+ p2 = expand_argument (text, p);
+
+ text = expand_argument (p + 1, end);
+
+ /* Chop TEXT up into words and then run each pattern through. */
+ words = wordtail = 0;
+ p3 = text;
+ while ((p = find_next_token (&p3, &len)) != 0)
+ {
+ struct word *w = (struct word *) alloca (sizeof (struct word));
+ if (words == 0)
+ words = w;
+ else
+ wordtail->next = w;
+ wordtail = w;
+
+ if (*p3 != '\0')
+ ++p3;
+ p[len] = '\0';
+ w->word = p;
+ w->matched = 0;
+ }
+
+ if (words != 0)
+ {
+ wordtail->next = 0;
+
+ /* Run each pattern through the words, killing words. */
+ p3 = p2;
+ while ((p = find_next_token (&p3, &len)) != 0)
+ {
+ char *percent;
+ char save = p[len];
+ p[len] = '\0';
+
+ percent = find_percent (p);
+ for (wp = words; wp != 0; wp = wp->next)
+ wp->matched |= (percent == 0 ? streq (p, wp->word)
+ : pattern_matches (p, percent, wp->word));
+
+ p[len] = save;
+ }
+
+ /* Output the words that matched (or didn't, for filter-out). */
+ for (wp = words; wp != 0; wp = wp->next)
+ if (function == function_filter ? wp->matched : !wp->matched)
+ {
+ o = variable_buffer_output (o, wp->word, strlen (wp->word));
+ o = variable_buffer_output (o, " ", 1);
+ doneany = 1;
+ }
+ if (doneany)
+ /* Kill the last space. */
+ --o;
+ }
+
+ free (p2);
+ free (text);
+ }
+ break;
+
+ case function_patsubst:
+ /* Get three comma-separated arguments and expand each one. */
+ count = 0;
+ for (p = text; p < end; ++p)
+ {
+ if (*p == startparen)
+ ++count;
+ else if (*p == endparen)
+ --count;
+ else if (*p == ',' && count <= 0)
+ break;
+ }
+ if (p == end)
+ BADARGS ("patsubst");
+
+ p2 = p;
+ count = 0;
+ for (++p; p < end; ++p)
+ {
+ if (*p == startparen)
+ ++count;
+ else if (*p == endparen)
+ --count;
+ else if (*p == ',' && count <= 0)
+ break;
+ }
+ if (p == end)
+ BADARGS ("patsubst");
+
+ text = expand_argument (text, p2);
+ p3 = expand_argument (p2 + 1, p);
+ p2 = expand_argument (p + 1, end);
+
+ o = patsubst_expand (o, p2, text, p3, (char *) 0, (char *) 0);
+
+ free (text);
+ free (p3);
+ free (p2);
+ break;
+
+ case function_join:
+ /* Get two comma-separated arguments and expand each one. */
+ count = 0;
+ for (p = text; p < end; ++p)
+ {
+ if (*p == startparen)
+ ++count;
+ else if (*p == endparen)
+ --count;
+ else if (*p == ',' && count <= 0)
+ break;
+ }
+ if (p == end)
+ BADARGS ("join");
+ text = expand_argument (text, p);
+
+ p = expand_argument (p + 1, end);
+
+ {
+ /* Write each word of the first argument directly followed
+ by the corresponding word of the second argument.
+ If the two arguments have a different number of words,
+ the excess words are just output separated by blanks. */
+ register char *tp, *pp;
+ p2 = text;
+ p3 = p;
+ do
+ {
+ unsigned int tlen, plen;
+
+ tp = find_next_token (&p2, &tlen);
+ if (tp != 0)
+ o = variable_buffer_output (o, tp, tlen);
+
+ pp = find_next_token (&p3, &plen);
+ if (pp != 0)
+ o = variable_buffer_output (o, pp, plen);
+
+ if (tp != 0 || pp != 0)
+ {
+ o = variable_buffer_output (o, " ", 1);
+ doneany = 1;
+ }
+ }
+ while (tp != 0 || pp != 0);
+ if (doneany)
+ /* Kill the last blank. */
+ --o;
+ }
+
+ free (text);
+ free (p);
+ break;
+
+ case function_strip:
+ /* Expand the argument. */
+ text = expand_argument (text, end);
+
+ p2 = text;
+ while ((p = find_next_token (&p2, &i)) != 0)
+ {
+ o = variable_buffer_output (o, p, i);
+ o = variable_buffer_output (o, " ", 1);
+ doneany = 1;
+ }
+ if (doneany)
+ /* Kill the last space. */
+ --o;
+
+ free (text);
+ break;
+
+ case function_wildcard:
+ text = expand_argument (text, end);
+
+ p = string_glob (text);
+ o = variable_buffer_output (o, p, strlen (p));
+
+ free (text);
+ break;
+
+ case function_subst:
+ /* Get three comma-separated arguments and expand each one. */
+ count = 0;
+ for (p = text; p < end; ++p)
+ {
+ if (*p == startparen)
+ ++count;
+ else if (*p == endparen)
+ --count;
+ else if (*p == ',' && count <= 0)
+ break;
+ }
+ if (p == end)
+ BADARGS ("subst");
+
+ p2 = p;
+ count = 0;
+ for (++p; p < end; ++p)
+ {
+ if (*p == startparen)
+ ++count;
+ else if (*p == endparen)
+ --count;
+ else if (*p == ',' && count <= 0)
+ break;
+ }
+ if (p == end)
+ BADARGS ("subst");
+
+ text = expand_argument (text, p2);
+ p3 = expand_argument (p2 + 1, p);
+ p2 = expand_argument (p + 1, end);
+
+ o = subst_expand (o, p2, text, p3, strlen (text), strlen (p3), 0, 0);
+
+ free (text);
+ free (p3);
+ free (p2);
+ break;
+
+ case function_firstword:
+ /* Expand the argument. */
+ text = expand_argument (text, end);
+
+ /* Find the first word in TEXT. */
+ p2 = text;
+ p = find_next_token (&p2, &i);
+ if (p != 0)
+ o = variable_buffer_output (o, p, i);
+
+ free (text);
+ break;
+
+ case function_word:
+ /* Get two comma-separated arguments and expand each one. */
+ count = 0;
+ for (p = text; p < end; ++p)
+ {
+ if (*p == startparen)
+ ++count;
+ else if (*p == endparen)
+ --count;
+ else if (*p == ',' && count <= 0)
+ break;
+ }
+ if (p == end)
+ BADARGS ("word");
+ text = expand_argument (text, p);
+
+ p3 = expand_argument (p + 1, end);
+
+ /* Check the first argument. */
+ for (p2 = text; *p2 != '\0'; ++p2)
+ if (*p2 < '0' || *p2 > '9')
+ {
+ if (reading_filename != 0)
+ makefile_fatal (reading_filename, *reading_lineno_ptr,
+ "non-numeric first argument to `word' function");
+ else
+ fatal ("non-numeric first argument to `word' function");
+ }
+
+ i = (unsigned int) atoi (text);
+ if (i == 0)
+ {
+ if (reading_filename != 0)
+ makefile_fatal (reading_filename, *reading_lineno_ptr,
+ "the `word' function takes a one-origin \
+ index argument");
+ else
+ fatal ("the `word' function takes a one-origin index argument");
+ }
+
+ p2 = p3;
+ while ((p = find_next_token (&p2, &len)) != 0)
+ if (--i == 0)
+ break;
+ if (i == 0)
+ o = variable_buffer_output (o, p, len);
+
+ free (text);
+ free (p3);
+ break;
+
+ case function_words:
+ /* Expand the argument. */
+ text = expand_argument (text, end);
+
+ i = 0;
+ p2 = text;
+ while (find_next_token (&p2, (unsigned int *) 0) != 0)
+ ++i;
+
+ {
+ char buf[20];
+ sprintf (buf, "%d", i);
+ o = variable_buffer_output (o, buf, strlen (buf));
+ }
+
+ free (text);
+ break;
+
+ case function_findstring:
+ /* Get two comma-separated arguments and expand each one. */
+ count = 0;
+ for (p = text; p < end; ++p)
+ {
+ if (*p == startparen)
+ ++count;
+ else if (*p == endparen)
+ --count;
+ else if (*p == ',' && count <= 0)
+ break;
+ }
+ if (p == end)
+ BADARGS ("findstring");
+ text = expand_argument (text, p);
+
+ p = expand_argument (p + 1, end);
+
+ /* Find the first occurrence of the first string in the second. */
+ i = strlen (text);
+ if (sindex (p, 0, text, i) != 0)
+ o = variable_buffer_output (o, text, i);
+
+ free (p);
+ free (text);
+ break;
+
+ case function_addsuffix:
+ case function_addprefix:
+ /* Get two comma-separated arguments and expand each one. */
+ count = 0;
+ for (p = text; p < end; ++p)
+ {
+ if (*p == startparen)
+ ++count;
+ else if (*p == endparen)
+ --count;
+ else if (*p == ',' && count <= 0)
+ break;
+ }
+ if (p == end)
+ BADARGS (function == function_addsuffix ? "addsuffix" : "addprefix");
+ text = expand_argument (text, p);
+ i = strlen (text);
+
+ p2 = expand_argument (p + 1, end);
+
+ p3 = p2;
+ while ((p = find_next_token (&p3, &len)) != 0)
+ {
+ if (function == function_addprefix)
+ o = variable_buffer_output (o, text, i);
+ o = variable_buffer_output (o, p, len);
+ if (function == function_addsuffix)
+ o = variable_buffer_output (o, text, i);
+ o = variable_buffer_output (o, " ", 1);
+ doneany = 1;
+ }
+ if (doneany)
+ /* Kill last space. */
+ --o;
+
+ free (p2);
+ free (text);
+ break;
+
+ case function_dir:
+ case function_basename:
+ /* Expand the argument. */
+ text = expand_argument (text, end);
+
+ p3 = text;
+ while ((p2 = find_next_token (&p3, &len)) != 0)
+ {
+ p = p2 + len;
+ while (p >= p2 && *p != (function == function_dir ? '/' : '.'))
+ --p;
+ if (p >= p2)
+ {
+ if (function == function_dir)
+ ++p;
+ o = variable_buffer_output (o, p2, p - p2);
+ }
+ else if (function == function_dir)
+ o = variable_buffer_output (o, "./", 2);
+ else
+ /* The entire name is the basename. */
+ o = variable_buffer_output (o, p2, len);
+
+ o = variable_buffer_output (o, " ", 1);
+ doneany = 1;
+ }
+ if (doneany)
+ /* Kill last space. */
+ --o;
+
+ free (text);
+ break;
+
+ case function_notdir:
+ case function_suffix:
+ /* Expand the argument. */
+ text = expand_argument (text, end);
+
+ p3 = text;
+ while ((p2 = find_next_token (&p3, &len)) != 0)
+ {
+ p = p2 + len;
+ while (p >= p2 && *p != (function == function_notdir ? '/' : '.'))
+ --p;
+ if (p >= p2)
+ {
+ if (function == function_notdir)
+ ++p;
+ o = variable_buffer_output (o, p, len - (p - p2));
+ }
+ else if (function == function_notdir)
+ o = variable_buffer_output (o, p2, len);
+
+ if (function == function_notdir || p >= p2)
+ {
+ o = variable_buffer_output (o, " ", 1);
+ doneany = 1;
+ }
+ }
+ if (doneany)
+ /* Kill last space. */
+ --o;
+
+ free (text);
+ break;
+ }
+
+ return o;
+ }
+
+ /* Check for a function invocation in *STRINGP. *STRINGP points at the
+ opening ( or { and is not null-terminated. If a function invocation
+ is found, expand it into the buffer at *OP, updating *OP, incrementing
+ *STRINGP past the reference and returning nonzero. If not, return zero. */
+
+ int
+ handle_function (op, stringp)
+ char **op;
+ char **stringp;
+
+ {
+ register unsigned int code;
+ unsigned int maxlen;
+ char *beg = *stringp + 1;
+ char *endref;
+
+ endref = lindex (beg, beg + MAXFUNCTIONLEN, '\0');
+ maxlen = endref != 0 ? endref - beg : MAXFUNCTIONLEN;
+
+ for (code = 0; function_table[code].name != 0; ++code)
+ {
+ if (maxlen < function_table[code].len)
+ continue;
+ endref = beg + function_table[code].len;
+ if (isblank (*endref)
+ && !strncmp (function_table[code].name, beg,
+ function_table[code].len))
+ break;
+ }
+ if (function_table[code].name != 0)
+ {
+ /* We have found a call to an expansion-time function.
+ Find the end of the arguments, and do the function. */
+
+ char openparen = beg[-1], closeparen = openparen == '(' ? ')' : '}';
+ int count = 0;
+ char *argbeg;
+ register char *p;
+
+ /* Space after function name isn't part of the args. */
+ p = next_token (endref);
+ argbeg = p;
+
+ /* Count nested use of whichever kind of parens we use,
+ so that nested calls and variable refs work. */
+
+ for (; *p != '\0'; ++p)
+ {
+ if (*p == openparen)
+ ++count;
+ else if (*p == closeparen && --count < 0)
+ break;
+ }
+
+ /* We found the end; expand the function call. */
+
+ *op = expand_function (*op, function_table[code].function, argbeg, p);
+ *stringp = p;
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /* Glob-expand LINE. The returned pointer is
+ only good until the next call to string_glob. */
+
+ static char *
+ string_glob (line)
+ char *line;
+ {
+ static char *result = 0;
+ static unsigned int length;
+ register struct nameseq *chain;
+ register unsigned int idx;
+
+ chain = multi_glob (parse_file_seq (&line, '\0', sizeof (struct nameseq)),
+ sizeof (struct nameseq));
+
+ if (result == 0)
+ {
+ length = 100;
+ result = (char *) xmalloc (100);
+ }
+
+ idx = 0;
+ while (chain != 0)
+ {
+ register char *name = chain->name;
+ unsigned int len = strlen (name);
+
+ struct nameseq *next = chain->next;
+ free ((char *) chain);
+ chain = next;
+
+ /* multi_glob will pass names without globbing metacharacters
+ through as is, but we want only files that actually exist. */
+ if (file_exists_p (name))
+ {
+ if (idx + len + 1 > length)
+ {
+ length += (len + 1) * 2;
+ result = (char *) xrealloc (result, length);
+ }
+ bcopy (name, &result[idx], len);
+ idx += len;
+ result[idx++] = ' ';
+ }
+
+ free (name);
+ }
+
+ /* Kill the last space and terminate the string. */
+ if (idx == 0)
+ result[0] = '\0';
+ else
+ result[idx - 1] = '\0';
+
+ return result;
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/implicit.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/implicit.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/implicit.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,569 ----
+ /* Implicit rule searching for GNU Make.
+ Copyright (C) 1988, 1989, 1990, 1991 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 2, 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. */
+
+ #include "make.h"
+ #include "rule.h"
+ #include "dep.h"
+ #include "file.h"
+
+ static int pattern_search ();
+
+ /* For a FILE which has no commands specified, try to figure out some
+ from the implicit pattern rules.
+ Returns 1 if a suitable implicit rule was found,
+ after modifying FILE to contain the appropriate commands and deps,
+ or returns 0 if no implicit rule was found. */
+
+ int
+ try_implicit_rule (file, depth)
+ struct file *file;
+ unsigned int depth;
+ {
+ DEBUGPR ("Looking for an implicit rule for `%s'.\n");
+
+ #ifndef NO_ARCHIVES
+ /* If this is an archive member reference, use just the
+ archive member name to search for implicit rules. */
+ if (ar_name (file->name))
+ {
+ DEBUGPR ("Looking for archive-member implicit rule for `%s'.\n");
+ if (pattern_search (file, 1, depth, 0))
+ return 1;
+ }
+ #endif
+
+ return pattern_search (file, 0, depth, 0);
+ }
+
+ #define DEBUGP2(msg, a1, a2) \
+ if (debug_flag) \
+ { print_spaces (depth); printf (msg, a1, a2); fflush (stdout); } else
+
+ /* Search the pattern rules for a rule with an existing dependency to make
+ FILE. If a rule is found, the appropriate commands and deps are put in FILE
+ and 1 is returned. If not, 0 is returned.
+
+ If ARCHIVE is nonzero, FILE->name is of the form "LIB(MEMBER)". A rule for
+ "(MEMBER)" will be searched for, and "(MEMBER)" will not be chopped up into
+ directory and filename parts.
+
+ If an intermediate file is found by pattern search, the intermediate file
+ is set up as a target by the recursive call and is also made a dependency
+ of FILE.
+
+ DEPTH is used for debugging messages. */
+
+ static int
+ pattern_search (file, archive, depth, recursions)
+ struct file *file;
+ int archive;
+ unsigned int depth;
+ unsigned int recursions;
+ {
+ /* Filename we are searching for a rule for. */
+ char *filename = archive ? index (file->name, '(') : file->name;
+
+ /* Length of FILENAME. */
+ unsigned int namelen = strlen (filename);
+
+ /* The last slash in FILENAME (or nil if there is none). */
+ char *lastslash;
+
+ /* This is a file-object used as an argument in
+ recursive calls. It never contains any data
+ except during a recursive call. */
+ struct file *intermediate_file = 0;
+
+ /* List of dependencies found recursively. */
+ struct file **intermediate_files
+ = (struct file **) alloca (max_pattern_deps * sizeof (struct file *));
+
+ /* List of the patterns used to find intermediate files. */
+ char **intermediate_patterns
+ = (char **) alloca (max_pattern_deps * sizeof (char *));
+
+ /* This buffer records all the dependencies actually found for a rule. */
+ char **found_files = (char **) alloca (max_pattern_deps * sizeof (char *));
+ /* Number of dep names now in FOUND_FILES. */
+ unsigned int deps_found;
+
+ /* Names of possible dependencies are constructed in this buffer. */
+ register char *depname = (char *) alloca (namelen + max_pattern_dep_length);
+
+ /* The start and length of the stem of FILENAME for the current rule. */
+ register char *stem;
+ register unsigned int stemlen;
+
+ /* Buffer in which we store all the rules that are possibly applicable. */
+ struct rule **tryrules
+ = (struct rule **) alloca (num_pattern_rules * sizeof (struct rule *));
+
+ /* Number of valid elements in TRYRULES. */
+ unsigned int nrules;
+
+ /* The numbers of the rule targets of each rule
+ in TRYRULES that matched the target file. */
+ unsigned int *matches
+ = (unsigned int *) alloca (num_pattern_rules * sizeof (unsigned int));
+
+ /* Each element is nonzero if LASTSLASH was used in
+ matching the corresponding element of TRYRULES. */
+ char *checked_lastslash
+ = (char *) alloca (num_pattern_rules * sizeof (char));
+
+ /* The index in TRYRULES of the rule we found. */
+ unsigned int foundrule;
+
+ /* Nonzero if should consider intermediate files as dependencies. */
+ int intermed_ok;
+
+ /* Nonzero if we have matched a pattern-rule target
+ that is not just `%'. */
+ int specific_rule_matched = 0;
+
+ register unsigned int i;
+ register struct rule *rule;
+ register struct dep *dep;
+
+ char *p;
+
+ #ifndef NO_ARCHIVES
+ if (archive || ar_name (filename))
+ lastslash = 0;
+ else
+ #endif
+ {
+ /* Set LASTSLASH to point at the last slash in FILENAME
+ but not counting any slash at the end. (foo/bar/ counts as
+ bar/ in directory foo/, not empty in directory foo/bar/.) */
+ lastslash = rindex (filename, '/');
+ if (lastslash != 0 && lastslash[1] == '\0')
+ lastslash = 0;
+ }
+
+ /* First see which pattern rules match this target
+ and may be considered. Put them in TRYRULES. */
+
+ nrules = 0;
+ for (rule = pattern_rules; rule != 0; rule = rule->next)
+ {
+ int specific_rule_may_have_matched = 0;
+ int check_lastslash;
+
+ /* If the pattern rule has deps but no commands, ignore it.
+ Users cancel built-in rules by redefining them without commands. */
+ if (rule->deps != 0 && rule->cmds == 0)
+ continue;
+
+ /* If this rule is in use by a parent pattern_search,
+ don't use it here. */
+ if (rule->in_use)
+ {
+ DEBUGP2 ("Avoiding implicit rule recursion.\n", 0, 0);
+ continue;
+ }
+
+ for (i = 0; rule->targets[i] != 0; ++i)
+ {
+ char *target = rule->targets[i];
+ char *suffix = rule->suffixes[i];
+
+ /* Rules that can match any filename and are not terminal
+ are ignored if we're recursing, so that they cannot be
+ intermediate files. */
+ if (recursions > 0 && target[1] == '\0' && !rule->terminal)
+ continue;
+
+ if (rule->lens[i] > namelen)
+ /* It can't possibly match. */
+ continue;
+
+ /* From the lengths of the filename and the pattern parts,
+ find the stem: the part of the filename that matches the %. */
+ stem = filename + (suffix - target - 1);
+ stemlen = namelen - rule->lens[i] + 1;
+
+ /* Set CHECK_LASTSLASH if FILENAME contains a directory
+ prefix and the target pattern does not contain a slash. */
+
+ check_lastslash = lastslash != 0 && index (target, '/') == 0;
+ if (check_lastslash)
+ {
+ /* In that case, don't include the
+ directory prefix in STEM here. */
+ unsigned int difference = lastslash - filename + 1;
+ if (difference > stemlen)
+ continue;
+ stemlen -= difference;
+ stem += difference;
+ }
+
+ /* Check that the rule pattern matches the text before the stem. */
+ if (check_lastslash)
+ {
+ if (stem > (lastslash + 1)
+ && strncmp (target, lastslash + 1, stem - lastslash - 1))
+ continue;
+ }
+ else if (stem > filename
+ && strncmp (target, filename, stem - filename))
+ continue;
+
+ /* Check that the rule pattern matches the text after the stem.
+ We could test simply use streq, but this way we compare the
+ first two characters immediately. This saves time in the very
+ common case where the first character matches because it is a
+ period. */
+ if (*suffix != stem[stemlen]
+ || (*suffix != '\0' && !streq (&suffix[1], &stem[stemlen + 1])))
+ continue;
+
+ /* Record if we match a rule that not all filenames will match. */
+ if (target[1] != '\0')
+ specific_rule_may_have_matched = 1;
+
+ /* We have a matching target. Don't search for any more. */
+ break;
+ }
+
+ /* None of the targets matched. */
+ if (rule->targets[i] == 0)
+ continue;
+
+ specific_rule_matched |= specific_rule_may_have_matched;
+
+ /* A rule with no dependencies and no commands exists solely to set
+ specific_rule_matched when it matches. Don't try to use it. */
+ if (rule->deps == 0 && rule->cmds == 0)
+ continue;
+
+ /* Record this rule in TRYRULES and the index
+ of the (first) matching target in MATCHES. */
+ tryrules[nrules] = rule;
+ matches[nrules] = i;
+ checked_lastslash[nrules] = check_lastslash;
+ ++nrules;
+ }
+
+ /* If we have found a matching rule that won't match all filenames,
+ retroactively reject any "terminal" rules that do always match. */
+ if (specific_rule_matched)
+ for (i = 0; i < nrules; ++i)
+ if (!tryrules[i]->terminal)
+ {
+ register unsigned int j;
+ for (j = 0; tryrules[i]->targets[j] != 0; ++j)
+ if (tryrules[i]->targets[j][1] == '\0')
+ break;
+ if (tryrules[i]->targets[j] != 0)
+ tryrules[i] = 0;
+ }
+
+ /* Try each rule once without intermediate files, then once with them. */
+ for (intermed_ok = 0; intermed_ok == !!intermed_ok; ++intermed_ok)
+ {
+ /* Try each pattern rule till we find one that applies.
+ If it does, copy the names of its dependencies (as substituted)
+ and store them in FOUND_FILES. DEPS_FOUND is the number of them. */
+
+ for (i = 0; i < nrules; i++)
+ {
+ int check_lastslash;
+
+ rule = tryrules[i];
+
+ /* RULE is nil when we discover that a rule,
+ already placed in TRYRULES, should not be applied. */
+ if (rule == 0)
+ continue;
+
+ /* Reject any terminal rules if we're
+ looking to make intermediate files. */
+ if (intermed_ok && rule->terminal)
+ continue;
+
+ /* Mark this rule as in use so a recursive
+ pattern_search won't try to use it. */
+ rule->in_use = 1;
+
+ /* From the lengths of the filename and the matching pattern parts,
+ find the stem: the part of the filename that matches the %. */
+ stem = filename
+ + (rule->suffixes[matches[i]] - rule->targets[matches[i]]) - 1;
+ stemlen = namelen - rule->lens[matches[i]] + 1;
+ check_lastslash = (lastslash != 0
+ && index (rule->targets[matches[i]], '/') == 0);
+ if (check_lastslash)
+ {
+ stem += lastslash - filename + 1;
+ stemlen -= (lastslash - filename) + 1;
+ }
+
+ DEBUGP2 ("Trying pattern rule with stem `%.*s'.\n",
+ stemlen, stem);
+
+ /* Try each dependency; see if it "exists". */
+
+ deps_found = 0;
+ for (dep = rule->deps; dep != 0; dep = dep->next)
+ {
+ /* If the dependency name has a %, substitute the stem. */
+ p = index (dep_name (dep), '%');
+ if (p != 0)
+ {
+ register unsigned int i;
+ if (check_lastslash)
+ {
+ i = lastslash - filename + 1;
+ bcopy (filename, depname, i);
+ }
+ else
+ i = 0;
+ bcopy (dep_name (dep), depname + i, p - dep_name (dep));
+ i += p - dep_name (dep);
+ bcopy (stem, depname + i, stemlen);
+ i += stemlen;
+ strcpy (depname + i, p + 1);
+ p = depname;
+ }
+ else
+ p = dep_name (dep);
+
+ /* P is now the actual dependency name as substituted. */
+
+ if (file_impossible_p (p))
+ {
+ /* If this dependency has already been ruled
+ "impossible", then the rule fails and don't
+ bother trying it on the second pass either
+ since we know that will fail too. */
+ DEBUGP2 ("Rejecting impossible %s dependent `%s'.\n",
+ p == depname ? "implicit" : "rule", p);
+ tryrules[i] = 0;
+ break;
+ }
+
+ intermediate_files[deps_found] = 0;
+
+ DEBUGP2 ("Trying %s dependency `%s'.\n",
+ p == depname ? "implicit" : "rule", p);
+ if (!rule->subdir && lookup_file (p) != 0 || file_exists_p (p))
+ {
+ found_files[deps_found++] = savestring (p, strlen (p));
+ continue;
+ }
+ /* This code, given FILENAME = "lib/foo.o", dependency name
+ "lib/foo.c", and VPATH=src, searches for "src/lib/foo.c". */
+ if (vpath_search (&p))
+ {
+ DEBUGP2 ("Found dependent as `%s'.\n", p, 0);
+ found_files[deps_found++] = p;
+ continue;
+ }
+
+ /* We could not find the file in any place we should look.
+ Try to make this dependency as an intermediate file,
+ but only on the second pass. */
+
+ if (intermed_ok)
+ {
+ if (intermediate_file == 0)
+ intermediate_file
+ = (struct file *) alloca (sizeof (struct file));
+
+ DEBUGP2 ("Looking for a rule with intermediate file `%s'.\n",
+ p, 0);
+
+ bzero ((char *) intermediate_file, sizeof (struct file));
+ intermediate_file->name = p;
+ if (pattern_search (intermediate_file, 0, depth + 1,
+ recursions + 1))
+ {
+ p = savestring (p, strlen (p));
+ intermediate_patterns[deps_found]
+ = intermediate_file->name;
+ found_files[deps_found] = p;
+ intermediate_file->name = p;
+ intermediate_files[deps_found] = intermediate_file;
+ intermediate_file = 0;
+ ++deps_found;
+ continue;
+ }
+
+ /* If we have tried to find P as an intermediate
+ file and failed, mark that name as impossible
+ so we won't go through the search again later. */
+ file_impossible (p);
+ }
+
+ /* A dependency of this rule does not exist.
+ Therefore, this rule fails. */
+ break;
+ }
+
+ /* This rule is no longer `in use' for recursive searches. */
+ rule->in_use = 0;
+
+ if (dep != 0)
+ {
+ /* This pattern rule does not apply.
+ If some of its dependencies succeeded,
+ free the data structure describing them. */
+ while (deps_found-- > 0)
+ {
+ register struct file *f = intermediate_files[deps_found];
+ free (found_files[deps_found]);
+ if (f != 0
+ && (f->stem < f->name
+ || f->stem > f->name + strlen (f->name)))
+ free (f->stem);
+ }
+ }
+ else
+ /* This pattern rule does apply. Stop looking for one. */
+ break;
+ }
+
+ /* If we found an applicable rule without
+ intermediate files, don't try with them. */
+ if (i < nrules)
+ break;
+
+ rule = 0;
+ }
+
+ /* RULE is nil if the loop went all the way
+ through the list and everything failed. */
+ if (rule == 0)
+ return 0;
+
+ foundrule = i;
+
+ /* If we are recursing, store the pattern that matched
+ FILENAME in FILE->name for use in upper levels. */
+
+ if (recursions > 0)
+ /* Kludge-o-matic */
+ file->name = rule->targets[matches[foundrule]];
+
+ /* FOUND_FILES lists the dependencies for the rule we found.
+ This includes the intermediate files, if any.
+ Convert them into entries on the deps-chain of FILE. */
+
+ while (deps_found-- > 0)
+ {
+ register char *s;
+
+ if (intermediate_files[deps_found] != 0)
+ {
+ /* If we need to use an intermediate file,
+ make sure it is entered as a target, with the info that was
+ found for it in the recursive pattern_search call.
+ We know that the intermediate file did not already exist as
+ a target; therefore we can assume that the deps and cmds
+ of F below are null before we change them. */
+
+ struct file *imf = intermediate_files[deps_found];
+ register struct file *f = enter_file (imf->name);
+ f->deps = imf->deps;
+ f->cmds = imf->cmds;
+ f->stem = imf->stem;
+ imf = lookup_file (intermediate_patterns[deps_found]);
+ if (imf != 0 && imf->precious)
+ f->precious = 1;
+ f->intermediate = 1;
+ f->tried_implicit = 1;
+ for (dep = f->deps; dep != 0; dep = dep->next)
+ {
+ dep->file = enter_file (dep->name);
+ dep->name = 0;
+ dep->file->tried_implicit |= dep->changed;
+ }
+ num_intermediates++;
+ }
+
+ dep = (struct dep *) xmalloc (sizeof (struct dep));
+ s = found_files[deps_found];
+ if (recursions == 0)
+ {
+ dep->name = 0;
+ dep->file = enter_file (s);
+ }
+ else
+ {
+ dep->name = s;
+ dep->file = 0;
+ dep->changed = 0;
+ }
+ if (intermediate_files[deps_found] == 0 && tryrules[foundrule]->terminal)
+ {
+ /* If the file actually existed (was not an intermediate file),
+ and the rule that found it was a terminal one, then we want
+ to mark the found file so that it will not have implicit rule
+ search done for it. If we are not entering a `struct file' for
+ it now, we indicate this with the `changed' flag. */
+ if (dep->file == 0)
+ dep->changed = 1;
+ else
+ dep->file->tried_implicit = 1;
+ }
+ dep->next = file->deps;
+ file->deps = dep;
+ }
+
+ uniquize_deps (file->deps);
+
+ if (!checked_lastslash[foundrule])
+ file->stem = stem[stemlen] == '\0' ? stem : savestring (stem, stemlen);
+ else
+ {
+ file->stem = (char *) xmalloc (((lastslash + 1) - filename)
+ + stemlen + 1);
+ bcopy (filename, file->stem, (lastslash + 1) - filename);
+ bcopy (stem, file->stem + ((lastslash + 1) - filename), stemlen);
+ file->stem[((lastslash + 1) - filename) + stemlen] = '\0';
+ }
+
+ file->cmds = rule->cmds;
+
+ /* Put the targets other than the one that
+ matched into FILE's `also_make' member. */
+
+ /* If there was only one target, there is nothing to do. */
+ if (rule->targets[1] != 0)
+ for (i = 0; rule->targets[i] != 0; ++i)
+ if (i != matches[foundrule])
+ {
+ struct dep *new = (struct dep *) xmalloc (sizeof (struct dep));
+ new->name = p = (char *) xmalloc (rule->lens[i] + stemlen + 1);
+ bcopy (rule->targets[i], p,
+ rule->suffixes[i] - rule->targets[i] - 1);
+ p += rule->suffixes[i] - rule->targets[i] - 1;
+ bcopy (stem, p, stemlen);
+ p += stemlen;
+ bcopy (rule->suffixes[i], p,
+ rule->lens[i]
+ - (rule->suffixes[i] - rule->targets[i] - 1) + 1);
+ new->file = enter_file (new->name);
+ new->next = file->also_make;
+ file->also_make = new;
+ }
+
+
+ return 1;
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/job.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/job.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/job.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,1419 ----
+ /* Job execution and handling for GNU Make.
+ Copyright (C) 1988-1991 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 2, 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. */
+
+ #include "make.h"
+ #include "commands.h"
+ #include "job.h"
+ #include "file.h"
+ #include "variable.h"
+ #include <errno.h>
+
+ /* Default path to search for executables. */
+ static char default_path[] = ":/bin:/usr/bin";
+
+ /* Default shell to use. */
+ char default_shell[] = "/bin/sh";
+
+ extern int errno;
+
+ #if defined(POSIX) || defined(__GNU_LIBRARY__)
+ #include <limits.h>
+ #include <unistd.h>
+ #define GET_NGROUPS_MAX sysconf (_SC_NGROUPS_MAX)
+ #else /* Not POSIX. */
+ #ifndef USG
+ #include <sys/param.h>
+ #define NGROUPS_MAX NGROUPS
+ #endif /* Not USG. */
+ #endif /* POSIX. */
+
+ #ifdef POSIX
+ #include <sys/wait.h>
+
+ #define WAIT_NOHANG(status) waitpid(-1, (status), WNOHANG)
+
+ #else /* Not POSIX. */
+
+ #if defined(HAVE_SYS_WAIT) || !defined(USG)
+ #include <sys/wait.h>
+ #include <sys/time.h>
+ #include <sys/resource.h>
+
+ #ifndef wait3
+ extern int wait3 ();
+ #endif
+ #define WAIT_NOHANG(status) \
+ wait3((union wait *) (status), WNOHANG, (struct rusage *) 0)
+
+ #if !defined (wait) && !defined (POSIX)
+ extern int wait ();
+ #endif
+ #endif /* HAVE_SYS_WAIT || !USG */
+ #endif /* POSIX. */
+
+ #if defined(WTERMSIG) || (defined(USG) && !defined(HAVE_SYS_WAIT))
+ #define WAIT_T int
+
+ #ifndef WTERMSIG
+ #define WTERMSIG(x) ((x) & 0x7f)
+ #endif
+ #ifndef WCOREDUMP
+ #define WCOREDUMP(x) ((x) & 0x80)
+ #endif
+ #ifndef WEXITSTATUS
+ #define WEXITSTATUS(x) (((x) >> 8) & 0xff)
+ #endif
+ #ifndef WIFSIGNALED
+ #define WIFSIGNALED(x) (WTERMSIG (x) != 0)
+ #endif
+ #ifndef WIFEXITED
+ #define WIFEXITED(x) (WTERMSIG (x) == 0)
+ #endif
+
+ #else /* WTERMSIG not defined and have <sys/wait.h> or not USG. */
+
+ #define WAIT_T union wait
+ #define WTERMSIG(x) ((x).w_termsig)
+ #define WCOREDUMP(x) ((x).w_coredump)
+ #define WEXITSTATUS(x) ((x).w_retcode)
+ #ifndef WIFSIGNALED
+ #define WIFSIGNALED(x) (WTERMSIG(x) != 0)
+ #endif
+ #ifndef WIFEXITED
+ #define WIFEXITED(x) (WTERMSIG(x) == 0)
+ #endif
+
+ #endif /* WTERMSIG defined or USG and don't have <sys/wait.h>. */
+
+
+ #if defined(__GNU_LIBRARY__) || defined(POSIX)
+
+ #include <sys/types.h>
+ #define GID_T gid_t
+
+ #else /* Not GNU C library. */
+
+ #define GID_T int
+
+ extern int dup2 ();
+ extern int execve ();
+ extern void _exit ();
+ extern int geteuid (), getegid ();
+ extern int setgid (), getgid ();
+ #endif /* GNU C library. */
+
+ #ifndef USG
+ extern int getdtablesize ();
+ #else
+ #include <sys/param.h>
+ #define getdtablesize() NOFILE
+ #endif
+
+ extern void wait_to_start_job ();
+ extern int start_remote_job_p ();
+ extern int start_remote_job (), remote_status ();
+
+
+ #if (defined(USG) && !defined(HAVE_SIGLIST)) || defined(DGUX)
+ static char *sys_siglist[NSIG];
+ void init_siglist ();
+ #else /* Not (USG and HAVE_SIGLIST), or DGUX. */
+ extern const char * const sys_siglist[];
+ #endif /* USG and not HAVE_SIGLIST, or DGUX. */
+
+ int child_handler ();
+ static void free_child (), start_job ();
+
+ /* Chain of all children. */
+
+ struct child *children = 0;
+
+ /* Number of children currently running. */
+
+ unsigned int job_slots_used = 0;
+
+ /* Nonzero if the `good' standard input is in use. */
+
+ static int good_stdin_used = 0;
+
+ /* Write an error message describing the exit status given in
+ EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME.
+ Append "(ignored)" if IGNORED is nonzero. */
+
+ static void
+ child_error (target_name, exit_code, exit_sig, coredump, ignored)
+ char *target_name;
+ int exit_code, exit_sig, coredump;
+ int ignored;
+ {
+ char *ignore_string = ignored ? " (ignored)" : "";
+
+ if (exit_sig == 0)
+ error ("*** [%s] Error %d%s", target_name, exit_code, ignore_string);
+ else
+ {
+ char *coredump_string = coredump ? " (core dumped)" : "";
+ if (exit_sig > 0 && exit_sig < NSIG)
+ error ("*** [%s] %s%s",
+ target_name, sys_siglist[exit_sig], coredump_string);
+ else
+ error ("*** [%s] Signal %d%s", target_name, exit_sig, coredump_string);
+ }
+ }
+
+ extern void block_remote_children (), unblock_remote_children ();
+
+ extern int fatal_signal_mask;
+
+ #ifdef USG
+ /* Set nonzero in the interval when it's possible that we may see a dead
+ child that's not in the `children' chain. */
+ static int unknown_children_possible = 0;
+ #endif
+
+
+ /* Block the child termination signal and fatal signals. */
+
+ static void
+ block_signals ()
+ {
+ #ifdef USG
+
+ /* Tell child_handler that it might see children that aren't yet
+ in the `children' chain. */
+ unknown_children_possible = 1;
+
+ /* Ignoring SIGCLD makes wait always return -1.
+ Using the default action does the right thing. */
+ (void) SIGNAL (SIGCLD, SIG_DFL);
+
+ #else /* Not USG. */
+
+ /* Block the signals. */
+ (void) sigblock (fatal_signal_mask | sigmask (SIGCHLD));
+
+ #endif
+
+ block_remote_children ();
+ }
+
+ /* Unblock the child termination signal and fatal signals. */
+ static void
+ unblock_signals ()
+ {
+ #ifdef USG
+
+ (void) SIGNAL (SIGCLD, child_handler);
+
+ /* It should no longer be possible for children not in the chain to die. */
+ unknown_children_possible = 0;
+
+ #else /* Not USG. */
+
+ /* Unblock the signals. */
+ (void) sigsetmask (sigblock (0) & ~(fatal_signal_mask | sigmask (SIGCHLD)));
+
+ #endif
+
+ unblock_remote_children ();
+ }
+
+ static char *signals_blocked_p_stack = 0;
+ static unsigned int signals_blocked_p_max;
+ static unsigned int signals_blocked_p_depth;
+
+ /* Make signals blocked in FLAG is nonzero, unblocked if FLAG is zero.
+ Push this setting on the signals_blocked_p_stack, so it can be
+ popped off by pop_signals_blocked_p. */
+
+ void
+ push_signals_blocked_p (flag)
+ int flag;
+ {
+ int blocked;
+
+ if (signals_blocked_p_stack == 0)
+ {
+ signals_blocked_p_max = 8;
+ signals_blocked_p_stack = (char *) xmalloc (8);
+ signals_blocked_p_depth = 1;
+ signals_blocked_p_stack[0] = flag;
+
+ blocked = 0;
+ }
+ else
+ {
+ if (signals_blocked_p_depth == signals_blocked_p_max)
+ {
+ signals_blocked_p_max += 8;
+ signals_blocked_p_stack
+ = (char *) xrealloc(signals_blocked_p_stack,
+ signals_blocked_p_max);
+ }
+
+ blocked = (signals_blocked_p_depth > 0
+ && signals_blocked_p_stack[signals_blocked_p_depth - 1]);
+
+ signals_blocked_p_stack[++signals_blocked_p_depth - 1] = flag;
+ }
+
+ if (blocked && !flag)
+ unblock_signals ();
+ else if (flag && !blocked)
+ block_signals ();
+ }
+
+ /* Pop the signals_blocked_p setting from the stack
+ and block or unblock signals as appropriate. */
+
+ void
+ pop_signals_blocked_p ()
+ {
+ int blocked, block;
+
+ blocked = (signals_blocked_p_depth > 0
+ && signals_blocked_p_stack[signals_blocked_p_depth-- - 1]);
+
+ block = (signals_blocked_p_depth > 0
+ && signals_blocked_p_stack[signals_blocked_p_depth - 1]);
+
+ if (block && !blocked)
+ block_signals ();
+ else if (blocked && !block)
+ unblock_signals ();
+ }
+
+ extern int shell_function_pid, shell_function_completed;
+
+ /* Handle a child-termination signal (SIGCHLD, or SIGCLD for USG),
+ storing the returned status and the new command state (`cs_finished')
+ in the `file' member of the `struct child' for the dead child,
+ and removing the child from the chain.
+
+ If we were called as a signal handler, SIG should be SIGCHLD
+ (SIGCLD for USG). If instead it is zero, we were called explicitly
+ and should block waiting for running children.
+ If SIG is < 0, - SIG is the maximum number of children to bury (record
+ status of and remove from the chain). */
+
+ int
+ child_handler (sig)
+ int sig;
+ {
+ WAIT_T status;
+ unsigned int dead_children = 0;
+
+ if (sig > 0)
+ block_signals ();
+
+ while (1)
+ {
+ int remote = 0;
+ register int pid;
+ int exit_code, exit_sig, coredump;
+ register struct child *lastc, *c;
+ int child_failed;
+
+ /* First, check for remote children. */
+ pid = remote_status (&exit_code, &exit_sig, &coredump, 0);
+ if (pid < 0)
+ {
+ /* No remote children. Check for local children. */
+
+ #ifdef WAIT_NOHANG
+ if (sig > 0)
+ pid = WAIT_NOHANG (&status);
+ else
+ pid = wait (&status);
+ #else /* USG and don't HAVE_SYS_WAIT. */
+ /* System V cannot do non-blocking waits, so we have two
+ choices if called as a signal handler: handle only one
+ child (there may be more if the signal was blocked),
+ or block waiting for more. The latter option makes
+ parallelism useless, so we must choose the former. */
+ pid = wait (&status);
+ #endif /* HAVE_SYS_WAIT or not USG. */
+
+ if (pid <= 0)
+ /* No local children. */
+ break;
+ else
+ {
+ /* Chop the status word up. */
+ exit_code = WEXITSTATUS (status);
+ exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0;
+ coredump = WCOREDUMP (status);
+ }
+ }
+ else
+ /* We got a remote child. */
+ remote = 1;
+
+ /* Check if this is the child of the `shell' function. */
+ if (!remote && pid == shell_function_pid)
+ {
+ /* It is. Leave an indicator for the `shell' function. */
+ if (exit_sig == 0 && exit_code == 127)
+ shell_function_completed = -1;
+ else
+ shell_function_completed = 1;
+
+ /* Check if we have reached our quota of children. */
+ ++dead_children;
+ if (sig < 0 && dead_children == -sig)
+ break;
+ #if defined(USG) && !defined(HAVE_SYS_WAIT)
+ else if (sig > 0)
+ break;
+ #endif
+ else
+ continue;
+ }
+
+ child_failed = exit_sig != 0 || exit_code != 0;
+
+ /* Search for a child matching the deceased one. */
+ lastc = 0;
+ for (c = children; c != 0; lastc = c, c = c->next)
+ if (c->remote == remote && c->pid == pid)
+ break;
+
+ if (c == 0)
+ {
+ /* An unknown child died. */
+ #ifdef USG
+ if (!unknown_children_possible)
+ {
+ #endif
+ char buf[100];
+ sprintf (buf, "Unknown%s job %d", remote ? " remote" : "", pid);
+ if (child_failed)
+ child_error (buf, exit_code, exit_sig, coredump,
+ ignore_errors_flag);
+ else
+ error ("%s finished.", buf);
+ #ifdef USG
+ }
+ #endif
+ }
+ else
+ {
+ /* If this child had the good stdin, say it is now free. */
+ if (c->good_stdin)
+ good_stdin_used = 0;
+
+ if (child_failed && !c->noerror && !ignore_errors_flag)
+ {
+ /* The commands failed. Write an error message,
+ delete non-precious targets, and abort. */
+ child_error (c->file->name, exit_code, exit_sig, coredump, 0);
+ c->file->update_status = 1;
+ if (exit_sig != 0)
+ delete_child_targets (c);
+ }
+ else
+ {
+ if (child_failed)
+ {
+ /* The commands failed, but we don't care. */
+ child_error (c->file->name,
+ exit_code, exit_sig, coredump, 1);
+ child_failed = 0;
+ }
+
+ /* If there are more commands to run, try to start them. */
+ start_job (c);
+
+ switch (c->file->command_state)
+ {
+ case cs_running:
+ /* Successfully started. Loop to reap more children. */
+ continue;
+
+ case cs_finished:
+ if (c->file->update_status != 0)
+ {
+ /* We failed to start the commands. */
+ delete_child_targets (c);
+ }
+ break;
+
+ default:
+ error ("internal error: `%s' command_state \
+ %d in child_handler", c->file->name);
+ abort ();
+ break;
+ }
+ }
+
+ /* Set the state flag to say the commands have finished. */
+ notice_finished_file (c->file);
+
+ /* Remove the child from the chain and free it. */
+ if (lastc == 0)
+ children = c->next;
+ else
+ lastc->next = c->next;
+ free_child (c);
+
+ /* There is now another slot open. */
+ --job_slots_used;
+
+ /* If the job failed, and the -k flag was not given, die. */
+ if (child_failed && !keep_going_flag)
+ die (1);
+
+ /* See if we have reached our quota for blocking. */
+ ++dead_children;
+ if (sig < 0 && dead_children == -sig)
+ break;
+ #if defined(USG) && !defined(HAVE_SYS_WAIT)
+ else if (sig > 0)
+ break;
+ #endif
+ }
+ }
+
+ #ifdef USG
+ if (sig > 0)
+ (void) SIGNAL (sig, child_handler);
+ #endif
+
+ if (sig > 0)
+ unblock_signals ();
+
+ return 0;
+ }
+
+
+ /* Wait for N children, blocking if necessary.
+ If N is zero, wait until we run out of children.
+ If ERR is nonzero and we have any children to wait for,
+ print a message on stderr. */
+
+ void
+ wait_for_children (n, err)
+ unsigned int n;
+ int err;
+ {
+ push_signals_blocked_p (1);
+
+ if (err && (children != 0 || shell_function_pid != 0))
+ {
+ fflush (stdout);
+ error ("*** Waiting for unfinished jobs....");
+ }
+
+ /* Call child_handler to do the work. */
+ (void) child_handler (- (int) n);
+
+ pop_signals_blocked_p ();
+ }
+
+ /* Free the storage allocated for CHILD. */
+
+ static void
+ free_child (child)
+ register struct child *child;
+ {
+ if (child->command_lines != 0)
+ {
+ register unsigned int i;
+ for (i = 0; i < child->file->cmds->ncommand_lines; ++i)
+ free (child->command_lines[i]);
+ free ((char *) child->command_lines);
+ }
+
+ if (child->environment != 0)
+ {
+ register char **ep = child->environment;
+ while (*ep != 0)
+ free (*ep++);
+ free ((char *) child->environment);
+ }
+
+ free ((char *) child);
+ }
+
+ /* Start a job to run the commands specified in CHILD.
+ CHILD is updated to reflect the commands and ID of the child process. */
+
+ static void
+ start_job (child)
+ register struct child *child;
+ {
+ static int bad_stdin = -1;
+ register char *p;
+ char noprint = 0, recursive;
+ char **argv;
+
+ if (child->command_ptr == 0 || *child->command_ptr == '\0')
+ {
+ /* There are no more lines in the expansion of this line. */
+ if (child->command_line == child->file->cmds->ncommand_lines)
+ {
+ /* There are no more lines to be expanded. */
+ child->command_ptr = 0;
+ child->file->command_state = cs_finished;
+ child->file->update_status = 0;
+ return;
+ }
+ else
+ {
+ /* Get the next line to run, and set RECURSIVE
+ if the unexpanded line contains $(MAKE). */
+ child->command_ptr = child->command_lines[child->command_line];
+ recursive = child->file->cmds->lines_recurse[child->command_line];
+ ++child->command_line;
+ }
+ }
+ else
+ /* Still executing the last line we started. */
+ recursive = child->file->cmds->lines_recurse[child->command_line - 1];
+
+ /* Find the end of this line. Backslash-newlines don't mean the end. */
+
+ p = child->command_ptr;
+ child->noerror = 0;
+ while (*p != '\0')
+ {
+ if (*p == '@')
+ noprint = 1;
+ else if (*p == '-')
+ child->noerror = 1;
+ else if (*p == '+')
+ recursive = 1;
+ else if (!isblank (*p))
+ break;
+ ++p;
+ }
+
+ /* If -q was given, just say that updating `failed'. */
+ if (question_flag && !recursive)
+ goto error;
+
+ /* There may be some preceding whitespace left if there
+ was nothing but a backslash on the first line. */
+ p = next_token (p);
+
+ /* Figure out an argument list from this command line. */
+
+ {
+ char *end;
+ argv = construct_command_argv (p, &end, child->file);
+ if (end == NULL)
+ child->command_ptr = NULL;
+ else
+ {
+ *end++ = '\0';
+ child->command_ptr = end;
+ }
+ }
+
+ /* Print out the command. */
+
+ if (just_print_flag || (!noprint && !silent_flag))
+ puts (p);
+
+ if (argv == 0)
+ {
+ /* This line has no commands. Go to the next. */
+ start_job (child);
+ return;
+ }
+
+ /* If -n was given, recurse to get the next line in the sequence. */
+
+ if (just_print_flag && !recursive)
+ {
+ free (argv[0]);
+ free ((char *) argv);
+ start_job (child);
+ return;
+ }
+
+ /* Flush the output streams so they won't have things written twice. */
+
+ fflush (stdout);
+ fflush (stderr);
+
+ /* Set up a bad standard input that reads from a broken pipe. */
+
+ if (bad_stdin == -1)
+ {
+ /* Make a file descriptor that is the read end of a broken pipe.
+ This will be used for some children's standard inputs. */
+ int pd[2];
+ if (pipe (pd) == 0)
+ {
+ /* Close the write side. */
+ (void) close (pd[1]);
+ /* Save the read side. */
+ bad_stdin = pd[0];
+ }
+ }
+
+ /* Decide whether to give this child the `good' standard input
+ (one that points to the terminal or whatever), or the `bad' one
+ that points to the read side of a broken pipe. */
+
+ child->good_stdin = !good_stdin_used;
+ if (child->good_stdin)
+ good_stdin_used = 1;
+
+ child->deleted = 0;
+
+ /* Set up the environment for the child. */
+ if (child->environment == 0)
+ child->environment = target_environment (child->file);
+
+ if (start_remote_job_p ())
+ {
+ int is_remote, id, used_stdin;
+ if (start_remote_job (argv, child->good_stdin ? 0 : bad_stdin,
+ &is_remote, &id, &used_stdin))
+ goto error;
+ else
+ {
+ if (child->good_stdin && !used_stdin)
+ {
+ child->good_stdin = 0;
+ good_stdin_used = 0;
+ }
+ child->remote = is_remote;
+ child->pid = id;
+ }
+ }
+ else
+ {
+ if (child->command_line - 1 == 0)
+ {
+ /* Wait for the load to be low enough if this
+ is the first command in the sequence. */
+ make_access ();
+ wait_to_start_job ();
+ user_access ();
+ }
+
+ /* Fork the child process. */
+
+ child->remote = 0;
+ child->pid = vfork ();
+ if (child->pid == 0)
+ /* We are the child side. */
+ child_execute_job (child->good_stdin ? 0 : bad_stdin, 1,
+ argv, child->environment);
+ else if (child->pid < 0)
+ {
+ /* Fork failed! */
+ perror_with_name (VFORK_NAME, "");
+ goto error;
+ }
+ }
+
+ /* We are the parent side. Set the state to
+ say the commands are running and return. */
+
+ child->file->command_state = cs_running;
+
+ /* Free the storage used by the child's argument list. */
+
+ free (argv[0]);
+ free ((char *) argv);
+
+ return;
+
+ error:;
+ child->file->update_status = 1;
+ child->file->command_state = cs_finished;
+ }
+
+
+ /* Create a `struct child' for FILE and start its commands running. */
+
+ void
+ new_job (file)
+ register struct file *file;
+ {
+ register struct commands *cmds = file->cmds;
+ register struct child *c;
+ char **lines;
+ register unsigned int i;
+
+ /* Chop the commands up into lines if they aren't already. */
+ 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);
+
+ /* Expand the command lines and store the results in LINES. */
+ lines = (char **) xmalloc (cmds->ncommand_lines * sizeof (char *));
+ for (i = 0; i < cmds->ncommand_lines; ++i)
+ lines[i] = allocated_variable_expand_for_file (cmds->command_lines[i],
+ file);
+
+ /* Start the command sequence, record it in a new
+ `struct child', and add that to the chain. */
+
+ push_signals_blocked_p (1);
+
+ c = (struct child *) xmalloc (sizeof (struct child));
+ c->file = file;
+ c->command_lines = lines;
+ c->command_line = 0;
+ c->command_ptr = 0;
+ c->environment = 0;
+ start_job (c);
+ switch (file->command_state)
+ {
+ case cs_running:
+ c->next = children;
+ children = c;
+ /* One more job slot is in use. */
+ ++job_slots_used;
+ break;
+
+ case cs_finished:
+ free_child (c);
+ notice_finished_file (file);
+ break;
+
+ default:
+ error ("internal error: `%s' command_state == %d in new_job",
+ file->name, (int) file->command_state);
+ abort ();
+ break;
+ }
+
+ pop_signals_blocked_p ();
+
+ if (job_slots == 1 && file->command_state == cs_running)
+ {
+ /* Since there is only one job slot, make things run linearly.
+ Wait for the child to finish, setting the state to `cs_finished'. */
+ while (file->command_state != cs_finished)
+ wait_for_children (1, 0);
+ }
+ }
+
+ /* Replace the current process with one executing the command in ARGV.
+ STDIN_FD and STDOUT_FD are used as the process's stdin and stdout; ENVP is
+ the environment of the new program. This function does not return. */
+
+ void
+ child_execute_job (stdin_fd, stdout_fd, argv, envp)
+ int stdin_fd, stdout_fd;
+ char **argv, **envp;
+ {
+ if (stdin_fd != 0)
+ (void) dup2 (stdin_fd, 0);
+ if (stdout_fd != 1)
+ (void) dup2 (stdout_fd, 1);
+
+ /* Free up file descriptors. */
+ {
+ register int d;
+ int max = getdtablesize ();
+ for (d = 3; d < max; ++d)
+ (void) close (d);
+ }
+
+ /* Don't block signals for the new process. */
+ unblock_signals ();
+
+ /* Run the command. */
+ exec_command (argv, envp);
+ }
+
+ /* Search PATH for FILE.
+ If successful, store the full pathname in PROGRAM and return 1.
+ If not sucessful, return zero. */
+
+ static int
+ search_path (file, path, program)
+ char *file, *path, *program;
+ {
+ if (path == 0 || path[0] == '\0')
+ path = default_path;
+
+ if (index (file, '/') != 0)
+ {
+ strcpy (program, file);
+ return 1;
+ }
+ else
+ {
+ unsigned int len;
+
+ #if !defined (USG) || defined (POSIX)
+ #ifndef POSIX
+ extern int getgroups ();
+ #endif
+ static int ngroups = -1;
+ #ifdef NGROUPS_MAX
+ static GID_T groups[NGROUPS_MAX];
+ #define ngroups_max NGROUPS_MAX
+ #else
+ static GID_T *groups = 0;
+ static int ngroups_max;
+ if (groups == 0)
+ {
+ ngroups_max = GET_NGROUPS_MAX;
+ groups = (GID_T *) malloc (ngroups_max * sizeof (GID_T));
+ }
+ #endif
+ if (groups != 0 && ngroups == -1)
+ ngroups = getgroups (ngroups_max, groups);
+ #endif /* POSIX or not USG. */
+
+ len = strlen (file) + 1;
+ do
+ {
+ struct stat st;
+ int perm;
+ char *p;
+
+ p = index (path, ':');
+ if (p == 0)
+ p = path + strlen (path);
+
+ if (p == path)
+ bcopy (file, program, len);
+ else
+ {
+ bcopy (path, program, p - path);
+ program[p - path] = '/';
+ bcopy (file, program + (p - path) + 1, len);
+ }
+
+ if (stat (program, &st) == 0
+ && S_ISREG (st.st_mode))
+ {
+ if (st.st_uid == geteuid ())
+ perm = (st.st_mode & 0100);
+ else if (st.st_gid == getegid ())
+ perm = (st.st_mode & 0010);
+ else
+ {
+ #ifndef USG
+ register int i;
+ for (i = 0; i < ngroups; ++i)
+ if (groups[i] == st.st_gid)
+ break;
+ if (i < ngroups)
+ perm = (st.st_mode & 0010);
+ else
+ #endif /* Not USG. */
+ perm = (st.st_mode & 0001);
+ }
+
+ if (perm != 0)
+ return 1;
+ }
+
+ path = p + 1;
+ } while (*path != '\0');
+ }
+
+ return 0;
+ }
+
+ /* Replace the current process with one running the command in ARGV,
+ with environment ENVP. This function does not return. */
+
+ void
+ exec_command (argv, envp)
+ char **argv, **envp;
+ {
+ char *shell, *path;
+ PATH_VAR (program);
+ register char **ep;
+
+ shell = path = 0;
+ for (ep = envp; *ep != 0; ++ep)
+ {
+ if (shell == 0 && !strncmp(*ep, "SHELL=", 6))
+ shell = &(*ep)[6];
+ else if (path == 0 && !strncmp(*ep, "PATH=", 5))
+ path = &(*ep)[5];
+ else if (path != 0 && shell != 0)
+ break;
+ }
+
+ /* Be the user, permanently. */
+ child_access ();
+
+ if (!search_path (argv[0], path, program))
+ error ("%s: Command not found", argv[0]);
+ else
+ {
+ /* Run the program. */
+ execve (program, argv, envp);
+
+ if (errno == ENOEXEC)
+ {
+ PATH_VAR (shell_program);
+ char *shell_path;
+ if (shell == 0)
+ shell_path = default_shell;
+ else
+ {
+ if (search_path (shell, path, shell_program))
+ shell_path = shell_program;
+ else
+ {
+ shell_path = 0;
+ error ("%s: Shell program not found", shell);
+ }
+ }
+
+ if (shell_path != 0)
+ {
+ char **new_argv;
+ int argc;
+
+ argc = 1;
+ while (argv[argc] != 0)
+ ++argc;
+
+ new_argv = (char **) alloca ((1 + argc + 1) * sizeof (char *));
+ new_argv[0] = shell_path;
+ new_argv[1] = program;
+ while (argc > 0)
+ {
+ new_argv[1 + argc] = argv[argc];
+ --argc;
+ }
+
+ execve (shell_path, new_argv, envp);
+ perror_with_name ("execve: ", shell_path);
+ }
+ }
+ else
+ perror_with_name ("execve: ", program);
+ }
+
+ _exit (127);
+ }
+
+ /* Figure out the argument list necessary to run LINE as a command.
+ Try to avoid using a shell. This routine handles only ' quoting.
+ Starting quotes may be escaped with a backslash. If any of the
+ characters in sh_chars[] is seen, or any of the builtin commands
+ listed in sh_cmds[] is the first word of a line, the shell is used.
+
+ If RESTP is not NULL, *RESTP is set to point to the first newline in LINE.
+ If *RESTP is NULL, newlines will be ignored.
+
+ SHELL is the shell to use, or nil to use the default shell.
+ IFS is the value of $IFS, or nil (meaning the default). */
+
+ static char **
+ construct_command_argv_internal (line, restp, shell, ifs)
+ char *line, **restp;
+ char *shell, *ifs;
+ {
+ static char sh_chars[] = "#;\"*?[]&|<>(){}=$`";
+ static char *sh_cmds[] = { "cd", "eval", "exec", "exit", "login",
+ "logout", "set", "umask", "wait", "while", "for",
+ "case", "if", ":", ".", "break", "continue",
+ "export", "read", "readonly", "shift", "times",
+ "trap", "switch", 0 };
+ register int i;
+ register char *p;
+ register char *ap;
+ char *end;
+ int instring;
+ char **new_argv = 0;
+
+ /* See if it is safe to parse commands internally. */
+ if (shell != 0 && strcmp (shell, default_shell))
+ goto slow;
+
+ if (ifs != 0)
+ for (ap = ifs; *ap != '\0'; ++ap)
+ if (*ap != ' ' && *ap != '\t' && *ap != '\n')
+ goto slow;
+
+ i = strlen (line) + 1;
+
+ /* More than 1 arg per character is impossible. */
+ new_argv = (char **) xmalloc (i * sizeof (char *));
+
+ /* All the args can fit in a buffer as big as LINE is. */
+ ap = new_argv[0] = (char *) xmalloc (i);
+ end = ap + i;
+
+ if (restp != NULL)
+ *restp = NULL;
+
+ /* I is how many complete arguments have been found. */
+ i = 0;
+ instring = 0;
+ for (p = line; *p != '\0'; ++p)
+ {
+ if (ap > end)
+ abort ();
+
+ if (instring)
+ {
+ /* Inside a string, just copy any char except a closing quote. */
+ if (*p == '\'')
+ instring = 0;
+ else
+ *ap++ = *p;
+ }
+ else if (index (sh_chars, *p) != 0)
+ /* Not inside a string, but it's a special char. */
+ goto slow;
+ else
+ /* Not a special char. */
+ switch (*p)
+ {
+ case '\\':
+ /* Backslash-newline combinations are eaten. */
+ if (p[1] != '\0' && p[1] != '\n')
+ /* Copy and skip the following char. */
+ *ap++ = *++p;
+ break;
+
+ case '\'':
+ instring = 1;
+ break;
+
+ case '\n':
+ if (restp != NULL)
+ {
+ /* End of the command line. */
+ *restp = p;
+ goto end_of_line;
+ }
+ else
+ /* Newlines are not special. */
+ *ap++ = '\n';
+ break;
+
+ case ' ':
+ case '\t':
+ /* We have the end of an argument.
+ Terminate the text of the argument. */
+ *ap++ = '\0';
+ new_argv[++i] = ap;
+ /* If this argument is the command name,
+ see if it is a built-in shell command.
+ If so, have the shell handle it. */
+ if (i == 1)
+ {
+ register int j;
+ for (j = 0; sh_cmds[j] != 0; ++j)
+ if (streq (sh_cmds[j], new_argv[0]))
+ goto slow;
+ }
+
+ /* Ignore multiple whitespace chars. */
+ p = next_token (p);
+ /* Next iteration should examine the first nonwhite char. */
+ --p;
+ break;
+
+ default:
+ *ap++ = *p;
+ break;
+ }
+ }
+ end_of_line:
+
+ if (instring)
+ /* Let the shell deal with an unterminated quote. */
+ goto slow;
+
+ /* Terminate the last argument and the argument list. */
+
+ *ap = '\0';
+ if (new_argv[i][0] != '\0')
+ ++i;
+ new_argv[i] = 0;
+
+ if (new_argv[0] == 0)
+ /* Line was empty. */
+ return 0;
+ else
+ return new_argv;
+
+ slow:;
+ /* We must use the shell. */
+
+ if (new_argv != 0)
+ {
+ /* Free the old argument list we were working on. */
+ free (new_argv[0]);
+ free (new_argv);
+ }
+
+ if (shell == 0 || !strcmp (shell, default_shell))
+ {
+ /* The shell is the default, or we're in a recursive call to construct
+ the argument list for the real shell. Construct a simple argument
+ list using the default shell. */
+ new_argv = (char **) xmalloc (4 * sizeof (char *));
+ new_argv[0] = savestring (default_shell, sizeof (default_shell) - 1);
+ new_argv[1] = "-c";
+ new_argv[2] = savestring (line, strlen (line));
+ new_argv[3] = 0;
+ }
+ else
+ {
+ /* SHELL may be a multi-word command. Construct a command line
+ "SHELL -c LINE", with all special chars in LINE escaped.
+ Then recurse, expanding this command line to get the final
+ argument list. */
+
+ unsigned int shell_len = strlen (shell);
+ static char minus_c[] = " -c ";
+ unsigned int line_len = strlen (line);
+
+ char *new_line = (char *) alloca (shell_len + (sizeof (minus_c) - 1)
+ + (line_len * 2) + 1);
+
+ ap = new_line;
+ bcopy (shell, ap, shell_len);
+ ap += shell_len;
+ bcopy (minus_c, ap, sizeof (minus_c) - 1);
+ ap += sizeof (minus_c) - 1;
+ for (p = line; *p != '\0'; ++p)
+ {
+ if (*p == '\\' || *p == '\''
+ || isspace (*p)
+ || index (sh_chars, *p) != 0)
+ *ap++ = '\\';
+ *ap++ = *p;
+ }
+ *ap = '\0';
+
+ new_argv = construct_command_argv_internal (new_line, restp,
+ (char *) 0, (char *) 0);
+ }
+
+ return new_argv;
+ }
+
+ /* Figure out the argument list necessary to run LINE as a command.
+ Try to avoid using a shell. This routine handles only ' quoting.
+ Starting quotes may be escaped with a backslash. If any of the
+ characters in sh_chars[] is seen, or any of the builtin commands
+ listed in sh_cmds[] is the first word of a line, the shell is used.
+
+ If RESTP is not NULL, *RESTP is set to point to the first newline in LINE.
+ If *RESTP is NULL, newlines will be ignored.
+
+ FILE is the target whose commands these are. It is used for
+ variable expansion for $(SHELL) and $(IFS). */
+
+ char **
+ construct_command_argv (line, restp, file)
+ char *line, **restp;
+ struct file *file;
+ {
+ char *shell = allocated_variable_expand_for_file ("$(SHELL)", file);
+ char *ifs = allocated_variable_expand_for_file ("$(IFS)", file);
+ char **argv;
+
+ argv = construct_command_argv_internal (line, restp, shell, ifs);
+
+ free (shell);
+ free (ifs);
+
+ return argv;
+ }
+
+ #if (defined(USG) && !defined(HAVE_SIGLIST)) || defined(DGUX)
+ /* Initialize sys_siglist. */
+
+ void
+ init_siglist ()
+ {
+ char buf[100];
+ register unsigned int i;
+
+ for (i = 0; i < NSIG; ++i)
+ switch (i)
+ {
+ default:
+ sprintf (buf, "Signal %u", i);
+ sys_siglist[i] = savestring (buf, strlen (buf));
+ break;
+ case SIGHUP:
+ sys_siglist[i] = "Hangup";
+ break;
+ case SIGINT:
+ sys_siglist[i] = "Interrupt";
+ break;
+ case SIGQUIT:
+ sys_siglist[i] = "Quit";
+ break;
+ case SIGILL:
+ sys_siglist[i] = "Illegal Instruction";
+ break;
+ case SIGTRAP:
+ sys_siglist[i] = "Trace Trap";
+ break;
+ case SIGIOT:
+ sys_siglist[i] = "IOT Trap";
+ break;
+ #ifdef SIGEMT
+ case SIGEMT:
+ sys_siglist[i] = "EMT Trap";
+ break;
+ #endif
+ #ifdef SIGDANGER
+ case SIGDANGER:
+ sys_siglist[i] = "Danger signal";
+ break;
+ #endif
+ case SIGFPE:
+ sys_siglist[i] = "Floating Point Exception";
+ break;
+ case SIGKILL:
+ sys_siglist[i] = "Killed";
+ break;
+ case SIGBUS:
+ sys_siglist[i] = "Bus Error";
+ break;
+ case SIGSEGV:
+ sys_siglist[i] = "Segmentation fault";
+ break;
+ case SIGSYS:
+ sys_siglist[i] = "Bad Argument to System Call";
+ break;
+ case SIGPIPE:
+ sys_siglist[i] = "Broken Pipe";
+ break;
+ case SIGALRM:
+ sys_siglist[i] = "Alarm Clock";
+ break;
+ case SIGTERM:
+ sys_siglist[i] = "Terminated";
+ break;
+ #if !defined (SIGIO) || SIGUSR1 != SIGIO
+ case SIGUSR1:
+ sys_siglist[i] = "User-defined signal 1";
+ break;
+ #endif
+ #if !defined (SIGURG) || SIGUSR2 != SIGURG
+ case SIGUSR2:
+ sys_siglist[i] = "User-defined signal 2";
+ break;
+ #endif
+ #ifdef SIGCLD
+ case SIGCLD:
+ #endif
+ #if defined(SIGCHLD) && !defined(SIGCLD)
+ case SIGCHLD:
+ #endif
+ sys_siglist[i] = "Child Process Exited";
+ break;
+ #ifdef SIGPWR
+ case SIGPWR:
+ sys_siglist[i] = "Power Failure";
+ break;
+ #endif
+ #ifdef SIGVTALRM
+ case SIGVTALRM:
+ sys_siglist[i] = "Virtual Timer Alarm";
+ break;
+ #endif
+ #ifdef SIGPROF
+ case SIGPROF:
+ sys_siglist[i] = "Profiling Alarm Clock";
+ break;
+ #endif
+ #ifdef SIGIO
+ case SIGIO:
+ sys_siglist[i] = "I/O Possible";
+ break;
+ #endif
+ #ifdef SIGWINDOW
+ case SIGWINDOW:
+ sys_siglist[i] = "Window System Signal";
+ break;
+ #endif
+ #ifdef SIGSTOP
+ case SIGSTOP:
+ sys_siglist[i] = "Stopped (signal)";
+ break;
+ #endif
+ #ifdef SIGTSTP
+ case SIGTSTP:
+ sys_siglist[i] = "Stopped";
+ break;
+ #endif
+ #ifdef SIGCONT
+ case SIGCONT:
+ sys_siglist[i] = "Continued";
+ break;
+ #endif
+ #ifdef SIGTTIN
+ case SIGTTIN:
+ sys_siglist[i] = "Stopped (tty input)";
+ break;
+ #endif
+ #ifdef SIGTTOU
+ case SIGTTOU:
+ sys_siglist[i] = "Stopped (tty output)";
+ break;
+ #endif
+ #ifdef SIGURG
+ case SIGURG:
+ sys_siglist[i] = "Urgent Condition on Socket";
+ break;
+ #endif
+ #ifdef SIGXCPU
+ case SIGXCPU:
+ sys_siglist[i] = "CPU Limit Exceeded";
+ break;
+ #endif
+ #ifdef SIGXFSZ
+ case SIGXFSZ:
+ sys_siglist[i] = "File Size Limit Exceeded";
+ break;
+ #endif
+ }
+ }
+ #endif /* USG and not HAVE_SIGLIST. */
+
+ #if defined(USG) && !defined(USGr3) && !defined(HAVE_DUP2)
+ int
+ dup2 (old, new)
+ int old, new;
+ {
+ int fd;
+
+ (void) close (new);
+ fd = dup (old);
+ if (fd != new)
+ {
+ (void) close (fd);
+ errno = EMFILE;
+ return -1;
+ }
+
+ return fd;
+ }
+ #endif /* USG and not USGr3 and not HAVE_DUP2. */
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/job.h
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/job.h:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/job.h Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,34 ----
+ /* Structure describing a running or dead child process. */
+
+ struct child
+ {
+ struct child *next; /* Link in the chain. */
+
+ struct file *file; /* File being remade. */
+
+ char **environment; /* Environment for commands. */
+
+ char **command_lines; /* Array of variable-expanded cmd lines. */
+ unsigned int command_line; /* Index into above. */
+ char *command_ptr; /* Ptr into command_lines[command_line]. */
+
+ int pid; /* Child process's ID number. */
+ unsigned int remote:1; /* Nonzero if executing remotely. */
+
+ unsigned int noerror:1; /* Nonzero if commands contained a `-'. */
+
+ unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */
+ unsigned int deleted:1; /* Nonzero if targets have been deleted. */
+ };
+
+ extern struct child *children;
+
+ extern void new_job ();
+ extern void wait_for_children ();
+ extern void push_signals_blocked_p (), pop_signals_blocked_p ();
+
+ extern char **construct_command_argv ();
+ extern void child_execute_job ();
+ extern void exec_command ();
+
+ extern unsigned int job_slots_used;
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/load.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/load.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/load.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,311 ----
+ /* Copyright (C) 1988, 1989, 1991 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 2, 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. */
+
+ #include "make.h"
+ #include "commands.h"
+ #include "job.h"
+
+ #ifdef UMAX
+
+ #define LDAV_BASED
+
+ /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
+ have a /dev/kmem. Information about the workings of the running kernel
+ can be gathered with inq_stats system calls. */
+ #include <stdio.h>
+ #include <signal.h>
+
+ #include <sys/time.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+ #include <sys/syscall.h>
+
+ #ifdef UMAX_43
+ #include <machine/cpu.h>
+ #include <inq_stats/statistics.h>
+ #include <inq_stats/sysstats.h>
+ #include <inq_stats/cpustats.h>
+ #include <inq_stats/procstats.h>
+ #else /* Not UMAX_43. */
+ #include <sys/sysdefs.h>
+ #include <sys/statistics.h>
+ #include <sys/sysstats.h>
+ #include <sys/cpudefs.h>
+ #include <sys/cpustats.h>
+ #include <sys/procstats.h>
+ #endif
+
+ double
+ load_average ()
+ {
+ static unsigned int cpus = 0, samples;
+ struct proc_summary proc_sum_data;
+ struct stat_descr proc_info;
+ double load;
+ register unsigned int i, j;
+
+ if (cpus == 0)
+ {
+ register unsigned int c, i;
+ struct cpu_config conf;
+ struct stat_descr desc;
+
+ desc.sd_next = 0;
+ desc.sd_subsys = SUBSYS_CPU;
+ desc.sd_type = CPUTYPE_CONFIG;
+ desc.sd_addr = (char *) &conf;
+ desc.sd_size = sizeof conf;
+
+ if (inq_stats (1, &desc))
+ return 0.0;
+
+ c = 0;
+ for (i = 0; i < conf.config_maxclass; ++i)
+ {
+ struct class_stats stats;
+ bzero ((char *) &stats, sizeof stats);
+
+ desc.sd_type = CPUTYPE_CLASS;
+ desc.sd_objid = i;
+ desc.sd_addr = (char *) &stats;
+ desc.sd_size = sizeof stats;
+
+ if (inq_stats (1, &desc))
+ return 0.0;
+
+ c += stats.class_numcpus;
+ }
+ cpus = c;
+ samples = cpus < 2 ? 3 : (2 * cpus / 3);
+ }
+
+ proc_info.sd_next = 0;
+ proc_info.sd_subsys = SUBSYS_PROC;
+ proc_info.sd_type = PROCTYPE_SUMMARY;
+ proc_info.sd_addr = (char *) &proc_sum_data;
+ proc_info.sd_size = sizeof (struct proc_summary);
+ proc_info.sd_sizeused = 0;
+
+ if (inq_stats (1, &proc_info) != 0)
+ return 0.0;
+
+ load = proc_sum_data.ps_nrunnable;
+ j = 0;
+ for (i = samples - 1; i > 0; --i)
+ {
+ load += proc_sum_data.ps_nrun[j];
+ if (j++ == PS_NRUNSIZE)
+ j = 0;
+ }
+
+ return (load / samples / cpus);
+ }
+
+ #else /* Not UMAX. */
+
+ #ifdef apollo
+
+ /* Apollo code from lisch at mentorg.com (Ray Lischner). */
+
+ #define LDAV_BASED
+
+ /* Return the current load average as a double.
+
+ This system call is not documented. The load average is obtained as
+ three long integers, for the load average over the past minute,
+ five minutes, and fifteen minutes. Each value is a scaled integer,
+ with 16 bits of integer part and 16 bits of fraction part.
+
+ I'm not sure which operating system first supported this system call,
+ but I know that SR10.2 supports it. */
+
+ double
+ load_average ()
+ {
+ extern void proc1_$get_loadav ();
+ unsigned long int loadav[3];
+ proc1_$get_loadav(loadav);
+ return loadav[0] / 65536.0;
+ }
+
+ #else /* Not apollo. */
+
+ #ifndef NO_LDAV
+
+ #define LDAV_BASED
+
+ #if defined(hp300) && !defined(USG)
+ #define LDAV_CVT (((double) load) / 2048.0)
+ #endif
+
+ #if defined(ultrix) && defined(vax)
+ #define LDAV_TYPE double
+ #define LDAV_CVT (load)
+ #endif
+
+ #ifndef KERNEL_FILE_NAME
+ #define KERNEL_FILE_NAME "/vmunix"
+ #endif
+ #ifndef LDAV_SYMBOL
+ #define LDAV_SYMBOL "_avenrun"
+ #endif
+ #ifndef LDAV_TYPE
+ #define LDAV_TYPE long int
+ #endif
+ #ifndef LDAV_CVT
+ #define LDAV_CVT ((double) load)
+ #endif
+
+ #include <nlist.h>
+ #ifdef NLIST_NAME_UNION
+ #define nl_name n_un.n_name
+ #else
+ #define nl_name n_name
+ #endif
+
+ #ifdef USG
+ #include <fcntl.h>
+ #else
+ #include <sys/file.h>
+ #endif
+
+ /* Return the current load average as a double. */
+
+ double
+ load_average ()
+ {
+ extern int nlist ();
+ LDAV_TYPE load;
+ static int complained = 0;
+ static int kmem = -1;
+ static unsigned long int offset = 0;
+
+ if (kmem < 0)
+ {
+ kmem = open ("/dev/kmem", O_RDONLY);
+ if (kmem < 0)
+ {
+ if (!complained)
+ perror_with_name ("open: ", "/dev/kmem");
+ goto lose;
+ }
+ }
+
+ if (offset == 0)
+ {
+ struct nlist nl[2];
+
+ #ifdef NLIST_NAME_ARRAY
+ strcpy (nl[0].nl_name, LDAV_SYMBOL);
+ strcpy (nl[1].nl_name, "");
+ #else /* Not NLIST_NAME_ARRAY. */
+ nl[0].nl_name = LDAV_SYMBOL;
+ nl[1].nl_name = 0;
+ #endif /* NLIST_NAME_ARRAY. */
+
+ if (nlist (KERNEL_FILE_NAME, nl) < 0 || nl[0].n_type == 0)
+ {
+ if (!complained)
+ perror_with_name ("nlist: ", KERNEL_FILE_NAME);
+ goto lose;
+ }
+ offset = nl[0].n_value;
+ }
+
+ if (lseek (kmem, offset, 0) == -1L)
+ {
+ if (!complained)
+ perror_with_name ("lseek: ", "/dev/kmem");
+ goto lose;
+ }
+ if (read (kmem, &load, sizeof load) < 0)
+ {
+ if (!complained)
+ perror_with_name ("read: ", "/dev/kmem");
+ goto lose;
+ }
+
+ if (complained)
+ {
+ error ("Load average limits will be enforced again.");
+ complained = 0;
+ }
+ return LDAV_CVT;
+
+ lose:;
+ if (!complained)
+ {
+ error ("Load average limits will not be enforced.");
+ complained = 1;
+ }
+ return 0.0;
+ }
+
+ #endif /* Not NO_LDAV. */
+
+ #endif /* Apollo. */
+ #endif /* UMAX. */
+
+
+ #ifdef LDAV_BASED
+
+ extern unsigned int job_slots_used;
+
+ extern unsigned int sleep ();
+
+ /* Don't return until a job should be started. */
+
+ void
+ wait_to_start_job ()
+ {
+ register unsigned int loops = 0;
+
+ if (max_load_average < 0.0)
+ return;
+
+ while (job_slots_used > 0)
+ {
+ double load = load_average ();
+
+ if (load < max_load_average)
+ return;
+
+ ++loops;
+ if (loops == 5 || load > max_load_average * 2)
+ {
+ /* If the load is still too high after five loops or it is very
+ high, just wait for a child to die before checking again. */
+ loops = 0;
+ wait_for_children (1, 0);
+ }
+ else
+ /* Don't check the load again immediately, because that will
+ just worsen the load. Check it progressively more slowly. */
+ sleep (loops);
+ }
+ }
+
+ #else /* Not LDAV_BASED. */
+
+ /* How else to do it? */
+
+ void
+ wait_to_start_job ()
+ {
+ return;
+ }
+ #endif /* LDAV_BASED. */
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/main.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/main.c:1.2.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/main.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,1388 ----
+ /* Copyright (C) 1988-1991 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 2, 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. */
+
+ #include "make.h"
+ #include "commands.h"
+ #include "dep.h"
+ #include "file.h"
+ #include "variable.h"
+ #include "job.h"
+ #include <time.h>
+
+
+ extern char *version_string;
+
+ extern int fatal_error_signal ();
+
+ extern struct dep *read_all_makefiles ();
+
+ extern void print_variable_data_base ();
+ extern void print_dir_data_base ();
+ extern void print_rule_data_base ();
+ extern void print_file_data_base ();
+ extern void print_vpath_data_base ();
+
+ #if !defined(__GNU_LIBRARY__) && !defined(POSIX)
+ extern int chdir ();
+ extern void exit ();
+ extern time_t time ();
+ extern double atof ();
+ #endif
+ extern char *mktemp ();
+
+ static void log_working_directory ();
+ static void print_data_base (), print_version ();
+ static void decode_switches (), decode_env_switches ();
+ static void define_makeflags ();
+
+
+ #if 0 /* dummy tag */
+ flags () {}
+ #endif
+ /* Flags:
+ * -b ignored for compatibility with System V Make
+ * -C change directory
+ * -d debug
+ * -e env_overrides
+ * -f makefile
+ * -i ignore_errors
+ * -j job_slots
+ * -k keep_going
+ * -l max_load_average
+ * -m ignored for compatibility with something or other
+ * -n just_print
+ * -o consider file old
+ * -p print_data_base
+ * -q question
+ * -r no_builtin_rules
+ * -s silent
+ * -S turn off -k
+ * -t touch
+ * -v print version information
+ * -w log working directory
+ * -W consider file new (with -n, `what' if effect)
+ */
+
+ /* The structure that describes an accepted command switch. */
+
+ struct command_switch
+ {
+ char c; /* The switch character. */
+ enum /* Type of the value. */
+ {
+ flag, /* Turn int flag on. */
+ flag_off, /* Turn int flag off. */
+ string, /* One string per switch, may be in the same word. */
+ positive_int, /* A positive integer. */
+ floating, /* A floating-point number (double). */
+ ignore /* Ignored. */
+ } type;
+
+ char *value_ptr; /* Pointer to the value-holding variable. */
+
+ unsigned int env:1; /* Can come from MAKEFLAGS. */
+ unsigned int toenv:1; /* Should be put in MAKEFLAGS. */
+ unsigned int no_makefile:1; /* Don't propagate when remaking makefiles. */
+
+ char *noarg_value; /* Pointer to value used if no argument is given. */
+ char *default_value;/* Pointer to default value. */
+ };
+
+
+ /* The structure used to hold the list of strings given
+ in command switches of a type that takes string arguments. */
+
+ struct stringlist
+ {
+ char **list; /* Nil-terminated list of strings. */
+ unsigned int idx; /* Index into above. */
+ unsigned int max; /* Number of pointers allocated. */
+ };
+
+
+ /* The recognized command switches. */
+
+ /* Nonzero means do not print commands to be executed (-s). */
+
+ int silent_flag;
+
+ /* Nonzero means just touch the files
+ that would appear to need remaking (-t) */
+
+ int touch_flag;
+
+ /* Nonzero means just print what commands would need to be executed,
+ don't actually execute them (-n). */
+
+ int just_print_flag;
+
+ /* Print debugging trace info (-d). */
+
+ int debug_flag = 0;
+
+ /* Environment variables override makefile definitions. */
+
+ int env_overrides = 0;
+
+ /* Nonzero means ignore status codes returned by commands
+ executed to remake files. Just treat them all as successful (-i). */
+
+ int ignore_errors_flag = 0;
+
+ /* Nonzero means don't remake anything, just print the data base
+ that results from reading the makefile (-p). */
+
+ int print_data_base_flag = 0;
+
+ /* Nonzero means don't remake anything; just return a nonzero status
+ if the specified targets are not up to date (-q). */
+
+ int question_flag = 0;
+
+ /* Nonzero means do not use any of the builtin rules (-r). */
+
+ int no_builtin_rules_flag = 0;
+
+ /* Nonzero means keep going even if remaking some file fails (-k). */
+
+ int keep_going_flag;
+ int default_keep_going_flag = 0;
+
+ /* Nonzero means print working directory
+ before starting and after finishing make. */
+
+ int print_directory_flag = 0;
+
+ /* Nonzero means print version information. */
+
+ int print_version_flag = 0;
+
+ /* List of makefiles given with -f switches. */
+
+ static struct stringlist *makefiles = 0;
+
+
+ /* Number of job slots (commands that can be run at once). */
+
+ unsigned int job_slots = 1;
+ unsigned int default_job_slots = 1;
+
+ /* Value of job_slots that means no limit. */
+
+ static unsigned int inf_jobs = 0;
+
+ /* Maximum load average at which multiple jobs will be run.
+ Negative values mean unlimited, while zero means limit to
+ zero load (which could be useful to start infinite jobs remotely
+ but one at a time locally). */
+
+ double max_load_average = -1.0;
+ double default_load_average = -1.0;
+
+ /* List of directories given with -c switches. */
+
+ static struct stringlist *directories = 0;
+
+ /* List of include directories given with -I switches. */
+
+ static struct stringlist *include_directories = 0;
+
+ /* List of files given with -o switches. */
+
+ static struct stringlist *old_files = 0;
+
+ /* List of files given with -W switches. */
+
+ static struct stringlist *new_files = 0;
+
+ /* The table of command switches. */
+
+ static struct command_switch switches[] =
+ {
+ { 'b', ignore, 0, 0, 0, 0, 0, 0 },
+ { 'C', string, (char *) &directories, 0, 0, 0, 0, 0 },
+ { 'd', flag, (char *) &debug_flag, 1, 1, 0, 0, 0 },
+ { 'e', flag, (char *) &env_overrides, 1, 1, 0, 0, 0 },
+ { 'f', string, (char *) &makefiles, 0, 0, 0, 0, 0 },
+ { 'i', flag, (char *) &ignore_errors_flag, 1, 1, 0, 0, 0 },
+ { 'I', string, (char *) &include_directories, 0, 0, 0, 0, 0 },
+ { 'j', positive_int, (char *) &job_slots, 1, 1, 0,
+ (char *) &inf_jobs, (char *) &default_job_slots },
+ { 'k', flag, (char *) &keep_going_flag, 1, 1, 0,
+ 0, (char *) &default_keep_going_flag },
+ { 'l', floating, (char *) &max_load_average, 1, 1, 0,
+ (char *) &default_load_average, (char *) &default_load_average },
+ { 'm', ignore, 0, 0, 0, 0, 0, 0 },
+ { 'n', flag, (char *) &just_print_flag, 1, 1, 1, 0, 0 },
+ { 'o', string, (char *) &old_files, 0, 0, 0, 0, 0 },
+ { 'p', flag, (char *) &print_data_base_flag, 1, 1, 0, 0, 0 },
+ { 'q', flag, (char *) &question_flag, 1, 1, 1, 0, 0 },
+ { 'r', flag, (char *) &no_builtin_rules_flag, 1, 1, 0, 0, 0 },
+ { 's', flag, (char *) &silent_flag, 1, 1, 0, 0, 0 },
+ { 'S', flag_off, (char *) &keep_going_flag, 1, 1, 0,
+ 0, (char *) &default_keep_going_flag },
+ { 't', flag, (char *) &touch_flag, 1, 1, 1, 0, 0 },
+ { 'v', flag, (char *) &print_version_flag, 0, 0, 0, 0, 0 },
+ { 'w', flag, (char *) &print_directory_flag, 1, 1, 0, 0, 0 },
+ { 'W', string, (char *) &new_files, 0, 0, 0, 0, 0 },
+ { '\0', ignore, 0, 0, 0, 0, 0 }
+ };
+
+ /* List of non-switch arguments. */
+
+ struct stringlist *other_args = 0;
+
+
+ /* The name we were invoked with. */
+
+ char *program;
+
+ /* Value of the MAKELEVEL variable at startup (or 0). */
+
+ unsigned int makelevel;
+
+ /* First file defined in the makefile whose name does not
+ start with `.'. This is the default to remake if the
+ command line does not specify. */
+
+ struct file *default_goal_file;
+
+ /* Pointer to structure for the file .DEFAULT
+ whose commands are used for any file that has none of its own.
+ This is zero if the makefiles do not define .DEFAULT. */
+
+ struct file *default_file;
+
+ /* Mask of signals that are being caught with fatal_error_signal. */
+ int fatal_signal_mask;
+
+ int
+ main (argc, argv, envp)
+ int argc;
+ char **argv;
+ char **envp;
+ {
+ #if (defined(USG) && !defined(HAVE_SIGLIST)) || defined(DGUX)
+ extern void init_siglist ();
+ #endif
+ extern int child_handler ();
+ register struct file *f;
+ register unsigned int i;
+ register char *cmd_defs;
+ register unsigned int cmd_defs_len, cmd_defs_idx;
+ char **p;
+ time_t now;
+ struct dep *goals = 0;
+ register struct dep *lastgoal;
+ struct dep *read_makefiles;
+ PATH_VAR (current_directory);
+
+ default_goal_file = 0;
+ reading_filename = 0;
+ reading_lineno_ptr = 0;
+
+ #if (defined(USG) && !defined(HAVE_SIGLIST)) || defined(DGUX)
+ init_siglist ();
+ #endif
+
+ fatal_signal_mask = 0;
+
+ #define FATAL_SIG(sig) \
+ if (SIGNAL ((sig), (SIGHANDLER) fatal_error_signal) \
+ == (SIGHANDLER) SIG_IGN) \
+ (void) SIGNAL ((sig), SIG_IGN); \
+ else \
+ fatal_signal_mask |= sigmask (sig);
+
+ FATAL_SIG (SIGHUP);
+ FATAL_SIG (SIGQUIT);
+ FATAL_SIG (SIGINT);
+ FATAL_SIG (SIGILL);
+ FATAL_SIG (SIGTRAP);
+ FATAL_SIG (SIGIOT);
+ #ifdef SIGEMT
+ FATAL_SIG (SIGEMT);
+ #endif
+ #ifdef SIGDANGER
+ FATAL_SIG (SIGDANGER);
+ #endif
+ FATAL_SIG (SIGFPE);
+ FATAL_SIG (SIGBUS);
+ FATAL_SIG (SIGSEGV);
+ FATAL_SIG (SIGSYS);
+ FATAL_SIG (SIGTERM);
+ #ifdef SIGXCPU
+ FATAL_SIG (SIGXCPU);
+ #endif
+ #ifdef SIGXFSZ
+ FATAL_SIG (SIGXFSZ);
+ #endif
+
+ #undef FATAL_SIG
+
+ /* Make sure stdout is line-buffered. */
+
+ #if (defined (USGr3) || defined (HPUX) || defined (hpux) \
+ || defined (M_XENIX) || defined (APOLLO))
+ setvbuf (stdout, (char *) 0, _IOLBF, BUFSIZ);
+ #else /* Not USGr3 and not HPUX et al. */
+ #ifdef USG
+ #ifdef sgi
+ setvbuf (stdout, _IOLBF, xmalloc (BUFSIZ), BUFSIZ);
+ #else
+ setvbuf (stdout, _IOLBF, (char *) 0, BUFSIZ);
+ #endif
+ #else /* Not USG. */
+ setlinebuf (stdout);
+ #endif /* USG. */
+ #endif /* USGr3. */
+
+ /* Set up to access user data (files). */
+ user_access ();
+
+ /* Figure out where this program lives. */
+
+ if (argv[0] == 0)
+ argv[0] = "";
+ if (argv[0][0] == '\0')
+ program = "make";
+ else
+ {
+ program = rindex (argv[0], '/');
+ if (program == 0)
+ program = argv[0];
+ else
+ ++program;
+ }
+
+ /* Figure out where we are. */
+
+ #ifdef USG
+ /* In some System V's, `getcwd' spawns a child running /bin/pwd. */
+ push_signals_blocked_p (1);
+ #endif
+ if (getwd (current_directory) == 0)
+ {
+ #ifdef USG
+ perror_with_name ("getcwd: ", "");
+ #else
+ error ("getwd: %s", current_directory);
+ #endif
+ current_directory[0] = '\0';
+ }
+ #ifdef USG
+ pop_signals_blocked_p ();
+ #endif
+
+ /* Read in variables from the environment. It is important that this be
+ done before `MAKE' and `MAKEOVERRIDES' are figured out so their
+ definitions will not be ones from the environment. */
+
+ for (i = 0; envp[i] != 0; ++i)
+ {
+ register char *ep = envp[i];
+ while (*ep++ != '=')
+ ;
+ (void) define_variable (envp[i], ep - envp[i] - 1, ep, o_env, 1);
+ }
+
+ /* Decode the switches. */
+
+ decode_switches (argc, argv);
+
+ /* Print version information. */
+
+ if (print_version_flag || print_data_base_flag || debug_flag)
+ print_version ();
+
+ /* Search for command line arguments that define variables,
+ and do the definitions. Also save up the text of these
+ arguments in CMD_DEFS so we can put them into the values
+ of $(MAKEOVERRIDES) and $(MAKE). */
+
+ cmd_defs_len = 200;
+ cmd_defs = (char *) xmalloc (cmd_defs_len);
+ cmd_defs_idx = 0;
+
+ for (i = 1; other_args->list[i] != 0; ++i)
+ {
+ if (other_args->list[i][0] == '\0')
+ /* Ignore empty arguments, so they can't kill enter_file. */
+ continue;
+
+ /* Try a variable definition. */
+ if (try_variable_definition (other_args->list[i], o_command))
+ {
+ /* It succeeded. The variable is already defined.
+ Backslash-quotify it and append it to CMD_DEFS, then clobber it
+ to 0 in the list so that it won't be taken for a goal target. */
+ register char *p = other_args->list[i];
+ unsigned int l = strlen (p);
+ if (cmd_defs_idx + (l * 2) + 1 > cmd_defs_len)
+ {
+ if (l * 2 > cmd_defs_len)
+ cmd_defs_len += l * 2;
+ else
+ cmd_defs_len *= 2;
+ cmd_defs = (char *) xrealloc (cmd_defs, cmd_defs_len);
+ }
+
+ while (*p != '\0')
+ {
+ if (index (";'\"*?[]$<>(){}|&~`\\ \t\r\n\f\v", *p) != 0)
+ cmd_defs[cmd_defs_idx++] = '\\';
+ cmd_defs[cmd_defs_idx++] = *p++;
+ }
+ cmd_defs[cmd_defs_idx++] = ' ';
+ }
+ else
+ {
+ /* It was not a variable definition, so it is a target to be made.
+ Enter it as a file and add it to the dep chain of goals. */
+ f = enter_file (other_args->list[i]);
+ f->cmd_target = 1;
+
+ if (goals == 0)
+ {
+ goals = (struct dep *) xmalloc (sizeof (struct dep));
+ lastgoal = goals;
+ }
+ else
+ {
+ lastgoal->next = (struct dep *) xmalloc (sizeof (struct dep));
+ lastgoal = lastgoal->next;
+ }
+ lastgoal->name = 0;
+ lastgoal->file = f;
+ }
+ }
+
+ if (cmd_defs_idx > 0)
+ {
+ cmd_defs[cmd_defs_idx - 1] = '\0';
+ (void) define_variable ("MAKEOVERRIDES", 13, cmd_defs, o_override, 0);
+ }
+
+ /* Set the "MAKE" variable to the name we were invoked with.
+ (If it is a relative pathname with a slash, prepend our directory name
+ so the result will run the same program regardless of the current dir.
+ If it is a name with no slash, we can only hope that PATH did not
+ find it in the current directory.)
+
+ Append the command-line variable definitions gathered above
+ so sub-makes will get them as command-line definitions. */
+
+ if (current_directory[0] != '\0'
+ && argv[0] != 0 && argv[0][0] != '/' && index (argv[0], '/') != 0)
+ argv[0] = concat (current_directory, "/", argv[0]);
+
+ if (cmd_defs_idx > 0)
+ {
+ char *str = concat (argv[0], " ", cmd_defs);
+ (void) define_variable ("MAKE", 4, str, o_env, 0);
+ free (str);
+ }
+ else
+ (void) define_variable ("MAKE", 4, argv[0], o_env, 0);
+
+ free (cmd_defs);
+
+ /* If there were -c flags, move ourselves about. */
+
+ if (directories != 0)
+ for (i = 0; directories->list[i] != 0; ++i)
+ {
+ char *dir = directories->list[i];
+ if (chdir (dir) < 0)
+ pfatal_with_name (dir);
+ }
+
+ /* Figure out the level of recursion. */
+ {
+ struct variable *v = lookup_variable ("MAKELEVEL", 9);
+ if (v != 0 && *v->value != '\0' && *v->value != '-')
+ makelevel = (unsigned int) atoi (v->value);
+ else
+ makelevel = 0;
+ }
+
+ /* Construct the list of include directories to search. */
+
+ construct_include_path (include_directories == 0 ? (char **) 0
+ : include_directories->list);
+
+ /* Tell the user where he is. */
+
+ if (print_directory_flag)
+ log_working_directory (1);
+
+ /* Read any stdin makefiles into temporary files. */
+
+ if (makefiles != 0)
+ {
+ register unsigned int i;
+ for (i = 0; i < makefiles->idx; ++i)
+ if (makefiles->list[i][0] == '-' && makefiles->list[i][1] == '\0')
+ {
+ /* This makefile is standard input. Since we may re-exec
+ and thus re-read the makefiles, we read standard input
+ into a temporary file and read from that. */
+ static char name[] = "/tmp/GmXXXXXX";
+ FILE *outfile;
+
+ /* Free the storage allocated for "-". */
+ free (makefiles->list[i]);
+
+ /* Make a unique filename. */
+ (void) mktemp (name);
+
+ outfile = fopen (name, "w");
+ if (outfile == 0)
+ pfatal_with_name ("fopen (temporary file)");
+ while (!feof (stdin))
+ {
+ char buf[2048];
+ int n = fread (buf, 1, sizeof(buf), stdin);
+ if (n > 0 && fwrite (buf, 1, n, outfile) != n)
+ pfatal_with_name ("fwrite (temporary file)");
+ }
+ /* Try to make sure we won't remake the temporary
+ file when we are re-exec'd. Kludge-o-matic! */
+ fprintf (outfile, "%s:;\n", name);
+ (void) fclose (outfile);
+
+ /* Replace the name that read_all_makefiles will
+ see with the name of the temporary file. */
+ makefiles->list[i] = savestring (name, sizeof name - 1);
+
+ /* Make sure the temporary file will not be remade. */
+ f = enter_file (savestring (name, sizeof name - 1));
+ f->updated = 1;
+ f->update_status = 0;
+ /* Let it be removed when we're done. */
+ f->intermediate = 1;
+ /* But don't mention it. */
+ f->dontcare = 1;
+ }
+ }
+
+ /* Set up to handle children dying. This must be done before
+ reading in the makefiles so that `shell' function calls will work. */
+
+ #if defined (SIGCHLD) && !defined (USG)
+ (void) SIGNAL (SIGCHLD, child_handler);
+ #else
+ (void) SIGNAL (SIGCLD, child_handler);
+ #endif
+
+ /* Define the initial list of suffixes for old-style rules. */
+
+ set_default_suffixes ();
+
+ /* Define some internal and special variables. */
+
+ define_automatic_variables ();
+
+ /* Set up the MAKEFLAGS and MFLAGS variables
+ so makefiles can look at them. */
+
+ define_makeflags (0, 0);
+
+ /* Define the default variables. */
+ define_default_variables ();
+
+ /* Read all the makefiles. */
+
+ default_file = enter_file (".DEFAULT");
+
+ read_makefiles
+ = read_all_makefiles (makefiles == 0 ? (char **) 0 : makefiles->list);
+
+ decode_env_switches ("MAKEFLAGS", 9);
+ decode_env_switches ("MFLAGS", 6);
+
+ /* Set up MAKEFLAGS and MFLAGS again, so they will be right. */
+
+ define_makeflags (1, 0);
+
+ ignore_errors_flag |= lookup_file (".IGNORE") != 0;
+
+ silent_flag |= lookup_file (".SILENT") != 0;
+
+ /* Make each `struct dep' point at the
+ `struct file' for the file depended on. */
+
+ snap_deps ();
+
+ /* Install the default implicit rules.
+ This used to be done before reading the makefiles.
+ But in that case, built-in pattern rules were in the chain
+ before user-defined ones, so they matched first. */
+
+ install_default_implicit_rules ();
+
+ /* Convert old-style suffix rules to pattern rules. */
+
+ convert_to_pattern ();
+
+ /* Compute implicit rule limits. */
+
+ count_implicit_rule_limits ();
+
+ /* Construct the listings of directories in VPATH lists. */
+
+ build_vpath_lists ();
+
+ /* Mark files given with -o flags as very old (00:00:01.00 Jan 1, 1970)
+ and as having been updated already, and files given with -W flags
+ as brand new (time-stamp of now). */
+
+ if (old_files != 0)
+ for (p = old_files->list; *p != 0; ++p)
+ {
+ f = enter_file (*p);
+ f->last_mtime = (time_t) 1;
+ f->updated = 1;
+ f->update_status = 0;
+ }
+
+ if (new_files != 0)
+ {
+ now = time ((time_t *) 0);
+ for (p = new_files->list; *p != 0; ++p)
+ {
+ f = enter_file (*p);
+ f->last_mtime = now;
+ }
+ }
+
+ if (read_makefiles != 0)
+ {
+ /* Update any makefiles if necessary. */
+
+ time_t *makefile_mtimes = 0;
+ unsigned int mm_idx = 0;
+
+ if (debug_flag)
+ puts ("Updating makefiles....");
+
+ /* Remove any makefiles we don't want to try to update.
+ Also record the current modtimes so we can compare them later. */
+ {
+ register struct dep *d, *last;
+ last = 0;
+ d = read_makefiles;
+ while (d != 0)
+ {
+ register struct file *f = d->file;
+ if (f->double_colon)
+ {
+ do
+ {
+ if (f->deps == 0 && f->cmds != 0)
+ {
+ /* This makefile is a :: target with commands, but
+ no dependencies. So, it will always be remade.
+ This might well cause an infinite loop, so don't
+ try to remake it. (This will only happen if
+ your makefiles are written exceptionally
+ stupidly; but if you work for Athena, that's how
+ you write your makefiles.) */
+
+ if (debug_flag)
+ printf ("Makefile `%s' might loop; not remaking it.\n",
+ f->name);
+
+ if (last == 0)
+ read_makefiles = d->next;
+ else
+ last->next = d->next;
+
+ /* Free the storage. */
+ free ((char *) d);
+
+ d = last == 0 ? 0 : last->next;
+
+ break;
+ }
+ f = f->prev;
+ }
+ while (f != NULL);
+ }
+ if (f == NULL || !f->double_colon)
+ {
+ if (makefile_mtimes == 0)
+ makefile_mtimes = (time_t *) xmalloc (sizeof (time_t));
+ else
+ makefile_mtimes = (time_t *)
+ xrealloc ((char *) makefile_mtimes,
+ (mm_idx + 1) * sizeof (time_t));
+ makefile_mtimes[mm_idx++] = file_mtime_no_search (d->file);
+ last = d;
+ d = d->next;
+ }
+ }
+ }
+
+ /* Set up `MAKEFLAGS' specially while remaking makefiles. */
+ define_makeflags (1, 1);
+
+ switch (update_goal_chain (read_makefiles, 1))
+ {
+ default:
+ abort ();
+
+ case -1:
+ /* Did nothing. */
+ break;
+
+ case 1:
+ /* Failed to update. Figure out if we care. */
+ {
+ /* Nonzero if any makefile was successfully remade. */
+ int any_remade = 0;
+ /* Nonzero if any makefile we care about failed
+ in updating or could not be found at all. */
+ int any_failed = 0;
+ register unsigned int i;
+
+ for (i = 0; read_makefiles != 0; ++i)
+ {
+ struct dep *d = read_makefiles;
+ read_makefiles = d->next;
+ if (d->file->updated)
+ {
+ /* This makefile was updated. */
+ if (d->file->update_status == 0)
+ {
+ /* It was successfully updated. */
+ any_remade |= (file_mtime_no_search (d->file)
+ != makefile_mtimes[i]);
+ }
+ else if (d->changed != 1)
+ {
+ time_t mtime;
+ /* The update failed and this makefile was not
+ from the MAKEFILES variable, so we care. */
+ error ("Failed to remake makefile `%s'.",
+ d->file->name);
+ mtime = file_mtime_no_search (d->file);
+ any_remade |= (mtime != (time_t) -1
+ && mtime != makefile_mtimes[i]);
+ }
+ }
+ else
+ /* This makefile was not found at all. */
+ switch (d->changed)
+ {
+ case 0:
+ /* A normal makefile. We must die later. */
+ error ("Makefile `%s' was not found", dep_name (d));
+ any_failed = 1;
+ break;
+ case 1:
+ /* A makefile from the MAKEFILES variable.
+ We don't care. */
+ break;
+ case 2:
+ /* An included makefile. We don't need
+ to die, but we do want to complain. */
+ error ("Included makefile `%s' was not found.",
+ dep_name (d));
+ break;
+ }
+
+ free ((char *) d);
+ }
+
+ if (any_remade)
+ goto re_exec;
+ else if (any_failed)
+ die (1);
+ else
+ break;
+ }
+
+ case 0:
+ re_exec:;
+ /* Updated successfully. Re-exec ourselves. */
+ if (print_directory_flag)
+ log_working_directory (0);
+ if (debug_flag)
+ puts ("Re-execing myself....");
+ if (makefiles != 0)
+ {
+ /* These names might have changed. */
+ register unsigned int i, j = 0;
+ for (i = 1; i < argc; ++i)
+ if (!strcmp (argv[i], "-f"))
+ {
+ char *p = &argv[i][2];
+ if (*p == '\0')
+ argv[++i] = makefiles->list[j];
+ else
+ argv[i] = concat ("-f", makefiles->list[j], "");
+ ++j;
+ }
+ }
+ if (directories != 0 && directories->idx > 0)
+ {
+ char bad;
+ if (current_directory[0] != '\0')
+ {
+ if (chdir (current_directory) < 0)
+ {
+ perror_with_name ("chdir", "");
+ bad = 1;
+ }
+ else
+ bad = 0;
+ }
+ else
+ bad = 1;
+ if (bad)
+ fatal ("Couldn't change back to original directory.");
+ }
+ fflush (stdout);
+ fflush (stderr);
+ for (p = environ; *p != 0; ++p)
+ if (!strncmp (*p, "MAKELEVEL=", 10))
+ {
+ sprintf (*p, "MAKELEVEL=%u", makelevel);
+ break;
+ }
+ exec_command (argv, environ);
+ /* NOTREACHED */
+ }
+ }
+
+ /* Set up `MAKEFLAGS' again for the normal targets. */
+ define_makeflags (1, 0);
+
+ {
+ int status;
+
+ /* If there were no command-line goals, use the default. */
+ if (goals == 0)
+ {
+ if (default_goal_file != 0)
+ {
+ goals = (struct dep *) xmalloc (sizeof (struct dep));
+ goals->next = 0;
+ goals->name = 0;
+ goals->file = default_goal_file;
+ }
+ }
+ else
+ lastgoal->next = 0;
+
+ if (goals != 0)
+ {
+ /* Update the goals. */
+
+ if (debug_flag)
+ puts ("Updating goal targets....");
+
+ switch (update_goal_chain (goals, 0))
+ {
+ case -1:
+ /* Nothing happened. */
+ case 0:
+ /* Updated successfully. */
+ status = 0;
+ break;
+ case 1:
+ /* Updating failed. */
+ status = 1;
+ break;
+ default:
+ abort ();
+ }
+ }
+
+ /* Print the data base under -p. */
+ if (print_data_base_flag)
+ print_data_base ();
+
+ if (goals == 0)
+ {
+ if (read_makefiles == 0)
+ fatal ("No targets specified and no makefile found");
+ else
+ fatal ("No targets");
+ }
+
+ /* Exit. */
+ die (status);
+ }
+
+ return 0;
+ }
+
+ static void
+ decode_switches (argc, argv)
+ int argc;
+ char **argv;
+ {
+ char bad = 0;
+ register unsigned int i;
+ register char *sw;
+ register struct command_switch *cs;
+ register struct stringlist *sl;
+ char *arg;
+
+ decode_env_switches ("MAKEFLAGS", 9);
+ decode_env_switches ("MFLAGS", 6);
+
+ other_args = (struct stringlist *) xmalloc (sizeof (struct stringlist));
+ other_args->max = 5;
+ other_args->list = (char **) xmalloc (5 * sizeof (char *));
+ other_args->idx = 1;
+ other_args->list[0] = savestring (argv[0], strlen (argv[0]));
+
+ for (i = 1; i < argc; i++)
+ {
+ sw = argv[i];
+ if (*sw++ == '-')
+ while (*sw != '\0')
+ {
+ for (cs = switches; cs->c != '\0'; ++cs)
+ if (cs->c == *sw)
+ {
+ ++sw;
+ switch (cs->type)
+ {
+ default:
+ abort ();
+ case ignore:
+ break;
+ case flag:
+ case flag_off:
+ *(int *) cs->value_ptr = cs->type == flag;
+ break;
+ case string:
+ if (*sw == '\0')
+ {
+ arg = argv[++i];
+ if (arg == 0)
+ {
+ arg = cs->noarg_value;
+ if (arg == 0)
+ {
+ error ("argument required for `-%c' option",
+ cs->c);
+ bad = 1;
+ break;
+ }
+ }
+ }
+ else
+ arg = sw;
+
+ sl = *(struct stringlist **) cs->value_ptr;
+ if (sl == 0)
+ {
+ sl = (struct stringlist *)
+ xmalloc (sizeof (struct stringlist));
+ sl->max = 5;
+ sl->idx = 0;
+ sl->list = (char **) xmalloc (5 * sizeof (char *));
+ *(struct stringlist **) cs->value_ptr = sl;
+ }
+ else if (sl->idx == sl->max - 1)
+ {
+ sl->max += 5;
+ sl->list = (char **)
+ xrealloc ((char *) sl->list,
+ sl->max * sizeof (char *));
+ }
+ sl->list[sl->idx++] = savestring (arg, strlen (arg));
+ sl->list[sl->idx] = 0;
+ sw = "";
+ break;
+
+ case positive_int:
+ if (*sw == '\0')
+ arg = argv[++i];
+ else
+ arg = sw;
+ if (arg != 0 && isdigit (*arg))
+ {
+ int i = atoi (arg);
+ if (arg == sw)
+ while (isdigit (*sw))
+ ++sw;
+ if (i < 1)
+ {
+ error ("the `-%c' option requires a \
+ positive integral argument",
+ cs->c);
+ bad = 1;
+ }
+ else
+ *(unsigned int *) cs->value_ptr = i;
+ }
+ else
+ {
+ if (cs->noarg_value != 0)
+ *(unsigned int *) cs->value_ptr
+ = *(unsigned int *) cs->noarg_value;
+ else
+ {
+ error ("the `-%c' option requires an argument",
+ cs->c);
+ bad = 1;
+ }
+
+ if (arg == argv[i])
+ /* We moved to the next arg, so move back. */
+ --i;
+ }
+ break;
+
+ case floating:
+ if (*sw == '\0')
+ arg = argv[++i];
+ else
+ arg = sw;
+ if (arg != 0 && (*arg == '.' || isdigit (*arg)))
+ {
+ *(double *) cs->value_ptr = atof (arg);
+ if (arg == sw)
+ while (*sw == '.' || isdigit (*sw))
+ ++sw;
+ }
+ else
+ {
+ if (cs->noarg_value != 0)
+ *(double *) cs->value_ptr
+ = *(double *) cs->noarg_value;
+ else
+ {
+ error ("the `-%c' option requires an argument",
+ cs->c);
+ bad = 1;
+ }
+
+ if (arg == argv[i])
+ /* We moved to the next arg, so move back. */
+ --i;
+ }
+ break;
+ }
+
+ /* We've found the switch. Stop looking. */
+ break;
+ }
+
+ if (cs->c == '\0')
+ {
+ error ("unknown option `-%c'", *sw++);
+ bad = 1;
+ }
+ }
+ else
+ {
+ if (other_args->idx == other_args->max - 1)
+ {
+ other_args->max += 5;
+ other_args->list = (char **)
+ xrealloc ((char *) other_args->list,
+ other_args->max * sizeof (char *));
+ }
+ other_args->list[other_args->idx++] = argv[i];
+ }
+ }
+
+ if (other_args != 0)
+ other_args->list[other_args->idx] = 0;
+
+ if (bad)
+ die (1);
+ }
+
+ static void
+ decode_env_switches (envar, len)
+ char *envar;
+ unsigned int len;
+ {
+ struct variable *v;
+ register char *args;
+ register struct command_switch *cs;
+
+ v = lookup_variable (envar, len);
+ if (v == 0 || *v->value == '\0')
+ return;
+
+ for (args = v->value; *args != '\0'; ++args)
+ for (cs = switches; cs->c != '\0'; ++cs)
+ if (cs->c == *args)
+ if (cs->env)
+ switch (cs->type)
+ {
+ case string:
+ /* None of these allow environment changes. */
+ default:
+ abort ();
+ case flag:
+ case flag_off:
+ *(int *) cs->value_ptr = cs->type == flag;
+ break;
+ case positive_int:
+ while (isspace (args[1]))
+ ++args;
+ if (isdigit(args[1]))
+ {
+ int i = atoi (&args[1]);
+ while (isdigit (args[1]))
+ ++args;
+ if (i >= 1)
+ *(unsigned int *) cs->value_ptr = i;
+ }
+ else
+ *(unsigned int *) cs->value_ptr
+ = *(unsigned int *) cs->noarg_value;
+ break;
+ case floating:
+ while (isspace (args[1]))
+ ++args;
+ if (args[1] == '.' || isdigit (args[1]))
+ {
+ *(double *) cs->value_ptr = atof (&args[1]);
+ while (args[1] == '.' || isdigit (args[1]))
+ ++args;
+ }
+ else
+ *(double *) cs->value_ptr = *(double *) cs->noarg_value;
+ break;
+ }
+ }
+
+ /* Define the MAKEFLAGS and MFLAGS variables to reflect the settings of the
+ command switches. Include positive_int and floating options if PF.
+ Don't include options with the `no_makefile' flag is if MAKEFILE. */
+
+ static void
+ define_makeflags (pf, makefile)
+ int pf, makefile;
+ {
+ register struct command_switch *cs;
+ char flags[200];
+ register unsigned int i;
+
+ i = 0;
+ for (cs = switches; cs->c != '\0'; ++cs)
+ if (cs->toenv && (!makefile || !cs->no_makefile))
+ {
+ if (i == 0 || flags[i - 1] == ' ')
+ flags[i++] = '-';
+ switch (cs->type)
+ {
+ default:
+ abort ();
+
+ case ignore:
+ break;
+
+ case flag:
+ case flag_off:
+ if (!*(int *) cs->value_ptr == (cs->type == flag_off)
+ && (cs->default_value == 0
+ || *(int *) cs->value_ptr != *(int *) cs->default_value))
+ flags[i++] = cs->c;
+ break;
+
+ case positive_int:
+ if (pf)
+ {
+ if ((cs->default_value != 0
+ && (*(unsigned int *) cs->value_ptr
+ == *(unsigned int *) cs->default_value)))
+ break;
+ else if (cs->noarg_value != 0
+ && (*(unsigned int *) cs->value_ptr ==
+ *(unsigned int *) cs->noarg_value))
+ flags[i++] = cs->c;
+ else
+ {
+ unsigned int value;
+ if (cs->c == 'j')
+ value = 1;
+ else
+ value = *(unsigned int *) cs->value_ptr;
+ sprintf (&flags[i], "%c%u ", cs->c, value);
+ i += strlen (&flags[i]);
+ }
+ }
+ break;
+
+ case floating:
+ if (pf)
+ {
+ if (cs->default_value != 0
+ && (*(double *) cs->value_ptr
+ == *(double *) cs->default_value))
+ break;
+ else if (cs->noarg_value != 0
+ && (*(double *) cs->value_ptr
+ == *(double *) cs->noarg_value))
+ flags[i++] = cs->c;
+ else
+ {
+ sprintf (&flags[i], "%c%f ",
+ cs->c, *(double *) cs->value_ptr);
+ i += strlen (&flags[i]);
+ }
+ }
+ break;
+ }
+ }
+
+ if (i == 0)
+ flags[0] = flags[1] = '\0';
+ else if (flags[i - 1] == ' ' || flags[i - 1] == '-')
+ flags[i - 1] = '\0';
+ flags[i] = '\0';
+
+ /* On Sun, the value of MFLAGS starts with a `-' but the
+ value of MAKEFLAGS lacks the `-'. Be compatible. */
+ (void) define_variable ("MAKEFLAGS", 9, &flags[1], o_env, 0);
+ (void) define_variable ("MFLAGS", 6, flags, o_env, 0);
+ }
+
+ static int printed_version = 0;
+
+ /* Print version information. */
+
+ static void
+ print_version ()
+ {
+ extern char *remote_description;
+ char *precede = print_data_base_flag ? "# " : "";
+
+ printf ("%sGNU Make version %s", precede, version_string);
+ if (remote_description != 0 && *remote_description != '\0')
+ printf ("-%s", remote_description);
+
+ printf (", by Richard Stallman and Roland McGrath.\n\
+ %sCopyright (C) 1988-1991 Free Software Foundation, Inc.\n\
+ %sThis is free software; see the source for copying conditions.\n\
+ %sThere is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\
+ %sPARTICULAR PURPOSE.\n\n", precede, precede, precede, precede);
+
+ printed_version = 1;
+
+ /* Flush stdout so the user doesn't have to wait to see the
+ version information while things are thought about. */
+ fflush (stdout);
+ }
+
+ /* Print a bunch of information about this and that. */
+
+ static void
+ print_data_base ()
+ {
+ extern char *ctime ();
+ time_t when;
+
+ when = time ((time_t *) 0);
+ printf ("\n# Make data base, printed on %s", ctime (&when));
+
+ print_variable_data_base ();
+ print_dir_data_base ();
+ print_rule_data_base ();
+ print_file_data_base ();
+ print_vpath_data_base ();
+
+ when = time ((time_t *) 0);
+ printf ("\n# Finished Make data base on %s\n", ctime (&when));
+ }
+
+ /* Exit with STATUS, cleaning up as necessary. */
+
+ void
+ die (status)
+ int status;
+ {
+ static char dying = 0;
+
+ if (!dying)
+ {
+ dying = 1;
+
+ if (print_version_flag && !printed_version)
+ print_version ();
+
+ /* Wait for children to die. */
+ wait_for_children (0, status != 0);
+
+ /* Remove the intermediate files. */
+
+ remove_intermediates (0);
+
+ if (print_directory_flag)
+ log_working_directory (0);
+ }
+
+ exit (status);
+ }
+
+ /* Write a message indicating that we've just entered or
+ left (according to ENTERING) the current directory. */
+
+ static void
+ log_working_directory (entering)
+ int entering;
+ {
+ static int entered = 0;
+ PATH_VAR (pwdbuf);
+ char *message = entering ? "Entering" : "Leaving";
+
+ if (entered && entering)
+ /* Don't print the leaving message if we
+ haven't printed the entering message. */
+ return;
+ else
+ entered = 1;
+
+ if (print_data_base_flag)
+ fputs ("# ", stdout);
+
+ if (makelevel == 0)
+ printf ("%s: %s ", "make", message);
+ else
+ printf ("%s[%u]: %s ", "make", makelevel, message);
+
+ #ifdef USG
+ /* In some System V's, `getcwd' spawns a child running /bin/pwd. */
+ push_signals_blocked_p (1);
+ #endif
+ if (getwd (pwdbuf) == 0)
+ {
+ #ifdef USG
+ perror_with_name ("getcwd: ", "");
+ #else
+ error ("getwd: %s", pwdbuf);
+ #endif
+ puts ("an unknown directory");
+ }
+ else
+ printf ("directory `%s'\n", pwdbuf);
+ #ifdef USG
+ pop_signals_blocked_p ();
+ #endif
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/make.h
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/make.h:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/make.h Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,274 ----
+ /* Copyright (C) 1988-1991 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 2, 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. */
+
+ #define _GNU_SOURCE
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <signal.h>
+ #include <stdio.h>
+ #include <ctype.h>
+
+ #ifndef isblank
+ #define isblank(c) ((c) == ' ' || (c) == '\t')
+ #endif
+
+ #if !defined(NSIG) && defined(_NSIG)
+ #define NSIG _NSIG
+ #endif
+
+ #ifdef __STDC__
+ #define SIGHANDLER void *
+ #else
+ #define SIGHANDLER int (*)()
+ #endif
+ #define SIGNAL(sig, handler) \
+ ((SIGHANDLER) signal((sig), (SIGHANDLER) (handler)))
+
+ #ifndef sigmask
+ #define sigmask(sig) (1 << ((sig) - 1))
+ #endif
+
+ #if defined(POSIX) || defined(__GNU_LIBRARY__)
+ #include <limits.h>
+ #ifndef PATH_MAX
+ #define GET_PATH_MAX pathconf ("/", _PC_PATH_MAX)
+ #endif
+ #else /* Not POSIX. */
+ #include <sys/param.h>
+ #ifndef PATH_MAX
+ #ifndef MAXPATHLEN
+ #define MAXPATHLEN 1024
+ #endif /* No MAXPATHLEN. */
+ #define PATH_MAX MAXPATHLEN
+ #endif /* No PATH_MAX. */
+ #endif /* POSIX. */
+ #ifdef PATH_MAX
+ #define PATH_VAR(var) char var[PATH_MAX]
+ #else
+ #define PATH_VAR(var) char *var = (char *) alloca (GET_PATH_MAX)
+ #endif
+
+ #ifdef uts
+ #ifdef S_ISREG
+ #undef S_ISREG
+ #endif
+ #ifdef S_ISDIR
+ #undef S_ISDIR
+ #endif
+ #endif /* uts. */
+
+ #ifndef S_ISREG
+ #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+ #endif
+ #ifndef S_ISDIR
+ #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+ #endif
+
+
+ #if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) \
+ || defined (POSIX))
+ #include <stdlib.h>
+ #include <string.h>
+ #define ANSI_STRING
+ #else /* No standard headers. */
+
+ #ifdef USG
+
+ #include <string.h>
+ #include <memory.h>
+ #define ANSI_STRING
+
+ #else /* Not USG. */
+
+ #ifdef NeXT
+
+ #include <string.h>
+
+ #else /* Not NeXT. */
+
+ #include <strings.h>
+
+ #ifndef bcmp
+ extern int bcmp ();
+ #endif
+ #ifndef bzero
+ extern void bzero ();
+ #endif
+ #ifndef bcopy
+ extern void bcopy ();
+ #endif
+
+ #endif /* NeXT. */
+
+ #endif /* USG. */
+
+ extern char *malloc (), *realloc ();
+ extern void free ();
+
+ #endif /* Standard headers. */
+
+ #ifdef ANSI_STRING
+ #define index(s, c) strchr((s), (c))
+ #define rindex(s, c) strrchr((s), (c))
+
+ #define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
+ #define bzero(s, n) memset ((s), 0, (n))
+ #define bcopy(s, d, n) memcpy ((d), (s), (n))
+ #endif
+ #undef ANSI_STRING
+
+
+ #ifdef __GNUC__
+ #undef alloca
+ #define alloca(n) __builtin_alloca (n)
+ #else /* Not GCC. */
+ #ifdef sparc
+ #include <alloca.h>
+ #else /* Not sparc. */
+ extern char *alloca ();
+ #endif /* sparc. */
+ #endif /* GCC. */
+
+ #ifndef iAPX286
+ #define streq(a, b) \
+ ((a) == (b) || \
+ (*(a) == *(b) && (*(a) == '\0' || !strcmp ((a) + 1, (b) + 1))))
+ #else
+ /* Buggy compiler can't handle this. */
+ #define streq(a, b) (strcmp ((a), (b)) == 0)
+ #endif
+
+ /* Add to VAR the hashing value of C, one character in a name. */
+ #define HASH(var, c) \
+ ((var += (c)), (var = ((var) << 7) + ((var) >> 20)))
+
+ #if defined(__GNUC__) || defined(ENUM_BITFIELDS)
+ #define ENUM_BITFIELD(bits) :bits
+ #else
+ #define ENUM_BITFIELD(bits)
+ #endif
+
+ extern void die ();
+ extern void message (), fatal (), error ();
+ extern void makefile_error (), makefile_fatal ();
+ extern void pfatal_with_name (), perror_with_name ();
+ extern char *savestring (), *concat ();
+ extern char *xmalloc (), *xrealloc ();
+ extern char *find_next_token (), *next_token (), *end_of_token ();
+ extern void collapse_continuations (), remove_comments ();
+ extern char *sindex (), *lindex ();
+ extern int alpha_compare ();
+ extern void print_spaces ();
+ extern struct dep *copy_dep_chain ();
+ extern char *find_percent ();
+
+ #ifndef NO_ARCHIVES
+ extern int ar_name ();
+ extern void ar_parse_name ();
+ extern int ar_touch ();
+ extern time_t ar_member_date ();
+ #endif
+
+ extern void dir_load ();
+ extern int dir_file_exists_p (), file_exists_p (), file_impossible_p ();
+ extern void file_impossible ();
+ extern char *dir_name ();
+
+ extern void define_default_variables ();
+ extern void set_default_suffixes (), install_default_implicit_rules ();
+ extern void convert_to_pattern (), count_implicit_rule_limits ();
+ extern void create_pattern_rule ();
+
+ extern void build_vpath_lists (), construct_vpath_list ();
+ extern int vpath_search ();
+
+ extern void construct_include_path ();
+ extern void uniquize_deps ();
+
+ extern int update_goal_chain ();
+ extern void notice_finished_file ();
+
+ extern void user_access (), make_access (), child_access ();
+
+
+ #if defined(USG) && !defined(HAVE_VFORK)
+ #define vfork fork
+ #define VFORK_NAME "fork"
+ #else /* Have vfork or not USG. */
+ #define VFORK_NAME "vfork"
+ #endif /* USG and don't have vfork. */
+
+ #if defined(__GNU_LIBRARY__) || defined(POSIX)
+
+ #include <unistd.h>
+
+ #else
+
+ #ifndef USG
+ extern int sigsetmask ();
+ extern int sigblock ();
+ #endif
+ extern int kill ();
+ extern void abort (), exit ();
+ extern int unlink (), stat ();
+ extern void qsort ();
+ extern int atoi ();
+ extern int pipe (), close (), read (), write (), open ();
+ extern long int lseek ();
+ extern char *ctime ();
+ #endif /* GNU C library or POSIX. */
+
+ #if defined(USG) || defined(POSIX) && !defined(__GNU_LIBRARY__)
+ extern char *getcwd ();
+ #ifdef PATH_MAX
+ #define getwd(buf) getcwd (buf, PATH_MAX - 2)
+ #else
+ #define getwd(buf) getcwd (buf, GET_PATH_MAX - 2)
+ #endif
+ #else /* USG or POSIX and not GNU C library. */
+ extern char *getwd ();
+ #endif /* Not USG or POSIX, or maybe GNU C library. */
+
+ #if !defined(__GNU_LIBRARY__) && (!defined(vfork) || !defined(POSIX))
+ #ifdef POSIX
+ extern pid_t vfork ();
+ #else
+ extern int vfork ();
+ #endif
+ #endif
+
+ extern char **environ;
+
+ extern char *reading_filename;
+ extern unsigned int *reading_lineno_ptr;
+
+ extern int just_print_flag, silent_flag, ignore_errors_flag, keep_going_flag;
+ extern int debug_flag, print_data_base_flag, question_flag, touch_flag;
+ extern int env_overrides, no_builtin_rules_flag, print_version_flag;
+ extern int print_directory_flag;
+
+ extern unsigned int job_slots;
+ extern double max_load_average;
+
+ extern char *program;
+
+ extern unsigned int makelevel;
+
+
+ #define DEBUGPR(msg) \
+ if (debug_flag) { print_spaces (depth); printf (msg, file->name); \
+ fflush (stdout); } else
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/misc.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/misc.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/misc.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,598 ----
+ /* Copyright (C) 1988-1991 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 2, 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. */
+
+ #include "make.h"
+ #include "dep.h"
+
+
+ /* Compare strings *S1 and *S2.
+ Return negative if the first is less, positive if it is greater,
+ zero if they are equal. */
+
+ int
+ alpha_compare (s1, s2)
+ char **s1, **s2;
+ {
+ if (**s1 != **s2)
+ return **s1 - **s2;
+ return strcmp (*s1, *s2);
+ }
+
+ /* Discard each backslash-newline combination from LINE.
+ Backslash-backslash-newline combinations become backslash-newlines.
+ This is done by copying the text at LINE into itself. */
+
+ void
+ collapse_continuations (line)
+ char *line;
+ {
+ register char *in, *out, *p;
+ register int backslash;
+ register unsigned int bs_write;
+
+ in = index (line, '\n');
+ if (in == 0)
+ return;
+
+ out = in;
+ if (out > line)
+ while (out[-1] == '\\')
+ --out;
+
+ while (*in != '\0')
+ {
+ /* BS_WRITE gets the number of quoted backslashes at
+ the end just before IN, and BACKSLASH gets nonzero
+ if the next character is quoted. */
+ backslash = 0;
+ bs_write = 0;
+ for (p = in - 1; p >= line && *p == '\\'; --p)
+ {
+ if (backslash)
+ ++bs_write;
+ backslash = !backslash;
+
+ /* It should be impossible to go back this far without exiting,
+ but if we do, we can't get the right answer. */
+ if (in == out - 1)
+ abort ();
+ }
+
+ /* Output the appropriate number of backslashes. */
+ while (bs_write-- > 0)
+ *out++ = '\\';
+
+ /* Skip the newline. */
+ ++in;
+
+ /* If the newline is quoted, discard following whitespace
+ and any preceding whitespace; leave just one space. */
+ if (backslash)
+ {
+ in = next_token (in);
+ while (out > line && isblank (out[-1]))
+ --out;
+ *out++ = ' ';
+ }
+ else
+ /* If the newline isn't quoted, put it in the output. */
+ *out++ = '\n';
+
+ /* Now copy the following line to the output.
+ Stop when we find backslashes followed by a newline. */
+ while (*in != '\0')
+ if (*in == '\\')
+ {
+ p = in + 1;
+ while (*p == '\\')
+ ++p;
+ if (*p == '\n')
+ {
+ in = p;
+ break;
+ }
+ while (in < p)
+ *out++ = *in++;
+ }
+ else
+ *out++ = *in++;
+ }
+
+ *out = '\0';
+ }
+
+
+ /* Remove comments from LINE.
+ This is done by copying the text at LINE onto itself. */
+
+ void
+ remove_comments (line)
+ char *line;
+ {
+ register char *p, *p2;
+ register int backslash;
+ register unsigned int bs_write;
+
+ while (1)
+ {
+ p = index (line, '#');
+ if (p == 0)
+ break;
+
+ backslash = 0;
+ bs_write = 0;
+ for (p2 = p - 1; p2 > line && *p2 == '\\'; --p2)
+ {
+ if (backslash)
+ ++bs_write;
+ backslash = !backslash;
+ }
+
+ if (!backslash)
+ {
+ /* Cut off the line at the #. */
+ *p = '\0';
+ break;
+ }
+
+ /* strcpy better copy left to right. */
+ line = p;
+ strcpy (p2 + 1 + bs_write, line);
+ }
+ }
+
+ /* Print N spaces (used by DEBUGPR for target-depth). */
+
+ void
+ print_spaces (n)
+ register unsigned int n;
+ {
+ while (n-- > 0)
+ putchar (' ');
+ }
+
+
+ /* Return a newly-allocated string whose contents
+ concatenate those of s1, s2, s3. */
+
+ char *
+ concat (s1, s2, s3)
+ register char *s1, *s2, *s3;
+ {
+ register unsigned int len1, len2, len3;
+ register char *result;
+
+ len1 = *s1 != '\0' ? strlen (s1) : 0;
+ len2 = *s2 != '\0' ? strlen (s2) : 0;
+ len3 = *s3 != '\0' ? strlen (s3) : 0;
+
+ result = (char *) xmalloc (len1 + len2 + len3 + 1);
+
+ if (*s1 != '\0')
+ bcopy (s1, result, len1);
+ if (*s2 != '\0')
+ bcopy (s2, result + len1, len2);
+ if (*s3 != '\0')
+ bcopy (s3, result + len1 + len2, len3);
+ *(result + len1 + len2 + len3) = '\0';
+
+ return result;
+ }
+
+ /* Print a message on stdout. */
+
+ void
+ message (s1, s2, s3, s4, s5, s6)
+ char *s1, *s2, *s3, *s4, *s5, *s6;
+ {
+ if (makelevel == 0)
+ printf ("%s: ", program);
+ else
+ printf ("%s[%u]: ", program, makelevel);
+ printf (s1, s2, s3, s4, s5, s6);
+ putchar ('\n');
+ fflush (stdout);
+ }
+
+ /* Print an error message and exit. */
+
+ /* VARARGS1 */
+ void
+ fatal (s1, s2, s3, s4, s5, s6)
+ char *s1, *s2, *s3, *s4, *s5, *s6;
+ {
+ if (makelevel == 0)
+ fprintf (stderr, "%s: ", program);
+ else
+ fprintf (stderr, "%s[%u]: ", program, makelevel);
+ fprintf (stderr, s1, s2, s3, s4, s5, s6);
+ fputs (". Stop.\n", stderr);
+
+ die (1);
+ }
+
+ /* Print error message. `s1' is printf control string, `s2' is arg for it. */
+
+ /* VARARGS1 */
+
+ void
+ error (s1, s2, s3, s4, s5, s6)
+ char *s1, *s2, *s3, *s4, *s5, *s6;
+ {
+ if (makelevel == 0)
+ fprintf (stderr, "%s: ", program);
+ else
+ fprintf (stderr, "%s[%u]: ", program, makelevel);
+ fprintf (stderr, s1, s2, s3, s4, s5, s6);
+ putc ('\n', stderr);
+ fflush (stderr);
+ }
+
+ void
+ makefile_error (file, lineno, s1, s2, s3, s4, s5, s6)
+ char *file;
+ unsigned int lineno;
+ char *s1, *s2, *s3, *s4, *s5, *s6;
+ {
+ fprintf (stderr, "%s:%u: ", file, lineno);
+ fprintf (stderr, s1, s2, s3, s4, s5, s6);
+ putc ('\n', stderr);
+ fflush (stderr);
+ }
+
+ void
+ makefile_fatal (file, lineno, s1, s2, s3, s4, s5, s6)
+ char *file;
+ unsigned int lineno;
+ char *s1, *s2, *s3, *s4, *s5, *s6;
+ {
+ fprintf (stderr, "%s:%u: ", file, lineno);
+ fprintf (stderr, s1, s2, s3, s4, s5, s6);
+ fputs (". Stop.\n", stderr);
+
+ die (1);
+ }
+
+ /* Print an error message from errno. */
+
+ void
+ perror_with_name (str, name)
+ char *str, *name;
+ {
+ extern int errno, sys_nerr;
+ extern const char * const sys_errlist[];
+
+ if (errno < sys_nerr)
+ error ("%s%s: %s", str, name, sys_errlist[errno]);
+ else
+ error ("%s%s: Unknown error %d", str, name, errno);
+ }
+
+ /* Print an error message from errno and exit. */
+
+ void
+ pfatal_with_name (name)
+ char *name;
+ {
+ extern int errno, sys_nerr;
+ extern const char *const sys_errlist[];
+
+ if (errno < sys_nerr)
+ fatal ("%s: %s", name, sys_errlist[errno]);
+ else
+ fatal ("%s: Unknown error %d", name, errno);
+
+ /* NOTREACHED */
+ }
+
+ /* Like malloc but get fatal error if memory is exhausted. */
+
+ #undef xmalloc
+ #undef xrealloc
+
+ char *
+ xmalloc (size)
+ unsigned int size;
+ {
+ char *result = malloc (size);
+ if (result == 0)
+ fatal ("virtual memory exhausted");
+ return result;
+ }
+
+
+ char *
+ xrealloc (ptr, size)
+ char *ptr;
+ unsigned int size;
+ {
+ char *result = realloc (ptr, size);
+ if (result == 0)
+ fatal ("virtual memory exhausted");
+ return result;
+ }
+
+ char *
+ savestring (str, length)
+ char *str;
+ unsigned int length;
+ {
+ register char *out = (char *) xmalloc (length + 1);
+ if (length > 0)
+ bcopy (str, out, length);
+ out[length] = '\0';
+ return out;
+ }
+
+ /* Search string BIG (length BLEN) for an occurrence of
+ string SMALL (length SLEN). Return a pointer to the
+ beginning of the first occurrence, or return nil if none found. */
+
+ char *
+ sindex (big, blen, small, slen)
+ char *big;
+ unsigned int blen;
+ char *small;
+ unsigned int slen;
+ {
+ register unsigned int b;
+
+ if (blen < 1)
+ blen = strlen (big);
+ if (slen < 1)
+ slen = strlen (small);
+
+ for (b = 0; b < blen; ++b)
+ if (big[b] == *small && !strncmp (&big[b + 1], small + 1, slen - 1))
+ return (&big[b]);
+
+ return 0;
+ }
+
+ /* Limited INDEX:
+ Search through the string STRING, which ends at LIMIT, for the character C.
+ Returns a pointer to the first occurrence, or nil if none is found.
+ Like INDEX except that the string searched ends where specified
+ instead of at the first null. */
+
+ char *
+ lindex (s, limit, c)
+ register char *s, *limit;
+ int c;
+ {
+ while (s < limit)
+ if (*s++ == c)
+ return s - 1;
+
+ return 0;
+ }
+
+ /* Return the address of the first whitespace or null in the string S. */
+
+ char *
+ end_of_token (s)
+ char *s;
+ {
+ register char *p = s;
+ register int backslash = 0;
+
+ while (*p != '\0' && (backslash || !isblank (*p)))
+ {
+ if (*p++ == '\\')
+ {
+ backslash = !backslash;
+ while (*p == '\\')
+ {
+ backslash = !backslash;
+ ++p;
+ }
+ }
+ else
+ backslash = 0;
+ }
+
+ return p;
+ }
+
+ /* Return the address of the first nonwhitespace or null in the string S. */
+
+ char *
+ next_token (s)
+ char *s;
+ {
+ register char *p = s;
+
+ while (isblank (*p))
+ ++p;
+ return p;
+ }
+
+ /* Find the next token in PTR; return the address of it, and store the
+ length of the token into *LENGTHPTR if LENGTHPTR is not nil. */
+
+ char *
+ find_next_token (ptr, lengthptr)
+ char **ptr;
+ unsigned int *lengthptr;
+ {
+ char *p = next_token (*ptr);
+ char *end;
+
+ if (*p == '\0')
+ return 0;
+
+ *ptr = end = end_of_token (p);
+ if (lengthptr != 0)
+ *lengthptr = end - p;
+ return p;
+ }
+
+ /* Copy a chain of `struct dep', making a new chain
+ with the same contents as the old one. */
+
+ struct dep *
+ copy_dep_chain (d)
+ register struct dep *d;
+ {
+ register struct dep *c;
+ struct dep *firstnew = 0;
+ struct dep *lastnew;
+
+ while (d != 0)
+ {
+ c = (struct dep *) xmalloc (sizeof (struct dep));
+ bcopy ((char *) d, (char *) c, sizeof (struct dep));
+ if (c->name != 0)
+ c->name = savestring (c->name, strlen (c->name));
+ c->next = 0;
+ if (firstnew == 0)
+ firstnew = lastnew = c;
+ else
+ lastnew = lastnew->next = c;
+
+ d = d->next;
+ }
+
+ return firstnew;
+ }
+
+ #ifdef iAPX286
+ /* The losing compiler on this machine can't handle this macro. */
+
+ char *
+ dep_name (dep)
+ struct dep *dep;
+ {
+ return dep->name == 0 ? dep->file->name : dep->name;
+ }
+ #endif
+
+ #if !defined(POSIX) && !defined(__GNU_LIBRARY__)
+ extern int getuid (), getgid (), geteuid (), getegid ();
+ #ifdef USG
+ extern int setuid (), setgid ();
+ #else
+ extern int setreuid (), setregid ();
+ #endif /* USG. */
+ #endif /* Not POSIX and not GNU C library. */
+
+ /* Keep track of the user and group IDs for user- and make- access. */
+ static int user_uid = -1, user_gid = -1, make_uid = -1, make_gid = -1;
+ #define access_inited (user_uid != -1)
+ static enum { make, user } current_access;
+
+ static void
+ init_access ()
+ {
+ user_uid = getuid ();
+ user_gid = getgid ();
+
+ make_uid = geteuid ();
+ make_gid = getegid ();
+
+ /* Do these ever fail? */
+ if (user_uid == -1 || user_gid == -1 || make_uid == -1 || make_gid == -1)
+ pfatal_with_name ("get{e}[gu]id");
+
+ current_access = make;
+ }
+
+ /* Give the process appropriate permissions for access to
+ user data (i.e., to stat files, or to spawn a child process). */
+ void
+ user_access ()
+ {
+ if (!access_inited)
+ init_access ();
+
+ if (current_access == user)
+ return;
+
+ /* We are in "make access" mode. This means that the effective user and
+ group IDs are those of make (if it was installed setuid or setgid).
+ We now want to set the effective user and group IDs to the real IDs,
+ which are the IDs of the process that exec'd make. */
+
+ #if defined (USG) || defined (POSIX)
+ /* System V has only the setuid/setgid calls to set user/group IDs.
+ There is an effective ID, which can be set by setuid/setgid.
+ It can be set (unless you are root) only to either what it already is
+ (returned by geteuid/getegid, now in make_uid/make_gid),
+ the real ID (return by getuid/getgid, now in user_uid/user_gid),
+ or the saved set ID (what the effective ID was before this set-ID
+ executable (make) was exec'd). */
+ if (setuid (user_uid) < 0)
+ pfatal_with_name ("setuid");
+ if (setgid (user_gid) < 0)
+ pfatal_with_name ("setgid");
+ #else
+ /* In 4BSD, the setreuid/setregid calls set both the real and effective IDs.
+ They may be set to themselves or each other. So you have two alternatives
+ at any one time. If you use setuid/setgid, the effective will be set to
+ the real, leaving only one alternative. Using setreuid/setregid, however,
+ you can toggle between your two alternatives by swapping the values in a
+ single setreuid or setregid call. */
+ if (setreuid (make_uid, user_uid) < 0)
+ pfatal_with_name ("setreuid");
+ if (setregid (make_gid, user_gid) < 0)
+ pfatal_with_name ("setregid");
+ #endif
+
+ current_access = user;
+ }
+
+ /* Give the process appropriate permissions for access to
+ make data (i.e., the load average). */
+ void
+ make_access ()
+ {
+ if (!access_inited)
+ init_access ();
+
+ if (current_access == make)
+ return;
+
+ /* See comments in user_access, above. */
+
+ #if defined (USG) || defined (POSIX)
+ if (setuid (make_uid) < 0)
+ pfatal_with_name ("setuid");
+ if (setgid (make_gid) < 0)
+ pfatal_with_name ("setgid");
+ #else
+ if (setreuid (user_uid, make_uid) < 0)
+ pfatal_with_name ("setreuid");
+ if (setregid (user_gid, make_gid) < 0)
+ pfatal_with_name ("setregid");
+ #endif
+
+ current_access = make;
+ }
+
+ /* Give the process appropriate permissions for a child process.
+ This is like user_access, but you can't get back to make_access. */
+ void
+ child_access ()
+ {
+ /* Set both the real and effective UID and GID to the user's.
+ They cannot be changed back to make's. */
+
+ if (setuid (user_uid) < 0)
+ pfatal_with_name ("setuid");
+ if (setgid (user_gid) < 0)
+ pfatal_with_name ("setgid");
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/read.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/read.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/read.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,1554 ----
+ /* Copyright (C) 1988, 1989, 1990, 1991 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 2, 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. */
+
+ #include "make.h"
+ #include "commands.h"
+ #include "dep.h"
+ #include "file.h"
+ #include "variable.h"
+
+ /* This is POSIX.2, but most systems using -DPOSIX probably don't have it. */
+ #ifdef __GNU_LIBRARY__
+ #include <glob.h>
+ #else
+ #include "glob/glob.h"
+ #endif
+
+ #include <pwd.h>
+ struct passwd *getpwnam ();
+
+
+ static void read_makefile ();
+ static unsigned int readline (), do_define ();
+ static int conditional_line ();
+ static void record_files ();
+ static char *find_semicolon ();
+
+
+ /* A `struct linebuffer' is a structure which holds a line of text.
+ `readline' reads a line from a stream into a linebuffer
+ and works regardless of the length of the line. */
+
+ struct linebuffer
+ {
+ /* Note: This is the number of bytes malloc'ed for `buffer'
+ It does not indicate `buffer's real length.
+ Instead, a null char indicates end-of-string. */
+ unsigned int size;
+ char *buffer;
+ };
+
+ #define initbuffer(lb) (lb)->buffer = (char *) xmalloc ((lb)->size = 200)
+ #define freebuffer(lb) free ((lb)->buffer)
+
+
+ /* A `struct conditionals' contains the information describing
+ all the active conditionals in a makefile.
+
+ The global variable `conditionals' contains the conditionals
+ information for the current makefile. It is initialized from
+ the static structure `toplevel_conditionals' and is later changed
+ to new structures for included makefiles. */
+
+ struct conditionals
+ {
+ unsigned int if_cmds;
+ unsigned int max_ignoring;
+ char *ignoring;
+ };
+
+ static struct conditionals toplevel_conditionals;
+ static struct conditionals *conditionals = &toplevel_conditionals;
+
+
+ /* Default directories to search for include files in */
+
+ static char *default_include_directories[] =
+ {
+ "/usr/gnu/include",
+ "/usr/local/include",
+ "/usr/include",
+ 0
+ };
+
+ /* List of directories to search for include files in */
+
+ static char **include_directories;
+
+ /* Maximum length of an element of the above. */
+
+ static unsigned int max_incl_len;
+
+ /* The filename and pointer to line number of the
+ makefile currently being read in. */
+
+ char *reading_filename;
+ unsigned int *reading_lineno_ptr;
+
+ /* The chain of makefiles read by read_makefile. */
+
+ static struct dep *read_makefiles = 0;
+
+ /* Read in all the makefiles and return the chain of their names. */
+
+ struct dep *
+ read_all_makefiles (makefiles)
+ char **makefiles;
+ {
+ unsigned int num_makefiles = 0;
+
+ if (debug_flag)
+ puts ("Reading makefiles...");
+
+ /* If there's a non-null variable MAKEFILES, its value is a list of
+ files to read first thing. But don't let it prevent reading the
+ default makefiles and don't let the default goal come from there. */
+
+ {
+ char *value = allocated_variable_expand ("$(MAKEFILES)");
+ char *name, *p;
+ unsigned int length;
+
+ /* Set NAME to the start of next token and LENGTH to its length.
+ MAKEFILES is updated for finding remaining tokens. */
+ p = value;
+ while ((name = find_next_token (&p, &length)) != 0)
+ read_makefile (name, 1);
+
+ free (value);
+ }
+
+ /* Read makefiles specified with -f switches. */
+
+ if (makefiles != 0)
+ while (*makefiles != 0)
+ {
+ struct dep *tail = read_makefiles;
+ register struct dep *d;
+
+ read_makefile (*makefiles, 0);
+
+ /* Find the right element of read_makefiles. */
+ d = read_makefiles;
+ while (d->next != tail)
+ d = d->next;
+
+ /* Use the storage read_filename allocates. */
+ free (*makefiles);
+ *makefiles = dep_name (d);
+ ++num_makefiles;
+ ++makefiles;
+ }
+
+ /* If there were no -f switches, try the default names. */
+
+ if (num_makefiles == 0)
+ {
+ static char *default_makefiles[] =
+ { "GNUmakefile", "makefile", "Makefile", 0 };
+ register char **p = default_makefiles;
+ while (*p != 0 && !file_exists_p (*p))
+ ++p;
+
+ if (*p != 0)
+ read_makefile (*p, 0);
+ else
+ {
+ /* No default makefile was found. Add the default makefiles to the
+ `read_makefiles' chain so they will be updated if possible. */
+ struct dep *tail = read_makefiles;
+ for (p = default_makefiles; *p != 0; ++p)
+ {
+ struct dep *d = (struct dep *) xmalloc (sizeof (struct dep));
+ d->name = 0;
+ d->file = enter_file (*p);
+ d->file->dontcare = 1;
+ /* Setting the `changed' member to 1 will make failure to
+ update or find this makefile as if it had come from the
+ MAKEFILES variable: we don't care, so we won't die. */
+ d->changed = 1;
+ if (tail == 0)
+ read_makefiles = d;
+ else
+ tail->next = d;
+ tail = d;
+ }
+ if (tail != 0)
+ tail->next = 0;
+ }
+ }
+
+ return read_makefiles;
+ }
+
+ /* Read file FILENAME as a makefile and add its contents to the data base.
+
+ TYPE indicates what flavor of makefile this is: 0 => a default or -f
+ makefile (the basis for comparison); 1 => from the MAKEFILES variable:
+ cannot determine the default goal, is searched for in the search path,
+ and it's not an error if it doesn't exist; 2 => an included makefile:
+ is searched for in the search path.
+
+ FILENAME is added to the `read_makefiles' chain. */
+
+ static void
+ read_makefile (filename, type)
+ char *filename;
+ int type;
+ {
+ static char *collapsed = 0;
+ static unsigned int collapsed_length = 0;
+ register FILE *infile;
+ struct linebuffer lb;
+ unsigned int commands_len = 200;
+ char *commands = (char *) xmalloc (200);
+ unsigned int commands_idx = 0;
+ unsigned int commands_started;
+ register char *p;
+ char *p2;
+ int ignoring = 0;
+
+ struct nameseq *filenames = 0;
+ struct dep *deps;
+ unsigned int lineno = 1;
+ unsigned int nlines = 0;
+ int two_colon;
+ char *pattern = 0, *pattern_percent;
+
+ #define record_waiting_files() \
+ do \
+ { \
+ record_files (filenames, pattern, pattern_percent, deps, \
+ commands_started, commands, commands_idx, \
+ two_colon, filename, lineno, type != 1); \
+ filenames = 0; \
+ commands_idx = 0; \
+ pattern = 0; \
+ } while (0)
+
+ #ifdef lint /* Suppress `used before set' messages. */
+ two_colon = 0;
+ #endif
+
+ /* First, get a stream to read. */
+
+ infile = fopen (filename, "r");
+
+ /* If the makefile wasn't found and it's either a makefile from
+ the `MAKEFILES' variable (type 1) or an included makefile (type 2),
+ search the included makefile search path for this makefile. */
+
+ if (infile == 0 && (type == 1 || type == 2) && *filename != '/')
+ {
+ register unsigned int i;
+ for (i = 0; include_directories[i] != 0; ++i)
+ {
+ char *name = concat (include_directories[i], "/", filename);
+ infile = fopen (name, "r");
+ if (infile != 0)
+ {
+ filename = name;
+ break;
+ }
+ else
+ free (name);
+ }
+ }
+
+ /* Add FILENAME to the chain of read makefiles. */
+ deps = (struct dep *) xmalloc (sizeof (struct dep));
+ deps->next = read_makefiles;
+ read_makefiles = deps;
+ deps->name = 0;
+ deps->file = lookup_file (filename);
+ if (deps->file == 0)
+ {
+ deps->file = enter_file (savestring (filename, strlen (filename)));
+ if (type == 1)
+ deps->file->dontcare = 1;
+ }
+ filename = deps->file->name;
+ deps->file->precious = 1;
+ deps->changed = type;
+ deps = 0;
+
+ /* If the makefile can't be found at all,
+ either ignore it or give up entirely. */
+
+ if (infile == 0)
+ {
+ if (type != 1)
+ perror_with_name ("fopen: ", filename);
+ return;
+ }
+
+ reading_filename = filename;
+ reading_lineno_ptr = &lineno;
+
+ /* Loop over lines in the file.
+ The strategy is to accumulate target names in FILENAMES,
+ dependencies in DEPS and commands in COMMANDS.
+ These are used to define a rule
+ when the start of the next rule (or eof) is encountered. */
+
+ initbuffer (&lb);
+
+ while (!feof (infile))
+ {
+ lineno += nlines;
+ nlines = readline (&lb, infile, filename);
+
+ /* Collapse continuation lines. */
+ collapse_continuations (lb.buffer);
+
+ if (collapsed_length < lb.size)
+ {
+ collapsed_length = lb.size;
+ if (collapsed != 0)
+ free (collapsed);
+ collapsed = (char *) xmalloc (collapsed_length);
+ }
+ strcpy (collapsed, lb.buffer);
+ remove_comments (collapsed);
+
+ p = collapsed;
+ while (isspace (*p))
+ ++p;
+ if (*p == '\0' && lb.buffer[0] != '\t')
+ continue;
+
+ #define word1eq(s, l) ((p[l] == '\0' || isblank (p[l])) && \
+ !strncmp (s, p, l))
+ if (word1eq ("ifdef", 5) || word1eq ("ifndef", 6)
+ || word1eq ("ifeq", 4) || word1eq ("ifneq", 5)
+ || word1eq ("else", 4) || word1eq ("endif", 5))
+ {
+ int i = conditional_line (p, filename, lineno);
+ if (i >= 0)
+ {
+ ignoring = i;
+ continue;
+ }
+ else
+ makefile_fatal (filename, lineno,
+ "invalid syntax in conditional");
+ }
+ if (ignoring)
+ continue;
+ else if (lb.buffer[0] == '\t')
+ {
+ /* This line is a shell command. */
+ unsigned int len;
+
+ if (filenames == 0)
+ makefile_fatal (filename, lineno,
+ "commands commence before first target");
+
+ /* Add this command line to end of the line being accumulated. */
+ p = lb.buffer;
+ if (commands_idx == 0)
+ commands_started = lineno;
+ len = strlen (p);
+ if (len + 1 + commands_idx > commands_len)
+ {
+ commands_len = (len + 1 + commands_idx) * 2;
+ commands = (char *) xrealloc (commands, commands_len);
+ }
+ bcopy (p, &commands[commands_idx], len);
+ commands_idx += len;
+ commands[commands_idx++] = '\n';
+ }
+ else if (word1eq ("define", 6))
+ {
+ p2 = next_token (p + 6);
+ p = end_of_token (p2);
+ lineno = do_define (p2, p - p2, o_file, lineno, infile, filename);
+ continue;
+ }
+ else if (word1eq ("endef", 5))
+ makefile_fatal (filename, lineno, "extraneous `endef'");
+ else if (word1eq ("override", 8))
+ {
+ p2 = next_token (p + 8);
+ if (p2 == 0)
+ makefile_error (filename, lineno, "empty `override' directive");
+ if (!strncmp (p2, "define", 6))
+ {
+ unsigned int len;
+ p2 = end_of_token (p2);
+ p = find_next_token (&p2, &len);
+ lineno = do_define (p, len, o_override,
+ lineno, infile, filename);
+ }
+ else if (!try_variable_definition (p2, o_override))
+ makefile_error (filename, lineno,
+ "Empty `override' directive");
+ continue;
+ }
+ else if (word1eq ("include", 7))
+ {
+ /* We have found an `include' line specifying a nested
+ makefile to be read at this point. */
+ struct conditionals *save = conditionals;
+ struct conditionals new_conditionals;
+ p = allocated_variable_expand (next_token (p + 8));
+ if (*p == '\0')
+ {
+ makefile_error (filename, lineno, "no filename for `include'");
+ continue;
+ }
+ p2 = end_of_token (p);
+ if (*p2 != '\0')
+ {
+ *p2++ = '\0';
+ if (*next_token (p2) != '\0')
+ makefile_error (filename, lineno,
+ "extraneous text after `include'");
+ }
+ bzero ((char *) &new_conditionals, sizeof new_conditionals);
+ conditionals = &new_conditionals;
+ /* Record the rules that are waiting so they will determine
+ the default goal before those in the included makefile. */
+ record_waiting_files ();
+ read_makefile (p, 2);
+ free (p);
+ conditionals = save;
+ reading_filename = filename;
+ reading_lineno_ptr = &lineno;
+ continue;
+ }
+ else if (word1eq ("vpath", 5))
+ {
+ char *pattern;
+ unsigned int len;
+ p2 = variable_expand (p + 5);
+ p = find_next_token (&p2, &len);
+ if (p != 0)
+ {
+ pattern = savestring (p, len);
+ p = find_next_token (&p2, &len);
+ if (p != 0)
+ {
+ p = savestring (p, len);
+ if (find_next_token (&p2, (unsigned int *) 0) != 0)
+ makefile_error (filename, lineno,
+ "extraneous text after `vpath' directive");
+ }
+ /* No searchpath means remove all previous
+ selective VPATH's with the same pattern. */
+ }
+ else
+ /* No pattern means remove all previous selective VPATH's. */
+ pattern = 0;
+ construct_vpath_list (pattern, p);
+ if (pattern != 0)
+ free (pattern);
+ if (p != 0)
+ free (p);
+ continue;
+ }
+ #undef word1eq
+ else if (try_variable_definition (p, o_file))
+ continue;
+ else
+ {
+ /* This line describes some target files. */
+
+ char *cmdleft;
+
+ /* Record the previous rule. */
+
+ record_waiting_files ();
+
+ /* Look for a semicolon in the unexpanded line. */
+ cmdleft = find_semicolon (lb.buffer);
+ if (cmdleft != 0)
+ /* Found one. Cut the line short there before expanding it. */
+ *cmdleft = '\0';
+
+ /* Expand variable and function references before doing anything
+ else so that special characters can be inside variables. */
+ p = variable_expand (lb.buffer);
+
+ if (cmdleft == 0)
+ /* Look for a semicolon in the expanded line. */
+ cmdleft = find_semicolon (p);
+
+ if (cmdleft != 0)
+ /* Cut the line short at the semicolon. */
+ *cmdleft = '\0';
+
+ /* Remove comments from the line. */
+ remove_comments (p);
+
+ p2 = next_token (p);
+ if (*p2 == '\0')
+ /* This line contained a variable reference that
+ expanded to nothing but whitespace. */
+ continue;
+ else if (*p2 == ':')
+ makefile_fatal (filename, lineno, "missing target name");
+
+ filenames = multi_glob (parse_file_seq (&p2, ':',
+ sizeof (struct nameseq)),
+ sizeof (struct nameseq));
+ if (*p2++ == '\0')
+ makefile_fatal (filename, lineno, "missing separator");
+ /* Is this a one-colon or two-colon entry? */
+ two_colon = *p2 == ':';
+ if (two_colon)
+ p2++;
+
+ /* Is this a static pattern rule: `target: %targ: %dep; ...'? */
+ p = index (p2, ':');
+ while (p != 0 && p[-1] == '\\')
+ {
+ register char *q = &p[-1];
+ register int backslash = 0;
+ while (*q-- == '\\')
+ backslash = !backslash;
+ if (backslash)
+ p = index (p + 1, ':');
+ else
+ break;
+ }
+ if (p != 0)
+ {
+ struct nameseq *target;
+ target = parse_file_seq (&p2, ':', sizeof (struct nameseq));
+ ++p2;
+ if (target == 0)
+ makefile_fatal (filename, lineno, "missing target pattern");
+ else if (target->next != 0)
+ makefile_fatal (filename, lineno, "multiple target patterns");
+ pattern = target->name;
+ pattern_percent = find_percent (pattern);
+ if (pattern_percent == 0)
+ makefile_fatal (filename, lineno,
+ "target pattern contains no `%%'");
+ }
+ else
+ pattern = 0;
+
+ /* Parse the dependencies. */
+ deps = (struct dep *)
+ multi_glob (parse_file_seq (&p2, '\0', sizeof (struct dep)),
+ sizeof (struct dep));
+
+ commands_idx = 0;
+ if (cmdleft != 0)
+ {
+ /* Semicolon means rest of line is a command */
+ unsigned int len = strlen (cmdleft + 1);
+
+ commands_started = lineno;
+
+ /* Add this command line to the buffer. */
+ if (len + 2 > commands_len)
+ {
+ commands_len = (len + 2) * 2;
+ commands = (char *) xrealloc (commands, commands_len);
+ }
+ bcopy (cmdleft + 1, commands, len);
+ commands_idx += len;
+ commands[commands_idx++] = '\n';
+ }
+ }
+ }
+
+ if (ignoring)
+ makefile_fatal (filename, lineno, "missing `endif'");
+
+ /* At eof, record the last rule. */
+ record_waiting_files ();
+
+ freebuffer (&lb);
+ free ((char *) commands);
+ fclose (infile);
+
+ reading_filename = 0;
+ reading_lineno_ptr = 0;
+ }
+
+ /* Execute a `define' directive.
+ The first line has already been read, and NAME is the name of
+ the variable to be defined. The following lines remain to be read.
+ LINENO, INFILE and FILENAME refer to the makefile being read.
+ The value returned is LINENO, updated for lines read here. */
+
+ static unsigned int
+ do_define (name, namelen, origin, lineno, infile, filename)
+ char *name;
+ unsigned int namelen;
+ enum variable_origin origin;
+ unsigned int lineno;
+ FILE *infile;
+ char *filename;
+ {
+ struct linebuffer lb;
+ unsigned int nlines = 0;
+ unsigned int length = 100;
+ char *definition = (char *) xmalloc (100);
+ register unsigned int idx = 0;
+ register char *p;
+
+ initbuffer (&lb);
+ while (!feof (infile))
+ {
+ lineno += nlines;
+ nlines = readline (&lb, infile, filename);
+ p = next_token (lb.buffer);
+
+ if ((p[5] == '\0' || isblank (p[5])) && !strncmp (p, "endef", 5))
+ {
+ p += 5;
+ collapse_continuations (p);
+ remove_comments (p);
+ if (*next_token (p) != '\0')
+ makefile_error (filename, lineno,
+ "Extraneous text after `endef' directive");
+ /* Define the variable. */
+ if (idx == 0)
+ definition[0] = '\0';
+ else
+ definition[idx - 1] = '\0';
+ (void) define_variable (name, namelen, definition, origin, 1);
+ free (definition);
+ return lineno;
+ }
+ else
+ {
+ unsigned int len = strlen (p);
+
+ /* Increase the buffer size if necessary. */
+ if (idx + len + 1 > length)
+ {
+ length = (idx + len) * 2;
+ definition = (char *) xrealloc (definition, length + 1);
+ }
+
+ bcopy (p, &definition[idx], len);
+ idx += len;
+ /* Separate lines with a newline. */
+ definition[idx++] = '\n';
+ }
+ }
+
+ /* No `endef'!! */
+ makefile_fatal (filename, lineno, "missing `endef', unterminated `define'");
+ return 0;
+ }
+
+ /* Interpret conditional commands "ifdef", "ifndef", "ifeq",
+ "ifneq", "else" and "endif".
+ LINE is the input line, with the command as its first word.
+
+ FILENAME and LINENO are the filename and line number in the
+ current makefile. They are used for error messages.
+
+ Value is -1 if the line is invalid,
+ 0 if following text should be interpreted,
+ 1 if following text should be ignored. */
+
+ static int
+ conditional_line (line, filename, lineno)
+ char *line;
+ char *filename;
+ unsigned int lineno;
+ {
+ int notdef;
+ char *cmdname;
+ register unsigned int i;
+
+ if (*line == 'i')
+ {
+ /* It's an "if..." command. */
+ notdef = line[2] == 'n';
+ if (notdef)
+ {
+ cmdname = line[3] == 'd' ? "ifndef" : "ifneq";
+ line += cmdname[3] == 'd' ? 7 : 6;
+ }
+ else
+ {
+ cmdname = line[2] == 'd' ? "ifdef" : "ifeq";
+ line += cmdname[2] == 'd' ? 6 : 5;
+ }
+ }
+ else
+ {
+ /* It's an "else" or "endif" command. */
+ notdef = line[1] == 'n';
+ cmdname = notdef ? "endif" : "else";
+ line += notdef ? 5 : 4;
+ }
+
+ line = next_token (line);
+
+ if (*cmdname == 'e')
+ {
+ if (*line != '\0')
+ makefile_error (filename, lineno,
+ "Extraneous text after `%s' directive",
+ cmdname);
+ /* "Else" or "endif". */
+ if (conditionals->if_cmds == 0)
+ makefile_fatal (filename, lineno, "extraneous `%s'", cmdname);
+ /* NOTDEF indicates an `endif' command. */
+ if (notdef)
+ --conditionals->if_cmds;
+ else
+ conditionals->ignoring[conditionals->if_cmds - 1]
+ = !conditionals->ignoring[conditionals->if_cmds - 1];
+ for (i = 0; i < conditionals->if_cmds; ++i)
+ if (conditionals->ignoring[i])
+ return 1;
+ return 0;
+ }
+
+ if (conditionals->max_ignoring == 0)
+ {
+ conditionals->max_ignoring = 5;
+ conditionals->ignoring = (char *) xmalloc (conditionals->max_ignoring);
+ }
+
+ ++conditionals->if_cmds;
+ if (conditionals->if_cmds > conditionals->max_ignoring)
+ {
+ conditionals->max_ignoring += 5;
+ conditionals->ignoring = (char *)
+ xrealloc (conditionals->ignoring, conditionals->max_ignoring);
+ }
+
+ if (conditionals->if_cmds > 1 &&
+ conditionals->ignoring[conditionals->if_cmds - 2])
+ /* We are already ignoring, so just push a level
+ to match the next "else" or "endif", and keep ignoring. */
+ conditionals->ignoring[conditionals->if_cmds - 1] = 1;
+ else if (cmdname[notdef ? 3 : 2] == 'd')
+ {
+ /* "Ifdef" or "ifndef". */
+ struct variable *v;
+ register char *p = end_of_token (line);
+ i = p - line;
+ p = next_token (p);
+ if (*p != '\0')
+ return -1;
+ v = lookup_variable (line, i);
+ conditionals->ignoring[conditionals->if_cmds - 1]
+ = (v != 0 && *v->value != '\0') == notdef;
+ }
+ else
+ {
+ /* "Ifeq" or "ifneq". */
+ char *s1, *s2;
+ unsigned int len;
+ char termin = *line == '(' ? ',' : *line;
+
+ if (termin != ',' && termin != '"' && termin != '\'')
+ return -1;
+
+ s1 = ++line;
+ /* Find the end of the first string. */
+ if (termin == ',')
+ {
+ register int count = 0;
+ for (; *line != '\0'; ++line)
+ if (*line == '(')
+ ++count;
+ else if (*line == ')')
+ --count;
+ else if (*line == ',' && count <= 0)
+ break;
+ }
+ else
+ while (*line != '\0' && *line != termin)
+ ++line;
+
+ if (*line == '\0')
+ return -1;
+
+ *line++ = '\0';
+
+ s2 = variable_expand (s1);
+ /* We must allocate a new copy of the expanded string because
+ variable_expand re-uses the same buffer. */
+ len = strlen (s2);
+ s1 = (char *) alloca (len + 1);
+ bcopy (s2, s1, len + 1);
+
+ if (termin != ',')
+ /* Find the start of the second string. */
+ line = next_token (line);
+
+ termin = termin == ',' ? ')' : *line;
+ if (termin != ')' && termin != '"' && termin != '\'')
+ return -1;
+
+ /* Find the end of the second string. */
+ if (termin == ')')
+ {
+ register int count = 0;
+ s2 = next_token (line);
+ for (line = s2; *line != '\0'; ++line)
+ {
+ if (*line == '(')
+ ++count;
+ else if (*line == ')')
+ if (count <= 0)
+ break;
+ else
+ --count;
+ }
+ }
+ else
+ {
+ ++line;
+ s2 = line;
+ while (*line != '\0' && *line != termin)
+ ++line;
+ }
+
+ if (*line == '\0')
+ return -1;
+
+ *line = '\0';
+ line = next_token (++line);
+ if (*line != '\0')
+ makefile_error (filename, lineno,
+ "Extraneous text after `%s' directive",
+ cmdname);
+
+ s2 = variable_expand (s2);
+ conditionals->ignoring[conditionals->if_cmds - 1]
+ = streq (s1, s2) == notdef;
+ }
+
+ /* Search through the stack to see if we're ignoring. */
+ for (i = 0; i < conditionals->if_cmds; ++i)
+ if (conditionals->ignoring[i])
+ return 1;
+ return 0;
+ }
+
+ /* Remove duplicate dependencies in CHAIN. */
+
+ void
+ uniquize_deps (chain)
+ struct dep *chain;
+ {
+ register struct dep *d;
+
+ /* Make sure that no dependencies are repeated. This does not
+ really matter for the purpose of updating targets, but it
+ might make some names be listed twice for $^ and $?. */
+
+ for (d = chain; d != 0; d = d->next)
+ {
+ struct dep *last, *next;
+
+ last = d;
+ next = d->next;
+ while (next != 0)
+ if (streq (dep_name (d), dep_name (next)))
+ {
+ struct dep *n = next->next;
+ last->next = n;
+ if (next->name != 0 && next->name != d->name)
+ free (next->name);
+ if (next != d)
+ free ((char *) next);
+ next = n;
+ }
+ else
+ {
+ last = next;
+ next = next->next;
+ }
+ }
+ }
+
+ /* Record a description line for files FILENAMES,
+ with dependencies DEPS, commands to execute described
+ by COMMANDS and COMMANDS_IDX, coming from FILENAME:COMMANDS_STARTED.
+ TWO_COLON is nonzero if a double colon was used.
+ If not nil, PATTERN is the `%' pattern to make this
+ a static pattern rule, and PATTERN_PERCENT is a pointer
+ to the `%' within it.
+
+ The links of FILENAMES are freed, and so are any names in it
+ that are not incorporated into other data structures. */
+
+ static void
+ record_files (filenames, pattern, pattern_percent, deps, commands_started,
+ commands, commands_idx, two_colon, filename, lineno, set_default)
+ struct nameseq *filenames;
+ char *pattern, *pattern_percent;
+ struct dep *deps;
+ unsigned int commands_started;
+ char *commands;
+ unsigned int commands_idx;
+ int two_colon;
+ char *filename;
+ unsigned int lineno;
+ int set_default;
+ {
+ struct nameseq *nextf;
+ int implicit = 0;
+ unsigned int max_targets, target_idx;
+ char **targets = 0, **target_percents = 0;
+ struct commands *cmds;
+
+ if (commands_idx > 0)
+ {
+ cmds = (struct commands *) xmalloc (sizeof (struct commands));
+ cmds->filename = filename;
+ cmds->lineno = commands_started;
+ cmds->commands = savestring (commands, commands_idx);
+ cmds->command_lines = 0;
+ }
+ else
+ cmds = 0;
+
+ for (; filenames != 0; filenames = nextf)
+ {
+ register char *name = filenames->name;
+ register struct file *f;
+ register struct dep *d;
+ struct dep *this;
+ char *implicit_percent;
+
+ nextf = filenames->next;
+ free ((char *) filenames);
+
+ implicit_percent = find_percent (name);
+ implicit |= implicit_percent != 0;
+
+ if (implicit && pattern != 0)
+ makefile_fatal (filename, lineno,
+ "mixed implicit and static pattern rules");
+
+ if (implicit && implicit_percent == 0)
+ makefile_fatal (filename, lineno, "mixed implicit and normal rules");
+
+ if (implicit)
+ {
+ if (targets == 0)
+ {
+ max_targets = 5;
+ targets = (char **) xmalloc (5 * sizeof (char *));
+ target_percents = (char **) xmalloc (5 * sizeof (char *));
+ target_idx = 0;
+ }
+ else if (target_idx == max_targets - 1)
+ {
+ max_targets += 5;
+ targets = (char **) xrealloc ((char *) targets,
+ max_targets * sizeof (char *));
+ target_percents
+ = (char **) xrealloc ((char *) target_percents,
+ max_targets * sizeof (char *));
+ }
+ targets[target_idx] = name;
+ target_percents[target_idx] = implicit_percent;
+ ++target_idx;
+ continue;
+ }
+
+ /* If there are multiple filenames, copy the chain DEPS
+ for all but the last one. It is not safe for the same deps
+ to go in more than one place in the data base. */
+ this = nextf != 0 ? copy_dep_chain (deps) : deps;
+
+ if (pattern != 0)
+ /* If this is an extended static rule:
+ `targets: target%pattern: dep%pattern; cmds',
+ translate each dependency pattern into a plain filename
+ using the target pattern and this target's name. */
+ if (!pattern_matches (pattern, pattern_percent, name))
+ {
+ /* Give a warning if the rule is meaningless. */
+ makefile_error (filename, lineno,
+ "target `%s' doesn't match the target pattern");
+ this = 0;
+ }
+ else
+ {
+ /* We use patsubst_expand to do the work of translating
+ the target pattern, the target's name and the dependencies'
+ patterns into plain dependency names. */
+ char *buffer = variable_expand ("");
+
+ for (d = this; d != 0; d = d->next)
+ {
+ char *o;
+ char *percent = find_percent (d->name);
+ if (percent == 0)
+ continue;
+ o = patsubst_expand (buffer, name, pattern, d->name,
+ pattern_percent, percent);
+ free (d->name);
+ d->name = savestring (buffer, o - buffer);
+ }
+ }
+
+ if (!two_colon)
+ {
+ /* Single-colon. Combine these dependencies
+ with others in file's existing record, if any. */
+ f = enter_file (name);
+
+ if (f->double_colon)
+ makefile_fatal (filename, lineno,
+ "target file `%s' has both : and :: entries",
+ f->name);
+
+ /* If CMDS == F->CMDS, this target was listed in this rule
+ more than once. Just give a warning since this is harmless. */
+ if (cmds != 0 && cmds == f->cmds)
+ makefile_error
+ (filename, lineno,
+ "target `%s' given more than once in the same rule.",
+ f->name);
+
+ /* Check for two single-colon entries both with commands.
+ Check is_target so that we don't lose on files such as .c.o
+ whose commands were preinitialized. */
+ else if (cmds != 0 && f->cmds != 0 && f->is_target)
+ {
+ makefile_error (cmds->filename, cmds->lineno,
+ "warning: overriding commands for target `%s'",
+ f->name);
+ makefile_error (f->cmds->filename, f->cmds->lineno,
+ "warning: ignoring old commands for target `%s'",
+ f->name);
+ }
+
+ f->is_target = 1;
+
+ /* Defining .DEFAULT with no deps or cmds clears it. */
+ if (f == default_file && this == 0 && cmds == 0)
+ f->cmds = 0;
+ if (cmds != 0)
+ f->cmds = cmds;
+ /* Defining .SUFFIXES with no dependencies
+ clears out the list of suffixes. */
+ if (f == suffix_file && this == 0)
+ f->deps = 0;
+ else if (f->deps != 0)
+ {
+ d = f->deps;
+ while (d->next != 0)
+ d = d->next;
+ d->next = this;
+ }
+ else
+ f->deps = this;
+
+ uniquize_deps (f->deps);
+
+ /* If this is a static pattern rule, set the file's stem to
+ the part of its name that matched the `%' in the pattern,
+ so you can use $* in the commands. */
+ if (pattern != 0)
+ {
+ static char *percent = "%";
+ char *buffer = variable_expand ("");
+ char *o = patsubst_expand (buffer, name, pattern, percent,
+ pattern_percent, percent);
+ f->stem = savestring (buffer, o - buffer);
+ }
+ }
+ else
+ {
+ /* Double-colon. Make a new record
+ even if the file already has one. */
+ f = lookup_file (name);
+ /* Check for both : and :: rules. Check is_target so
+ we don't lose on default suffix rules or makefiles. */
+ if (f != 0 && f->is_target && !f->double_colon)
+ makefile_fatal (filename, lineno,
+ "target file `%s' has both : and :: entries",
+ f->name);
+ f = enter_file (name);
+ /* If there was an existing entry and it was a
+ double-colon entry, enter_file will have returned a
+ new one, making it the prev pointer of the old one. */
+ f->is_target = 1;
+ f->double_colon = 1;
+ f->deps = this;
+ f->cmds = cmds;
+ }
+
+ /* Free name if not needed further. */
+ if (f != 0 && name != f->name
+ && !(f->name == name + 2 && name[0] == '.' && name[1] == '/'))
+ {
+ free (name);
+ name = f->name;
+ }
+
+ /* See if this is first target seen whose name does
+ not start with a `.', unless it contains a slash. */
+ if (default_goal_file == 0 && set_default
+ && (*name != '.' || index (name, '/') != 0))
+ {
+ int reject = 0;
+
+ /* If this file is a suffix, don't
+ let it be the default goal file. */
+
+ for (d = suffix_file->deps; d != 0; d = d->next)
+ {
+ register struct dep *d2;
+ if (*dep_name (d) != '.' && streq (name, dep_name (d)))
+ {
+ reject = 1;
+ break;
+ }
+ for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
+ {
+ register unsigned int len = strlen (dep_name (d2));
+ if (strncmp (name, dep_name (d2), len))
+ continue;
+ if (streq (name + len, dep_name (d)))
+ {
+ reject = 1;
+ break;
+ }
+ }
+ if (reject)
+ break;
+ }
+
+ if (!reject)
+ default_goal_file = f;
+ }
+ }
+
+ if (implicit)
+ {
+ targets[target_idx] = 0;
+ target_percents[target_idx] = 0;
+ create_pattern_rule (targets, target_percents, two_colon, deps, cmds, 1);
+ free ((char *) target_percents);
+ }
+ }
+
+ /* Search STRING for an unquoted ; that is not after an unquoted #. */
+
+ static char *
+ find_semicolon (string)
+ char *string;
+ {
+ char *found, *p;
+
+ found = index (string, ';');
+ while (found != 0 && found[-1] == '\\')
+ {
+ register char *q = &found[-1];
+ register int backslash = 0;
+ while (*q-- == '\\')
+ backslash = !backslash;
+ if (backslash)
+ found = index (found + 1, ';');
+ else
+ break;
+ }
+ if (found == 0)
+ return 0;
+
+ /* Look for a comment character (#) before the ; we found. */
+ p = lindex (string, found, '#');
+ while (p != 0 && p[-1] == '\\')
+ {
+ register char *q = &p[-1];
+ register int backslash = 0;
+ while (*q-- == '\\')
+ backslash = !backslash;
+ if (backslash)
+ p = lindex (p + 1, found, '#');
+ else
+ break;
+ }
+ if (p == 0)
+ return found;
+ return 0;
+ }
+
+ /* Search PATTERN for an unquoted %. Backslashes quote % and backslash.
+ Quoting backslashes are removed from PATTERN by compacting it into
+ itself. Returns a pointer to the first unquoted % if there is one,
+ or nil if there are none. */
+
+ char *
+ find_percent (pattern)
+ char *pattern;
+ {
+ unsigned int pattern_len = strlen (pattern);
+ register char *p = pattern;
+
+ while ((p = index (p, '%')) != 0)
+ if (p > pattern && p[-1] == '\\')
+ {
+ /* Search for more backslashes. */
+ register int i = -2;
+ while (&p[i] >= pattern && p[i] == '\\')
+ --i;
+ ++i;
+ /* The number of backslashes is now -I.
+ Copy P over itself to swallow half of them. */
+ bcopy (&p[i / 2], &p[i], (pattern_len - (p - pattern)) - (i / 2) + 1);
+ p += i / 2;
+ if (i % 2 == 0)
+ /* All the backslashes quoted each other; the % was unquoted. */
+ return p;
+ else
+ /* The % was quoted by a backslash. Look for another. */
+ ++p;
+ }
+ else
+ /* No backslash in sight. */
+ return p;
+
+ /* Never hit a %. */
+ return 0;
+ }
+
+ /* Parse a string into a sequence of filenames represented as a
+ chain of struct nameseq's in reverse order and return that chain.
+
+ The string is passed as STRINGP, the address of a string pointer.
+ The string pointer is updated to point at the first character
+ not parsed, which either is a null char or equals STOPCHAR.
+
+ SIZE is how big to construct chain elements.
+ This is useful if we want them actually to be other structures
+ that have room for additional info. */
+
+ struct nameseq *
+ parse_file_seq (stringp, stopchar, size)
+ char **stringp;
+ char stopchar;
+ unsigned int size;
+ {
+ register struct nameseq *new = 0;
+ register struct nameseq *new1;
+ register char *p = *stringp;
+ char *q;
+ char *name;
+ register int c;
+
+ while (1)
+ {
+ /* Skip whitespace; see if any more names are left. */
+ p = next_token (p);
+ if (*p == '\0')
+ break;
+ if (*p == stopchar)
+ break;
+ /* Yes, find end of next name. */
+ q = p;
+ while (1)
+ {
+ c = *p++;
+ if (c == '\0')
+ break;
+ else if (c == '\\' &&
+ (*p == '\\' || isblank (*p) || *p == stopchar))
+ ++p;
+ else if (isblank (c) || c == stopchar)
+ break;
+ }
+ p--;
+
+ /* Extract the filename just found, and skip it. */
+ name = savestring (q, p - q);
+
+ /* Add it to the front of the chain. */
+ new1 = (struct nameseq *) xmalloc (size);
+ new1->name = name;
+ new1->next = new;
+ new = new1;
+ }
+
+ *stringp = p;
+ return new;
+ }
+
+ /* Read a line of text from STREAM into LINEBUFFER.
+ Combine continuation lines into one line.
+ Return the number of actual lines read (> 1 if hacked continuation lines).
+ */
+
+ static unsigned int
+ readline (linebuffer, stream, filename)
+ struct linebuffer *linebuffer;
+ FILE *stream;
+ char *filename;
+ {
+ char *buffer = linebuffer->buffer;
+ register char *p = linebuffer->buffer;
+ register char *end = p + linebuffer->size;
+ register int len, lastlen = 0;
+ register char *p2;
+ register unsigned int nlines = 0;
+ register int backslash;
+
+ *p = '\0';
+
+ while (1)
+ {
+ if (fgets (p, end - p, stream) == 0)
+ if (feof (stream))
+ return nlines;
+ else
+ pfatal_with_name (filename);
+
+ len = strlen (p);
+ if (len == 0 || (p += len)[-1] != '\n')
+ {
+ /* Probably ran out of buffer space. */
+ register unsigned int p_off = p - buffer;
+ linebuffer->size *= 2;
+ buffer = (char *) xrealloc (buffer, linebuffer->size);
+ p = buffer + p_off;
+ end = buffer + linebuffer->size;
+ linebuffer->buffer = buffer;
+ *p = '\0';
+ lastlen = len;
+ continue;
+ }
+
+ ++nlines;
+
+ if (len == 1 && p > buffer)
+ /* P is pointing at a newline and it's the beginning of
+ the buffer returned by the last fgets call. However,
+ it is not necessarily the beginning of a line if P is
+ pointing past the beginning of the holding buffer.
+ If the buffer was just enlarged (right before the newline),
+ we must account for that, so we pretend that the two lines
+ were one line. */
+ len += lastlen;
+ lastlen = len;
+ backslash = 0;
+ for (p2 = p - 2; --len > 0; --p2)
+ {
+ if (*p2 == '\\')
+ backslash = !backslash;
+ else
+ break;
+ }
+
+ if (!backslash)
+ {
+ p[-1] = '\0';
+ return nlines;
+ }
+
+ if (end - p <= 1)
+ {
+ /* Enlarge the buffer. */
+ register unsigned int p_off = p - buffer;
+ linebuffer->size *= 2;
+ buffer = (char *) xrealloc (buffer, linebuffer->size);
+ p = buffer + p_off;
+ end = buffer + linebuffer->size;
+ linebuffer->buffer = buffer;
+ }
+ }
+ }
+
+ /* Construct the list of include directories
+ from the arguments and the default list. */
+
+ void
+ construct_include_path (arg_dirs)
+ char **arg_dirs;
+ {
+ register unsigned int i;
+ struct stat stbuf;
+
+ /* Table to hold the dirs. */
+
+ register unsigned int defsize = (sizeof (default_include_directories)
+ / sizeof (default_include_directories[0]));
+ register unsigned int max = 5;
+ register char **dirs = (char **) xmalloc ((5 + defsize) * sizeof (char *));
+ register unsigned int idx = 0;
+
+ /* First consider any dirs specified with -I switches.
+ Ignore dirs that don't exist. */
+
+ if (arg_dirs != 0)
+ while (*arg_dirs != 0)
+ {
+ char *dir = *arg_dirs++;
+ if (stat (dir, &stbuf) == 0 && S_ISDIR (stbuf.st_mode))
+ {
+ if (idx == max - 1)
+ {
+ max += 5;
+ dirs = (char **)
+ xrealloc ((char *) dirs, (max + defsize) * sizeof (char *));
+ }
+ dirs[idx++] = dir;
+ }
+ }
+
+ /* Now add at the end the standard default dirs. */
+
+ for (i = 0; default_include_directories[i] != 0; ++i)
+ if (stat (default_include_directories[i], &stbuf) == 0
+ && S_ISDIR (stbuf.st_mode))
+ dirs[idx++] = default_include_directories[i];
+
+ dirs[idx] = 0;
+
+ /* Now compute the maximum length of any name in it. */
+
+ max_incl_len = 0;
+ for (i = 0; i < idx; ++i)
+ {
+ unsigned int len = strlen (dirs[i]);
+ /* If dir name is written with a trailing slash, discard it. */
+ if (dirs[i][len - 1] == '/')
+ /* We can't just clobber a null in because it may have come from
+ a literal string and literal strings may not be writable. */
+ dirs[i] = savestring (dirs[i], len - 1);
+ if (len > max_incl_len)
+ max_incl_len = len;
+ }
+
+ include_directories = dirs;
+ }
+
+ /* Given a chain of struct nameseq's describing a sequence of filenames,
+ in reverse of the intended order, return a new chain describing the
+ result of globbing the filenames. The new chain is in forward order.
+ The links of the old chain are freed or used in the new chain.
+ Likewise for the names in the old chain.
+
+ SIZE is how big to construct chain elements.
+ This is useful if we want them actually to be other structures
+ that have room for additional info. */
+
+ struct nameseq *
+ multi_glob (chain, size)
+ struct nameseq *chain;
+ unsigned int size;
+ {
+ register struct nameseq *new = 0;
+ register struct nameseq *old;
+ struct nameseq *nexto;
+
+ for (old = chain; old != 0; old = nexto)
+ {
+ glob_t gl;
+
+ nexto = old->next;
+
+ if (old->name[0] == '~')
+ {
+ if (old->name[1] == '/' || old->name[1] == '\0')
+ {
+ extern char *getenv ();
+ char *home_dir = allocated_variable_expand ("$(HOME)");
+ int is_variable = home_dir[0] != '\0';
+ if (!is_variable)
+ {
+ free (home_dir);
+ home_dir = getenv ("HOME");
+ }
+ if (home_dir == 0 || home_dir[0] == '\0')
+ {
+ extern char *getlogin ();
+ char *name = getlogin ();
+ home_dir = 0;
+ if (name != 0)
+ {
+ struct passwd *p = getpwnam (name);
+ if (p != 0)
+ home_dir = p->pw_dir;
+ }
+ }
+ if (home_dir != 0)
+ {
+ char *new = concat (home_dir, "", old->name + 1);
+ if (is_variable)
+ free (home_dir);
+ free (old->name);
+ old->name = new;
+ }
+ }
+ else
+ {
+ struct passwd *pwent;
+ char *userend = index (old->name + 1, '/');
+ if (userend != 0)
+ *userend = '\0';
+ pwent = getpwnam (old->name + 1);
+ if (pwent != 0)
+ {
+ if (userend == 0)
+ {
+ free (old->name);
+ old->name = savestring (pwent->pw_dir,
+ strlen (pwent->pw_dir));
+ }
+ else
+ {
+ char *new = concat (pwent->pw_dir, "/", userend + 1);
+ free (old->name);
+ old->name = new;
+ }
+ }
+ else if (userend != 0)
+ *userend = '/';
+ }
+ }
+
+ switch (glob (old->name, GLOB_NOCHECK, NULL, &gl))
+ {
+ case 0: /* Success. */
+ {
+ register int i;
+ for (i = 0; i < gl.gl_pathc; ++i)
+ {
+ struct nameseq *elt = (struct nameseq *) xmalloc (size);
+ elt->name = savestring (gl.gl_pathv[i],
+ strlen (gl.gl_pathv[i]));
+ elt->next = new;
+ new = elt;
+ }
+ globfree (&gl);
+ break;
+ }
+
+ case GLOB_NOSPACE:
+ fatal ("virtual memory exhausted");
+ break;
+
+ default:
+ old->next = new;
+ new = old;
+ }
+ }
+
+ return new;
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/remake.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/remake.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/remake.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,907 ----
+ /* Copyright (C) 1988-1991 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 2, 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. */
+
+ #include "make.h"
+ #include "commands.h"
+ #include "job.h"
+ #include "dep.h"
+ #include "file.h"
+
+ #if !defined (USG) && !defined (POSIX)
+ #ifndef sgi
+ #include <sys/file.h>
+ #endif
+ #else
+ #include <fcntl.h>
+ #endif
+
+
+ #if !defined(__GNU_LIBRARY__) && !defined(POSIX)
+ extern int fstat ();
+ extern time_t time ();
+ #endif
+
+ extern int try_implicit_rule ();
+
+
+ /* Incremented when a file has been remade. */
+ static unsigned int files_remade = 0;
+
+ static int update_file (), update_file_1 (), check_dep ();
+ static void remake_file ();
+ static time_t name_mtime (), library_file_mtime ();
+ extern time_t f_mtime ();
+
+ /* Remake all the goals in the `struct dep' chain GOALS. Return -1 if nothing
+ was done, 0 if all goals were updated successfully, or 1 if a goal failed.
+ If MAKEFILES is nonzero, these goals are makefiles, so -t, -q, and -n should
+ be disabled for them unless they were also command-line targets, and we
+ should only make one goal at a time and return as soon as one goal whose
+ `changed' member is nonzero is successfully made. */
+
+ int
+ update_goal_chain (goals, makefiles)
+ register struct dep *goals;
+ int makefiles;
+ {
+ int t = touch_flag, q = question_flag, n = just_print_flag;
+ unsigned int j = job_slots;
+ int status = -1;
+
+ #define MTIME(file) (makefiles ? file_mtime_no_search (file) \
+ : file_mtime (file))
+
+ /* Duplicate the chain so we can remove things from it. */
+
+ goals = copy_dep_chain (goals);
+
+ if (makefiles)
+ /* Only run one job at a time. */
+ job_slots = 1;
+
+ /* Update all the goals until they are all finished. */
+
+ while (goals != 0)
+ {
+ register struct dep *g, *lastgoal;
+
+ /* Wait for a child to die. */
+
+ wait_for_children (1, 0);
+
+ lastgoal = 0;
+ g = goals;
+ while (g != 0)
+ {
+ int x;
+ time_t mtime = MTIME (g->file);
+ check_renamed (g->file);
+
+ if (makefiles)
+ {
+ if (g->file->cmd_target)
+ {
+ touch_flag = t;
+ question_flag = q;
+ just_print_flag = n;
+ }
+ else
+ touch_flag = question_flag = just_print_flag = 0;
+ }
+
+ x = update_file (g->file, makefiles ? 1 : 0);
+ check_renamed (g->file);
+ if (x != 0 || g->file->updated)
+ {
+ int stop = 0;
+ /* If STATUS was not already 1, set it to 1 if
+ updating failed, or to 0 if updating succeeded.
+ Leave STATUS as it is if no updating was done. */
+ if (status < 1)
+ {
+ if (g->file->update_status != 0)
+ {
+ /* Updating failed. */
+ status = 1;
+ stop = !keep_going_flag && !makefiles;
+ }
+ else if (MTIME (g->file) != mtime)
+ {
+ /* Updating was done.
+ If this is a makefile and just_print_flag or
+ question_flag is set (meaning -n or -q was given
+ and this file was specified as a command-line target),
+ don't change STATUS. If STATUS is changed, we will
+ get re-exec'd, and fall into an infinite loop. */
+ if (!makefiles || (!just_print_flag && !question_flag))
+ status = 0;
+ if (makefiles && g->file->dontcare)
+ /* This is a default makefile. Stop remaking. */
+ stop = 1;
+ }
+ }
+
+ g->file = g->file->prev;
+ if (stop || g->file == 0)
+ {
+ /* This goal is finished. Remove it from the chain. */
+ if (lastgoal == 0)
+ goals = g->next;
+ else
+ lastgoal->next = g->next;
+
+ /* Free the storage. */
+ free ((char *) g);
+
+ g = lastgoal == 0 ? goals : lastgoal->next;
+ }
+
+ if (stop)
+ break;
+ }
+ else
+ {
+ lastgoal = g;
+ g = g->next;
+ }
+ }
+ }
+
+ if (makefiles)
+ {
+ touch_flag = t;
+ question_flag = q;
+ just_print_flag = n;
+ job_slots = j;
+ }
+
+ return status;
+ }
+
+ /* If FILE is not up to date, execute the commands for it.
+ Return 0 if successful, 1 if unsuccessful;
+ but with some flag settings, just call `exit' if unsuccessful.
+
+ DEPTH is the depth in recursions of this function.
+ We increment it during the consideration of our dependencies,
+ then decrement it again after finding out whether this file
+ is out of date.
+
+ If there are multiple double-colon entries for FILE,
+ each is considered in turn. */
+
+ static int
+ update_file (file, depth)
+ struct file *file;
+ unsigned int depth;
+ {
+ register int status = 0;
+ register struct file *f;
+ unsigned int ofiles_remade = files_remade;
+ int commands_finished = 0;
+
+ for (f = file; f != 0; f = f->prev)
+ {
+ register struct dep *d;
+ char not_started = f->command_state == cs_not_started;
+
+ status |= update_file_1 (f, depth);
+ check_renamed (f);
+
+ for (d = f->also_make; d != 0; d = d->next)
+ {
+ d->file->command_state = f->command_state;
+ d->file->update_status = f->update_status;
+ d->file->updated = f->updated;
+ }
+
+ if (status != 0 && !keep_going_flag)
+ return status;
+
+ commands_finished |= not_started && f->command_state == cs_finished;
+ }
+
+ /* For a top level target, if we have found nothing whatever to do for it,
+ print a message saying nothing needs doing. */
+
+ if (status == 0 && files_remade == ofiles_remade
+ && commands_finished && depth == 0 && !silent_flag && !question_flag)
+ {
+ if (file->phony || file->cmds == 0)
+ message ("Nothing to be done for `%s'.", file->name);
+ else
+ message ("`%s' is up to date.", file->name);
+ fflush (stdout);
+ }
+
+ return status;
+ }
+
+ /* Consider a single `struct file' and update it as appropriate. */
+
+ static int
+ update_file_1 (file, depth)
+ struct file *file;
+ unsigned int depth;
+ {
+ register time_t this_mtime;
+ int noexist, must_make, deps_changed;
+ int dep_status = 0;
+ register struct dep *d, *lastd;
+ char running = 0;
+
+ DEBUGPR ("Considering target file `%s'.\n");
+
+ if (file->updated)
+ {
+ if (file->update_status > 0)
+ {
+ DEBUGPR ("Recently tried and failed to update file `%s'.\n");
+ return file->update_status;
+ }
+
+ DEBUGPR ("File `%s' was considered already.\n");
+ return 0;
+ }
+
+ switch (file->command_state)
+ {
+ case cs_not_started:
+ case cs_deps_running:
+ break;
+ case cs_running:
+ DEBUGPR ("Still updating file `%s'.\n");
+ return 0;
+ case cs_finished:
+ DEBUGPR ("Finished updating file `%s'.\n");
+ return file->update_status;
+ default:
+ abort ();
+ }
+
+ ++depth;
+
+ /* Notice recursive update of the same file. */
+ file->updating = 1;
+
+ /* Looking at the file's modtime beforehand allows the possibility
+ that its name may be changed by a VPATH search, and thus it may
+ not need an implicit rule. If this were not done, the file
+ might get implicit commands that apply to its initial name, only
+ to have that name replaced with another found by VPATH search. */
+
+ this_mtime = file_mtime (file);
+ check_renamed (file);
+ noexist = this_mtime == (time_t) -1;
+ if (noexist)
+ DEBUGPR ("File `%s' does not exist.\n");
+
+ must_make = noexist;
+
+ /* If file was specified as a target with no commands,
+ come up with some default commands. */
+
+ if (!file->phony && file->cmds == 0 && !file->tried_implicit)
+ {
+ if (try_implicit_rule (file, depth))
+ DEBUGPR ("Found an implicit rule for `%s'.\n");
+ else
+ {
+ DEBUGPR ("No implicit rule found for `%s'.\n");
+ if (default_file != 0 && default_file->cmds != 0)
+ {
+ DEBUGPR ("Using default commands for `%s'.\n");
+ file->cmds = default_file->cmds;
+ }
+ }
+ file->tried_implicit = 1;
+ }
+
+ /* Update all non-intermediate files we depend on, if necessary,
+ and see whether any of them is more recent than this file. */
+
+ lastd = 0;
+ d = file->deps;
+ while (d != 0)
+ {
+ time_t mtime;
+
+ mtime = file_mtime (d->file);
+ check_renamed (d->file);
+
+ if (d->file->updating)
+ {
+ error ("Circular %s <- %s dependency dropped.",
+ file->name, d->file->name);
+ if (lastd == 0)
+ {
+ file->deps = d->next;
+ free ((char *) d);
+ d = file->deps;
+ }
+ else
+ {
+ lastd->next = d->next;
+ free ((char *) d);
+ d = lastd->next;
+ }
+ continue;
+ }
+
+ d->file->parent = file;
+ dep_status |= check_dep (d->file, depth, this_mtime, &must_make);
+ check_renamed (d->file);
+
+ {
+ register struct file *f = d->file;
+ do
+ {
+ running |= (f->command_state == cs_running
+ || f->command_state == cs_deps_running);
+ f = f->prev;
+ }
+ while (f != 0);
+ }
+
+ if (dep_status != 0 && !keep_going_flag)
+ break;
+
+ if (!running)
+ d->changed = file_mtime (d->file) != mtime;
+
+ lastd = d;
+ d = d->next;
+ }
+
+ /* Now we know whether this target needs updating.
+ If it does, update all the intermediate files we depend on. */
+
+ if (must_make)
+ {
+ for (d = file->deps; d != 0; d = d->next)
+ if (d->file->intermediate)
+ {
+ time_t mtime = file_mtime (d->file);
+ check_renamed (d->file);
+ d->file->parent = file;
+ dep_status |= update_file (d->file, depth);
+ check_renamed (d->file);
+
+ {
+ register struct file *f = d->file;
+ do
+ {
+ running |= (f->command_state == cs_running
+ || f->command_state == cs_deps_running);
+ f = f->prev;
+ }
+ while (f != 0);
+ }
+
+ if (dep_status != 0 && !keep_going_flag)
+ break;
+
+ if (!running)
+ d->changed = ((file->phony && file->cmds != 0)
+ || file_mtime (d->file) != mtime);
+ }
+ }
+
+ file->updating = 0;
+
+ DEBUGPR ("Finished dependencies of target file `%s'.\n");
+
+ if (running)
+ {
+ file->command_state = cs_deps_running;
+ --depth;
+ DEBUGPR ("The dependencies of `%s' are being made.\n");
+ return 0;
+ }
+
+ /* If any dependency failed, give up now. */
+
+ if (dep_status != 0)
+ {
+ file->command_state = cs_finished;
+ file->update_status = dep_status;
+ file->updated = 1;
+
+ depth--;
+
+ DEBUGPR ("Giving up on target file `%s'.\n");
+
+ if (depth == 0 && keep_going_flag
+ && !just_print_flag && !question_flag)
+ error ("Target `%s' not remade because of errors.", file->name);
+
+ return dep_status;
+ }
+
+ file->command_state = cs_not_started;
+
+ /* Now record which dependencies are more
+ recent than this file, so we can define $?. */
+
+ deps_changed = 0;
+ for (d = file->deps; d != 0; d = d->next)
+ {
+ time_t d_mtime = file_mtime (d->file);
+ check_renamed (d->file);
+
+ #if 1 /* %%% In version 4, remove this code completely to
+ implement not remaking deps if their deps are newer
+ than their parents. */
+ if (d_mtime == (time_t) -1 && !d->file->intermediate)
+ /* We must remake if this dep does not
+ exist and is not intermediate. */
+ must_make = 1;
+ #endif
+
+ /* Set DEPS_CHANGED if this dep actually changed. */
+ deps_changed |= d->changed;
+
+ /* Set D->changed if either this dep actually changed,
+ or its dependent, FILE, is older or does not exist. */
+ d->changed |= noexist || d_mtime > this_mtime;
+
+ if (debug_flag && !noexist)
+ {
+ print_spaces (depth);
+ if (d_mtime == (time_t) -1)
+ printf ("Dependency `%s' does not exist.\n", dep_name (d));
+ else
+ printf ("Dependency `%s' is %s than dependent `%s'.\n",
+ dep_name (d), d->changed ? "newer" : "older", file->name);
+ fflush (stdout);
+ }
+ }
+
+ /* Here depth returns to the value it had when we were called. */
+ depth--;
+
+ if (file->double_colon && file->deps == 0)
+ {
+ must_make = 1;
+ DEBUGPR ("Target `%s' is double-colon and has no dependencies.\n");
+ }
+ else if (file->is_target && !deps_changed && file->cmds == 0)
+ {
+ must_make = 0;
+ DEBUGPR ("No commands for `%s' and no dependencies actually changed.\n");
+ }
+
+ if (!must_make)
+ {
+ DEBUGPR ("No need to remake target `%s'.\n");
+ file->command_state = cs_finished;
+ file->update_status = 0;
+ file->updated = 1;
+ return 0;
+ }
+
+ DEBUGPR ("Must remake target `%s'.\n");
+
+ /* Now, take appropriate actions to remake the file. */
+ remake_file (file);
+
+ if (file->command_state != cs_finished)
+ {
+ DEBUGPR ("Commands of `%s' are being run.\n");
+ return 0;
+ }
+
+ switch (file->update_status)
+ {
+ case 1:
+ DEBUGPR ("Failed to remake target file `%s'.\n");
+ break;
+ case 0:
+ DEBUGPR ("Successfully remade target file `%s'.\n");
+ break;
+ case -1:
+ error ("internal error: `%s' update_status is -1 at cs_finished!",
+ file->name);
+ abort ();
+ default:
+ error ("internal error: `%s' update_status invalid!", file->name);
+ abort ();
+ }
+
+ file->updated = 1;
+ return file->update_status;
+ }
+
+ /* Set FILE's `updated' flag and re-check its mtime and the mtime's
+ of all files listed in its `also_make' member. */
+
+ void
+ notice_finished_file (file)
+ register struct file *file;
+ {
+ struct dep *d;
+
+ file->command_state = cs_finished;
+ file->updated = 1;
+
+ ++files_remade;
+
+ if (!file->phony)
+ {
+ if (just_print_flag || question_flag
+ || (file->is_target && file->cmds == 0))
+ file->last_mtime = time ((time_t *) 0);
+ else
+ file->last_mtime = 0;
+ }
+
+ for (d = file->also_make; d != 0; d = d->next)
+ {
+ d->file->command_state = cs_finished;
+ d->file->updated = 1;
+ d->file->update_status = file->update_status;
+ if (just_print_flag || question_flag)
+ d->file->last_mtime = file->last_mtime;
+ else
+ d->file->last_mtime = 0;
+ }
+ }
+
+ /* Check whether another file (whose mtime is THIS_MTIME)
+ needs updating on account of a dependency which is file FILE.
+ If it does, store 1 in *MUST_MAKE_PTR.
+ In the process, update any non-intermediate files
+ that FILE depends on (including FILE itself).
+ Return nonzero if any updating failed. */
+
+ static int
+ check_dep (file, depth, this_mtime, must_make_ptr)
+ struct file *file;
+ unsigned int depth;
+ time_t this_mtime;
+ int *must_make_ptr;
+ {
+ register struct dep *d;
+ int dep_status = 0;
+
+ ++depth;
+ file->updating = 1;
+
+ if (!file->intermediate)
+ /* If this is a non-intermediate file, update it and record
+ whether it is newer than THIS_MTIME. */
+ {
+ time_t mtime;
+ dep_status = update_file (file, depth);
+ check_renamed (file);
+ mtime = file_mtime (file);
+ check_renamed (file);
+ if (mtime == (time_t) -1 || mtime > this_mtime)
+ *must_make_ptr = 1;
+ }
+ else
+ {
+ /* FILE is an intermediate file.
+ Update all non-intermediate files we depend on, if necessary,
+ and see whether any of them is more recent than the file
+ on whose behalf we are checking. */
+ register struct dep *lastd;
+ lastd = 0;
+ d = file->deps;
+ while (d != 0)
+ {
+ if (d->file->updating)
+ {
+ error ("Circular %s <- %s dependency dropped.",
+ file->name, d->file->name);
+ if (lastd == 0)
+ {
+ file->deps = d->next;
+ free ((char *) d);
+ d = file->deps;
+ }
+ else
+ {
+ lastd->next = d->next;
+ free ((char *) d);
+ d = lastd->next;
+ }
+ continue;
+ }
+
+ d->file->parent = file;
+ dep_status |= check_dep (d->file, depth, this_mtime, must_make_ptr);
+ check_renamed (d->file);
+ if (dep_status != 0 && !keep_going_flag)
+ break;
+
+ lastd = d;
+ d = d->next;
+ }
+ }
+
+ file->updating = 0;
+ return dep_status;
+ }
+
+ /* Touch FILE. Return zero if successful, nonzero if not. */
+
+ #define TOUCH_ERROR(call) return (perror_with_name (call, file->name), 1)
+
+ static int
+ touch_file (file)
+ register struct file *file;
+ {
+ if (!silent_flag)
+ {
+ printf ("touch %s\n", file->name);
+ fflush (stdout);
+ }
+
+ #ifndef NO_ARCHIVES
+ if (ar_name (file->name))
+ return ar_touch (file->name);
+ else
+ #endif
+ {
+ int fd = open (file->name, O_RDWR | O_CREAT, 0666);
+
+ if (fd < 0)
+ TOUCH_ERROR ("touch: open: ");
+ else
+ {
+ struct stat statbuf;
+ char buf;
+
+ if (fstat (fd, &statbuf) < 0)
+ TOUCH_ERROR ("touch: fstat: ");
+ /* Rewrite character 0 same as it already is. */
+ if (read (fd, &buf, 1) < 0)
+ TOUCH_ERROR ("touch: read: ");
+ if (lseek (fd, 0L, 0) < 0L)
+ TOUCH_ERROR ("touch: lseek: ");
+ if (write (fd, &buf, 1) < 0)
+ TOUCH_ERROR ("touch: write: ");
+ /* If file length was 0, we just
+ changed it, so change it back. */
+ if (statbuf.st_size == 0)
+ {
+ (void) close (fd);
+ fd = open (file->name, O_RDWR | O_TRUNC, 0666);
+ if (fd < 0)
+ TOUCH_ERROR ("touch: open: ");
+ }
+ (void) close (fd);
+ }
+ }
+
+ return 0;
+ }
+
+ /* Having checked and updated the dependencies of FILE,
+ do whatever is appropriate to remake FILE itself.
+ Return the status from executing FILE's commands. */
+
+ static void
+ remake_file (file)
+ struct file *file;
+ {
+ if (file->cmds == 0)
+ {
+ if (file->phony)
+ /* Phony target. Pretend it succeeded. */
+ file->update_status = 0;
+ else if (file->is_target)
+ /* This is a nonexistent target file we cannot make.
+ Pretend it was successfully remade. */
+ file->update_status = 0;
+ else
+ {
+ /* This is a dependency file we cannot remake. Fail. */
+ static char noway[] = "*** No way to make target";
+ if (keep_going_flag || file->dontcare)
+ {
+ if (!file->dontcare)
+ error ("%s `%s'.", noway, file->name);
+ file->update_status = 1;
+ }
+ else
+ fatal ("%s `%s'", noway, file->name);
+ }
+ }
+ else
+ {
+ chop_commands (file->cmds);
+
+ if (touch_flag && !file->cmds->any_recurse)
+ {
+ if (file->phony)
+ file->update_status = 0;
+ else
+ /* Should set file's modification date and do nothing else. */
+ file->update_status = touch_file (file);
+ }
+ else
+ {
+ execute_file_commands (file);
+ return;
+ }
+ }
+
+ notice_finished_file (file);
+ }
+
+ /* Return the mtime of a file, given a `struct file'.
+ Caches the time in the struct file to avoid excess stat calls. If the file
+ is not found, and SEARCH is nonzero, VPATH searching and replacement is
+ done. If that fails, a library (-lLIBNAME) is tried but the library's
+ actual name (/lib/libLIBNAME.a, etc.) is not substituted into FILE. */
+
+ time_t
+ f_mtime (file, search)
+ register struct file *file;
+ int search;
+ {
+ register time_t mtime;
+
+ /* File's mtime is not known; must get it from the system. */
+
+ #ifndef NO_ARCHIVES
+ if (ar_name (file->name))
+ {
+ /* This file is an archive-member reference. */
+
+ char *arname, *memname;
+ struct file *arfile;
+ int arname_used = 0;
+
+ /* Find the archive's name. */
+ ar_parse_name (file->name, &arname, &memname);
+
+ /* Find the modification time of the archive itself.
+ Also allow for its name to be changed via VPATH search. */
+ arfile = lookup_file (arname);
+ if (arfile == 0)
+ {
+ arfile = enter_file (arname);
+ arname_used = 1;
+ }
+ mtime = f_mtime (arfile, search);
+ check_renamed (arfile);
+ if (search && strcmp (arfile->name, arname))
+ {
+ /* The archive's name has changed.
+ Change the archive-member reference accordingly. */
+
+ unsigned int arlen, memlen;
+
+ if (!arname_used)
+ {
+ free (arname);
+ arname_used = 1;
+ }
+
+ arname = arfile->name;
+ arlen = strlen (arname);
+ memlen = strlen (memname);
+
+ free (file->name);
+
+ file->name = (char *) xmalloc (arlen + 1 + memlen + 2);
+ bcopy (arname, file->name, arlen);
+ file->name[arlen] = '(';
+ bcopy (memname, file->name + arlen + 1, memlen);
+ file->name[arlen + 1 + memlen] = ')';
+ file->name[arlen + 1 + memlen + 1] = '\0';
+ }
+
+ if (!arname_used)
+ free (arname);
+ free (memname);
+
+ if (mtime == (time_t) -1)
+ /* The archive doesn't exist, so it's members don't exist either. */
+ return (time_t) -1;
+
+ mtime = ar_member_date (file->name);
+ }
+ else
+ #endif
+ {
+ mtime = name_mtime (file->name);
+
+ if (mtime == (time_t) -1 && search)
+ {
+ /* If name_mtime failed, search VPATH. */
+ char *name = file->name;
+ if (vpath_search (&name))
+ {
+ rename_file (file, name);
+ check_renamed (file);
+ return file_mtime (file);
+ }
+ else
+ /* Last resort, is it a library (-lxxx)? */
+ if (name[0] == '-' && name[1] == 'l')
+ mtime = library_file_mtime (&name[2]);
+ }
+ }
+
+ /* Store the mtime into all the entries for this file. */
+
+ while (file != 0)
+ {
+ file->last_mtime = mtime;
+ file = file->prev;
+ }
+
+ return mtime;
+ }
+
+
+ /* Return the mtime of the file or archive-member reference NAME. */
+
+ static time_t
+ name_mtime (name)
+ register char *name;
+ {
+ struct stat st;
+
+ if (stat (name, &st) < 0)
+ return (time_t) -1;
+
+ return (time_t) st.st_mtime;
+ }
+
+
+ /* Return the mtime of a library file specified as -lLIBNAME,
+ searching for a suitable library file in the system library directories
+ and the VPATH directories. */
+
+ static time_t
+ library_file_mtime (lib)
+ char *lib;
+ {
+ time_t mtime;
+ char *name;
+
+ name = concat ("/usr/lib/lib", lib, ".a");
+ mtime = name_mtime (name);
+ if (mtime == (time_t) -1)
+ mtime = name_mtime (name + 4);
+ if (mtime == (time_t) -1)
+ {
+ char *local = concat ("/usr/local/lib/lib", lib, ".a");
+ mtime = name_mtime (local);
+ free (local);
+ }
+ if (mtime == (time_t) -1)
+ mtime = name_mtime (name + 9);
+ if (mtime == (time_t) -1)
+ {
+ char *newname = name + 9;
+ if (vpath_search (&newname))
+ {
+ mtime = name_mtime (newname);
+ free (newname);
+ }
+ }
+
+ free (name);
+
+ return mtime;
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/remote-stub.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/remote-stub.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/remote-stub.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,91 ----
+ /* 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. */
+
+ #include "make.h"
+ #include "commands.h"
+
+
+ char *remote_description = 0;
+
+
+ /* Return nonzero if the next job should be done remotely. */
+
+ int
+ start_remote_job_p ()
+ {
+ return 0;
+ }
+
+ /* Start a remote job running the command in ARGV.
+ It gets standard input from STDIN_FD. On failure,
+ return nonzero. On success, return zero, and set
+ *USED_STDIN to nonzero if it will actually use STDIN_FD,
+ zero if not, set *ID_PTR to a unique identification, and
+ set *IS_REMOTE to zero if the job is local, nonzero if it
+ is remote (meaning *ID_PTR is a process ID). */
+
+ int
+ start_remote_job (argv, stdin_fd, is_remote, id_ptr, used_stdin)
+ char **argv;
+ int stdin_fd;
+ int *is_remote;
+ int *id_ptr;
+ int *used_stdin;
+ {
+ return -1;
+ }
+
+ /* Get the status of a dead remote child. Block waiting for one to die
+ if BLOCK is nonzero. Set *EXIT_CODE_PTR to the exit status, *SIGNAL_PTR
+ to the termination signal or zero if it exited normally, and *COREDUMP_PTR
+ nonzero if it dumped core. Return the ID of the child that died,
+ 0 if we would have to block and !BLOCK, or < 0 if there were none. */
+
+ int
+ remote_status (exit_code_ptr, signal_ptr, coredump_ptr, block)
+ int *exit_code_ptr, *signal_ptr, *coredump_ptr;
+ int block;
+ {
+ return -1;
+ }
+
+ /* Block asynchronous notification of remote child death.
+ If this notification is done by raising the child termination
+ signal, do not block that signal. */
+ void
+ block_remote_children ()
+ {
+ return;
+ }
+
+ /* Restore asynchronous notification of remote child death.
+ If this is done by raising the child termination signal,
+ do not unblock that signal. */
+ void
+ unblock_remote_children ()
+ {
+ return;
+ }
+
+ /* Send signal SIG to child ID. Return 0 if successful, -1 if not. */
+ int
+ remote_kill (id, sig)
+ int id;
+ int sig;
+ {
+ return -1;
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/remote.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/remote.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/remote.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,5 ----
+ #ifdef CUSTOMS
+ #include "remote-cstms.c"
+ #else /* Not CUSTOMS. */
+ #include "remote-stub.c"
+ #endif /* CUSTOMS. */
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/rule.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/rule.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/rule.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,524 ----
+ /* Pattern and suffix rule internals for GNU Make.
+ Copyright (C) 1988, 1989, 1990, 1991 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 2, 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. */
+
+ #include "make.h"
+ #include "commands.h"
+ #include "dep.h"
+ #include "file.h"
+ #include "variable.h"
+ #include "rule.h"
+
+ static void freerule ();
+ static int new_pattern_rule ();
+
+ /* Chain of all pattern rules. */
+
+ struct rule *pattern_rules;
+
+ /* Pointer to last rule in the chain, so we can add onto the end. */
+
+ struct rule *last_pattern_rule;
+
+ /* Number of rules in the chain. */
+
+ unsigned int num_pattern_rules;
+
+ /* Maximum number of dependencies of any pattern rule. */
+
+ unsigned int max_pattern_deps;
+
+ /* Maximum length of the name of a dependencies of any pattern rule. */
+
+ unsigned int max_pattern_dep_length;
+
+ /* Pointer to structure for the file .SUFFIXES
+ whose dependencies are the suffixes to be searched. */
+
+ struct file *suffix_file;
+
+ /* Maximum length of a suffix. */
+
+ unsigned int maxsuffix;
+
+ /* Compute the maximum dependency length and maximum number of
+ dependencies of all implicit rules. Also sets the subdir
+ flag for a rule when appropriate, possibly removing the rule
+ completely when appropriate. */
+
+ void
+ count_implicit_rule_limits ()
+ {
+ char *name;
+ unsigned int namelen;
+ register struct rule *rule, *lastrule;
+
+ num_pattern_rules = 0;
+
+ name = 0;
+ namelen = 0;
+ rule = lastrule = pattern_rules;
+ while (rule != 0)
+ {
+ unsigned int ndeps = 0;
+ register struct dep *dep;
+
+ ++num_pattern_rules;
+
+ for (dep = rule->deps; dep != 0; dep = dep->next)
+ {
+ unsigned int len = strlen (dep->name);
+ char *p = rindex (dep->name, '/');
+ char *p2 = p != 0 ? index (dep->name, '%') : 0;
+
+ ndeps++;
+
+ if (len > max_pattern_dep_length)
+ max_pattern_dep_length = len;
+
+ if (p != 0 && p2 > p)
+ {
+ if (p == dep->name)
+ ++p;
+ if (p - dep->name > namelen)
+ {
+ if (name != 0)
+ free (name);
+ namelen = p - dep->name;
+ name = (char *) xmalloc (namelen + 1);
+ }
+ bcopy (dep->name, name, p - dep->name);
+ name[p - dep->name] = '\0';
+
+ if (!dir_file_exists_p (name, "."))
+ {
+ if (*name == '/')
+ {
+ freerule (rule, lastrule);
+ rule = lastrule;
+ goto end_main_loop;
+ }
+ else
+ rule->subdir = 1;
+ }
+ }
+ }
+
+ if (ndeps > max_pattern_deps)
+ max_pattern_deps = ndeps;
+
+ end_main_loop:;
+ lastrule = rule;
+ rule = rule->next;
+ }
+
+ if (name != 0)
+ free (name);
+ }
+
+ /* Convert old-style suffix rules to pattern rules.
+ All rules for the suffixes on the .SUFFIXES list
+ are converted and added to the chain of pattern rules. */
+
+ void
+ convert_to_pattern ()
+ {
+ register struct dep *d, *d2, *newd;
+ register struct file *f;
+ register char *rulename;
+ register unsigned int slen, s2len;
+ register char *name, **names;
+
+ /* Compute maximum length of all the suffixes. */
+
+ maxsuffix = 0;
+ for (d = suffix_file->deps; d != 0; d = d->next)
+ {
+ register unsigned int namelen = strlen (dep_name (d));
+ if (namelen > maxsuffix)
+ maxsuffix = namelen;
+ }
+
+ rulename = (char *) alloca ((maxsuffix * 2) + 1);
+
+ for (d = suffix_file->deps; d != 0; d = d->next)
+ {
+ /* Make a rule that is just the suffix, with no deps or commands.
+ This rule exists solely to disqualify match-anything rules. */
+ slen = strlen (dep_name (d));
+ name = (char *) xmalloc (1 + slen + 1);
+ name[0] = '%';
+ bcopy (dep_name (d), name + 1, slen + 1);
+ names = (char **) xmalloc (2 * sizeof (char *));
+ names[0] = name;
+ names[1] = 0;
+ create_pattern_rule (names, (char **) 0, 0, (struct dep *) 0,
+ (struct commands *) 0, 0);
+
+ f = d->file;
+ if (f->cmds != 0)
+ {
+ /* Record a pattern for this suffix's null-suffix rule. */
+ newd = (struct dep *) xmalloc (sizeof (struct dep));
+ /* Construct this again rather than using the contents
+ of NAME (above), since that may have been freed by
+ create_pattern_rule. */
+ newd->name = (char *) xmalloc (1 + slen + 1);
+ newd->name[0] = '%';
+ bcopy (dep_name (d), newd->name + 1, slen + 1);
+ newd->next = 0;
+ names = (char **) xmalloc (2 * sizeof (char *));
+ names[0] = savestring ("%", 1);
+ names[1] = 0;
+ create_pattern_rule (names, (char **) 0, 0, newd, f->cmds, 0);
+ }
+
+ /* Record a pattern for each of this suffix's two-suffix rules. */
+ bcopy (dep_name (d), rulename, slen);
+ for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
+ {
+ s2len = strlen (dep_name (d2));
+
+ if (slen == s2len && streq (dep_name (d), dep_name (d2)))
+ continue;
+
+ bcopy (dep_name (d2), rulename + slen, s2len + 1);
+ f = lookup_file (rulename);
+ if (f == 0 || f->cmds == 0)
+ continue;
+
+ if (s2len == 2 && rulename[slen] == '.' && rulename[slen + 1] == 'a')
+ /* The suffix rule `.X.a:' is converted
+ to the pattern rule `(%.o): %.X'. */
+ name = savestring ("(%.o)", 5);
+ else
+ {
+ /* The suffix rule `.X.Y:' is converted
+ to the pattern rule `%.Y: %.X'. */
+ name = (char *) xmalloc (1 + s2len + 1);
+ name[0] = '%';
+ bcopy (dep_name (d2), name + 1, s2len + 1);
+ }
+ names = (char **) xmalloc (2 * sizeof (char *));
+ names[0] = name;
+ names[1] = 0;
+ newd = (struct dep *) xmalloc (sizeof (struct dep));
+ newd->next = 0;
+ /* Construct this again (see comment above). */
+ newd->name = (char *) xmalloc (1 + slen + 1);
+ newd->name[0] = '%';
+ bcopy (dep_name (d), newd->name + 1, slen + 1);
+ create_pattern_rule (names, (char **) 0, 0, newd, f->cmds, 0);
+ }
+ }
+ }
+
+
+ /* Install the pattern rule RULE (whose fields have been filled in)
+ at the end of the list (so that any rules previously defined
+ will take precedence). If this rule duplicates a previous one
+ (identical target and dependents), the old one is replaced
+ if OVERRIDE is nonzero, otherwise this new one is thrown out.
+ When an old rule is replaced, the new one is put at the end of the
+ list. Return nonzero if RULE is used; zero if not. */
+
+ static int
+ new_pattern_rule (rule, override)
+ register struct rule *rule;
+ int override;
+ {
+ register struct rule *r, *lastrule;
+ register unsigned int i, j;
+
+ rule->subdir = 0;
+ rule->in_use = 0;
+ rule->terminal = 0;
+
+ rule->next = 0;
+
+ /* Search for an identical rule. */
+ lastrule = pattern_rules;
+ for (r = pattern_rules; r != 0; lastrule = r, r = r->next)
+ for (i = 0; rule->targets[i] != 0; ++i)
+ for (j = 0; r->targets[j] != 0; ++j)
+ if (streq (rule->targets[i], r->targets[j]))
+ {
+ register struct dep *d, *d2;
+ for (d = rule->deps, d2 = r->deps;
+ d != 0 && d2 != 0; d = d->next, d2 = d2->next)
+ if (!streq (dep_name (d), dep_name (d2)))
+ break;
+ if (d == 0 && d2 == 0)
+ /* All the dependencies matched. */
+ if (override)
+ {
+ /* Remove the old rule. */
+ freerule (r, lastrule);
+ /* Install the new one. */
+ if (pattern_rules == 0)
+ pattern_rules = rule;
+ else
+ last_pattern_rule->next = rule;
+ last_pattern_rule = rule;
+
+ /* We got one. Stop looking. */
+ goto matched;
+ }
+ else
+ {
+ /* The old rule stays intact. Destroy the new one. */
+ freerule (rule, (struct rule *) 0);
+ return 0;
+ }
+ }
+
+ matched:;
+
+ if (r == 0)
+ {
+ /* There was no rule to replace. */
+ if (pattern_rules == 0)
+ pattern_rules = rule;
+ else
+ last_pattern_rule->next = rule;
+ last_pattern_rule = rule;
+ }
+
+ return 1;
+ }
+
+
+ /* Install an implicit pattern rule based on the three text strings
+ in the structure P points to. These strings come from one of
+ the arrays of default implicit pattern rules.
+ TERMINAL specifies what the `terminal' field of the rule should be. */
+
+ void
+ install_pattern_rule (p, terminal)
+ struct pspec *p;
+ int terminal;
+ {
+ register struct rule *r;
+ char *ptr;
+
+ r = (struct rule *) xmalloc (sizeof (struct rule));
+
+ r->targets = (char **) xmalloc (2 * sizeof (char *));
+ r->suffixes = (char **) xmalloc (2 * sizeof (char *));
+ r->lens = (unsigned int *) xmalloc (2 * sizeof (unsigned int));
+
+ r->targets[1] = 0;
+ r->suffixes[1] = 0;
+ r->lens[1] = 0;
+
+ r->lens[0] = strlen (p->target);
+ /* These will all be string literals, but we malloc space for
+ them anyway because somebody might want to free them later on. */
+ r->targets[0] = savestring (p->target, r->lens[0]);
+ r->suffixes[0] = find_percent (r->targets[0]);
+ if (r->suffixes[0] == 0)
+ /* Programmer-out-to-lunch error. */
+ abort ();
+ else
+ ++r->suffixes[0];
+
+ ptr = p->dep;
+ r->deps = (struct dep *) multi_glob (parse_file_seq (&ptr, '\0',
+ sizeof (struct dep)),
+ sizeof (struct dep));
+
+ if (new_pattern_rule (r, 0))
+ {
+ r->terminal = terminal;
+ r->cmds = (struct commands *) xmalloc (sizeof (struct commands));
+ r->cmds->filename = 0;
+ r->cmds->lineno = 0;
+ /* These will all be string literals, but we malloc space for them
+ anyway because somebody might want to free them later. */
+ r->cmds->commands = savestring (p->commands, strlen (p->commands));
+ r->cmds->command_lines = 0;
+ }
+ }
+
+
+ /* Free all the storage used in RULE and take it out of the
+ pattern_rules chain. LASTRULE is the rule whose next pointer
+ points to RULE. */
+
+ static void
+ freerule (rule, lastrule)
+ register struct rule *rule, *lastrule;
+ {
+ struct rule *next = rule->next;
+ register unsigned int i;
+
+ for (i = 0; rule->targets[i] != 0; ++i)
+ free (rule->targets[i]);
+
+ free ((char *) rule->targets);
+ free ((char *) rule->suffixes);
+ free ((char *) rule->lens);
+
+ /* We can't free the storage for the commands because there
+ are ways that they could be in more than one place:
+ * If the commands came from a suffix rule, they could also be in
+ the `struct file's for other suffix rules or plain targets given
+ on the same makefile line.
+ * If two suffixes that together make a two-suffix rule were each
+ given twice in the .SUFFIXES list, and in the proper order, two
+ identical pattern rules would be created and the second one would
+ be discarded here, but both would contain the same `struct commands'
+ pointer from the `struct file' for the suffix rule. */
+
+ free ((char *) rule);
+
+ if (lastrule == 0)
+ return;
+
+ if (pattern_rules == rule)
+ if (lastrule != pattern_rules)
+ abort ();
+ else
+ pattern_rules = next;
+ else
+ lastrule->next = next;
+ if (last_pattern_rule == rule)
+ last_pattern_rule = lastrule;
+ }
+
+ /* Create a new pattern rule with the targets in the nil-terminated
+ array TARGETS. If TARGET_PERCENTS is not nil, it is an array of
+ pointers into the elements of TARGETS, where the `%'s are.
+ The new rule has dependencies DEPS and commands from COMMANDS.
+ It is a terminal rule if TERMINAL is nonzero. This rule overrides
+ identical rules with different commands if OVERRIDE is nonzero.
+
+ The storage for TARGETS and its elements is used and must not be freed
+ until the rule is destroyed. The storage for TARGET_PERCENTS is not used;
+ it may be freed. */
+
+ void
+ create_pattern_rule (targets, target_percents,
+ terminal, deps, commands, override)
+ char **targets, **target_percents;
+ int terminal;
+ struct dep *deps;
+ struct commands *commands;
+ int override;
+ {
+ register struct rule *r = (struct rule *) xmalloc (sizeof (struct rule));
+ register unsigned int max_targets, i;
+
+ r->cmds = commands;
+ r->deps = deps;
+ r->targets = targets;
+
+ max_targets = 2;
+ r->lens = (unsigned int *) xmalloc (2 * sizeof (unsigned int));
+ r->suffixes = (char **) xmalloc (2 * sizeof (char *));
+ for (i = 0; targets[i] != 0; ++i)
+ {
+ if (i == max_targets - 1)
+ {
+ max_targets += 5;
+ r->lens = (unsigned int *)
+ xrealloc ((char *) r->lens, max_targets * sizeof (unsigned int));
+ r->suffixes = (char **)
+ xrealloc ((char *) r->suffixes, max_targets * sizeof (char *));
+ }
+ r->lens[i] = strlen (targets[i]);
+ r->suffixes[i] = (target_percents == 0 ? find_percent (targets[i])
+ : target_percents[i]) + 1;
+ if (r->suffixes[i] == 0)
+ abort ();
+ }
+
+ if (i < max_targets - 1)
+ {
+ r->lens = (unsigned int *) xrealloc ((char *) r->lens,
+ (i + 1) * sizeof (unsigned int));
+ r->suffixes = (char **) xrealloc ((char *) r->suffixes,
+ (i + 1) * sizeof (char *));
+ }
+
+ if (new_pattern_rule (r, override))
+ r->terminal = terminal;
+ }
+
+ /* Print the data base of rules. */
+
+ void
+ print_rule_data_base ()
+ {
+ register unsigned int rules, terminal, subdir;
+ register struct rule *r;
+ register struct dep *d;
+ register unsigned int i;
+
+ puts ("\n# Implicit Rules");
+
+ rules = terminal = subdir = 0;
+ for (r = pattern_rules; r != 0; r = r->next)
+ {
+ ++rules;
+
+ putchar ('\n');
+ for (i = 0; r->targets[i] != 0; ++i)
+ {
+ fputs (r->targets[i], stdout);
+ if (r->targets[i + 1] != 0)
+ putchar (' ');
+ else
+ putchar (':');
+ }
+ if (r->terminal)
+ {
+ ++terminal;
+ putchar (':');
+ }
+
+ for (d = r->deps; d != 0; d = d->next)
+ printf (" %s", dep_name (d));
+ putchar ('\n');
+
+ if (r->subdir)
+ {
+ ++subdir;
+ puts ("# references nonexistent subdirectory.");
+ }
+
+ if (r->cmds != 0)
+ print_commands (r->cmds);
+ }
+
+ if (rules == 0)
+ puts ("\n# No implicit rules.");
+ else
+ {
+ printf ("\n# %u implicit rules, %u", rules, terminal);
+ #ifndef NO_FLOAT
+ printf (" (%.1f%%)", (double) terminal / (double) rules * 100.0);
+ #endif
+ puts (" terminal.");
+
+ printf ("# %u", subdir);
+ #ifndef NO_FLOAT
+ printf (" (%.1f%%)", (double) subdir / (double) rules * 100.0);
+ #endif
+ puts (" reference nonexistent subdirectories.");
+ }
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/rule.h
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/rule.h:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/rule.h Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,51 ----
+ /* Copyright (C) 1988, 1989, 1991 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 2, 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. */
+
+ /* Structure used for pattern rules. */
+
+ struct rule
+ {
+ struct rule *next;
+ char **targets; /* Targets of the rule. */
+ unsigned int *lens; /* Lengths of each target. */
+ char **suffixes; /* Suffixes (after `%') of each target. */
+ struct dep *deps; /* Dependencies of the rule. */
+ struct commands *cmds; /* Commands to execute. */
+ char terminal; /* If terminal (double-colon). */
+ char subdir; /* If references nonexistent subdirectory. */
+ char in_use; /* If in use by a parent pattern_search. */
+ };
+
+ /* For calling install_pattern_rule. */
+ struct pspec
+ {
+ char *target, *dep, *commands;
+ };
+
+
+ extern struct rule *pattern_rules;
+ extern struct rule *last_pattern_rule;
+ extern unsigned int num_pattern_rules;
+
+ extern unsigned int max_pattern_deps;
+ extern unsigned int max_pattern_dep_length;
+
+ extern struct file *suffix_file;
+ extern unsigned int maxsuffix;
+
+
+ extern void install_pattern_rule ();
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/variable.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/variable.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:22 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/variable.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,768 ----
+ /* Internals of variables for GNU Make.
+ Copyright (C) 1988, 1989, 1990, 1991 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 2, 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. */
+
+ #include "make.h"
+ #include "commands.h"
+ #include "variable.h"
+ #include "dep.h"
+ #include "file.h"
+
+ #ifdef __GNUC__
+ #define max(a, b) \
+ ({ register int __a = (a), __b = (b); __a > __b ? __a : __b; })
+ #else
+ #define max(a, b) ((a) > (b) ? (a) : (b))
+ #endif
+
+
+ /* Hash table of all global variable definitions. */
+
+ #ifndef VARIABLE_BUCKETS
+ #define VARIABLE_BUCKETS 523
+ #endif
+ #ifndef PERFILE_VARIABLE_BUCKETS
+ #define PERFILE_VARIABLE_BUCKETS 23
+ #endif
+ #ifndef SMALL_SCOPE_VARIABLE_BUCKETS
+ #define SMALL_SCOPE_VARIABLE_BUCKETS 13
+ #endif
+ static struct variable *variable_table[VARIABLE_BUCKETS];
+ static struct variable_set global_variable_set
+ = { variable_table, VARIABLE_BUCKETS };
+ static struct variable_set_list global_setlist
+ = { 0, &global_variable_set };
+ struct variable_set_list *current_variable_set_list = &global_setlist;
+
+ /* The next two describe the variable output buffer.
+ This buffer is used to hold the variable-expansion of a line of the
+ makefile. It is made bigger with realloc whenever it is too small.
+ variable_buffer_length is the size currently allocated.
+ variable_buffer is the address of the buffer. */
+
+ static unsigned int variable_buffer_length;
+ static char *variable_buffer;
+
+ /* Implement variables. */
+
+ /* Define variable named NAME with value VALUE in SET. VALUE is copied.
+ LENGTH is the length of NAME, which does not need to be null-terminated.
+ ORIGIN specifies the origin of the variable (makefile, command line
+ or environment).
+ If RECURSIVE is nonzero a flag is set in the variable saying
+ that it should be recursively re-expanded. */
+
+ static struct variable *
+ define_variable_in_set (name, length, value, origin, recursive, set)
+ char *name;
+ unsigned int length;
+ char *value;
+ enum variable_origin origin;
+ int recursive;
+ struct variable_set *set;
+ {
+ register unsigned int i;
+ register unsigned int hashval;
+ register struct variable *v;
+
+ hashval = 0;
+ for (i = 0; i < length; ++i)
+ HASH (hashval, name[i]);
+ hashval %= set->buckets;
+
+ for (v = set->table[hashval]; v != 0; v = v->next)
+ if (*v->name == *name
+ && !strncmp (v->name + 1, name + 1, length - 1)
+ && v->name[length] == '\0')
+ break;
+
+ if (env_overrides && origin == o_env)
+ origin = o_env_override;
+
+ if (v != 0)
+ {
+ if (env_overrides && v->origin == o_env)
+ /* V came from in the environment. Since it was defined
+ before the switches were parsed, it wasn't affected by -e. */
+ v->origin = o_env_override;
+
+ /* A variable of this name is already defined.
+ If the old definition is from a stronger source
+ than this one, don't redefine it. */
+ if ((int) origin >= (int) v->origin)
+ {
+ v->value = savestring (value, strlen (value));
+ v->origin = origin;
+ v->recursive = recursive;
+ }
+ return v;
+ }
+
+ /* Create a new variable definition and add it to the hash table. */
+
+ v = (struct variable *) xmalloc (sizeof (struct variable));
+ v->name = savestring (name, length);
+ v->value = savestring (value, strlen (value));
+ v->origin = origin;
+ v->recursive = recursive;
+ v->expanding = 0;
+ v->next = set->table[hashval];
+ set->table[hashval] = v;
+ return v;
+ }
+
+ /* Define a variable in the current variable set. */
+
+ struct variable *
+ define_variable (name, length, value, origin, recursive)
+ char *name;
+ unsigned int length;
+ char *value;
+ enum variable_origin origin;
+ int recursive;
+ {
+ return define_variable_in_set (name, length, value, origin, recursive,
+ current_variable_set_list->set);
+ }
+
+ /* Define a variable in FILE's variable set. */
+
+ struct variable *
+ define_variable_for_file (name, length, value, origin, recursive, file)
+ char *name;
+ unsigned int length;
+ char *value;
+ enum variable_origin origin;
+ int recursive;
+ struct file *file;
+ {
+ return define_variable_in_set (name, length, value, origin, recursive,
+ file->variables->set);
+ }
+
+ /* Lookup a variable whose name is a string starting at NAME
+ and with LENGTH chars. NAME need not be null-terminated.
+ Returns address of the `struct variable' containing all info
+ on the variable, or nil if no such variable is defined. */
+
+ struct variable *
+ lookup_variable (name, length)
+ char *name;
+ unsigned int length;
+ {
+ register struct variable_set_list *setlist;
+
+ register unsigned int i;
+ register unsigned int rawhash = 0;
+
+ for (i = 0; i < length; ++i)
+ HASH (rawhash, name[i]);
+
+ for (setlist = current_variable_set_list;
+ setlist != 0; setlist = setlist->next)
+ {
+ register struct variable_set *set = setlist->set;
+ register unsigned int hashval = rawhash % set->buckets;
+ register struct variable *v;
+
+ for (v = set->table[hashval]; v != 0; v = v->next)
+ if (*v->name == *name
+ && !strncmp (v->name + 1, name + 1, length - 1)
+ && v->name[length] == 0)
+ return v;
+ }
+
+ return 0;
+ }
+
+ /* Initialize FILE's variable set list. If FILE already has a variable set
+ list, the topmost variable set is left intact, but the the rest of the
+ chain is replaced with FILE->parent's setlist. */
+
+ void
+ initialize_file_variables (file)
+ struct file *file;
+ {
+ register struct variable_set_list *l = file->variables;
+ if (l == 0)
+ {
+ l = (struct variable_set_list *)
+ xmalloc (sizeof (struct variable_set_list));
+ l->set = (struct variable_set *) xmalloc (sizeof (struct variable_set));
+ l->set->buckets = PERFILE_VARIABLE_BUCKETS;
+ l->set->table = (struct variable **)
+ xmalloc (l->set->buckets * sizeof (struct variable *));
+ bzero ((char *) l->set->table,
+ l->set->buckets * sizeof (struct variable *));
+ file->variables = l;
+ }
+
+ if (file->parent == 0)
+ l->next = &global_setlist;
+ else
+ {
+ if (file->parent->variables == 0)
+ initialize_file_variables (file->parent);
+ l->next = file->parent->variables;
+ }
+ }
+
+ /* Pop the top set off the current variable set list,
+ and free all its storage. */
+
+ void
+ pop_variable_scope ()
+ {
+ register struct variable_set_list *setlist = current_variable_set_list;
+ register struct variable_set *set = setlist->set;
+ register unsigned int i;
+
+ current_variable_set_list = setlist->next;
+ free ((char *) setlist);
+
+ for (i = 0; i < set->buckets; ++i)
+ {
+ register struct variable *next = set->table[i];
+ while (next != 0)
+ {
+ register struct variable *v = next;
+ next = v->next;
+
+ free (v->name);
+ free ((char *) v);
+ }
+ }
+ free ((char *) set->table);
+ free ((char *) set);
+ }
+
+ /* Create a new variable set and push it on the current setlist. */
+
+ void
+ push_new_variable_scope ()
+ {
+ register struct variable_set_list *setlist;
+ register struct variable_set *set;
+
+ set = (struct variable_set *) xmalloc (sizeof (struct variable_set));
+ set->buckets = SMALL_SCOPE_VARIABLE_BUCKETS;
+ set->table = (struct variable **)
+ xmalloc (set->buckets * sizeof (struct variable *));
+ bzero ((char *) set->table, set->buckets * sizeof (struct variable *));
+
+ setlist = (struct variable_set_list *)
+ xmalloc (sizeof (struct variable_set_list));
+ setlist->set = set;
+ setlist->next = current_variable_set_list;
+ current_variable_set_list = setlist;
+ }
+
+ /* Merge SET1 into SET0, freeing unused storage in SET1. */
+
+ static void
+ merge_variable_sets (set0, set1)
+ struct variable_set *set0, *set1;
+ {
+ register unsigned int bucket1;
+
+ for (bucket1 = 0; bucket1 < set1->buckets; ++bucket1)
+ {
+ register struct variable *v1 = set1->table[bucket1];
+ while (v1 != 0)
+ {
+ struct variable *next = v1->next;
+ unsigned int bucket0;
+ register struct variable *v0;
+
+ if (set1->buckets >= set0->buckets)
+ bucket0 = bucket1;
+ else
+ {
+ register char *n;
+ bucket0 = 0;
+ for (n = v1->name; *n != '\0'; ++n)
+ HASH (bucket0, *n);
+ }
+ bucket0 %= set0->buckets;
+
+ for (v0 = set0->table[bucket0]; v0 != 0; v0 = v0->next)
+ if (streq (v0->name, v1->name))
+ break;
+
+ if (v0 == 0)
+ {
+ /* There is no variable in SET0 with the same name. */
+ v1->next = set0->table[bucket0];
+ set0->table[bucket0] = v1;
+ }
+ else
+ {
+ /* The same variable exists in both sets.
+ SET0 takes precedence. */
+ free (v1->value);
+ free ((char *) v1);
+ }
+
+ v1 = next;
+ }
+ }
+ }
+
+ /* Merge SETLIST1 into SETLIST0, freeing unused storage in SETLIST1. */
+
+ void
+ merge_variable_set_lists (setlist0, setlist1)
+ struct variable_set_list **setlist0, *setlist1;
+ {
+ register struct variable_set_list *list0 = *setlist0;
+ struct variable_set_list *last0 = 0;
+
+ while (setlist1 != 0 && list0 != 0)
+ {
+ struct variable_set_list *next = setlist1;
+ setlist1 = setlist1->next;
+
+ merge_variable_sets (list0->set, next->set);
+
+ free ((char *) next);
+
+ last0 = list0;
+ list0 = list0->next;
+ }
+
+ if (setlist1 != 0)
+ {
+ if (last0 == 0)
+ *setlist0 = setlist1;
+ else
+ last0->next = setlist1;
+ }
+ }
+
+ /* Define the automatic variables, and record the addresses
+ of their structures so we can change their values quickly. */
+
+ void
+ define_automatic_variables ()
+ {
+ extern char default_shell[];
+ register struct variable *v;
+ char buf[100];
+
+ sprintf (buf, "%u", makelevel);
+ (void) define_variable ("MAKELEVEL", 9, buf, o_env, 0);
+
+ /* This won't override any definition, but it
+ will provide one if there isn't one there. */
+ v = define_variable ("SHELL", 5, default_shell, o_default, 0);
+
+ /* Don't let SHELL come from the environment
+ if MAKELEVEL is 0. Also, SHELL must not be empty. */
+ if (*v->value == '\0' || (v->origin == o_env && makelevel == 0))
+ {
+ v->origin = o_file;
+ v->value = savestring ("/bin/sh", 7);
+ }
+ }
+
+ /* Subroutine of variable_expand and friends:
+ The text to add is LENGTH chars starting at STRING to the variable_buffer.
+ The text is added to the buffer at PTR, and the updated pointer into
+ the buffer is returned as the value. Thus, the value returned by
+ each call to variable_buffer_output should be the first argument to
+ the following call. */
+
+ char *
+ variable_buffer_output (ptr, string, length)
+ char *ptr, *string;
+ unsigned int length;
+ {
+ register unsigned int newlen = length + (ptr - variable_buffer);
+
+ if (newlen > variable_buffer_length)
+ {
+ unsigned int offset = ptr - variable_buffer;
+ variable_buffer_length = max (2 * variable_buffer_length, newlen + 100);
+ variable_buffer = (char *) xrealloc (variable_buffer,
+ variable_buffer_length);
+ ptr = variable_buffer + offset;
+ }
+
+ bcopy (string, ptr, length);
+ return ptr + length;
+ }
+
+ /* Return a pointer to the beginning of the variable buffer. */
+
+ char *
+ initialize_variable_output ()
+ {
+ /* If we don't have a variable output buffer yet, get one. */
+
+ if (variable_buffer == 0)
+ {
+ variable_buffer_length = 200;
+ variable_buffer = (char *) xmalloc (variable_buffer_length);
+ }
+
+ return variable_buffer;
+ }
+
+ /* Create a new environment for FILE's commands.
+ The child's MAKELEVEL variable is incremented. */
+
+ char **
+ target_environment (file)
+ struct file *file;
+ {
+ register struct variable_set_list *s;
+ struct variable_bucket
+ {
+ struct variable_bucket *next;
+ struct variable *variable;
+ };
+ struct variable_bucket **table;
+ unsigned int buckets;
+ register unsigned int i;
+ register unsigned nvariables;
+ char **result;
+
+ int noexport = enter_file (".NOEXPORT")->is_target;
+
+ /* Find the lowest number of buckets in any set in the list. */
+ s = file->variables;
+ buckets = s->set->buckets;
+ for (s = s->next; s != 0; s = s->next)
+ if (s->set->buckets < buckets)
+ buckets = s->set->buckets;
+
+ /* Temporarily allocate a table with that many buckets. */
+ table = (struct variable_bucket **)
+ alloca (buckets * sizeof (struct variable_bucket *));
+ bzero ((char *) table, buckets * sizeof (struct variable_bucket *));
+
+ /* Run through all the variable sets in the list,
+ accumulating variables in TABLE. */
+ nvariables = 0;
+ for (s = file->variables; s != 0; s = s->next)
+ {
+ register struct variable_set *set = s->set;
+ for (i = 0; i < set->buckets; ++i)
+ {
+ register struct variable *v;
+ for (v = set->table[i]; v != 0; v = v->next)
+ {
+ extern char *getenv ();
+ unsigned int j = i % buckets;
+ register struct variable_bucket *ov;
+ register char *p = v->name;
+
+ /* If `.NOEXPORT' was specified, only export command-line and
+ environment variables. This is a temporary (very ugly) hack
+ until I fix this problem the right way in version 4. Ick. */
+ if (noexport
+ && (v->origin != o_command
+ && v->origin != o_env && v->origin != o_env_override
+ && !(v->origin == o_file && getenv (p) != 0)))
+ continue;
+
+ if (v->origin == o_default
+ || streq (p, "MAKELEVEL"))
+ continue;
+
+ if (*p != '_' && (*p < 'A' || *p > 'Z')
+ && (*p < 'a' || *p > 'z'))
+ continue;
+ for (++p; *p != '\0'; ++p)
+ if (*p != '_' && (*p < 'a' || *p > 'z')
+ && (*p < 'A' || *p > 'Z') && (*p < '0' || *p > '9'))
+ break;
+ if (*p != '\0')
+ continue;
+
+ for (ov = table[j]; ov != 0; ov = ov->next)
+ if (streq (v->name, ov->variable->name))
+ break;
+ if (ov == 0)
+ {
+ register struct variable_bucket *entry;
+ entry = (struct variable_bucket *)
+ alloca (sizeof (struct variable_bucket));
+ entry->next = table[j];
+ entry->variable = v;
+ table[j] = entry;
+ ++nvariables;
+ }
+ }
+ }
+ }
+
+ result = (char **) xmalloc ((nvariables + 2) * sizeof (char *));
+ nvariables = 0;
+ for (i = 0; i < buckets; ++i)
+ {
+ register struct variable_bucket *b;
+ for (b = table[i]; b != 0; b = b->next)
+ {
+ register struct variable *v = b->variable;
+ result[nvariables++] = concat (v->name, "=", v->value);
+ }
+ }
+ result[nvariables] = (char *) xmalloc (100);
+ (void) sprintf (result[nvariables], "MAKELEVEL=%u", makelevel + 1);
+ result[++nvariables] = 0;
+
+ return result;
+ }
+
+ /* Try to interpret LINE (a null-terminated string)
+ as a variable definition. If it is one, define the
+ variable and return 1. Otherwise return 0.
+
+ ORIGIN may be o_file, o_override, o_env, o_env_override,
+ or o_command specifying that the variable definition comes
+ from a makefile, an override directive, the environment with
+ or without the -e switch, or the command line.
+
+ A variable definition has the form "name = value" or "name := value".
+ Any whitespace around the "=" or ":=" is removed. The first form
+ defines a variable that is recursively re-evaluated. The second form
+ defines a variable whose value is variable-expanded at the time of
+ definition and then is evaluated only once at the time of expansion. */
+
+ int
+ try_variable_definition (line, origin)
+ char *line;
+ enum variable_origin origin;
+ {
+ register int c;
+ register char *p = line;
+ register char *beg;
+ register char *end;
+ register int recursive;
+
+ if (*p == '\t')
+ return 0;
+ while (1)
+ {
+ c = *p++;
+ if (c == '\0' || c == '#')
+ return 0;
+ if (c == '=')
+ {
+ recursive = 1;
+ break;
+ }
+ else if (c == ':')
+ if (*p == '=')
+ {
+ ++p;
+ recursive = 0;
+ break;
+ }
+ else
+ return 0;
+ }
+
+ beg = next_token (line);
+ end = p - 1;
+ if (!recursive)
+ --end;
+ while (isblank (end[-1]))
+ --end;
+ p = next_token (p);
+
+ (void) define_variable (beg, end - beg, recursive ? p : variable_expand (p),
+ origin, recursive);
+
+ return 1;
+ }
+
+ /* Print information for variable V, prefixing it with PREFIX. */
+
+ static void
+ print_variable (v, prefix)
+ register struct variable *v;
+ char *prefix;
+ {
+ char *origin;
+
+ switch (v->origin)
+ {
+ case o_default:
+ origin = "default";
+ break;
+ case o_env:
+ origin = "environment";
+ break;
+ case o_file:
+ origin = "makefile";
+ break;
+ case o_env_override:
+ origin = "environment under -e";
+ break;
+ case o_command:
+ origin = "command line";
+ break;
+ case o_override:
+ origin = "`override' directive";
+ break;
+ case o_automatic:
+ origin = "automatic";
+ break;
+ case o_invalid:
+ default:
+ abort ();
+ break;
+ }
+ printf ("# %s\n", origin);
+
+ fputs (prefix, stdout);
+
+ /* Is this a `define'? */
+ if (v->recursive && index (v->value, '\n') != 0)
+ printf ("define %s\n%s\nendef\n", v->name, v->value);
+ else
+ {
+ register char *p;
+
+ printf ("%s %s= ", v->name, v->recursive ? "" : ":");
+
+ /* Check if the value is just whitespace. */
+ p = next_token (v->value);
+ if (p != v->value && *p == '\0')
+ /* All whitespace. */
+ printf ("$(subst ,,%s)", v->value);
+ else if (v->recursive)
+ fputs (v->value, stdout);
+ else
+ /* Double up dollar signs. */
+ for (p = v->value; *p != '\0'; ++p)
+ {
+ if (*p == '$')
+ putchar ('$');
+ putchar (*p);
+ }
+ putchar ('\n');
+ }
+ }
+
+
+ /* Print all the variables in SET. PREFIX is printed before
+ the actual variable definitions (everything else is comments). */
+
+ static void
+ print_variable_set (set, prefix)
+ register struct variable_set *set;
+ char *prefix;
+ {
+ register unsigned int i, nvariables, per_bucket;
+ register struct variable *v;
+
+ per_bucket = nvariables = 0;
+ for (i = 0; i < set->buckets; ++i)
+ {
+ register unsigned int this_bucket = 0;
+
+ for (v = set->table[i]; v != 0; v = v->next)
+ {
+ ++this_bucket;
+ print_variable (v, prefix);
+ }
+
+ nvariables += this_bucket;
+ if (this_bucket > per_bucket)
+ per_bucket = this_bucket;
+ }
+
+ if (nvariables == 0)
+ puts ("# No variables.");
+ else
+ {
+ printf ("# %u variables in %u hash buckets.\n",
+ nvariables, set->buckets);
+ #ifndef NO_FLOAT
+ printf ("# average of %.1f variables per bucket, \
+ max %u in one bucket.\n",
+ ((double) nvariables) * 100.0 / (double) set->buckets,
+ per_bucket);
+ #endif
+ }
+ }
+
+
+ /* Print the data base of variables. */
+
+ void
+ print_variable_data_base ()
+ {
+ puts ("\n# Variables\n");
+
+ print_variable_set (&global_variable_set, "");
+ }
+
+
+ /* Print all the local variables of FILE. */
+
+ void
+ print_file_variables (file)
+ struct file *file;
+ {
+ if (file->variables != 0)
+ print_variable_set (file->variables->set, "# ");
+ }
+
+ struct output_state
+ {
+ char *buffer;
+ unsigned int length;
+ };
+
+ /* Save the current variable output state and return a pointer
+ to storage describing it. Then reset the output state. */
+
+ char *
+ save_variable_output ()
+ {
+ struct output_state *state;
+
+ state = (struct output_state *) xmalloc (sizeof (struct output_state));
+ state->buffer = variable_buffer;
+ state->length = variable_buffer_length;
+
+ variable_buffer = 0;
+ variable_buffer_length = 0;
+
+ return (char *) state;
+ }
+
+ /* Restore the variable output state saved in SAVE. */
+
+ void
+ restore_variable_output (save)
+ char *save;
+ {
+ register struct output_state *state = (struct output_state *) save;
+
+ if (variable_buffer != 0)
+ free (variable_buffer);
+
+ variable_buffer = state->buffer;
+ variable_buffer_length = state->length;
+
+ free ((char *) state);
+ }
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/variable.h
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/variable.h:1.1.2.1
*** /dev/null Mon Mar 1 17:59:23 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/variable.h Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,94 ----
+ /* Copyright (C) 1988, 1989, 1990, 1991 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 2, 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. */
+
+ /* Codes in a variable definition saying where the definition came from.
+ Increasing numeric values signify less-overridable definitions. */
+ enum variable_origin
+ {
+ o_default, /* Variable from the default set. */
+ o_env, /* Variable from environment. */
+ o_file, /* Variable given in a makefile. */
+ o_env_override, /* Variable from environment, if -e. */
+ o_command, /* Variable given by user. */
+ o_override, /* Variable from an `override' directive. */
+ o_automatic, /* Automatic variable -- cannot be set. */
+ o_invalid /* Core dump time. */
+ };
+
+ /* Structure that represents one variable definition.
+ Each bucket of the hash table is a chain of these,
+ chained through `next'. */
+
+ struct variable
+ {
+ struct variable *next; /* Link in the chain. */
+ char *name; /* Variable name. */
+ char *value; /* Variable value. */
+ enum variable_origin
+ origin ENUM_BITFIELD (3); /* Variable origin. */
+ unsigned int recursive:1; /* Gets recursively re-evaluated. */
+ unsigned int expanding:1; /* Nonzero if currently being expanded. */
+ };
+
+ /* Structure that represents a variable set. */
+
+ struct variable_set
+ {
+ struct variable **table; /* Hash table of variables. */
+ unsigned int buckets; /* Number of hash buckets in `table'. */
+ };
+
+ /* Structure that represents a list of variable sets. */
+
+ struct variable_set_list
+ {
+ struct variable_set_list *next; /* Link in the chain. */
+ struct variable_set *set; /* Variable set. */
+ };
+
+ extern struct variable_set_list *current_variable_set_list;
+
+
+ extern char *variable_buffer_output ();
+ extern char *initialize_variable_output ();
+ extern char *save_variable_output ();
+ extern void restore_variable_output ();
+
+ extern void push_new_variable_scope (), pop_variable_scope ();
+
+ extern int handle_function ();
+
+ extern char *variable_expand (), *allocated_variable_expand ();
+ extern char *variable_expand_for_file ();
+ extern char *allocated_variable_expand_for_file ();
+ extern char *expand_argument ();
+
+ extern void define_automatic_variables ();
+ extern void initialize_file_variables ();
+ extern void print_file_variables ();
+
+ extern void merge_variable_set_lists ();
+
+ extern int try_variable_definition ();
+
+ extern struct variable *lookup_variable (), *define_variable ();
+ extern struct variable *define_variable_for_file ();
+
+ extern int pattern_matches ();
+ extern char *subst_expand (), *patsubst_expand ();
+
+ extern char **target_environment ();
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/version.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/version.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:23 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/version.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,7 ----
+ char *version_string = "3.62";
+
+ /*
+ Local variables:
+ version-control: never
+ End:
+ */
Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/vpath.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/vpath.c:1.1.2.1
*** /dev/null Mon Mar 1 17:59:23 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/vpath.c Mon Mar 1 17:59:12 2004
***************
*** 0 ****
--- 1,417 ----
+ /* Copyright (C) 1988, 1989, 1991 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 2, 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. */
+
+ #include "make.h"
+ #include "file.h"
+ #include "variable.h"
+
+
+ /* Structure used to represent a selective VPATH searchpath. */
+
+ struct vpath
+ {
+ struct vpath *next; /* Pointer to next struct in the linked list. */
+ char *pattern; /* The pattern to match. */
+ char *percent; /* Pointer into `pattern' where the `%' is. */
+ unsigned int patlen;/* Length of the pattern. */
+ char **searchpath; /* Null-terminated list of directories. */
+ unsigned int maxlen;/* Maximum length of any entry in the list. */
+ };
+
+ /* Linked-list of all selective VPATHs. */
+
+ static struct vpath *vpaths;
+
+ /* Structure for the general VPATH given in the variable. */
+
+ static struct vpath *general_vpath;
+
+ static int selective_vpath_search ();
+
+ /* Reverse the chain of selective VPATH lists so they
+ will be searched in the order given in the makefiles
+ and construct the list from the VPATH variable. */
+
+ void
+ build_vpath_lists ()
+ {
+ register struct vpath *new = 0;
+ register struct vpath *old, *nexto;
+ register char *p;
+
+ /* Reverse the chain. */
+ for (old = vpaths; old != 0; old = nexto)
+ {
+ nexto = old->next;
+ old->next = new;
+ new = old;
+ }
+
+ vpaths = new;
+
+ /* If there is a VPATH variable with a nonnull value, construct the
+ general VPATH list from it. We use variable_expand rather than just
+ calling lookup_variable so that it will be recursively expanded. */
+ p = variable_expand ("$(VPATH)");
+ if (*p != '\0')
+ {
+ construct_vpath_list ("%", p);
+ /* VPATHS will be nil if there have been no previous `vpath'
+ directives and none of the given directories exists. */
+ if (vpaths == 0)
+ general_vpath = 0;
+ else
+ {
+ general_vpath = vpaths;
+ /* It was just put into the linked list,
+ but we don't want it there, so we must remove it. */
+ vpaths = general_vpath->next;
+ }
+ }
+ }
+
+ /* Construct the VPATH listing for the pattern and searchpath given.
+
+ This function is called to generate selective VPATH lists and also for
+ the general VPATH list (which is in fact just a selective VPATH that
+ is applied to everything). The returned pointer is either put in the
+ linked list of all selective VPATH lists or in the GENERAL_VPATH
+ variable.
+
+ If SEARCHPATH is nil, remove all previous listings with the same
+ pattern. If PATTERN is nil, remove all VPATH listings.
+ Existing and readable directories that are not "." given in the
+ searchpath separated by colons are loaded into the directory hash
+ table if they are not there already and put in the VPATH searchpath
+ for the given pattern with trailing slashes stripped off if present
+ (and if the directory is not the root, "/").
+ The length of the longest entry in the list is put in the structure as well.
+ The new entry will be at the head of the VPATHS chain. */
+
+ void
+ construct_vpath_list (pattern, dirpath)
+ char *pattern, *dirpath;
+ {
+ register unsigned int elem;
+ register char *p;
+ register char **vpath;
+ register unsigned int maxvpath;
+ unsigned int maxelem;
+ char *percent;
+
+ if (pattern != 0)
+ {
+ pattern = savestring (pattern, strlen (pattern));
+ percent = find_percent (pattern);
+ }
+
+ if (dirpath == 0)
+ {
+ /* Remove matching listings. */
+ register struct vpath *path, *lastpath;
+
+ lastpath = vpaths;
+ for (path = vpaths; path != 0; lastpath = path, path = path->next)
+ if (pattern == 0
+ || (((percent == 0 && path->percent == 0)
+ || (percent - pattern == path->percent - path->pattern))
+ && streq (pattern, path->pattern)))
+ {
+ /* Remove it from the linked list. */
+ if (lastpath == vpaths)
+ vpaths = path->next;
+ else
+ lastpath->next = path->next;
+
+ /* Free its unused storage. */
+ free (path->pattern);
+ free ((char *) path->searchpath);
+ free ((char *) path);
+ }
+ if (pattern != 0)
+ free (pattern);
+ return;
+ }
+
+ /* Skip over any initial colons. */
+ p = dirpath;
+ while (*p == ':')
+ ++p;
+
+ /* Figure out the maximum number of VPATH entries and
+ put it in MAXELEM. We start with 2, one before the
+ first colon and one nil, the list terminator and
+ increment our estimated number for each colon we find. */
+ maxelem = 2;
+ while (*p != '\0')
+ if (*p++ == ':')
+ ++maxelem;
+
+ vpath = (char **) xmalloc (maxelem * sizeof (char *));
+ maxvpath = 0;
+
+ elem = 0;
+ p = dirpath;
+ while (*p != '\0')
+ {
+ char *v;
+ unsigned int len;
+
+ /* Find the next entry. */
+ while (*p != '\0' && *p == ':')
+ ++p;
+ if (*p == '\0')
+ break;
+
+ /* Find the end of this entry. */
+ v = p;
+ while (*p != '\0' && *p != ':')
+ ++p;
+
+ len = p - v;
+ /* Make sure there's no trailing slash,
+ but still allow "/" as a directory. */
+ if (len > 1 && p[-1] == '/')
+ --len;
+
+ if (len == 1 && *v == '.')
+ continue;
+
+ v = savestring (v, len);
+ if (dir_file_exists_p (v, ""))
+ {
+ vpath[elem++] = dir_name (v);
+ free (v);
+ if (len > maxvpath)
+ maxvpath = len;
+ }
+ else
+ free (v);
+ }
+
+ if (elem > 0)
+ {
+ struct vpath *path;
+ /* ELEM is now incremented one element past the last
+ entry, to where the nil-pointer terminator goes.
+ Usually this is maxelem - 1. If not, shrink down. */
+ if (elem < (maxelem - 1))
+ vpath = (char **) xrealloc ((char *) vpath,
+ (elem + 1) * sizeof (char *));
+
+ /* Put the nil-pointer terminator on the end of the VPATH list. */
+ vpath[elem] = 0;
+
+ /* Construct the vpath structure and put it into the linked list. */
+ path = (struct vpath *) xmalloc (sizeof (struct vpath));
+ path->searchpath = vpath;
+ path->maxlen = maxvpath;
+ path->next = vpaths;
+ vpaths = path;
+
+ /* Set up the members. */
+ path->pattern = pattern;
+ path->percent = percent;
+ path->patlen = strlen (pattern);
+ }
+ else
+ /* There were no entries, so free whatever space we allocated. */
+ free ((char *) vpath);
+ }
+
+ /* Search the VPATH list whose pattern matches *FILE for a directory
+ where the name pointed to by FILE exists. If it is found, the pointer
+ in FILE is set to the newly malloc'd name of the existing file and
+ we return 1. Otherwise we return 0. */
+
+ int
+ vpath_search (file)
+ char **file;
+ {
+ register struct vpath *v;
+
+ /* If there are no VPATH entries or FILENAME starts at the root,
+ there is nothing we can do. */
+
+ if (**file == '/' || (vpaths == 0 && general_vpath == 0))
+ return 0;
+
+ for (v = vpaths; v != 0; v = v->next)
+ if (pattern_matches (v->pattern, v->percent, *file))
+ if (selective_vpath_search (v, file))
+ return 1;
+
+ if (general_vpath != 0
+ && selective_vpath_search (general_vpath, file))
+ return 1;
+
+ return 0;
+ }
+
+
+ /* Search the given VPATH list for a directory where the name pointed
+ to by FILE exists. If it is found, the pointer in FILE
+ is set to the newly malloc'd name of the existing file and we return 1.
+ Otherwise we return 0. */
+
+ static int
+ selective_vpath_search (path, file)
+ struct vpath *path;
+ char **file;
+ {
+ int not_target;
+ char *name, *n;
+ char *filename;
+ register char **vpath = path->searchpath;
+ unsigned int maxvpath = path->maxlen;
+ register unsigned int i;
+ unsigned int flen, vlen, name_dplen;
+ int exists = 0;
+
+ /* Find out if *FILE is a target.
+ If and only if it is NOT a target, we will accept prospective
+ files that don't exist but are mentioned in a makefile. */
+ {
+ struct file *f = lookup_file (*file);
+ not_target = f == 0 || !f->is_target;
+ }
+
+ flen = strlen (*file);
+
+ /* Split *FILE into a directory prefix and a name-within-directory.
+ NAME_DPLEN gets the length of the prefix; FILENAME gets the
+ pointer to the name-within-directory and FLEN is its length. */
+
+ n = rindex (*file, '/');
+ name_dplen = n != 0 ? n - *file : 0;
+ filename = name_dplen > 0 ? n + 1 : *file;
+ if (name_dplen > 0)
+ flen -= name_dplen + 1;
+
+ /* Allocate enough space for the biggest VPATH entry,
+ a slash, the directory prefix that came with *FILE,
+ another slash (although this one may not always be
+ necessary), the filename, and a null terminator. */
+ name = (char *) alloca (maxvpath + 1 + name_dplen + 1 + flen + 1);
+
+ /* Try each VPATH entry. */
+ for (i = 0; vpath[i] != 0; ++i)
+ {
+ n = name;
+
+ /* Put the next VPATH entry into NAME at N and increment N past it. */
+ vlen = strlen (vpath[i]);
+ bcopy (vpath[i], n, vlen);
+ n += vlen;
+
+ /* Add the directory prefix already in *FILE. */
+ if (name_dplen > 0)
+ {
+ *n++ = '/';
+ bcopy (*file, n, name_dplen);
+ n += name_dplen;
+ }
+
+ /* Now add the name-within-directory at the end of NAME. */
+ if (n != name && n[-1] != '/')
+ *n = '/';
+ bcopy (filename, n + 1, flen + 1);
+
+ if (not_target)
+ /* Since *FILE is not a target, if the file is
+ mentioned in a makefile, we consider it existent. */
+ exists = lookup_file (name) != 0;
+
+ if (!exists)
+ {
+ /* That file wasn't mentioned in the makefile.
+ See if it actually exists. */
+
+ /* Clobber a null into the name at the last slash.
+ Now NAME is the name of the directory to look in. */
+ *n = '\0';
+
+ /* Make sure the directory exists and we know its contents. */
+ if (name_dplen > 0 && !dir_file_exists_p (name, ""))
+ /* It doesn't exist. */
+ continue;
+
+ /* We know the directory is in the hash table now because either
+ construct_vpath_list or the code just above put it there.
+ Does the file we seek exist in it? */
+ exists = dir_file_exists_p (name, filename);
+ }
+
+ if (exists)
+ {
+ /* We have found a file.
+ Store the name we found into *FILE for the caller. */
+
+ /* Put the slash back in NAME. */
+ *n = '/';
+
+ *file = savestring (name, (n + 1 - name) + flen);
+
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+ /* Print the data base of VPATH search paths. */
+
+ void
+ print_vpath_data_base ()
+ {
+ register unsigned int nvpaths;
+ register struct vpath *v;
+
+ puts ("\n# VPATH Search Paths\n");
+
+ nvpaths = 0;
+ for (v = vpaths; v != 0; v = v->next)
+ {
+ register unsigned int i;
+
+ ++nvpaths;
+
+ printf ("vpath %s ", v->pattern);
+
+ for (i = 0; v->searchpath[i] != 0; ++i)
+ printf ("%s%c", v->searchpath[i],
+ v->searchpath[i + 1] == 0 ? '\n' : ':');
+ }
+
+ if (vpaths == 0)
+ puts ("# No `vpath' search paths.");
+ else
+ printf ("\n# %u `vpath' search paths.\n", nvpaths);
+
+ if (general_vpath == 0)
+ puts ("\n# No general (`VPATH' variable) search path.");
+ else
+ {
+ register char **path = general_vpath->searchpath;
+ register unsigned int i;
+
+ fputs ("\n# General (`VPATH' variable) search path:\n# ", stdout);
+
+ for (i = 0; path[i] != 0; ++i)
+ printf ("%s%c", path[i], path[i + 1] == 0 ? '\n' : ':');
+ }
+ }
More information about the llvm-commits
mailing list