Mon, 07 Apr 2025 20:43:52 +0200
implement -d option (issue #489) and various improvements
fixes #636
resolves #638
src/Makefile | file | annotate | diff | comparison | revisions | |
src/cline.c | file | annotate | diff | comparison | revisions | |
src/cline.h | file | annotate | diff | comparison | revisions | |
src/scanner.c | file | annotate | diff | comparison | revisions | |
src/settings.c | file | annotate | diff | comparison | revisions | |
src/settings.h | file | annotate | diff | comparison | revisions | |
src/stdinc.h | file | annotate | diff | comparison | revisions | |
vs/cline.vcxproj | file | annotate | diff | comparison | revisions | |
vs/cline.vcxproj.filters | file | annotate | diff | comparison | revisions |
--- a/src/Makefile Sun Nov 10 14:06:03 2024 +0100 +++ b/src/Makefile Mon Apr 07 20:43:52 2025 +0200 @@ -50,7 +50,7 @@ echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $< -$(BUILD_DIR)/cline.o: cline.c cline.h stdinc.h settings.h string_list.h \ +$(BUILD_DIR)/cline.o: cline.c stdinc.h settings.h string_list.h \ bfile_heuristics.h regex_parser.h scanner.h arguments.h echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $<
--- a/src/cline.c Sun Nov 10 14:06:03 2024 +0100 +++ b/src/cline.c Mon Apr 07 20:43:52 2025 +0200 @@ -1,5 +1,5 @@ /* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * Copyright 2018 Mike Becker. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,13 +24,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "cline.h" +#ifndef VERSION +#error "VERSION macro must be set by build system" +#endif + +#include "stdinc.h" +#include "settings.h" #include "scanner.h" -#include "settings.h" #include "arguments.h" #include "regex_parser.h" -void printHelpText() { +static void printHelpText() { printf( "\nUsage:" "\n cline [Options] [Directories...]" @@ -40,6 +44,7 @@ "\n -b <level> - binary file heuristics level (default medium)" "\n One of: ignore low medium high" "\n -c - Count non-whitespace characters instead of lines" + "\n -d - Report only directory sums" "\n -E <pattern> - Excludes any line matching the <pattern>" "\n -e <start> <end> - Excludes lines between <start> and <end>" "\n You may use these options multiple times" @@ -74,19 +79,22 @@ "\n"); } -int exit_with_version(settings_t* settings) { +static int exit_with_version(settings_t* settings) { printf("cline - Version: " VERSION "\n"); destroy_settings_t(settings); return 0; } -int exit_with_help(settings_t* settings, int code) { +static int exit_with_help(settings_t* settings, int code) { printf("cline - Version: " VERSION "\n"); printHelpText(); destroy_settings_t(settings); return code; } +static const char * sepline_double = "===============================================================================\n"; +static const char * sepline_single = "-------------------------------------------------------------------------------\n"; + int main(int argc, char** argv) { /* Settings */ @@ -108,7 +116,7 @@ for (int t = 1 ; t < argc ; t++) { - int argflags = checkArgument(argv[t], "hsSrRmvVbeEic"); + int argflags = checkArgument(argv[t], "hsSrRmvVbeEicd"); int paropt = 0; /* h */ @@ -203,11 +211,12 @@ /* i */ if ((argflags & 2048) > 0) { /* cannot be used together with -V */ - if (registerArgument(&checked, 128)) { + if ((checked & 128) > 0) { return exit_with_help(settings, 1); } settings->individual_sums = true; } + /* c */ if ((argflags & 4096) > 0) { if (registerArgument(&checked, 4096)) { return exit_with_help(settings, 1); @@ -215,6 +224,16 @@ settings->count_chars = true; settings->regex->count_chars = true; } + /* d */ + if ((argflags & 8192) > 0) { + if (registerArgument(&checked, 8192)) { + return exit_with_help(settings, 1); + } + /* ignored together with -V */ + if ((checked & 128) == 0) { + settings->dirsOnly = true; + } + } if (argflags == 0) { /* SHORTCUTS */ if (strcmp(argv[t], "--exclude-cstyle-comments") == 0) { @@ -247,33 +266,25 @@ unsigned total = 0; if (directories->count == 0) { - add_string(directories, "."); + add_string(directories, "./"); } for (unsigned t = 0 ; t < directories->count ; t++) { scanDirectory((scanner_t){directories->items[t], 0}, settings, output, result); total += result->result; - if (directories->count > 1 ) { - outbuf = (char*) malloc(81); - memset(outbuf, '-', 79); - outbuf[79] = '\n'; - outbuf[80] = 0; - add_string(output, outbuf); + if (directories->count > 1) { + add_string(output, strdup(sepline_single)); outbuf = (char*) malloc(81); snprintf(outbuf, 81, "%-63s%10u %s\n", directories->items[t], result->result, result_type); add_string(output, outbuf); - outbuf = (char*) malloc(81); - memset(outbuf, '-', 79); - outbuf[79] = '\n'; - outbuf[80] = 0; - add_string(output, outbuf); + add_string(output, strdup(sepline_single)); } } destroy_string_list_t(directories); /* Print result */ - if (settings->verbose) { + if (output != NULL) { for (int i = 0 ; i < output->count ; i++) { printf("%s", output->items[i]); free(output->items[i]); @@ -281,9 +292,7 @@ if (result->ext) { if (result->ext->count > 0) { - for (unsigned t = 0 ; t < 79 ; t++) { - printf("="); - } + fwrite(sepline_double, 1, 80, stdout); printf("\nIndividual sums:\n"); for (unsigned t = 0 ; t < result->ext->count ; t++) { printf(" %-62s%10u %s\n", @@ -293,11 +302,14 @@ } } } - - for (unsigned t = 0 ; t < 79 ; t++) { - printf("="); + + if (output->count > 0) { + fwrite(sepline_double, 1, 80, stdout); + printf("%73d %s\n", total, result_type); + } else { + /* If we only need to output a total, output it differently */ + printf("%d %s\n", total, result_type); } - printf("\n%73d %s\n", total, result_type); if (settings->confusing_lnlen && settings->regex->pattern_list->count > 0) {
--- a/src/cline.h Sun Nov 10 14:06:03 2024 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * Copyright 2018 Mike Becker. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CLINE_H_ -#define CLINE_H_ - -#ifndef VERSION -#error "VERSION macro must be set by build system" -#endif - -#include "stdinc.h" -#include "settings.h" - -#ifdef _cplusplus -extern "C" { -#endif - -void printHelpText(); -int exit_with_version(settings_t*); -int exit_with_help(settings_t*, int); - -#ifdef _cplusplus -} -#endif - -#endif /* CLINE_H_ */
--- a/src/scanner.c Sun Nov 10 14:06:03 2024 +0100 +++ b/src/scanner.c Mon Apr 07 20:43:52 2025 +0200 @@ -199,27 +199,29 @@ /* Scan subdirectories */ if (!S_ISREG(filelist->st_mode)) { - if (settings->recursive && S_ISDIR(filelist->st_mode)) { - string_list_t *recoutput = new_string_list_t(); - scanresult_t recresult; - recresult.ext = result->ext; - scanDirectory( - (scanner_t) {filelist->filename, scanner.spaces+1}, - settings, recoutput, &recresult); - result->result += recresult.result; - if (!settings->matchesOnly || recoutput->count > 0) { - outbuf = (char*) malloc(81); - snprintf(outbuf, 81, "%*s/%*s%13u %s\n", - filelist->displayname_len+scanner.spaces, filelist->displayname, - 60-filelist->displayname_len-scanner.spaces-1, "", - recresult.result, result_type); - add_string(output, outbuf); - for (unsigned i = 0 ; i < recoutput->count ; i++) { - add_string(output, recoutput->items[i]); + if (S_ISDIR(filelist->st_mode)) { + if (settings->recursive) { + string_list_t *recoutput = new_string_list_t(); + scanresult_t recresult; + recresult.ext = result->ext; + scanDirectory( + (scanner_t) {filelist->filename, scanner.spaces+1}, + settings, recoutput, &recresult); + result->result += recresult.result; + if (!settings->matchesOnly || recresult.result > 0) { + outbuf = (char*) malloc(81); + snprintf(outbuf, 81, "%*s/%*s%13u %s\n", + filelist->displayname_len+scanner.spaces, filelist->displayname, + 60-filelist->displayname_len-scanner.spaces-1, "", + recresult.result, result_type); + add_string(output, outbuf); + for (unsigned i = 0 ; i < recoutput->count ; i++) { + add_string(output, recoutput->items[i]); + } } + destroy_string_list_t(recoutput); } - destroy_string_list_t(recoutput); - } else { + } else if (!settings->matchesOnly) { outbuf = (char*) malloc(81); snprintf(outbuf, 81, "%*s\n", filelist->displayname_len+scanner.spaces, @@ -288,7 +290,7 @@ /* Print and sum line count */ if (bfile) { - if (!settings->matchesOnly) { + if (!settings->matchesOnly && !settings->dirsOnly) { outbuf = (char*) malloc(81); snprintf(outbuf, 81, "%*s%*s%19s\n", filelist->displayname_len+scanner.spaces, @@ -299,20 +301,22 @@ } else { addResultPerExtension(result->ext, filelist->ext, res_value); result->result += res_value; - outbuf = (char*) malloc(81); - snprintf(outbuf, 81, "%*s%*s%13u %s\n", - filelist->displayname_len+scanner.spaces, - filelist->displayname, - 60-filelist->displayname_len-scanner.spaces, - "", - res_value, - result_type - ); - add_string(output, outbuf); + if (!settings->dirsOnly) { + outbuf = (char*) malloc(81); + snprintf(outbuf, 81, "%*s%*s%13u %s\n", + filelist->displayname_len+scanner.spaces, + filelist->displayname, + 60-filelist->displayname_len-scanner.spaces, + "", + res_value, + result_type + ); + add_string(output, outbuf); + } } } } else { - if (!settings->matchesOnly) { + if (!settings->matchesOnly && !settings->dirsOnly) { /* Print hint */ outbuf = (char*) malloc(81); snprintf(outbuf, 81, "%*s%*s%19s\n",
--- a/src/settings.c Sun Nov 10 14:06:03 2024 +0100 +++ b/src/settings.c Mon Apr 07 20:43:52 2025 +0200 @@ -44,6 +44,7 @@ settings->regex = new_regex_parser_t(); settings->individual_sums = false; settings->count_chars = false; + settings->dirsOnly = false; } return settings;
--- a/src/settings.h Sun Nov 10 14:06:03 2024 +0100 +++ b/src/settings.h Mon Apr 07 20:43:52 2025 +0200 @@ -44,6 +44,7 @@ bool confusing_lnlen; /* this flag is set by the scanner */ bool individual_sums; bool count_chars; + bool dirsOnly; } settings_t; #ifdef _cplusplus
--- a/src/stdinc.h Sun Nov 10 14:06:03 2024 +0100 +++ b/src/stdinc.h Mon Apr 07 20:43:52 2025 +0200 @@ -32,6 +32,7 @@ #include <stdbool.h> #include <stdlib.h> #include <dirent.h> +#include <assert.h> #ifdef _MSC_VER #define strcasecmp _stricmp #if __STDC_VERSION__ < 202300L
--- a/vs/cline.vcxproj Sun Nov 10 14:06:03 2024 +0100 +++ b/vs/cline.vcxproj Mon Apr 07 20:43:52 2025 +0200 @@ -22,7 +22,6 @@ <ItemGroup> <ClInclude Include="..\src\arguments.h" /> <ClInclude Include="..\src\bfile_heuristics.h" /> - <ClInclude Include="..\src\cline.h" /> <ClInclude Include="..\src\regex_parser.h" /> <ClInclude Include="..\src\scanner.h" /> <ClInclude Include="..\src\settings.h" />
--- a/vs/cline.vcxproj.filters Sun Nov 10 14:06:03 2024 +0100 +++ b/vs/cline.vcxproj.filters Mon Apr 07 20:43:52 2025 +0200 @@ -40,9 +40,6 @@ <ClInclude Include="..\src\bfile_heuristics.h"> <Filter>Header</Filter> </ClInclude> - <ClInclude Include="..\src\cline.h"> - <Filter>Header</Filter> - </ClInclude> <ClInclude Include="..\src\regex_parser.h"> <Filter>Header</Filter> </ClInclude>