Thu, 02 Feb 2012 16:55:51 +0100
fixed author note
1 /*
2 * cline.c
3 *
4 * Created on: 23.05.2011
5 * Author: Mike
6 */
8 #include "cline.h"
9 #include "scanner.h"
10 #include "settings.h"
11 #include "arguments.h"
12 #include "stream.h"
13 #include "regex_parser.h"
15 void printHelpText() {
16 const char* helpText =
17 "\nUsage:"
18 "\n cline [Options] [Directory]"
19 "\n cline [Options] [Directory]"
20 "\n\nCounts the line terminator characters (\\n) within all"
21 " files in the specified\ndirectory."
22 "\n\nOptions:"
23 "\n -b <level> - binary file heuristics level (default medium)"
24 "\n One of: ignore low medium high"
25 "\n -E <pattern> - Excludes any line matching the <pattern>"
26 "\n -e <start> <end> - Excludes lines between <start> and <end>"
27 "\n You may use these options multiple times"
28 "\n -h, --help - this help text"
29 "\n -m - print information about matching files only"
30 "\n -s <suffixes> - only count files with these suffixes (separated"
31 "\n by commas)"
32 "\n -S <suffixes> - count any file except those with these suffixes"
33 "\n (separated by commas)"
34 "\n -r, -R - includes subdirectories"
35 "\n -v, --version - print out version information"
36 "\n -V - turn verbose output off, print the result only"
37 "\n\n"
38 "The default call without any options is:"
39 "\n cline ./\n\n"
40 "So each file in the working directory is counted. If you want to count C"
41 "\nsource code in your working directory and its subdirectories, type:"
42 "\n cline -rs .c\n"
43 "\nIf you want to exclude comment lines, you may use the -e/-E option."
44 "\nAfter a line matches the regex pattern <start> any following line is"
45 "\nnot counted unless a line matches the <end> pattern. A line is still "
46 "\ncounted when it does not start or end with the respective patterns."
47 "\nPlease note, that cline does not remove whitespace characters as this"
48 "\nmight not be reasonable in some cases."
49 "\n\nExample (C comments):"
50 "\n cline -s .c,.h -E \"\\s*//\" -e \"\\s*/\\*\" \"\\*/\\s*\"";
52 printf(helpText);
53 }
55 int exit_with_version(settings_t* settings) {
56 printf("cline - Revision: %s", VERSION);
57 destroy_settings_t(settings);
58 return 0;
59 }
61 int exit_with_help(settings_t* settings, int code) {
62 printHelpText();
63 destroy_settings_t(settings);
64 return code;
65 }
67 int main(int argc, char** argv) {
69 /* Settings */
70 settings_t *settings = new_settings_t();
71 if (settings == NULL) {
72 fprintf(stderr, "Memory allocation failed.\n");
73 return 1;
74 }
76 /* Get arguments */
77 char* directory = "./";
78 char* suffix = " ";
79 int checked = 0;
81 for (int t = 1 ; t < argc ; t++) {
83 int argflags = checkArgument(argv[t], "hsSrRmvVbeE");
85 /* s, S */
86 if ((argflags & 6) > 0) {
87 if (registerArgument(&checked, 6)) {
88 return exit_with_help(settings, 1);
89 }
90 settings->includeSuffixes = (argflags & 2) > 0;
91 t++;
92 if (t >= argc) {
93 return exit_with_help(settings, 1);
94 }
95 suffix = argv[t];
96 }
97 /* h */
98 if ((argflags & 1) > 0 || strcmp(argv[t], "--help") == 0) {
99 return exit_with_help(settings, 0);
100 }
101 /* r, R */
102 if ((argflags & 24) > 0) {
103 if (registerArgument(&checked, 24)) {
104 return exit_with_help(settings, 1);
105 }
106 settings->recursive = true;
107 }
108 /* m */
109 if ((argflags & 32) > 0) {
110 if (registerArgument(&checked, 32)) {
111 return exit_with_help(settings, 1);
112 }
113 settings->matchesOnly = true;
114 }
115 /* v */
116 if ((argflags & 64) > 0 || strcmp(argv[t], "--version") == 0) {
117 return exit_with_version(settings);
118 }
119 /* V */
120 if ((argflags & 128) > 0) {
121 if (registerArgument(&checked, 128)) {
122 return exit_with_help(settings, 1);
123 }
124 settings->verbose = false;
125 }
126 /* b */
127 if ((argflags & 256) > 0) {
128 if (registerArgument(&checked, 256)) {
129 return exit_with_help(settings, 1);
130 }
131 t++;
132 if (t >= argc) {
133 return exit_with_help(settings, 1);
134 }
135 if (strcasecmp(argv[t], "ignore") == 0) {
136 settings->bfileHeuristics->level = BFILE_IGNORE;
137 } else if (strcasecmp(argv[t], "low") == 0) {
138 settings->bfileHeuristics->level = BFILE_LOW_ACCURACY;
139 } else if (strcasecmp(argv[t], "medium") == 0) {
140 settings->bfileHeuristics->level = BFILE_MEDIUM_ACCURACY;
141 } else if (strcasecmp(argv[t], "high") == 0) {
142 settings->bfileHeuristics->level = BFILE_HIGH_ACCURACY;
143 } else {
144 return exit_with_help(settings, 1);
145 }
146 }
147 /* e */
148 if ((argflags & 512) > 0) {
149 if (t + 2 >= argc) {
150 return exit_with_help(settings, 1);
151 }
152 t++; add_string(settings->regex->pattern_list, argv[t]);
153 t++; add_string(settings->regex->pattern_list, argv[t]);
154 }
155 /* E */
156 if ((argflags & 1024) > 0) {
157 t++;
158 if (t >= argc) {
159 return exit_with_help(settings, 1);
160 }
161 add_string(settings->regex->pattern_list, argv[t]);
162 add_string(settings->regex->pattern_list, "$");
163 }
164 /* Path */
165 if (argflags == 0) {
166 if (registerArgument(&checked, 1024)) {
167 return exit_with_help(settings, 1);
168 }
169 directory = argv[t];
170 }
171 }
173 /* Configure output */
174 if (!settings->verbose) {
175 close_stdout();
176 }
178 /* Find tokens */
179 char* finder = strtok(suffix, ",");
180 while (finder != NULL) {
181 add_string(settings->suffixList, finder);
182 finder = strtok(NULL, ",");
183 }
185 /* Scan directory */
186 if (regex_compile_all(settings->regex)) {
187 int lines = scanDirectory((scanner_t){directory, 0}, settings);
188 destroy_settings_t(settings);
190 /* Print double line and line count */
191 for (int t = 0 ; t < 79 ; t++) {
192 printf("=");
193 }
194 printf("\n%73d lines\n", lines);
196 if (settings->confusing_lnlen && settings->regex->pattern_list->count > 0) {
197 printf("\nSome files contain too long lines.\n"
198 "The regex parser currently supports a maximum line length of %d."
199 "\nThe result might be wrong.\n", REGEX_MAX_LINELENGTH);
200 }
202 if (!settings->verbose) {
203 reopen_stdout();
204 printf("%d", lines);
205 }
206 }
208 fflush(stdout);
209 fflush(stderr);
210 return 0;
211 }