Mon, 27 Jul 2020 17:44:47 +0200
fixes missing files in dist package
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 * Copyright 2018 Mike Becker. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
27 #include "cline.h"
28 #include "scanner.h"
29 #include "settings.h"
30 #include "arguments.h"
31 #include "regex_parser.h"
33 void printHelpText() {
34 printf(
35 "\nUsage:"
36 "\n cline [Options] [Directories...]"
37 "\n\nCounts the line terminator characters (\\n) within all"
38 " files in the specified\ndirectories."
39 "\n\nOptions:"
40 "\n -b <level> - binary file heuristics level (default medium)"
41 "\n One of: ignore low medium high"
42 "\n -E <pattern> - Excludes any line matching the <pattern>"
43 "\n -e <start> <end> - Excludes lines between <start> and <end>"
44 "\n You may use these options multiple times"
45 "\n -h, --help - this help text"
46 "\n -i - print out individual sums per file extension"
47 "\n (cannot be used together with -V)"
48 "\n -m - print information about matching files only"
49 "\n -s <suffixes> - only count files with these suffixes (separated"
50 "\n by commas)"
51 "\n -S <suffixes> - count any file except those with these suffixes"
52 "\n (separated by commas)"
53 "\n -r, -R - includes subdirectories"
54 "\n -v, --version - print out version information"
55 "\n -V - turn verbose output off, print the result only"
56 "\n\nShortcuts:"
57 "\n --exclude-cstyle-comments : -E '\\s*//' -e '\\s*/\\*' '\\*/\\s*'"
58 "\n --exclude-blank-lines : -E '^\\s*$'"
59 "\n\n"
60 "The default call without any options is:"
61 "\n cline ./\n\n"
62 "So each file in the working directory is counted. If you want to count C"
63 "\nsource code in your working directory and its subdirectories, type:"
64 "\n cline -rs .c\n"
65 "\nIf you want to exclude comment lines, you may use the -e/-E option."
66 "\nAfter a line matches the regex pattern <start> any following line is"
67 "\nnot counted unless a line matches the <end> pattern. A line is still "
68 "\ncounted when it does not start or end with the respective patterns."
69 "\nPlease note, that cline does not remove whitespace characters as this"
70 "\nmight not be reasonable in some cases."
71 "\n\nExample (C without comments):"
72 "\n cline -s .c,.h --exclude-cstyle-comments"
73 "\n");
74 }
76 int exit_with_version(settings_t* settings) {
77 printf("cline - Version: " VERSION "\n");
78 destroy_settings_t(settings);
79 return 0;
80 }
82 int exit_with_help(settings_t* settings, int code) {
83 printf("cline - Version: " VERSION "\n");
84 printHelpText();
85 destroy_settings_t(settings);
86 return code;
87 }
89 int main(int argc, char** argv) {
91 /* Settings */
92 settings_t *settings = new_settings_t();
93 if (settings == NULL) {
94 fprintf(stderr, "Memory allocation failed.\n");
95 return 1;
96 }
98 /* Get arguments */
99 string_list_t *directories = new_string_list_t();
100 if (directories == NULL) {
101 fprintf(stderr, "Memory allocation failed.\n");
102 return 1;
103 }
104 char* includeSuffix = NULL;
105 char* excludeSuffix = NULL;
106 int checked = 0;
108 for (int t = 1 ; t < argc ; t++) {
110 int argflags = checkArgument(argv[t], "hsSrRmvVbeEi");
111 int paropt = 0;
113 /* h */
114 if ((argflags & 1) > 0 || strcmp(argv[t], "--help") == 0) {
115 return exit_with_help(settings, 0);
116 }
117 /* s */
118 if ((argflags & 2) > 0) {
119 if (!checkParamOpt(&paropt) || registerArgument(&checked, 2)) {
120 return exit_with_help(settings, 1);
121 }
122 t++;
123 if (t >= argc) {
124 return exit_with_help(settings, 1);
125 }
126 includeSuffix = argv[t];
127 }
128 /* S */
129 if ((argflags & 4) > 0) {
130 if (!checkParamOpt(&paropt) || registerArgument(&checked, 4)) {
131 return exit_with_help(settings, 1);
132 }
133 t++;
134 if (t >= argc) {
135 return exit_with_help(settings, 1);
136 }
137 excludeSuffix = argv[t];
138 }
139 /* r, R */
140 if ((argflags & 24) > 0) {
141 if (registerArgument(&checked, 24)) {
142 return exit_with_help(settings, 1);
143 }
144 settings->recursive = true;
145 }
146 /* m */
147 if ((argflags & 32) > 0) {
148 if (registerArgument(&checked, 32)) {
149 return exit_with_help(settings, 1);
150 }
151 settings->matchesOnly = true;
152 }
153 /* v */
154 if ((argflags & 64) > 0 || strcmp(argv[t], "--version") == 0) {
155 return exit_with_version(settings);
156 }
157 /* V */
158 if ((argflags & 128) > 0) {
159 if (registerArgument(&checked, 128)) {
160 return exit_with_help(settings, 1);
161 }
162 settings->verbose = false;
163 }
164 /* b */
165 if ((argflags & 256) > 0) {
166 if (!checkParamOpt(&paropt) || registerArgument(&checked, 256)) {
167 return exit_with_help(settings, 1);
168 }
169 t++;
170 if (t >= argc) {
171 return exit_with_help(settings, 1);
172 }
173 if (strcasecmp(argv[t], "ignore") == 0) {
174 settings->bfileHeuristics->level = BFILE_IGNORE;
175 } else if (strcasecmp(argv[t], "low") == 0) {
176 settings->bfileHeuristics->level = BFILE_LOW_ACCURACY;
177 } else if (strcasecmp(argv[t], "medium") == 0) {
178 settings->bfileHeuristics->level = BFILE_MEDIUM_ACCURACY;
179 } else if (strcasecmp(argv[t], "high") == 0) {
180 settings->bfileHeuristics->level = BFILE_HIGH_ACCURACY;
181 } else {
182 return exit_with_help(settings, 1);
183 }
184 }
185 /* e */
186 if ((argflags & 512) > 0) {
187 if (!checkParamOpt(&paropt) || t + 2 >= argc) {
188 return exit_with_help(settings, 1);
189 }
190 t++; add_string(settings->regex->pattern_list, argv[t]);
191 t++; add_string(settings->regex->pattern_list, argv[t]);
192 }
193 /* E */
194 if ((argflags & 1024) > 0) {
195 t++;
196 if (!checkParamOpt(&paropt) || t >= argc) {
197 return exit_with_help(settings, 1);
198 }
199 add_string(settings->regex->pattern_list, argv[t]);
200 add_string(settings->regex->pattern_list, "$");
201 }
202 /* i */
203 if ((argflags & 2048) > 0) {
204 // cannot be used together with -V
205 if (registerArgument(&checked, 128)) {
206 return exit_with_help(settings, 1);
207 }
208 settings->individual_sums = true;
209 }
210 if (argflags == 0) {
211 /* SHORTCUTS */
212 if (strcmp(argv[t], "--exclude-cstyle-comments") == 0) {
213 add_string(settings->regex->pattern_list, "\\s*//");
214 add_string(settings->regex->pattern_list, "$");
215 add_string(settings->regex->pattern_list, "\\s*/\\*");
216 add_string(settings->regex->pattern_list, "\\*/\\s*");
217 } else if (strcmp(argv[t], "--exclude-blank-lines") == 0) {
218 add_string(settings->regex->pattern_list, "^\\s*$");
219 add_string(settings->regex->pattern_list, "$");
220 }
221 /* Path */
222 else {
223 add_string(directories, argv[t]);
224 }
225 }
226 }
228 /* Find tokens */
229 parseCSL(includeSuffix, settings->includeSuffixes);
230 parseCSL(excludeSuffix, settings->excludeSuffixes);
232 /* Scan directories */
233 if (regex_compile_all(settings->regex)) {
234 scanresult_t* result = new_scanresult_t(settings);
235 /* Don't waste memory when only the total sum is needed */
236 string_list_t *output = settings->verbose ? new_string_list_t() : NULL;
237 char *outbuf;
239 int total = 0;
240 if (directories->count == 0) {
241 add_string(directories, ".");
242 }
243 for (int t = 0 ; t < directories->count ; t++) {
244 scanDirectory((scanner_t){directories->items[t], 0}, settings,
245 output, result);
246 total += result->lines;
247 if (directories->count > 1 ) {
248 outbuf = (char*) malloc(81);
249 memset(outbuf, '-', 79);
250 outbuf[79] = '\n';
251 outbuf[80] = 0;
252 add_string(output, outbuf);
253 outbuf = (char*) malloc(81);
254 snprintf(outbuf, 81, "%-63s%10d lines\n", directories->items[t],
255 result->lines);
256 add_string(output, outbuf);
257 outbuf = (char*) malloc(81);
258 memset(outbuf, '-', 79);
259 outbuf[79] = '\n';
260 outbuf[80] = 0;
261 add_string(output, outbuf);
262 }
263 }
264 destroy_string_list_t(directories);
266 /* Print result */
267 if (settings->verbose) {
268 for (int i = 0 ; i < output->count ; i++) {
269 printf("%s", output->items[i]);
270 free(output->items[i]);
271 }
273 if (result->ext) {
274 if (result->ext->count > 0) {
275 for (int t = 0 ; t < 79 ; t++) {
276 printf("=");
277 }
278 printf("\nIndividual sums:\n");
279 for (int t = 0 ; t < result->ext->count ; t++) {
280 printf(" %-62s%10d lines\n",
281 result->ext->extensions[t],
282 result->ext->lines[t]);
283 }
284 }
285 }
287 for (int t = 0 ; t < 79 ; t++) {
288 printf("=");
289 }
290 printf("\n%73d lines\n", total);
292 if (settings->confusing_lnlen &&
293 settings->regex->pattern_list->count > 0) {
295 printf("\nSome files contain too long lines.\n"
296 "The regex parser currently supports a maximum line length of %d."
297 "\nThe result might be wrong.\n", REGEX_MAX_LINELENGTH);
298 }
299 } else {
300 printf("%d", total);
301 }
302 destroy_scanresult_t(result);
303 destroy_string_list_t(output);
304 destroy_settings_t(settings);
305 }
307 fflush(stdout);
308 fflush(stderr);
309 return 0;
310 }