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 */