Add ISDIRSEP() helper macro and use it

Create a ISDIRSEP() macro to check for directory separator chars
using the stopchar_map, and replace inline checks and explicit
STOP_SET calls with this macro.

* src/makeint.h (ISDIRSEP): Create the macro using MAP_DIRSEP.
* src/dir.c (find_directory): Replace inline checks with ISDIRSEP.
(file_exists_p): Ditto.
(file_impossible): Ditto.
(file_impossible_p): Ditto.
(local_stat): Ditto.
* src/file.c (lookup_file): Ditto.
* src/function.c (abspath): Ditto.
* src/job.c (_is_unixy_shell): Ditto.
(is_bourne_compatible_shell): Ditto.
(construct_command_argv): Ditto.
* src/main.c (find_and_set_default_shell): Ditto.
(main): Ditto.
* src/read.c (eval): Ditto.
(parse_file_seq): Ditto.
* src/remake.c (name_mtime): Ditto.
* src/vpath.c (construct_vpath_list): Ditto.
This commit is contained in:
Paul Smith 2022-10-17 23:36:36 -04:00
parent b79791533b
commit 7bb7bb4ba4
9 changed files with 39 additions and 63 deletions

View File

@ -530,9 +530,7 @@ find_directory (const char *name)
tstart = tem; tstart = tem;
if (tstart[1] == ':') if (tstart[1] == ':')
tstart += 2; tstart += 2;
for (tend = tem + (len - 1); for (tend = tem + (len - 1); tend > tstart && ISDIRSEP (*tend); tend--)
tend > tstart && (*tend == '/' || *tend == '\\');
tend--)
*tend = '\0'; *tend = '\0';
r = stat (tem, &st); r = stat (tem, &st);
@ -867,7 +865,7 @@ file_exists_p (const char *name)
#ifdef HAVE_DOS_PATHS #ifdef HAVE_DOS_PATHS
/* d:/ and d: are *very* different... */ /* d:/ and d: are *very* different... */
if (dirend < name + 3 && name[1] == ':' && if (dirend < name + 3 && name[1] == ':' &&
(*dirend == '/' || *dirend == '\\' || *dirend == ':')) (ISDIRSEP (*dirend) || *dirend == ':'))
dirend++; dirend++;
#endif #endif
p = alloca (dirend - name + 1); p = alloca (dirend - name + 1);
@ -943,7 +941,7 @@ file_impossible (const char *filename)
#ifdef HAVE_DOS_PATHS #ifdef HAVE_DOS_PATHS
/* d:/ and d: are *very* different... */ /* d:/ and d: are *very* different... */
if (dirend < p + 3 && p[1] == ':' && if (dirend < p + 3 && p[1] == ':' &&
(*dirend == '/' || *dirend == '\\' || *dirend == ':')) (ISDIRSEP (*dirend) || *dirend == ':'))
dirend++; dirend++;
#endif #endif
cp = alloca (dirend - p + 1); cp = alloca (dirend - p + 1);
@ -1041,7 +1039,7 @@ file_impossible_p (const char *filename)
#ifdef HAVE_DOS_PATHS #ifdef HAVE_DOS_PATHS
/* d:/ and d: are *very* different... */ /* d:/ and d: are *very* different... */
if (dirend < filename + 3 && filename[1] == ':' && if (dirend < filename + 3 && filename[1] == ':' &&
(*dirend == '/' || *dirend == '\\' || *dirend == ':')) (ISDIRSEP (*dirend) || *dirend == ':'))
dirend++; dirend++;
#endif #endif
cp = alloca (dirend - filename + 1); cp = alloca (dirend - filename + 1);
@ -1314,8 +1312,7 @@ local_stat (const char *path, struct stat *buf)
/* Make sure the parent of "." exists and is a directory, not a /* Make sure the parent of "." exists and is a directory, not a
file. This is because 'stat' on Windows normalizes the argument file. This is because 'stat' on Windows normalizes the argument
foo/. => foo without checking first that foo is a directory. */ foo/. => foo without checking first that foo is a directory. */
if (plen > 2 && path[plen - 1] == '.' if (plen > 2 && path[plen - 1] == '.' && ISDIRSEP (path[plen - 2]))
&& (path[plen - 2] == '/' || path[plen - 2] == '\\'))
{ {
char parent[MAXPATHLEN+1]; char parent[MAXPATHLEN+1];

View File

@ -108,20 +108,10 @@ lookup_file (const char *name)
while (name[0] == '<' && name[1] == '>' && name[2] != '\0') while (name[0] == '<' && name[1] == '>' && name[2] != '\0')
name += 2; name += 2;
#endif #endif
while (name[0] == '.' while (name[0] == '.' && ISDIRSEP (name[1]) && name[2] != '\0')
#ifdef HAVE_DOS_PATHS
&& (name[1] == '/' || name[1] == '\\')
#else
&& name[1] == '/'
#endif
&& name[2] != '\0')
{ {
name += 2; name += 2;
while (*name == '/' while (ISDIRSEP (*name))
#ifdef HAVE_DOS_PATHS
|| *name == '\\'
#endif
)
/* Skip following slashes: ".//foo" is "foo", not "/foo". */ /* Skip following slashes: ".//foo" is "foo", not "/foo". */
++name; ++name;
} }

View File

@ -2135,7 +2135,7 @@ func_not (char *o, char **argv, char *funcname UNUSED)
#ifdef HAVE_DOS_PATHS #ifdef HAVE_DOS_PATHS
# ifdef __CYGWIN__ # ifdef __CYGWIN__
# define IS_ABSOLUTE(n) ((n[0] && n[1] == ':') || STOP_SET (n[0], MAP_DIRSEP)) # define IS_ABSOLUTE(n) ((n[0] && n[1] == ':') || ISDIRSEP (n[0]))
# else # else
# define IS_ABSOLUTE(n) (n[0] && n[1] == ':') # define IS_ABSOLUTE(n) (n[0] && n[1] == ':')
# endif # endif
@ -2169,9 +2169,9 @@ abspath (const char *name, char *apath)
strcpy (apath, starting_directory); strcpy (apath, starting_directory);
#ifdef HAVE_DOS_PATHS #ifdef HAVE_DOS_PATHS
if (STOP_SET (name[0], MAP_DIRSEP)) if (ISDIRSEP (name[0]))
{ {
if (STOP_SET (name[1], MAP_DIRSEP)) if (ISDIRSEP (name[1]))
{ {
/* A UNC. Don't prepend a drive letter. */ /* A UNC. Don't prepend a drive letter. */
apath[0] = name[0]; apath[0] = name[0];
@ -2191,7 +2191,7 @@ abspath (const char *name, char *apath)
else else
{ {
#if defined(__CYGWIN__) && defined(HAVE_DOS_PATHS) #if defined(__CYGWIN__) && defined(HAVE_DOS_PATHS)
if (STOP_SET (name[0], MAP_DIRSEP)) if (ISDIRSEP (name[0]))
root_len = 1; root_len = 1;
#endif #endif
memcpy (apath, name, root_len); memcpy (apath, name, root_len);
@ -2200,7 +2200,7 @@ abspath (const char *name, char *apath)
/* Get past the root, since we already copied it. */ /* Get past the root, since we already copied it. */
name += root_len; name += root_len;
#ifdef HAVE_DOS_PATHS #ifdef HAVE_DOS_PATHS
if (! STOP_SET (apath[root_len - 1], MAP_DIRSEP)) if (! ISDIRSEP (apath[root_len - 1]))
{ {
/* Convert d:foo into d:./foo and increase root_len. */ /* Convert d:foo into d:./foo and increase root_len. */
apath[2] = '.'; apath[2] = '.';
@ -2220,7 +2220,7 @@ abspath (const char *name, char *apath)
size_t len; size_t len;
/* Skip sequence of multiple path-separators. */ /* Skip sequence of multiple path-separators. */
while (STOP_SET (*start, MAP_DIRSEP)) while (ISDIRSEP (*start))
++start; ++start;
/* Find end of path component. */ /* Find end of path component. */
@ -2237,12 +2237,12 @@ abspath (const char *name, char *apath)
{ {
/* Back up to previous component, ignore if at root already. */ /* Back up to previous component, ignore if at root already. */
if (dest > apath + root_len) if (dest > apath + root_len)
for (--dest; ! STOP_SET (dest[-1], MAP_DIRSEP); --dest) for (--dest; ! ISDIRSEP (dest[-1]); --dest)
; ;
} }
else else
{ {
if (! STOP_SET (dest[-1], MAP_DIRSEP)) if (! ISDIRSEP (dest[-1]))
*dest++ = '/'; *dest++ = '/';
if (dest + len >= apath_limit) if (dest + len >= apath_limit)
@ -2254,7 +2254,7 @@ abspath (const char *name, char *apath)
} }
/* Unless it is root strip trailing separator. */ /* Unless it is root strip trailing separator. */
if (dest > apath + root_len && STOP_SET (dest[-1], MAP_DIRSEP)) if (dest > apath + root_len && ISDIRSEP (dest[-1]))
--dest; --dest;
*dest = '\0'; *dest = '\0';

View File

@ -416,7 +416,8 @@ _is_unixy_shell (const char *path)
else if (!name) /* name and p must be 0 */ else if (!name) /* name and p must be 0 */
name = path; name = path;
if (*name == '/' || *name == '\\') name++; if (ISDIRSEP (*name))
name++;
i = 0; i = 0;
while (known_os2shells[i] != NULL) while (known_os2shells[i] != NULL)
@ -439,38 +440,30 @@ is_bourne_compatible_shell (const char *path)
static const char *unix_shells[] = { static const char *unix_shells[] = {
"sh", "sh",
"bash", "bash",
"dash",
"ksh", "ksh",
"rksh", "rksh",
"zsh", "zsh",
"ash", "ash",
"dash",
NULL NULL
}; };
const char **s; const char **s;
/* find the rightmost '/' or '\\' */ /* find the last directory separator, or the beginning of the string. */
const char *name = strrchr (path, '/'); const char *cp = path + strlen (path);
char *p = strrchr (path, '\\');
if (name && p) /* take the max */ while (cp > path && !ISDIRSEP (cp[-1]))
name = (name > p) ? name : p; --cp;
else if (p) /* name must be 0 */
name = p;
else if (!name) /* name and p must be 0 */
name = path;
if (*name == '/' || *name == '\\')
++name;
/* this should be able to deal with extensions on Windows-like systems */ /* this should be able to deal with extensions on Windows-like systems */
for (s = unix_shells; *s != NULL; ++s) for (s = unix_shells; *s != NULL; ++s)
{ {
#if defined(WINDOWS32) || defined(__MSDOS__) #if defined(WINDOWS32) || defined(__MSDOS__)
size_t len = strlen (*s); size_t len = strlen (*s);
if ((strlen (name) >= len && STOP_SET (name[len], MAP_DOT|MAP_NUL)) if ((strlen (cp) >= len && STOP_SET (cp[len], MAP_DOT|MAP_NUL))
&& strncasecmp (name, *s, len) == 0) && strncasecmp (cp, *s, len) == 0)
#else #else
if (strcmp (name, *s) == 0) if (strcmp (cp, *s) == 0)
#endif #endif
return 1; /* a known unix-style shell */ return 1; /* a known unix-style shell */
} }
@ -3053,8 +3046,7 @@ construct_command_argv_internal (char *line, char **restp, const char *shell,
} }
else else
#endif #endif
if (p[1] != '\\' && p[1] != '\'' if (p[1] != '\\' && p[1] != '\'' && !ISSPACE (p[1])
&& !ISSPACE (p[1])
&& strchr (sh_chars_sh, p[1]) == 0) && strchr (sh_chars_sh, p[1]) == 0)
/* back up one notch, to copy the backslash */ /* back up one notch, to copy the backslash */
--p; --p;
@ -3688,8 +3680,7 @@ construct_command_argv (char *line, char **restp, struct file *file,
performed) and if shell is an absolute path without drive letter, performed) and if shell is an absolute path without drive letter,
try whether it exists e.g.: if "/bin/sh" does not exist use try whether it exists e.g.: if "/bin/sh" does not exist use
"$UNIXROOT/bin/sh" instead. */ "$UNIXROOT/bin/sh" instead. */
if (unixroot && shell && strcmp (shell, last_shell) != 0 if (unixroot && shell && ISDIRSEP (shell[0]) && !streq (shell, last_shell))
&& (shell[0] == '/' || shell[0] == '\\'))
{ {
/* trying a new shell, check whether it exists */ /* trying a new shell, check whether it exists */
size_t size = strlen (shell); size_t size = strlen (shell);

View File

@ -1016,12 +1016,10 @@ find_and_set_default_shell (const char *token)
"cmd.exe" case-insensitive. */ "cmd.exe" case-insensitive. */
tokend = search_token + strlen (search_token) - 3; tokend = search_token + strlen (search_token) - 3;
if (((tokend == search_token if (((tokend == search_token
|| (tokend > search_token || (tokend > search_token && ISDIRSEP (tokend[-1])))
&& (tokend[-1] == '/' || tokend[-1] == '\\')))
&& !strcasecmp (tokend, "cmd")) && !strcasecmp (tokend, "cmd"))
|| ((tokend - 4 == search_token || ((tokend - 4 == search_token
|| (tokend - 4 > search_token || (tokend - 4 > search_token && ISDIRSEP (tokend[-5])))
&& (tokend[-5] == '/' || tokend[-5] == '\\')))
&& !strcasecmp (tokend - 4, "cmd.exe"))) && !strcasecmp (tokend - 4, "cmd.exe")))
{ {
batch_mode_shell = 1; batch_mode_shell = 1;
@ -1320,7 +1318,7 @@ main (int argc, char **argv, char **envp)
else else
{ {
program = start + strlen (start); program = start + strlen (start);
while (program > start && ! STOP_SET (program[-1], MAP_DIRSEP)) while (program > start && ! ISDIRSEP (program[-1]))
--program; --program;
/* Remove the .exe extension if present. */ /* Remove the .exe extension if present. */
@ -1762,7 +1760,7 @@ main (int argc, char **argv, char **envp)
But allow -C/ just in case someone wants that. */ But allow -C/ just in case someone wants that. */
{ {
char *p = (char *)dir + strlen (dir) - 1; char *p = (char *)dir + strlen (dir) - 1;
while (p > dir && (p[0] == '/' || p[0] == '\\')) while (p > dir && ISDIRSEP (p[0]))
--p; --p;
p[1] = '\0'; p[1] = '\0';
} }

View File

@ -468,6 +468,8 @@ extern int unixy_shell;
#define STOP_SET(_v,_m) ANY_SET(stopchar_map[(unsigned char)(_v)],(_m)) #define STOP_SET(_v,_m) ANY_SET(stopchar_map[(unsigned char)(_v)],(_m))
/* True if C is a directory separator on the current system. */
#define ISDIRSEP(c) STOP_SET((c),MAP_DIRSEP)
/* True if C is whitespace but not newline. */ /* True if C is whitespace but not newline. */
#define ISBLANK(c) STOP_SET((c),MAP_BLANK) #define ISBLANK(c) STOP_SET((c),MAP_BLANK)
/* True if C is whitespace including newlines. */ /* True if C is whitespace including newlines. */

View File

@ -1108,7 +1108,7 @@ eval (struct ebuffer *ebuf, int set_default)
Note that the only separators of targets in this context are Note that the only separators of targets in this context are
whitespace and a left paren. If others are possible, add them whitespace and a left paren. If others are possible, add them
to the string in the call to strchr. */ to the string in the call to strchr. */
while (colonp && (colonp[1] == '/' || colonp[1] == '\\') && while (colonp && ISDIRSEP (colonp[1]) &&
isalpha ((unsigned char) colonp[-1]) && isalpha ((unsigned char) colonp[-1]) &&
(colonp == p2 + 1 || strchr (" \t(", colonp[-2]) != 0)) (colonp == p2 + 1 || strchr (" \t(", colonp[-2]) != 0))
colonp = find_char_unquote (colonp + 1, ':'); colonp = find_char_unquote (colonp + 1, ':');
@ -1279,8 +1279,7 @@ eval (struct ebuffer *ebuf, int set_default)
do { do {
check_again = 0; check_again = 0;
/* For DOS-style paths, skip a "C:\..." or a "C:/..." */ /* For DOS-style paths, skip a "C:\..." or a "C:/..." */
if (p != 0 && (p[1] == '\\' || p[1] == '/') && if (p != 0 && ISDIRSEP (p[1]) && isalpha ((unsigned char)p[-1]) &&
isalpha ((unsigned char)p[-1]) &&
(p == p2 + 1 || strchr (" \t:(", p[-2]) != 0)) { (p == p2 + 1 || strchr (" \t:(", p[-2]) != 0)) {
p = strchr (p + 1, ':'); p = strchr (p + 1, ':');
check_again = 1; check_again = 1;
@ -3270,7 +3269,7 @@ parse_file_seq (char **stringp, size_t size, int stopmap,
Tokens separated by spaces are treated as separate paths since make Tokens separated by spaces are treated as separate paths since make
doesn't allow path names with spaces. */ doesn't allow path names with spaces. */
if (p && p == s+1 && p[0] == ':' if (p && p == s+1 && p[0] == ':'
&& isalpha ((unsigned char)s[0]) && STOP_SET (p[1], MAP_DIRSEP)) && isalpha ((unsigned char)s[0]) && ISDIRSEP (p[1]))
p = find_map_unquote (p+1, findmap); p = find_map_unquote (p+1, findmap);
#endif #endif

View File

@ -1564,7 +1564,7 @@ name_mtime (const char *name)
tend--; tend--;
if (*tend == '.' && tend > tstart) if (*tend == '.' && tend > tstart)
tend--; tend--;
for ( ; tend > tstart && (*tend == '/' || *tend == '\\'); tend--) for ( ; tend > tstart && ISDIRSEP (*tend); tend--)
*tend = '\0'; *tend = '\0';
} }
else else

View File

@ -239,8 +239,7 @@ construct_vpath_list (char *pattern, char *dirpath)
also define HAVE_DOS_PATHS would like us to recognize also define HAVE_DOS_PATHS would like us to recognize
colons after the drive letter in the likes of colons after the drive letter in the likes of
"D:/foo/bar:C:/xyzzy". */ "D:/foo/bar:C:/xyzzy". */
&& (*p != PATH_SEPARATOR_CHAR && (*p != PATH_SEPARATOR_CHAR || (p == v + 1 && ISDIRSEP (p[1])))
|| (p == v + 1 && (p[1] == '/' || p[1] == '\\')))
#else #else
&& *p != PATH_SEPARATOR_CHAR && *p != PATH_SEPARATOR_CHAR
#endif #endif