From 7bb7bb4ba49967e71abf14d7d59036b9a0eddf93 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Mon, 17 Oct 2022 23:36:36 -0400 Subject: [PATCH] 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. --- src/dir.c | 13 +++++-------- src/file.c | 14 ++------------ src/function.c | 18 +++++++++--------- src/job.c | 33 ++++++++++++--------------------- src/main.c | 10 ++++------ src/makeint.h | 2 ++ src/read.c | 7 +++---- src/remake.c | 2 +- src/vpath.c | 3 +-- 9 files changed, 39 insertions(+), 63 deletions(-) diff --git a/src/dir.c b/src/dir.c index cca968c7..ec7bb207 100644 --- a/src/dir.c +++ b/src/dir.c @@ -530,9 +530,7 @@ find_directory (const char *name) tstart = tem; if (tstart[1] == ':') tstart += 2; - for (tend = tem + (len - 1); - tend > tstart && (*tend == '/' || *tend == '\\'); - tend--) + for (tend = tem + (len - 1); tend > tstart && ISDIRSEP (*tend); tend--) *tend = '\0'; r = stat (tem, &st); @@ -867,7 +865,7 @@ file_exists_p (const char *name) #ifdef HAVE_DOS_PATHS /* d:/ and d: are *very* different... */ if (dirend < name + 3 && name[1] == ':' && - (*dirend == '/' || *dirend == '\\' || *dirend == ':')) + (ISDIRSEP (*dirend) || *dirend == ':')) dirend++; #endif p = alloca (dirend - name + 1); @@ -943,7 +941,7 @@ file_impossible (const char *filename) #ifdef HAVE_DOS_PATHS /* d:/ and d: are *very* different... */ if (dirend < p + 3 && p[1] == ':' && - (*dirend == '/' || *dirend == '\\' || *dirend == ':')) + (ISDIRSEP (*dirend) || *dirend == ':')) dirend++; #endif cp = alloca (dirend - p + 1); @@ -1041,7 +1039,7 @@ file_impossible_p (const char *filename) #ifdef HAVE_DOS_PATHS /* d:/ and d: are *very* different... */ if (dirend < filename + 3 && filename[1] == ':' && - (*dirend == '/' || *dirend == '\\' || *dirend == ':')) + (ISDIRSEP (*dirend) || *dirend == ':')) dirend++; #endif 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 file. This is because 'stat' on Windows normalizes the argument foo/. => foo without checking first that foo is a directory. */ - if (plen > 2 && path[plen - 1] == '.' - && (path[plen - 2] == '/' || path[plen - 2] == '\\')) + if (plen > 2 && path[plen - 1] == '.' && ISDIRSEP (path[plen - 2])) { char parent[MAXPATHLEN+1]; diff --git a/src/file.c b/src/file.c index 62b8dd00..d2ee2c68 100644 --- a/src/file.c +++ b/src/file.c @@ -108,20 +108,10 @@ lookup_file (const char *name) while (name[0] == '<' && name[1] == '>' && name[2] != '\0') name += 2; #endif - while (name[0] == '.' -#ifdef HAVE_DOS_PATHS - && (name[1] == '/' || name[1] == '\\') -#else - && name[1] == '/' -#endif - && name[2] != '\0') + while (name[0] == '.' && ISDIRSEP (name[1]) && name[2] != '\0') { name += 2; - while (*name == '/' -#ifdef HAVE_DOS_PATHS - || *name == '\\' -#endif - ) + while (ISDIRSEP (*name)) /* Skip following slashes: ".//foo" is "foo", not "/foo". */ ++name; } diff --git a/src/function.c b/src/function.c index fb4ffbc8..61164dcb 100644 --- a/src/function.c +++ b/src/function.c @@ -2135,7 +2135,7 @@ func_not (char *o, char **argv, char *funcname UNUSED) #ifdef HAVE_DOS_PATHS # 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 # define IS_ABSOLUTE(n) (n[0] && n[1] == ':') # endif @@ -2169,9 +2169,9 @@ abspath (const char *name, char *apath) strcpy (apath, starting_directory); #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. */ apath[0] = name[0]; @@ -2191,7 +2191,7 @@ abspath (const char *name, char *apath) else { #if defined(__CYGWIN__) && defined(HAVE_DOS_PATHS) - if (STOP_SET (name[0], MAP_DIRSEP)) + if (ISDIRSEP (name[0])) root_len = 1; #endif memcpy (apath, name, root_len); @@ -2200,7 +2200,7 @@ abspath (const char *name, char *apath) /* Get past the root, since we already copied it. */ name += root_len; #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. */ apath[2] = '.'; @@ -2220,7 +2220,7 @@ abspath (const char *name, char *apath) size_t len; /* Skip sequence of multiple path-separators. */ - while (STOP_SET (*start, MAP_DIRSEP)) + while (ISDIRSEP (*start)) ++start; /* 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. */ if (dest > apath + root_len) - for (--dest; ! STOP_SET (dest[-1], MAP_DIRSEP); --dest) + for (--dest; ! ISDIRSEP (dest[-1]); --dest) ; } else { - if (! STOP_SET (dest[-1], MAP_DIRSEP)) + if (! ISDIRSEP (dest[-1])) *dest++ = '/'; if (dest + len >= apath_limit) @@ -2254,7 +2254,7 @@ abspath (const char *name, char *apath) } /* 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 = '\0'; diff --git a/src/job.c b/src/job.c index 4bbdc990..7f855e95 100644 --- a/src/job.c +++ b/src/job.c @@ -416,7 +416,8 @@ _is_unixy_shell (const char *path) else if (!name) /* name and p must be 0 */ name = path; - if (*name == '/' || *name == '\\') name++; + if (ISDIRSEP (*name)) + name++; i = 0; while (known_os2shells[i] != NULL) @@ -439,38 +440,30 @@ is_bourne_compatible_shell (const char *path) static const char *unix_shells[] = { "sh", "bash", + "dash", "ksh", "rksh", "zsh", "ash", - "dash", NULL }; const char **s; - /* find the rightmost '/' or '\\' */ - const char *name = strrchr (path, '/'); - char *p = strrchr (path, '\\'); + /* find the last directory separator, or the beginning of the string. */ + const char *cp = path + strlen (path); - if (name && p) /* take the max */ - name = (name > p) ? name : p; - else if (p) /* name must be 0 */ - name = p; - else if (!name) /* name and p must be 0 */ - name = path; - - if (*name == '/' || *name == '\\') - ++name; + while (cp > path && !ISDIRSEP (cp[-1])) + --cp; /* this should be able to deal with extensions on Windows-like systems */ for (s = unix_shells; *s != NULL; ++s) { #if defined(WINDOWS32) || defined(__MSDOS__) size_t len = strlen (*s); - if ((strlen (name) >= len && STOP_SET (name[len], MAP_DOT|MAP_NUL)) - && strncasecmp (name, *s, len) == 0) + if ((strlen (cp) >= len && STOP_SET (cp[len], MAP_DOT|MAP_NUL)) + && strncasecmp (cp, *s, len) == 0) #else - if (strcmp (name, *s) == 0) + if (strcmp (cp, *s) == 0) #endif return 1; /* a known unix-style shell */ } @@ -3053,8 +3046,7 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, } else #endif - if (p[1] != '\\' && p[1] != '\'' - && !ISSPACE (p[1]) + if (p[1] != '\\' && p[1] != '\'' && !ISSPACE (p[1]) && strchr (sh_chars_sh, p[1]) == 0) /* back up one notch, to copy the backslash */ --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, try whether it exists e.g.: if "/bin/sh" does not exist use "$UNIXROOT/bin/sh" instead. */ - if (unixroot && shell && strcmp (shell, last_shell) != 0 - && (shell[0] == '/' || shell[0] == '\\')) + if (unixroot && shell && ISDIRSEP (shell[0]) && !streq (shell, last_shell)) { /* trying a new shell, check whether it exists */ size_t size = strlen (shell); diff --git a/src/main.c b/src/main.c index 8adce3a5..41490f4e 100644 --- a/src/main.c +++ b/src/main.c @@ -1016,12 +1016,10 @@ find_and_set_default_shell (const char *token) "cmd.exe" case-insensitive. */ tokend = search_token + strlen (search_token) - 3; if (((tokend == search_token - || (tokend > search_token - && (tokend[-1] == '/' || tokend[-1] == '\\'))) + || (tokend > search_token && ISDIRSEP (tokend[-1]))) && !strcasecmp (tokend, "cmd")) || ((tokend - 4 == search_token - || (tokend - 4 > search_token - && (tokend[-5] == '/' || tokend[-5] == '\\'))) + || (tokend - 4 > search_token && ISDIRSEP (tokend[-5]))) && !strcasecmp (tokend - 4, "cmd.exe"))) { batch_mode_shell = 1; @@ -1320,7 +1318,7 @@ main (int argc, char **argv, char **envp) else { program = start + strlen (start); - while (program > start && ! STOP_SET (program[-1], MAP_DIRSEP)) + while (program > start && ! ISDIRSEP (program[-1])) --program; /* 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. */ { char *p = (char *)dir + strlen (dir) - 1; - while (p > dir && (p[0] == '/' || p[0] == '\\')) + while (p > dir && ISDIRSEP (p[0])) --p; p[1] = '\0'; } diff --git a/src/makeint.h b/src/makeint.h index 276def9a..8ab7ea84 100644 --- a/src/makeint.h +++ b/src/makeint.h @@ -468,6 +468,8 @@ extern int unixy_shell; #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. */ #define ISBLANK(c) STOP_SET((c),MAP_BLANK) /* True if C is whitespace including newlines. */ diff --git a/src/read.c b/src/read.c index b13d1dc8..3336fb83 100644 --- a/src/read.c +++ b/src/read.c @@ -1108,7 +1108,7 @@ eval (struct ebuffer *ebuf, int set_default) Note that the only separators of targets in this context are whitespace and a left paren. If others are possible, add them to the string in the call to strchr. */ - while (colonp && (colonp[1] == '/' || colonp[1] == '\\') && + while (colonp && ISDIRSEP (colonp[1]) && isalpha ((unsigned char) colonp[-1]) && (colonp == p2 + 1 || strchr (" \t(", colonp[-2]) != 0)) colonp = find_char_unquote (colonp + 1, ':'); @@ -1279,8 +1279,7 @@ eval (struct ebuffer *ebuf, int set_default) do { check_again = 0; /* For DOS-style paths, skip a "C:\..." or a "C:/..." */ - if (p != 0 && (p[1] == '\\' || p[1] == '/') && - isalpha ((unsigned char)p[-1]) && + if (p != 0 && ISDIRSEP (p[1]) && isalpha ((unsigned char)p[-1]) && (p == p2 + 1 || strchr (" \t:(", p[-2]) != 0)) { p = strchr (p + 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 doesn't allow path names with spaces. */ 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); #endif diff --git a/src/remake.c b/src/remake.c index e536c8b5..57f10427 100644 --- a/src/remake.c +++ b/src/remake.c @@ -1564,7 +1564,7 @@ name_mtime (const char *name) tend--; if (*tend == '.' && tend > tstart) tend--; - for ( ; tend > tstart && (*tend == '/' || *tend == '\\'); tend--) + for ( ; tend > tstart && ISDIRSEP (*tend); tend--) *tend = '\0'; } else diff --git a/src/vpath.c b/src/vpath.c index 203fca1b..343e3446 100644 --- a/src/vpath.c +++ b/src/vpath.c @@ -239,8 +239,7 @@ construct_vpath_list (char *pattern, char *dirpath) also define HAVE_DOS_PATHS would like us to recognize colons after the drive letter in the likes of "D:/foo/bar:C:/xyzzy". */ - && (*p != PATH_SEPARATOR_CHAR - || (p == v + 1 && (p[1] == '/' || p[1] == '\\'))) + && (*p != PATH_SEPARATOR_CHAR || (p == v + 1 && ISDIRSEP (p[1]))) #else && *p != PATH_SEPARATOR_CHAR #endif