diff --git a/ChangeLog b/ChangeLog index 78d9bc1a..5ed4f0b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,93 @@ +Wed May 15 10:14:14 CDT 1996 Rob Tulloh + + * dir.c: WIN32 does not support inode. For now, fully qualified + pathname along with st_mtime will be keys for files. + Fixed problem where vpath can be confused when files + are added to a directory after the directory has already been + read in. The code now attempts to reread the directory if it + discovers that the datestamp on the directory has changed since + it was cached by make. This problem only seems to occur on WIN32 + right now so it is lumped under port #ifdef WIN32. + + * function.c: WIN32: call subproc library (CreateProcess()) instead of + fork/exec. + + * job.c: WIN32: Added the code to do fork/exec/waitpid style processing + on WIN32 systems via calls to subproc library. + + * main.c: WIN32: Several things added here. First, there is code + for dealing with PATH and SHELL defaults. Make tries to figure + out if the user has %PATH% set in the environment and sets it to + %Path% if it is not set already. Make also looks to see if sh.exe + is anywhere to be found. Code path through job.c will change + based on existence of a working Bourne shell. The checking for + default shell is done twice: once before makefiles are read in + and again after. Fall back to MSDOS style execution mode if no sh.exe + is found. Also added some debug support that allows user to pause make + with -D switch and attach a debugger. This is especially useful for + debugging recursive calls to make where problems appear only in the + sub-make. + + * make.h: WIN32: A few macros and header files for WIN32 support. + + * misc.c: WIN32: Added a function end_of_token_w32() to assist + in parsing code in read.c. + + * read.c: WIN32: Fixes similar to MSDOS which allow colon to + appear in filenames. Use of colon in filenames would otherwise + confuse make. + + * remake.c: WIN32: Added include of io.h to eliminate compiler + warnings. Added some code to default LIBDIR if it is not set + on WIN32. + + * variable.c: WIN32: Added support for detecting Path/PATH + and converting them to semicolon separated lists for make's + internal use. New function sync_Path_environment() + which is called in job.c and function.c before creating a new + process. Caller must set Path in environment since we don't + have fork() to do this for us. + + * vpath.c: WIN32: Added detection for filenames containing + forward or backward slashes. + + * NMakefile: WIN32: Visual C compatible makefile for use with nmake. + Use this to build GNU make the first time on Windows NT or Windows 95. + + * README.WIN32: WIN32: Contains some helpful notes. + + * build_w32.bat: WIN32: If you don't like nmake, use this the first + time you build GNU make on Windows NT or Windows 95. + + * config.h.WIN32: WIN32 version of config.h + + * subproc.bat: WIN32: A bat file used to build the + subproc library from the top-level NMakefile. Needed because + WIndows 95 (nmake) doesn't allow you to cd in a make rule. + + * w32/include/dirent.h + * w32/compat/dirent.c: WIN32: opendir, readdir, closedir, etc. + + * w32/include/pathstuff.h: WIN32: used by files needed functions + defined in pathstuff.c (prototypes). + + * w32/include/sub_proc.h: WIN32: prototypes for subproc.lib functions. + + * w32/include/w32err.h: WIN32: prototypes for w32err.c. + + * w32/pathstuff.c: WIN32: File and Path/Path conversion functions. + + * w32/subproc/build.bat: WIN32: build script for subproc library + if you don't wish to use nmake. + + * w32/subproc/NMakefile: WIN32: Visual C compatible makefile for use + with nmake. Used to build subproc library. + + * w32/subproc/misc.c: WIN32: subproc library support code + * w32/subproc/proc.h: WIN32: subproc library support code + * w32/subproc/sub_proc.c: WIN32: subproc library source code + * w32/subproc/w32err.c: WIN32: subproc library support code + Wed May 22 17:24:51 1996 Roland McGrath * makefile.vms: Set LOADLIBES. diff --git a/NMakefile.template b/NMakefile.template new file mode 100644 index 00000000..f546074f --- /dev/null +++ b/NMakefile.template @@ -0,0 +1,135 @@ +# NOTE: If you have no `make' program at all to process this makefile, run +# `build_w32.bat' instead. +# +# Copyright (C) 1988, 89, 91, 92, 93, 94, 95, 1996 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 +# + +LINK = link +CC = cl + +OUTDIR=. +MAKEFILE=NMakefile +SUBPROC_MAKEFILE=NMakefile + +CFLAGS_any = /nologo /MT /W3 /GX /Zi /YX /I . /I glob /I w32/include /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES +CFLAGS_debug = $(CFLAGS_any) /Od /D _DEBUG /FR.\WinDebug/ /Fp.\WinDebug/make.pch /Fo.\WinDebug/ /Fd.\WinDebug/make.pdb +CFLAGS_release = $(CFLAGS_any) /O2 /D NDEBUG /FR.\WinRel/ /Fp.\WinRel/make.pch /Fo.\WinRel/ + +LDFLAGS_debug = w32\subproc\WinDebug\subproc.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:no /PDB:WinRel/make.pdb /MACHINE:I386 /OUT:WinDebug/make.exe +LDFLAGS_release = w32\subproc\WinRel\subproc.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:no /MACHINE:I386 /OUT:WinRel/make.exe + +all: subproc Release Debug + +# +# Make sure we build the subproc library first. It has it's own +# makefile. To be portable to Windows 95, we put the instructions +# on how to build the library into a batch file. On NT, we could +# simply have done foo && bar && dog, but this doesn't port. +# +subproc: w32/subproc/WinDebug/subproc.lib w32/subproc/WinRel/subproc.lib + +w32/subproc/WinDebug/subproc.lib w32/subproc/WinRel/subproc.lib: + subproc.bat $(SUBPROC_MAKEFILE) + +Release: + nmake /f $(MAKEFILE) LDFLAGS="$(LDFLAGS_release)" CFLAGS="$(CFLAGS_release)" OUTDIR=WinRel WinRel/make.exe +Debug: + nmake /f $(MAKEFILE) LDFLAGS="$(LDFLAGS_debug)" CFLAGS="$(CFLAGS_debug)" OUTDIR=WinDebug WinDebug/make.exe + +clean: + rmdir /s /q WinDebug WinRel + +$(OUTDIR): + if not exist .\$@\nul mkdir .\$@ + +LIBS = kernel32.lib user32.lib advapi32.lib + +OBJS = \ + $(OUTDIR)/ar.obj \ + $(OUTDIR)/arscan.obj \ + $(OUTDIR)/commands.obj \ + $(OUTDIR)/default.obj \ + $(OUTDIR)/dir.obj \ + $(OUTDIR)/expand.obj \ + $(OUTDIR)/file.obj \ + $(OUTDIR)/function.obj \ + $(OUTDIR)/getloadavg.obj \ + $(OUTDIR)/getopt.obj \ + $(OUTDIR)/getopt1.obj \ + $(OUTDIR)/implicit.obj \ + $(OUTDIR)/job.obj \ + $(OUTDIR)/main.obj \ + $(OUTDIR)/misc.obj \ + $(OUTDIR)/read.obj \ + $(OUTDIR)/remake.obj \ + $(OUTDIR)/remote-stub.obj \ + $(OUTDIR)/rule.obj \ + $(OUTDIR)/signame.obj \ + $(OUTDIR)/variable.obj \ + $(OUTDIR)/version.obj \ + $(OUTDIR)/vpath.obj \ + $(OUTDIR)/glob.obj \ + $(OUTDIR)/fnmatch.obj \ + $(OUTDIR)/dirent.obj \ + $(OUTDIR)/pathstuff.obj + +$(OUTDIR)/make.exe: $(OUTDIR) $(OBJS) + $(LINK) @<< + $(LDFLAGS) $(LIBS) $(OBJS) +<< + +.c{$(OUTDIR)}.obj: + $(CC) $(CFLAGS) /c $< + +$(OUTDIR)/ar.obj : ar.c make.h filedef.h dep.h +$(OUTDIR)/arscan.obj : arscan.c make.h +$(OUTDIR)/commands.obj : commands.c +$(OUTDIR)/default.obj : default.c make.h rule.h dep.h filedef.h job.h commands.h variable.h +$(OUTDIR)/dir.obj : dir.c make.h +$(OUTDIR)/expand.obj : expand.c make.h filedef.h job.h commands.h variable.h +$(OUTDIR)/file.obj : file.c make.h dep.h filedef.h job.h commands.h variable.h +$(OUTDIR)/function.obj : function.c make.h filedef.h variable.h dep.h job.h commands.h +$(OUTDIR)/getloadavg.obj : getloadavg.c +$(OUTDIR)/getopt.obj : getopt.c +$(OUTDIR)/getopt1.obj : getopt1.c getopt.h +$(OUTDIR)/implicit.obj : implicit.c make.h rule.h dep.h filedef.h +$(OUTDIR)/job.obj : job.c make.h job.h filedef.h commands.h variable.h +$(OUTDIR)/main.obj : main.c make.h dep.h filedef.h variable.h job.h commands.h getopt.h +$(OUTDIR)/misc.obj : misc.c make.h dep.h +$(OUTDIR)/read.obj : read.c make.h dep.h filedef.h job.h commands.h variable.h glob/glob.h +$(OUTDIR)/remake.obj : remake.c make.h filedef.h job.h commands.h dep.h +$(OUTDIR)/remote-stub.obj : remote-stub.c make.h filedef.h job.h commands.h +$(OUTDIR)/rule.obj : rule.c make.h dep.h filedef.h job.h commands.h variable.h rule.h +$(OUTDIR)/signame.obj : signame.c signame.h +$(OUTDIR)/variable.obj : variable.c make.h dep.h filedef.h job.h commands.h variable.h +$(OUTDIR)/version.obj : version.c +$(OUTDIR)/vpath.obj : vpath.c make.h filedef.h variable.h +$(OUTDIR)/glob.obj : glob/glob.c + $(CC) $(CFLAGS) /c $? +$(OUTDIR)/fnmatch.obj : glob/fnmatch.c + $(CC) $(CFLAGS) /c $? +$(OUTDIR)/dirent.obj : w32/compat/dirent.c + $(CC) $(CFLAGS) /c $? +$(OUTDIR)/pathstuff.obj : w32/pathstuff.c + $(CC) $(CFLAGS) /c $? + diff --git a/README.W32 b/README.W32 new file mode 100644 index 00000000..9e4c56ed --- /dev/null +++ b/README.W32 @@ -0,0 +1,49 @@ +Port of GNU make to Windows NT and Windows 95 +Builds natively with MSVC 2.x or MSVC 4.x compilers. + +To build with nmake on Windows NT or Windows 95: + + 1. Make sure cl.exe is in your %Path%. Example: + + set Path=%Path%;c:/msdev/bin + + 2. Make sure %include% is set to msvc include directory. Example: + + set include=c:/msdev/include + + 3. Make sure %lib% is set to msvc lib directory. Example: + + set lib=c:/msdev/lib + + 4. nmake /f NMakefile + + +There is a bat file (build_w32.bat) for folks who have fear of nmake. + +Outputs: + + WinDebug/make.exe + WinRel/make.exe + +Notes: + + This port prefers you have a working sh.exe somewhere on your + system. If you don't have sh.exe, port falls back to + MSDOS mode for launching programs (via a batch file). + The MSDOS mode style execution has not been tested too + carefully though (I use GNU bash as sh.exe). + + I verified all functionality with a slightly modified version + of make-test-0.4.5 (modifications to get test suite to run + on Windows NT). All tests pass in an environment that includes + sh.exe. + + I did not provide a Visual C project file with this port as + the project file would not be considered freely distributable + (or so I think). It is easy enough to create one though if + you know how to use Visual C. + + I build the program statically to avoid problems locating DLL's + on machines that may not have MSVC runtime installed. If you + prefer, you can change make to build with shared libraries by + changing /MT to /MD in the NMakefile (or build_w32.bat). diff --git a/README.WIN32 b/README.WIN32 new file mode 100644 index 00000000..9e4c56ed --- /dev/null +++ b/README.WIN32 @@ -0,0 +1,49 @@ +Port of GNU make to Windows NT and Windows 95 +Builds natively with MSVC 2.x or MSVC 4.x compilers. + +To build with nmake on Windows NT or Windows 95: + + 1. Make sure cl.exe is in your %Path%. Example: + + set Path=%Path%;c:/msdev/bin + + 2. Make sure %include% is set to msvc include directory. Example: + + set include=c:/msdev/include + + 3. Make sure %lib% is set to msvc lib directory. Example: + + set lib=c:/msdev/lib + + 4. nmake /f NMakefile + + +There is a bat file (build_w32.bat) for folks who have fear of nmake. + +Outputs: + + WinDebug/make.exe + WinRel/make.exe + +Notes: + + This port prefers you have a working sh.exe somewhere on your + system. If you don't have sh.exe, port falls back to + MSDOS mode for launching programs (via a batch file). + The MSDOS mode style execution has not been tested too + carefully though (I use GNU bash as sh.exe). + + I verified all functionality with a slightly modified version + of make-test-0.4.5 (modifications to get test suite to run + on Windows NT). All tests pass in an environment that includes + sh.exe. + + I did not provide a Visual C project file with this port as + the project file would not be considered freely distributable + (or so I think). It is easy enough to create one though if + you know how to use Visual C. + + I build the program statically to avoid problems locating DLL's + on machines that may not have MSVC runtime installed. If you + prefer, you can change make to build with shared libraries by + changing /MT to /MD in the NMakefile (or build_w32.bat). diff --git a/build_w32.bat b/build_w32.bat new file mode 100644 index 00000000..5a0c9c14 --- /dev/null +++ b/build_w32.bat @@ -0,0 +1,136 @@ +cd w32\subproc +echo "Creating the subproc library" +%ComSpec% /c build.bat +cd ..\.. +del link.dbg link.rel +del config.h +copy config.h.WIN32 config.h +echo off +echo "Creating GNU make 3.74 for Windows NT" +echo on +if not exist .\WinDebug\nul mkdir .\WinDebug +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D TIVOLI /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c variable.c +echo WinDebug\variable.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c rule.c +echo WinDebug\rule.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c remote-stub.c +echo WinDebug\remote-stub.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c commands.c +echo WinDebug\commands.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c file.c +echo WinDebug\file.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c getloadavg.c +echo WinDebug\getloadavg.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c default.c +echo WinDebug\default.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c signame.c +echo WinDebug\signame.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c expand.c +echo WinDebug\expand.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c dir.c +echo WinDebug\dir.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c main.c +echo WinDebug\main.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c getopt1.c +echo WinDebug\getopt1.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c job.c +echo WinDebug\job.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c read.c +echo WinDebug\read.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c version.c +echo WinDebug\version.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c getopt.c +echo WinDebug\getopt.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c arscan.c +echo WinDebug\arscan.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c remake.c +echo WinDebug\remake.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c misc.c +echo WinDebug\misc.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c ar.c +echo WinDebug\ar.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c function.c +echo WinDebug\function.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c vpath.c +echo WinDebug\vpath.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c implicit.c +echo WinDebug\implicit.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c .\w32\compat\dirent.c +echo WinDebug\dirent.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c .\glob\glob.c +echo WinDebug\glob.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c .\glob\fnmatch.c +echo WinDebug\fnmatch.obj >>link.dbg +cl.exe /nologo /MT /W3 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinDebug/ /Fp.\WinDebug/make374.pch /Fo.\WinDebug/ /Fd.\WinDebug/make374.pdb /c .\w32\pathstuff.c +echo WinDebug\pathstuff.obj >>link.dbg +echo off +echo "Linking WinDebug/make374.exe" +rem link.exe kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib w32\subproc\windebug\subproc.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes /PDB:.\WinDebug/make374.pdb /DEBUG /MACHINE:I386 /OUT:.\WinDebug/make374.exe .\WinDebug/variable.obj .\WinDebug/rule.obj .\WinDebug/remote-stub.obj .\WinDebug/commands.obj .\WinDebug/file.obj .\WinDebug/getloadavg.obj .\WinDebug/default.obj .\WinDebug/signame.obj .\WinDebug/expand.obj .\WinDebug/dir.obj .\WinDebug/main.obj .\WinDebug/getopt1.obj .\WinDebug/job.obj .\WinDebug/read.obj .\WinDebug/version.obj .\WinDebug/getopt.obj .\WinDebug/arscan.obj .\WinDebug/remake.obj .\WinDebug/misc.obj .\WinDebug/ar.obj .\WinDebug/function.obj .\WinDebug/vpath.obj .\WinDebug/implicit.obj .\WinDebug/dirent.obj .\WinDebug/glob.obj .\WinDebug/fnmatch.obj .\WinDebug/pathstuff.obj +echo kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib w32\subproc\windebug\subproc.lib >>link.dbg +link.exe /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes /PDB:.\WinDebug/make374.pdb /DEBUG /MACHINE:I386 /OUT:.\WinDebug/make374.exe @link.dbg +if not exist .\WinDebug/make374.exe echo "WinDebug build failed" +if exist .\WinDebug/make374.exe echo "WinDebug build succeeded!" +if not exist .\WinRel\nul mkdir .\WinRel +echo on +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /D TIVOLI /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c variable.c +echo WinRel\variable.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c rule.c +echo WinRel\rule.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c remote-stub.c +echo WinRel\remote-stub.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c commands.c +echo WinRel\commands.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c file.c +echo WinRel\file.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c getloadavg.c +echo WinRel\getloadavg.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c default.c +echo WinRel\default.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c signame.c +echo WinRel\signame.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c expand.c +echo WinRel\expand.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c dir.c +echo WinRel\dir.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c main.c +echo WinRel\main.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c getopt1.c +echo WinRel\getopt1.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c job.c +echo WinRel\job.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c read.c +echo WinRel\read.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c version.c +echo WinRel\version.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c getopt.c +echo WinRel\getopt.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c arscan.c +echo WinRel\arscan.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c remake.c +echo WinRel\remake.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c misc.c +echo WinRel\misc.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c ar.c +echo WinRel\ar.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c function.c +echo WinRel\function.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c vpath.c +echo WinRel\vpath.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c implicit.c +echo WinRel\implicit.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c .\w32\compat\dirent.c +echo WinRel\dirent.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c .\glob\glob.c +echo WinRel\glob.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c .\glob\fnmatch.c +echo WinRel\fnmatch.obj >>link.rel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES /FR.\WinRel/ /Fp.\WinRel/make374.pch /Fo.\WinRel/ /c .\w32\pathstuff.c +echo WinRel\pathstuff.obj >>link.rel +echo off +echo "Linking WinRel/make374.exe" +rem link.exe kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib w32\subproc\winrel\subproc.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no /PDB:.\WinRel/make374.pdb /MACHINE:I386 /OUT:.\WinRel/make374.exe .\WinRel/variable.obj .\WinRel/rule.obj .\WinRel/remote-stub.obj .\WinRel/commands.obj .\WinRel/file.obj .\WinRel/getloadavg.obj .\WinRel/default.obj .\WinRel/signame.obj .\WinRel/expand.obj .\WinRel/dir.obj .\WinRel/main.obj .\WinRel/getopt1.obj .\WinRel/job.obj .\WinRel/read.obj .\WinRel/version.obj .\WinRel/getopt.obj .\WinRel/arscan.obj .\WinRel/remake.obj .\WinRel/misc.obj .\WinRel/ar.obj .\WinRel/function.obj .\WinRel/vpath.obj .\WinRel/implicit.obj .\WinRel/dirent.obj .\WinRel/glob.obj .\WinRel/fnmatch.obj .\WinRel/pathstuff.obj +echo kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib w32\subproc\winrel\subproc.lib >>link.rel +link.exe /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no /PDB:.\WinRel/make374.pdb /MACHINE:I386 /OUT:.\WinRel/make374.exe @link.rel +if not exist .\WinRel/make374.exe echo "WinRel build failed" +if exist .\WinRel/make374.exe echo "WinRel build succeeded!" +echo on diff --git a/config.h.W32.template b/config.h.W32.template new file mode 100644 index 00000000..5188b1fe --- /dev/null +++ b/config.h.W32.template @@ -0,0 +1,289 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +#undef _ALL_SOURCE +#endif + +/* Define if using alloca.c. */ +#undef C_ALLOCA + +/* Define to empty if the keyword does not work. */ +#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 + +/* Define for DGUX with . */ +#undef DGUX + +/* Define if the `getloadavg' function needs to be run setuid or setgid. */ +#undef GETLOADAVG_PRIVILEGED + +/* Define to `int' if doesn't define. */ +#undef gid_t +#define gid_t int + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA +#define HAVE_ALLOCA + +/* Define if you have and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if your system has its own `getloadavg' function. */ +#undef HAVE_GETLOADAVG + +/* Define if you have the getmntent function. */ +#undef HAVE_GETMNTENT + +/* Define if the `long double' type works. */ +#undef HAVE_LONG_DOUBLE + +/* Define if you support file names longer than 14 characters. */ +#undef HAVE_LONG_FILE_NAMES +#define HAVE_LONG_FILE_NAMES + +/* Define if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define if system calls automatically restart after interruption + by a signal. */ +#undef HAVE_RESTARTABLE_SYSCALLS + +/* Define if your struct stat has st_blksize. */ +#undef HAVE_ST_BLKSIZE + +/* Define if your struct stat has st_blocks. */ +#undef HAVE_ST_BLOCKS + +/* Define if you have the strcoll function and it is properly defined. */ +#undef HAVE_STRCOLL +#define HAVE_STRCOLL + +/* Define if your struct stat has st_rdev. */ +#undef HAVE_ST_RDEV +#define HAVE_ST_RDEV + +/* Define if you have the strftime function. */ +#undef HAVE_STRFTIME +#define HAVE_STRFTIME + +/* Define if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define if your struct tm has tm_zone. */ +#undef HAVE_TM_ZONE + +/* Define if you don't have tm_zone but do have the external array + tzname. */ +#undef HAVE_TZNAME +#define HAVE_TZNAME + +/* Define if you have . */ +#undef HAVE_UNISTD_H + +/* Define if utime(file, NULL) sets file's timestamp to the present. */ +#undef HAVE_UTIME_NULL +#define HAVE_UTIME_NULL + +/* Define if you have . */ +#undef HAVE_VFORK_H + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF +#define HAVE_VPRINTF + +/* Define if you have the wait3 system call. */ +#undef HAVE_WAIT3 + +/* Define if on MINIX. */ +#undef _MINIX + +/* Define if your struct nlist has an n_un member. */ +#undef NLIST_NAME_UNION + +/* Define if you have . */ +#undef NLIST_STRUCT + +/* Define if your C compiler doesn't accept -c and -o together. */ +#undef NO_MINUS_C_MINUS_O + +/* Define to `int' if doesn't define. */ +#undef pid_t +#define pid_t int + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +#undef _POSIX_1_SOURCE + +/* Define if you need to in order for stat and other things to work. */ +#undef _POSIX_SOURCE +#define _POSIX_SOURCE + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE +#define RETSIGTYPE void + +/* 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 + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#undef STACK_DIRECTION + +/* Define if the `S_IS*' macros in do not work properly. */ +#undef STAT_MACROS_BROKEN + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS +#define STDC_HEADERS + +/* Define on System V Release 4. */ +#undef SVR4 + +/* Define if `sys_siglist' is declared by . */ +#undef SYS_SIGLIST_DECLARED + +/* Define to `int' if doesn't define. */ +#undef uid_t +#define uid_t int + +/* Define for Encore UMAX. */ +#undef UMAX + +/* Define for Encore UMAX 4.3 that has + instead of . */ +#undef UMAX4_3 + +/* Define vfork as fork if vfork does not work. */ +#undef vfork + +/* Define to the name of the SCCS `get' command. */ +#undef SCCS_GET +#define SCCS_GET "echo no sccs get" + +/* Define this if the SCCS `get' command understands the `-G' option. */ +#undef SCCS_GET_MINUS_G + +/* Define this if the C library defines the variable `sys_siglist'. */ +#undef HAVE_SYS_SIGLIST + +/* Define this if the C library defines the variable `_sys_siglist'. */ +#undef HAVE__SYS_SIGLIST + +/* Define this if you have the `union wait' type in . */ +#undef HAVE_UNION_WAIT + +/* Define if you have the dup2 function. */ +#undef HAVE_DUP2 +#define HAVE_DUP2 + +/* Define if you have the getcwd function. */ +#undef HAVE_GETCWD +#define HAVE_GETCWD + +/* Define if you have the getgroups function. */ +#undef HAVE_GETGROUPS + +/* Define if you have the mktemp function. */ +#undef HAVE_MKTEMP +#define HAVE_MKTEMP + +/* Define if you have the psignal function. */ +#undef HAVE_PSIGNAL + +/* Define if you have the setegid function. */ +#undef HAVE_SETEGID + +/* Define if you have the seteuid function. */ +#undef HAVE_SETEUID + +/* Define if you have the setlinebuf function. */ +#undef HAVE_SETLINEBUF + +/* Define if you have the setregid function. */ +#undef HAVE_SETREGID + +/* Define if you have the setreuid function. */ +#undef HAVE_SETREUID + +/* Define if you have the sigsetmask function. */ +#undef HAVE_SIGSETMASK + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR +#define HAVE_STRERROR + +/* Define if you have the strsignal function. */ +#undef HAVE_STRSIGNAL + +/* Define if you have the wait3 function. */ +#undef HAVE_WAIT3 + +/* Define if you have the waitpid function. */ +#undef HAVE_WAITPID + +/* Define if you have the header file. */ +#undef HAVE_DIRENT_H +#define HAVE_DIRENT_H + +/* Define if you have the header file. */ +#undef HAVE_FCNTL_H +#define HAVE_FCNTL_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H +#define HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_MACH_MACH_H + +/* Define if you have the header file. */ +#undef HAVE_MEMORY_H +#define HAVE_MEMORY_H + +/* Define if you have the header file. */ +#undef HAVE_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H +#define HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_DIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIMEB_H +#define HAVE_SYS_TIMEB_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_WAIT_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the dgc library (-ldgc). */ +#undef HAVE_LIBDGC + +/* Define if you have the sun library (-lsun). */ +#undef HAVE_LIBSUN diff --git a/config.h.WIN32 b/config.h.WIN32 new file mode 100644 index 00000000..5188b1fe --- /dev/null +++ b/config.h.WIN32 @@ -0,0 +1,289 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +#undef _ALL_SOURCE +#endif + +/* Define if using alloca.c. */ +#undef C_ALLOCA + +/* Define to empty if the keyword does not work. */ +#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 + +/* Define for DGUX with . */ +#undef DGUX + +/* Define if the `getloadavg' function needs to be run setuid or setgid. */ +#undef GETLOADAVG_PRIVILEGED + +/* Define to `int' if doesn't define. */ +#undef gid_t +#define gid_t int + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA +#define HAVE_ALLOCA + +/* Define if you have and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if your system has its own `getloadavg' function. */ +#undef HAVE_GETLOADAVG + +/* Define if you have the getmntent function. */ +#undef HAVE_GETMNTENT + +/* Define if the `long double' type works. */ +#undef HAVE_LONG_DOUBLE + +/* Define if you support file names longer than 14 characters. */ +#undef HAVE_LONG_FILE_NAMES +#define HAVE_LONG_FILE_NAMES + +/* Define if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define if system calls automatically restart after interruption + by a signal. */ +#undef HAVE_RESTARTABLE_SYSCALLS + +/* Define if your struct stat has st_blksize. */ +#undef HAVE_ST_BLKSIZE + +/* Define if your struct stat has st_blocks. */ +#undef HAVE_ST_BLOCKS + +/* Define if you have the strcoll function and it is properly defined. */ +#undef HAVE_STRCOLL +#define HAVE_STRCOLL + +/* Define if your struct stat has st_rdev. */ +#undef HAVE_ST_RDEV +#define HAVE_ST_RDEV + +/* Define if you have the strftime function. */ +#undef HAVE_STRFTIME +#define HAVE_STRFTIME + +/* Define if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define if your struct tm has tm_zone. */ +#undef HAVE_TM_ZONE + +/* Define if you don't have tm_zone but do have the external array + tzname. */ +#undef HAVE_TZNAME +#define HAVE_TZNAME + +/* Define if you have . */ +#undef HAVE_UNISTD_H + +/* Define if utime(file, NULL) sets file's timestamp to the present. */ +#undef HAVE_UTIME_NULL +#define HAVE_UTIME_NULL + +/* Define if you have . */ +#undef HAVE_VFORK_H + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF +#define HAVE_VPRINTF + +/* Define if you have the wait3 system call. */ +#undef HAVE_WAIT3 + +/* Define if on MINIX. */ +#undef _MINIX + +/* Define if your struct nlist has an n_un member. */ +#undef NLIST_NAME_UNION + +/* Define if you have . */ +#undef NLIST_STRUCT + +/* Define if your C compiler doesn't accept -c and -o together. */ +#undef NO_MINUS_C_MINUS_O + +/* Define to `int' if doesn't define. */ +#undef pid_t +#define pid_t int + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +#undef _POSIX_1_SOURCE + +/* Define if you need to in order for stat and other things to work. */ +#undef _POSIX_SOURCE +#define _POSIX_SOURCE + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE +#define RETSIGTYPE void + +/* 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 + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#undef STACK_DIRECTION + +/* Define if the `S_IS*' macros in do not work properly. */ +#undef STAT_MACROS_BROKEN + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS +#define STDC_HEADERS + +/* Define on System V Release 4. */ +#undef SVR4 + +/* Define if `sys_siglist' is declared by . */ +#undef SYS_SIGLIST_DECLARED + +/* Define to `int' if doesn't define. */ +#undef uid_t +#define uid_t int + +/* Define for Encore UMAX. */ +#undef UMAX + +/* Define for Encore UMAX 4.3 that has + instead of . */ +#undef UMAX4_3 + +/* Define vfork as fork if vfork does not work. */ +#undef vfork + +/* Define to the name of the SCCS `get' command. */ +#undef SCCS_GET +#define SCCS_GET "echo no sccs get" + +/* Define this if the SCCS `get' command understands the `-G' option. */ +#undef SCCS_GET_MINUS_G + +/* Define this if the C library defines the variable `sys_siglist'. */ +#undef HAVE_SYS_SIGLIST + +/* Define this if the C library defines the variable `_sys_siglist'. */ +#undef HAVE__SYS_SIGLIST + +/* Define this if you have the `union wait' type in . */ +#undef HAVE_UNION_WAIT + +/* Define if you have the dup2 function. */ +#undef HAVE_DUP2 +#define HAVE_DUP2 + +/* Define if you have the getcwd function. */ +#undef HAVE_GETCWD +#define HAVE_GETCWD + +/* Define if you have the getgroups function. */ +#undef HAVE_GETGROUPS + +/* Define if you have the mktemp function. */ +#undef HAVE_MKTEMP +#define HAVE_MKTEMP + +/* Define if you have the psignal function. */ +#undef HAVE_PSIGNAL + +/* Define if you have the setegid function. */ +#undef HAVE_SETEGID + +/* Define if you have the seteuid function. */ +#undef HAVE_SETEUID + +/* Define if you have the setlinebuf function. */ +#undef HAVE_SETLINEBUF + +/* Define if you have the setregid function. */ +#undef HAVE_SETREGID + +/* Define if you have the setreuid function. */ +#undef HAVE_SETREUID + +/* Define if you have the sigsetmask function. */ +#undef HAVE_SIGSETMASK + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR +#define HAVE_STRERROR + +/* Define if you have the strsignal function. */ +#undef HAVE_STRSIGNAL + +/* Define if you have the wait3 function. */ +#undef HAVE_WAIT3 + +/* Define if you have the waitpid function. */ +#undef HAVE_WAITPID + +/* Define if you have the header file. */ +#undef HAVE_DIRENT_H +#define HAVE_DIRENT_H + +/* Define if you have the header file. */ +#undef HAVE_FCNTL_H +#define HAVE_FCNTL_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H +#define HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_MACH_MACH_H + +/* Define if you have the header file. */ +#undef HAVE_MEMORY_H +#define HAVE_MEMORY_H + +/* Define if you have the header file. */ +#undef HAVE_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H +#define HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_DIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIMEB_H +#define HAVE_SYS_TIMEB_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_WAIT_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the dgc library (-ldgc). */ +#undef HAVE_LIBDGC + +/* Define if you have the sun library (-lsun). */ +#undef HAVE_LIBSUN diff --git a/dir.c b/dir.c index 84a9a42a..d9977621 100644 --- a/dir.c +++ b/dir.c @@ -44,7 +44,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define NAMLEN(d) _D_NAMLEN(d) #endif -#if defined (POSIX) && !defined (__GNU_LIBRARY__) +#if (defined (POSIX) || defined (WIN32)) && !defined (__GNU_LIBRARY__) /* Posix does not require that the d_ino field be present, and some systems do not provide it. */ #define REAL_DIR_ENTRY(dp) 1 @@ -97,6 +97,10 @@ dosify (filename) } #endif /* __MSDOS__ */ +#ifdef WIN32 +#include "pathstuff.h" +#endif + #ifdef _AMIGA #include @@ -193,11 +197,24 @@ struct directory_contents struct directory_contents *next; dev_t dev; /* Device and inode numbers of this dir. */ +#ifdef WIN32 + /* + * Inode means nothing on WIN32. Even file key information is + * unreliable because it is random per file open and undefined + * for remote filesystems. The most unique attribute I can + * come up with is the fully qualified name of the directory. Beware + * though, this is also unreliable. I'm open to suggestion on a better + * way to emulate inode. + */ + char *path_key; + int mtime; /* controls check for stale directory cache */ +#else #ifdef VMS ino_t ino[3]; #else ino_t ino; #endif +#endif /* WIN32 */ struct dirfile **files; /* Files in this directory. */ DIR *dirstream; /* Stream reading this directory. */ }; @@ -253,6 +270,9 @@ find_directory (name) register unsigned int hash = 0; register char *p; register struct directory *dir; +#ifdef WIN32 + char* w32_path; +#endif #ifdef VMS if ((*name == '.') && (*(name+1) == 0)) name = "[]"; @@ -298,6 +318,10 @@ find_directory (name) struct directory_contents *dc; +#ifdef WIN32 + w32_path = w32ify(name, 1); + hash = ((unsigned int) st.st_dev << 16) | (unsigned int) st.st_ctime; +#else #ifdef VMS hash = ((unsigned int) st.st_dev << 16) | ((unsigned int) st.st_ino[0] @@ -305,10 +329,14 @@ find_directory (name) + (unsigned int) st.st_ino[2]); #else hash = ((unsigned int) st.st_dev << 16) | (unsigned int) st.st_ino; +#endif #endif hash %= DIRECTORY_BUCKETS; for (dc = directories_contents[hash]; dc != 0; dc = dc->next) +#ifdef WIN32 + if (!strcmp(dc->path_key, w32_path)) +#else if (dc->dev == st.st_dev #ifdef VMS && dc->ino[0] == st.st_ino[0] @@ -317,6 +345,7 @@ find_directory (name) #else && dc->ino == st.st_ino) #endif +#endif /* WIN32 */ break; if (dc == 0) @@ -328,6 +357,10 @@ find_directory (name) /* Enter it in the contents hash table. */ dc->dev = st.st_dev; +#ifdef WIN32 + dc->path_key = strdup(w32_path); + dc->mtime = st.st_mtime; +#else #ifdef VMS dc->ino[0] = st.st_ino[0]; dc->ino[1] = st.st_ino[1]; @@ -335,6 +368,7 @@ find_directory (name) #else dc->ino = st.st_ino; #endif +#endif /* WIN32 */ dc->next = directories_contents[hash]; directories_contents[hash] = dc; @@ -382,6 +416,10 @@ dir_contents_file_exists_p (dir, filename) register char *p; register struct dirfile *df; register struct dirent *d; +#ifdef WIN32 + struct stat st; + int rehash = 0; +#endif if (dir == 0 || dir->files == 0) { @@ -429,6 +467,24 @@ dir_contents_file_exists_p (dir, filename) if (dir->dirstream == 0) { +#ifdef WIN32 + /* Check to see if directory has changed since last read */ + if (dir->path_key && + stat(dir->path_key, &st) == 0 && + st.st_mtime > dir->mtime) { + + /* reset date stamp to show most recent re-process */ + dir->mtime = st.st_mtime; + + /* make sure directory can still be opened */ + dir->dirstream = opendir(dir->path_key); + + if (dir->dirstream) + rehash = 1; + else + return 0; /* couldn't re-read - fail */ + } else +#endif /* The directory has been all read in. */ return 0; } @@ -447,12 +503,33 @@ dir_contents_file_exists_p (dir, filename) for (i = 0; i < len; ++i) HASHI (newhash, d->d_name[i]); newhash %= DIRFILE_BUCKETS; +#ifdef WIN32 + /* + * If re-reading a directory, check that this file isn't already + * in the cache. + */ + if (rehash) { + for (df = dir->files[newhash]; df != 0; df = df->next) + if (streq(df->name, d->d_name)) + break; + } else + df = 0; + + /* + * If re-reading a directory, don't cache files that have + * already been discovered. + */ + if (!df) { +#endif df = (struct dirfile *) xmalloc (sizeof (struct dirfile)); df->next = dir->files[newhash]; dir->files[newhash] = df; df->name = savestring (d->d_name, len); df->impossible = 0; +#ifdef WIN32 + } +#endif /* Check if the name matches the one we're searching for. */ if (filename != 0 && newhash == hash && strieq (d->d_name, filename)) @@ -506,6 +583,10 @@ file_exists_p (name) return dir_file_exists_p ("[]", name); #else /* !VMS */ dirend = rindex (name, '/'); +#ifdef WIN32 + if (!dirend) + dirend = rindex(name, '\\'); +#endif /* WIN32 */ if (dirend == 0) return dir_file_exists_p (".", name); if (dirend == 0) @@ -569,6 +650,10 @@ file_impossible (filename) structure for it, but leave it out of the contents hash table. */ dir->contents = (struct directory_contents *) xmalloc (sizeof (struct directory_contents)); +#ifdef WIN32 + dir->contents->path_key = NULL; + dir->contents->mtime = 0; +#else /* WIN32 */ #ifdef VMS dir->contents->dev = 0; dir->contents->ino[0] = dir->contents->ino[1] = @@ -576,6 +661,7 @@ file_impossible (filename) #else dir->contents->dev = dir->contents->ino = 0; #endif +#endif /* WIN32 */ dir->contents->files = 0; dir->contents->dirstream = 0; } @@ -616,6 +702,10 @@ file_impossible_p (filename) dir = find_directory ("[]")->contents; #else dirend = rindex (filename, '/'); +#ifdef WIN32 + if (!dirend) + dirend = rindex (filename, '\\'); +#endif /* WIN32 */ if (dirend == 0) #ifdef _AMIGA dir = find_directory ("")->contents; @@ -685,6 +775,10 @@ print_dir_data_base () if (dir->contents == 0) printf ("# %s: could not be stat'd.\n", dir->name); else if (dir->contents->files == 0) +#ifdef WIN32 + printf ("# %s (key %s, mtime %d): could not be opened.\n", + dir->name, dir->contents->path_key,dir->contents->mtime); +#else /* WIN32 */ #ifdef VMS printf ("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n", dir->name, dir->contents->dev, @@ -694,6 +788,7 @@ print_dir_data_base () printf ("# %s (device %d, inode %d): could not be opened.\n", dir->name, dir->contents->dev, dir->contents->ino); #endif +#endif /* WIN32 */ else { register unsigned int f = 0, im = 0; @@ -705,6 +800,10 @@ print_dir_data_base () ++im; else ++f; +#ifdef WIN32 + printf ("# %s (key %s, mtime %d): ", + dir->name, dir->contents->path_key, dir->contents->mtime); +#else /* WIN32 */ #ifdef VMS printf ("# %s (device %d, inode [%d,%d,%d]): ", dir->name, dir->contents->dev, @@ -714,6 +813,7 @@ print_dir_data_base () printf ("# %s (device %d, inode %d): ", dir->name, dir->contents->dev, dir->contents->ino); #endif +#endif /* WIN32 */ if (f == 0) fputs ("No", stdout); else diff --git a/function.c b/function.c index 73e34a96..6771fa84 100644 --- a/function.c +++ b/function.c @@ -30,6 +30,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef _AMIGA #include "amiga.h" #endif +#ifdef WIN32 +#include +#include +#include "sub_proc.h" +#endif static char *string_glob PARAMS ((char *line)); @@ -345,6 +350,14 @@ expand_function (o, function, text, end) #ifndef VMS /* not supported for vms yet */ case function_shell: { +#ifdef WIN32 + SECURITY_ATTRIBUTES saAttr; + HANDLE hIn; + HANDLE hErr; + HANDLE hChildOutRd; + HANDLE hChildOutWr; + HANDLE hProcess; +#endif char **argv; char *error_prefix; #ifndef _AMIGA @@ -387,7 +400,58 @@ expand_function (o, function, text, end) else error_prefix = ""; -#if !defined(__MSDOS__) && !defined(_AMIGA) +#if !defined(__MSDOS__) && !defined(_AMIGA) +# ifdef WIN32 + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + if (DuplicateHandle(GetCurrentProcess(), + GetStdHandle(STD_INPUT_HANDLE), + GetCurrentProcess(), + &hIn, + 0, + TRUE, + DUPLICATE_SAME_ACCESS) == FALSE) { + fatal("create_child_process: DuplicateHandle(In) failed (e=%d)\n", + GetLastError()); + } + if (DuplicateHandle(GetCurrentProcess(), + GetStdHandle(STD_ERROR_HANDLE), + GetCurrentProcess(), + &hErr, + 0, + TRUE, + DUPLICATE_SAME_ACCESS) == FALSE) { + fatal("create_child_process: DuplicateHandle(Err) failed (e=%d)\n", + GetLastError()); + } + + if (!CreatePipe(&hChildOutRd, &hChildOutWr, &saAttr, 0)) + fatal("CreatePipe() failed (e=%d)\n", GetLastError()); + + hProcess = process_init_fd(hIn, hChildOutWr, hErr); + + if (!hProcess) + fatal("expand_function: process_init_fd() failed\n"); + else + process_register(hProcess); + + /* make sure that CreateProcess() has Path it needs */ + sync_Path_environment(); + + if (!process_begin(hProcess, argv, envp, argv[0], NULL)) + pid = (int) hProcess; + else + fatal("expand_function: unable to launch process (e=%d)\n", + process_last_err(hProcess)); + + /* set up to read data from child */ + pipedes[0] = _open_osfhandle((long) hChildOutRd, O_RDONLY); + + /* this will be closed almost right away */ + pipedes[1] = _open_osfhandle((long) hChildOutWr, O_APPEND); +# else /* WIN32 */ if (pipe (pipedes) < 0) { perror_with_name (error_prefix, "pipe"); @@ -400,6 +464,7 @@ expand_function (o, function, text, end) else if (pid == 0) child_execute_job (0, pipedes[1], argv, envp); else +# endif /* WIN32 */ { /* We are the parent. */ diff --git a/job.c b/job.c index b2cc86f7..cc098108 100644 --- a/job.c +++ b/job.c @@ -25,12 +25,17 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include /* Default shell to use. */ +#ifdef WIN32 +char *default_shell = "sh.exe"; +int no_default_sh_exe = 1; +#else /* WIN32 */ #ifndef _AMIGA char default_shell[] = "/bin/sh"; #else char default_shell[] = ""; extern int MyExecute (char **); #endif +#endif /* WIN32 */ #ifdef __MSDOS__ #include @@ -40,6 +45,7 @@ static char *dos_bname; static char *dos_bename; static int dos_batch_file; #endif /* MSDOS. */ + #ifdef _AMIGA #include static int amiga_pid = 123; @@ -55,6 +61,20 @@ static int amiga_batch_file; #include #endif +#ifdef WIN32 +#include +#include +#include +#include "sub_proc.h" +#include "w32err.h" +#include "pathstuff.h" + +/* this stuff used if no sh.exe is around */ +static char *dos_bname; +static char *dos_bename; +static int dos_batch_file; +#endif /* WIN32 */ + #ifdef HAVE_FCNTL_H #include #else @@ -172,6 +192,16 @@ static int good_stdin_used = 0; static struct child *waiting_jobs = 0; +#ifdef WIN32 +/* + * The macro which references this function is defined in make.h. + */ +int w32_kill(int pid, int sig) +{ + return ((process_kill(pid, sig) == TRUE) ? 0 : -1); +} +#endif /* WIN32 */ + /* Write an error message describing the exit status given in EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME. Append "(ignored)" if IGNORED is nonzero. */ @@ -312,7 +342,7 @@ reap_children (block, err) } else if (pid == 0) { -#if !defined(__MSDOS__) && !defined(_AMIGA) +#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WIN32) /* No remote children. Check for local children. */ if (any_local) @@ -366,7 +396,7 @@ reap_children (block, err) exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0; coredump = WCOREDUMP (status); } -#else /* MSDOS. */ +#else /* MSDOS, Amiga, WIN32. */ #ifdef __MSDOS__ /* Life is very different on MSDOS. */ pid = dos_pid - 1; @@ -374,14 +404,49 @@ reap_children (block, err) exit_code = dos_status; exit_sig = 0; coredump = 0; -#else +#endif /* __MSDOS__ */ +#ifdef _AMIGA /* Same on Amiga */ pid = amiga_pid - 1; status = amiga_status; exit_code = amiga_status; exit_sig = 0; coredump = 0; -#endif +#endif /* _AMIGA */ +#ifdef WIN32 + { + HANDLE hPID; + int err; + + /* wait for anything to finish */ + if (hPID = process_wait_for_any()) { + + /* was an error found on this process? */ + err = process_last_err(hPID); + + /* get exit data */ + exit_code = process_exit_code(hPID); + + if (err) + fprintf(stderr, "make (e=%d): %s", + exit_code, map_win32_error_to_string(exit_code)); + + exit_sig = process_signal(hPID); + + /* cleanup process */ + process_cleanup(hPID); + + if (dos_batch_file) { + remove (dos_bname); + remove (dos_bename); + dos_batch_file = 0; + } + + coredump = 0; + } + pid = (int) hPID; + } +#endif /* WIN32 */ #endif /* Not MSDOS. */ } else @@ -715,6 +780,7 @@ start_job_command (child) fflush (stdout); fflush (stderr); +#ifndef WIN32 #ifndef _AMIGA #ifndef VMS @@ -745,6 +811,7 @@ start_job_command (child) } #endif /* !AMIGA */ +#endif /* !WIN32 */ /* Decide whether to give this child the `good' standard input (one that points to the terminal or whatever), or the `bad' one @@ -764,7 +831,7 @@ start_job_command (child) child->environment = target_environment (child->file); #endif -#if !defined(__MSDOS__) && !defined(_AMIGA) +#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WIN32) #ifndef VMS /* start_waiting_job has set CHILD->remote if we can start a remote job. */ @@ -848,7 +915,8 @@ start_job_command (child) dos_status = 0; remove (dos_bename); } -#else +#endif /* __MSDOS__ */ +#ifdef _AMIGA amiga_status = MyExecute (argv); ++dead_children; @@ -859,6 +927,37 @@ start_job_command (child) DeleteFile (amiga_bname); /* Ignore errors. */ } #endif /* Not Amiga */ +#ifdef WIN32 + { + HANDLE hPID; + char* arg0; + + /* make UNC paths safe for CreateProcess -- backslash format */ + arg0 = argv[0]; + if (arg0 && arg0[0] == '/' && arg0[1] == '/') + for ( ; arg0 && *arg0; arg0++) + if (*arg0 == '/') + *arg0 = '\\'; + + /* make sure CreateProcess() has Path it needs */ + sync_Path_environment(); + + hPID = process_easy(argv, child->environment); + + if (hPID != INVALID_HANDLE_VALUE) + child->pid = (int) hPID; + else { + int i; + unblock_sigs(); + fprintf(stderr, + "process_easy() failed failed to launch process (e=%d)\n", + process_last_err(hPID)); + for (i = 0; argv[i]; i++) + fprintf(stderr, "%s ", argv[i]); + fprintf(stderr, "\nCounted %d args in failed launch\n", i); + } + } +#endif /* WIN32 */ #endif /* Not MSDOS. */ /* We are the parent side. Set the state to @@ -1177,6 +1276,7 @@ start_waiting_jobs () return; } +#ifndef WIN32 #ifdef VMS #include #include @@ -1414,6 +1514,7 @@ child_execute_job (stdin_fd, stdout_fd, argv, envp) } #endif /* !AMIGA */ #endif /* !VMS */ +#endif /* !WIN32 */ #ifndef _AMIGA /* Replace the current process with one running the command in ARGV, @@ -1532,12 +1633,30 @@ construct_command_argv_internal (line, restp, shell, ifs) "unset", "unsetenv", "version", 0 }; #else +#ifdef WIN32 + static char sh_chars_dos[] = "\"|<>"; + static char *sh_cmds_dos[] = { "break", "call", "cd", "chcp", "chdir", "cls", + "copy", "ctty", "date", "del", "dir", "echo", + "erase", "exit", "for", "goto", "if", "if", "md", + "mkdir", "path", "pause", "prompt", "rem", "ren", + "rename", "set", "shift", "time", "type", + "ver", "verify", "vol", ":", 0 }; + static char sh_chars_sh[] = "#;\"*?[]&|<>(){}$`^"; + static char *sh_cmds_sh[] = { "cd", "eval", "exec", "exit", "login", + "logout", "set", "umask", "wait", "while", "for", + "case", "if", ":", ".", "break", "continue", + "export", "read", "readonly", "shift", "times", + "trap", "switch", "test", 0 }; + char* sh_chars; + char** sh_cmds; +#else /* WIN32 */ static char sh_chars[] = "#;\"*?[]&|<>(){}$`^"; static char *sh_cmds[] = { "cd", "eval", "exec", "exit", "login", "logout", "set", "umask", "wait", "while", "for", "case", "if", ":", ".", "break", "continue", "export", "read", "readonly", "shift", "times", "trap", "switch", 0 }; +#endif /* WIN32 */ #endif register int i; register char *p; @@ -1545,6 +1664,17 @@ construct_command_argv_internal (line, restp, shell, ifs) char *end; int instring, word_has_equals, seen_nonequals; char **new_argv = 0; +#ifdef WIN32 + int slow_flag = 0; + + if (no_default_sh_exe) { + sh_cmds = sh_cmds_dos; + sh_chars = sh_chars_dos; + } else { + sh_cmds = sh_cmds_sh; + sh_chars = sh_chars_sh; + } +#endif if (restp != NULL) *restp = NULL; @@ -1559,6 +1689,20 @@ construct_command_argv_internal (line, restp, shell, ifs) if (shell == 0) shell = default_shell; else if (strcmp (shell, default_shell)) +#ifdef WIN32 + { + char *s1 = _fullpath(NULL, shell, 0); + char *s2 = _fullpath(NULL, default_shell, 0); + + slow_flag = strcmp((s1 ? s1 : ""), (s2 ? s2 : "")); + + if (s1); + free(s1); + if (s2); + free(s2); + } + if (slow_flag) +#endif /* WIN32 */ goto slow; if (ifs != 0) @@ -1750,8 +1894,31 @@ construct_command_argv_internal (line, restp, shell, ifs) free (new_argv[0]); free ((void *)new_argv); } +#ifdef WIN32 + /* + * Not eating this whitespace caused things like + * + * sh -c "\n" + * + * which gave the shell fits. I think we have to eat + * whitespace here, but this code should be considered + * suspicious if things start failing.... + */ -#ifdef __MSDOS__ + /* Make sure not to bother processing an empty line. */ + while (isspace (*line)) + ++line; + if (*line == '\0') + return 0; +#endif + +#if defined(__MSDOS__) || defined(WIN32) +#ifdef WIN32 + /* + * only come here if no sh.exe command + */ + if (no_default_sh_exe) +#endif { FILE *batch; dos_batch_file = 1; @@ -1807,6 +1974,13 @@ construct_command_argv_internal (line, restp, shell, ifs) new_argv[1] = 0; } #else /* Not MSDOS or Amiga */ +#ifdef WIN32 + /* + * This is technically an else to the above 'if (no_default_sh_exe)', + * but (IMHO) coding if-else across ifdef is dangerous. + */ + if (!no_default_sh_exe) +#endif { /* SHELL may be a multi-word command. Construct a command line "SHELL -c LINE", with all special chars in LINE escaped. @@ -1896,6 +2070,16 @@ construct_command_argv (line, restp, file) warn_undefined_variables_flag = 0; shell = allocated_variable_expand_for_file ("$(SHELL)", file); +#ifdef WIN32 + /* + * Convert to forward slashes so that construct_command_argv_internal() + * is not confused. + */ + if (shell) { + char *p = w32ify(shell, 0); + strcpy(shell, p); + } +#endif ifs = allocated_variable_expand_for_file ("$(IFS)", file); warn_undefined_variables_flag = save; diff --git a/main.c b/main.c index c3f8089c..9cb5a83e 100644 --- a/main.c +++ b/main.c @@ -28,6 +28,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ # include # include #endif +#ifdef WIN32 +#include +#include "pathstuff.h" +#endif #ifdef _AMIGA int __stack = 20000; /* Make sure we have 20K of stack space */ @@ -123,6 +127,12 @@ int just_print_flag; int debug_flag = 0; +#ifdef WIN32 +/* Suspend make in main for a short time to allow debugger to attach */ + +int suspend_flag = 0; +#endif + /* Environment variables override makefile definitions. */ int env_overrides = 0; @@ -228,6 +238,11 @@ static const struct command_switch switches[] = { 'd', flag, (char *) &debug_flag, 1, 1, 0, 0, 0, "debug", 0, "Print lots of debugging information" }, +#ifdef WIN32 + { 'D', flag, (char *) &suspend_flag, 1, 1, 0, 0, 0, + "suspend-for-debug", 0, + "Suspend process to allow a debugger to attach" }, +#endif { 'e', flag, (char *) &env_overrides, 1, 1, 0, 0, 0, "environment-overrides", 0, "Environment variables override makefiles" }, @@ -448,6 +463,11 @@ int main (int argc, char ** argv) char **p; struct dep *read_makefiles; PATH_VAR (current_directory); +#ifdef WIN32 + extern int no_default_sh_exe; + char *unix_path = NULL; + char *win32_path = NULL; +#endif default_goal_file = 0; reading_filename = 0; @@ -539,7 +559,11 @@ int main (int argc, char ** argv) /* Figure out where we are. */ +#ifdef WIN32 + if (getcwd_fs (current_directory, GET_PATH_MAX) == 0) +#else if (getcwd (current_directory, GET_PATH_MAX) == 0) +#endif { #ifdef HAVE_GETCWD perror_with_name ("getcwd: ", ""); @@ -563,6 +587,12 @@ int main (int argc, char ** argv) register char *ep = envp[i]; while (*ep != '=') ++ep; +#ifdef WIN32 + if (!strncmp(ep, "PATH", 4)) + unix_path = &ep[5]; + if (!strncmp(ep, "Path", 4)) + win32_path = &ep[5]; +#endif /* The result of pointer arithmetic is cast to unsigned int for machines where ptrdiff_t is a different size that doesn't widen the same. */ @@ -575,6 +605,13 @@ int main (int argc, char ** argv) be exported, because it was originally in the environment. */ ->export = v_export; } +#ifdef WIN32 + /* + * PATH defaults to Path iff PATH not found and Path is found. + */ + if (!unix_path && win32_path) + define_variable("PATH", 4, win32_path, o_env, 1)->export = v_export; +#endif #else /* For Amiga, read the ENV: device, ignoring all dirs */ { BPTR env, file, old; @@ -616,6 +653,14 @@ int main (int argc, char ** argv) decode_env_switches ("MFLAGS", 6); #endif decode_switches (argc, argv, 0); +#ifdef WIN32 + if (suspend_flag) { + fprintf(stderr, "%s (pid = %d)\n", argv[0], GetCurrentProcessId()); + fprintf(stderr, "%s is suspending for 30 seconds...", argv[0]); + Sleep(30 * 1000); + fprintf(stderr, "done sleep(30). Continuing.\n"); + } +#endif /* Print version information. */ @@ -632,10 +677,22 @@ int main (int argc, char ** argv) so the result will run the same program regardless of the current dir. If it is a name with no slash, we can only hope that PATH did not find it in the current directory.) */ - +#ifdef WIN32 + /* + * Convert from backslashes to forward slashes for + * programs like sh which don't like them. Shouldn't + * matter if the path is one way or the other for + * CreateProcess(). + */ + if (strpbrk(argv[0], "/:\\") || + strstr(argv[0], "..") || + !strncmp(argv[0], "//", 2)) + argv[0] = strdup(w32ify(argv[0],1)); +#else /* WIN32 */ if (current_directory[0] != '\0' && argv[0] != 0 && argv[0][0] != '/' && index (argv[0], '/') != 0) argv[0] = concat (current_directory, "/", argv[0]); +#endif /* WIN32 */ #endif /* The extra indirection through $(MAKE_COMMAND) is done @@ -708,6 +765,79 @@ int main (int argc, char ** argv) free (dir); } +#ifdef WIN32 + /* + * THIS BLOCK OF CODE MUST COME AFTER chdir() CALL ABOVE IN ORDER + * TO NOT CONFUSE THE DEPENDENCY CHECKING CODE IN implicit.c. + * + * The functions in dir.c can incorrectly cache information for "." + * before we have changed directory and this can cause file + * lookups to fail because the current directory (.) was pointing + * at the wrong place when it was first evaluated. + */ + + /* + * On Windows/NT, we don't have the luxury of a /bin directory that + * is mapped globally to every drive mounted to the system. Since make could + * be invoked from any drive, and we don't want to propogate /bin/sh + * to every single drive. Allow ourselves a chance to search for + * a value for default shell here (if the default path does not exist). + * + * The value of default_shell is set here, but it could get reset after + * the Makefiles are read in. See logic below where SHELL is checked + * after the call to read_all_makefiles() completes. + * + * The reason SHELL is set here is so that macros can be safely evaluated + * as makefiles are read in (some macros require $SHELL). + */ + + { + extern char *default_shell; + + if (!file_exists_p(default_shell)) { + char *p; + struct variable *v = lookup_variable ("Path", 4); + + /* + * Try and make sure we have a full path to default_shell before + * we parse makefiles. + */ + if (v && v->value) { + PATH_VAR(sh_path); + char *ep; + + p = v->value; + ep = strchr(p, PATH_SEPARATOR_CHAR); + + while (ep && *ep) { + *ep = '\0'; + + if (dir_file_exists_p(p, default_shell)) { + sprintf(sh_path, "%s/%s", p, default_shell); + default_shell = strdup(w32ify(sh_path,0)); + no_default_sh_exe = 0; + *ep = PATH_SEPARATOR_CHAR; + + /* terminate loop */ + p += strlen(p); + } else { + *ep = PATH_SEPARATOR_CHAR; + p = ++ep; + } + + ep = strchr(p, PATH_SEPARATOR_CHAR); + } + + /* be sure to check last element of Path */ + if (p && *p && dir_file_exists_p(p, default_shell)) { + sprintf(sh_path, "%s/%s", p, default_shell); + default_shell = strdup(w32ify(sh_path,0)); + no_default_sh_exe = 0; + } + } + } + } +#endif /* WIN32 */ /* Figure out the level of recursion. */ { struct variable *v = lookup_variable ("MAKELEVEL", 9); @@ -736,7 +866,11 @@ int main (int argc, char ** argv) starting_directory = current_directory; else { +#ifdef WIN32 + if (getcwd_fs (current_directory, GET_PATH_MAX) == 0) +#else if (getcwd (current_directory, GET_PATH_MAX) == 0) +#endif { #ifdef HAVE_GETCWD perror_with_name ("getcwd: ", ""); @@ -849,6 +983,53 @@ int main (int argc, char ** argv) define_makeflags (0, 0); +#ifdef WIN32 + /* + * Now that makefiles are parsed, see if a Makefile gave a + * value for SHELL and use that for default_shell instead if + * that filename exists. This should speed up the + * construct_argv_internal() function by avoiding unnecessary + * recursion. + */ + { + struct variable *v = lookup_variable("SHELL", 5); + extern char* default_shell; + + /* + * to change value: + * + * SHELL must be found, SHELL must be set, value of SHELL + * must be different from current value, and the + * specified file must exist. Whew! + */ + if (v != 0 && *v->value != '\0') { + char *fn = recursively_expand(v); + + if (fn && strcmp(fn, default_shell) && file_exists_p(fn)) { + char *p; + + default_shell = fn; + + /* if Makefile says SHELL is sh.exe, believe it */ + if (strstr(default_shell, "sh.exe")) + no_default_sh_exe = 0; + + /* + * Convert from backslashes to forward slashes so + * create_command_line_argv_internal() is not confused. + */ + for (p = strchr(default_shell, '\\'); p; p = strchr(default_shell, '\\')) + *p = '/'; + } + } + } + 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."); + job_slots = 1; + } +#endif /* WIN32 */ + /* Define the default variables. */ define_default_variables (); diff --git a/make.h b/make.h index dc88f2a3..43696531 100644 --- a/make.h +++ b/make.h @@ -286,11 +286,23 @@ extern char *alloca (); #define ENUM_BITFIELD(bits) #endif -#ifdef __MSDOS__ +#if defined(__MSDOS__) || defined(WIN32) #define PATH_SEPARATOR_CHAR ';' #else #define PATH_SEPARATOR_CHAR ':' #endif + +#ifdef WIN32 +#include +#include +#define pipe(p) _pipe(p, 512, O_BINARY) +#define kill(pid,sig) w32_kill(pid,sig) + +extern void sync_Path_environment(void); +extern int kill(int pid, int sig); +extern int safe_stat(char *file, struct stat *sb); +extern char *end_of_token_w32(); +#endif extern void die (); extern void message (); @@ -361,7 +373,7 @@ extern void child_access (); /* We omit these declarations on non-POSIX systems which define _POSIX_VERSION, because such systems often declare the in header files anyway. */ -#if !defined (__GNU_LIBRARY__) && !defined (POSIX) && !defined (_POSIX_VERSION) +#if !defined (__GNU_LIBRARY__) && !defined (POSIX) && !defined (_POSIX_VERSION) && !defined(WIN32) extern long int atol (); #ifndef VMS diff --git a/misc.c b/misc.c index 10fce3a9..b8ce6e9c 100644 --- a/misc.c +++ b/misc.c @@ -397,6 +397,37 @@ end_of_token (s) return s; } +#ifdef WIN32 +/* + * Same as end_of_token, but take into account a stop character + */ +char * +end_of_token_w32 (s, stopchar) + char *s; + char stopchar; +{ + register char *p = s; + register int backslash = 0; + + while (*p != '\0' && *p != stopchar && (backslash || !isblank (*p))) + { + if (*p++ == '\\') + { + backslash = !backslash; + while (*p == '\\') + { + backslash = !backslash; + ++p; + } + } + else + backslash = 0; + } + + return p; +} +#endif + /* Return the address of the first nonwhitespace or null in the string S. */ char * diff --git a/read.c b/read.c index 97af2caf..76681624 100644 --- a/read.c +++ b/read.c @@ -30,6 +30,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "glob/glob.h" #endif +#ifndef WIN32 #ifndef _AMIGA #ifndef VMS #include @@ -37,6 +38,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ struct passwd *getpwnam PARAMS ((char *name)); #endif #endif +#endif /* !WIN32 */ /* A `struct linebuffer' is a structure which holds a line of text. `readline' reads a line from a stream into a linebuffer @@ -79,6 +81,13 @@ static struct conditionals *conditionals = &toplevel_conditionals; static char *default_include_directories[] = { +#if defined(WIN32) && !defined(INCLUDEDIR) +/* + * This completly up to the user when they install MSVC or other packages. + * This is defined as a placeholder. + */ +#define INCLUDEDIR "." +#endif INCLUDEDIR, #ifndef _AMIGA "/usr/gnu/include", @@ -274,6 +283,9 @@ read_makefile (filename, flags) char *pattern = 0, *pattern_percent; int makefile_errno; +#ifdef WIN32 + int check_again; +#endif #define record_waiting_files() \ do \ @@ -772,6 +784,16 @@ read_makefile (filename, flags) */ if (p && !(isspace(p[1]) || !p[1] || isspace(p[-1]))) p = 0; +#endif +#ifdef WIN32 + do { + check_again = 0; + /* For WIN32, skip a "C:\..." or a "C:/..." */ + if (p != 0 && (p[1] == '\\' || p[1] == '/') && isalpha (p[-1])) { + p = index(p + 1, ':'); + check_again = 1; + } + } while (check_again); #endif if (p != 0) { @@ -1598,6 +1620,17 @@ parse_file_seq (stringp, stopchar, size, strip) { p = find_char_unquote (p+1, stopchars, 1); } +#endif +#ifdef WIN32 + /* For WIN32, skip a "C:\..." or "C:/...". */ + if (stopchar == ':' && + p != 0 && + (p[1] == '\\' || p[1] == '/') && + isalpha (p[-1])) { + p = end_of_token_w32(++p, ':'); + if (*p == '\0' && p[-1] == ':') + p--; + } #endif if (p == 0) p = q + strlen (q); @@ -1984,7 +2017,7 @@ tilde_expand (name) free (home_dir); home_dir = getenv ("HOME"); } -#ifndef _AMIGA +#if !defined(_AMIGA) && !defined(WIN32) if (home_dir == 0 || home_dir[0] == '\0') { extern char *getlogin (); @@ -1997,7 +2030,7 @@ tilde_expand (name) home_dir = p->pw_dir; } } -#endif /* !AMIGA */ +#endif /* !AMIGA && !WIN32 */ if (home_dir != 0) { char *new = concat (home_dir, "", name + 1); @@ -2006,7 +2039,7 @@ tilde_expand (name) return new; } } -#ifndef _AMIGA +#if !defined(_AMIGA) && !defined(WIN32) else { struct passwd *pwent; @@ -2024,7 +2057,7 @@ tilde_expand (name) else if (userend != 0) *userend = '/'; } -#endif /* !AMIGA */ +#endif /* !AMIGA && !WIN32 */ #endif /* !VMS */ return 0; } diff --git a/remake.c b/remake.c index 8eb6a5d7..33824afb 100644 --- a/remake.c +++ b/remake.c @@ -32,6 +32,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef VMS #include #endif +#ifdef WIN32 +#include +#endif extern int try_implicit_rule PARAMS ((struct file *file, unsigned int depth)); @@ -1103,6 +1106,13 @@ library_search (lib, mtime_ptr) #ifndef _AMIGA "/lib", "/usr/lib", +#endif +#if defined(WIN32) && !defined(LIBDIR) +/* + * This is completely up to the user at product install time. Just define + * a placeholder. + */ +#define LIBDIR "." #endif LIBDIR, /* Defined by configuration. */ 0 diff --git a/subproc.bat b/subproc.bat new file mode 100644 index 00000000..95d9d0db --- /dev/null +++ b/subproc.bat @@ -0,0 +1,3 @@ +cd w32\subproc +nmake /f %1 +cd ..\.. diff --git a/variable.c b/variable.c index 65b9cccc..3bdf65be 100644 --- a/variable.c +++ b/variable.c @@ -22,6 +22,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "job.h" #include "commands.h" #include "variable.h" +#ifdef WIN32 +#include "pathstuff.h" +#endif /* Hash table of all global variable definitions. */ @@ -351,7 +354,11 @@ merge_variable_set_lists (setlist0, setlist1) void define_automatic_variables () { +#ifdef WIN32 + extern char* default_shell; +#else extern char default_shell[]; +#endif register struct variable *v; char buf[200]; @@ -539,11 +546,25 @@ target_environment (file) && v->origin != o_env && v->origin != o_env_override) { char *value = recursively_expand (v); +#ifdef WIN32 + if (strcmp(v->name, "Path") == 0 || + strcmp(v->name, "PATH") == 0) + convert_Path_to_win32(value, ';'); +#endif result[nvariables++] = concat (v->name, "=", value); free (value); } else +#ifdef WIN32 + { + if (strcmp(v->name, "Path") == 0 || + strcmp(v->name, "PATH") == 0) + convert_Path_to_win32(v->value, ';'); + result[nvariables++] = concat (v->name, "=", v->value); + } +#else result[nvariables++] = concat (v->name, "=", v->value); +#endif } } result[nvariables] = (char *) xmalloc (100); @@ -862,3 +883,30 @@ print_file_variables (file) if (file->variables != 0) print_variable_set (file->variables->set, "# "); } + +#ifdef WIN32 +void +sync_Path_environment(void) +{ + char* path = allocated_variable_expand("$(Path)"); + static char* environ_path = NULL; + + if (!path) + return; + + /* + * If done this before, don't leak memory unnecessarily. + * Free the previous entry before allocating new one. + */ + if (environ_path) + free(environ_path); + + /* + * Create something WIN32 world can grok + */ + convert_Path_to_win32(path, ';'); + environ_path = concat("Path", "=", path); + putenv(environ_path); + free(path); +} +#endif diff --git a/vpath.c b/vpath.c index 57f2b7c5..bf13bc3a 100644 --- a/vpath.c +++ b/vpath.c @@ -19,6 +19,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "make.h" #include "filedef.h" #include "variable.h" +#ifdef WIN32 +#include "pathstuff.h" +#endif /* Structure used to represent a selective VPATH searchpath. */ @@ -170,6 +173,10 @@ construct_vpath_list (pattern, dirpath) return; } +#ifdef WIN32 + convert_vpath_to_win32(dirpath, ';'); +#endif + /* Figure out the maximum number of VPATH entries and put it in MAXELEM. We start with 2, one before the first colon and one nil, the list terminator and @@ -279,7 +286,12 @@ vpath_search (file, mtime_ptr) /* If there are no VPATH entries or FILENAME starts at the root, there is nothing we can do. */ - if (**file == '/' || (vpaths == 0 && general_vpath == 0)) + if (**file == '/' +#ifdef WIN32 + || **file == '\\' + || (*file)[1] == ':' +#endif + || (vpaths == 0 && general_vpath == 0)) return 0; for (v = vpaths; v != 0; v = v->next) @@ -331,6 +343,10 @@ selective_vpath_search (path, file, mtime_ptr) pointer to the name-within-directory and FLEN is its length. */ n = rindex (*file, '/'); +#ifdef WIN32 + if (!n) + n = rindex(*file,, '\\'); +#endif name_dplen = n != 0 ? n - *file : 0; filename = name_dplen > 0 ? n + 1 : *file; if (name_dplen > 0) diff --git a/w32/compat/dirent.c b/w32/compat/dirent.c new file mode 100644 index 00000000..f516eb96 --- /dev/null +++ b/w32/compat/dirent.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include +#include +#include "dirent.h" + + +DIR* +opendir(const char* pDirName) +{ + struct stat sb; + DIR* pDir; + char* pEndDirName; + int nBufferLen; + + /* sanity checks */ + if (!pDirName) { + errno = EINVAL; + return NULL; + } + if (stat(pDirName, &sb) != 0) { + errno = ENOENT; + return NULL; + } + if ((sb.st_mode & S_IFMT) != S_IFDIR) { + errno = ENOTDIR; + return NULL; + } + + /* allocate a DIR structure to return */ + pDir = (DIR *) malloc(sizeof (DIR)); + + if (!pDir) + return NULL; + + /* input directory name length */ + nBufferLen = strlen(pDirName); + + /* copy input directory name to DIR buffer */ + strcpy(pDir->dir_pDirectoryName, pDirName); + + /* point to end of the copied directory name */ + pEndDirName = &pDir->dir_pDirectoryName[nBufferLen - 1]; + + /* if directory name did not end in '/' or '\', add '/' */ + if ((*pEndDirName != '/') && (*pEndDirName != '\\')) { + pEndDirName++; + *pEndDirName = '/'; + } + + /* now append the wildcard character to the buffer */ + pEndDirName++; + *pEndDirName = '*'; + pEndDirName++; + *pEndDirName = '\0'; + + /* other values defaulted */ + pDir->dir_nNumFiles = 0; + pDir->dir_hDirHandle = INVALID_HANDLE_VALUE; + pDir->dir_ulCookie = __DIRENT_COOKIE; + + return pDir; +} + +void +closedir(DIR *pDir) +{ + /* got a valid pointer? */ + if (!pDir) { + errno = EINVAL; + return; + } + + /* sanity check that this is a DIR pointer */ + if (pDir->dir_ulCookie != __DIRENT_COOKIE) { + errno = EINVAL; + return; + } + + /* close the WIN32 directory handle */ + if (pDir->dir_hDirHandle != INVALID_HANDLE_VALUE) + FindClose(pDir->dir_hDirHandle); + + free(pDir); + + return; +} + +struct dirent * +readdir(DIR* pDir) +{ + WIN32_FIND_DATA wfdFindData; + + if (!pDir) { + errno = EINVAL; + return NULL; + } + + /* sanity check that this is a DIR pointer */ + if (pDir->dir_ulCookie != __DIRENT_COOKIE) { + errno = EINVAL; + return NULL; + } + + if (pDir->dir_nNumFiles == 0) { + pDir->dir_hDirHandle = FindFirstFile(pDir->dir_pDirectoryName, &wfdFindData); + if (pDir->dir_hDirHandle == INVALID_HANDLE_VALUE) + return NULL; + } else if (!FindNextFile(pDir->dir_hDirHandle, &wfdFindData)) + return NULL; + + /* bump count for next call to readdir() or telldir() */ + pDir->dir_nNumFiles++; + + /* fill in struct dirent values */ + pDir->dir_sdReturn.d_ino = -1; + strcpy(pDir->dir_sdReturn.d_name, wfdFindData.cFileName); + + return &pDir->dir_sdReturn; +} + +void +rewinddir(DIR* pDir) +{ + if (!pDir) { + errno = EINVAL; + return; + } + + /* sanity check that this is a DIR pointer */ + if (pDir->dir_ulCookie != __DIRENT_COOKIE) { + errno = EINVAL; + return; + } + + /* close the WIN32 directory handle */ + if (pDir->dir_hDirHandle != INVALID_HANDLE_VALUE) + if (!FindClose(pDir->dir_hDirHandle)) + errno = EBADF; + + /* reset members which control readdir() */ + pDir->dir_hDirHandle = INVALID_HANDLE_VALUE; + pDir->dir_nNumFiles = 0; + + return; +} + +int +telldir(DIR* pDir) +{ + if (!pDir) { + errno = EINVAL; + return -1; + } + + /* sanity check that this is a DIR pointer */ + if (pDir->dir_ulCookie != __DIRENT_COOKIE) { + errno = EINVAL; + return -1; + } + + /* return number of times readdir() called */ + return pDir->dir_nNumFiles; +} + +void +seekdir(DIR* pDir, long nPosition) +{ + if (!pDir) + return; + + /* sanity check that this is a DIR pointer */ + if (pDir->dir_ulCookie != __DIRENT_COOKIE) + return; + + /* go back to beginning of directory */ + rewinddir(pDir); + + /* loop until we have found position we care about */ + for (--nPosition; nPosition && readdir(pDir); nPosition--); + + /* flag invalid nPosition value */ + if (nPosition) + errno = EINVAL; + + return; +} diff --git a/w32/include/dirent.h b/w32/include/dirent.h new file mode 100644 index 00000000..6bb7fbdc --- /dev/null +++ b/w32/include/dirent.h @@ -0,0 +1,37 @@ +#ifndef _DIRENT_H +#define _DIRENT_H + +#include +#include +#include +#include + +#ifndef NAME_MAX +#define NAME_MAX 255 +#endif + +#define __DIRENT_COOKIE 0xfefeabab + + +struct dirent +{ + ino_t d_ino; /* unused - no equivalent on WIN32 */ + char d_name[NAME_MAX+1]; +}; + +typedef struct dir_struct { + ULONG dir_ulCookie; + HANDLE dir_hDirHandle; + DWORD dir_nNumFiles; + char dir_pDirectoryName[NAME_MAX+1]; + struct dirent dir_sdReturn; +} DIR; + +DIR *opendir(const char *); +struct dirent *readdir(DIR *); +void rewinddir(DIR *); +void closedir(DIR *); +int telldir(DIR *); +void seekdir(DIR *, long); + +#endif diff --git a/w32/include/pathstuff.h b/w32/include/pathstuff.h new file mode 100644 index 00000000..285ed04a --- /dev/null +++ b/w32/include/pathstuff.h @@ -0,0 +1,10 @@ +#ifndef _PATHSTUFF_H +#define _PATHSTUFF_H + +extern char * convert_Path_to_win32(char *Path, char to_delim); +extern char * w32ify(char *file, int resolve); +extern char * getcwd_fs(char *buf, int len); + +#define convert_vpath_to_win32(vpath, delim) convert_Path_to_win32(vpath, delim) + +#endif diff --git a/w32/include/sub_proc.h b/w32/include/sub_proc.h new file mode 100644 index 00000000..12e9cf37 --- /dev/null +++ b/w32/include/sub_proc.h @@ -0,0 +1,54 @@ +#ifndef SUB_PROC_H +#define SUB_PROC_H + +/* + * Component Name: + * + * $Date$ + * + * $Source$ + * + * $Revision$ + * + * Description: + * + * (C) COPYRIGHT TIVOLI Systems, Inc. 1991-1994 + * Unpublished Work + * All Rights Reserved + * Licensed Material - Property of TIVOLI Systems, Inc. + */ + +/* $Id$ */ + +#ifdef WIN32 + +#define EXTERN_DECL(entry, args) extern entry args +#define VOID_DECL void + +EXTERN_DECL(HANDLE process_init, (VOID_DECL)); +EXTERN_DECL(HANDLE process_init_fd, (HANDLE stdinh, HANDLE stdouth, + HANDLE stderrh)); +EXTERN_DECL(long process_begin, (HANDLE proc, char **argv, char **envp, + char *exec_path, char *as_user)); +EXTERN_DECL(long process_pipe_io, (HANDLE proc, char *stdin_data, + int stdin_data_len)); +EXTERN_DECL(long process_file_io, (HANDLE proc)); +EXTERN_DECL(void process_cleanup, (HANDLE proc)); +EXTERN_DECL(HANDLE process_wait_for_any, (VOID_DECL)); +EXTERN_DECL(void process_register, (HANDLE proc)); +EXTERN_DECL(HANDLE process_easy, (char** argv, char** env)); +EXTERN_DECL(BOOL process_kill, (HANDLE proc, int signal)); + +/* support routines */ +EXTERN_DECL(long process_errno, (HANDLE proc)); +EXTERN_DECL(long process_last_err, (HANDLE proc)); +EXTERN_DECL(long process_exit_code, (HANDLE proc)); +EXTERN_DECL(long process_signal, (HANDLE proc)); +EXTERN_DECL(char * process_outbuf, (HANDLE proc)); +EXTERN_DECL(char * process_errbuf, (HANDLE proc)); +EXTERN_DECL(int process_outcnt, (HANDLE proc)); +EXTERN_DECL(int process_errcnt, (HANDLE proc)); +EXTERN_DECL(void process_pipes, (HANDLE proc, int pipes[3])); + +#endif +#endif diff --git a/w32/include/w32err.h b/w32/include/w32err.h new file mode 100644 index 00000000..7e9df785 --- /dev/null +++ b/w32/include/w32err.h @@ -0,0 +1,10 @@ +#ifndef _W32ERR_H_ +#define _W32ERR_H_ + +#ifndef EXTERN_DECL +#define EXTERN_DECL(entry, args) entry args +#endif + +EXTERN_DECL(char * map_win32_error_to_string, (DWORD error)); + +#endif /* !_W32ERR_H */ diff --git a/w32/pathstuff.c b/w32/pathstuff.c new file mode 100644 index 00000000..e5011f85 --- /dev/null +++ b/w32/pathstuff.c @@ -0,0 +1,219 @@ +#include +#include +#include "make.h" + +/* + * Convert delimiter separated path to Canonical format. + */ +char * +convert_Path_to_win32(char *Path, char to_delim) +{ + char *etok; /* token separator for old Path */ + char *p; /* points to element of old Path */ + + /* is this a multi-element Path ? */ + for (p = Path, etok = strpbrk(p, ":;"); + etok; + etok = strpbrk(p, ":;")) + if ((etok - p) == 1) { + if (*(etok - 1) == ';' || + *(etok - 1) == ':') { + etok[-1] = to_delim; + etok[0] = to_delim; + p = ++etok; + continue; /* ignore empty bucket */ + } else if (etok = strpbrk(etok+1, ":;")) { + /* found one to count, handle drive letter */ + *etok = to_delim; + p = ++etok; + } else + /* all finished, force abort */ + p += strlen(p); + } else { + /* found another one, no drive letter */ + *etok = to_delim; + p = ++etok; + } + +#if 0 + /* convert to backward slashes */ + for (p = Path, p = strchr(p, '/'); p; p = strchr(p, '/')) + *p = '\\'; +#endif + return Path; +} + +/* + * Convert to forward slashes. Resolve to full pathname optionally + */ +char * +w32ify(char *filename, int resolve) +{ + static char w32_path[FILENAME_MAX]; + char *p; + + if (resolve) + _fullpath(w32_path, filename, sizeof (w32_path)); + else + strncpy(w32_path, filename, sizeof (w32_path)); + + for (p = w32_path; p && *p; p++) + if (*p == '\\') + *p = '/'; + + return w32_path; +} + +char * +getcwd_fs(char* buf, int len) +{ + char *p; + + if (p = getcwd(buf, len)) { + char *q = w32ify(buf, 0); + strncpy(buf, q, len); + } + + return p; +} + +#ifdef unused +/* + * Convert delimiter separated pathnames (e.g. PATH) or single file pathname + * (e.g. c:/foo, c:\bar) to NutC format. If we are handed a string that + * _NutPathToNutc() fails to convert, just return the path we were handed + * and assume the caller will know what to do with it (It was probably + * a mistake to try and convert it anyway due to some of the bizarre things + * that might look like pathnames in makefiles). + */ +char * +convert_path_to_nutc(char *path) +{ + int count; /* count of path elements */ + char *nutc_path; /* new NutC path */ + int nutc_path_len; /* length of buffer to allocate for new path */ + char *pathp; /* pointer to nutc_path used to build it */ + char *etok; /* token separator for old path */ + char *p; /* points to element of old path */ + char sep; /* what flavor of separator used in old path */ + char *rval; + + /* is this a multi-element path ? */ + for (p = path, etok = strpbrk(p, ":;"), count = 0; + etok; + etok = strpbrk(p, ":;")) + if ((etok - p) == 1) { + if (*(etok - 1) == ';' || + *(etok - 1) == ':') { + p = ++etok; + continue; /* ignore empty bucket */ + } else if (etok = strpbrk(etok+1, ":;")) + /* found one to count, handle drive letter */ + p = ++etok, count++; + else + /* all finished, force abort */ + p += strlen(p); + } else + /* found another one, no drive letter */ + p = ++etok, count++; + + if (count) { + count++; /* x1;x2;x3 <- need to count x3 */ + + /* + * Hazard a guess on how big the buffer needs to be. + * We have to convert things like c:/foo to /c=/foo. + */ + nutc_path_len = strlen(path) + (count*2) + 1; + nutc_path = xmalloc(nutc_path_len); + pathp = nutc_path; + *pathp = '\0'; + + /* + * Loop through PATH and convert one elemnt of the path at at + * a time. Single file pathnames will fail this and fall + * to the logic below loop. + */ + for (p = path, etok = strpbrk(p, ":;"); + etok; + etok = strpbrk(p, ":;")) { + + /* don't trip up on device specifiers or empty path slots */ + if ((etok - p) == 1) + if (*(etok - 1) == ';' || + *(etok - 1) == ':') { + p = ++etok; + continue; + } else if ((etok = strpbrk(etok+1, ":;")) == NULL) + break; /* thing found was a WIN32 pathname */ + + /* save separator */ + sep = *etok; + + /* terminate the current path element -- temporarily */ + *etok = '\0'; + +#ifdef __NUTC__ + /* convert to NutC format */ + if (_NutPathToNutc(p, pathp, 0) == FALSE) { + free(nutc_path); + rval = savestring(path, strlen(path)); + return rval; + } +#else + *pathp++ = '/'; + *pathp++ = p[0]; + *pathp++ = '='; + *pathp++ = '/'; + strcpy(pathp, &p[2]); +#endif + + pathp += strlen(pathp); + *pathp++ = ':'; /* use Unix style path separtor for new path */ + *pathp = '\0'; /* make sure we are null terminaed */ + + /* restore path separator */ + *etok = sep; + + /* point p to first char of next path element */ + p = ++etok; + + } + } else { + nutc_path_len = strlen(path) + 3; + nutc_path = xmalloc(nutc_path_len); + pathp = nutc_path; + *pathp = '\0'; + p = path; + } + + /* + * OK, here we handle the last element in PATH (e.g. c of a;b;c) + * or the path was a single filename and will be converted + * here. Note, testing p here assures that we don't trip up + * on paths like a;b; which have trailing delimiter followed by + * nothing. + */ + if (*p != '\0') { +#ifdef __NUTC__ + if (_NutPathToNutc(p, pathp, 0) == FALSE) { + free(nutc_path); + rval = savestring(path, strlen(path)); + return rval; + } +#else + *pathp++ = '/'; + *pathp++ = p[0]; + *pathp++ = '='; + *pathp++ = '/'; + strcpy(pathp, &p[2]); +#endif + } else + *(pathp-1) = '\0'; /* we're already done, don't leave trailing : */ + + rval = savestring(nutc_path, strlen(nutc_path)); + free(nutc_path); + return rval; +} + +#endif diff --git a/w32/subproc/NMakefile b/w32/subproc/NMakefile new file mode 100644 index 00000000..3d44b82c --- /dev/null +++ b/w32/subproc/NMakefile @@ -0,0 +1,59 @@ +# 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, 1996 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 _WINDOWS -I. -I../include +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 + +$(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/build.bat b/w32/subproc/build.bat new file mode 100644 index 00000000..45231bfd --- /dev/null +++ b/w32/subproc/build.bat @@ -0,0 +1,10 @@ +if not exist .\WinDebug\nul mkdir .\WinDebug +cl.exe /nologo /MT /W3 /GX /Z7 /YX /Od /I .. /I . /I ../include /D WIN32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c misc.c +cl.exe /nologo /MT /W3 /GX /Z7 /YX /Od /I .. /I . /I ../include /D WIN32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c sub_proc.c +cl.exe /nologo /MT /W3 /GX /Z7 /YX /Od /I .. /I . /I ../include /D WIN32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c w32err.c +lib.exe /NOLOGO /OUT:.\WinDebug\subproc.lib .\WinDebug/misc.obj .\WinDebug/sub_proc.obj .\WinDebug/w32err.obj +if not exist .\WinRel\nul mkdir .\WinRel +cl.exe /nologo /MT /W3 /GX /YX /O2 /I ../include /D WIN32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c misc.c +cl.exe /nologo /MT /W3 /GX /YX /O2 /I ../include /D WIN32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c sub_proc.c +cl.exe /nologo /MT /W3 /GX /YX /O2 /I ../include /D WIN32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c w32err.c +lib.exe /NOLOGO /OUT:.\WinRel\subproc.lib .\WinRel/misc.obj .\WinRel/sub_proc.obj .\WinRel/w32err.obj diff --git a/w32/subproc/misc.c b/w32/subproc/misc.c new file mode 100644 index 00000000..23b61244 --- /dev/null +++ b/w32/subproc/misc.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include "proc.h" + + +/* + * Description: Convert a NULL string terminated UNIX environment block to + * an environment block suitable for a win32 system call + * + * Returns: TRUE= success, FALSE=fail + * + * Notes/Dependencies: the environment block is sorted in case-insensitive + * order, is double-null terminated, and is a char *, not a char ** + */ +int _cdecl compare(const void *a1, const void *a2) +{ + return _stricoll(*((char**)a1),*((char**)a2)); +} +bool_t +arr2envblk(char **arr, char **envblk_out) +{ + char **tmp; + int size_needed; + int arrcnt; + char *ptr; + + arrcnt = 0; + while (arr[arrcnt]) { + arrcnt++; + } + + tmp = (char**) calloc(arrcnt + 1, sizeof(char *)); + if (!tmp) { + return FALSE; + } + + arrcnt = 0; + size_needed = 0; + while (arr[arrcnt]) { + tmp[arrcnt] = arr[arrcnt]; + size_needed += strlen(arr[arrcnt]) + 1; + arrcnt++; + } + size_needed++; + + qsort((void *) tmp, (size_t) arrcnt, sizeof (char*), compare); + + ptr = *envblk_out = calloc(size_needed, 1); + if (!ptr) { + free(tmp); + return FALSE; + } + + arrcnt = 0; + while (tmp[arrcnt]) { + strcpy(ptr, tmp[arrcnt]); + ptr += strlen(tmp[arrcnt]) + 1; + arrcnt++; + } + return TRUE; +} diff --git a/w32/subproc/proc.h b/w32/subproc/proc.h new file mode 100644 index 00000000..ce7a14f1 --- /dev/null +++ b/w32/subproc/proc.h @@ -0,0 +1,13 @@ +#ifndef _PROC_H +#define _PROC_H + +typedef int bool_t; + +#define E_SCALL 101 +#define E_IO 102 +#define E_NO_MEM 103 +#define E_FORK 104 + +extern bool_t arr2envblk(char **arr, char **envblk_out); + +#endif diff --git a/w32/subproc/sub_proc.c b/w32/subproc/sub_proc.c new file mode 100644 index 00000000..52cd9d7e --- /dev/null +++ b/w32/subproc/sub_proc.c @@ -0,0 +1,1100 @@ +#include +#include +#include /* for msvc _beginthreadex, _endthreadex */ +#include + +#include "sub_proc.h" +#include "proc.h" +#include "w32err.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; + + if ((exec_handle = (HANDLE)OpenFile(exec_path, file_info, + OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) { + return(exec_handle); + } + + 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, ".bat"); + if ((exec_handle = (HANDLE)OpenFile(fname, 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 Win32 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]; + + /* + * See if we need to setuid to a different user. + */ + if (as_user) { + return -1; + } + + if (as_user) { + 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); + 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 ); + 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_win32_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_win32_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_win32_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_win32_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); +} + + +/* + * Try to protect against WIN32 argument munging. This function takes + * an argv vector and outputs a 'protected' string as a return + * value. The return code can be safely passed to CreateProcess(). + * + * The caller should free the return value. + */ + +#define TRACE(x) +static char *fix_command_line(char *args[]) +{ + int i; + char *narg; + char *nargp; + char *p; + char *q; + int alloc_len = 0; + + for (i = 0; args[i]; i++) + alloc_len += ((strlen(args[i]) * 2) + 1); + /* account for possible enclosing quotes and null termination */ + alloc_len += 3; + + nargp = narg = malloc(alloc_len); + + for (i = 0; args[i]; i++) { + p = args[i]; + TRACE(("original arg: %s\n", p)); + + if (*p == '\0') { + *nargp++ = '"'; + *nargp++ = '"'; + *nargp = '\0'; + TRACE(("empty string arg: %s\n", nargp-2)); + } else if (strpbrk(p, "\" \t")) { + /* point to end of copy buffer */ + q = narg; + q += (alloc_len-1); + *q-- = '\0'; /* ensure null terminated string */ + *q-- = '"'; /* terminating quote of argument */ + + /* point to end of the input string */ + p = args[i]; + p += strlen(args[i]); + p--; + + /* + * Because arg is quoted, escape any backslashes + * that might occur at the end of the string which + * proceed the closing quote. + * Example: + * foo c:\ + * Becomes: + * "foo c:\\" + */ + while (*p == '\\') + *q-- = *p--, *q-- = '\\'; + + /* copy the string in reverse */ + while (p >= args[i]) { + /* copy the character */ + *q-- = *p--; + + /* + * Escape any double quote found. Also escape + * each backslash preceding the double quote. + */ + if (*(p+1) == '"') { + *q-- = '\\'; + if (p >= args[i] && *p == '\\') + while (p >= args[i] && *p == '\\') + *q-- = *p--, *q-- = '\\'; + } + } + + /* finish quoting arg, q now points to complete arg */ + *q = '"'; + + /* rejustify */ + memmove(nargp, q, strlen(q) + 1); + TRACE(("arg with white space or doublequotes: %s\n", nargp)); + nargp += strlen(nargp); + } else { + /* just copy the argument, no protection needed */ + strcpy(nargp, args[i]); + TRACE(("plain arg: %s\n", nargp)); + nargp += strlen(nargp); + } + + /* separate arguments with spaces (if more args to gather) */ + if (args[i+1]) + *nargp++ = ' '; + *nargp = '\0'; + } /* end for */ + + /* NULL terminate the arg list */ + *nargp = '\0'; + + return (narg); +} +#undef TRACE + +/* + * 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 *exec_path, char **argv) +{ + char** nargv; + char* buf; + int i; + + if (shell_name) { + for (i = 0; argv[i]; i++); + i += 2; + nargv = (char **) malloc(i * sizeof (char *)); + nargv[0] = shell_name; + for (i = 1; argv[i-1]; i++) + nargv[i] = argv[i-1]; + nargv[i] = NULL; + } else + nargv = argv; + + /* create string suitable for CreateProcess() */ + buf = fix_command_line(nargv); + + if (shell_name) + free(nargv); + + return buf; +} + +/* + * 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; +} diff --git a/w32/subproc/w32err.c b/w32/subproc/w32err.c new file mode 100644 index 00000000..e4e88355 --- /dev/null +++ b/w32/subproc/w32err.c @@ -0,0 +1,51 @@ +#include +#include "w32err.h" + +/* + * Description: the win32 version of perror() + * + * Returns: a pointer to a static error + * + * Notes/Dependencies: I got this from + * comp.os.ms-windows.programmer.win32 + */ +char * +map_win32_error_to_string (DWORD ercode) { +/* __declspec (thread) necessary if you will use multiple threads */ +__declspec (thread) static char szMessageBuffer[128]; + + /* Fill message buffer with a default message in + * case FormatMessage fails + */ + wsprintf (szMessageBuffer, "Error %ld", ercode); + + /* + * Special code for winsock error handling. + */ + if (ercode > WSABASEERR) { + HMODULE hModule = GetModuleHandle("wsock32"); + if (hModule != NULL) { + FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, + hModule, + ercode, + LANG_NEUTRAL, + szMessageBuffer, + sizeof(szMessageBuffer), + NULL); + FreeLibrary(hModule); + } + } else { + /* + * Default system message handling + */ + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + ercode, + LANG_NEUTRAL, + szMessageBuffer, + sizeof(szMessageBuffer), + NULL); + } + return szMessageBuffer; +} +