Wed, 31 May 2017 11:40:07 +0200
replaces Makefiles with autoconf files
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 * Copyright 2013 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 *
26 * cline.c
27 *
28 * Created on: 23.05.2011
29 * Author: Mike
30 */
32 #include "cline.h"
33 #include "scanner.h"
34 #include "settings.h"
35 #include "arguments.h"
36 #include "regex_parser.h"
38 void printHelpText() {
39 printf(
40 "\nUsage:"
41 "\n cline [Options] [Directories...]"
42 "\n cline [Options] [Directories...]"
43 "\n\nCounts the line terminator characters (\\n) within all"
44 " files in the specified\ndirectories."
45 "\n\nOptions:"
46 "\n -b <level> - binary file heuristics level (default medium)"
47 "\n One of: ignore low medium high"
48 "\n -E <pattern> - Excludes any line matching the <pattern>"
49 "\n -e <start> <end> - Excludes lines between <start> and <end>"
50 "\n You may use these options multiple times"
51 "\n -h, --help - this help text"
52 "\n -m - print information about matching files only"
53 "\n -s <suffixes> - only count files with these suffixes (separated"
54 "\n by commas)"
55 "\n -S <suffixes> - count any file except those with these suffixes"
56 "\n (separated by commas)"
57 "\n -r, -R - includes subdirectories"
58 "\n -v, --version - print out version information"
59 "\n -V - turn verbose output off, print the result only"
60 "\n\nShortcuts:"
61 "\n --exclude-cstyle-comments"
62 "\n = -E \"\\s*//\" -e \"\\s*/\\*\" \"\\*/\\s*\""
63 "\n\n"
64 "The default call without any options is:"
65 "\n cline ./\n\n"
66 "So each file in the working directory is counted. If you want to count C"
67 "\nsource code in your working directory and its subdirectories, type:"
68 "\n cline -rs .c\n"
69 "\nIf you want to exclude comment lines, you may use the -e/-E option."
70 "\nAfter a line matches the regex pattern <start> any following line is"
71 "\nnot counted unless a line matches the <end> pattern. A line is still "
72 "\ncounted when it does not start or end with the respective patterns."
73 "\nPlease note, that cline does not remove whitespace characters as this"
74 "\nmight not be reasonable in some cases."
75 "\n\nExample (C without comments):"
76 "\n cline -s .c,.h --exclude-cstyle-comments"
77 "\n");
78 }
80 int exit_with_version(settings_t* settings) {
81 printf("cline - Version: %s\n", VERSION);
82 destroy_settings_t(settings);
83 return 0;
84 }
86 int exit_with_help(settings_t* settings, int code) {
87 printHelpText();
88 destroy_settings_t(settings);
89 return code;
90 }
92 int main(int argc, char** argv) {
94 /* Settings */
95 settings_t *settings = new_settings_t();
96 if (settings == NULL) {
97 fprintf(stderr, "Memory allocation failed.\n");
98 return 1;
99 }
101 /* Get arguments */
102 string_list_t *directories = new_string_list_t();
103 if (directories == NULL) {
104 fprintf(stderr, "Memory allocation failed.\n");
105 return 1;
106 }
107 char* includeSuffix = NULL;
108 char* excludeSuffix = NULL;
109 int checked = 0;
111 for (int t = 1 ; t < argc ; t++) {
113 int argflags = checkArgument(argv[t], "hsSrRmvVbeE");
114 int paropt = 0;
116 /* s */
117 if ((argflags & 2) > 0) {
118 if (!checkParamOpt(&paropt) || registerArgument(&checked, 2)) {
119 return exit_with_help(settings, 1);
120 }
121 t++;
122 if (t >= argc) {
123 return exit_with_help(settings, 1);
124 }
125 includeSuffix = argv[t];
126 }
127 /* S */
128 if ((argflags & 4) > 0) {
129 if (!checkParamOpt(&paropt) || registerArgument(&checked, 4)) {
130 return exit_with_help(settings, 1);
131 }
132 t++;
133 if (t >= argc) {
134 return exit_with_help(settings, 1);
135 }
136 excludeSuffix = argv[t];
137 }
138 /* h */
139 if ((argflags & 1) > 0 || strcmp(argv[t], "--help") == 0) {
140 return exit_with_help(settings, 0);
141 }
142 /* r, R */
143 if ((argflags & 24) > 0) {
144 if (registerArgument(&checked, 24)) {
145 return exit_with_help(settings, 1);
146 }
147 settings->recursive = true;
148 }
149 /* m */
150 if ((argflags & 32) > 0) {
151 if (registerArgument(&checked, 32)) {
152 return exit_with_help(settings, 1);
153 }
154 settings->matchesOnly = true;
155 }
156 /* v */
157 if ((argflags & 64) > 0 || strcmp(argv[t], "--version") == 0) {
158 return exit_with_version(settings);
159 }
160 /* V */
161 if ((argflags & 128) > 0) {
162 if (registerArgument(&checked, 128)) {
163 return exit_with_help(settings, 1);
164 }
165 settings->verbose = false;
166 }
167 /* b */
168 if ((argflags & 256) > 0) {
169 if (!checkParamOpt(&paropt) || registerArgument(&checked, 256)) {
170 return exit_with_help(settings, 1);
171 }
172 t++;
173 if (t >= argc) {
174 return exit_with_help(settings, 1);
175 }
176 if (strcasecmp(argv[t], "ignore") == 0) {
177 settings->bfileHeuristics->level = BFILE_IGNORE;
178 } else if (strcasecmp(argv[t], "low") == 0) {
179 settings->bfileHeuristics->level = BFILE_LOW_ACCURACY;
180 } else if (strcasecmp(argv[t], "medium") == 0) {
181 settings->bfileHeuristics->level = BFILE_MEDIUM_ACCURACY;
182 } else if (strcasecmp(argv[t], "high") == 0) {
183 settings->bfileHeuristics->level = BFILE_HIGH_ACCURACY;
184 } else {
185 return exit_with_help(settings, 1);
186 }
187 }
188 /* e */
189 if ((argflags & 512) > 0) {
190 if (!checkParamOpt(&paropt) || t + 2 >= argc) {
191 return exit_with_help(settings, 1);
192 }
193 t++; add_string(settings->regex->pattern_list, argv[t]);
194 t++; add_string(settings->regex->pattern_list, argv[t]);
195 }
196 /* E */
197 if ((argflags & 1024) > 0) {
198 t++;
199 if (!checkParamOpt(&paropt) || t >= argc) {
200 return exit_with_help(settings, 1);
201 }
202 add_string(settings->regex->pattern_list, argv[t]);
203 add_string(settings->regex->pattern_list, "$");
204 }
205 if (argflags == 0) {
206 /* SHORTCUTS */
207 /* exclude-cstyle-comments */
208 if (strcmp(argv[t], "--exclude-cstyle-comments") == 0) {
209 add_string(settings->regex->pattern_list, "\\s*//");
210 add_string(settings->regex->pattern_list, "$");
211 add_string(settings->regex->pattern_list, "\\s*/\\*");
212 add_string(settings->regex->pattern_list, "\\*/\\s*");
213 }
214 /* Path */
215 else {
216 add_string(directories, argv[t]);
217 }
218 }
219 }
221 /* Find tokens */
222 parseCSL(includeSuffix, settings->includeSuffixes);
223 parseCSL(excludeSuffix, settings->excludeSuffixes);
225 /* Scan directories */
226 if (regex_compile_all(settings->regex)) {
227 /* Don't waste memory when only the total sum is needed */
228 string_list_t *output = settings->verbose ? new_string_list_t() : NULL;
229 char *outbuf;
231 int lineSum = 0, lines;
232 if (directories->count == 0) {
233 add_string(directories, ".");
234 }
235 for (int t = 0 ; t < directories->count ; t++) {
236 lines = scanDirectory((scanner_t){directories->items[t], 0}, settings,
237 output);
238 lineSum += lines;
239 if (directories->count > 1 ) {
240 outbuf = (char*) malloc(81);
241 memset(outbuf, '-', 79);
242 outbuf[79] = '\n';
243 outbuf[80] = 0;
244 add_string(output, outbuf);
245 outbuf = (char*) malloc(81);
246 snprintf(outbuf, 81, "%-63s%10d lines\n", directories->items[t], lines);
247 add_string(output, outbuf);
248 outbuf = (char*) malloc(81);
249 memset(outbuf, '-', 79);
250 outbuf[79] = '\n';
251 outbuf[80] = 0;
252 add_string(output, outbuf);
253 }
254 }
255 destroy_string_list_t(directories);
257 /* Print result */
258 if (settings->verbose) {
259 for (int i = 0 ; i < output->count ; i++) {
260 printf("%s", output->items[i]);
261 free(output->items[i]);
262 }
264 for (int t = 0 ; t < 79 ; t++) {
265 printf("=");
266 }
267 printf("\n%73d lines\n", lineSum);
269 if (settings->confusing_lnlen &&
270 settings->regex->pattern_list->count > 0) {
272 printf("\nSome files contain too long lines.\n"
273 "The regex parser currently supports a maximum line length of %d."
274 "\nThe result might be wrong.\n", REGEX_MAX_LINELENGTH);
275 }
276 } else {
277 printf("%d", lineSum);
278 }
279 destroy_string_list_t(output);
280 destroy_settings_t(settings);
281 }
283 fflush(stdout);
284 fflush(stderr);
285 return 0;
286 }