# HG changeset patch # User Mike Becker # Date 1782821948 -7200 # Node ID 8a20001544c1c05a020028c87cf95e0ed0c80328 # Parent 9637e3efb8e723c32b287624788e205f25c98fa8 support dir exclusion part 2/2 tests with MSVC are still open resolves issue #838 (at least for non-Windows) diff -r 9637e3efb8e7 -r 8a20001544c1 src/cline.c --- a/src/cline.c Tue Jun 30 12:00:16 2026 +0200 +++ b/src/cline.c Tue Jun 30 14:19:08 2026 +0200 @@ -94,6 +94,61 @@ return code; } +static void normalize_excluded_dirs(settings_t *settings) { + /* normalize all paths */ + for (int i = 0 ; i < settings->excludeDirs->count ; i++) { + char *arg = strdup(settings->excludeDirs->items[i]); + if (strpbrk(arg, "/\\") == NULL) { + /* do not normalize names */ + settings->excludeDirs->items[i] = arg; + } else { + size_t arglen = strlen(arg); + /* fix file separators */ + char fs = settings->fileSeparator; + char badfs = settings->fileSeparator == '/' ? '\\' : '/'; + for (size_t j = 0 ; j < arglen ; j++) { + if (arg[j] == badfs) { + arg[j] = fs; + } + } + /* make path absolute */ + { + char *ap = make_path_absolute(arg); + free(arg); + arg = ap; + arglen = strlen(ap); + } + /* make path canonical */ + char *canonical = malloc(arglen+1); + size_t canonicallen = 0; + for (size_t j = 0 ; j < arglen ; j++) { + canonical[canonicallen++] = arg[j]; + if (arg[j] == fs) { + /* collapse consecutive separators */ + while (arg[j+1] == fs) j++; + } else if (arg[j] == '.') { + if (arg[j+1] == fs) { + /* skip '.' segments */ + canonicallen--; + j++; + } else if (arg[j+1] == '.' && arg[j+2] == fs) { + /* trace back '..' segment */ + canonicallen -= 2; + while (canonical[canonicallen-1] != fs) canonicallen--; + j+=2; + } + } + } + canonical[canonicallen] = '\0'; + settings->excludeDirs->items[i] = canonical; + free(arg); + } + } + + /* tell the string list to free the items */ + settings->excludeDirs->free_item = free; +} + static const char * sepline_double = "===============================================================================\n"; static const char * sepline_single = "-------------------------------------------------------------------------------\n"; @@ -242,8 +297,6 @@ if (!checkParamOpt(&paropt) || t >= argc) { return exit_with_help(settings, 1); } - // TODO: normalize argument before adding to dir list - // this makes it more efficient to compare dir names later add_string(settings->excludeDirs, argv[t]); } if (argflags == 0) { @@ -280,13 +333,16 @@ return 1; } + /* Normalize paths for excluded directories */ + normalize_excluded_dirs(settings); + /* Scan directories */ scanresult_t* result = new_scanresult_t(settings); const char* result_type = settings->count_chars ? "chars" : "lines"; bool has_output = false; unsigned total = 0; if (directories->count == 0) { - add_string(directories, "./"); + add_string(directories, "."); } for (unsigned t = 0 ; t < directories->count ; t++) { /* Don't waste memory when only the total sum is needed */ diff -r 9637e3efb8e7 -r 8a20001544c1 src/scanner.c --- a/src/scanner.c Tue Jun 30 12:00:16 2026 +0200 +++ b/src/scanner.c Tue Jun 30 14:19:08 2026 +0200 @@ -31,6 +31,54 @@ #include #include +#ifdef _MSC_VER +#include +#include + +void get_working_dir(const char** out_ptr, size_t *out_len) { + static char cwd[MAX_PATH]; + if (GetCurrentDirectory(MAX_PATH, cwd) == 0) { + fprintf(stderr, "Could not get current working directory.\n"); + exit(1); + } + size_t len = strlen(cwd); + if (cwd[len - 1] != '/') { + cwd[len++] = '/'; + cwd[len] = '\0'; + } + *out_ptr = cwd; + *out_len = len; +} +bool path_is_relative(const char *path) { + return PathIsRelative(path); +} +int pathcmp(const char *p1, const char *p2) { + return strcasecmp(p1, p2); +} +#else +#include +void get_working_dir(const char** out_ptr, size_t *out_len) { + static char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) == NULL) { + fprintf(stderr, "Could not get current working directory.\n"); + exit(1); + } + size_t len = strlen(cwd); + if (cwd[len - 1] != '/') { + cwd[len++] = '/'; + cwd[len] = '\0'; + } + *out_ptr = cwd; + *out_len = len; +} +bool path_is_relative(const char *path) { + return path[0] != '/'; +} +int pathcmp(const char *p1, const char *p2) { + return strcmp(p1, p2); +} +#endif + typedef struct filelist filelist_t; struct filelist { @@ -185,10 +233,32 @@ return list; } -static bool is_dir_excluded(string_list_t* list, char* dir) { - // TODO: implement - // assume normalized dir names in list (cline.c will make sure of it) - // remember to do case-insensitive comparison for WIN32 +static bool is_dir_excluded(settings_t* settings, const char* dir) { + const string_list_t * const list = settings->excludeDirs; + + for (size_t i = 0 ; i < list->count ; i++) { + /* determine if the list item is a path or a name */ + if (strchr(list->items[i], settings->fileSeparator) == NULL) { + /* compare only the name */ + const char *dirpart = strrchr(dir, settings->fileSeparator); + if (dirpart == NULL) { + dirpart = dir; + } else { + dirpart++; + } + if (pathcmp(list->items[i], dirpart) == 0) { + return true; + } + } else { + /* compare the full paths */ + char* absdir = make_path_absolute(dir); + if (pathcmp(list->items[i], absdir) == 0) { + free(absdir); + return true; + } + free(absdir); + } + } return false; } @@ -208,9 +278,16 @@ if (!S_ISREG(filelist->st_mode)) { if (S_ISDIR(filelist->st_mode)) { if (settings->recursive) { - if (is_dir_excluded(settings->excludeDirs, filelist->filename)) { + if (is_dir_excluded(settings, filelist->filename)) { if (!settings->matchesOnly && settings->verbose) { - // TODO: print "no match" + /* Print hint */ + outbuf = malloc(81); + snprintf(outbuf, 81, "%*s%*s%19s\n", + filelist->displayname_len + scanner.spaces, + filelist->displayname, + 60 - filelist->displayname_len - scanner.spaces, + "", "no match"); + add_string(output, outbuf); } } else { string_list_t *recoutput = settings->verbose ? new_string_list_t() : NULL; @@ -343,3 +420,32 @@ free(freethis); } } + +char *make_path_absolute(const char *path) { + static const char *cwd = NULL; + static size_t cwdlen = 0; +#ifdef _WIN32 + static char fs = '\\'; +#else + static char fs = '/'; +#endif /* _WIN32 */ + if (path_is_relative(path)) { + if (cwdlen == 0) { + get_working_dir(&cwd, &cwdlen); + } + size_t pathlen = strlen(path); + char *result = malloc(pathlen+cwdlen+1); + const char *part = path; + size_t partlen = pathlen; + if (part[0] == '.' && part[1] == fs) { + part += 2; + partlen -= 2; + } + memcpy(result, cwd, cwdlen); + memcpy(result+cwdlen, part, partlen); + result[cwdlen+partlen] = '\0'; + return result; + } else { + return strdup(path); + } +} diff -r 9637e3efb8e7 -r 8a20001544c1 src/scanner.h --- a/src/scanner.h Tue Jun 30 12:00:16 2026 +0200 +++ b/src/scanner.h Tue Jun 30 14:19:08 2026 +0200 @@ -57,6 +57,7 @@ scanresult_t* new_scanresult_t(settings_t* settings); void destroy_scanresult_t(scanresult_t*); +char *make_path_absolute(const char *path); #ifdef _cplusplus }