There are very few true ports of Bourne shell for NT right now.
There is a version of GNU bash available from Cygnus gnu-win32
- porting effort. Other possibilites are to get the MKS version
+ porting effort. Other possibilities are to get the MKS version
of sh.exe or to build your own with a package like
NutCracker (DataFocus) or Portage (Consensys).
freely available. It may be available someday, but I am not in control
of this decision nor do I influence it. Sorry!
+GNU make handling of drive letters in pathnames (PATH, vpath, VPATH):
+
+ There is a caveat that should be noted with respect to handling
+ single character pathnames on Windows systems. When colon is
+ used in PATH variables, make tries to be smart about knowing when
+ you are using colon as a separator versus colon as a drive
+ letter. Unfortunately, something as simple as the string 'x:/'
+ could be interpreted 2 ways: (x and /) or (x:/).
+
+ Make chooses to interpret a letter plus colon (e.g. x:/) as a
+ drive letter pathname. If it is necessary to use single
+ character directories in paths (VPATH, vpath, Path, PATH), the
+ user must do one of two things:
+
+ a. Use semicolon as the separator to disambiguate colon. For
+ example use 'x;/' if you want to say 'x' and '/' are
+ separate components.
+
+ b. Qualify the directory name so that there is more than
+ one character in the path(s) used. For example, none
+ of these settings are ambiguous:
+
+ ./x:./y
+ /some/path/x:/some/path/y
+ x:/some/path/x:x:/some/path/y
+
+ These caveats affect Windows systems only (Windows NT and
+ Windows 95) and can be ignored for other platforms.
+
+ Please note that you are free to mix colon and semi-colon in the
+ specification of paths. Make is able to figure out the intended
+ result and convert the paths internally to the format needed
+ when interacting with the operating system.
+
+ You are encouraged to use colon as the separator character.
+ This should ease the pain of deciding how to handle various path
+ problems which exist between platforms. If colon is used on
+ both Unix and Windows systems, then no ifdef'ing will be
+ necessary in the makefile source.
+
GNU make test suite:
I verified all functionality with a slightly modified version
under VFAT. VFAT users may wish to be aware that this port
of make does respect case sensitivity.
- Version 3.76 contains some preliminary support for FAT.
- Make now tries to work around some difficulties with stat'ing of
- files and caching of filenames and directories internally.
- There is still a known problem with filenames sometimes being found
- to have modification dates in the future which cause make to
- complain about the file and exit (remake.c).
+ Version 3.76 contains some preliminary support for FAT. Make
+ now tries to work around some difficulties with stat'ing of
+ files and caching of filenames and directories internally.
+ There is still a known problem with filenames sometimes being
+ found to have modification dates in the future which cause make
+ to complain about the file and exit (remake.c).
Bug reports:
Please submit bugs via the normal bug reporting mechanism
- which is described in one of the texinfo files. If you don't
- have texinfo for Windows NT or Windows 95, these files are simple
+ which is described in one of the Texinfo files. If you don't
+ have Texinfo for Windows NT or Windows 95, these files are simple
text files and can be read with a text editor.
if (len < pattern_prepercent_len + pattern_postpercent_len)
fail = 1;
- /* Does the prefix match? */
+ /* Does the prefix match? */
if (!fail && pattern_prepercent_len > 0
&& (*t != *pattern
|| t[pattern_prepercent_len - 1] != pattern_percent[-1]
|| strncmp (t + 1, pattern + 1, pattern_prepercent_len - 1)))
fail = 1;
- /* Does the suffix match? */
+ /* Does the suffix match? */
if (!fail && pattern_postpercent_len > 0
&& (t[len - 1] != pattern_percent[pattern_postpercent_len]
|| t[len - pattern_postpercent_len] != pattern_percent[1]
The output is written into VARIABLE_BUFFER starting at O. */
/* Note this absorbs a semicolon and is safe to use in conditionals. */
-#define BADARGS(func) \
- if (reading_filename != 0) \
- makefile_fatal (reading_filename, *reading_lineno_ptr, \
- "insufficient arguments to function `%s'", \
- func); \
- else \
+#define BADARGS(func) \
+ if (reading_filename != 0) \
+ makefile_fatal (reading_filename, *reading_lineno_ptr, \
+ "insufficient arguments to function `%s'", \
+ func); \
+ else \
fatal ("insufficient arguments to function `%s'", func)
static char *
case function_shell:
{
#ifdef WINDOWS32
- SECURITY_ATTRIBUTES saAttr;
- HANDLE hIn;
- HANDLE hErr;
- HANDLE hChildOutRd;
- HANDLE hChildOutWr;
- HANDLE hProcess;
+ SECURITY_ATTRIBUTES saAttr;
+ HANDLE hIn;
+ HANDLE hErr;
+ HANDLE hChildOutRd;
+ HANDLE hChildOutWr;
+ HANDLE hProcess;
#endif
#ifdef __MSDOS__
FILE *fpipe;
#ifndef _AMIGA
/* Using a target environment for `shell' loses in cases like:
- export var = $(shell echo foobie)
+ export var = $(shell echo foobie)
because target_environment hits a loop trying to expand $(var)
to put it in the environment. This is even more confusing when
var was not explicitly exported, but just appeared in the
/* Construct the environment. */
envp = target_environment ((struct file *) 0);
#endif
-#endif /* Not Amiga. */
+#endif /* Not Amiga. */
/* For error messages. */
if (reading_filename != 0)
#ifndef _AMIGA
# ifdef WINDOWS32
- 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);
+ 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 /* WINDOWS32 */
# ifdef __MSDOS__
- {
- /* MSDOS can't fork, but it has `popen'.
- (Bwt, why isn't `popen' used in all the versions?) */
- struct variable *sh = lookup_variable ("SHELL", 5);
- int e;
- extern int dos_command_running, dos_status;
-
- /* Make sure not to bother processing an empty line. */
- while (isblank (*text))
- ++text;
- if (*text == '\0')
- break;
-
- if (sh)
- {
- char buf[PATH_MAX + 7];
- /* This makes sure $SHELL value is used by $(shell), even
- though the target environment is not passed to it. */
- sprintf (buf, "SHELL=%s", sh->value);
- putenv (buf);
- }
-
- e = errno;
- errno = 0;
- dos_command_running = 1;
- dos_status = 0;
- fpipe = popen (text, "rt");
- dos_command_running = 0;
- if (!fpipe || dos_status)
- {
- pipedes[0] = -1;
- pid = -1;
- if (dos_status)
- errno = EINTR;
- else if (errno == 0)
- errno = ENOMEM;
- shell_function_completed = -1;
- }
- else
- {
- pipedes[0] = fileno (fpipe);
- pid = 42;
- errno = e;
- shell_function_completed = 1;
- }
- }
- if (pipedes[0] < 0)
+ {
+ /* MSDOS can't fork, but it has `popen'.
+ (Bwt, why isn't `popen' used in all the versions?) */
+ struct variable *sh = lookup_variable ("SHELL", 5);
+ int e;
+ extern int dos_command_running, dos_status;
+
+ /* Make sure not to bother processing an empty line. */
+ while (isblank (*text))
+ ++text;
+ if (*text == '\0')
+ break;
+
+ if (sh)
+ {
+ char buf[PATH_MAX + 7];
+ /* This makes sure $SHELL value is used by $(shell), even
+ though the target environment is not passed to it. */
+ sprintf (buf, "SHELL=%s", sh->value);
+ putenv (buf);
+ }
+
+ e = errno;
+ errno = 0;
+ dos_command_running = 1;
+ dos_status = 0;
+ fpipe = popen (text, "rt");
+ dos_command_running = 0;
+ if (!fpipe || dos_status)
+ {
+ pipedes[0] = -1;
+ pid = -1;
+ if (dos_status)
+ errno = EINTR;
+ else if (errno == 0)
+ errno = ENOMEM;
+ shell_function_completed = -1;
+ }
+ else
+ {
+ pipedes[0] = fileno (fpipe);
+ pid = 42;
+ errno = e;
+ shell_function_completed = 1;
+ }
+ }
+ if (pipedes[0] < 0)
# else /* ! __MSDOS__ */
- if (pipe (pipedes) < 0)
+ if (pipe (pipedes) < 0)
# endif /* __MSDOS__ */
- {
- perror_with_name (error_prefix, "pipe");
- break;
- }
+ {
+ perror_with_name (error_prefix, "pipe");
+ break;
+ }
# ifndef __MSDOS__
pid = vfork ();
if (i > 0)
{
if (buffer[i - 1] == '\n')
- buffer[--i] = '\0';
+ {
+ if (i > 1 && buffer[i - 2] == '\r')
+ --i;
+ buffer[--i] = '\0';
+ }
else
buffer[i] = '\0';
+
p = buffer;
- while ((p = index (p, '\n')) != 0)
- *p++ = ' ';
+ for (p2=p; *p != '\0'; ++p)
+ {
+ if (p[0] == '\r' && p[1] == '\n')
+ continue;
+ if (*p == '\n')
+ *p2++ = ' ';
+ else
+ *p2++ = *p;
+ }
+ *p2 = '\0';
o = variable_buffer_output (o, buffer, i);
}
}
free (buffer);
}
-#else /* Amiga */
+#else /* Amiga */
{
/* Amiga can't fork nor spawn, but I can start a program with
- redirection of my choice. However, this means that we
+ redirection of my choice. However, this means that we
don't have an opportunity to reopen stdout to trap it. Thus,
we save our own stdout onto a new descriptor and dup a temp
file's descriptor onto our stdout temporarily. After we
spawn the shell program, we dup our own stdout back to the
stdout descriptor. The buffer reading is the same as above,
- except that we're now reading from a file. */
+ except that we're now reading from a file. */
#include <dos/dos.h>
#include <proto/dos.h>
}
free (buffer);
}
-#endif /* Not Amiga. */
+#endif /* Not Amiga. */
free (text);
break;
p2 = text;
while (*p2 != '\0')
{
- while (isspace(*p2))
- ++p2;
- p = p2;
- for (i=0; *p2 != '\0' && !isspace(*p2); ++p2, ++i)
- {}
- if (!i)
- break;
+ while (isspace(*p2))
+ ++p2;
+ p = p2;
+ for (i=0; *p2 != '\0' && !isspace(*p2); ++p2, ++i)
+ {}
+ if (!i)
+ break;
o = variable_buffer_output (o, p, i);
o = variable_buffer_output (o, " ", 1);
doneany = 1;
/* Check the next argument */
for (p2 = p + 1; isblank(*p2); ++p2)
- {}
+ {}
count = 0;
for (p = p2; p < end; ++p)
- {
- if (*p == startparen)
- ++count;
- else if (*p == endparen)
- --count;
- else if (*p == ',' && count <= 0)
- break;
- }
+ {
+ if (*p == startparen)
+ ++count;
+ else if (*p == endparen)
+ --count;
+ else if (*p == ',' && count <= 0)
+ break;
+ }
if (p == end)
- BADARGS ("wordlist");
+ BADARGS ("wordlist");
text = expand_argument (p2, p);
for (p2 = text; *p2 != '\0'; ++p2)
- if (*p2 < '0' || *p2 > '9')
- {
- if (reading_filename != 0)
- makefile_fatal (reading_filename, *reading_lineno_ptr,
- "non-numeric second argument to `wordlist' function");
- else
- fatal ("non-numeric second argument to `wordlist' function");
- }
+ if (*p2 < '0' || *p2 > '9')
+ {
+ if (reading_filename != 0)
+ makefile_fatal (reading_filename, *reading_lineno_ptr,
+ "non-numeric second argument to `wordlist' function");
+ else
+ fatal ("non-numeric second argument to `wordlist' function");
+ }
j = (unsigned int)atoi(text);
free (text);
if (j > i)
- j -= i;
+ j -= i;
else
- {
- unsigned int k;
- k = j;
- j = i - j;
- i = k;
- }
+ {
+ unsigned int k;
+ k = j;
+ j = i - j;
+ i = k;
+ }
++j;
/* Extract the requested words */
p2 = text;
while (((p = find_next_token (&p2, &len)) != 0) && --i)
- {}
+ {}
if (p)
- {
- while (--j && (find_next_token (&p2, &len) != 0))
- {}
- o = variable_buffer_output (o, p, p2 - p);
- }
+ {
+ while (--j && (find_next_token (&p2, &len) != 0))
+ {}
+ o = variable_buffer_output (o, p, p2 - p);
+ }
free (text);
break;
p = p2 + len;
#ifdef VMS
while (p >= p2 && *p != ']'
- && (function != function_basename || *p != '.'))
+ && (function != function_basename || *p != '.'))
#else
# ifdef __MSDOS__
while (p >= p2 && *p != '/' && *p != '\\'
- && (function != function_basename || *p != '.'))
+ && (function != function_basename || *p != '.'))
# else
while (p >= p2 && *p != '/'
- && (function != function_basename || *p != '.'))
+ && (function != function_basename || *p != '.'))
# endif
#endif
--p;
if (p >= p2 && (function == function_dir))
o = variable_buffer_output (o, p2, ++p - p2);
- else if (p >= p2 && (*p == '.'))
- o = variable_buffer_output (o, p2, p - p2);
+ else if (p >= p2 && (*p == '.'))
+ o = variable_buffer_output (o, p2, p - p2);
#if defined(WINDOWS32) || defined(__MSDOS__)
- /* Handle the "d:foobar" case */
- else if (p2[0] && p2[1] == ':' && function == function_dir)
- o = variable_buffer_output (o, p2, 2);
+ /* Handle the "d:foobar" case */
+ else if (p2[0] && p2[1] == ':' && function == function_dir)
+ o = variable_buffer_output (o, p2, 2);
#endif
else if (function == function_dir)
#ifdef VMS
- o = variable_buffer_output (o, "[]", 2);
+ o = variable_buffer_output (o, "[]", 2);
#else
#ifndef _AMIGA
- o = variable_buffer_output (o, "./", 2);
+ o = variable_buffer_output (o, "./", 2);
#else
- /* o = o */; /* Just a nop... */
+ /* o = o */; /* Just a nop... */
#endif /* AMIGA */
#endif /* !VMS */
else
p = p2 + len;
#ifdef VMS
while (p >= p2 && *p != ']'
- && (function != function_suffix || *p != '.'))
+ && (function != function_suffix || *p != '.'))
#else
# ifdef __MSDOS__
while (p >= p2 && *p != '/' && *p != '\\'
- && (function != function_suffix || *p != '.'))
+ && (function != function_suffix || *p != '.'))
# else
while (p >= p2 && *p != '/'
- && (function != function_suffix || *p != '.'))
+ && (function != function_suffix || *p != '.'))
# endif
#endif
--p;
if (p >= p2)
{
if (function == function_notdir)
- ++p;
- else if (*p != '.')
- continue;
+ ++p;
+ else if (*p != '.')
+ continue;
o = variable_buffer_output (o, p, len - (p - p2));
}
#if defined(WINDOWS32) || defined(__MSDOS__)
- /* Handle the case of "d:foo/bar". */
- else if (function == function_notdir && p2[0] && p2[1] == ':')
- {
- p = p2 + 2;
- o = variable_buffer_output (o, p, len - (p - p2));
- }
+ /* Handle the case of "d:foo/bar". */
+ else if (function == function_notdir && p2[0] && p2[1] == ':')
+ {
+ p = p2 + 2;
+ o = variable_buffer_output (o, p, len - (p - p2));
+ }
#endif
else if (function == function_notdir)
o = variable_buffer_output (o, p2, len);