From 2c64fb221a265f9e7fc93374906b1e7540377561 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Sat, 3 Oct 1998 05:39:55 +0000 Subject: [PATCH] Checkpoint changes. Bug fixes, mostly. --- ChangeLog | 234 +++- GNUmakefile | 20 +- acconfig.h | 8 + acinclude.m4 | 81 +- amiga.c | 2 +- ar.c | 25 +- arscan.c | 6 +- commands.c | 17 +- commands.h | 3 +- config.ami.template | 188 ++-- config.h-vms.template | 105 +- config.h.W32.template | 149 +-- configure.in | 35 +- default.c | 2 +- dep.h | 22 +- expand.c | 40 +- file.c | 85 +- filedef.h | 77 +- function.c | 73 +- getloadavg.c | 2 +- glob/ChangeLog | 5 + implicit.c | 11 +- job.c | 302 ++--- job.h | 2 +- main.c | 92 +- make.h | 494 +++++---- make.texinfo | 11 +- misc.c | 163 ++- read.c | 219 ++-- remake.c | 97 +- remote-cstms.c | 8 +- rule.c | 6 +- rule.h | 7 + variable.c | 7 +- variable.h | 2 +- vpath.c | 10 +- w32/subproc/NMakefile | 120 +- w32/subproc/sub_proc.c | 2376 ++++++++++++++++++++-------------------- 38 files changed, 2840 insertions(+), 2266 deletions(-) diff --git a/ChangeLog b/ChangeLog index c3ffc61f..bf590806 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,225 @@ +1998-09-21 Paul D. Smith + + * job.c (construct_command_argv_internal): Only add COMMAND.COM + "@echo off" line for non-UNIXy shells. + +1998-09-09 Paul D. Smith + + * w32/subproc/sub_proc.c: Add in missing HAVE_MKS_SHELL tests. + +1998-09-04 Paul D. Smith + + * read.c (read_makefile): If we hit the "missing separator" error, + check for the common case of 8 spaces instead of a TAB and give an + extra comment to help people out. + +1998-08-29 Paul Eggert + + * configure.in (AC_STRUCT_ST_MTIM_NSEC): + Renamed from AC_STRUCT_ST_MTIM. + + * acinclude.m4 (AC_STRUCT_ST_MTIM_NSEC): Likewise. + Port to UnixWare 2.1.2 and pedantic Solaris 2.6. + + * acconfig.h (ST_MTIM_NSEC): + Renamed from HAVE_ST_MTIM, with a new meaning. + + * filedef.h (FILE_TIMESTAMP_FROM_S_AND_NS): + Use new ST_MTIM_NSEC macro. + +1998-08-26 Paul D. Smith + + * remake.c (check_dep): For any intermediate file, not just + secondary ones, try implicit and default rules if no explicit + rules are given. I'm not sure why this was restricted to + secondary rules in the first place. + +1998-08-24 Paul D. Smith + + * make.texinfo (Special Targets): Update documentation for + .INTERMEDIATE: if used with no dependencies, then it does nothing; + old docs said it marked all targets as intermediate, which it + didn't... and which would be silly :). + + * implicit.c (pattern_search): If we find a dependency in our + internal tables, make sure it's not marked intermediate before + accepting it as a found_file[]. + +1998-08-20 Paul D. Smith + + * ar.c (ar_glob): Use existing alpha_compare() with qsort. + (ar_glob_alphacompare): Remove it. + + Modify Paul Eggert's patch so we don't abandon older systems: + + * configure.in: Warn the user if neither waitpid() nor wait3() is + available. + + * job.c (WAIT_NOHANG): Don't syntax error on ancient hosts. + (child_handler, dead_children): Define these if WAIT_NOHANG is not + available. + (reap_children): Only track the dead_children count if no + WAIT_NOHANG. Otherwise, it's a boolean. + + * main.c (main): Add back signal handler if no WAIT_NOHANG is + available; only use default signal handler if it is. + +1998-08-20 Paul Eggert + + Install a more robust signal handling mechanism for systems which + support it. + + * job.c (WAIT_NOHANG): Define to a syntax error if our host + is truly ancient; this should never happen. + (child_handler, dead_children): Remove. + (reap_children): Don't try to keep separate track of how many + dead children we have, as this is too bug-prone. + Just ask the OS instead. + (vmsHandleChildTerm): Fix typo in error message; don't mention + child_handler. + + * main.c (main): Make sure we're not ignoring SIGCHLD/SIGCLD; + do this early, before we could possibly create a subprocess. + Just use the default behavior; don't have our own handler. + +1998-08-18 Eli Zaretskii + + * read.c (read_makefile) [__MSDOS__, WINDOWS32]: Add code to + recognize library archive members when dealing with drive spec + mess. Discovery and initial fix by George Racz . + +1998-08-18 Paul D. Smith + + * configure.in: Check for stdlib.h explicitly (some hosts have it + but don't have STDC_HEADERS). + * make.h: Use HAVE_STDLIB_H. Clean up some #defines. + * config.ami: Re-compute based on new config.h.in contents. + * config.h-vms: Ditto. + * config.h.W32: Ditto. + * configh.dos: Ditto. + +1998-08-17 Paul D. Smith + + * make.texinfo: Added copyright year to the printed copy. Removed + the price from the manual. Change the top-level reference to + running make to be "Invoking make" instead of "make Invocation", + to comply with GNU doc standards. + + * make.h (__format__, __printf__): Added support for these in + __attribute__ macro. + (message, error, fatal): Use ... prototype form under __STDC__. + Add __format__ attributes for printf-style functions. + + * configure.in (AC_FUNC_VPRINTF): Check for vprintf()/_doprnt(). + + * misc.c(message, error, fatal): Add preprocessor stuff to enable + creation of variable-argument functions with appropriate + prototypes, that works with ANSI, pre-ANSI, varargs.h, stdarg.h, + v*printf(), _doprnt(), or none of the above. Culled from GNU + fileutils and slightly modified. + (makefile_error, makefile_error): Removed (merged into error() and + fatal(), respectively). + * amiga.c: Use them. + * ar.c: Use them. + * arscan.c: Use them. + * commands.c: Use them. + * expand.c: Use them. + * file.c: Use them. + * function.c: Use them. + * job.c: Use them. + * main.c: Use them. + * misc.c: Use them. + * read.c: Use them. + * remake.c: Use them. + * remote-cstms.c: Use them. + * rule.c: Use them. + * variable.c: Use them. + + * make.h (struct floc): New structure to store file location + information. + * commands.h (struct commands): Use it. + * variable.c (try_variable_definition): Use it. + * commands.c: Use it. + * default.c: Use it. + * file.c: Use it. + * function.c: Use it. + * misc.c: Use it. + * read.c: Use it. + * rule.c: Use it. + +1998-08-16 Paul Eggert + + * filedef.h (FILE_TIMESTAMP_PRINT_LEN_BOUND): Add 10, for nanoseconds. + +1998-08-16 Paul Eggert + + * filedef.h (FLOOR_LOG2_SECONDS_PER_YEAR): New macro. + (FILE_TIMESTAMP_PRINT_LEN_BOUND): Tighten bound, and try to + make it easier to understand. + +1998-08-14 Paul D. Smith + + * read.c (read_makefile): We've already unquoted any colon chars + by the time we're done reading the targets, so arrange for + parse_file_seq() on the target list to not do so again. + +1998-08-05 Paul D. Smith + + * configure.in: Added glob/configure.in data. We'll have the glob + code include the regular make config.h, rather than creating its + own. + + * getloadavg.c (main): Change return type to int. + +1998-08-01 Paul Eggert + + * job.c (reap_children): Ignore unknown children. + +1998-07-31 Paul D. Smith + + * make.h, filedef.h, dep.h, rule.h, commands.h, remake.c: + Add prototypes for functions. Some prototypes needed to be moved + in order to get #include order reasonable. + +1998-07-30 Paul D. Smith + + * make.h: Added MIN/MAX. + * filedef.h: Use them; remove FILE_TIMESTAMP_MIN. + +1998-07-30 Paul Eggert + + Add support for sub-second timestamp resolution on hosts that + support it (just Solaris 2.6, so far). + + * acconfig.h (HAVE_ST_MTIM, uintmax_t): New undefs. + * acinclude.m4 (jm_AC_HEADER_INTTYPES_H, AC_STRUCT_ST_MTIM, + jm_AC_TYPE_UINTMAX_T): New defuns. + * commands.c (delete_target): Convert file timestamp to + seconds before comparing to archive timestamp. Extract mod + time from struct stat using FILE_TIMESTAMP_STAT_MODTIME. + * configure.in (C_STRUCT_ST_MTIM, jm_AC_TYPE_UINTMAX_T): Add. + (AC_CHECK_LIB, AC_CHECK_FUNCS): Add clock_gettime. + * file.c (snap_deps): Use FILE_TIMESTAMP, not time_t. + (file_timestamp_now, file_timestamp_sprintf): New functions. + (print_file): Print file timestamps as FILE_TIMESTAMP, not + time_t. + * filedef.h: Include if available and if HAVE_ST_MTIM. + (FILE_TIMESTAMP, FILE_TIMESTAMP_STAT_MODTIME, FILE_TIMESTAMP_MIN, + FILE_TIMESTAMPS_PER_S, FILE_TIMESTAMP_FROM_S_AND_NS, + FILE_TIMESTAMP_DIV, FILE_TIMESTAMP_MOD, FILE_TIMESTAMP_S, + FILE_TIMESTAMP_NS, FILE_TIMESTAMP_PRINT_LEN_BOUND): New macros. + (file_timestamp_now, file_timestamp_sprintf): New decls. + (struct file.last_mtime, f_mtime, file_mtime_1, NEW_MTIME): + time_t -> FILE_TIMESTAMP. + * implicit.c (pattern_search): Likewise. + * vpath.c (vpath_search, selective_vpath_search): Likewise. + * main.c (main): Likewise. + * remake.c (check_dep, name_mtime, library_search, f_mtime): Likewise. + (f_mtime): Use file_timestamp_now instead of `time'. + Print file timestamp with file_timestamp_sprintf. + * vpath.c (selective_vpath_search): Extract file time stamp from + struct stat with FILE_TIMESTAMP_STAT_MODTIME. + 1998-07-28 Paul D. Smith * Version 3.77 released. @@ -118,7 +340,7 @@ 1998-06-19 Eli Zaretskii - * job.c (start_job_command): Reset execute_by_shell after an empty + * job.c (start_job_command): Reset execute_by_shell after an empty command was skipped. 1998-06-09 Paul D. Smith @@ -503,7 +725,7 @@ Thu Aug 28 17:04:47 1997 Paul D. Smith Wed Aug 27 17:09:32 1997 Paul D. Smith - * Version 3.75.92 + * Version 3.75.92 Tue Aug 26 11:59:15 1997 Paul D. Smith @@ -538,16 +760,16 @@ Fri Aug 22 1997 Eli Zaretskii Sat Aug 16 00:56:15 1997 John W. Eaton - * vmsify.c (vmsify, case 11): After translating `..' elements, set + * vmsify.c (vmsify, case 11): After translating `..' elements, set nstate to N_OPEN if there are still more elements to process. (vmsify, case 2): After translating `foo/bar' up to the slash, set nstate to N_OPEN, not N_DOT. Fri Aug 8 15:18:09 1997 John W. Eaton - * dir.c (vmsstat_dir): Leave name unmodified on exit. - * make.h (PATH_SEPARATOR_CHAR): Set to comma for VMS. - * vpath.c: Fix comments to refer to path separator, not colon. + * dir.c (vmsstat_dir): Leave name unmodified on exit. + * make.h (PATH_SEPARATOR_CHAR): Set to comma for VMS. + * vpath.c: Fix comments to refer to path separator, not colon. (selective_vpath_search): Avoid Unixy slash handling for VMS. Thu Aug 7 22:24:03 1997 John W. Eaton diff --git a/GNUmakefile b/GNUmakefile index 15067c6d..97b2e1d8 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -7,13 +7,18 @@ NORECURSE = true +ACLOCALARGS = + +CFLAGS = -g -O -Wall -D__USE_FIXED_PROTOTYPES__ +export CFLAGS + # If the user asked for a specific target, invoke the Makefile instead. # .DEFAULT: @[ -f Makefile.in -a -f configure -a -f aclocal.m4 -a -f config.h.in ] \ || $(MAKE) __cfg NORECURSE= @[ -f Makefile ] \ - || ./configure + || CFLAGS='-g -O -Wall -D__USE_FIXED_PROTOTYPES__' ./configure $(MAKE) -f Makefile $@ .PHONY: __cfg __cfg_basic @@ -23,21 +28,20 @@ NORECURSE = true ACCONFIG = acconfig.h __cfg: __cfg_basic config.h.in TAGS - cd glob && $(MAKE) -f ../GNUmakefile __cfg_basic ACCONFIG= ifdef NORECURSE - @echo ""; echo "Now you should run one of:"; echo ""; \ - echo " make all"; \ + @echo ""; echo "Now you should run:"; echo ""; \ + echo " make all"; echo ""; \ + echo "then, optionally, one of:"; echo ""; \ echo " make dist"; \ echo " make distdir"; \ - echo " make distcheck"; echo ""; \ - echo "Or similar to proceed.";\ + echo " make distcheck"; \ echo "" endif __cfg_basic: aclocal.m4 stamp-h.in configure Makefile.in aclocal.m4: configure.in $(wildcard acinclude.m4) - aclocal + aclocal $(ACLOCALARGS) config.h.in: stamp-h.in stamp-h.in: configure.in aclocal.m4 $(ACCONFIG) @@ -45,7 +49,7 @@ stamp-h.in: configure.in aclocal.m4 $(ACCONFIG) echo timestamp > $@ configure: configure.in aclocal.m4 - autoconf + autoconf $(ACARGS) Makefile.in: configure.in config.h.in Makefile.am aclocal.m4 automake --add-missing diff --git a/acconfig.h b/acconfig.h index d20cae17..d575b921 100644 --- a/acconfig.h +++ b/acconfig.h @@ -10,6 +10,10 @@ /* Define this if the SCCS `get' command understands the `-G' option. */ #undef SCCS_GET_MINUS_G +/* Define to be the nanoseconds member of struct stat's st_mtim, + if it exists. */ +#undef ST_MTIM_NSEC + /* Define this if the C library defines the variable `sys_siglist'. */ #undef HAVE_SYS_SIGLIST @@ -18,3 +22,7 @@ /* Define this if you have the `union wait' type in . */ #undef HAVE_UNION_WAIT + +/* Define to `unsigned long' or `unsigned long long' + if doesn't define. */ +#undef uintmax_t diff --git a/acinclude.m4 b/acinclude.m4 index 343c3336..ff51c4c0 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -86,7 +86,7 @@ changequote([,])dnl dnl --------------------------------------------------------------------------- dnl Got this from the GNU fileutils 3.16r distribution -dnl by Paul Eggert +dnl by Paul Eggert dnl --------------------------------------------------------------------------- dnl The problem is that the default compilation flags in Solaris 2.6 won't @@ -129,3 +129,82 @@ AC_DEFUN(AC_LFS, done ;; esac ]) + + +dnl --------------------------------------------------------------------------- +dnl From Paul Eggert + +dnl Define HAVE_INTTYPES_H if exists, +dnl doesn't clash with , and declares uintmax_t. + +AC_DEFUN(jm_AC_HEADER_INTTYPES_H, +[ + if test x = y; then + dnl This code is deliberately never run via ./configure. + dnl FIXME: this is a gross hack to make autoheader put an entry + dnl for `HAVE_INTTYPES_H' in config.h.in. + AC_CHECK_FUNCS(INTTYPES_H) + fi + AC_CACHE_CHECK([for inttypes.h], jm_ac_cv_header_inttypes_h, + [AC_TRY_COMPILE( + [#include +#include ], + [uintmax_t i = (uintmax_t) -1;], + jm_ac_cv_header_inttypes_h=yes, + jm_ac_cv_header_inttypes_h=no)]) + if test $jm_ac_cv_header_inttypes_h = yes; then + ac_kludge=HAVE_INTTYPES_H + AC_DEFINE_UNQUOTED($ac_kludge) + fi +]) + + +dnl --------------------------------------------------------------------------- +dnl From Paul Eggert + +AC_DEFUN(AC_STRUCT_ST_MTIM_NSEC, + [AC_CACHE_CHECK([for nanoseconds member of struct stat.st_mtim], + ac_cv_struct_st_mtim_nsec, + [ac_save_CPPFLAGS="$CPPFLAGS" + ac_cv_struct_st_mtim_nsec=no + # tv_nsec -- the usual case + # _tv_nsec -- Solaris 2.6, if + # (defined _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED == 1 + # && !defined __EXTENSIONS__) + # st__tim.tv_nsec -- UnixWare 2.1.2 + for ac_val in tv_nsec _tv_nsec st__tim.tv_nsec; do + CPPFLAGS="$ac_save_CPPFLAGS -DST_MTIM_NSEC=$ac_val" + AC_TRY_COMPILE([#include +#include ], [struct stat s; s.st_mtim.ST_MTIM_NSEC;], + [ac_cv_struct_st_mtim_nsec=$ac_val; break]) + done + CPPFLAGS="$ac_save_CPPFLAGS"]) + + if test $ac_cv_struct_st_mtim_nsec != no; then + AC_DEFINE_UNQUOTED(ST_MTIM_NSEC, $ac_cv_struct_st_mtim_nsec) + fi + ] +) + +dnl --------------------------------------------------------------------------- +dnl From Paul Eggert + +dnl Define uintmax_t to `unsigned long' or `unsigned long long' +dnl if does not exist. + +AC_DEFUN(jm_AC_TYPE_UINTMAX_T, +[ + AC_REQUIRE([jm_AC_HEADER_INTTYPES_H]) + if test $jm_ac_cv_header_inttypes_h = no; then + AC_CACHE_CHECK([for unsigned long long], ac_cv_type_unsigned_long_long, + [AC_TRY_COMPILE([], + [unsigned long long i = (unsigned long long) -1;], + ac_cv_type_unsigned_long_long=yes, + ac_cv_type_unsigned_long_long=no)]) + if test $ac_cv_type_unsigned_long_long = yes; then + AC_DEFINE(uintmax_t, unsigned long long) + else + AC_DEFINE(uintmax_t, unsigned long) + fi + fi +]) diff --git a/amiga.c b/amiga.c index a1637817..d0e4ff50 100644 --- a/amiga.c +++ b/amiga.c @@ -45,7 +45,7 @@ char ** argv; buffer = AllocMem (len, MEMF_ANY); if (!buffer) - fatal ("MyExecute: Cannot allocate space for calling a command"); + fatal (NILF, "MyExecute: Cannot allocate space for calling a command"); ptr = buffer; diff --git a/ar.c b/ar.c index 7167dc3e..04d74118 100644 --- a/ar.c +++ b/ar.c @@ -46,7 +46,7 @@ ar_name (name) return 0; if (p[1] == '(' && end[-1] == ')') - fatal ("attempt to use unsupported feature: `%s'", name); + fatal (NILF, "attempt to use unsupported feature: `%s'", name); return 1; } @@ -137,7 +137,7 @@ int ar_touch (name) char *name; { - error ("touch archive member is not available on VMS"); + error (NILF, "touch archive member is not available on VMS"); return -1; } #else @@ -169,22 +169,24 @@ ar_touch (name) switch (ar_member_touch (arname, memname)) { case -1: - error ("touch: Archive `%s' does not exist", arname); + error (NILF, "touch: Archive `%s' does not exist", arname); break; case -2: - error ("touch: `%s' is not a valid archive", arname); + error (NILF, "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); + error (NILF, + "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); + error (NILF, + "touch: Bad return code from ar_member_touch on `%s'", name); } if (!arname_used) @@ -233,15 +235,6 @@ ar_glob_match (desc, mem, truncated, return 0L; } -/* Alphabetic sorting function for `qsort'. */ - -static int -ar_glob_alphacompare (a, b) - char **a, **b; -{ - return strcmp (*a, *b); -} - /* Return nonzero if PATTERN contains any metacharacters. Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ static int @@ -316,7 +309,7 @@ ar_glob (arname, member_pattern, size) names[i++] = n->name; /* Sort them alphabetically. */ - qsort ((char *) names, i, sizeof (*names), ar_glob_alphacompare); + qsort ((char *) names, i, sizeof (*names), alpha_compare); /* Put them back into the chain in the sorted order. */ i = 0; diff --git a/arscan.c b/arscan.c index 13ae45ba..1fc0a16f 100644 --- a/arscan.c +++ b/arscan.c @@ -69,7 +69,7 @@ VMS_get_member_info (module, rfa) &bufdesc.dsc$w_length, 0); if (! status) { - error ("lbr$set_module failed to extract module info, status = %d", + error (NILF, "lbr$set_module failed to extract module info, status = %d", status); lbr$close (&VMS_lib_idx); @@ -151,7 +151,7 @@ ar_scan (archive, function, arg) if (! status) { - error ("lbr$ini_control failed with status = %d",status); + error (NILF, "lbr$ini_control failed with status = %d",status); return -2; } @@ -162,7 +162,7 @@ ar_scan (archive, function, arg) if (! status) { - error ("unable to open library `%s' to lookup member `%s'", + error (NILF, "unable to open library `%s' to lookup member `%s'", archive, (char *)arg); return -1; } diff --git a/commands.c b/commands.c index 5646b18e..166b96d8 100644 --- a/commands.c +++ b/commands.c @@ -473,13 +473,13 @@ delete_target (file, on_behalf_of) #ifndef NO_ARCHIVES if (ar_name (file->name)) { - if (ar_member_date (file->name) != file->last_mtime) + if (ar_member_date (file->name) != FILE_TIMESTAMP_S (file->last_mtime)) { if (on_behalf_of) - error ("*** [%s] Archive member `%s' may be bogus; not deleted", + error (NILF, "*** [%s] Archive member `%s' may be bogus; not deleted", on_behalf_of, file->name); else - error ("*** Archive member `%s' may be bogus; not deleted", + error (NILF, "*** Archive member `%s' may be bogus; not deleted", file->name); } return; @@ -488,12 +488,12 @@ delete_target (file, on_behalf_of) if (stat (file->name, &st) == 0 && S_ISREG (st.st_mode) - && (time_t) st.st_mtime != file->last_mtime) + && FILE_TIMESTAMP_STAT_MODTIME (st) != file->last_mtime) { if (on_behalf_of) - error ("*** [%s] Deleting file `%s'", on_behalf_of, file->name); + error (NILF, "*** [%s] Deleting file `%s'", on_behalf_of, file->name); else - error ("*** Deleting file `%s'", file->name); + error (NILF, "*** Deleting file `%s'", file->name); if (unlink (file->name) < 0 && errno != ENOENT) /* It disappeared; so what. */ perror_with_name ("unlink: ", file->name); @@ -533,10 +533,11 @@ print_commands (cmds) fputs ("# commands to execute", stdout); - if (cmds->filename == 0) + if (cmds->fileinfo.filenm == 0) puts (" (built-in):"); else - printf (" (from `%s', line %u):\n", cmds->filename, cmds->lineno); + printf (" (from `%s', line %lu):\n", + cmds->fileinfo.filenm, cmds->fileinfo.lineno); s = cmds->commands; while (*s != '\0') diff --git a/commands.h b/commands.h index c55fa672..9547fc36 100644 --- a/commands.h +++ b/commands.h @@ -21,8 +21,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ struct commands { - char *filename; /* File that contains commands. */ - unsigned int lineno; /* Line number in file. */ + struct floc fileinfo; /* Where commands were defined. */ char *commands; /* Commands text. */ unsigned int ncommand_lines;/* Number of command lines. */ char **command_lines; /* Commands chopped up into lines. */ diff --git a/config.ami.template b/config.ami.template index b7103ed5..523876eb 100644 --- a/config.ami.template +++ b/config.ami.template @@ -4,121 +4,123 @@ System headers sometimes define this. We just want to avoid a redefinition error message. */ #ifndef _ALL_SOURCE -#undef _ALL_SOURCE +/* #undef _ALL_SOURCE */ #endif /* Define if using alloca.c. */ #define C_ALLOCA +/* Define if the closedir function returns void instead of int. */ +/* #undef CLOSEDIR_VOID */ + /* Define to empty if the keyword does not work. */ -#undef const +/* #undef const */ /* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. This function is required for alloca.c support on those systems. */ -#undef CRAY_STACKSEG_END +/* #undef CRAY_STACKSEG_END */ /* Define for DGUX with . */ -#undef DGUX +/* #undef DGUX */ /* Define if the `getloadavg' function needs to be run setuid or setgid. */ -#undef GETLOADAVG_PRIVILEGED +/* #undef GETLOADAVG_PRIVILEGED */ /* Define to `int' if doesn't define. */ #define gid_t int /* Define if you have alloca, as a function or macro. */ -#undef HAVE_ALLOCA +/* #undef HAVE_ALLOCA */ /* Define if you have and it should be used (not on Ultrix). */ -#undef HAVE_ALLOCA_H - -/* Define if you have the memmove function. */ -#define HAVE_MEMMOVE 1 +/* #undef HAVE_ALLOCA_H */ /* Define if you don't have vprintf but do have _doprnt. */ -#undef HAVE_DOPRNT +/* #undef HAVE_DOPRNT */ + +/* Define if your system has a working fnmatch function. */ +/* #undef HAVE_FNMATCH */ /* Define if your system has its own `getloadavg' function. */ -#undef HAVE_GETLOADAVG +/* #undef HAVE_GETLOADAVG */ /* Define if you have the getmntent function. */ -#undef HAVE_GETMNTENT +/* #undef HAVE_GETMNTENT */ /* Define if the `long double' type works. */ -#undef HAVE_LONG_DOUBLE +/* #undef HAVE_LONG_DOUBLE */ /* Define if you support file names longer than 14 characters. */ -#define HAVE_LONG_FILE_NAMES +#define HAVE_LONG_FILE_NAMES 1 /* Define if you have a working `mmap' system call. */ -#undef HAVE_MMAP +/* #undef HAVE_MMAP */ /* Define if system calls automatically restart after interruption by a signal. */ -#undef HAVE_RESTARTABLE_SYSCALLS +/* #undef HAVE_RESTARTABLE_SYSCALLS */ /* Define if your struct stat has st_blksize. */ -#undef HAVE_ST_BLKSIZE +/* #undef HAVE_ST_BLKSIZE */ /* Define if your struct stat has st_blocks. */ -#undef HAVE_ST_BLOCKS +/* #undef HAVE_ST_BLOCKS */ /* Define if you have the strcoll function and it is properly defined. */ -#define HAVE_STRCOLL +#define HAVE_STRCOLL 1 /* Define if your struct stat has st_rdev. */ -#define HAVE_ST_RDEV +#define HAVE_ST_RDEV 1 /* Define if you have the strftime function. */ -#define HAVE_STRFTIME +#define HAVE_STRFTIME 1 /* Define if you have that is POSIX.1 compatible. */ -#undef HAVE_SYS_WAIT_H +/* #undef HAVE_SYS_WAIT_H */ /* Define if your struct tm has tm_zone. */ -#undef HAVE_TM_ZONE +/* #undef HAVE_TM_ZONE */ /* Define if you don't have tm_zone but do have the external array tzname. */ -#define HAVE_TZNAME -/* #define tzname __tzname */ +#define HAVE_TZNAME 1 /* Define if you have . */ -#define HAVE_UNISTD_H +#define HAVE_UNISTD_H 1 /* Define if utime(file, NULL) sets file's timestamp to the present. */ -#undef HAVE_UTIME_NULL +/* #undef HAVE_UTIME_NULL */ /* Define if you have . */ -#undef HAVE_VFORK_H +/* #undef HAVE_VFORK_H */ /* Define if you have the vprintf function. */ -#define HAVE_VPRINTF +#define HAVE_VPRINTF 1 /* Define if you have the wait3 system call. */ -#undef HAVE_WAIT3 +/* #undef HAVE_WAIT3 */ /* Define if on MINIX. */ -#undef _MINIX +/* #undef _MINIX */ /* Define if your struct nlist has an n_un member. */ -#undef NLIST_NAME_UNION +/* #undef NLIST_NAME_UNION */ /* Define if you have . */ -#undef NLIST_STRUCT +/* #undef NLIST_STRUCT */ /* Define if your C compiler doesn't accept -c and -o together. */ -#undef NO_MINUS_C_MINUS_O +/* #undef NO_MINUS_C_MINUS_O */ /* Define to `int' if doesn't define. */ #define pid_t int /* Define if the system does not provide POSIX.1 features except with this defined. */ -#undef _POSIX_1_SOURCE +/* #undef _POSIX_1_SOURCE */ /* Define if you need to in order for stat and other things to work. */ -#undef _POSIX_SOURCE +/* #undef _POSIX_SOURCE */ /* Define as the return type of signal handlers (int or void). */ #define RETSIGTYPE void @@ -126,7 +128,7 @@ /* Define if the setvbuf function takes the buffering type as its second argument and the buffer pointer as the third, as on System V before release 3. */ -#undef SETVBUF_REVERSED +/* #undef SETVBUF_REVERSED */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be @@ -138,29 +140,29 @@ #define STACK_DIRECTION -1 /* Define if the `S_IS*' macros in do not work properly. */ -#undef STAT_MACROS_BROKEN +/* #undef STAT_MACROS_BROKEN */ /* Define if you have the ANSI C header files. */ #define STDC_HEADERS /* Define on System V Release 4. */ -#undef SVR4 +/* #undef SVR4 */ /* Define if `sys_siglist' is declared by . */ -#undef SYS_SIGLIST_DECLARED +/* #undef SYS_SIGLIST_DECLARED */ /* Define to `int' if doesn't define. */ #define uid_t int /* Define for Encore UMAX. */ -#undef UMAX +/* #undef UMAX */ /* Define for Encore UMAX 4.3 that has instead of . */ -#undef UMAX4_3 +/* #undef UMAX4_3 */ /* Define vfork as fork if vfork does not work. */ -#undef vfork +/* #undef vfork */ /* Name of this package (needed by automake) */ #define PACKAGE "%PACKAGE%" @@ -172,112 +174,130 @@ #define SCCS_GET "get" /* Define this if the SCCS `get' command understands the `-G' option. */ -#undef SCCS_GET_MINUS_G +/* #undef SCCS_GET_MINUS_G */ /* Define this if the C library defines the variable `sys_siglist'. */ -#undef HAVE_SYS_SIGLIST +/* #undef HAVE_SYS_SIGLIST */ /* Define this if the C library defines the variable `_sys_siglist'. */ -#undef HAVE__SYS_SIGLIST +/* #undef HAVE__SYS_SIGLIST */ /* Define this if you have the `union wait' type in . */ -#undef HAVE_UNION_WAIT - -/* Define this if the POSIX.1 call `sysconf (_SC_OPEN_MAX)' works properly. */ -#undef HAVE_SYSCONF_OPEN_MAX +/* #undef HAVE_UNION_WAIT */ /* Define if you have the dup2 function. */ -#undef HAVE_DUP2 +/* #undef HAVE_DUP2 */ /* Define if you have the getcwd function. */ -#define HAVE_GETCWD - -/* Define if you have the getdtablesize function. */ -#undef HAVE_GETDTABLESIZE +#define HAVE_GETCWD 1 /* Define if you have the getgroups function. */ -#undef HAVE_GETGROUPS +/* #undef HAVE_GETGROUPS */ + +/* Define if you have the gethostbyname function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define if you have the gethostname function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define if you have the memmove function. */ +#define HAVE_MEMMOVE 1 /* Define if you have the mktemp function. */ -#define HAVE_MKTEMP +#define HAVE_MKTEMP 1 /* Define if you have the psignal function. */ -#undef HAVE_PSIGNAL +/* #undef HAVE_PSIGNAL */ + +/* Define if you have the pstat_getdynamic function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ /* Define if you have the setegid function. */ -#undef HAVE_SETEGID +/* #undef HAVE_SETEGID */ /* Define if you have the seteuid function. */ -#undef HAVE_SETEUID +/* #undef HAVE_SETEUID */ /* Define if you have the setlinebuf function. */ -#undef HAVE_SETLINEBUF +/* #undef HAVE_SETLINEBUF */ /* Define if you have the setregid function. */ -#undef HAVE_SETREGID +/* #undef HAVE_SETREGID */ /* Define if you have the setreuid function. */ -#undef HAVE_SETREUID +/* #undef HAVE_SETREUID */ /* Define if you have the sigsetmask function. */ -#undef HAVE_SIGSETMASK +/* #undef HAVE_SIGSETMASK */ + +/* Define if you have the socket function. */ +/* #undef HAVE_SOCKET */ + +/* Define if you have the strcasecmp function. */ +/* #undef HAVE_STRCASECMP */ /* Define if you have the strerror function. */ -#define HAVE_STRERROR +#define HAVE_STRERROR 1 /* Define if you have the strsignal function. */ -#undef HAVE_STRSIGNAL +/* #undef HAVE_STRSIGNAL */ /* Define if you have the wait3 function. */ -#undef HAVE_WAIT3 +/* #undef HAVE_WAIT3 */ /* Define if you have the waitpid function. */ -#undef HAVE_WAITPID +/* #undef HAVE_WAITPID */ /* Define if you have the header file. */ -#define HAVE_DIRENT_H +#define HAVE_DIRENT_H 1 /* Define if you have the header file. */ -#define HAVE_FCNTL_H +#define HAVE_FCNTL_H 1 /* Define if you have the header file. */ -#define HAVE_LIMITS_H +#define HAVE_LIMITS_H 1 /* Define if you have the header file. */ -#undef HAVE_MACH_MACH_H +/* #undef HAVE_MACH_MACH_H */ /* Define if you have the header file. */ -#undef HAVE_MEMORY_H +/* #undef HAVE_MEMORY_H */ /* Define if you have the header file. */ -#undef HAVE_NDIR_H +/* #undef HAVE_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_STDLIB_H */ /* Define if you have the header file. */ -#define HAVE_STRING_H +#define HAVE_STRING_H 1 /* Define if you have the header file. */ -#define HAVE_SYS_DIR_H +#define HAVE_SYS_DIR_H 1 /* Define if you have the header file. */ -#undef HAVE_SYS_NDIR_H +/* #undef HAVE_SYS_NDIR_H */ /* Define if you have the header file. */ -#undef HAVE_SYS_PARAM_H +/* #undef HAVE_SYS_PARAM_H */ /* Define if you have the header file. */ -#undef HAVE_SYS_TIMEB_H +/* #undef HAVE_SYS_TIMEB_H */ /* Define if you have the header file. */ -#undef HAVE_SYS_WAIT_H +/* #undef HAVE_SYS_WAIT_H */ /* Define if you have the header file. */ -#define HAVE_UNISTD_H +#define HAVE_UNISTD_H 1 /* Define if you have the dgc library (-ldgc). */ -#undef HAVE_LIBDGC +/* #undef HAVE_LIBDGC */ + +/* Define if you have the kstat library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ /* Define if you have the sun library (-lsun). */ -#undef HAVE_LIBSUN +/* #undef HAVE_LIBSUN */ /* Define for Case Insensitve behavior */ #define HAVE_CASE_INSENSITIVE_FS diff --git a/config.h-vms.template b/config.h-vms.template index a41ae06f..e44af440 100644 --- a/config.h-vms.template +++ b/config.h-vms.template @@ -12,6 +12,9 @@ /* Define if using alloca.c. */ /* #undef C_ALLOCA */ +/* Define if the closedir function returns void instead of int. */ +/* #undef CLOSEDIR_VOID */ + /* Define to empty if the keyword does not work. */ /* #undef const */ @@ -23,7 +26,7 @@ /* #undef DGUX */ /* Define if the `getloadavg' function needs to be run setuid or setgid. */ -/* #undef GETLOADAVG_PRIVILEGED 1 */ +/* #undef GETLOADAVG_PRIVILEGED */ /* Define to `int' if doesn't define. */ /* #undef gid_t */ @@ -32,14 +35,14 @@ #define HAVE_ALLOCA 1 /* Define if you have and it should be used (not on Ultrix). */ -/* #undef HAVE_ALLOCA_H 1 */ - -/* Define if you have the memmove function. */ -#define HAVE_MEMMOVE 1 +/* #undef HAVE_ALLOCA_H */ /* Define if you don't have vprintf but do have _doprnt. */ /* #undef HAVE_DOPRNT */ +/* Define if your system has a working fnmatch function. */ +/* #undef HAVE_FNMATCH */ + /* Define if your system has its own `getloadavg' function. */ /* #undef HAVE_GETLOADAVG */ @@ -66,16 +69,16 @@ /* #undef HAVE_ST_BLOCKS */ /* Define if you have the strcoll function and it is properly defined. */ -/* #undef HAVE_STRCOLL 1 */ +/* #undef HAVE_STRCOLL */ /* Define if your struct stat has st_rdev. */ -/* #undef HAVE_ST_RDEV */ +/* #undef HAVE_ST_RDEV */ /* Define if you have the strftime function. */ /* #undef HAVE_STRFTIME */ /* Define if you have that is POSIX.1 compatible. */ -/* #undef HAVE_SYS_WAIT_H 1 */ +/* #undef HAVE_SYS_WAIT_H */ /* Define if your struct tm has tm_zone. */ /* #undef HAVE_TM_ZONE */ @@ -93,13 +96,13 @@ /* #undef HAVE_UTIME_NULL */ /* Define if you have . */ -/* #undef HAVE_VFORK_H 1 */ +/* #undef HAVE_VFORK_H */ /* Define if you have the vprintf function. */ #define HAVE_VPRINTF 1 /* Define if you have the wait3 system call. */ -/* #undef HAVE_WAIT3 1 */ +/* #undef HAVE_WAIT3 */ /* Define if on MINIX. */ /* #undef _MINIX */ @@ -108,7 +111,7 @@ /* #undef NLIST_NAME_UNION */ /* Define if you have . */ -/* #undef NLIST_STRUCT 1 */ +/* #undef NLIST_STRUCT */ /* Define if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ @@ -129,7 +132,7 @@ /* Define if the setvbuf function takes the buffering type as its second argument and the buffer pointer as the third, as on System V before release 3. */ -/* #undef SETVBUF_REVERSED 1 */ +/* #undef SETVBUF_REVERSED */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be @@ -162,23 +165,23 @@ instead of . */ /* #undef UMAX4_3 */ +/* Define vfork as fork if vfork does not work. */ +/* #undef vfork */ + /* Name of this package (needed by automake) */ #define PACKAGE "%PACKAGE%" /* Version of this package (needed by automake) */ #define VERSION "%VERSION%" -/* Define vfork as fork if vfork does not work. */ -/* #undef vfork */ - /* Define to the name of the SCCS `get' command. */ -/* #undef SCCS_GET "/usr/sccs/get" */ +/* #undef SCCS_GET */ /* Define this if the SCCS `get' command understands the `-G' option. */ -/* #undef SCCS_GET_MINUS_G 1 */ +/* #undef SCCS_GET_MINUS_G */ /* Define this if the C library defines the variable `sys_siglist'. */ -/* #undefine HAVE_SYS_SIGLIST 1 */ +/* #undefine HAVE_SYS_SIGLIST */ /* Define this if the C library defines the variable `_sys_siglist'. */ /* #undef HAVE__SYS_SIGLIST */ @@ -186,45 +189,60 @@ /* Define this if you have the `union wait' type in . */ /* #undef HAVE_UNION_WAIT */ -/* Define this if the POSIX.1 call `sysconf (_SC_OPEN_MAX)' works properly. */ -/* #undef HAVE_SYSCONF_OPEN_MAX */ - /* Define if you have the dup2 function. */ #define HAVE_DUP2 1 /* Define if you have the getcwd function. */ #define HAVE_GETCWD 1 -/* Define if you have the getdtablesize function. */ -/* #undef HAVE_GETDTABLESIZE 1 */ - /* Define if you have the getgroups function. */ -/* #undef HAVE_GETGROUPS 1 */ +/* #undef HAVE_GETGROUPS */ + +/* Define if you have the gethostbyname function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define if you have the gethostname function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define if you have the getloadavg function. */ +/* #undef HAVE_GETLOADAVG */ + +/* Define if you have the memmove function. */ +#define HAVE_MEMMOVE 1 /* Define if you have the mktemp function. */ #define HAVE_MKTEMP 1 /* Define if you have the psignal function. */ -/* #undef HAVE_PSIGNAL 1 */ +/* #undef HAVE_PSIGNAL */ + +/* Define if you have the pstat_getdynamic function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ /* Define if you have the setegid function. */ -/* #undef HAVE_SETEGID 1 */ +/* #undef HAVE_SETEGID */ /* Define if you have the seteuid function. */ -/* #undef HAVE_SETEUID 1 */ +/* #undef HAVE_SETEUID */ /* Define if you have the setlinebuf function. */ -/* #undef HAVE_SETLINEBUF 1 */ +/* #undef HAVE_SETLINEBUF */ /* Define if you have the setregid function. */ -/* #undefine HAVE_SETREGID 1 */ +/* #undefine HAVE_SETREGID */ /* Define if you have the setreuid function. */ -/* #define HAVE_SETREUID 1 */ +/* #define HAVE_SETREUID */ /* Define if you have the sigsetmask function. */ #define HAVE_SIGSETMASK 1 +/* Define if you have the socket function. */ +/* #undef HAVE_SOCKET */ + +/* Define if you have the strcasecmp function. */ +/* #undef HAVE_STRCASECMP */ + /* Define if you have the strerror function. */ #define HAVE_STRERROR 1 @@ -232,13 +250,13 @@ /* #undef HAVE_STRSIGNAL */ /* Define if you have the wait3 function. */ -/* #define HAVE_WAIT3 1 */ +/* #undef HAVE_WAIT3 */ /* Define if you have the waitpid function. */ -/* #undef HAVE_WAITPID 1 */ +/* #undef HAVE_WAITPID */ /* Define if you have the header file. */ -/* #unddef HAVE_DIRENT_H 1 */ +/* #undef HAVE_DIRENT_H */ /* Define if you have the header file. */ #ifdef __DECC @@ -252,17 +270,17 @@ /* #undef HAVE_MACH_MACH_H */ /* Define if you have the header file. */ -/* #undef HAVE_MEMORY_H 1 */ +/* #undef HAVE_MEMORY_H */ /* Define if you have the header file. */ /* #undef HAVE_NDIR_H */ +/* Define if you have the header file. */ +#define HAVE_STDLIB_H 1 + /* Define if you have the header file. */ #define HAVE_STRING_H 1 -/* Define if you have the header file. */ -/* #undef HAVE_PWD_H */ - /* Define if you have the header file. */ /* #undef HAVE_SYS_DIR_H */ @@ -270,24 +288,29 @@ /* #undef HAVE_SYS_NDIR_H */ /* Define if you have the header file. */ -/* #undef HAVE_SYS_PARAM_H 1 */ +/* #undef HAVE_SYS_PARAM_H */ /* Define if you have the header file. */ #define HAVE_SYS_TIMEB_H 1 /* Define if you have the header file. */ -/* #undef HAVE_SYS_WAIT_H 1 */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_UNISTD_H */ /* Define if you have the dgc library (-ldgc). */ /* #undef HAVE_LIBDGC */ +/* Define if you have the kstat library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ + /* Define if you have the sun library (-lsun). */ /* #undef HAVE_LIBSUN */ /* VMS specific */ #define HAVE_VMSDIR_H 1 -#define HAVE_STDLIB_H 1 #define INCLUDEDIR "sys$sysroot:[syslib]" #define LIBDIR "sys$sysroot:[syslib]" diff --git a/config.h.W32.template b/config.h.W32.template index aa5a0277..79bb6cd3 100644 --- a/config.h.W32.template +++ b/config.h.W32.template @@ -4,24 +4,27 @@ System headers sometimes define this. We just want to avoid a redefinition error message. */ #ifndef _ALL_SOURCE -#undef _ALL_SOURCE +/* #undef _ALL_SOURCE */ #endif /* Define if using alloca.c. */ -#undef C_ALLOCA +/* #undef C_ALLOCA */ + +/* Define if the closedir function returns void instead of int. */ +/* #undef CLOSEDIR_VOID */ /* Define to empty if the keyword does not work. */ -#undef const +/* #undef const */ /* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. This function is required for alloca.c support on those systems. */ -#undef CRAY_STACKSEG_END +/* #undef CRAY_STACKSEG_END */ /* Define for DGUX with . */ -#undef DGUX +/* #undef DGUX */ /* Define if the `getloadavg' function needs to be run setuid or setgid. */ -#undef GETLOADAVG_PRIVILEGED +/* #undef GETLOADAVG_PRIVILEGED */ /* Define to `int' if doesn't define. */ #undef gid_t @@ -32,40 +35,39 @@ #define HAVE_ALLOCA 1 /* Define if you have and it should be used (not on Ultrix). */ -#undef HAVE_ALLOCA_H - -/* Define if you have the memmove function. */ -#undef HAVE_MEMMOVE -#define HAVE_MEMMOVE 1 +/* #undef HAVE_ALLOCA_H */ /* Define if you don't have vprintf but do have _doprnt. */ -#undef HAVE_DOPRNT +/* #undef HAVE_DOPRNT */ + +/* Define if your system has a working fnmatch function. */ +/* #undef HAVE_FNMATCH */ /* Define if your system has its own `getloadavg' function. */ -#undef HAVE_GETLOADAVG +/* #undef HAVE_GETLOADAVG */ /* Define if you have the getmntent function. */ -#undef HAVE_GETMNTENT +/* #undef HAVE_GETMNTENT */ /* Define if the `long double' type works. */ -#undef HAVE_LONG_DOUBLE +/* #undef HAVE_LONG_DOUBLE */ /* Define if you support file names longer than 14 characters. */ #undef HAVE_LONG_FILE_NAMES #define HAVE_LONG_FILE_NAMES 1 /* Define if you have a working `mmap' system call. */ -#undef HAVE_MMAP +/* #undef HAVE_MMAP */ /* Define if system calls automatically restart after interruption by a signal. */ -#undef HAVE_RESTARTABLE_SYSCALLS +/* #undef HAVE_RESTARTABLE_SYSCALLS */ /* Define if your struct stat has st_blksize. */ -#undef HAVE_ST_BLKSIZE +/* #undef HAVE_ST_BLKSIZE */ /* Define if your struct stat has st_blocks. */ -#undef HAVE_ST_BLOCKS +/* #undef HAVE_ST_BLOCKS */ /* Define if you have the strcoll function and it is properly defined. */ #undef HAVE_STRCOLL @@ -80,10 +82,10 @@ #define HAVE_STRFTIME 1 /* Define if you have that is POSIX.1 compatible. */ -#undef HAVE_SYS_WAIT_H +/* #undef HAVE_SYS_WAIT_H */ /* Define if your struct tm has tm_zone. */ -#undef HAVE_TM_ZONE +/* #undef HAVE_TM_ZONE */ /* Define if you don't have tm_zone but do have the external array tzname. */ @@ -91,33 +93,33 @@ #define HAVE_TZNAME 1 /* Define if you have . */ -#undef HAVE_UNISTD_H +/* #undef HAVE_UNISTD_H */ /* Define if utime(file, NULL) sets file's timestamp to the present. */ #undef HAVE_UTIME_NULL #define HAVE_UTIME_NULL 1 /* Define if you have . */ -#undef HAVE_VFORK_H +/* #undef HAVE_VFORK_H */ /* Define if you have the vprintf function. */ #undef HAVE_VPRINTF #define HAVE_VPRINTF 1 /* Define if you have the wait3 system call. */ -#undef HAVE_WAIT3 +/* #undef HAVE_WAIT3 */ /* Define if on MINIX. */ -#undef _MINIX +/* #undef _MINIX */ /* Define if your struct nlist has an n_un member. */ -#undef NLIST_NAME_UNION +/* #undef NLIST_NAME_UNION */ /* Define if you have . */ -#undef NLIST_STRUCT +/* #undef NLIST_STRUCT */ /* Define if your C compiler doesn't accept -c and -o together. */ -#undef NO_MINUS_C_MINUS_O +/* #undef NO_MINUS_C_MINUS_O */ /* Define to `int' if doesn't define. */ #undef pid_t @@ -125,7 +127,7 @@ /* Define if the system does not provide POSIX.1 features except with this defined. */ -#undef _POSIX_1_SOURCE +/* #undef _POSIX_1_SOURCE */ /* Define if you need to in order for stat and other things to work. */ #undef _POSIX_SOURCE @@ -138,7 +140,7 @@ /* Define if the setvbuf function takes the buffering type as its second argument and the buffer pointer as the third, as on System V before release 3. */ -#undef SETVBUF_REVERSED +/* #undef SETVBUF_REVERSED */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be @@ -147,34 +149,34 @@ STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ -#undef STACK_DIRECTION +/* #undef STACK_DIRECTION */ /* Define if the `S_IS*' macros in do not work properly. */ -#undef STAT_MACROS_BROKEN +/* #undef STAT_MACROS_BROKEN */ /* Define if you have the ANSI C header files. */ #undef STDC_HEADERS #define STDC_HEADERS 1 /* Define on System V Release 4. */ -#undef SVR4 +/* #undef SVR4 */ /* Define if `sys_siglist' is declared by . */ -#undef SYS_SIGLIST_DECLARED +/* #undef SYS_SIGLIST_DECLARED */ /* Define to `int' if doesn't define. */ #undef uid_t #define uid_t int /* Define for Encore UMAX. */ -#undef UMAX +/* #undef UMAX */ /* Define for Encore UMAX 4.3 that has instead of . */ -#undef UMAX4_3 +/* #undef UMAX4_3 */ /* Define vfork as fork if vfork does not work. */ -#undef vfork +/* #undef vfork */ /* Name of this package (needed by automake) */ #define PACKAGE "%PACKAGE%" @@ -187,16 +189,16 @@ #define SCCS_GET "echo no sccs get" /* Define this if the SCCS `get' command understands the `-G' option. */ -#undef SCCS_GET_MINUS_G +/* #undef SCCS_GET_MINUS_G */ /* Define this if the C library defines the variable `sys_siglist'. */ -#undef HAVE_SYS_SIGLIST +/* #undef HAVE_SYS_SIGLIST */ /* Define this if the C library defines the variable `_sys_siglist'. */ -#undef HAVE__SYS_SIGLIST +/* #undef HAVE__SYS_SIGLIST */ /* Define this if you have the `union wait' type in . */ -#undef HAVE_UNION_WAIT +/* #undef HAVE_UNION_WAIT */ /* Define if you have the dup2 function. */ #undef HAVE_DUP2 @@ -207,45 +209,67 @@ #define HAVE_GETCWD 1 /* Define if you have the getgroups function. */ -#undef HAVE_GETGROUPS +/* #undef HAVE_GETGROUPS */ + +/* Define if you have the gethostbyname function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define if you have the gethostname function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define if you have the getloadavg function. */ +/* #undef HAVE_GETLOADAVG */ + +/* Define if you have the memmove function. */ +#undef HAVE_MEMMOVE +#define HAVE_MEMMOVE 1 /* Define if you have the mktemp function. */ #undef HAVE_MKTEMP #define HAVE_MKTEMP 1 /* Define if you have the psignal function. */ -#undef HAVE_PSIGNAL +/* #undef HAVE_PSIGNAL */ + +/* Define if you have the pstat_getdynamic function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ /* Define if you have the setegid function. */ -#undef HAVE_SETEGID +/* #undef HAVE_SETEGID */ /* Define if you have the seteuid function. */ -#undef HAVE_SETEUID +/* #undef HAVE_SETEUID */ /* Define if you have the setlinebuf function. */ -#undef HAVE_SETLINEBUF +/* #undef HAVE_SETLINEBUF */ /* Define if you have the setregid function. */ -#undef HAVE_SETREGID +/* #undef HAVE_SETREGID */ /* Define if you have the setreuid function. */ -#undef HAVE_SETREUID +/* #undef HAVE_SETREUID */ /* Define if you have the sigsetmask function. */ -#undef HAVE_SIGSETMASK +/* #undef HAVE_SIGSETMASK */ + +/* Define if you have the socket function. */ +/* #undef HAVE_SOCKET */ + +/* Define if you have the strcasecmp function. */ +/* #undef HAVE_STRCASECMP */ /* Define if you have the strerror function. */ #undef HAVE_STRERROR #define HAVE_STRERROR 1 /* Define if you have the strsignal function. */ -#undef HAVE_STRSIGNAL +/* #undef HAVE_STRSIGNAL */ /* Define if you have the wait3 function. */ -#undef HAVE_WAIT3 +/* #undef HAVE_WAIT3 */ /* Define if you have the waitpid function. */ -#undef HAVE_WAITPID +/* #undef HAVE_WAITPID */ /* Define if you have the header file. */ #undef HAVE_DIRENT_H @@ -260,43 +284,46 @@ #define HAVE_LIMITS_H 1 /* Define if you have the header file. */ -#undef HAVE_MACH_MACH_H +/* #undef HAVE_MACH_MACH_H */ /* Define if you have the header file. */ #undef HAVE_MEMORY_H #define HAVE_MEMORY_H 1 /* Define if you have the header file. */ -#undef HAVE_NDIR_H +/* #undef HAVE_NDIR_H */ /* Define if you have the header file. */ #undef HAVE_STRING_H #define HAVE_STRING_H 1 /* Define if you have the header file. */ -#undef HAVE_SYS_DIR_H +/* #undef HAVE_SYS_DIR_H */ /* Define if you have the header file. */ -#undef HAVE_SYS_NDIR_H +/* #undef HAVE_SYS_NDIR_H */ /* Define if you have the header file. */ -#undef HAVE_SYS_PARAM_H +/* #undef HAVE_SYS_PARAM_H */ /* Define if you have the header file. */ #undef HAVE_SYS_TIMEB_H #define HAVE_SYS_TIMEB_H 1 /* Define if you have the header file. */ -#undef HAVE_SYS_WAIT_H +/* #undef HAVE_SYS_WAIT_H */ /* Define if you have the header file. */ -#undef HAVE_UNISTD_H +/* #undef HAVE_UNISTD_H */ /* Define if you have the dgc library (-ldgc). */ -#undef HAVE_LIBDGC +/* #undef HAVE_LIBDGC */ + +/* Define if you have the kstat library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ /* Define if you have the sun library (-lsun). */ -#undef HAVE_LIBSUN +/* #undef HAVE_LIBSUN */ /* * Refer to README.W32 for info on the following settings diff --git a/configure.in b/configure.in index 8fb99f71..ebc9cdff 100644 --- a/configure.in +++ b/configure.in @@ -3,9 +3,8 @@ AC_REVISION([$Id$]) AC_PREREQ(2.12)dnl dnl Minimum Autoconf version required. AC_INIT(vpath.c)dnl dnl A distinctive file to look for in srcdir. -AM_INIT_AUTOMAKE(make, 3.77) +AM_INIT_AUTOMAKE(make, 3.77.90) AM_CONFIG_HEADER(config.h) -AC_CONFIG_SUBDIRS(glob) AM_CONDITIONAL(MAINT_MAKEFILE, test -r $srcdir/maintMakefile) @@ -14,6 +13,8 @@ dnl Regular configure stuff AC_PROG_MAKE_SET AC_PROG_CC AC_PROG_INSTALL +AC_CHECK_PROG(AR, ar, ar, ar) +AC_PROG_RANLIB AC_PROG_CPP dnl Later checks need this. dnl AC_ARG_PROGRAM -- implied by AM_INIT_AUTOMAKE; gives errors if run twice. AC_AIX @@ -30,12 +31,15 @@ AC_HEADER_DIRENT AC_TYPE_UID_T dnl Also does gid_t. AC_TYPE_PID_T AC_TYPE_SIGNAL -AC_CHECK_HEADERS(unistd.h limits.h sys/param.h fcntl.h string.h memory.h \ - sys/timeb.h) +AC_CHECK_HEADERS(stdlib.h unistd.h limits.h sys/param.h fcntl.h string.h \ + memory.h sys/timeb.h) AC_PROG_CC_C_O AC_C_CONST dnl getopt needs this. AC_HEADER_STAT +AC_STRUCT_ST_MTIM_NSEC +jm_AC_TYPE_UINTMAX_T + AC_SUBST(LIBOBJS) AC_DEFUN(AC_CHECK_SYMBOL, [dnl @@ -51,19 +55,25 @@ changequote([,])dnl fi AC_MSG_RESULT($ac_cv_check_symbol_$1)])dnl +# clock_gettime is in -lposix4 in Solaris 2.6. +AC_CHECK_LIB(posix4, clock_gettime) + AC_CHECK_FUNCS(memmove psignal mktemp pstat_getdynamic \ - dup2 getcwd sigsetmask getgroups setlinebuf \ + clock_gettime dup2 getcwd sigsetmask getgroups setlinebuf \ seteuid setegid setreuid setregid strerror strsignal) AC_CHECK_SYMBOL(sys_siglist) AC_FUNC_ALLOCA AC_FUNC_VFORK +AC_FUNC_VPRINTF +AC_FUNC_STRCOLL +AC_FUNC_CLOSEDIR_VOID AC_FUNC_SETVBUF_REVERSED AC_FUNC_GETLOADAVG AC_CHECK_LIB(kstat, kstat_open) -AC_FUNC_STRCOLL # Check out the wait reality. -AC_CHECK_HEADERS(sys/wait.h) AC_CHECK_FUNCS(waitpid wait3) +AC_CHECK_HEADERS(sys/wait.h) +AC_CHECK_FUNCS(waitpid wait3) AC_MSG_CHECKING(for union wait) AC_CACHE_VAL(make_cv_union_wait, [dnl AC_TRY_LINK([#include @@ -137,7 +147,7 @@ if ( /usr/sccs/admin -n s.conftest || admin -n s.conftest ) >/dev/null 2>&1 && fi rm -f s.conftest conftoast -AC_OUTPUT(Makefile build.sh) +AC_OUTPUT(Makefile glob/Makefile build.sh) case "$make_badcust" in yes) echo @@ -159,6 +169,15 @@ case "$with_customs" in fi ;; esac +case "$ac_cv_func_waitpid/$ac_cv_func_wait3" in + no/no) echo + echo "WARNING: Your system has neither waitpid() nor wait3()." + echo " Without one of these, signal handling is unreliable." + echo " You should be aware that run GNU make with -j could" + echo " result in erratic behavior." + echo ;; +esac + dnl Local Variables: dnl comment-start: "dnl " dnl comment-end: "" diff --git a/default.c b/default.c index 653bc81f..06f56fad 100644 --- a/default.c +++ b/default.c @@ -468,7 +468,7 @@ install_default_suffix_rules () if (f->cmds == 0) { f->cmds = (struct commands *) xmalloc (sizeof (struct commands)); - f->cmds->filename = 0; + f->cmds->fileinfo.filenm = 0; f->cmds->commands = s[1]; f->cmds->command_lines = 0; } diff --git a/dep.h b/dep.h index fa3e0733..2f9561c9 100644 --- a/dep.h +++ b/dep.h @@ -16,6 +16,16 @@ 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. */ +/* Flag bits for the second argument to `read_makefile'. + These flags are saved in the `changed' field of each + `struct dep' in the chain returned by `read_all_makefiles'. */ + +#define RM_NO_DEFAULT_GOAL (1 << 0) /* Do not set default goal. */ +#define RM_INCLUDED (1 << 1) /* Search makefile search path. */ +#define RM_DONTCARE (1 << 2) /* No error if it doesn't exist. */ +#define RM_NO_TILDE (1 << 3) /* Don't expand ~ in file name. */ +#define RM_NOFLAG 0 + /* Structure representing one dependency of a file. Each struct file's `deps' points to a chain of these, chained through the `next'. @@ -59,13 +69,7 @@ extern struct nameseq *ar_glob PARAMS ((char *arname, char *member_pattern, unsi extern char *dep_name (); #endif +extern struct dep *copy_dep_chain PARAMS ((struct dep *d)); extern struct dep *read_all_makefiles PARAMS ((char **makefiles)); - -/* Flag bits for the second argument to `read_makefile'. - These flags are saved in the `changed' field of each - `struct dep' in the chain returned by `read_all_makefiles'. */ -#define RM_NO_DEFAULT_GOAL (1 << 0) /* Do not set default goal. */ -#define RM_INCLUDED (1 << 1) /* Search makefile search path. */ -#define RM_DONTCARE (1 << 2) /* No error if it doesn't exist. */ -#define RM_NO_TILDE (1 << 3) /* Don't expand ~ in file name. */ -#define RM_NOFLAG 0 +extern int update_goal_chain PARAMS ((struct dep *goals, int makefiles)); +extern void uniquize_deps PARAMS ((struct dep *)); diff --git a/expand.c b/expand.c index 3f4bcfce..31c40249 100644 --- a/expand.c +++ b/expand.c @@ -95,17 +95,9 @@ recursively_expand (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); - } + /* Expanding V causes infinite recursion. Lose. */ + fatal (reading_file, + "Recursive variable `%s' references itself (eventually)", v->name); v->expanding = 1; value = allocated_variable_expand (v->value); @@ -125,14 +117,8 @@ warn_undefined (name, length) unsigned int length; { if (warn_undefined_variables_flag) - { - static const char warnmsg[] = "warning: undefined variable `%.*s'"; - if (reading_filename != 0) - makefile_error (reading_filename, *reading_lineno_ptr, - warnmsg, length, name); - else - error (warnmsg, length, name); - } + error (reading_file, + "warning: undefined variable `%.*s'", (int)length, name); } /* Expand a simple reference to variable NAME, which is LENGTH chars long. */ @@ -243,14 +229,8 @@ variable_expand_string (line, string, length) end = index (beg, closeparen); if (end == 0) - { - /* Unterminated variable reference. */ - if (reading_filename != 0) - makefile_fatal (reading_filename, *reading_lineno_ptr, - "unterminated variable reference"); - else - fatal ("unterminated variable reference"); - } + /* Unterminated variable reference. */ + fatal (reading_file, "unterminated variable reference"); p1 = lindex (beg, end, '$'); if (p1 != 0) { @@ -460,8 +440,7 @@ variable_expand_for_file (line, file) save = current_variable_set_list; current_variable_set_list = file->variables; - reading_filename = file->cmds->filename; - reading_lineno_ptr = &file->cmds->lineno; + reading_file = &file->cmds->fileinfo; fnext = file->variables->next; /* See if there's a pattern-specific variable struct for this target. */ if (!file->pat_searched) @@ -476,8 +455,7 @@ variable_expand_for_file (line, file) } result = variable_expand (line); current_variable_set_list = save; - reading_filename = 0; - reading_lineno_ptr = 0; + reading_file = 0; file->variables->next = fnext; return result; diff --git a/file.c b/file.c index a60e70fb..22e95840 100644 --- a/file.c +++ b/file.c @@ -16,13 +16,14 @@ 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 + #include "make.h" #include "dep.h" #include "filedef.h" #include "job.h" #include "commands.h" #include "variable.h" -#include /* Hash table of files the makefile knows how to make. */ @@ -294,22 +295,22 @@ file_hash_enter (file, name, oldhash, oldname) /* 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. */ - if (oldfile->cmds->filename != 0) - makefile_error (file->cmds->filename, file->cmds->lineno, - "Commands were specified for \ -file `%s' at %s:%u,", - oldname, oldfile->cmds->filename, - oldfile->cmds->lineno); + if (oldfile->cmds->fileinfo.filenm != 0) + error (&file->cmds->fileinfo, + "Commands were specified for \ +file `%s' at %s:%lu,", + oldname, oldfile->cmds->fileinfo.filenm, + oldfile->cmds->fileinfo.lineno); else - makefile_error (file->cmds->filename, file->cmds->lineno, + error (&file->cmds->fileinfo, "Commands for file `%s' were found by \ implicit rule search,", oldname); - makefile_error (file->cmds->filename, file->cmds->lineno, + error (&file->cmds->fileinfo, "but `%s' is now considered the same file \ as `%s'.", oldname, name); - makefile_error (file->cmds->filename, file->cmds->lineno, + error (&file->cmds->fileinfo, "Commands for `%s' will be ignored \ in favor of those for `%s'.", name, oldname); @@ -331,12 +332,12 @@ in favor of those for `%s'.", merge_variable_set_lists (&oldfile->variables, file->variables); if (oldfile->double_colon && file->is_target && !file->double_colon) - fatal ("can't rename single-colon `%s' to double-colon `%s'", + fatal (NILF, "can't rename single-colon `%s' to double-colon `%s'", oldname, name); if (!oldfile->double_colon && file->double_colon) { if (oldfile->is_target) - fatal ("can't rename double-colon `%s' to single-colon `%s'", + fatal (NILF, "can't rename double-colon `%s' to single-colon `%s'", oldname, name); else oldfile->double_colon = file->double_colon; @@ -401,7 +402,7 @@ remove_intermediates (sig) if (!f->dontcare) { if (sig) - error ("*** Deleting intermediate file `%s'", f->name); + error (NILF, "*** Deleting intermediate file `%s'", f->name); else if (!silent_flag) { if (! doneany) @@ -465,7 +466,7 @@ snap_deps () { /* Mark this file as phony and nonexistent. */ f2->phony = 1; - f2->last_mtime = (time_t) -1; + f2->last_mtime = (FILE_TIMESTAMP) -1; } for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev) @@ -549,6 +550,51 @@ set_command_state (file, state) d->file->command_state = state; } +/* Get and print file timestamps. */ + +FILE_TIMESTAMP +file_timestamp_now () +{ +#if HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME + struct timespec timespec; + if (clock_gettime (CLOCK_REALTIME, ×pec) == 0) + return FILE_TIMESTAMP_FROM_S_AND_NS (timespec.tv_sec, timespec.tv_nsec); +#endif + return FILE_TIMESTAMP_FROM_S_AND_NS (time ((time_t *) 0), 0); +} + +void +file_timestamp_sprintf (p, ts) + char *p; + FILE_TIMESTAMP ts; +{ + time_t t = FILE_TIMESTAMP_S (ts); + struct tm *tm = localtime (&t); + + if (tm) + sprintf (p, "%04d-%02d-%02d %02d:%02d:%02d", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (t < 0) + sprintf (p, "%ld", (long) t); + else + sprintf (p, "%lu", (unsigned long) t); + p += strlen (p); + + /* Append nanoseconds as a fraction, but remove trailing zeros. + We don't know the actual timestamp resolution, since clock_getres + applies only to local times, whereas this timestamp might come + from a remote filesystem. So removing trailing zeros is the + best guess that we can do. */ + sprintf (p, ".%09ld", (long) FILE_TIMESTAMP_NS (ts)); + p += strlen (p) - 1; + while (*p == '0') + p--; + p += *p != '.'; + + *p = '\0'; +} + /* Print the data base of files. */ static void @@ -587,13 +633,16 @@ print_file (f) printf (" %s", dep_name (d)); putchar ('\n'); } - if (f->last_mtime == (time_t) 0) + if (f->last_mtime == 0) puts ("# Modification time never checked."); - else if (f->last_mtime == (time_t) -1) + else if (f->last_mtime == (FILE_TIMESTAMP) -1) puts ("# File does not exist."); else - printf ("# Last modified %.24s (%ld)\n", - ctime (&f->last_mtime), (long int) f->last_mtime); + { + char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; + file_timestamp_sprintf (buf, f->last_mtime); + printf ("# Last modified %s\n", buf); + } printf ("# File has%s been updated.\n", f->updated ? "" : " not"); switch (f->command_state) diff --git a/filedef.h b/filedef.h index a5de0a11..6ee52143 100644 --- a/filedef.h +++ b/filedef.h @@ -16,6 +16,7 @@ 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'. */ @@ -32,7 +33,7 @@ struct file 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. */ + FILE_TIMESTAMP 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. */ @@ -96,12 +97,63 @@ 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 (), rehash_file (), file_hash_enter (); -extern void set_command_state (); +extern struct file *lookup_file PARAMS ((char *name)); +extern struct file *enter_file PARAMS ((char *name)); +extern void remove_intermediates PARAMS ((int sig)); +extern void snap_deps PARAMS ((void)); +extern void rename_file PARAMS ((struct file *file, char *name)); +extern void rehash_file PARAMS ((struct file *file, char *name)); +extern void file_hash_enter PARAMS ((struct file *file, char *name, + unsigned int oldhash, char *oldname)); +extern void set_command_state PARAMS ((struct file *file, int state)); +extern void notice_finished_file PARAMS ((struct file *file)); +#if ST_MTIM_NSEC +# define FILE_TIMESTAMP_STAT_MODTIME(st) \ + FILE_TIMESTAMP_FROM_S_AND_NS ((st).st_mtim.tv_sec, \ + (st).st_mtim.ST_MTIM_NSEC) +# define FILE_TIMESTAMPS_PER_S \ + MIN ((FILE_TIMESTAMP) 1000000000, \ + (INTEGER_TYPE_MAXIMUM (FILE_TIMESTAMP) \ + / INTEGER_TYPE_MAXIMUM (time_t))) +#else +# define FILE_TIMESTAMP_STAT_MODTIME(st) ((st).st_mtime) +# define FILE_TIMESTAMPS_PER_S 1 +#endif + +#define FILE_TIMESTAMP_FROM_S_AND_NS(s, ns) \ + ((s) * FILE_TIMESTAMPS_PER_S \ + + (ns) * FILE_TIMESTAMPS_PER_S / 1000000000) +#define FILE_TIMESTAMP_DIV(a, b) ((a)/(b) - ((a)%(b) < 0)) +#define FILE_TIMESTAMP_MOD(a, b) ((a)%(b) + ((a)%(b) < 0) * (b)) +#define FILE_TIMESTAMP_S(ts) FILE_TIMESTAMP_DIV ((ts), FILE_TIMESTAMPS_PER_S) +#define FILE_TIMESTAMP_NS(ts) \ + (((FILE_TIMESTAMP_MOD ((ts), FILE_TIMESTAMPS_PER_S) * 1000000000) \ + + (FILE_TIMESTAMPS_PER_S - 1)) \ + / FILE_TIMESTAMPS_PER_S) + +/* Upper bound on length of string "YYYY-MM-DD HH:MM:SS.NNNNNNNNN" + representing a file timestamp. The upper bound is not necessarily 19, + since the year might be less than -999 or greater than 9999. + + Subtract one for the sign bit if in case file timestamps can be negative; + subtract FLOOR_LOG2_SECONDS_PER_YEAR to yield an upper bound on how many + file timestamp bits might affect the year; + 302 / 1000 is log10 (2) rounded up; + add one for integer division truncation; + add one more for a minus sign if file timestamps can be negative; + add 4 to allow for any 4-digit epoch year (e.g. 1970); + add 25 to allow for "-MM-DD HH:MM:SS.NNNNNNNNN". */ +#define FLOOR_LOG2_SECONDS_PER_YEAR 24 +#define FILE_TIMESTAMP_PRINT_LEN_BOUND \ + (((sizeof (FILE_TIMESTAMP) * CHAR_BIT - 1 - FLOOR_LOG2_SECONDS_PER_YEAR) \ + * 302 / 1000) \ + + 1 + 1 + 4 + 25) + +extern FILE_TIMESTAMP file_timestamp_now PARAMS ((void)); +extern void file_timestamp_sprintf PARAMS ((char *p, FILE_TIMESTAMP ts)); + /* Return the mtime of file F (a struct file *), caching it. The value is -1 if the file does not exist. */ #define file_mtime(f) file_mtime_1 ((f), 1) @@ -110,9 +162,9 @@ extern void set_command_state (); we don't find it. The value is -1 if the file does not exist. */ #define file_mtime_no_search(f) file_mtime_1 ((f), 0) -extern time_t f_mtime (); +extern FILE_TIMESTAMP f_mtime PARAMS ((struct file *file, int search)); #define file_mtime_1(f, v) \ - ((f)->last_mtime != (time_t) 0 ? (f)->last_mtime : f_mtime ((f), v)) + ((f)->last_mtime ? (f)->last_mtime : f_mtime ((f), v)) /* Modtime value to use for `infinitely new'. We used to get the current time from the system and use that whenever we wanted `new'. But that causes @@ -121,12 +173,13 @@ extern time_t f_mtime (); targets, which need to be considered newer than anything that depends on them, even if said dependents' modtimes are in the future. - If time_t is unsigned, its maximum value is the same as "(time_t) -1", - so use one less than that, because -1 is used for non-existing files. */ + If FILE_TIMESTAMP is unsigned, its maximum value is the same as + ((FILE_TIMESTAMP) -1), so use one less than that, because -1 is + used for non-existing files. */ #define NEW_MTIME \ - (INTEGER_TYPE_SIGNED (time_t) \ - ? INTEGER_TYPE_MAXIMUM (time_t) \ - : (INTEGER_TYPE_MAXIMUM (time_t) - 1)) + (INTEGER_TYPE_SIGNED (FILE_TIMESTAMP) \ + ? INTEGER_TYPE_MAXIMUM (FILE_TIMESTAMP) \ + : (INTEGER_TYPE_MAXIMUM (FILE_TIMESTAMP) - 1)) #define check_renamed(file) \ while ((file)->renamed != 0) (file) = (file)->renamed /* No ; here. */ diff --git a/function.c b/function.c index 198ab442..13196ebf 100644 --- a/function.c +++ b/function.c @@ -319,12 +319,8 @@ int shell_function_pid = 0, shell_function_completed; /* Note this absorbs a semicolon and is safe to use in conditionals. */ #define BADARGS(func) do { \ - 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); } while (0) + fatal (reading_file, "insufficient arguments to function `%s'", func); \ + } while (0) static char * expand_function (o, function, text, end) @@ -395,11 +391,11 @@ expand_function (o, function, text, end) #endif /* Not Amiga. */ /* For error messages. */ - if (reading_filename != 0) + if (reading_file != 0) { - error_prefix = (char *) alloca (strlen (reading_filename) + 100); + error_prefix = (char *) alloca (strlen(reading_file->filenm)+100); sprintf (error_prefix, - "%s:%u: ", reading_filename, *reading_lineno_ptr); + "%s:%lu: ", reading_file->filenm, reading_file->lineno); } else error_prefix = ""; @@ -417,7 +413,7 @@ expand_function (o, function, text, end) 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) { - fatal("create_child_process: DuplicateHandle(In) failed (e=%d)\n", + fatal (NILF, "create_child_process: DuplicateHandle(In) failed (e=%d)\n", GetLastError()); } if (DuplicateHandle(GetCurrentProcess(), @@ -427,17 +423,17 @@ expand_function (o, function, text, end) 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) { - fatal("create_child_process: DuplicateHandle(Err) failed (e=%d)\n", + fatal (NILF, "create_child_process: DuplicateHandle(Err) failed (e=%d)\n", GetLastError()); } if (!CreatePipe(&hChildOutRd, &hChildOutWr, &saAttr, 0)) - fatal("CreatePipe() failed (e=%d)\n", GetLastError()); + fatal (NILF, "CreatePipe() failed (e=%d)\n", GetLastError()); hProcess = process_init_fd(hIn, hChildOutWr, hErr); if (!hProcess) - fatal("expand_function: process_init_fd() failed\n"); + fatal (NILF, "expand_function: process_init_fd() failed\n"); else process_register(hProcess); @@ -447,7 +443,7 @@ expand_function (o, function, text, end) if (!process_begin(hProcess, argv, envp, argv[0], NULL)) pid = (int) hProcess; else - fatal("expand_function: unable to launch process (e=%d)\n", + fatal (NILF, "expand_function: unable to launch process (e=%d)\n", process_last_err(hProcess)); /* set up to read data from child */ @@ -1178,24 +1174,13 @@ expand_function (o, function, text, 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"); - } + fatal (reading_file, + "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"); - } + fatal (reading_file, + "the `word' function takes a one-origin index argument"); p2 = p3; while ((p = find_next_token (&p2, &len)) != 0) @@ -1245,13 +1230,8 @@ index argument"); /* 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 `wordlist' function"); - else - fatal ("non-numeric first argument to `wordlist' function"); - } + fatal (reading_file, + "non-numeric first argument to `wordlist' function"); i = (unsigned int)atoi(text); free (text); @@ -1274,13 +1254,8 @@ index 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 second argument to `wordlist' function"); - else - fatal ("non-numeric second argument to `wordlist' function"); - } + fatal (reading_file, + "non-numeric second argument to `wordlist' function"); j = (unsigned int)atoi(text); free (text); @@ -1545,15 +1520,9 @@ handle_function (op, stringp) } if (count >= 0) - { - static const char errmsg[] - = "unterminated call to function `%s': missing `%c'"; - if (reading_filename == 0) - fatal (errmsg, function_table[code].name, closeparen); - else - makefile_fatal (reading_filename, *reading_lineno_ptr, errmsg, - function_table[code].name, closeparen); - } + fatal (reading_file, + "unterminated call to function `%s': missing `%c'", + function_table[code].name, closeparen); /* We found the end; expand the function call. */ diff --git a/getloadavg.c b/getloadavg.c index 7c1cc800..36245efc 100644 --- a/getloadavg.c +++ b/getloadavg.c @@ -1038,7 +1038,7 @@ getloadavg (loadavg, nelem) #endif /* ! HAVE_GETLOADAVG */ #ifdef TEST -void +int main (argc, argv) int argc; char **argv; diff --git a/glob/ChangeLog b/glob/ChangeLog index e3854a5a..b7e85ad0 100644 --- a/glob/ChangeLog +++ b/glob/ChangeLog @@ -1,3 +1,8 @@ +1998-08-05 Paul D. Smith + + * configure.in: Remove; configuration for glob is handled by the + make configure.in. + 1998-07-29 Paul D. Smith * glob.c, fnmatch.c: New versions from the GLIBC folks (Ulrich diff --git a/implicit.c b/implicit.c index a999a0f6..4be5cf55 100644 --- a/implicit.c +++ b/implicit.c @@ -148,7 +148,7 @@ pattern_search (file, archive, depth, recursions) that is not just `%'. */ int specific_rule_matched = 0; - register unsigned int i; + register unsigned int i = 0; /* uninit checks OK */ register struct rule *rule; register struct dep *dep; @@ -342,6 +342,8 @@ pattern_search (file, archive, depth, recursions) deps_found = 0; for (dep = rule->deps; dep != 0; dep = dep->next) { + struct file *fp; + /* If the dependency name has a %, substitute the stem. */ p = index (dep_name (dep), '%'); if (p != 0) @@ -390,9 +392,12 @@ pattern_search (file, archive, depth, recursions) dependency file we are actually looking for is in a different directory (the one gotten by prepending FILENAME's directory), so it might actually exist. */ + /* If we find a file but the intermediate flag is set, then it + was put here by a .INTERMEDIATE: rule so ignore it. */ if ((!dep->changed || check_lastslash) - && (lookup_file (p) != 0 || file_exists_p (p))) + && (((fp = lookup_file (p)) != 0 && !fp->intermediate) + || file_exists_p (p))) { found_files[deps_found++] = savestring (p, strlen (p)); continue; @@ -400,7 +405,7 @@ pattern_search (file, archive, depth, recursions) /* This code, given FILENAME = "lib/foo.o", dependency name "lib/foo.c", and VPATH=src, searches for "src/lib/foo.c". */ vp = p; - if (vpath_search (&vp, (time_t *) 0)) + if (vpath_search (&vp, (FILE_TIMESTAMP *) 0)) { DEBUGP2 ("Found dependency `%s' as VPATH `%s'\n", p, vp); strcpy(vp, p); diff --git a/job.c b/job.c index 91bc30b4..fcdd2f1d 100644 --- a/job.c +++ b/job.c @@ -29,25 +29,25 @@ char *default_shell = "sh.exe"; int no_default_sh_exe = 1; int batch_mode_shell = 1; #else /* WINDOWS32 */ -#ifdef _AMIGA +# ifdef _AMIGA char default_shell[] = ""; extern int MyExecute (char **); -#else /* _AMIGA */ -#ifdef __MSDOS__ +# else /* _AMIGA */ +# ifdef __MSDOS__ /* The default shell is a pointer so we can change it if Makefile says so. It is without an explicit path so we get a chance to search the $PATH for it (since MSDOS doesn't have standard directories we could trust). */ char *default_shell = "command.com"; -#else /* __MSDOS__ */ +# else /* __MSDOS__ */ char default_shell[] = "/bin/sh"; -#endif /* __MSDOS__ */ +# endif /* __MSDOS__ */ int batch_mode_shell = 0; -#endif /* _AMIGA */ +# endif /* _AMIGA */ #endif /* WINDOWS32 */ #ifdef __MSDOS__ -#include +# include static int execute_by_shell; static int dos_pid = 123; int dos_status; @@ -55,7 +55,7 @@ int dos_command_running; #endif /* __MSDOS__ */ #ifdef _AMIGA -#include +# include static int amiga_pid = 123; static int amiga_status; static char amiga_bname[32]; @@ -63,101 +63,101 @@ static int amiga_batch_file; #endif /* Amiga. */ #ifdef VMS -#include -#include -#include -#include +# include +# include +# include +# include #endif #ifdef WINDOWS32 -#include -#include -#include -#include "sub_proc.h" -#include "w32err.h" -#include "pathstuff.h" +# include +# include +# include +# include "sub_proc.h" +# include "w32err.h" +# include "pathstuff.h" #endif /* WINDOWS32 */ #ifdef HAVE_FCNTL_H -#include +# include #else -#include +# include #endif #if defined (HAVE_SYS_WAIT_H) || defined (HAVE_UNION_WAIT) -#include +# include #endif -#ifdef HAVE_WAITPID -#define WAIT_NOHANG(status) waitpid (-1, (status), WNOHANG) +#ifdef HAVE_WAITPID +# define WAIT_NOHANG(status) waitpid (-1, (status), WNOHANG) #else /* Don't have waitpid. */ -#ifdef HAVE_WAIT3 -#ifndef wait3 +# ifdef HAVE_WAIT3 +# ifndef wait3 extern int wait3 (); -#endif -#define WAIT_NOHANG(status) wait3 ((status), WNOHANG, (struct rusage *) 0) -#endif /* Have wait3. */ -#endif /* Have waitpid. */ +# endif +# define WAIT_NOHANG(status) wait3 ((status), WNOHANG, (struct rusage *) 0) +# endif /* Have wait3. */ +#endif /* Have waitpid. */ -#if !defined (wait) && !defined (POSIX) +#if !defined (wait) && !defined (POSIX) extern int wait (); #endif #ifndef HAVE_UNION_WAIT -#define WAIT_T int +# 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 +# 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 /* Have `union wait'. */ -#define WAIT_T union wait -#ifndef WTERMSIG -#define WTERMSIG(x) ((x).w_termsig) -#endif -#ifndef WCOREDUMP -#define WCOREDUMP(x) ((x).w_coredump) -#endif -#ifndef WEXITSTATUS -#define WEXITSTATUS(x) ((x).w_retcode) -#endif -#ifndef WIFSIGNALED -#define WIFSIGNALED(x) (WTERMSIG(x) != 0) -#endif -#ifndef WIFEXITED -#define WIFEXITED(x) (WTERMSIG(x) == 0) -#endif +# define WAIT_T union wait +# ifndef WTERMSIG +# define WTERMSIG(x) ((x).w_termsig) +# endif +# ifndef WCOREDUMP +# define WCOREDUMP(x) ((x).w_coredump) +# endif +# ifndef WEXITSTATUS +# define WEXITSTATUS(x) ((x).w_retcode) +# endif +# ifndef WIFSIGNALED +# define WIFSIGNALED(x) (WTERMSIG(x) != 0) +# endif +# ifndef WIFEXITED +# define WIFEXITED(x) (WTERMSIG(x) == 0) +# endif #endif /* Don't have `union wait'. */ #ifdef VMS -static int vms_jobsefnmask=0; +static int vms_jobsefnmask = 0; #endif /* !VMS */ #ifndef HAVE_UNISTD_H extern int dup2 (); extern int execve (); extern void _exit (); -#ifndef VMS +# ifndef VMS extern int geteuid (); extern int getegid (); extern int setgid (); extern int getgid (); -#endif +# endif #endif extern char *allocated_variable_expand_for_file PARAMS ((char *line, struct file *file)); @@ -169,7 +169,6 @@ extern int start_remote_job_p PARAMS ((int)); extern int remote_status PARAMS ((int *exit_code_ptr, int *signal_ptr, int *coredump_ptr, int block)); -RETSIGTYPE child_handler PARAMS ((int)); static void free_child PARAMS ((struct child *)); static void start_job_command PARAMS ((struct child *child)); static int load_too_high PARAMS ((void)); @@ -224,21 +223,19 @@ child_error (target_name, exit_code, exit_sig, coredump, ignored) #ifdef VMS if (!(exit_code & 1)) - error("*** [%s] Error 0x%x%s", target_name, exit_code, ((ignored)? " (ignored)" : "")); + error (NILF, "*** [%s] Error 0x%x%s", target_name, exit_code, ((ignored)? " (ignored)" : "")); #else if (exit_sig == 0) - error (ignored ? "[%s] Error %d (ignored)" : + error (NILF, ignored ? "[%s] Error %d (ignored)" : "*** [%s] Error %d", target_name, exit_code); else - error ("*** [%s] %s%s", + error (NILF, "*** [%s] %s%s", target_name, strsignal (exit_sig), coredump ? " (core dumped)" : ""); #endif /* VMS */ } -static unsigned int dead_children = 0; - #ifdef VMS /* Wait for nchildren children to terminate */ static void @@ -259,6 +256,13 @@ vmsWaitForChildren(int *status) #endif +/* If we can't use waitpid() or wait3(), then we use a signal handler + to track the number of SIGCHLD's we got. This is less robust. */ + +#ifndef WAIT_NOHANG + +static unsigned int dead_children = 0; + /* Notice that a child died. reap_children should be called when convenient. */ RETSIGTYPE @@ -271,6 +275,8 @@ child_handler (sig) printf ("Got a SIGCHLD; %d unreaped children.\n", dead_children); } +#endif /* WAIT_NOHANG */ + extern int shell_function_pid, shell_function_completed; /* Reap dead children, storing the returned status and the new command @@ -284,9 +290,12 @@ reap_children (block, err) int block, err; { WAIT_T status; +#ifdef WAIT_NOHANG + int dead_children = 1; /* Initially, assume we have some. */ +#endif while ((children != 0 || shell_function_pid != 0) && - (block || dead_children > 0)) + (block || dead_children)) { int remote = 0; register int pid; @@ -295,13 +304,14 @@ reap_children (block, err) int child_failed; int any_remote, any_local; - if (err && dead_children == 0) + if (err && block) { /* We might block for a while, so let the user know why. */ fflush (stdout); - error ("*** Waiting for unfinished jobs...."); + error (NILF, "*** Waiting for unfinished jobs...."); } +#ifndef WAIT_NOHANG /* We have one less dead child to reap. The test and decrement are not atomic; if it is compiled into: register = dead_children - 1; @@ -316,6 +326,7 @@ reap_children (block, err) if (dead_children > 0) --dead_children; +#endif any_remote = 0; any_local = shell_function_pid != 0; @@ -338,8 +349,12 @@ reap_children (block, err) else pid = 0; - if (pid < 0) + if (pid > 0) + /* We got a remote child. */ + remote = 1; + else if (pid < 0) { + /* A remote status command failed miserably. Punt. */ remote_status_lose: #ifdef EINTR if (errno == EINTR) @@ -347,11 +362,11 @@ reap_children (block, err) #endif pfatal_with_name ("remote_status"); } - else if (pid == 0) + else { -#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32) /* No remote children. Check for local children. */ +#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32) if (any_local) { #ifdef VMS @@ -371,15 +386,26 @@ reap_children (block, err) if (pid < 0) { + /* The wait*() failed miserably. Punt. */ #ifdef EINTR if (errno == EINTR) continue; #endif pfatal_with_name ("wait"); } - else if (pid == 0) + else if (pid > 0) { - /* No local children. */ + /* We got one; chop the status word up. */ + exit_code = WEXITSTATUS (status); + exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0; + coredump = WCOREDUMP (status); + } + else + { + /* No local children are dead. */ +#ifdef WAIT_NOHANG + dead_children = 0; +#endif if (block && any_remote) { /* Now try a blocking wait for a remote child. */ @@ -396,14 +422,7 @@ reap_children (block, err) else break; } - else - { - /* Chop the status word up. */ - exit_code = WEXITSTATUS (status); - exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0; - coredump = WCOREDUMP (status); - } -#else /* __MSDOS__, Amiga, WINDOWS32. */ +#endif /* !__MSDOS__, !Amiga, !WINDOWS32. */ #ifdef __MSDOS__ /* Life is very different on MSDOS. */ pid = dos_pid - 1; @@ -423,39 +442,35 @@ reap_children (block, err) coredump = 0; #endif /* _AMIGA */ #ifdef WINDOWS32 - { - HANDLE hPID; - int err; + { + HANDLE hPID; + int err; - /* wait for anything to finish */ - if (hPID = process_wait_for_any()) { + /* wait for anything to finish */ + if (hPID = process_wait_for_any()) { - /* was an error found on this process? */ - err = process_last_err(hPID); + /* was an error found on this process? */ + err = process_last_err(hPID); - /* get exit data */ - exit_code = process_exit_code(hPID); + /* get exit data */ + exit_code = process_exit_code(hPID); - if (err) - fprintf(stderr, "make (e=%d): %s", - exit_code, map_windows32_error_to_string(exit_code)); + if (err) + fprintf(stderr, "make (e=%d): %s", + exit_code, map_windows32_error_to_string(exit_code)); - /* signal */ - exit_sig = process_signal(hPID); + /* signal */ + exit_sig = process_signal(hPID); - /* cleanup process */ - process_cleanup(hPID); + /* cleanup process */ + process_cleanup(hPID); - coredump = 0; - } - pid = (int) hPID; - } + coredump = 0; + } + pid = (int) hPID; + } #endif /* WINDOWS32 */ -#endif /* Not __MSDOS__ */ } - else - /* We got a remote child. */ - remote = 1; /* Check if this is the child of the `shell' function. */ if (!remote && pid == shell_function_pid) @@ -478,14 +493,9 @@ reap_children (block, err) if (c == 0) { - /* An unknown child died. */ - 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); + /* An unknown child died. + Ignore it; it was inherited from our invoker. */ + continue; } else { @@ -495,17 +505,17 @@ reap_children (block, err) (unsigned long int) c, (long) c->pid, c->remote ? " (remote)" : ""); - if (c->sh_batch_file) { - if (debug_flag) - printf("Cleaning up temporary batch file %s\n", c->sh_batch_file); + if (c->sh_batch_file) { + if (debug_flag) + printf("Cleaning up temp batch file %s\n", c->sh_batch_file); - /* just try and remove, don't care if this fails */ - remove(c->sh_batch_file); + /* just try and remove, don't care if this fails */ + remove(c->sh_batch_file); - /* all done with memory */ - free(c->sh_batch_file); - c->sh_batch_file = NULL; - } + /* all done with memory */ + free(c->sh_batch_file); + c->sh_batch_file = NULL; + } /* If this child had the good stdin, say it is now free. */ if (c->good_stdin) @@ -661,12 +671,12 @@ extern sigset_t fatal_signal_set; void block_sigs () { -#ifdef POSIX +#ifdef POSIX (void) sigprocmask (SIG_BLOCK, &fatal_signal_set, (sigset_t *) 0); #else -#ifdef HAVE_SIGSETMASK +# ifdef HAVE_SIGSETMASK (void) sigblock (fatal_signal_mask); -#endif +# endif #endif } @@ -1098,9 +1108,9 @@ start_waiting_job (c) case cs_running: c->next = children; if (debug_flag) - printf ("Putting child 0x%08lx PID %05d%s on the chain.\n", + printf ("Putting child 0x%08lx PID %ld%s on the chain.\n", (unsigned long int) c, - c->pid, c->remote ? " (remote)" : ""); + (long) c->pid, c->remote ? " (remote)" : ""); children = c; /* One more job slot is in use. */ ++job_slots_used; @@ -1322,7 +1332,7 @@ load_too_high () { if (errno == 0) /* An errno value of zero means getloadavg is just unsupported. */ - error ("cannot enforce load limits on this operating system"); + error (NILF, "cannot enforce load limits on this operating system"); else perror_with_name ("cannot enforce load limit: ", "getloadavg"); } @@ -1427,8 +1437,7 @@ int vmsHandleChildTerm(struct child *child) break; default: - error ("internal error: `%s' command_state \ -%d in child_handler", c->file->name); + error (NILF, "internal error: `%s' command_state", c->file->name); abort (); break; } @@ -1682,7 +1691,7 @@ exec_command (argv, envp) switch (errno) { case ENOENT: - error ("%s: Command not found", argv[0]); + error (NILF, "%s: Command not found", argv[0]); break; case ENOEXEC: { @@ -1711,7 +1720,7 @@ exec_command (argv, envp) execvp (shell, new_argv); if (errno == ENOENT) - error ("%s: Shell program not found", shell); + error (NILF, "%s: Shell program not found", shell); else perror_with_name ("execvp: ", shell); break; @@ -2205,8 +2214,8 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) p = next_token (p); --p; - if (unixy_shell && !batch_mode_shell) - *ap++ = '\\'; + if (unixy_shell && !batch_mode_shell) + *ap++ = '\\'; *ap++ = ' '; continue; } @@ -2234,11 +2243,9 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) *ap = '\0'; #ifdef WINDOWS32 - /* - * Some shells do not work well when invoked as 'sh -c xxx' to run - * a command line (e.g. Cygnus GNUWIN32 sh.exe on WIN32 systems). - * In these cases, run commands via a script file. - */ + /* Some shells do not work well when invoked as 'sh -c xxx' to run a + command line (e.g. Cygnus GNUWIN32 sh.exe on WIN32 systems). In these + cases, run commands via a script file. */ if ((no_default_sh_exe || batch_mode_shell) && batch_filename_ptr) { FILE* batch = NULL; int id = GetCurrentProcessId(); @@ -2269,7 +2276,8 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) /* create batch file to execute command */ batch = fopen (*batch_filename_ptr, "w"); - fputs ("@echo off\n", batch); + if (!unixy_shell) + fputs ("@echo off\n", batch); fputs (command_ptr, batch); fputc ('\n', batch); fclose (batch); @@ -2305,7 +2313,7 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) } #else else - fatal("%s (line %d) Invalid shell context (!unixy && !batch_mode_shell)\n", + fatal (NILF, "%s (line %d) Bad shell context (!unixy && !batch_mode_shell)\n", __FILE__, __LINE__); #endif } diff --git a/job.h b/job.h index eaac4921..d60247ad 100644 --- a/job.h +++ b/job.h @@ -44,7 +44,7 @@ struct child unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */ unsigned int deleted:1; /* Nonzero if targets have been deleted. */ - char* sh_batch_file; /* used to execute shell commands via scripts */ + char *sh_batch_file; /* Script file for shell commands */ }; extern struct child *children; diff --git a/main.c b/main.c index dcffa37c..efad30db 100644 --- a/main.c +++ b/main.c @@ -22,6 +22,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "variable.h" #include "job.h" #include "commands.h" +#include "rule.h" #include "getopt.h" #include #ifdef _AMIGA @@ -41,7 +42,6 @@ extern void init_dir PARAMS ((void)); extern void remote_setup PARAMS ((void)); extern void remote_cleanup PARAMS ((void)); extern RETSIGTYPE fatal_error_signal PARAMS ((int sig)); -extern RETSIGTYPE child_handler PARAMS ((int sig)); extern void print_variable_data_base PARAMS ((void)); extern void print_dir_data_base PARAMS ((void)); @@ -49,18 +49,22 @@ extern void print_rule_data_base PARAMS ((void)); extern void print_file_data_base PARAMS ((void)); extern void print_vpath_data_base PARAMS ((void)); +#if defined HAVE_WAITPID || defined HAVE_WAIT3 +# define HAVE_WAIT_NOHANG +#endif + #ifndef HAVE_UNISTD_H extern int chdir (); #endif #ifndef STDC_HEADERS #ifndef sun /* Sun has an incorrect decl in a header. */ -extern void exit (); +extern void exit PARAMS ((int)) __attribute__ ((noreturn)); #endif extern double atof (); #endif extern char *mktemp (); -static void print_data_base PARAMS((void)); +static void print_data_base PARAMS ((void)); static void print_version PARAMS ((void)); static void decode_switches PARAMS ((int argc, char **argv, int env)); static void decode_env_switches PARAMS ((char *envar, unsigned int len)); @@ -413,7 +417,7 @@ enter_command_line_file (name) char *name; { if (name[0] == '\0') - fatal ("empty string invalid as file name"); + fatal (NILF, "empty string invalid as file name"); if (name[0] == '~') { @@ -664,8 +668,7 @@ int main (int argc, char ** argv) #endif default_goal_file = 0; - reading_filename = 0; - reading_lineno_ptr = 0; + reading_file = 0; #if defined (__MSDOS__) && !defined (_POSIX_SOURCE) /* Request the most powerful version of `system', to @@ -722,6 +725,20 @@ int main (int argc, char ** argv) #undef FATAL_SIG + /* Do not ignore the child-death signal. This must be done before + any children could possibly be created; otherwise, the wait + functions won't work on systems with the SVR4 ECHILD brain + damage, if our invoker is ignoring this signal. */ + +#ifdef HAVE_WAIT_NOHANG +# if defined SIGCHLD + (void) signal (SIGCHLD, SIG_DFL); +# endif +# if defined SIGCLD && SIGCLD != SIGCHLD + (void) signal (SIGCLD, SIG_DFL); +# endif +#endif + /* Make sure stdout is line-buffered. */ #ifdef HAVE_SETLINEBUF @@ -782,7 +799,7 @@ int main (int argc, char ** argv) #ifdef HAVE_GETCWD perror_with_name ("getcwd: ", ""); #else - error ("getwd: %s", current_directory); + error (NILF, "getwd: %s", current_directory); #endif current_directory[0] = '\0'; directory_before_chdir = 0; @@ -1051,7 +1068,7 @@ int main (int argc, char ** argv) #ifdef HAVE_GETCWD perror_with_name ("getcwd: ", ""); #else - error ("getwd: %s", current_directory); + error (NILF, "getwd: %s", current_directory); #endif starting_directory = 0; } @@ -1089,7 +1106,7 @@ int main (int argc, char ** argv) #endif if (stdin_nm) - fatal("Makefile from standard input specified twice."); + fatal (NILF, "Makefile from standard input specified twice."); outfile = fopen (name, "w"); if (outfile == 0) @@ -1126,14 +1143,20 @@ int main (int argc, char ** argv) } } - /* Set up to handle children dying. This must be done before - reading in the makefiles so that `shell' function calls will work. */ +#ifndef HAVE_WAIT_NOHANG + { + extern RETSIGTYPE child_handler PARAMS ((int sig)); -#ifdef SIGCHLD - (void) signal (SIGCHLD, child_handler); -#endif -#ifdef SIGCLD - (void) signal (SIGCLD, child_handler); + /* Set up to handle children dying. This must be done before + reading in the makefiles so that `shell' function calls will work. + Note we only do this if we have to. */ +# if defined SIGCHLD + (void) signal (SIGCHLD, child_handler); +# endif +# if defined SIGCLD && SIGCLD != SIGCHLD + (void) signal (SIGCLD, child_handler); +# endif + } #endif /* Let the user send us SIGUSR1 to toggle the -d flag during the run. */ @@ -1178,8 +1201,8 @@ int main (int argc, char ** argv) no_default_sh_exe = !find_and_set_default_shell(NULL); if (no_default_sh_exe && job_slots != 1) { - error("Do not specify -j or --jobs if sh.exe is not available."); - error("Resetting make for single job mode."); + error (NILF, "Do not specify -j or --jobs if sh.exe is not available."); + error (NILF, "Resetting make for single job mode."); job_slots = 1; } #endif /* WINDOWS32 */ @@ -1251,7 +1274,7 @@ int main (int argc, char ** argv) for (p = old_files->list; *p != 0; ++p) { f = enter_command_line_file (*p); - f->last_mtime = (time_t) 1; + f->last_mtime = (FILE_TIMESTAMP) 1; f->updated = 1; f->update_status = 0; f->command_state = cs_finished; @@ -1273,7 +1296,7 @@ int main (int argc, char ** argv) { /* Update any makefiles if necessary. */ - time_t *makefile_mtimes = 0; + FILE_TIMESTAMP *makefile_mtimes = 0; unsigned int mm_idx = 0; char **nargv = argv; int nargc = argc; @@ -1323,11 +1346,12 @@ int main (int argc, char ** argv) if (f == NULL || !f->double_colon) { if (makefile_mtimes == 0) - makefile_mtimes = (time_t *) xmalloc (sizeof (time_t)); + makefile_mtimes = (FILE_TIMESTAMP *) + xmalloc (sizeof (FILE_TIMESTAMP)); else - makefile_mtimes = (time_t *) + makefile_mtimes = (FILE_TIMESTAMP *) xrealloc ((char *) makefile_mtimes, - (mm_idx + 1) * sizeof (time_t)); + (mm_idx + 1) * sizeof (FILE_TIMESTAMP)); makefile_mtimes[mm_idx++] = file_mtime_no_search (d->file); last = d; d = d->next; @@ -1373,13 +1397,13 @@ int main (int argc, char ** argv) } else if (! (d->changed & RM_DONTCARE)) { - time_t mtime; + FILE_TIMESTAMP mtime; /* The update failed and this makefile was not from the MAKEFILES variable, so we care. */ - error ("Failed to remake makefile `%s'.", + error (NILF, "Failed to remake makefile `%s'.", d->file->name); mtime = file_mtime_no_search (d->file); - any_remade |= (mtime != (time_t) -1 + any_remade |= (mtime != (FILE_TIMESTAMP) -1 && mtime != makefile_mtimes[i]); } } @@ -1391,12 +1415,12 @@ int main (int argc, char ** argv) if (d->changed & RM_INCLUDED) /* An included makefile. We don't need to die, but we do want to complain. */ - error ("Included makefile `%s' was not found.", + error (NILF, "Included makefile `%s' was not found.", dep_name (d)); else { /* A normal makefile. We must die later. */ - error ("Makefile `%s' was not found", dep_name (d)); + error (NILF, "Makefile `%s' was not found", dep_name (d)); any_failed = 1; } } @@ -1461,7 +1485,7 @@ int main (int argc, char ** argv) else bad = 1; if (bad) - fatal ("Couldn't change back to original directory."); + fatal (NILF, "Couldn't change back to original directory."); } #ifndef _AMIGA @@ -1570,14 +1594,14 @@ int main (int argc, char ** argv) else { if (read_makefiles == 0) - fatal ("No targets specified and no makefile found"); + fatal (NILF, "No targets specified and no makefile found"); else - fatal ("No targets"); + fatal (NILF, "No targets"); } /* If we detected some clock skew, generate one last warning */ if (clock_skew_detected) - error("*** Warning: Clock skew detected. Your build may be incomplete."); + error (NILF, "*** Warning: Clock skew detected. Your build may be incomplete."); /* Exit. */ die (status); @@ -1661,7 +1685,7 @@ handle_non_switch_argument (arg, env) if (arg[0] == '-' && arg[1] == '\0') /* Ignore plain `-' for compatibility. */ return; - v = try_variable_definition ((char *) 0, 0, arg, o_command); + v = try_variable_definition (0, arg, o_command); if (v != 0) { /* It is indeed a variable definition. Record a pointer to @@ -1825,7 +1849,7 @@ decode_switches (argc, argv, env) if (i < 1) { if (doit) - error ("the `-%c' option requires a \ + error (NILF, "the `-%c' option requires a \ positive integral argument", cs->c); bad = 1; diff --git a/make.h b/make.h index 58a0ff21..9f5af966 100644 --- a/make.h +++ b/make.h @@ -25,27 +25,27 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h (which it would do because make.h was found in $srcdir). */ #include -#undef HAVE_CONFIG_H -#define HAVE_CONFIG_H +#undef HAVE_CONFIG_H +#define HAVE_CONFIG_H 1 /* Use prototypes if available. */ #if defined (__cplusplus) || (defined (__STDC__) && __STDC__) -#undef PARAMS -#define PARAMS(protos) protos +# undef PARAMS +# define PARAMS(protos) protos #else /* Not C++ or ANSI C. */ -#undef PARAMS -#define PARAMS(protos) () +# undef PARAMS +# define PARAMS(protos) () #endif /* C++ or ANSI C. */ -#ifdef CRAY +#ifdef CRAY /* This must happen before #include so that the declaration therein is changed. */ -#define signal bsdsignal +# define signal bsdsignal #endif -#define _GNU_SOURCE +#define _GNU_SOURCE 1 #include #include #include @@ -55,35 +55,35 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* SCO 3.2 "devsys 4.2" has a prototype for `ftime' in that bombs unless has been included first. Does every system have a ? If any does not, configure should check for it. */ -#include +# include #endif #include #include -#ifndef errno +#ifndef errno extern int errno; #endif -#ifndef isblank -#define isblank(c) ((c) == ' ' || (c) == '\t') +#ifndef isblank +# define isblank(c) ((c) == ' ' || (c) == '\t') #endif -#ifdef HAVE_UNISTD_H -#include +#ifdef HAVE_UNISTD_H +# include /* Ultrix's unistd.h always defines _POSIX_VERSION, but you only get POSIX.1 behavior with `cc -YPOSIX', which predefines POSIX itself! */ -#if defined (_POSIX_VERSION) && !defined (ultrix) && !defined (VMS) -#define POSIX -#endif +# if defined (_POSIX_VERSION) && !defined (ultrix) && !defined (VMS) +# define POSIX 1 +# endif #endif /* Some systems define _POSIX_VERSION but are not really POSIX.1. */ #if (defined (butterfly) || defined (__arm) || (defined (__mips) && defined (_SYSTYPE_SVR3)) || (defined (sequent) && defined (i386))) -#undef POSIX +# undef POSIX #endif #if !defined (POSIX) && defined (_AIX) && defined (_POSIX_SOURCE) -#define POSIX +# define POSIX 1 #endif #if defined (HAVE_SYS_SIGLIST) && !defined (SYS_SIGLIST_DECLARED) @@ -91,54 +91,54 @@ extern char *sys_siglist[]; #endif #if !defined (HAVE_SYS_SIGLIST) || !defined (HAVE_STRSIGNAL) -#include "signame.h" +# include "signame.h" #endif /* Some systems do not define NSIG in . */ -#ifndef NSIG -#ifdef _NSIG -#define NSIG _NSIG -#else -#define NSIG 32 -#endif +#ifndef NSIG +# ifdef _NSIG +# define NSIG _NSIG +# else +# define NSIG 32 +# endif #endif -#ifndef RETSIGTYPE -#define RETSIGTYPE void +#ifndef RETSIGTYPE +# define RETSIGTYPE void #endif -#ifndef sigmask -#define sigmask(sig) (1 << ((sig) - 1)) +#ifndef sigmask +# define sigmask(sig) (1 << ((sig) - 1)) #endif -#ifdef HAVE_LIMITS_H -#include +#ifdef HAVE_LIMITS_H +# include #endif -#ifdef HAVE_SYS_PARAM_H -#include +#ifdef HAVE_SYS_PARAM_H +# include #endif -#ifndef PATH_MAX -#ifndef POSIX -#define PATH_MAX MAXPATHLEN -#endif /* Not POSIX. */ -#endif /* No PATH_MAX. */ +#ifndef PATH_MAX +# ifndef POSIX +# define PATH_MAX MAXPATHLEN +# endif +#endif #ifndef MAXPATHLEN -#define MAXPATHLEN 1024 -#endif /* No MAXPATHLEN. */ +# define MAXPATHLEN 1024 +#endif -#ifdef PATH_MAX -#define GET_PATH_MAX PATH_MAX -#define PATH_VAR(var) char var[PATH_MAX] +#ifdef PATH_MAX +# define GET_PATH_MAX PATH_MAX +# define PATH_VAR(var) char var[PATH_MAX] #else -#define NEED_GET_PATH_MAX +# define NEED_GET_PATH_MAX 1 +# define GET_PATH_MAX (get_path_max ()) +# define PATH_VAR(var) char *var = (char *) alloca (GET_PATH_MAX) extern unsigned int get_path_max PARAMS ((void)); -#define GET_PATH_MAX (get_path_max ()) -#define PATH_VAR(var) char *var = (char *) alloca (GET_PATH_MAX) #endif #ifndef CHAR_BIT -#define CHAR_BIT 8 +# define CHAR_BIT 8 #endif /* Nonzero if the integer type T is signed. */ @@ -150,171 +150,189 @@ extern unsigned int get_path_max PARAMS ((void)); (! INTEGER_TYPE_SIGNED (t) ? (t) 0 : ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)) #define INTEGER_TYPE_MAXIMUM(t) (~ (t) 0 - INTEGER_TYPE_MINIMUM (t)) -#ifdef STAT_MACROS_BROKEN -#ifdef S_ISREG -#undef S_ISREG -#endif -#ifdef S_ISDIR -#undef S_ISDIR -#endif -#endif /* STAT_MACROS_BROKEN. */ +#ifdef STAT_MACROS_BROKEN +# ifdef S_ISREG +# undef S_ISREG +# endif +# ifdef S_ISDIR +# undef S_ISDIR +# endif +#endif /* STAT_MACROS_BROKEN. */ -#ifndef S_ISREG -#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#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) +#ifndef S_ISDIR +# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) #endif #ifdef VMS -#include -#include -#include -#include -#include -#include +# include +# include +# include +# include +# include +# include #endif -#if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) || defined(VMS)) -#include -#include -#define ANSI_STRING -#else /* No standard headers. */ - -#ifdef HAVE_STRING_H -#include -#define ANSI_STRING -#else -#include -#endif -#ifdef HAVE_MEMORY_H -#include +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ +# define __attribute__(x) +# endif +/* The __-protected variants of `format' and `printf' attributes + are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __format__ format +# define __printf__ printf +# endif #endif +#if defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) +# include +# include +# define ANSI_STRING 1 +#else /* No standard headers. */ +# ifdef HAVE_STRING_H +# include +# define ANSI_STRING 1 +# else +# include +# endif +# ifdef HAVE_MEMORY_H +# include +# endif +# ifdef HAVE_STDLIB_H +# include +# else extern char *malloc PARAMS ((int)); extern char *realloc PARAMS ((char *, int)); extern void free PARAMS ((char *)); -extern void abort PARAMS ((void)); -extern void exit PARAMS ((int)); +extern void abort PARAMS ((void)) __attribute__ ((noreturn)); +extern void exit PARAMS ((int)) __attribute__ ((noreturn)); +# endif /* HAVE_STDLIB_H. */ -#endif /* Standard headers. */ +#endif /* Standard headers. */ -#ifdef ANSI_STRING - -#ifndef index -#define index(s, c) strchr((s), (c)) -#endif -#ifndef rindex -#define rindex(s, c) strrchr((s), (c)) +#if ST_MTIM_NSEC +# if HAVE_INTTYPES_H +# include +# endif +# define FILE_TIMESTAMP uintmax_t +#else +# define FILE_TIMESTAMP time_t #endif -#ifndef bcmp -#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) -#endif -#ifndef bzero -#define bzero(s, n) memset ((s), 0, (n)) -#endif -#if defined(HAVE_MEMMOVE) && !defined(bcopy) -#define bcopy(s, d, n) memmove ((d), (s), (n)) -#endif +#ifdef ANSI_STRING -#else /* Not ANSI_STRING. */ +# ifndef index +# define index(s, c) strchr((s), (c)) +# endif +# ifndef rindex +# define rindex(s, c) strrchr((s), (c)) +# endif -#ifndef bcmp -extern int bcmp (); -#endif -#ifndef bzero -extern void bzero (); -#endif -#ifndef bcopy -extern void bcopy (); -#endif +# ifndef bcmp +# define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) +# endif +# ifndef bzero +# define bzero(s, n) memset ((s), 0, (n)) +# endif +# if defined(HAVE_MEMMOVE) && !defined(bcopy) +# define bcopy(s, d, n) memmove ((d), (s), (n)) +# endif -#endif /* ANSI_STRING. */ -#undef ANSI_STRING +#else /* Not ANSI_STRING. */ + +# ifndef bcmp +extern int bcmp PARAMS ((const char *, const char *, int)); +# endif +# ifndef bzero +extern void bzero PARAMS ((char *, int)); +#endif +# ifndef bcopy +extern void bcopy PARAMS ((const char *b1, char *b2, int)); +# endif + +#endif /* ANSI_STRING. */ +#undef ANSI_STRING /* SCO Xenix has a buggy macro definition in . */ -#undef strerror +#undef strerror #if !defined(ANSI_STRING) && !defined(__DECC) extern char *strerror PARAMS ((int errnum)); #endif -#ifndef __attribute__ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) -# define __attribute__(x) -# endif -#endif - -#ifdef __GNUC__ -#undef alloca -#define alloca(n) __builtin_alloca (n) -#else /* Not GCC. */ -#ifdef HAVE_ALLOCA_H -#include -#else /* Not HAVE_ALLOCA_H. */ -#ifndef _AIX +#ifdef __GNUC__ +# undef alloca +# define alloca(n) __builtin_alloca (n) +#else /* Not GCC. */ +# ifdef HAVE_ALLOCA_H +# include +# else /* Not HAVE_ALLOCA_H. */ +# ifndef _AIX extern char *alloca (); -#endif /* Not AIX. */ -#endif /* HAVE_ALLOCA_H. */ -#endif /* GCC. */ +# endif /* Not AIX. */ +# endif /* HAVE_ALLOCA_H. */ +#endif /* GCC. */ -#ifndef iAPX286 -#define streq(a, b) \ - ((a) == (b) || \ - (*(a) == *(b) && (*(a) == '\0' || !strcmp ((a) + 1, (b) + 1)))) -#ifdef HAVE_CASE_INSENSITIVE_FS -#define strieq(a, b) \ - ((a) == (b) || \ - (tolower(*(a)) == tolower(*(b)) && (*(a) == '\0' || !strcmpi ((a) + 1, (b) + 1)))) -#else -#define strieq(a, b) \ - ((a) == (b) || \ - (*(a) == *(b) && (*(a) == '\0' || !strcmp ((a) + 1, (b) + 1)))) -#endif +#ifndef iAPX286 +# define streq(a, b) \ + ((a) == (b) || \ + (*(a) == *(b) && (*(a) == '\0' || !strcmp ((a) + 1, (b) + 1)))) +# ifdef HAVE_CASE_INSENSITIVE_FS +# define strieq(a, b) \ + ((a) == (b) || \ + (tolower(*(a)) == tolower(*(b)) && (*(a) == '\0' || !strcmpi ((a) + 1, (b) + 1)))) +# else +# define strieq(a, b) \ + ((a) == (b) || \ + (*(a) == *(b) && (*(a) == '\0' || !strcmp ((a) + 1, (b) + 1)))) +# endif #else /* Buggy compiler can't handle this. */ -#define streq(a, b) (strcmp ((a), (b)) == 0) -#define strieq(a, b) (strcmp ((a), (b)) == 0) +# define streq(a, b) (strcmp ((a), (b)) == 0) +# define strieq(a, b) (strcmp ((a), (b)) == 0) #endif /* Add to VAR the hashing value of C, one character in a name. */ -#define HASH(var, c) \ +#define HASH(var, c) \ ((var += (c)), (var = ((var) << 7) + ((var) >> 20))) #ifdef HAVE_CASE_INSENSITIVE_FS /* Fold filenames */ -#define HASHI(var, c) \ - ((var += tolower((c))), (var = ((var) << 7) + ((var) >> 20))) +# define HASHI(var, c) \ + ((var += tolower((c))), (var = ((var) << 7) + ((var) >> 20))) #else -#define HASHI(var, c) HASH(var,c) +# define HASHI(var, c) HASH(var,c) #endif #if defined(__GNUC__) || defined(ENUM_BITFIELDS) -#define ENUM_BITFIELD(bits) :bits +# define ENUM_BITFIELD(bits) :bits #else -#define ENUM_BITFIELD(bits) +# define ENUM_BITFIELD(bits) #endif #if defined(__MSDOS__) || defined(WINDOWS32) -#define PATH_SEPARATOR_CHAR ';' +# define PATH_SEPARATOR_CHAR ';' #else -#if defined(VMS) -#define PATH_SEPARATOR_CHAR ',' -#else -#define PATH_SEPARATOR_CHAR ':' -#endif +# if defined(VMS) +# define PATH_SEPARATOR_CHAR ',' +# else +# define PATH_SEPARATOR_CHAR ':' +# endif #endif #ifdef WINDOWS32 -#include -#include -#define pipe(p) _pipe(p, 512, O_BINARY) -#define kill(pid,sig) w32_kill(pid,sig) +# include +# include +# define pipe(p) _pipe(p, 512, O_BINARY) +# define kill(pid,sig) w32_kill(pid,sig) extern void sync_Path_environment(void); extern int kill(int pid, int sig); extern int safe_stat(char *file, struct stat *sb); -extern char *end_of_token_w32(); +extern char *end_of_token_w32(char *s, char stopchar); extern int find_and_set_default_shell(char *token); /* indicates whether or not we have Bourne shell */ @@ -323,72 +341,81 @@ extern int no_default_sh_exe; /* is default_shell unixy? */ extern int unixy_shell; #endif /* WINDOWS32 */ - -extern void die () __attribute__ ((noreturn)); -extern void message (); -extern void fatal () __attribute__ ((noreturn)); -extern void error (); -extern void log_working_directory (); -extern void makefile_error (); -extern void makefile_fatal () __attribute__ ((noreturn)); -extern void pfatal_with_name () __attribute__ ((noreturn)); -extern void perror_with_name (); -extern char *savestring (); -extern char *concat (); -extern char *xmalloc (); -extern char *xrealloc (); -extern char *find_next_token (); -extern char *next_token (); -extern char *end_of_token (); -extern void collapse_continuations (); -extern void remove_comments (); -extern char *sindex (); -extern char *lindex (); -extern int alpha_compare (); -extern void print_spaces (); -extern struct dep *copy_dep_chain (); -extern char *find_char_unquote (); -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 (); +struct floc + { + char *filenm; + unsigned long lineno; + }; +#define NILF ((struct floc *)0) + + +/* Fancy processing for variadic functions in both ANSI and pre-ANSI + compilers. */ +#if defined __STDC__ && __STDC__ +extern void message (int prefix, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); +extern void error (const struct floc *flocp, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); +extern void fatal (const struct floc *flocp, const char *fmt, ...) + __attribute__ ((noreturn, __format__ (__printf__, 2, 3))); +#else +extern void message (); +extern void error (); +extern void fatal (); #endif -extern void dir_load (); -extern int dir_file_exists_p (); -extern int file_exists_p (); -extern int file_impossible_p (); -extern void file_impossible (); -extern char *dir_name (); +extern void die PARAMS ((int)) __attribute__ ((noreturn)); +extern void log_working_directory PARAMS ((int)); +extern void pfatal_with_name PARAMS ((char *)) __attribute__ ((noreturn)); +extern void perror_with_name PARAMS ((char *, char *)); +extern char *savestring PARAMS ((char *, unsigned int)); +extern char *concat PARAMS ((char *, char *, char *)); +extern char *xmalloc PARAMS ((unsigned int)); +extern char *xrealloc PARAMS ((char *, unsigned int)); +extern char *find_next_token PARAMS ((char **, unsigned int *)); +extern char *next_token PARAMS ((char *)); +extern char *end_of_token PARAMS ((char *)); +extern void collapse_continuations PARAMS ((char *)); +extern void remove_comments PARAMS((char *)); +extern char *sindex PARAMS ((char *, unsigned int, char *, unsigned int)); +extern char *lindex PARAMS ((char *, char *, int)); +extern int alpha_compare PARAMS ((const void *, const void *)); +extern void print_spaces PARAMS ((unsigned int)); +extern char *find_char_unquote PARAMS ((char *, char *, int)); +extern char *find_percent PARAMS ((char *)); -extern void define_default_variables (); -extern void set_default_suffixes (); -extern void install_default_suffix_rules (); -extern void install_default_implicit_rules (); -extern void count_implicit_rule_limits (); -extern void convert_to_pattern (); -extern void create_pattern_rule (); +#ifndef NO_ARCHIVES +extern int ar_name PARAMS ((char *)); +extern void ar_parse_name PARAMS ((char *, char **, char **)); +extern int ar_touch PARAMS ((char *)); +extern time_t ar_member_date PARAMS ((char *)); +#endif -extern void build_vpath_lists (); -extern void construct_vpath_list (); -extern int vpath_search (); -extern int gpath_search (); +extern int dir_file_exists_p PARAMS ((char *, char *)); +extern int file_exists_p PARAMS ((char *)); +extern int file_impossible_p PARAMS ((char *)); +extern void file_impossible PARAMS ((char *)); +extern char *dir_name PARAMS ((char *)); -extern void construct_include_path (); -extern void uniquize_deps (); +extern void define_default_variables PARAMS ((void)); +extern void set_default_suffixes PARAMS ((void)); +extern void install_default_suffix_rules PARAMS ((void)); +extern void install_default_implicit_rules PARAMS ((void)); -extern int update_goal_chain (); -extern void notice_finished_file (); +extern void build_vpath_lists PARAMS ((void)); +extern void construct_vpath_list PARAMS ((char *pattern, char *dirpath)); +extern int vpath_search PARAMS ((char **file, FILE_TIMESTAMP *mtime_ptr)); +extern int gpath_search PARAMS ((char *file, int len)); -extern void user_access (); -extern void make_access (); -extern void child_access (); +extern void construct_include_path PARAMS ((char **arg_dirs)); -#ifdef HAVE_VFORK_H -#include +extern void user_access PARAMS ((void)); +extern void make_access PARAMS ((void)); +extern void child_access PARAMS ((void)); + +#ifdef HAVE_VFORK_H +# include #endif /* We omit these declarations on non-POSIX systems which define _POSIX_VERSION, @@ -397,26 +424,25 @@ extern void child_access (); #if !defined (__GNU_LIBRARY__) && !defined (POSIX) && !defined (_POSIX_VERSION) && !defined(WINDOWS32) extern long int atol (); -#ifndef VMS +# ifndef VMS extern long int lseek (); -#endif +# endif -#endif /* Not GNU C library or POSIX. */ +#endif /* Not GNU C library or POSIX. */ -#ifdef HAVE_GETCWD +#ifdef HAVE_GETCWD extern char *getcwd (); -#ifdef VMS +# ifdef VMS extern char *getwd PARAMS ((char *)); -#endif +# endif #else extern char *getwd (); -#define getcwd(buf, len) getwd (buf) +# define getcwd(buf, len) getwd (buf) #endif -extern char **environ; +extern const struct floc *reading_file; -extern char *reading_filename; -extern unsigned int *reading_lineno_ptr; +extern char **environ; 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; @@ -445,9 +471,16 @@ extern unsigned int commands_started; extern int handling_fatal_signal; +#ifndef MIN +#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b)) +#endif +#ifndef MAX +#define MAX(_a,_b) ((_a)>(_b)?(_a):(_b)) +#endif + #define DEBUGPR(msg) \ do if (debug_flag) { print_spaces (depth); printf (msg, file->name); \ - fflush (stdout); } while (0) + fflush (stdout); } while (0) #ifdef VMS # ifndef EXIT_FAILURE @@ -470,4 +503,3 @@ extern int handling_fatal_signal; # define EXIT_TROUBLE 1 # endif #endif - diff --git a/make.texinfo b/make.texinfo index 05d07462..e7b3bbf3 100644 --- a/make.texinfo +++ b/make.texinfo @@ -68,17 +68,17 @@ by the Free Software Foundation. @titlepage @title GNU Make @subtitle A Program for Directing Recompilation -@subtitle GNU @code{make} Version @value{VERSION}. +@subtitle GNU @code{make} Version @value{VERSION} @subtitle @value{UPDATE-MONTH} @author Richard M. Stallman and Roland McGrath @page @vskip 0pt plus 1filll -Copyright @copyright{} 1988, '89, '90, '91, '92, '93, '94, '95, '96, '97 Free Software Foundation, Inc. +Copyright @copyright{} 1988, '89, '90, '91, '92, '93, '94, '95, '96, '97, '98 +Free Software Foundation, Inc. @sp 2 Published by the Free Software Foundation @* 59 Temple Place -- Suite 330, @* Boston, MA 02111-1307 USA @* -Printed copies are available for $20 each. @* ISBN @value{ISBN} @* Permission is granted to make and distribute verbatim copies of @@ -124,7 +124,7 @@ This manual describes @code{make} and contains the following chapters:@refill * Conditionals:: Use or ignore parts of the makefile based on the values of variables. * Functions:: Many powerful ways to manipulate text. -* make Invocation: Running. How to invoke @code{make} on the command line. +* Invoking make: Running. How to invoke @code{make} on the command line. * Implicit Rules:: Use implicit rules to treat many files alike, based on their file names. * Archives:: How @code{make} can update library archives. @@ -2241,8 +2241,7 @@ match that file's name. The targets which @code{.INTERMEDIATE} depends on are treated as intermediate files. @xref{Chained Rules, ,Chains of Implicit Rules}. -@code{.INTERMEDIATE} with no dependencies marks all file targets -mentioned in the makefile as intermediate. +@code{.INTERMEDIATE} with no dependencies has no effect. @findex .SECONDARY @item .SECONDARY diff --git a/misc.c b/misc.c index 1411e54f..0612862b 100644 --- a/misc.c +++ b/misc.c @@ -20,17 +20,52 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "dep.h" +/* Variadic functions. We go through contortions to allow proper function + prototypes for both ANSI and pre-ANSI C compilers, and also for those + which support stdarg.h vs. varargs.h, and finally those which have + vfprintf(), etc. and those who have _doprnt... or nothing. + + This fancy stuff all came from GNU fileutils, except for the VA_PRINTF and + VA_END macros used here since we have multiple print functions. */ + +#if HAVE_VPRINTF || HAVE_DOPRNT +# define HAVE_STDVARARGS 1 +# if __STDC__ +# include +# define VA_START(args, lastarg) va_start(args, lastarg) +# else +# include +# define VA_START(args, lastarg) va_start(args) +# endif +# if HAVE_VPRINTF +# define VA_PRINTF(fp, lastarg, args) vfprintf((fp), (lastarg), (args)) +# else +# define VA_PRINTF(fp, lastarg, args) _doprnt((lastarg), (args), (fp)) +# endif +# define VA_END(args) va_end(args) +#else +/* # undef HAVE_STDVARARGS */ +# define va_alist a1, a2, a3, a4, a5, a6, a7, a8 +# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8; +# define VA_START(args, lastarg) +# define VA_END(args) +#endif + + /* 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; +alpha_compare (v1, v2) + const void *v1, *v2; { - if (**s1 != **s2) - return **s1 - **s2; - return strcmp (*s1, *s2); + const char *s1 = *((char **)v1); + const char *s2 = *((char **)v2); + + if (*s1 != *s2) + return *s1 - *s2; + return strcmp (s1, s2); } /* Discard each backslash-newline combination from LINE. @@ -173,13 +208,22 @@ concat (s1, s2, s3) /* Print a message on stdout. */ void -message (prefix, s1, s2, s3, s4, s5, s6) +#if __STDC__ && HAVE_STDVARARGS +message (int prefix, const char *fmt, ...) +#else +message (prefix, fmt, va_alist) int prefix; - char *s1, *s2, *s3, *s4, *s5, *s6; + const char *fmt; + va_dcl +#endif { +#if HAVE_STDVARARGS + va_list args; +#endif + log_working_directory (1); - if (s1 != 0) + if (fmt != 0) { if (prefix) { @@ -188,78 +232,77 @@ message (prefix, s1, s2, s3, s4, s5, s6) else printf ("%s[%u]: ", program, makelevel); } - printf (s1, s2, s3, s4, s5, s6); + VA_START (args, fmt); + VA_PRINTF (stdout, fmt, args); + VA_END (args); 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; -{ - log_working_directory (1); - - 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 (2); -} - -/* Print error message. `s1' is printf control string, `s2' is arg for it. */ - -/* VARARGS1 */ +/* Print an error message. */ void -error (s1, s2, s3, s4, s5, s6) - char *s1, *s2, *s3, *s4, *s5, *s6; +#if __STDC__ && HAVE_STDVARARGS +error (const struct floc *flocp, const char *fmt, ...) +#else +error (flocp, fmt, va_alist) + const struct floc *flocp; + const char *fmt; + va_dcl +#endif { +#if HAVE_STDVARARGS + va_list args; +#endif + log_working_directory (1); - if (makelevel == 0) + if (flocp && flocp->filenm) + fprintf (stderr, "%s:%lu: ", flocp->filenm, flocp->lineno); + else if (makelevel == 0) fprintf (stderr, "%s: ", program); else fprintf (stderr, "%s[%u]: ", program, makelevel); - fprintf (stderr, s1, s2, s3, s4, s5, s6); + + VA_START(args, fmt); + VA_PRINTF (stderr, fmt, args); + VA_END (args); + 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; -{ - log_working_directory (1); - - fprintf (stderr, "%s:%u: ", file, lineno); - fprintf (stderr, s1, s2, s3, s4, s5, s6); - putc ('\n', stderr); - fflush (stderr); -} +/* Print an error message and exit. */ void -makefile_fatal (file, lineno, s1, s2, s3, s4, s5, s6) - char *file; - unsigned int lineno; - char *s1, *s2, *s3, *s4, *s5, *s6; +#if __STDC__ && HAVE_STDVARARGS +fatal (const struct floc *flocp, const char *fmt, ...) +#else +fatal (flocp, fmt, va_alist) + const struct floc *flocp; + const char *fmt; + va_dcl +#endif { - if (!file) - fatal(s1, s2, s3, s4, s5, s6); +#if HAVE_STDVARARGS + va_list args; +#endif log_working_directory (1); - fprintf (stderr, "%s:%u: *** ", file, lineno); - fprintf (stderr, s1, s2, s3, s4, s5, s6); + if (flocp && flocp->filenm) + fprintf (stderr, "%s:%lu: *** ", flocp->filenm, flocp->lineno); + else if (makelevel == 0) + fprintf (stderr, "%s: *** ", program); + else + fprintf (stderr, "%s[%u]: *** ", program, makelevel); + + VA_START(args, fmt); + VA_PRINTF (stderr, fmt, args); + VA_END (args); + fputs (". Stop.\n", stderr); die (2); @@ -293,7 +336,7 @@ void perror_with_name (str, name) char *str, *name; { - error ("%s%s: %s", str, name, strerror (errno)); + error (NILF, "%s%s: %s", str, name, strerror (errno)); } /* Print an error message from errno and exit. */ @@ -302,7 +345,7 @@ void pfatal_with_name (name) char *name; { - fatal ("%s: %s", name, strerror (errno)); + fatal (NILF, "%s: %s", name, strerror (errno)); /* NOTREACHED */ } @@ -318,7 +361,7 @@ xmalloc (size) { char *result = (char *) malloc (size); if (result == 0) - fatal ("virtual memory exhausted"); + fatal (NILF, "virtual memory exhausted"); return result; } @@ -330,7 +373,7 @@ xrealloc (ptr, size) { char *result = (char *) realloc (ptr, size); if (result == 0) - fatal ("virtual memory exhausted"); + fatal (NILF, "virtual memory exhausted"); return result; } diff --git a/read.c b/read.c index 02075162..a677399d 100644 --- a/read.c +++ b/read.c @@ -119,26 +119,27 @@ 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; +const struct floc *reading_file; /* The chain of makefiles read by read_makefile. */ static struct dep *read_makefiles = 0; static int read_makefile PARAMS ((char *filename, int flags)); -static unsigned int readline PARAMS ((struct linebuffer *linebuffer, FILE *stream, - char *filename, unsigned int lineno)); -static unsigned int do_define PARAMS ((char *name, unsigned int namelen, enum variable_origin origin, - unsigned int lineno, FILE *infile, char *filename)); -static int conditional_line PARAMS ((char *line, char *filename, unsigned int lineno)); +static unsigned long readline PARAMS ((struct linebuffer *linebuffer, + FILE *stream, const struct floc *flocp)); +static void do_define PARAMS ((char *name, unsigned int namelen, + enum variable_origin origin, FILE *infile, + struct floc *flocp)); +static int conditional_line PARAMS ((char *line, const struct floc *flocp)); static void record_files PARAMS ((struct nameseq *filenames, char *pattern, char *pattern_percent, struct dep *deps, unsigned int cmds_started, char *commands, - unsigned int commands_idx, int two_colon, char *filename, - unsigned int lineno, int set_default)); + unsigned int commands_idx, int two_colon, + const struct floc *flocp, int set_default)); static void record_target_var PARAMS ((struct nameseq *filenames, char *defn, - int two_colon, enum variable_origin origin, - char *filename, unsigned int lineno)); + int two_colon, + enum variable_origin origin, + const struct floc *flocp)); static enum make_word_type get_next_mword PARAMS ((char *buffer, char *delim, char **startp, unsigned int *length)); @@ -290,11 +291,11 @@ read_makefile (filename, flags) int len, reading_target; int ignoring = 0, in_ignored_define = 0; int no_targets = 0; /* Set when reading a rule without targets. */ + struct floc fileinfo; char *passed_filename = filename; struct nameseq *filenames = 0; struct dep *deps; - unsigned int lineno = 1; unsigned int nlines = 0; int two_colon = 0; char *pattern = 0, *pattern_percent; @@ -310,19 +311,22 @@ read_makefile (filename, flags) if (filenames != 0) \ record_files (filenames, pattern, pattern_percent, deps, \ cmds_started, commands, commands_idx, \ - two_colon, filename, lineno, \ + two_colon, &fileinfo, \ !(flags & RM_NO_DEFAULT_GOAL)); \ filenames = 0; \ commands_idx = 0; \ if (pattern) { free(pattern); pattern = 0; } \ } while (0) + fileinfo.filenm = filename; + fileinfo.lineno = 1; + pattern_percent = 0; - cmds_started = lineno; + cmds_started = fileinfo.lineno; if (debug_flag) { - printf ("Reading makefile `%s'", filename); + printf ("Reading makefile `%s'", fileinfo.filenm); if (flags & RM_NO_DEFAULT_GOAL) printf (" (no default goal)"); if (flags & RM_INCLUDED) @@ -398,8 +402,7 @@ read_makefile (filename, flags) return 0; } - reading_filename = filename; - reading_lineno_ptr = &lineno; + reading_file = &fileinfo; /* Loop over lines in the file. The strategy is to accumulate target names in FILENAMES, dependencies @@ -410,8 +413,8 @@ read_makefile (filename, flags) while (!feof (infile)) { - lineno += nlines; - nlines = readline (&lb, infile, filename, lineno); + fileinfo.lineno += nlines; + nlines = readline (&lb, infile, &fileinfo); /* Check for a shell command line first. If it is not one, we can stop treating tab specially. */ @@ -437,7 +440,7 @@ read_makefile (filename, flags) /* Append this command line to the line being accumulated. */ p = lb.buffer; if (commands_idx == 0) - cmds_started = lineno; + cmds_started = fileinfo.lineno; len = strlen (p); if (len + 1 + commands_idx > commands_len) { @@ -506,12 +509,11 @@ read_makefile (filename, flags) || word1eq ("ifeq", 4) || word1eq ("ifneq", 5) || word1eq ("else", 4) || word1eq ("endif", 5))) { - int i = conditional_line (p, filename, lineno); + int i = conditional_line (p, &fileinfo); if (i >= 0) ignoring = i; else - makefile_fatal (filename, lineno, - "invalid syntax in conditional"); + fatal (&fileinfo, "invalid syntax in conditional"); continue; } @@ -520,7 +522,7 @@ read_makefile (filename, flags) if (in_ignored_define) in_ignored_define = 0; else - makefile_fatal (filename, lineno, "extraneous `endef'"); + fatal (&fileinfo, "extraneous `endef'"); continue; } @@ -538,8 +540,7 @@ read_makefile (filename, flags) p = index (p2, '\0'); while (isblank (p[-1])) --p; - lineno = do_define (p2, p - p2, o_file, - lineno, infile, filename); + do_define (p2, p - p2, o_file, infile, &fileinfo); } continue; } @@ -548,7 +549,7 @@ read_makefile (filename, flags) { p2 = next_token (p + 8); if (p2 == 0) - makefile_error (filename, lineno, "empty `override' directive"); + error (&fileinfo, "empty `override' directive"); if (!strncmp (p2, "define", 6) && (isblank (p2[6]) || p2[6] == '\0')) { if (ignoring) @@ -563,14 +564,12 @@ read_makefile (filename, flags) p = index (p2, '\0'); while (isblank (p[-1])) --p; - lineno = do_define (p2, p - p2, o_override, - lineno, infile, filename); + do_define (p2, p - p2, o_override, infile, &fileinfo); } } else if (!ignoring - && !try_variable_definition (filename, lineno, - p2, o_override)) - makefile_error (filename, lineno, "empty `override' directive"); + && !try_variable_definition (&fileinfo, p2, o_override)) + error (&fileinfo, "empty `override' directive"); continue; } @@ -587,7 +586,7 @@ read_makefile (filename, flags) p2 = next_token (p + 6); if (*p2 == '\0') export_all_variables = 1; - v = try_variable_definition (filename, lineno, p2, o_file); + v = try_variable_definition (&fileinfo, p2, o_file); if (v != 0) v->export = v_export; else @@ -653,7 +652,7 @@ read_makefile (filename, flags) p = allocated_variable_expand (next_token (p + (noerror ? 8 : 7))); if (*p == '\0') { - makefile_error (filename, lineno, + error (&fileinfo, "no file name for `%sinclude'", noerror ? "-" : ""); continue; @@ -688,7 +687,7 @@ read_makefile (filename, flags) if (! read_makefile (name, (RM_INCLUDED | RM_NO_TILDE | (noerror ? RM_DONTCARE : 0))) && ! noerror) - makefile_error (filename, lineno, + error (&fileinfo, "%s: %s", name, strerror (errno)); free(name); } @@ -701,11 +700,10 @@ read_makefile (filename, flags) /* Restore state. */ conditionals = save; - reading_filename = filename; - reading_lineno_ptr = &lineno; + reading_file = &fileinfo; } #undef word1eq - else if (try_variable_definition (filename, lineno, p, o_file)) + else if (try_variable_definition (&fileinfo, p, o_file)) /* This line has been dealt with. */ ; else if (lb.buffer[0] == '\t') @@ -720,7 +718,7 @@ read_makefile (filename, flags) because there was no preceding target, and the line might have been usable as a variable definition. But now it is definitely lossage. */ - makefile_fatal (filename, lineno, + fatal (&fileinfo, "commands commence before first target"); } else @@ -739,6 +737,7 @@ read_makefile (filename, flags) enum variable_origin v_origin; char *cmdleft, *lb_next; unsigned int len, plen = 0; + char *colonp; /* Record the previous rule. */ @@ -768,7 +767,7 @@ read_makefile (filename, flags) { case w_eol: if (cmdleft != 0) - makefile_fatal (filename, lineno, + fatal (&fileinfo, "missing rule before commands"); else /* This line contained a variable reference that @@ -789,8 +788,6 @@ read_makefile (filename, flags) p2 = variable_expand_string(NULL, lb_next, len); while (1) { - char *colonp; - lb_next += len; if (cmdleft == 0) { @@ -825,12 +822,12 @@ read_makefile (filename, flags) colonp = find_char_unquote(p2, ":", 0); #if defined(__MSDOS__) || defined(WINDOWS32) /* The drive spec brain-damage strikes again... */ - /* FIXME: is whitespace the only possible separator of words - in this context? If not, the `isspace' test below will - need to be changed into a call to `index'. */ + /* Note that the only separators of targets in this context + are whitespace and a left paren. If others are possible, + they should be added to the string in the call to index. */ while (colonp && (colonp[1] == '/' || colonp[1] == '\\') && colonp > p2 && isalpha(colonp[-1]) && - (colonp == p2 + 1 || isspace(colonp[-2]))) + (colonp == p2 + 1 || index(" \t(", colonp[-2]) != 0)) colonp = find_char_unquote(colonp + 1, ":", 0); #endif if (colonp != 0) @@ -838,7 +835,11 @@ read_makefile (filename, flags) wtype = get_next_mword(lb_next, NULL, &lb_next, &len); if (wtype == w_eol) - makefile_fatal (filename, lineno, "missing separator"); + /* There's no need to be ivory-tower about this: check for + one of the most common bugs found in makefiles... */ + fatal (&fileinfo, "missing separator%s", + strncmp(lb.buffer, " ", 8) ? "" + : " (did you mean TAB instead of 8 spaces?)"); p2 += strlen(p2); *(p2++) = ' '; @@ -850,10 +851,14 @@ read_makefile (filename, flags) p2 = next_token (variable_buffer); - filenames = multi_glob (parse_file_seq (&p2, ':', + /* Make the colon the end-of-string so we know where to stop + looking for targets. */ + *colonp = '\0'; + filenames = multi_glob (parse_file_seq (&p2, '\0', sizeof (struct nameseq), 1), sizeof (struct nameseq)); + *colonp = ':'; if (!filenames) { @@ -896,8 +901,7 @@ read_makefile (filename, flags) if (wtype == w_varassign || v_origin == o_override) { - record_target_var(filenames, p, two_colon, v_origin, - filename, lineno); + record_target_var(filenames, p, two_colon, v_origin, &fileinfo); filenames = 0; continue; } @@ -959,7 +963,8 @@ read_makefile (filename, flags) check_again = 0; /* For MSDOS and WINDOWS32, skip a "C:\..." or a "C:/..." */ if (p != 0 && (p[1] == '\\' || p[1] == '/') && - isalpha(p[-1]) && (p == p2 + 1 || index(" \t:", p[-2]) != 0)) { + isalpha(p[-1]) && + (p == p2 + 1 || index(" \t:(", p[-2]) != 0)) { p = index(p + 1, ':'); check_again = 1; } @@ -971,13 +976,13 @@ read_makefile (filename, flags) target = parse_file_seq (&p2, ':', sizeof (struct nameseq), 1); ++p2; if (target == 0) - makefile_fatal (filename, lineno, "missing target pattern"); + fatal (&fileinfo, "missing target pattern"); else if (target->next != 0) - makefile_fatal (filename, lineno, "multiple target patterns"); + fatal (&fileinfo, "multiple target patterns"); pattern = target->name; pattern_percent = find_percent (pattern); if (pattern_percent == 0) - makefile_fatal (filename, lineno, + fatal (&fileinfo, "target pattern contains no `%%'"); free((char *)target); } @@ -995,7 +1000,7 @@ read_makefile (filename, flags) /* Semicolon means rest of line is a command. */ unsigned int len = strlen (cmdleft); - cmds_started = lineno; + cmds_started = fileinfo.lineno; /* Add this command line to the buffer. */ if (len + 2 > commands_len) @@ -1019,7 +1024,7 @@ read_makefile (filename, flags) } if (conditionals->if_cmds) - makefile_fatal (filename, lineno, "missing `endif'"); + fatal (&fileinfo, "missing `endif'"); /* At eof, record the last rule. */ record_waiting_files (); @@ -1028,8 +1033,7 @@ read_makefile (filename, flags) free ((char *) commands); fclose (infile); - reading_filename = 0; - reading_lineno_ptr = 0; + reading_file = 0; return 1; } @@ -1040,14 +1044,13 @@ read_makefile (filename, flags) 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) +static void +do_define (name, namelen, origin, infile, flocp) char *name; unsigned int namelen; enum variable_origin origin; - unsigned int lineno; FILE *infile; - char *filename; + struct floc *flocp; { struct linebuffer lb; unsigned int nlines = 0; @@ -1067,8 +1070,8 @@ do_define (name, namelen, origin, lineno, infile, filename) { unsigned int len; - lineno += nlines; - nlines = readline (&lb, infile, filename, lineno); + flocp->lineno += nlines; + nlines = readline (&lb, infile, flocp); collapse_continuations (lb.buffer); @@ -1080,8 +1083,7 @@ do_define (name, namelen, origin, lineno, infile, filename) p += 5; remove_comments (p); if (*next_token (p) != '\0') - makefile_error (filename, lineno, - "Extraneous text after `endef' directive"); + error (flocp, "Extraneous text after `endef' directive"); /* Define the variable. */ if (idx == 0) definition[0] = '\0'; @@ -1090,7 +1092,7 @@ do_define (name, namelen, origin, lineno, infile, filename) (void) define_variable (var, strlen (var), definition, origin, 1); free (definition); freebuffer (&lb); - return (lineno + nlines); + return; } else { @@ -1110,10 +1112,10 @@ do_define (name, namelen, origin, lineno, infile, filename) } /* No `endef'!! */ - makefile_fatal (filename, lineno, "missing `endef', unterminated `define'"); + fatal (flocp, "missing `endef', unterminated `define'"); /* NOTREACHED */ - return 0; + return; } /* Interpret conditional commands "ifdef", "ifndef", "ifeq", @@ -1128,10 +1130,9 @@ do_define (name, namelen, origin, lineno, infile, filename) 1 if following text should be ignored. */ static int -conditional_line (line, filename, lineno) +conditional_line (line, flocp) char *line; - char *filename; - unsigned int lineno; + const struct floc *flocp; { int notdef; char *cmdname; @@ -1165,17 +1166,16 @@ conditional_line (line, filename, lineno) if (*cmdname == 'e') { if (*line != '\0') - makefile_error (filename, lineno, - "Extraneous text after `%s' directive", - cmdname); + error (flocp, + "Extraneous text after `%s' directive", cmdname); /* "Else" or "endif". */ if (conditionals->if_cmds == 0) - makefile_fatal (filename, lineno, "extraneous `%s'", cmdname); + fatal (flocp, "extraneous `%s'", cmdname); /* NOTDEF indicates an `endif' command. */ if (notdef) --conditionals->if_cmds; else if (conditionals->seen_else[conditionals->if_cmds - 1]) - makefile_fatal (filename, lineno, "only one `else' per conditional"); + fatal (flocp, "only one `else' per conditional"); else { /* Toggle the state of ignorance. */ @@ -1321,9 +1321,8 @@ conditional_line (line, filename, lineno) *line = '\0'; line = next_token (++line); if (*line != '\0') - makefile_error (filename, lineno, - "Extraneous text after `%s' directive", - cmdname); + error (flocp, + "Extraneous text after `%s' directive", cmdname); s2 = variable_expand (s2); conditionals->ignoring[conditionals->if_cmds - 1] @@ -1384,13 +1383,12 @@ uniquize_deps (chain) variable value list. */ static void -record_target_var (filenames, defn, two_colon, origin, filename, lineno) +record_target_var (filenames, defn, two_colon, origin, flocp) struct nameseq *filenames; char *defn; int two_colon; enum variable_origin origin; - char *filename; - unsigned int lineno; + const struct floc *flocp; { struct nameseq *nextf; struct variable_set_list *global; @@ -1433,10 +1431,9 @@ record_target_var (filenames, defn, two_colon, origin, filename, lineno) /* Make the new variable context current and define the variable. */ current_variable_set_list = vlist; - v = try_variable_definition(filename, lineno, defn, origin); + v = try_variable_definition(flocp, defn, origin); if (!v) - makefile_error(filename, lineno, - "Malformed per-target variable definition"); + error (flocp, "Malformed per-target variable definition"); v->per_target = 1; /* If it's not an override, check to see if there was a command-line @@ -1474,7 +1471,7 @@ record_target_var (filenames, defn, two_colon, origin, filename, lineno) static void record_files (filenames, pattern, pattern_percent, deps, cmds_started, - commands, commands_idx, two_colon, filename, lineno, set_default) + commands, commands_idx, two_colon, flocp, set_default) struct nameseq *filenames; char *pattern, *pattern_percent; struct dep *deps; @@ -1482,8 +1479,7 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started, char *commands; unsigned int commands_idx; int two_colon; - char *filename; - unsigned int lineno; + const struct floc *flocp; int set_default; { struct nameseq *nextf; @@ -1495,8 +1491,8 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started, if (commands_idx > 0) { cmds = (struct commands *) xmalloc (sizeof (struct commands)); - cmds->filename = filename; - cmds->lineno = cmds_started; + cmds->fileinfo.filenm = flocp->filenm; + cmds->fileinfo.lineno = cmds_started; cmds->commands = savestring (commands, commands_idx); cmds->command_lines = 0; } @@ -1519,11 +1515,10 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started, implicit |= implicit_percent != 0; if (implicit && pattern != 0) - makefile_fatal (filename, lineno, - "mixed implicit and static pattern rules"); + fatal (flocp, "mixed implicit and static pattern rules"); if (implicit && implicit_percent == 0) - makefile_fatal (filename, lineno, "mixed implicit and normal rules"); + fatal (flocp, "mixed implicit and normal rules"); if (implicit) { @@ -1562,7 +1557,7 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started, if (!pattern_matches (pattern, pattern_percent, name)) { /* Give a warning if the rule is meaningless. */ - makefile_error (filename, lineno, + error (flocp, "target `%s' doesn't match the target pattern", name); this = 0; @@ -1594,15 +1589,15 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started, f = enter_file (name); if (f->double_colon) - makefile_fatal (filename, lineno, + fatal (flocp, "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, + error + (flocp, "target `%s' given more than once in the same rule.", f->name); @@ -1611,10 +1606,10 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started, whose commands were preinitialized. */ else if (cmds != 0 && f->cmds != 0 && f->is_target) { - makefile_error (cmds->filename, cmds->lineno, + error (&cmds->fileinfo, "warning: overriding commands for target `%s'", f->name); - makefile_error (f->cmds->filename, f->cmds->lineno, + error (&f->cmds->fileinfo, "warning: ignoring old commands for target `%s'", f->name); } @@ -1696,7 +1691,7 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started, /* 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, + fatal (flocp, "target file `%s' has both : and :: entries", f->name); f = enter_file (name); @@ -2089,12 +2084,11 @@ parse_file_seq (stringp, stopchar, size, strip) Return the number of actual lines read (> 1 if hacked continuation lines). */ -static unsigned int -readline (linebuffer, stream, filename, lineno) +static unsigned long +readline (linebuffer, stream, flocp) struct linebuffer *linebuffer; FILE *stream; - char *filename; - unsigned int lineno; + const struct floc *flocp; { char *buffer = linebuffer->buffer; register char *p = linebuffer->buffer; @@ -2116,8 +2110,7 @@ readline (linebuffer, stream, filename, lineno) lossage strikes again! (xmkmf puts NULs in its makefiles.) There is nothing really to be done; we synthesize a newline so the following line doesn't appear to be part of this line. */ - makefile_error (filename, lineno, - "warning: NUL character seen; rest of line ignored"); + error (flocp, "warning: NUL character seen; rest of line ignored"); p[0] = '\n'; len = 1; } @@ -2177,7 +2170,7 @@ readline (linebuffer, stream, filename, lineno) } if (ferror (stream)) - pfatal_with_name (filename); + pfatal_with_name (flocp->filenm); return nlines; } @@ -2296,8 +2289,12 @@ get_next_mword (buffer, delim, startp, length) case ':': #if defined(__MSDOS__) || defined(WINDOWS32) - /* A word CAN include a colon in its drive spec. */ - if (!(p - beg == 2 && (*p == '/' || *p == '\\') && isalpha (*beg))) + /* A word CAN include a colon in its drive spec. The drive + spec is allowed either at the beginning of a word, or as part + of the archive member name, like in "libfoo.a(d:/foo/bar.o)". */ + if (!(p - beg >= 2 && + (*p == '/' || *p == '\\') && isalpha (p[-2]) && + (p - beg == 2 || p[-3] == '('))) #endif goto done_word; @@ -2657,7 +2654,7 @@ multi_glob (chain, size) } case GLOB_NOSPACE: - fatal ("virtual memory exhausted"); + fatal (NILF, "virtual memory exhausted"); break; default: diff --git a/remake.c b/remake.c index 9c459a48..d312321e 100644 --- a/remake.c +++ b/remake.c @@ -48,13 +48,11 @@ unsigned int commands_started = 0; static int update_file PARAMS ((struct file *file, unsigned int depth)); static int update_file_1 PARAMS ((struct file *file, unsigned int depth)); -static int check_dep PARAMS ((struct file *file, unsigned int depth, time_t this_mtime, int *must_make_ptr)); +static int check_dep PARAMS ((struct file *file, unsigned int depth, FILE_TIMESTAMP this_mtime, int *must_make_ptr)); static int touch_file PARAMS ((struct file *file)); static void remake_file PARAMS ((struct file *file)); -static time_t name_mtime PARAMS ((char *name)); -static int library_search PARAMS ((char **lib, time_t *mtime_ptr)); - -extern time_t f_mtime PARAMS ((struct file *file, int search)); +static FILE_TIMESTAMP name_mtime PARAMS ((char *name)); +static int library_search PARAMS ((char **lib, FILE_TIMESTAMP *mtime_ptr)); /* Remake all the goals in the `struct dep' chain GOALS. Return -1 if nothing @@ -128,7 +126,7 @@ update_goal_chain (goals, makefiles) { unsigned int ocommands_started; int x; - time_t mtime = MTIME (file); + FILE_TIMESTAMP mtime = MTIME (file); check_renamed (file); if (makefiles) { @@ -268,9 +266,9 @@ no_rule_error(file) if (!file->dontcare) { if (file->parent == 0) - error (msg_noparent, "*** ", file->name, "."); + error (NILF, msg_noparent, "*** ", file->name, "."); else - error (msg_parent, "*** ", + error (NILF, msg_parent, "*** ", file->name, file->parent->name, "."); file->shownerror = 1; } @@ -279,9 +277,9 @@ no_rule_error(file) else { if (file->parent == 0) - fatal (msg_noparent, "", file->name, ""); + fatal (NILF, msg_noparent, "", file->name, ""); else - fatal (msg_parent, "", file->name, file->parent->name, ""); + fatal (NILF, msg_parent, "", file->name, file->parent->name, ""); } } @@ -341,7 +339,7 @@ update_file_1 (file, depth) struct file *file; unsigned int depth; { - register time_t this_mtime; + register FILE_TIMESTAMP this_mtime; int noexist, must_make, deps_changed; int dep_status = 0; register struct dep *d, *lastd; @@ -396,7 +394,7 @@ update_file_1 (file, depth) this_mtime = file_mtime (file); check_renamed (file); - noexist = this_mtime == (time_t) -1; + noexist = this_mtime == (FILE_TIMESTAMP) -1; if (noexist) DEBUGPR ("File `%s' does not exist.\n"); @@ -427,7 +425,7 @@ update_file_1 (file, depth) d = file->deps; while (d != 0) { - time_t mtime; + FILE_TIMESTAMP mtime; check_renamed (d->file); @@ -436,7 +434,7 @@ update_file_1 (file, depth) if (d->file->updating) { - error ("Circular %s <- %s dependency dropped.", + error (NILF, "Circular %s <- %s dependency dropped.", file->name, d->file->name); /* We cannot free D here because our the caller will still have a reference to it when we were called recursively via @@ -484,7 +482,7 @@ update_file_1 (file, depth) for (d = file->deps; d != 0; d = d->next) if (d->file->intermediate) { - time_t mtime = file_mtime (d->file); + FILE_TIMESTAMP mtime = file_mtime (d->file); check_renamed (d->file); d->file->parent = file; dep_status |= update_file (d->file, depth); @@ -537,7 +535,7 @@ update_file_1 (file, depth) if (depth == 0 && keep_going_flag && !just_print_flag && !question_flag) - error ("Target `%s' not remade because of errors.", file->name); + error (NILF, "Target `%s' not remade because of errors.", file->name); return dep_status; } @@ -559,13 +557,13 @@ update_file_1 (file, depth) deps_changed = 0; for (d = file->deps; d != 0; d = d->next) { - time_t d_mtime = file_mtime (d->file); + FILE_TIMESTAMP 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) + if (d_mtime == (FILE_TIMESTAMP) -1 && !d->file->intermediate) /* We must remake if this dep does not exist and is not intermediate. */ must_make = 1; @@ -581,7 +579,7 @@ update_file_1 (file, depth) if (debug_flag && !noexist) { print_spaces (depth); - if (d_mtime == (time_t) -1) + if (d_mtime == (FILE_TIMESTAMP) -1) printf ("Dependency `%s' does not exist.\n", dep_name (d)); else printf ("Dependency `%s' is %s than dependent `%s'.\n", @@ -771,7 +769,7 @@ static int check_dep (file, depth, this_mtime, must_make_ptr) struct file *file; unsigned int depth; - time_t this_mtime; + FILE_TIMESTAMP this_mtime; int *must_make_ptr; { register struct dep *d; @@ -784,21 +782,20 @@ check_dep (file, depth, this_mtime, must_make_ptr) /* If this is a non-intermediate file, update it and record whether it is newer than THIS_MTIME. */ { - time_t mtime; + FILE_TIMESTAMP 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) + if (mtime == (FILE_TIMESTAMP) -1 || mtime > this_mtime) *must_make_ptr = 1; } else { /* FILE is an intermediate file. */ - time_t mtime; + FILE_TIMESTAMP mtime; - if (!file->phony && file->cmds == 0 && !file->tried_implicit - && file->secondary) + if (!file->phony && file->cmds == 0 && !file->tried_implicit) { if (try_implicit_rule (file, depth)) DEBUGPR ("Found an implicit rule for `%s'.\n"); @@ -806,7 +803,7 @@ check_dep (file, depth, this_mtime, must_make_ptr) DEBUGPR ("No implicit rule found for `%s'.\n"); file->tried_implicit = 1; } - if (file->cmds == 0 && !file->is_target && file->secondary + if (file->cmds == 0 && !file->is_target && default_file != 0 && default_file->cmds != 0) { DEBUGPR ("Using default commands for `%s'.\n"); @@ -818,7 +815,7 @@ check_dep (file, depth, this_mtime, must_make_ptr) check_renamed (file); mtime = file_mtime (file); check_renamed (file); - if (mtime != (time_t) -1 && mtime > this_mtime) + if (mtime != (FILE_TIMESTAMP) -1 && mtime > this_mtime) *must_make_ptr = 1; /* Otherwise, update all non-intermediate files we depend on, if necessary, and see whether any of them is more @@ -833,7 +830,7 @@ check_dep (file, depth, this_mtime, must_make_ptr) { if (d->file->updating) { - error ("Circular %s <- %s dependency dropped.", + error (NILF, "Circular %s <- %s dependency dropped.", file->name, d->file->name); if (lastd == 0) { @@ -858,7 +855,7 @@ check_dep (file, depth, this_mtime, must_make_ptr) if (d->file->command_state == cs_running || d->file->command_state == cs_deps_running) - /* Record that some of FILE's dependencies are still being made. + /* Record that some of FILE's deps are still being made. This tells the upper levels to wait on processing it until the commands are finished. */ set_command_state (file, cs_deps_running); @@ -978,12 +975,12 @@ remake_file (file) the library's actual name (/lib/libLIBNAME.a, etc.) is substituted into FILE. */ -time_t +FILE_TIMESTAMP f_mtime (file, search) register struct file *file; int search; { - time_t mtime; + FILE_TIMESTAMP mtime; /* File's mtime is not known; must get it from the system. */ @@ -1049,9 +1046,9 @@ f_mtime (file, search) free (arname); free (memname); - if (mtime == (time_t) -1) + if (mtime == (FILE_TIMESTAMP) -1) /* The archive doesn't exist, so it's members don't exist either. */ - return (time_t) -1; + return (FILE_TIMESTAMP) -1; mtime = ar_member_date (file->hname); } @@ -1060,7 +1057,7 @@ f_mtime (file, search) { mtime = name_mtime (file->name); - if (mtime == (time_t) -1 && search && !file->ignore_vpath) + if (mtime == (FILE_TIMESTAMP) -1 && search && !file->ignore_vpath) { /* If name_mtime failed, search VPATH. */ char *name = file->name; @@ -1098,16 +1095,15 @@ f_mtime (file, search) We only need to do this once, for now. */ - static time_t now = 0; + static FILE_TIMESTAMP now = 0; if (!clock_skew_detected - && mtime != (time_t)-1 && mtime > now + && mtime != (FILE_TIMESTAMP)-1 && mtime > now && !file->updated) { /* This file's time appears to be in the future. Update our concept of the present, and compare again. */ - extern time_t time (); - time (&now); + now = file_timestamp_now (); #ifdef WINDOWS32 /* @@ -1126,8 +1122,13 @@ f_mtime (file, search) #endif #endif { - error("*** Warning: File `%s' has modification time in the future (%ld > %ld)", - file->name, mtime, now); + char mtimebuf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; + char nowbuf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; + + file_timestamp_sprintf (mtimebuf, mtime); + file_timestamp_sprintf (nowbuf, now); + error (NILF, "*** Warning: File `%s' has modification time in the future (%s > %s)", + file->name, mtimebuf, nowbuf); clock_skew_detected = 1; } } @@ -1148,16 +1149,16 @@ f_mtime (file, search) /* Return the mtime of the file or archive-member reference NAME. */ -static time_t +static FILE_TIMESTAMP name_mtime (name) register char *name; { struct stat st; if (stat (name, &st) < 0) - return (time_t) -1; + return (FILE_TIMESTAMP) -1; - return (time_t) st.st_mtime; + return FILE_TIMESTAMP_STAT_MODTIME (st); } @@ -1168,7 +1169,7 @@ name_mtime (name) static int library_search (lib, mtime_ptr) char **lib; - time_t *mtime_ptr; + FILE_TIMESTAMP *mtime_ptr; { static char *dirs[] = { @@ -1188,7 +1189,7 @@ library_search (lib, mtime_ptr) }; char *libname = &(*lib)[2]; /* Name without the `-l'. */ - time_t mtime; + FILE_TIMESTAMP mtime; /* Buffer to construct possible names in. */ char *buf = xmalloc (sizeof (LIBDIR) + 8 + strlen (libname) + 4 + 2 + 1); @@ -1202,7 +1203,7 @@ library_search (lib, mtime_ptr) sprintf (buf, "%s.lib", libname); #endif mtime = name_mtime (buf); - if (mtime != (time_t) -1) + if (mtime != (FILE_TIMESTAMP) -1) { *lib = buf; if (mtime_ptr != 0) @@ -1235,7 +1236,7 @@ library_search (lib, mtime_ptr) buf = (char *) xrealloc (djdir_len + 1); sprintf (buf, "%s/lib/lib%s.a", djdir->value, libname); mtime = name_mtime (buf); - if (mtime != (time_t) -1) + if (mtime != (FILE_TIMESTAMP) -1) { *lib = buf; if (mtime_ptr != 0) @@ -1254,7 +1255,7 @@ library_search (lib, mtime_ptr) sprintf (buf, "%s/%s.lib", *dp, libname); #endif mtime = name_mtime (buf); - if (mtime != (time_t) -1) + if (mtime != (FILE_TIMESTAMP) -1) { *lib = buf; if (mtime_ptr != 0) diff --git a/remote-cstms.c b/remote-cstms.c index e1d63a3a..cf918163 100644 --- a/remote-cstms.c +++ b/remote-cstms.c @@ -157,7 +157,7 @@ start_remote_job (argv, envp, stdin_fd, is_remote, id_ptr, used_stdin) retsock = Rpc_UdpCreate (True, 0); if (retsock < 0) { - error ("exporting: Couldn't create return socket."); + error (NILF, "exporting: Couldn't create return socket."); return 1; } @@ -202,7 +202,7 @@ start_remote_job (argv, envp, stdin_fd, is_remote, id_ptr, used_stdin) { (void) close (retsock); (void) close (sock); - error ("exporting to %s: %s", + error (NILF, "exporting to %s: %s", host ? host->h_name : inet_ntoa (permit.addr), Rpc_ErrorMessage (status)); return 1; @@ -211,14 +211,14 @@ start_remote_job (argv, envp, stdin_fd, is_remote, id_ptr, used_stdin) { (void) close (retsock); (void) close (sock); - error ("exporting to %s: %s", + error (NILF, "exporting to %s: %s", host ? host->h_name : inet_ntoa (permit.addr), msg); return 1; } else { - error ("*** exported to %s (id %u)", + error (NILF, "*** exported to %s (id %u)", host ? host->h_name : inet_ntoa (permit.addr), permit.id); } diff --git a/rule.c b/rule.c index 69336312..eb4602fd 100644 --- a/rule.c +++ b/rule.c @@ -416,8 +416,8 @@ install_pattern_rule (p, terminal) { r->terminal = terminal; r->cmds = (struct commands *) xmalloc (sizeof (struct commands)); - r->cmds->filename = 0; - r->cmds->lineno = 0; + r->cmds->fileinfo.filenm = 0; + r->cmds->fileinfo.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)); @@ -664,7 +664,7 @@ print_rule_data_base () } if (num_pattern_rules != rules) - fatal ("BUG: num_pattern_rules wrong! %u != %u", + fatal (NILF, "BUG: num_pattern_rules wrong! %u != %u", num_pattern_rules, rules); puts ("\n# Pattern-specific variable values"); diff --git a/rule.h b/rule.h index 4effeb03..f57c7e01 100644 --- a/rule.h +++ b/rule.h @@ -62,3 +62,10 @@ extern void install_pattern_rule PARAMS ((struct pspec *p, int terminal)); extern int new_pattern_rule PARAMS ((struct rule *rule, int override)); extern struct pattern_var *create_pattern_var PARAMS ((char *target, char *suffix)); extern struct pattern_var *lookup_pattern_var PARAMS ((char *target)); +extern void count_implicit_rule_limits PARAMS ((void)); +extern void convert_to_pattern PARAMS ((void)); +extern void create_pattern_rule PARAMS ((char **targets, + char **target_percents, int terminal, + struct dep *deps, + struct commands *commands, + int override)); diff --git a/variable.c b/variable.c index 3155a925..85987dbf 100644 --- a/variable.c +++ b/variable.c @@ -676,9 +676,8 @@ target_environment (file) returned. */ struct variable * -try_variable_definition (filename, lineno, line, origin) - char *filename; - unsigned int lineno; +try_variable_definition (flocp, line, origin) + const struct floc *flocp; char *line; enum variable_origin origin; { @@ -766,7 +765,7 @@ try_variable_definition (filename, lineno, line, origin) expanded_name = allocated_variable_expand (name); if (expanded_name[0] == '\0') - makefile_fatal (filename, lineno, "empty variable name"); + fatal (flocp, "empty variable name"); /* Calculate the variable's new value in VALUE. */ diff --git a/variable.h b/variable.h index 4289c147..b1d0daf4 100644 --- a/variable.h +++ b/variable.h @@ -102,7 +102,7 @@ extern void initialize_file_variables PARAMS ((struct file *file)); extern void print_file_variables PARAMS ((struct file *file)); extern void print_variable_set PARAMS ((struct variable_set *set, char *prefix)); extern void merge_variable_set_lists PARAMS ((struct variable_set_list **setlist0, struct variable_set_list *setlist1)); -extern struct variable *try_variable_definition PARAMS ((char *filename, unsigned int lineno, char *line, enum variable_origin origin)); +extern struct variable *try_variable_definition PARAMS ((const struct floc *flocp, char *line, enum variable_origin origin)); extern struct variable *lookup_variable PARAMS ((char *name, unsigned int length)); extern struct variable *define_variable PARAMS ((char *name, unsigned int length, char *value, diff --git a/vpath.c b/vpath.c index ab88ac31..d3320313 100644 --- a/vpath.c +++ b/vpath.c @@ -48,7 +48,7 @@ static struct vpath *general_vpath; static struct vpath *gpaths; -static int selective_vpath_search PARAMS ((struct vpath *path, char **file, time_t *mtime_ptr)); +static int selective_vpath_search PARAMS ((struct vpath *path, char **file, FILE_TIMESTAMP *mtime_ptr)); /* Reverse the chain of selective VPATH lists so they will be searched in the order given in the makefiles @@ -338,7 +338,7 @@ gpath_search (file, len) int vpath_search (file, mtime_ptr) char **file; - time_t *mtime_ptr; + FILE_TIMESTAMP *mtime_ptr; { register struct vpath *v; @@ -376,7 +376,7 @@ static int selective_vpath_search (path, file, mtime_ptr) struct vpath *path; char **file; - time_t *mtime_ptr; + FILE_TIMESTAMP *mtime_ptr; { int not_target; char *name, *n; @@ -524,7 +524,9 @@ selective_vpath_search (path, file, mtime_ptr) /* Store the modtime into *MTIME_PTR for the caller. If we have had no need to stat the file here, we record a zero modtime to indicate this. */ - *mtime_ptr = exists_in_cache ? st.st_mtime : (time_t) 0; + *mtime_ptr = (exists_in_cache + ? FILE_TIMESTAMP_STAT_MODTIME (st) + : (FILE_TIMESTAMP) 0); free (name); return 1; diff --git a/w32/subproc/NMakefile b/w32/subproc/NMakefile index f1878278..66afe650 100644 --- a/w32/subproc/NMakefile +++ b/w32/subproc/NMakefile @@ -1,60 +1,60 @@ -# NOTE: If you have no `make' program at all to process this makefile, run -# `build.bat' instead. -# -# Copyright (C) 1988,89,91,92,93,94,95,96,97 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. - -# -# NMakefile for GNU Make (subproc library) -# -LIB = lib -CC = cl - -OUTDIR=. -MAKEFILE=NMakefile - -CFLAGS_any = /nologo /MT /W3 /GX /Z7 /YX /D WIN32 /D WINDOWS32 /D _WINDOWS -I. -I../include -I../.. -CFLAGS_debug = $(CFLAGS_any) /Od /D _DEBUG /FR.\WinDebug\ /Fp.\WinDebug\subproc.pch /Fo.\WinDebug/ -CFLAGS_release = $(CFLAGS_any) /O2 /FR.\WinRel\ /Fp.\WinRel\subproc.pch /Fo.\WinRel/ - -all: Release Debug - -Release: - $(MAKE) /f $(MAKEFILE) OUTDIR=WinRel CFLAGS="$(CFLAGS_release)" WinRel/subproc.lib -Debug: - $(MAKE) /f $(MAKEFILE) OUTDIR=WinDebug CFLAGS="$(CFLAGS_debug)" WinDebug/subproc.lib - -clean: - rmdir /s /q WinRel WinDebug - erase *.pdb - -$(OUTDIR): - if not exist .\$@\nul mkdir .\$@ - -OBJS = $(OUTDIR)/misc.obj $(OUTDIR)/w32err.obj $(OUTDIR)/sub_proc.obj - -$(OUTDIR)/subproc.lib: $(OUTDIR) $(OBJS) - $(LIB) -out:$@ @<< - $(OBJS) -<< - -.c{$(OUTDIR)}.obj: - $(CC) $(CFLAGS) /c $< - -$(OUTDIR)/misc.obj: misc.c proc.h -$(OUTDIR)/sub_proc.obj: sub_proc.c ../include/sub_proc.h ../include/w32err.h proc.h -$(OUTDIR)/w32err.obj: w32err.c ../include/w32err.h +# NOTE: If you have no `make' program at all to process this makefile, run +# `build.bat' instead. +# +# Copyright (C) 1988,89,91,92,93,94,95,96,97 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. + +# +# NMakefile for GNU Make (subproc library) +# +LIB = lib +CC = cl + +OUTDIR=. +MAKEFILE=NMakefile + +CFLAGS_any = /nologo /MT /W3 /GX /Z7 /YX /D WIN32 /D WINDOWS32 /D _WINDOWS -I. -I../include -I../../ +CFLAGS_debug = $(CFLAGS_any) /Od /D _DEBUG /FR.\WinDebug\ /Fp.\WinDebug\subproc.pch /Fo.\WinDebug/ +CFLAGS_release = $(CFLAGS_any) /O2 /FR.\WinRel\ /Fp.\WinRel\subproc.pch /Fo.\WinRel/ + +all: Release Debug + +Release: + $(MAKE) /f $(MAKEFILE) OUTDIR=WinRel CFLAGS="$(CFLAGS_release)" WinRel/subproc.lib +Debug: + $(MAKE) /f $(MAKEFILE) OUTDIR=WinDebug CFLAGS="$(CFLAGS_debug)" WinDebug/subproc.lib + +clean: + rmdir /s /q WinRel WinDebug + erase *.pdb + +$(OUTDIR): + if not exist .\$@\nul mkdir .\$@ + +OBJS = $(OUTDIR)/misc.obj $(OUTDIR)/w32err.obj $(OUTDIR)/sub_proc.obj + +$(OUTDIR)/subproc.lib: $(OUTDIR) $(OBJS) + $(LIB) -out:$@ @<< + $(OBJS) +<< + +.c{$(OUTDIR)}.obj: + $(CC) $(CFLAGS) /c $< + +$(OUTDIR)/misc.obj: misc.c proc.h +$(OUTDIR)/sub_proc.obj: sub_proc.c ../include/sub_proc.h ../include/w32err.h proc.h +$(OUTDIR)/w32err.obj: w32err.c ../include/w32err.h diff --git a/w32/subproc/sub_proc.c b/w32/subproc/sub_proc.c index 281c81cd..300bb7b9 100644 --- a/w32/subproc/sub_proc.c +++ b/w32/subproc/sub_proc.c @@ -1,1186 +1,1190 @@ -#include -#include -#include /* for msvc _beginthreadex, _endthreadex */ -#include - -#include "sub_proc.h" -#include "proc.h" -#include "w32err.h" -#include "config.h" - -static char *make_command_line( char *shell_name, char *exec_path, char **argv); - -typedef struct sub_process_t { - int sv_stdin[2]; - int sv_stdout[2]; - int sv_stderr[2]; - int using_pipes; - char *inp; - DWORD incnt; - char * volatile outp; - volatile DWORD outcnt; - char * volatile errp; - volatile DWORD errcnt; - int pid; - int exit_code; - int signal; - long last_err; - long lerrno; -} sub_process; - -/* keep track of children so we can implement a waitpid-like routine */ -static sub_process *proc_array[256]; -static int proc_index = 0; -static int fake_exits_pending = 0; - -/* - * When a process has been waited for, adjust the wait state - * array so that we don't wait for it again - */ -static void -process_adjust_wait_state(sub_process* pproc) -{ - int i; - - if (!proc_index) - return; - - for (i = 0; i < proc_index; i++) - if (proc_array[i]->pid == pproc->pid) - break; - - if (i < proc_index) { - proc_index--; - if (i != proc_index) - memmove(&proc_array[i], &proc_array[i+1], - (proc_index-i) * sizeof(sub_process*)); - proc_array[proc_index] = NULL; - } -} - -/* - * Waits for any of the registered child processes to finish. - */ -static sub_process * -process_wait_for_any_private(void) -{ - HANDLE handles[256]; - DWORD retval, which; - int i; - - if (!proc_index) - return NULL; - - /* build array of handles to wait for */ - for (i = 0; i < proc_index; i++) { - handles[i] = (HANDLE) proc_array[i]->pid; - - if (fake_exits_pending && proc_array[i]->exit_code) - break; - } - - /* wait for someone to exit */ - if (!fake_exits_pending) { - retval = WaitForMultipleObjects(proc_index, handles, FALSE, INFINITE); - which = retval - WAIT_OBJECT_0; - } else { - fake_exits_pending--; - retval = !WAIT_FAILED; - which = i; - } - - /* return pointer to process */ - if (retval != WAIT_FAILED) { - sub_process* pproc = proc_array[which]; - process_adjust_wait_state(pproc); - return pproc; - } else - return NULL; -} - -/* - * Terminate a process. - */ -BOOL -process_kill(HANDLE proc, int signal) -{ - sub_process* pproc = (sub_process*) proc; - pproc->signal = signal; - return (TerminateProcess((HANDLE) pproc->pid, signal)); -} - -/* - * Use this function to register processes you wish to wait for by - * calling process_file_io(NULL) or process_wait_any(). This must be done - * because it is possible for callers of this library to reuse the same - * handle for multiple processes launches :-( - */ -void -process_register(HANDLE proc) -{ - proc_array[proc_index++] = (sub_process *) proc; -} - -/* - * Public function which works kind of like waitpid(). Wait for any - * of the children to die and return results. To call this function, - * you must do 1 of things: - * - * x = process_easy(...); - * - * or - * - * x = process_init_fd(); - * process_register(x); - * - * or - * - * x = process_init(); - * process_register(x); - * - * You must NOT then call process_pipe_io() because this function is - * not capable of handling automatic notification of any child - * death. - */ - -HANDLE -process_wait_for_any(void) -{ - sub_process* pproc = process_wait_for_any_private(); - - if (!pproc) - return NULL; - else { - /* - * Ouch! can't tell caller if this fails directly. Caller - * will have to use process_last_err() - */ - (void) process_file_io(pproc); - return ((HANDLE) pproc); - } -} - -long -process_errno(HANDLE proc) -{ - return (((sub_process *)proc)->lerrno); -} - -long -process_signal(HANDLE proc) -{ - return (((sub_process *)proc)->signal); -} - - long -process_last_err(HANDLE proc) -{ - return (((sub_process *)proc)->last_err); -} - - long -process_exit_code(HANDLE proc) -{ - return (((sub_process *)proc)->exit_code); -} - - char * -process_outbuf(HANDLE proc) -{ - return (((sub_process *)proc)->outp); -} - - char * -process_errbuf(HANDLE proc) -{ - return (((sub_process *)proc)->errp); -} - - int -process_outcnt(HANDLE proc) -{ - return (((sub_process *)proc)->outcnt); -} - - int -process_errcnt(HANDLE proc) -{ - return (((sub_process *)proc)->errcnt); -} - - void -process_pipes(HANDLE proc, int pipes[3]) -{ - pipes[0] = ((sub_process *)proc)->sv_stdin[0]; - pipes[1] = ((sub_process *)proc)->sv_stdout[0]; - pipes[2] = ((sub_process *)proc)->sv_stderr[0]; - return; -} - - - HANDLE -process_init() -{ - sub_process *pproc; - /* - * open file descriptors for attaching stdin/stdout/sterr - */ - HANDLE stdin_pipes[2]; - HANDLE stdout_pipes[2]; - HANDLE stderr_pipes[2]; - SECURITY_ATTRIBUTES inherit; - BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH]; - - pproc = malloc(sizeof(*pproc)); - memset(pproc, 0, sizeof(*pproc)); - - /* We can't use NULL for lpSecurityDescriptor because that - uses the default security descriptor of the calling process. - Instead we use a security descriptor with no DACL. This - allows nonrestricted access to the associated objects. */ - - if (!InitializeSecurityDescriptor((PSECURITY_DESCRIPTOR)(&sd), - SECURITY_DESCRIPTOR_REVISION)) { - pproc->last_err = GetLastError(); - pproc->lerrno = E_SCALL; - return((HANDLE)pproc); - } - - inherit.nLength = sizeof(inherit); - inherit.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(&sd); - inherit.bInheritHandle = TRUE; - - // By convention, parent gets pipe[0], and child gets pipe[1] - // This means the READ side of stdin pipe goes into pipe[1] - // and the WRITE side of the stdout and stderr pipes go into pipe[1] - if (CreatePipe( &stdin_pipes[1], &stdin_pipes[0], &inherit, 0) == FALSE || - CreatePipe( &stdout_pipes[0], &stdout_pipes[1], &inherit, 0) == FALSE || - CreatePipe( &stderr_pipes[0], &stderr_pipes[1], &inherit, 0) == FALSE) { - - pproc->last_err = GetLastError(); - pproc->lerrno = E_SCALL; - return((HANDLE)pproc); - } - - // - // Mark the parent sides of the pipes as non-inheritable - // - if (SetHandleInformation(stdin_pipes[0], - HANDLE_FLAG_INHERIT, 0) == FALSE || - SetHandleInformation(stdout_pipes[0], - HANDLE_FLAG_INHERIT, 0) == FALSE || - SetHandleInformation(stderr_pipes[0], - HANDLE_FLAG_INHERIT, 0) == FALSE) { - - pproc->last_err = GetLastError(); - pproc->lerrno = E_SCALL; - return((HANDLE)pproc); - } - pproc->sv_stdin[0] = (int) stdin_pipes[0]; - pproc->sv_stdin[1] = (int) stdin_pipes[1]; - pproc->sv_stdout[0] = (int) stdout_pipes[0]; - pproc->sv_stdout[1] = (int) stdout_pipes[1]; - pproc->sv_stderr[0] = (int) stderr_pipes[0]; - pproc->sv_stderr[1] = (int) stderr_pipes[1]; - - pproc->using_pipes = 1; - - pproc->lerrno = 0; - - return((HANDLE)pproc); -} - - - HANDLE -process_init_fd(HANDLE stdinh, HANDLE stdouth, HANDLE stderrh) -{ - sub_process *pproc; - - pproc = malloc(sizeof(*pproc)); - memset(pproc, 0, sizeof(*pproc)); - - /* - * Just pass the provided file handles to the 'child side' of the - * pipe, bypassing pipes altogether. - */ - pproc->sv_stdin[1] = (int) stdinh; - pproc->sv_stdout[1] = (int) stdouth; - pproc->sv_stderr[1] = (int) stderrh; - - pproc->last_err = pproc->lerrno = 0; - - return((HANDLE)pproc); -} - - -static HANDLE -find_file(char *exec_path, LPOFSTRUCT file_info) -{ - HANDLE exec_handle; - char *fname; - char *ext; - - fname = malloc(strlen(exec_path) + 5); - strcpy(fname, exec_path); - ext = fname + strlen(fname); - - strcpy(ext, ".exe"); - if ((exec_handle = (HANDLE)OpenFile(fname, file_info, - OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) { - free(fname); - return(exec_handle); - } - - strcpy(ext, ".cmd"); - if ((exec_handle = (HANDLE)OpenFile(fname, file_info, - OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) { - free(fname); - return(exec_handle); - } - - strcpy(ext, ".bat"); - if ((exec_handle = (HANDLE)OpenFile(fname, file_info, - OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) { - free(fname); - return(exec_handle); - } - - /* should .com come before this case? */ - if ((exec_handle = (HANDLE)OpenFile(exec_path, file_info, - OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) { - free(fname); - return(exec_handle); - } - - strcpy(ext, ".com"); - if ((exec_handle = (HANDLE)OpenFile(fname, file_info, - OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) { - free(fname); - return(exec_handle); - } - - free(fname); - return(exec_handle); -} - - -/* - * Description: Create the child process to be helped - * - * Returns: - * - * Notes/Dependencies: - */ -long -process_begin( - HANDLE proc, - char **argv, - char **envp, - char *exec_path, - char *as_user) -{ - sub_process *pproc = (sub_process *)proc; - char *shell_name = 0; - int file_not_found=0; - HANDLE exec_handle; - char buf[256]; - DWORD bytes_returned; - DWORD flags; - char *command_line; - STARTUPINFO startInfo; - PROCESS_INFORMATION procInfo; - char *envblk=NULL; - OFSTRUCT file_info; - - - /* - * Shell script detection... if the exec_path starts with #! then - * we want to exec shell-script-name exec-path, not just exec-path - * NT doesn't recognize #!/bin/sh or #!/etc/Tivoli/bin/perl. We do not - * hard-code the path to the shell or perl or whatever: Instead, we - * assume it's in the path somewhere (generally, the NT tools - * bin directory) - * We use OpenFile here because it is capable of searching the Path. - */ - - exec_handle = find_file(exec_path, &file_info); - - /* - * If we couldn't open the file, just assume that Windows32 will be able - * to find and execute it. - */ - if (exec_handle == (HANDLE)HFILE_ERROR) { - file_not_found++; - } - else { - /* Attempt to read the first line of the file */ - if (ReadFile( exec_handle, - buf, sizeof(buf) - 1, /* leave room for trailing NULL */ - &bytes_returned, 0) == FALSE || bytes_returned < 2) { - - pproc->last_err = GetLastError(); - pproc->lerrno = E_IO; - CloseHandle(exec_handle); - return(-1); - } - if (buf[0] == '#' && buf[1] == '!') { - /* - * This is a shell script... Change the command line from - * exec_path args to shell_name exec_path args - */ - char *p; - - /* Make sure buf is NULL terminated */ - buf[bytes_returned] = 0; - /* - * Depending on the file system type, etc. the first line - * of the shell script may end with newline or newline-carriage-return - * Whatever it ends with, cut it off. - */ - p= strchr(buf, '\n'); - if (p) - *p = 0; - p = strchr(buf, '\r'); - if (p) - *p = 0; - - /* - * Find base name of shell - */ - shell_name = strrchr( buf, '/'); - if (shell_name) { - shell_name++; - } else { - shell_name = &buf[2];/* skipping "#!" */ - } - - } - CloseHandle(exec_handle); - } - - flags = 0; - - if (file_not_found) - command_line = make_command_line( shell_name, exec_path, argv); - else - command_line = make_command_line( shell_name, file_info.szPathName, - argv); - - if ( command_line == NULL ) { - pproc->last_err = 0; - pproc->lerrno = E_NO_MEM; - return(-1); - } - - if (envp) { - if (arr2envblk(envp, &envblk) ==FALSE) { - pproc->last_err = 0; - pproc->lerrno = E_NO_MEM; - free( command_line ); - return(-1); - } - } - - if ((shell_name) || (file_not_found)) { - exec_path = 0; /* Search for the program in %Path% */ - } else { - exec_path = file_info.szPathName; - } - - /* - * Set up inherited stdin, stdout, stderr for child - */ - GetStartupInfo(&startInfo); - startInfo.dwFlags = STARTF_USESTDHANDLES; - startInfo.lpReserved = 0; - startInfo.cbReserved2 = 0; - startInfo.lpReserved2 = 0; - startInfo.lpTitle = shell_name ? shell_name : exec_path; - startInfo.hStdInput = (HANDLE)pproc->sv_stdin[1]; - startInfo.hStdOutput = (HANDLE)pproc->sv_stdout[1]; - startInfo.hStdError = (HANDLE)pproc->sv_stderr[1]; - - if (as_user) { - if (envblk) free(envblk); - return -1; - } else { - if (CreateProcess( - exec_path, - command_line, - NULL, - 0, /* default security attributes for thread */ - TRUE, /* inherit handles (e.g. helper pipes, oserv socket) */ - flags, - envblk, - 0, /* default starting directory */ - &startInfo, - &procInfo) == FALSE) { - - pproc->last_err = GetLastError(); - pproc->lerrno = E_FORK; - fprintf(stderr, "process_begin: CreateProcess(%s, %s, ...) failed.\n", exec_path, command_line); - if (envblk) free(envblk); - free( command_line ); - return(-1); - } - } - - pproc->pid = (int)procInfo.hProcess; - /* Close the thread handle -- we'll just watch the process */ - CloseHandle(procInfo.hThread); - - /* Close the halves of the pipes we don't need */ - if (pproc->sv_stdin) { - CloseHandle((HANDLE)pproc->sv_stdin[1]); - (HANDLE)pproc->sv_stdin[1] = 0; - } - if (pproc->sv_stdout) { - CloseHandle((HANDLE)pproc->sv_stdout[1]); - (HANDLE)pproc->sv_stdout[1] = 0; - } - if (pproc->sv_stderr) { - CloseHandle((HANDLE)pproc->sv_stderr[1]); - (HANDLE)pproc->sv_stderr[1] = 0; - } - - free( command_line ); - if (envblk) free(envblk); - pproc->lerrno=0; - return 0; -} - - - -static DWORD -proc_stdin_thread(sub_process *pproc) -{ - DWORD in_done; - for (;;) { - if (WriteFile( (HANDLE) pproc->sv_stdin[0], pproc->inp, pproc->incnt, - &in_done, NULL) == FALSE) - _endthreadex(0); - // This if should never be true for anonymous pipes, but gives - // us a chance to change I/O mechanisms later - if (in_done < pproc->incnt) { - pproc->incnt -= in_done; - pproc->inp += in_done; - } else { - _endthreadex(0); - } - } - return 0; // for compiler warnings only.. not reached -} - -static DWORD -proc_stdout_thread(sub_process *pproc) -{ - DWORD bufsize = 1024; - char c; - DWORD nread; - pproc->outp = malloc(bufsize); - if (pproc->outp == NULL) - _endthreadex(0); - pproc->outcnt = 0; - - for (;;) { - if (ReadFile( (HANDLE)pproc->sv_stdout[0], &c, 1, &nread, NULL) - == FALSE) { -/* map_windows32_error_to_string(GetLastError());*/ - _endthreadex(0); - } - if (nread == 0) - _endthreadex(0); - if (pproc->outcnt + nread > bufsize) { - bufsize += nread + 512; - pproc->outp = realloc(pproc->outp, bufsize); - if (pproc->outp == NULL) { - pproc->outcnt = 0; - _endthreadex(0); - } - } - pproc->outp[pproc->outcnt++] = c; - } - return 0; -} - -static DWORD -proc_stderr_thread(sub_process *pproc) -{ - DWORD bufsize = 1024; - char c; - DWORD nread; - pproc->errp = malloc(bufsize); - if (pproc->errp == NULL) - _endthreadex(0); - pproc->errcnt = 0; - - for (;;) { - if (ReadFile( (HANDLE)pproc->sv_stderr[0], &c, 1, &nread, NULL) == FALSE) { - map_windows32_error_to_string(GetLastError()); - _endthreadex(0); - } - if (nread == 0) - _endthreadex(0); - if (pproc->errcnt + nread > bufsize) { - bufsize += nread + 512; - pproc->errp = realloc(pproc->errp, bufsize); - if (pproc->errp == NULL) { - pproc->errcnt = 0; - _endthreadex(0); - } - } - pproc->errp[pproc->errcnt++] = c; - } - return 0; -} - - -/* - * Purpose: collects output from child process and returns results - * - * Description: - * - * Returns: - * - * Notes/Dependencies: - */ - long -process_pipe_io( - HANDLE proc, - char *stdin_data, - int stdin_data_len) -{ - sub_process *pproc = (sub_process *)proc; - bool_t stdin_eof = FALSE, stdout_eof = FALSE, stderr_eof = FALSE; - HANDLE childhand = (HANDLE) pproc->pid; - HANDLE tStdin, tStdout, tStderr; - DWORD dwStdin, dwStdout, dwStderr; - HANDLE wait_list[4]; - DWORD wait_count; - DWORD wait_return; - HANDLE ready_hand; - bool_t child_dead = FALSE; - - - /* - * Create stdin thread, if needed - */ - pproc->inp = stdin_data; - pproc->incnt = stdin_data_len; - if (!pproc->inp) { - stdin_eof = TRUE; - CloseHandle((HANDLE)pproc->sv_stdin[0]); - (HANDLE)pproc->sv_stdin[0] = 0; - } else { - tStdin = (HANDLE) _beginthreadex( 0, 1024, - (unsigned (__stdcall *) (void *))proc_stdin_thread, pproc, 0, - (unsigned int *) &dwStdin); - if (tStdin == 0) { - pproc->last_err = GetLastError(); - pproc->lerrno = E_SCALL; - goto done; - } - } - - /* - * Assume child will produce stdout and stderr - */ - tStdout = (HANDLE) _beginthreadex( 0, 1024, - (unsigned (__stdcall *) (void *))proc_stdout_thread, pproc, 0, - (unsigned int *) &dwStdout); - tStderr = (HANDLE) _beginthreadex( 0, 1024, - (unsigned (__stdcall *) (void *))proc_stderr_thread, pproc, 0, - (unsigned int *) &dwStderr); - - if (tStdout == 0 || tStderr == 0) { - - pproc->last_err = GetLastError(); - pproc->lerrno = E_SCALL; - goto done; - } - - - /* - * Wait for all I/O to finish and for the child process to exit - */ - - while (!stdin_eof || !stdout_eof || !stderr_eof || !child_dead) { - wait_count = 0; - if (!stdin_eof) { - wait_list[wait_count++] = tStdin; - } - if (!stdout_eof) { - wait_list[wait_count++] = tStdout; - } - if (!stderr_eof) { - wait_list[wait_count++] = tStderr; - } - if (!child_dead) { - wait_list[wait_count++] = childhand; - } - - wait_return = WaitForMultipleObjects(wait_count, wait_list, - FALSE, /* don't wait for all: one ready will do */ - child_dead? 1000 :INFINITE); /* after the child dies, subthreads have - one second to collect all remaining output */ - - if (wait_return == WAIT_FAILED) { -/* map_windows32_error_to_string(GetLastError());*/ - pproc->last_err = GetLastError(); - pproc->lerrno = E_SCALL; - goto done; - } - - ready_hand = wait_list[wait_return - WAIT_OBJECT_0]; - - if (ready_hand == tStdin) { - CloseHandle((HANDLE)pproc->sv_stdin[0]); - (HANDLE)pproc->sv_stdin[0] = 0; - CloseHandle(tStdin); - tStdin = 0; - stdin_eof = TRUE; - - } else if (ready_hand == tStdout) { - - CloseHandle((HANDLE)pproc->sv_stdout[0]); - (HANDLE)pproc->sv_stdout[0] = 0; - CloseHandle(tStdout); - tStdout = 0; - stdout_eof = TRUE; - - } else if (ready_hand == tStderr) { - - CloseHandle((HANDLE)pproc->sv_stderr[0]); - (HANDLE)pproc->sv_stderr[0] = 0; - CloseHandle(tStderr); - tStderr = 0; - stderr_eof = TRUE; - - } else if (ready_hand == childhand) { - - if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) { - pproc->last_err = GetLastError(); - pproc->lerrno = E_SCALL; - goto done; - } - child_dead = TRUE; - - } else { - - /* ?? Got back a handle we didn't query ?? */ - pproc->last_err = 0; - pproc->lerrno = E_FAIL; - goto done; - } - } - - done: - if (tStdin != 0) - CloseHandle(tStdin); - if (tStdout != 0) - CloseHandle(tStdout); - if (tStderr != 0) - CloseHandle(tStderr); - - if (pproc->lerrno) - return(-1); - else - return(0); - -} - -/* - * Purpose: collects output from child process and returns results - * - * Description: - * - * Returns: - * - * Notes/Dependencies: - */ - long -process_file_io( - HANDLE proc) -{ - sub_process *pproc; - HANDLE childhand; - DWORD wait_return; - - if (proc == NULL) - pproc = process_wait_for_any_private(); - else - pproc = (sub_process *)proc; - - /* some sort of internal error */ - if (!pproc) - return -1; - - childhand = (HANDLE) pproc->pid; - - /* - * This function is poorly named, and could also be used just to wait - * for child death if you're doing your own pipe I/O. If that is - * the case, close the pipe handles here. - */ - if (pproc->sv_stdin[0]) { - CloseHandle((HANDLE)pproc->sv_stdin[0]); - pproc->sv_stdin[0] = 0; - } - if (pproc->sv_stdout[0]) { - CloseHandle((HANDLE)pproc->sv_stdout[0]); - pproc->sv_stdout[0] = 0; - } - if (pproc->sv_stderr[0]) { - CloseHandle((HANDLE)pproc->sv_stderr[0]); - pproc->sv_stderr[0] = 0; - } - - /* - * Wait for the child process to exit - */ - - wait_return = WaitForSingleObject(childhand, INFINITE); - - if (wait_return != WAIT_OBJECT_0) { -/* map_windows32_error_to_string(GetLastError());*/ - pproc->last_err = GetLastError(); - pproc->lerrno = E_SCALL; - goto done2; - } - - if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) { - pproc->last_err = GetLastError(); - pproc->lerrno = E_SCALL; - } - -done2: - if (pproc->lerrno) - return(-1); - else - return(0); - -} - -/* - * Description: Clean up any leftover handles, etc. It is up to the - * caller to manage and free the input, ouput, and stderr buffers. - */ - void -process_cleanup( - HANDLE proc) -{ - sub_process *pproc = (sub_process *)proc; - int i; - - if (pproc->using_pipes) { - for (i= 0; i <= 1; i++) { - if ((HANDLE)pproc->sv_stdin[i]) - CloseHandle((HANDLE)pproc->sv_stdin[i]); - if ((HANDLE)pproc->sv_stdout[i]) - CloseHandle((HANDLE)pproc->sv_stdout[i]); - if ((HANDLE)pproc->sv_stderr[i]) - CloseHandle((HANDLE)pproc->sv_stderr[i]); - } - } - if ((HANDLE)pproc->pid) - CloseHandle((HANDLE)pproc->pid); - - free(pproc); -} - - -/* - * Description: - * Create a command line buffer to pass to CreateProcess - * - * Returns: the buffer or NULL for failure - * Shell case: sh_name a:/full/path/to/script argv[1] argv[2] ... - * Otherwise: argv[0] argv[1] argv[2] ... - * - * Notes/Dependencies: - * CreateProcess does not take an argv, so this command creates a - * command line for the executable. - */ - -static char * -make_command_line( char *shell_name, char *full_exec_path, char **argv) -{ - int argc = 0; - char** argvi; - int* enclose_in_quotes = NULL; - int* enclose_in_quotes_i; - unsigned int bytes_required = 0; - char* command_line; - char* command_line_i; - - if (shell_name && full_exec_path) { - bytes_required - = strlen(shell_name) + 1 + strlen(full_exec_path); - /* - * Skip argv[0] if any, when shell_name is given. - */ - if (*argv) argv++; - /* - * Add one for the intervening space. - */ - if (*argv) bytes_required++; - } - - argvi = argv; - while (*(argvi++)) argc++; - - if (argc) { - enclose_in_quotes = (int*) calloc(1, argc * sizeof(int)); - - if (!enclose_in_quotes) { - return NULL; - } - } - - /* We have to make one pass through each argv[i] to see if we need - * to enclose it in ", so we might as well figure out how much - * memory we'll need on the same pass. - */ - - argvi = argv; - enclose_in_quotes_i = enclose_in_quotes; - while(*argvi) { - char* p = *argvi; - unsigned int backslash_count = 0; - - /* - * We have to enclose empty arguments in ". - */ - if (!(*p)) *enclose_in_quotes_i = 1; - - while(*p) { - switch (*p) { - case '\"': - /* - * We have to insert a backslash for each " - * and each \ that precedes the ". - */ - bytes_required += (backslash_count + 1); - backslash_count = 0; - break; - - case '\\': - backslash_count++; - break; - /* - * At one time we set *enclose_in_quotes_i for '*' or '?' to suppress - * wildcard expansion in programs linked with MSVC's SETARGV.OBJ so - * that argv in always equals argv out. This was removed. Say you have - * such a program named glob.exe. You enter - * glob '*' - * at the sh command prompt. Obviously the intent is to make glob do the - * wildcarding instead of sh. If we set *enclose_in_quotes_i for '*' or '?', - * then the command line that glob would see would be - * glob "*" - * and the _setargv in SETARGV.OBJ would _not_ expand the *. - */ - case ' ': - case '\t': - *enclose_in_quotes_i = 1; - /* fall through */ - - default: - backslash_count = 0; - break; - } - - /* - * Add one for each character in argv[i]. - */ - bytes_required++; - - p++; - } - - if (*enclose_in_quotes_i) { - /* - * Add one for each enclosing ", - * and one for each \ that precedes the - * closing ". - */ - bytes_required += (backslash_count + 2); - } - - /* - * Add one for the intervening space. - */ - if (*(++argvi)) bytes_required++; - enclose_in_quotes_i++; - } - - /* - * Add one for the terminating NULL. - */ - bytes_required++; - - command_line = (char*) malloc(bytes_required); - - if (!command_line) { - if (enclose_in_quotes) free(enclose_in_quotes); - return NULL; - } - - command_line_i = command_line; - - if (shell_name && full_exec_path) { - while(*shell_name) { - *(command_line_i++) = *(shell_name++); - } - - *(command_line_i++) = ' '; - - while(*full_exec_path) { - *(command_line_i++) = *(full_exec_path++); - } - - if (*argv) { - *(command_line_i++) = ' '; - } - } - - argvi = argv; - enclose_in_quotes_i = enclose_in_quotes; - - while(*argvi) { - char* p = *argvi; - unsigned int backslash_count = 0; - - if (*enclose_in_quotes_i) { - *(command_line_i++) = '\"'; - } - - while(*p) { - if (*p == '\"') { - /* - * We have to insert a backslash for the " - * and each \ that precedes the ". - */ - backslash_count++; - - while(backslash_count) { - *(command_line_i++) = '\\'; - backslash_count--; - }; - - } else if (*p == '\\') { - backslash_count++; - } else { - backslash_count = 0; - } - - /* - * Copy the character. - */ - *(command_line_i++) = *(p++); - } - - if (*enclose_in_quotes_i) { - /* - * Add one \ for each \ that precedes the - * closing ". - */ - while(backslash_count--) { - *(command_line_i++) = '\\'; - }; - - *(command_line_i++) = '\"'; - } - - /* - * Append an intervening space. - */ - if (*(++argvi)) { - *(command_line_i++) = ' '; - } - - enclose_in_quotes_i++; - } - - /* - * Append the terminating NULL. - */ - *command_line_i = '\0'; - - if (enclose_in_quotes) free(enclose_in_quotes); - return command_line; -} - -/* - * Description: Given an argv and optional envp, launch the process - * using the default stdin, stdout, and stderr handles. - * Also, register process so that process_wait_for_any_private() - * can be used via process_file_io(NULL) or - * process_wait_for_any(). - * - * Returns: - * - * Notes/Dependencies: - */ -HANDLE -process_easy( - char **argv, - char **envp) -{ - HANDLE hIn; - HANDLE hOut; - HANDLE hErr; - HANDLE hProcess; - - if (DuplicateHandle(GetCurrentProcess(), - GetStdHandle(STD_INPUT_HANDLE), - GetCurrentProcess(), - &hIn, - 0, - TRUE, - DUPLICATE_SAME_ACCESS) == FALSE) { - fprintf(stderr, - "process_easy: DuplicateHandle(In) failed (e=%d)\n", - GetLastError()); - return INVALID_HANDLE_VALUE; - } - if (DuplicateHandle(GetCurrentProcess(), - GetStdHandle(STD_OUTPUT_HANDLE), - GetCurrentProcess(), - &hOut, - 0, - TRUE, - DUPLICATE_SAME_ACCESS) == FALSE) { - fprintf(stderr, - "process_easy: DuplicateHandle(Out) failed (e=%d)\n", - GetLastError()); - return INVALID_HANDLE_VALUE; - } - if (DuplicateHandle(GetCurrentProcess(), - GetStdHandle(STD_ERROR_HANDLE), - GetCurrentProcess(), - &hErr, - 0, - TRUE, - DUPLICATE_SAME_ACCESS) == FALSE) { - fprintf(stderr, - "process_easy: DuplicateHandle(Err) failed (e=%d)\n", - GetLastError()); - return INVALID_HANDLE_VALUE; - } - - hProcess = process_init_fd(hIn, hOut, hErr); - - if (process_begin(hProcess, argv, envp, argv[0], NULL)) { - fake_exits_pending++; - ((sub_process*) hProcess)->exit_code = process_last_err(hProcess); - - /* close up unused handles */ - CloseHandle(hIn); - CloseHandle(hOut); - CloseHandle(hErr); - } - - process_register(hProcess); - - return hProcess; -} +#include +#include +#include /* for msvc _beginthreadex, _endthreadex */ +#include + +#include "sub_proc.h" +#include "proc.h" +#include "w32err.h" +#include "config.h" + +static char *make_command_line( char *shell_name, char *exec_path, char **argv); + +typedef struct sub_process_t { + int sv_stdin[2]; + int sv_stdout[2]; + int sv_stderr[2]; + int using_pipes; + char *inp; + DWORD incnt; + char * volatile outp; + volatile DWORD outcnt; + char * volatile errp; + volatile DWORD errcnt; + int pid; + int exit_code; + int signal; + long last_err; + long lerrno; +} sub_process; + +/* keep track of children so we can implement a waitpid-like routine */ +static sub_process *proc_array[256]; +static int proc_index = 0; +static int fake_exits_pending = 0; + +/* + * When a process has been waited for, adjust the wait state + * array so that we don't wait for it again + */ +static void +process_adjust_wait_state(sub_process* pproc) +{ + int i; + + if (!proc_index) + return; + + for (i = 0; i < proc_index; i++) + if (proc_array[i]->pid == pproc->pid) + break; + + if (i < proc_index) { + proc_index--; + if (i != proc_index) + memmove(&proc_array[i], &proc_array[i+1], + (proc_index-i) * sizeof(sub_process*)); + proc_array[proc_index] = NULL; + } +} + +/* + * Waits for any of the registered child processes to finish. + */ +static sub_process * +process_wait_for_any_private(void) +{ + HANDLE handles[256]; + DWORD retval, which; + int i; + + if (!proc_index) + return NULL; + + /* build array of handles to wait for */ + for (i = 0; i < proc_index; i++) { + handles[i] = (HANDLE) proc_array[i]->pid; + + if (fake_exits_pending && proc_array[i]->exit_code) + break; + } + + /* wait for someone to exit */ + if (!fake_exits_pending) { + retval = WaitForMultipleObjects(proc_index, handles, FALSE, INFINITE); + which = retval - WAIT_OBJECT_0; + } else { + fake_exits_pending--; + retval = !WAIT_FAILED; + which = i; + } + + /* return pointer to process */ + if (retval != WAIT_FAILED) { + sub_process* pproc = proc_array[which]; + process_adjust_wait_state(pproc); + return pproc; + } else + return NULL; +} + +/* + * Terminate a process. + */ +BOOL +process_kill(HANDLE proc, int signal) +{ + sub_process* pproc = (sub_process*) proc; + pproc->signal = signal; + return (TerminateProcess((HANDLE) pproc->pid, signal)); +} + +/* + * Use this function to register processes you wish to wait for by + * calling process_file_io(NULL) or process_wait_any(). This must be done + * because it is possible for callers of this library to reuse the same + * handle for multiple processes launches :-( + */ +void +process_register(HANDLE proc) +{ + proc_array[proc_index++] = (sub_process *) proc; +} + +/* + * Public function which works kind of like waitpid(). Wait for any + * of the children to die and return results. To call this function, + * you must do 1 of things: + * + * x = process_easy(...); + * + * or + * + * x = process_init_fd(); + * process_register(x); + * + * or + * + * x = process_init(); + * process_register(x); + * + * You must NOT then call process_pipe_io() because this function is + * not capable of handling automatic notification of any child + * death. + */ + +HANDLE +process_wait_for_any(void) +{ + sub_process* pproc = process_wait_for_any_private(); + + if (!pproc) + return NULL; + else { + /* + * Ouch! can't tell caller if this fails directly. Caller + * will have to use process_last_err() + */ + (void) process_file_io(pproc); + return ((HANDLE) pproc); + } +} + +long +process_errno(HANDLE proc) +{ + return (((sub_process *)proc)->lerrno); +} + +long +process_signal(HANDLE proc) +{ + return (((sub_process *)proc)->signal); +} + + long +process_last_err(HANDLE proc) +{ + return (((sub_process *)proc)->last_err); +} + + long +process_exit_code(HANDLE proc) +{ + return (((sub_process *)proc)->exit_code); +} + + char * +process_outbuf(HANDLE proc) +{ + return (((sub_process *)proc)->outp); +} + + char * +process_errbuf(HANDLE proc) +{ + return (((sub_process *)proc)->errp); +} + + int +process_outcnt(HANDLE proc) +{ + return (((sub_process *)proc)->outcnt); +} + + int +process_errcnt(HANDLE proc) +{ + return (((sub_process *)proc)->errcnt); +} + + void +process_pipes(HANDLE proc, int pipes[3]) +{ + pipes[0] = ((sub_process *)proc)->sv_stdin[0]; + pipes[1] = ((sub_process *)proc)->sv_stdout[0]; + pipes[2] = ((sub_process *)proc)->sv_stderr[0]; + return; +} + + + HANDLE +process_init() +{ + sub_process *pproc; + /* + * open file descriptors for attaching stdin/stdout/sterr + */ + HANDLE stdin_pipes[2]; + HANDLE stdout_pipes[2]; + HANDLE stderr_pipes[2]; + SECURITY_ATTRIBUTES inherit; + BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH]; + + pproc = malloc(sizeof(*pproc)); + memset(pproc, 0, sizeof(*pproc)); + + /* We can't use NULL for lpSecurityDescriptor because that + uses the default security descriptor of the calling process. + Instead we use a security descriptor with no DACL. This + allows nonrestricted access to the associated objects. */ + + if (!InitializeSecurityDescriptor((PSECURITY_DESCRIPTOR)(&sd), + SECURITY_DESCRIPTOR_REVISION)) { + pproc->last_err = GetLastError(); + pproc->lerrno = E_SCALL; + return((HANDLE)pproc); + } + + inherit.nLength = sizeof(inherit); + inherit.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(&sd); + inherit.bInheritHandle = TRUE; + + // By convention, parent gets pipe[0], and child gets pipe[1] + // This means the READ side of stdin pipe goes into pipe[1] + // and the WRITE side of the stdout and stderr pipes go into pipe[1] + if (CreatePipe( &stdin_pipes[1], &stdin_pipes[0], &inherit, 0) == FALSE || + CreatePipe( &stdout_pipes[0], &stdout_pipes[1], &inherit, 0) == FALSE || + CreatePipe( &stderr_pipes[0], &stderr_pipes[1], &inherit, 0) == FALSE) { + + pproc->last_err = GetLastError(); + pproc->lerrno = E_SCALL; + return((HANDLE)pproc); + } + + // + // Mark the parent sides of the pipes as non-inheritable + // + if (SetHandleInformation(stdin_pipes[0], + HANDLE_FLAG_INHERIT, 0) == FALSE || + SetHandleInformation(stdout_pipes[0], + HANDLE_FLAG_INHERIT, 0) == FALSE || + SetHandleInformation(stderr_pipes[0], + HANDLE_FLAG_INHERIT, 0) == FALSE) { + + pproc->last_err = GetLastError(); + pproc->lerrno = E_SCALL; + return((HANDLE)pproc); + } + pproc->sv_stdin[0] = (int) stdin_pipes[0]; + pproc->sv_stdin[1] = (int) stdin_pipes[1]; + pproc->sv_stdout[0] = (int) stdout_pipes[0]; + pproc->sv_stdout[1] = (int) stdout_pipes[1]; + pproc->sv_stderr[0] = (int) stderr_pipes[0]; + pproc->sv_stderr[1] = (int) stderr_pipes[1]; + + pproc->using_pipes = 1; + + pproc->lerrno = 0; + + return((HANDLE)pproc); +} + + + HANDLE +process_init_fd(HANDLE stdinh, HANDLE stdouth, HANDLE stderrh) +{ + sub_process *pproc; + + pproc = malloc(sizeof(*pproc)); + memset(pproc, 0, sizeof(*pproc)); + + /* + * Just pass the provided file handles to the 'child side' of the + * pipe, bypassing pipes altogether. + */ + pproc->sv_stdin[1] = (int) stdinh; + pproc->sv_stdout[1] = (int) stdouth; + pproc->sv_stderr[1] = (int) stderrh; + + pproc->last_err = pproc->lerrno = 0; + + return((HANDLE)pproc); +} + + +static HANDLE +find_file(char *exec_path, LPOFSTRUCT file_info) +{ + HANDLE exec_handle; + char *fname; + char *ext; + + fname = malloc(strlen(exec_path) + 5); + strcpy(fname, exec_path); + ext = fname + strlen(fname); + + strcpy(ext, ".exe"); + if ((exec_handle = (HANDLE)OpenFile(fname, file_info, + OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) { + free(fname); + return(exec_handle); + } + + strcpy(ext, ".cmd"); + if ((exec_handle = (HANDLE)OpenFile(fname, file_info, + OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) { + free(fname); + return(exec_handle); + } + + strcpy(ext, ".bat"); + if ((exec_handle = (HANDLE)OpenFile(fname, file_info, + OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) { + free(fname); + return(exec_handle); + } + + /* should .com come before this case? */ + if ((exec_handle = (HANDLE)OpenFile(exec_path, file_info, + OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) { + free(fname); + return(exec_handle); + } + + strcpy(ext, ".com"); + if ((exec_handle = (HANDLE)OpenFile(fname, file_info, + OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) { + free(fname); + return(exec_handle); + } + + free(fname); + return(exec_handle); +} + + +/* + * Description: Create the child process to be helped + * + * Returns: + * + * Notes/Dependencies: + */ +long +process_begin( + HANDLE proc, + char **argv, + char **envp, + char *exec_path, + char *as_user) +{ + sub_process *pproc = (sub_process *)proc; + char *shell_name = 0; + int file_not_found=0; + HANDLE exec_handle; + char buf[256]; + DWORD bytes_returned; + DWORD flags; + char *command_line; + STARTUPINFO startInfo; + PROCESS_INFORMATION procInfo; + char *envblk=NULL; + OFSTRUCT file_info; + + + /* + * Shell script detection... if the exec_path starts with #! then + * we want to exec shell-script-name exec-path, not just exec-path + * NT doesn't recognize #!/bin/sh or #!/etc/Tivoli/bin/perl. We do not + * hard-code the path to the shell or perl or whatever: Instead, we + * assume it's in the path somewhere (generally, the NT tools + * bin directory) + * We use OpenFile here because it is capable of searching the Path. + */ + + exec_handle = find_file(exec_path, &file_info); + + /* + * If we couldn't open the file, just assume that Windows32 will be able + * to find and execute it. + */ + if (exec_handle == (HANDLE)HFILE_ERROR) { + file_not_found++; + } + else { + /* Attempt to read the first line of the file */ + if (ReadFile( exec_handle, + buf, sizeof(buf) - 1, /* leave room for trailing NULL */ + &bytes_returned, 0) == FALSE || bytes_returned < 2) { + + pproc->last_err = GetLastError(); + pproc->lerrno = E_IO; + CloseHandle(exec_handle); + return(-1); + } + if (buf[0] == '#' && buf[1] == '!') { + /* + * This is a shell script... Change the command line from + * exec_path args to shell_name exec_path args + */ + char *p; + + /* Make sure buf is NULL terminated */ + buf[bytes_returned] = 0; + /* + * Depending on the file system type, etc. the first line + * of the shell script may end with newline or newline-carriage-return + * Whatever it ends with, cut it off. + */ + p= strchr(buf, '\n'); + if (p) + *p = 0; + p = strchr(buf, '\r'); + if (p) + *p = 0; + + /* + * Find base name of shell + */ + shell_name = strrchr( buf, '/'); + if (shell_name) { + shell_name++; + } else { + shell_name = &buf[2];/* skipping "#!" */ + } + + } + CloseHandle(exec_handle); + } + + flags = 0; + + if (file_not_found) + command_line = make_command_line( shell_name, exec_path, argv); + else + command_line = make_command_line( shell_name, file_info.szPathName, + argv); + + if ( command_line == NULL ) { + pproc->last_err = 0; + pproc->lerrno = E_NO_MEM; + return(-1); + } + + if (envp) { + if (arr2envblk(envp, &envblk) ==FALSE) { + pproc->last_err = 0; + pproc->lerrno = E_NO_MEM; + free( command_line ); + return(-1); + } + } + + if ((shell_name) || (file_not_found)) { + exec_path = 0; /* Search for the program in %Path% */ + } else { + exec_path = file_info.szPathName; + } + + /* + * Set up inherited stdin, stdout, stderr for child + */ + GetStartupInfo(&startInfo); + startInfo.dwFlags = STARTF_USESTDHANDLES; + startInfo.lpReserved = 0; + startInfo.cbReserved2 = 0; + startInfo.lpReserved2 = 0; + startInfo.lpTitle = shell_name ? shell_name : exec_path; + startInfo.hStdInput = (HANDLE)pproc->sv_stdin[1]; + startInfo.hStdOutput = (HANDLE)pproc->sv_stdout[1]; + startInfo.hStdError = (HANDLE)pproc->sv_stderr[1]; + + if (as_user) { + if (envblk) free(envblk); + return -1; + } else { + if (CreateProcess( + exec_path, + command_line, + NULL, + 0, /* default security attributes for thread */ + TRUE, /* inherit handles (e.g. helper pipes, oserv socket) */ + flags, + envblk, + 0, /* default starting directory */ + &startInfo, + &procInfo) == FALSE) { + + pproc->last_err = GetLastError(); + pproc->lerrno = E_FORK; + fprintf(stderr, "process_begin: CreateProcess(%s, %s, ...) failed.\n", exec_path, command_line); + if (envblk) free(envblk); + free( command_line ); + return(-1); + } + } + + pproc->pid = (int)procInfo.hProcess; + /* Close the thread handle -- we'll just watch the process */ + CloseHandle(procInfo.hThread); + + /* Close the halves of the pipes we don't need */ + if (pproc->sv_stdin) { + CloseHandle((HANDLE)pproc->sv_stdin[1]); + (HANDLE)pproc->sv_stdin[1] = 0; + } + if (pproc->sv_stdout) { + CloseHandle((HANDLE)pproc->sv_stdout[1]); + (HANDLE)pproc->sv_stdout[1] = 0; + } + if (pproc->sv_stderr) { + CloseHandle((HANDLE)pproc->sv_stderr[1]); + (HANDLE)pproc->sv_stderr[1] = 0; + } + + free( command_line ); + if (envblk) free(envblk); + pproc->lerrno=0; + return 0; +} + + + +static DWORD +proc_stdin_thread(sub_process *pproc) +{ + DWORD in_done; + for (;;) { + if (WriteFile( (HANDLE) pproc->sv_stdin[0], pproc->inp, pproc->incnt, + &in_done, NULL) == FALSE) + _endthreadex(0); + // This if should never be true for anonymous pipes, but gives + // us a chance to change I/O mechanisms later + if (in_done < pproc->incnt) { + pproc->incnt -= in_done; + pproc->inp += in_done; + } else { + _endthreadex(0); + } + } + return 0; // for compiler warnings only.. not reached +} + +static DWORD +proc_stdout_thread(sub_process *pproc) +{ + DWORD bufsize = 1024; + char c; + DWORD nread; + pproc->outp = malloc(bufsize); + if (pproc->outp == NULL) + _endthreadex(0); + pproc->outcnt = 0; + + for (;;) { + if (ReadFile( (HANDLE)pproc->sv_stdout[0], &c, 1, &nread, NULL) + == FALSE) { +/* map_windows32_error_to_string(GetLastError());*/ + _endthreadex(0); + } + if (nread == 0) + _endthreadex(0); + if (pproc->outcnt + nread > bufsize) { + bufsize += nread + 512; + pproc->outp = realloc(pproc->outp, bufsize); + if (pproc->outp == NULL) { + pproc->outcnt = 0; + _endthreadex(0); + } + } + pproc->outp[pproc->outcnt++] = c; + } + return 0; +} + +static DWORD +proc_stderr_thread(sub_process *pproc) +{ + DWORD bufsize = 1024; + char c; + DWORD nread; + pproc->errp = malloc(bufsize); + if (pproc->errp == NULL) + _endthreadex(0); + pproc->errcnt = 0; + + for (;;) { + if (ReadFile( (HANDLE)pproc->sv_stderr[0], &c, 1, &nread, NULL) == FALSE) { + map_windows32_error_to_string(GetLastError()); + _endthreadex(0); + } + if (nread == 0) + _endthreadex(0); + if (pproc->errcnt + nread > bufsize) { + bufsize += nread + 512; + pproc->errp = realloc(pproc->errp, bufsize); + if (pproc->errp == NULL) { + pproc->errcnt = 0; + _endthreadex(0); + } + } + pproc->errp[pproc->errcnt++] = c; + } + return 0; +} + + +/* + * Purpose: collects output from child process and returns results + * + * Description: + * + * Returns: + * + * Notes/Dependencies: + */ + long +process_pipe_io( + HANDLE proc, + char *stdin_data, + int stdin_data_len) +{ + sub_process *pproc = (sub_process *)proc; + bool_t stdin_eof = FALSE, stdout_eof = FALSE, stderr_eof = FALSE; + HANDLE childhand = (HANDLE) pproc->pid; + HANDLE tStdin, tStdout, tStderr; + DWORD dwStdin, dwStdout, dwStderr; + HANDLE wait_list[4]; + DWORD wait_count; + DWORD wait_return; + HANDLE ready_hand; + bool_t child_dead = FALSE; + + + /* + * Create stdin thread, if needed + */ + pproc->inp = stdin_data; + pproc->incnt = stdin_data_len; + if (!pproc->inp) { + stdin_eof = TRUE; + CloseHandle((HANDLE)pproc->sv_stdin[0]); + (HANDLE)pproc->sv_stdin[0] = 0; + } else { + tStdin = (HANDLE) _beginthreadex( 0, 1024, + (unsigned (__stdcall *) (void *))proc_stdin_thread, pproc, 0, + (unsigned int *) &dwStdin); + if (tStdin == 0) { + pproc->last_err = GetLastError(); + pproc->lerrno = E_SCALL; + goto done; + } + } + + /* + * Assume child will produce stdout and stderr + */ + tStdout = (HANDLE) _beginthreadex( 0, 1024, + (unsigned (__stdcall *) (void *))proc_stdout_thread, pproc, 0, + (unsigned int *) &dwStdout); + tStderr = (HANDLE) _beginthreadex( 0, 1024, + (unsigned (__stdcall *) (void *))proc_stderr_thread, pproc, 0, + (unsigned int *) &dwStderr); + + if (tStdout == 0 || tStderr == 0) { + + pproc->last_err = GetLastError(); + pproc->lerrno = E_SCALL; + goto done; + } + + + /* + * Wait for all I/O to finish and for the child process to exit + */ + + while (!stdin_eof || !stdout_eof || !stderr_eof || !child_dead) { + wait_count = 0; + if (!stdin_eof) { + wait_list[wait_count++] = tStdin; + } + if (!stdout_eof) { + wait_list[wait_count++] = tStdout; + } + if (!stderr_eof) { + wait_list[wait_count++] = tStderr; + } + if (!child_dead) { + wait_list[wait_count++] = childhand; + } + + wait_return = WaitForMultipleObjects(wait_count, wait_list, + FALSE, /* don't wait for all: one ready will do */ + child_dead? 1000 :INFINITE); /* after the child dies, subthreads have + one second to collect all remaining output */ + + if (wait_return == WAIT_FAILED) { +/* map_windows32_error_to_string(GetLastError());*/ + pproc->last_err = GetLastError(); + pproc->lerrno = E_SCALL; + goto done; + } + + ready_hand = wait_list[wait_return - WAIT_OBJECT_0]; + + if (ready_hand == tStdin) { + CloseHandle((HANDLE)pproc->sv_stdin[0]); + (HANDLE)pproc->sv_stdin[0] = 0; + CloseHandle(tStdin); + tStdin = 0; + stdin_eof = TRUE; + + } else if (ready_hand == tStdout) { + + CloseHandle((HANDLE)pproc->sv_stdout[0]); + (HANDLE)pproc->sv_stdout[0] = 0; + CloseHandle(tStdout); + tStdout = 0; + stdout_eof = TRUE; + + } else if (ready_hand == tStderr) { + + CloseHandle((HANDLE)pproc->sv_stderr[0]); + (HANDLE)pproc->sv_stderr[0] = 0; + CloseHandle(tStderr); + tStderr = 0; + stderr_eof = TRUE; + + } else if (ready_hand == childhand) { + + if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) { + pproc->last_err = GetLastError(); + pproc->lerrno = E_SCALL; + goto done; + } + child_dead = TRUE; + + } else { + + /* ?? Got back a handle we didn't query ?? */ + pproc->last_err = 0; + pproc->lerrno = E_FAIL; + goto done; + } + } + + done: + if (tStdin != 0) + CloseHandle(tStdin); + if (tStdout != 0) + CloseHandle(tStdout); + if (tStderr != 0) + CloseHandle(tStderr); + + if (pproc->lerrno) + return(-1); + else + return(0); + +} + +/* + * Purpose: collects output from child process and returns results + * + * Description: + * + * Returns: + * + * Notes/Dependencies: + */ + long +process_file_io( + HANDLE proc) +{ + sub_process *pproc; + HANDLE childhand; + DWORD wait_return; + + if (proc == NULL) + pproc = process_wait_for_any_private(); + else + pproc = (sub_process *)proc; + + /* some sort of internal error */ + if (!pproc) + return -1; + + childhand = (HANDLE) pproc->pid; + + /* + * This function is poorly named, and could also be used just to wait + * for child death if you're doing your own pipe I/O. If that is + * the case, close the pipe handles here. + */ + if (pproc->sv_stdin[0]) { + CloseHandle((HANDLE)pproc->sv_stdin[0]); + pproc->sv_stdin[0] = 0; + } + if (pproc->sv_stdout[0]) { + CloseHandle((HANDLE)pproc->sv_stdout[0]); + pproc->sv_stdout[0] = 0; + } + if (pproc->sv_stderr[0]) { + CloseHandle((HANDLE)pproc->sv_stderr[0]); + pproc->sv_stderr[0] = 0; + } + + /* + * Wait for the child process to exit + */ + + wait_return = WaitForSingleObject(childhand, INFINITE); + + if (wait_return != WAIT_OBJECT_0) { +/* map_windows32_error_to_string(GetLastError());*/ + pproc->last_err = GetLastError(); + pproc->lerrno = E_SCALL; + goto done2; + } + + if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) { + pproc->last_err = GetLastError(); + pproc->lerrno = E_SCALL; + } + +done2: + if (pproc->lerrno) + return(-1); + else + return(0); + +} + +/* + * Description: Clean up any leftover handles, etc. It is up to the + * caller to manage and free the input, ouput, and stderr buffers. + */ + void +process_cleanup( + HANDLE proc) +{ + sub_process *pproc = (sub_process *)proc; + int i; + + if (pproc->using_pipes) { + for (i= 0; i <= 1; i++) { + if ((HANDLE)pproc->sv_stdin[i]) + CloseHandle((HANDLE)pproc->sv_stdin[i]); + if ((HANDLE)pproc->sv_stdout[i]) + CloseHandle((HANDLE)pproc->sv_stdout[i]); + if ((HANDLE)pproc->sv_stderr[i]) + CloseHandle((HANDLE)pproc->sv_stderr[i]); + } + } + if ((HANDLE)pproc->pid) + CloseHandle((HANDLE)pproc->pid); + + free(pproc); +} + + +/* + * Description: + * Create a command line buffer to pass to CreateProcess + * + * Returns: the buffer or NULL for failure + * Shell case: sh_name a:/full/path/to/script argv[1] argv[2] ... + * Otherwise: argv[0] argv[1] argv[2] ... + * + * Notes/Dependencies: + * CreateProcess does not take an argv, so this command creates a + * command line for the executable. + */ + +static char * +make_command_line( char *shell_name, char *full_exec_path, char **argv) +{ + int argc = 0; + char** argvi; + int* enclose_in_quotes = NULL; + int* enclose_in_quotes_i; + unsigned int bytes_required = 0; + char* command_line; + char* command_line_i; + + if (shell_name && full_exec_path) { + bytes_required + = strlen(shell_name) + 1 + strlen(full_exec_path); + /* + * Skip argv[0] if any, when shell_name is given. + */ + if (*argv) argv++; + /* + * Add one for the intervening space. + */ + if (*argv) bytes_required++; + } + + argvi = argv; + while (*(argvi++)) argc++; + + if (argc) { + enclose_in_quotes = (int*) calloc(1, argc * sizeof(int)); + + if (!enclose_in_quotes) { + return NULL; + } + } + + /* We have to make one pass through each argv[i] to see if we need + * to enclose it in ", so we might as well figure out how much + * memory we'll need on the same pass. + */ + + argvi = argv; + enclose_in_quotes_i = enclose_in_quotes; + while(*argvi) { + char* p = *argvi; + unsigned int backslash_count = 0; + + /* + * We have to enclose empty arguments in ". + */ + if (!(*p)) *enclose_in_quotes_i = 1; + + while(*p) { + switch (*p) { + case '\"': + /* + * We have to insert a backslash for each " + * and each \ that precedes the ". + */ + bytes_required += (backslash_count + 1); + backslash_count = 0; + break; + +#ifndef HAVE_MKS_SHELL + case '\\': + backslash_count++; + break; +#endif + /* + * At one time we set *enclose_in_quotes_i for '*' or '?' to suppress + * wildcard expansion in programs linked with MSVC's SETARGV.OBJ so + * that argv in always equals argv out. This was removed. Say you have + * such a program named glob.exe. You enter + * glob '*' + * at the sh command prompt. Obviously the intent is to make glob do the + * wildcarding instead of sh. If we set *enclose_in_quotes_i for '*' or '?', + * then the command line that glob would see would be + * glob "*" + * and the _setargv in SETARGV.OBJ would _not_ expand the *. + */ + case ' ': + case '\t': + *enclose_in_quotes_i = 1; + /* fall through */ + + default: + backslash_count = 0; + break; + } + + /* + * Add one for each character in argv[i]. + */ + bytes_required++; + + p++; + } + + if (*enclose_in_quotes_i) { + /* + * Add one for each enclosing ", + * and one for each \ that precedes the + * closing ". + */ + bytes_required += (backslash_count + 2); + } + + /* + * Add one for the intervening space. + */ + if (*(++argvi)) bytes_required++; + enclose_in_quotes_i++; + } + + /* + * Add one for the terminating NULL. + */ + bytes_required++; + + command_line = (char*) malloc(bytes_required); + + if (!command_line) { + if (enclose_in_quotes) free(enclose_in_quotes); + return NULL; + } + + command_line_i = command_line; + + if (shell_name && full_exec_path) { + while(*shell_name) { + *(command_line_i++) = *(shell_name++); + } + + *(command_line_i++) = ' '; + + while(*full_exec_path) { + *(command_line_i++) = *(full_exec_path++); + } + + if (*argv) { + *(command_line_i++) = ' '; + } + } + + argvi = argv; + enclose_in_quotes_i = enclose_in_quotes; + + while(*argvi) { + char* p = *argvi; + unsigned int backslash_count = 0; + + if (*enclose_in_quotes_i) { + *(command_line_i++) = '\"'; + } + + while(*p) { + if (*p == '\"') { + /* + * We have to insert a backslash for the " + * and each \ that precedes the ". + */ + backslash_count++; + + while(backslash_count) { + *(command_line_i++) = '\\'; + backslash_count--; + }; +#ifndef HAVE_MKS_SHELL + } else if (*p == '\\') { + backslash_count++; + } else { + backslash_count = 0; +#endif + } + + /* + * Copy the character. + */ + *(command_line_i++) = *(p++); + } + + if (*enclose_in_quotes_i) { +#ifndef HAVE_MKS_SHELL + /* + * Add one \ for each \ that precedes the + * closing ". + */ + while(backslash_count--) { + *(command_line_i++) = '\\'; + }; +#endif + *(command_line_i++) = '\"'; + } + + /* + * Append an intervening space. + */ + if (*(++argvi)) { + *(command_line_i++) = ' '; + } + + enclose_in_quotes_i++; + } + + /* + * Append the terminating NULL. + */ + *command_line_i = '\0'; + + if (enclose_in_quotes) free(enclose_in_quotes); + return command_line; +} + +/* + * Description: Given an argv and optional envp, launch the process + * using the default stdin, stdout, and stderr handles. + * Also, register process so that process_wait_for_any_private() + * can be used via process_file_io(NULL) or + * process_wait_for_any(). + * + * Returns: + * + * Notes/Dependencies: + */ +HANDLE +process_easy( + char **argv, + char **envp) +{ + HANDLE hIn; + HANDLE hOut; + HANDLE hErr; + HANDLE hProcess; + + if (DuplicateHandle(GetCurrentProcess(), + GetStdHandle(STD_INPUT_HANDLE), + GetCurrentProcess(), + &hIn, + 0, + TRUE, + DUPLICATE_SAME_ACCESS) == FALSE) { + fprintf(stderr, + "process_easy: DuplicateHandle(In) failed (e=%d)\n", + GetLastError()); + return INVALID_HANDLE_VALUE; + } + if (DuplicateHandle(GetCurrentProcess(), + GetStdHandle(STD_OUTPUT_HANDLE), + GetCurrentProcess(), + &hOut, + 0, + TRUE, + DUPLICATE_SAME_ACCESS) == FALSE) { + fprintf(stderr, + "process_easy: DuplicateHandle(Out) failed (e=%d)\n", + GetLastError()); + return INVALID_HANDLE_VALUE; + } + if (DuplicateHandle(GetCurrentProcess(), + GetStdHandle(STD_ERROR_HANDLE), + GetCurrentProcess(), + &hErr, + 0, + TRUE, + DUPLICATE_SAME_ACCESS) == FALSE) { + fprintf(stderr, + "process_easy: DuplicateHandle(Err) failed (e=%d)\n", + GetLastError()); + return INVALID_HANDLE_VALUE; + } + + hProcess = process_init_fd(hIn, hOut, hErr); + + if (process_begin(hProcess, argv, envp, argv[0], NULL)) { + fake_exits_pending++; + ((sub_process*) hProcess)->exit_code = process_last_err(hProcess); + + /* close up unused handles */ + CloseHandle(hIn); + CloseHandle(hOut); + CloseHandle(hErr); + } + + process_register(hProcess); + + return hProcess; +}