diff options
author | Paul Smith <psmith@gnu.org> | 1998-10-03 05:39:55 +0000 |
---|---|---|
committer | Paul Smith <psmith@gnu.org> | 1998-10-03 05:39:55 +0000 |
commit | 2c64fb221a265f9e7fc93374906b1e7540377561 (patch) | |
tree | 4603a4b4e5ec9a6366e02f5ece9b6f6e9371084c | |
parent | e90887e68aa6dfa8c91af7d3bb2d2799f5a51b5e (diff) | |
download | gunmake-2c64fb221a265f9e7fc93374906b1e7540377561.tar.gz |
Checkpoint changes. Bug fixes, mostly.
-rw-r--r-- | ChangeLog | 234 | ||||
-rw-r--r-- | GNUmakefile | 20 | ||||
-rw-r--r-- | acconfig.h | 8 | ||||
-rw-r--r-- | acinclude.m4 | 81 | ||||
-rw-r--r-- | amiga.c | 2 | ||||
-rw-r--r-- | ar.c | 25 | ||||
-rw-r--r-- | arscan.c | 6 | ||||
-rw-r--r-- | commands.c | 17 | ||||
-rw-r--r-- | commands.h | 3 | ||||
-rw-r--r-- | config.ami.template | 188 | ||||
-rw-r--r-- | config.h-vms.template | 105 | ||||
-rw-r--r-- | config.h.W32.template | 149 | ||||
-rw-r--r-- | configure.in | 35 | ||||
-rw-r--r-- | default.c | 2 | ||||
-rw-r--r-- | dep.h | 22 | ||||
-rw-r--r-- | expand.c | 40 | ||||
-rw-r--r-- | file.c | 85 | ||||
-rw-r--r-- | filedef.h | 79 | ||||
-rw-r--r-- | function.c | 73 | ||||
-rw-r--r-- | getloadavg.c | 2 | ||||
-rw-r--r-- | glob/ChangeLog | 5 | ||||
-rw-r--r-- | implicit.c | 11 | ||||
-rw-r--r-- | job.c | 304 | ||||
-rw-r--r-- | job.h | 2 | ||||
-rw-r--r-- | main.c | 94 | ||||
-rw-r--r-- | make.h | 506 | ||||
-rw-r--r-- | make.texinfo | 11 | ||||
-rw-r--r-- | misc.c | 159 | ||||
-rw-r--r-- | read.c | 219 | ||||
-rw-r--r-- | remake.c | 97 | ||||
-rw-r--r-- | remote-cstms.c | 8 | ||||
-rw-r--r-- | rule.c | 6 | ||||
-rw-r--r-- | rule.h | 7 | ||||
-rw-r--r-- | variable.c | 7 | ||||
-rw-r--r-- | variable.h | 2 | ||||
-rw-r--r-- | vpath.c | 10 | ||||
-rw-r--r-- | w32/subproc/NMakefile | 120 | ||||
-rw-r--r-- | w32/subproc/sub_proc.c | 2376 |
38 files changed, 2847 insertions, 2273 deletions
@@ -1,3 +1,225 @@ +1998-09-21 Paul D. Smith <psmith@gnu.org> + + * job.c (construct_command_argv_internal): Only add COMMAND.COM + "@echo off" line for non-UNIXy shells. + +1998-09-09 Paul D. Smith <psmith@gnu.org> + + * w32/subproc/sub_proc.c: Add in missing HAVE_MKS_SHELL tests. + +1998-09-04 Paul D. Smith <psmith@gnu.org> + + * 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 <eggert@twinsun.com> + + * 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 <psmith@gnu.org> + + * 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 <psmith@gnu.org> + + * 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 <psmith@gnu.org> + + * 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 <eggert@twinsun.com> + + 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 <eliz@is.elta.co.il> + + * 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 <gracz@mincom.com>. + +1998-08-18 Paul D. Smith <psmith@gnu.org> + + * 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 <psmith@gnu.org> + + * 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 <eggert@twinsun.com> + + * filedef.h (FILE_TIMESTAMP_PRINT_LEN_BOUND): Add 10, for nanoseconds. + +1998-08-16 Paul Eggert <eggert@twinsun.com> + + * 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 <psmith@gnu.org> + + * 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 <psmith@gnu.org> + + * 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 <eggert@twinsun.com> + + * job.c (reap_children): Ignore unknown children. + +1998-07-31 Paul D. Smith <psmith@gnu.org> + + * 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 <psmith@gnu.org> + + * make.h: Added MIN/MAX. + * filedef.h: Use them; remove FILE_TIMESTAMP_MIN. + +1998-07-30 Paul Eggert <eggert@twinsun.com> + + 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 <inttypes.h> 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 <psmith@gnu.org> * Version 3.77 released. @@ -118,7 +340,7 @@ 1998-06-19 Eli Zaretskii <eliz@is.elta.co.il> - * 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 <psmith@gnu.org> @@ -503,7 +725,7 @@ Thu Aug 28 17:04:47 1997 Paul D. Smith <psmith@baynetworks.com> Wed Aug 27 17:09:32 1997 Paul D. Smith <psmith@baynetworks.com> - * Version 3.75.92 + * Version 3.75.92 Tue Aug 26 11:59:15 1997 Paul D. Smith <psmith@baynetworks.com> @@ -538,16 +760,16 @@ Fri Aug 22 1997 Eli Zaretskii <eliz@is.elta.co.il> Sat Aug 16 00:56:15 1997 John W. Eaton <jwe@bevo.che.wisc.edu> - * 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 <jwe@bevo.che.wisc.edu> - * 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 <jwe@bevo.che.wisc.edu> diff --git a/GNUmakefile b/GNUmakefile index 15067c6..97b2e1d 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 @@ -10,6 +10,10 @@ /* Define this if the SCCS `get' command understands the `-G<file>' 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 <sys/wait.h>. */ #undef HAVE_UNION_WAIT + +/* Define to `unsigned long' or `unsigned long long' + if <inttypes.h> doesn't define. */ +#undef uintmax_t diff --git a/acinclude.m4 b/acinclude.m4 index 343c333..ff51c4c 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 <egger@twinsun.com> +dnl by Paul Eggert <eggert@twinsun.com> 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 <eggert@twinsun.com> + +dnl Define HAVE_INTTYPES_H if <inttypes.h> exists, +dnl doesn't clash with <sys/types.h>, 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 <sys/types.h> +#include <inttypes.h>], + [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 <eggert@twinsun.com> + +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 <sys/types.h> +#include <sys/stat.h>], [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 <eggert@twinsun.com> + +dnl Define uintmax_t to `unsigned long' or `unsigned long long' +dnl if <inttypes.h> 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 +]) @@ -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; @@ -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; @@ -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; } @@ -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') @@ -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 b7103ed..523876e 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 <sys/dg_sys_info.h>. */ -#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 <sys/types.h> 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 <alloca.h> 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 <sys/wait.h> 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 <unistd.h>. */ -#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 <vfork.h>. */ -#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 <nlist.h>. */ -#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 <sys/types.h> 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 <sys/stat.h> 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 <signal.h>. */ -#undef SYS_SIGLIST_DECLARED +/* #undef SYS_SIGLIST_DECLARED */ /* Define to `int' if <sys/types.h> doesn't define. */ #define uid_t int /* Define for Encore UMAX. */ -#undef UMAX +/* #undef UMAX */ /* Define for Encore UMAX 4.3 that has <inq_status/cpustats.h> instead of <sys/cpustats.h>. */ -#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<file>' 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 <sys/wait.h>. */ -#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 <dirent.h> header file. */ -#define HAVE_DIRENT_H +#define HAVE_DIRENT_H 1 /* Define if you have the <fcntl.h> header file. */ -#define HAVE_FCNTL_H +#define HAVE_FCNTL_H 1 /* Define if you have the <limits.h> header file. */ -#define HAVE_LIMITS_H +#define HAVE_LIMITS_H 1 /* Define if you have the <mach/mach.h> header file. */ -#undef HAVE_MACH_MACH_H +/* #undef HAVE_MACH_MACH_H */ /* Define if you have the <memory.h> header file. */ -#undef HAVE_MEMORY_H +/* #undef HAVE_MEMORY_H */ /* Define if you have the <ndir.h> header file. */ -#undef HAVE_NDIR_H +/* #undef HAVE_NDIR_H */ + +/* Define if you have the <stdlib.h> header file. */ +/* #undef HAVE_STDLIB_H */ /* Define if you have the <string.h> header file. */ -#define HAVE_STRING_H +#define HAVE_STRING_H 1 /* Define if you have the <sys/dir.h> header file. */ -#define HAVE_SYS_DIR_H +#define HAVE_SYS_DIR_H 1 /* Define if you have the <sys/ndir.h> header file. */ -#undef HAVE_SYS_NDIR_H +/* #undef HAVE_SYS_NDIR_H */ /* Define if you have the <sys/param.h> header file. */ -#undef HAVE_SYS_PARAM_H +/* #undef HAVE_SYS_PARAM_H */ /* Define if you have the <sys/timeb.h> header file. */ -#undef HAVE_SYS_TIMEB_H +/* #undef HAVE_SYS_TIMEB_H */ /* Define if you have the <sys/wait.h> header file. */ -#undef HAVE_SYS_WAIT_H +/* #undef HAVE_SYS_WAIT_H */ /* Define if you have the <unistd.h> 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 a41ae06..e44af44 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 <sys/types.h> doesn't define. */ /* #undef gid_t */ @@ -32,14 +35,14 @@ #define HAVE_ALLOCA 1 /* Define if you have <alloca.h> 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 <sys/wait.h> 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 <vfork.h>. */ -/* #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 <nlist.h>. */ -/* #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 <sys/cpustats.h>. */ /* #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<file>' 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 <sys/wait.h>. */ /* #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 <dirent.h> header file. */ -/* #unddef HAVE_DIRENT_H 1 */ +/* #undef HAVE_DIRENT_H */ /* Define if you have the <fcntl.h> header file. */ #ifdef __DECC @@ -252,17 +270,17 @@ /* #undef HAVE_MACH_MACH_H */ /* Define if you have the <memory.h> header file. */ -/* #undef HAVE_MEMORY_H 1 */ +/* #undef HAVE_MEMORY_H */ /* Define if you have the <ndir.h> header file. */ /* #undef HAVE_NDIR_H */ +/* Define if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + /* Define if you have the <string.h> header file. */ #define HAVE_STRING_H 1 -/* Define if you have the <pwd.h> header file. */ -/* #undef HAVE_PWD_H */ - /* Define if you have the <sys/dir.h> header file. */ /* #undef HAVE_SYS_DIR_H */ @@ -270,24 +288,29 @@ /* #undef HAVE_SYS_NDIR_H */ /* Define if you have the <sys/param.h> header file. */ -/* #undef HAVE_SYS_PARAM_H 1 */ +/* #undef HAVE_SYS_PARAM_H */ /* Define if you have the <sys/timeb.h> header file. */ #define HAVE_SYS_TIMEB_H 1 /* Define if you have the <sys/wait.h> header file. */ -/* #undef HAVE_SYS_WAIT_H 1 */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define if you have the <unistd.h> 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 aa5a027..79bb6cd 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 <sys/dg_sys_info.h>. */ -#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 <sys/types.h> doesn't define. */ #undef gid_t @@ -32,40 +35,39 @@ #define HAVE_ALLOCA 1 /* Define if you have <alloca.h> 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 <sys/wait.h> 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 <unistd.h>. */ -#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 <vfork.h>. */ -#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 <nlist.h>. */ -#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 <sys/types.h> 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 <sys/stat.h> 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 <signal.h>. */ -#undef SYS_SIGLIST_DECLARED +/* #undef SYS_SIGLIST_DECLARED */ /* Define to `int' if <sys/types.h> 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 <inq_status/cpustats.h> instead of <sys/cpustats.h>. */ -#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<file>' 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 <sys/wait.h>. */ -#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 <dirent.h> header file. */ #undef HAVE_DIRENT_H @@ -260,43 +284,46 @@ #define HAVE_LIMITS_H 1 /* Define if you have the <mach/mach.h> header file. */ -#undef HAVE_MACH_MACH_H +/* #undef HAVE_MACH_MACH_H */ /* Define if you have the <memory.h> header file. */ #undef HAVE_MEMORY_H #define HAVE_MEMORY_H 1 /* Define if you have the <ndir.h> header file. */ -#undef HAVE_NDIR_H +/* #undef HAVE_NDIR_H */ /* Define if you have the <string.h> header file. */ #undef HAVE_STRING_H #define HAVE_STRING_H 1 /* Define if you have the <sys/dir.h> header file. */ -#undef HAVE_SYS_DIR_H +/* #undef HAVE_SYS_DIR_H */ /* Define if you have the <sys/ndir.h> header file. */ -#undef HAVE_SYS_NDIR_H +/* #undef HAVE_SYS_NDIR_H */ /* Define if you have the <sys/param.h> header file. */ -#undef HAVE_SYS_PARAM_H +/* #undef HAVE_SYS_PARAM_H */ /* Define if you have the <sys/timeb.h> header file. */ #undef HAVE_SYS_TIMEB_H #define HAVE_SYS_TIMEB_H 1 /* Define if you have the <sys/wait.h> header file. */ -#undef HAVE_SYS_WAIT_H +/* #undef HAVE_SYS_WAIT_H */ /* Define if you have the <unistd.h> 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 8fb99f7..ebc9cdf 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 <sys/types.h> @@ -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: "" @@ -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; } @@ -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 *)); @@ -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; @@ -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 <assert.h> + #include "make.h" #include "dep.h" #include "filedef.h" #include "job.h" #include "commands.h" #include "variable.h" -#include <assert.h> /* 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) @@ -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,11 +97,62 @@ 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. */ @@ -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. */ @@ -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 7c1cc80..36245ef 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 e3854a5..b7e85ad 100644 --- a/glob/ChangeLog +++ b/glob/ChangeLog @@ -1,3 +1,8 @@ +1998-08-05 Paul D. Smith <psmith@gnu.org> + + * configure.in: Remove; configuration for glob is handled by the + make configure.in. + 1998-07-29 Paul D. Smith <psmith@gnu.org> * glob.c, fnmatch.c: New versions from the GLIBC folks (Ulrich @@ -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); @@ -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 <process.h> +# include <process.h> 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 <proto/dos.h> +# include <proto/dos.h> 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 <time.h> -#include <processes.h> -#include <starlet.h> -#include <lib$routines.h> +# include <time.h> +# include <processes.h> +# include <starlet.h> +# include <lib$routines.h> #endif #ifdef WINDOWS32 -#include <windows.h> -#include <io.h> -#include <process.h> -#include "sub_proc.h" -#include "w32err.h" -#include "pathstuff.h" +# include <windows.h> +# include <io.h> +# include <process.h> +# include "sub_proc.h" +# include "w32err.h" +# include "pathstuff.h" #endif /* WINDOWS32 */ #ifdef HAVE_FCNTL_H -#include <fcntl.h> +# include <fcntl.h> #else -#include <sys/file.h> +# include <sys/file.h> #endif #if defined (HAVE_SYS_WAIT_H) || defined (HAVE_UNION_WAIT) -#include <sys/wait.h> +# include <sys/wait.h> #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 - -#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 +# define WAIT_T int + +# ifndef WTERMSIG +# define WTERMSIG(x) ((x) & 0x7f) +# endif +# ifndef WCOREDUMP +# define WCOREDUMP(x) ((x) & 0x80) +# endif +# ifndef WEXITSTATUS +# define WEXITSTATUS(x) (((x) >> 8) & 0xff) +# endif +# ifndef WIFSIGNALED +# define WIFSIGNALED(x) (WTERMSIG (x) != 0) +# endif +# ifndef WIFEXITED +# define WIFEXITED(x) (WTERMSIG (x) == 0) +# endif #else /* 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) + { + /* 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. */ + /* 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 } @@ -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; @@ -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 <assert.h> #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. */ - -#ifdef SIGCHLD - (void) signal (SIGCHLD, child_handler); -#endif -#ifdef SIGCLD - (void) signal (SIGCLD, child_handler); +#ifndef HAVE_WAIT_NOHANG + { + extern RETSIGTYPE child_handler PARAMS ((int sig)); + + /* 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; @@ -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 <config.h> -#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 <signal.h> so that the declaration therein is changed. */ -#define signal bsdsignal +# define signal bsdsignal #endif -#define _GNU_SOURCE +#define _GNU_SOURCE 1 #include <sys/types.h> #include <sys/stat.h> #include <signal.h> @@ -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 <time.h> that bombs unless <sys/timeb.h> has been included first. Does every system have a <sys/timeb.h>? If any does not, configure should check for it. */ -#include <sys/timeb.h> +# include <sys/timeb.h> #endif #include <time.h> #include <errno.h> -#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 <unistd.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> /* 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 <signal.h>. */ -#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 <limits.h> +#ifdef HAVE_LIMITS_H +# include <limits.h> #endif -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> +#ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> #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 <stdio.h> -#include <types.h> -#include <unixlib.h> -#include <unixio.h> -#include <errno.h> -#include <perror.h> +# include <stdio.h> +# include <types.h> +# include <unixlib.h> +# include <unixio.h> +# include <errno.h> +# include <perror.h> #endif -#if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) || defined(VMS)) -#include <stdlib.h> -#include <string.h> -#define ANSI_STRING -#else /* No standard headers. */ - -#ifdef HAVE_STRING_H -#include <string.h> -#define ANSI_STRING -#else -#include <strings.h> -#endif -#ifdef HAVE_MEMORY_H -#include <memory.h> +#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 <stdlib.h> +# include <string.h> +# define ANSI_STRING 1 +#else /* No standard headers. */ +# ifdef HAVE_STRING_H +# include <string.h> +# define ANSI_STRING 1 +# else +# include <strings.h> +# endif +# ifdef HAVE_MEMORY_H +# include <memory.h> +# endif +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# 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 <inttypes.h> +# 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 (); +# 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 + +#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 +#endif /* ANSI_STRING. */ +#undef ANSI_STRING /* SCO Xenix has a buggy macro definition in <string.h>. */ -#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 <alloca.h> -#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 <alloca.h> +# else /* Not HAVE_ALLOCA_H. */ +# ifndef _AIX extern char *alloca (); -#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 +# 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 #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 ';' -#else -#if defined(VMS) -#define PATH_SEPARATOR_CHAR ',' +# 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 <fcntl.h> -#include <malloc.h> -#define pipe(p) _pipe(p, 512, O_BINARY) -#define kill(pid,sig) w32_kill(pid,sig) +# include <fcntl.h> +# include <malloc.h> +# 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 */ + +struct floc + { + char *filenm; + unsigned long lineno; + }; +#define NILF ((struct floc *)0) + -extern void die () __attribute__ ((noreturn)); +/* 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 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 (); -#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 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 (); - -extern void build_vpath_lists (); -extern void construct_vpath_list (); -extern int vpath_search (); -extern int gpath_search (); - -extern void construct_include_path (); -extern void uniquize_deps (); - -extern int update_goal_chain (); -extern void notice_finished_file (); - -extern void user_access (); -extern void make_access (); -extern void child_access (); - -#ifdef HAVE_VFORK_H -#include <vfork.h> +extern void fatal (); +#endif + +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 *)); + +#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 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 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 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 construct_include_path PARAMS ((char **arg_dirs)); + +extern void user_access PARAMS ((void)); +extern void make_access PARAMS ((void)); +extern void child_access PARAMS ((void)); + +#ifdef HAVE_VFORK_H +# include <vfork.h> #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 05d0746..e7b3bbf 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 @@ -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 <stdarg.h> +# define VA_START(args, lastarg) va_start(args, lastarg) +# else +# include <varargs.h> +# 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. */ +/* Print an error message. */ -/* VARARGS1 */ void -fatal (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 { - 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 */ +#if HAVE_STDVARARGS + va_list args; +#endif -void -error (s1, s2, s3, s4, s5, s6) - char *s1, *s2, *s3, *s4, *s5, *s6; -{ 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); - 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); + VA_START(args, fmt); + VA_PRINTF (stderr, fmt, args); + VA_END (args); - 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; } @@ -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: @@ -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 e1d63a3..cf91816 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); } @@ -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"); @@ -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)); @@ -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. */ @@ -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, @@ -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 f187827..66afe65 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 281c81c..300bb7b 100644 --- a/w32/subproc/sub_proc.c +++ b/w32/subproc/sub_proc.c @@ -1,1186 +1,1190 @@ -#include <stdlib.h>
-#include <stdio.h>
-#include <process.h> /* for msvc _beginthreadex, _endthreadex */
-#include <windows.h>
-
-#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 <stdlib.h> +#include <stdio.h> +#include <process.h> /* for msvc _beginthreadex, _endthreadex */ +#include <windows.h> + +#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; +} |