New upstream version 3.1.0
Sylvestre Ledru
5 years ago
12 | 12 | ruby/ohcount.so |
13 | 13 | ruby/ohcount_wrap.c |
14 | 14 | test/unit/run_tests.dSYM/ |
15 | build-python/ | |
16 | python/ohcount.py | |
17 | .rvmrc | |
18 | .ruby-version |
0 | fix_null_dereference_2.patch | |
1 | fix_null_dereference.patch | |
2 | txx_support.patch | |
3 | disabled_test_suite.patch | |
4 | rbconfig.patch |
0 | #!/usr/bin/env bash | |
1 | # Build script for Ohcount. | |
2 | # Written by Mitchell Foral. mitchell<att>caladbolg.net. | |
3 | ||
4 | # Options | |
5 | # Change these for your system configuration. | |
6 | if [ `uname` != "Darwin" ] | |
7 | then | |
8 | # Linux | |
9 | INC_DIR= | |
10 | LIB_DIR= | |
11 | ||
12 | if [ `uname` == "FreeBSD" ] | |
13 | then | |
14 | INC_DIR=/usr/local/include | |
15 | LIB_DIR=/usr/local/lib | |
16 | fi | |
17 | ||
18 | # You shouldn't have to change the following. | |
19 | CFLAGS=-O3 | |
20 | CFLAGS="$CFLAGS -DTMP_FILES_ARE_DT_UNKNOWN" # workaround bug on centos/SF servers | |
21 | WARN="-Wall -Wno-pointer-to-int-cast -Wno-parentheses" | |
22 | SHARED=-shared | |
23 | SHARED_NAME=libohcount.so | |
24 | RB_SHARED=-shared | |
25 | RB_SHARED_NAME=ohcount.so | |
26 | else | |
27 | # Mac OSX | |
28 | INC_DIR=/opt/local/include | |
29 | LIB_DIR=/opt/local/lib | |
30 | # You shouldn't have to change the following. | |
31 | CFLAGS="-fno-common -g" | |
32 | WARN="-Wall -Wno-parentheses" | |
33 | SHARED="-dynamiclib -L$LIB_DIR -lpcre" | |
34 | SHARED_NAME=libohcount.dylib | |
35 | RB_SHARED="-dynamic -bundle -lruby" | |
36 | RB_SHARED_NAME=ohcount.bundle | |
37 | fi | |
38 | ||
39 | # C compiler and flags | |
40 | cc="gcc -fPIC -g $CFLAGS $WARN -I$INC_DIR -L$LIB_DIR" | |
41 | ||
42 | # Ohcount source files | |
43 | files="src/sourcefile.c \ | |
44 | src/detector.c \ | |
45 | src/licenses.c \ | |
46 | src/parser.o \ | |
47 | src/loc.c \ | |
48 | src/log.c \ | |
49 | src/diff.c \ | |
50 | src/parsed_language.c \ | |
51 | src/hash/language_hash.c" | |
52 | ||
53 | # If any src/hash/*.gperf file is newer than the header files (which were | |
54 | # presumably generated together), regenerate the headers. | |
55 | build_hash_headers() | |
56 | { | |
57 | if [[ -z `ls src/hash/ | grep "_hash.h$"` || | |
58 | ! -z `find src/hash/*.gperf -newer src/hash/parser_hash.h` ]] | |
59 | then | |
60 | echo "Generating hash headers" | |
61 | sh -c "cd src/hash/ && ./generate_headers" || exit 1 | |
62 | fi | |
63 | } | |
64 | ||
65 | # If src/parser.o does not exist, or if there are Ragel parsers or parser | |
66 | # header files newer than the existing parser.o, recompile parser.o. | |
67 | build_parser_o() | |
68 | { | |
69 | if [[ ! -f src/parser.o || | |
70 | ! -z `find src/parsers/*.{h,rl} -newer src/parser.o` ]] | |
71 | then | |
72 | bash -c "cd src/parsers/ && bash ./compile" || exit 1 | |
73 | echo "Building src/parser.c (will take a while)" | |
74 | bash -c "$cc -c src/parser.c -o src/parser.o" || exit 1 | |
75 | fi | |
76 | } | |
77 | ||
78 | build_shared() | |
79 | { | |
80 | build_hash_headers | |
81 | build_parser_o | |
82 | if [[ ! -f src/$SHARED_NAME || | |
83 | ! -z `find src/*.{h,c} -newer src/$SHARED_NAME` ]] | |
84 | then | |
85 | echo "Building shared library" | |
86 | sh -c "$cc $SHARED $files -o src/$SHARED_NAME" || exit 1 | |
87 | fi | |
88 | } | |
89 | ||
90 | build_ohcount() | |
91 | { | |
92 | build_hash_headers | |
93 | build_parser_o | |
94 | echo "Building Ohcount" | |
95 | mkdir -p bin/ | |
96 | sh -c "$cc src/ohcount.c $files -o bin/ohcount -lpcre" || exit 1 | |
97 | } | |
98 | ||
99 | build_test_suite() | |
100 | { | |
101 | build_hash_headers | |
102 | build_parser_o | |
103 | echo "Building test suite" | |
104 | sh -c "$cc test/unit/all_tests.c $files -o test/unit/run_tests -lpcre" \ | |
105 | || exit 1 | |
106 | } | |
107 | ||
108 | run_test_suite() | |
109 | { | |
110 | echo "Running test suite" | |
111 | sh -c "cd test/unit/ && ./run_tests" | |
112 | } | |
113 | ||
114 | build_ruby_bindings() | |
115 | { | |
116 | arch=`ruby -rmkmf -e 'print Config::expand(CONFIG["arch"])'` | |
117 | echo "Generating Ruby bindings for $arch" | |
118 | sh -c "swig -ruby -o ruby/ohcount_wrap.c ruby/ohcount.i" || exit 1 | |
119 | mkdir -p ruby/$arch | |
120 | sh -c "$cc $RB_SHARED ruby/ohcount_wrap.c $files -o ruby/$arch/$RB_SHARED_NAME \ | |
121 | -I`ruby -rmkmf -e 'print Config::expand(CONFIG["archdir"])'` \ | |
122 | -lpcre" || exit 1 | |
123 | sh -c "cd test/unit/ruby && ruby ruby_test.rb" || exit 1 | |
124 | } | |
125 | ||
126 | if [ $# -eq 0 ] || [ $1 == "all" ] | |
127 | then | |
128 | build_ohcount | |
129 | build_test_suite | |
130 | run_test_suite | |
131 | echo $success | |
132 | elif [ $1 == "shared" ] | |
133 | then | |
134 | build_shared | |
135 | echo "Build successful; $SHARED_NAME is in src/" | |
136 | elif [ $1 == "ohcount" ] | |
137 | then | |
138 | build_ohcount | |
139 | echo "Build successful; ohcount is in bin/" | |
140 | elif [ $1 == "tests" ] | |
141 | then | |
142 | build_test_suite | |
143 | run_test_suite | |
144 | elif [ $1 == "ruby" ] | |
145 | then | |
146 | build_ruby_bindings | |
147 | echo "Build successful; $RB_SHARED_NAME is in ruby/$arch" | |
148 | elif [ $1 == "clean" ] | |
149 | then | |
150 | rm -f bin/ohcount | |
151 | rm -f test/unit/run_tests | |
152 | rm -f src/parser.o | |
153 | rm -f src/parsers/*.h | |
154 | rm -f src/hash/*.h | |
155 | rm -f src/hash/*.c | |
156 | rm -f src/$SHARED_NAME | |
157 | rm -f ruby/$RB_SHARED_NAME | |
158 | rm -rf ruby/`ruby -rmkmf -e 'print Config::expand(CONFIG["arch"])'`/* | |
159 | else | |
160 | echo "Usage: build [all|ohcount|shared|tests|ruby|clean]" | |
161 | fi |
0 | // detector.c written by Mitchell Foral. mitchell<att>caladbolg.net. | |
1 | // See COPYING for license information. | |
2 | ||
3 | #include <ctype.h> | |
4 | #include <stdio.h> | |
5 | #include <stdlib.h> | |
6 | #include <string.h> | |
7 | #include <unistd.h> | |
8 | ||
9 | #include "detector.h" | |
10 | #include "languages.h" | |
11 | #include "log.h" | |
12 | ||
13 | #include "hash/cppheader_hash.h" | |
14 | #include "hash/disambiguatefunc_hash.h" | |
15 | #include "hash/extension_hash.h" | |
16 | #include "hash/filename_hash.h" | |
17 | ||
18 | #define ISBINARY(x) (x[0] == '\1') | |
19 | #define ISAMBIGUOUS(x) (x[0] == '\2') | |
20 | #define DISAMBIGUATEWHAT(x) &x[1] | |
21 | ||
22 | const char *ohcount_detect_language(SourceFile *sourcefile) { | |
23 | const char *language = NULL; | |
24 | char *p, *pe; | |
25 | int length; | |
26 | ||
27 | // Attempt to detect based on file extension. | |
28 | length = strlen(sourcefile->ext); | |
29 | struct ExtensionMap *re = ohcount_hash_language_from_ext(sourcefile->ext, | |
30 | length); | |
31 | if (re) language = re->value; | |
32 | if (language == NULL) { | |
33 | // Try the lower-case version of this extension. | |
34 | char lowerext[length + 1]; | |
35 | strncpy(lowerext, sourcefile->ext, length); | |
36 | lowerext[length] = '\0'; | |
37 | for (p = lowerext; p < lowerext + length; p++) *p = tolower(*p); | |
38 | struct ExtensionMap *re = ohcount_hash_language_from_ext(lowerext, length); | |
39 | if (re) return re->value; | |
40 | } | |
41 | if (language) { | |
42 | if (ISAMBIGUOUS(language)) { | |
43 | // Call the appropriate function for disambiguation. | |
44 | length = strlen(DISAMBIGUATEWHAT(language)); | |
45 | struct DisambiguateFuncsMap *rd = | |
46 | ohcount_hash_disambiguate_func_from_id(DISAMBIGUATEWHAT(language), | |
47 | length); | |
48 | if (rd) return rd->value(sourcefile); | |
49 | } else return ISBINARY(language) ? NULL : language; | |
50 | } | |
51 | ||
52 | // Attempt to detect based on filename. | |
53 | length = strlen(sourcefile->filename); | |
54 | struct FilenameMap *rf = | |
55 | ohcount_hash_language_from_filename(sourcefile->filename, length); | |
56 | if (rf) return rf->value; | |
57 | ||
58 | char line[81] = { '\0' }, buf[81]; | |
59 | ||
60 | // Attempt to detect using Emacs mode line (/^-\*-\s*mode[\s:]*\w/i). | |
61 | p = ohcount_sourcefile_get_contents(sourcefile); | |
62 | pe = p; | |
63 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
64 | while (pe < eof) { | |
65 | // Get the contents of the first line. | |
66 | while (pe < eof && *pe != '\r' && *pe != '\n') pe++; | |
67 | length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); | |
68 | strncpy(line, p, length); | |
69 | line[length] = '\0'; | |
70 | if (*line == '#' && *(line + 1) == '!') { | |
71 | // First line was sh-bang; loop to get contents of second line. | |
72 | while (*pe == '\r' || *pe == '\n') pe++; | |
73 | p = pe; | |
74 | } else break; | |
75 | } | |
76 | char *eol = line + strlen(line); | |
77 | for (p = line; p < eol; p++) *p = tolower(*p); | |
78 | p = strstr(line, "-*-"); | |
79 | if (p) { | |
80 | p += 3; | |
81 | while (*p == ' ' || *p == '\t') p++; | |
82 | if (strncmp(p, "mode", 4) == 0) { | |
83 | p += 4; | |
84 | while (*p == ' ' || *p == '\t' || *p == ':') p++; | |
85 | } | |
86 | pe = p; | |
87 | while (isalnum(*pe)) pe++; | |
88 | length = pe - p; | |
89 | strncpy(buf, p, length); | |
90 | buf[length] = '\0'; | |
91 | struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); | |
92 | if (rl) return rl->name; | |
93 | } | |
94 | ||
95 | // Attempt to detect based on Unix 'file' command. | |
96 | int tmpfile = 0; | |
97 | char *path = sourcefile->filepath; | |
98 | if (sourcefile->diskpath) | |
99 | path = sourcefile->diskpath; | |
100 | if (access(path, F_OK) != 0) { // create temporary file | |
101 | path = malloc(21); | |
102 | strncpy(path, "/tmp/ohcount_XXXXXXX", 20); | |
103 | *(path + 21) = '\0'; | |
104 | int fd = mkstemp(path); | |
105 | char *contents = ohcount_sourcefile_get_contents(sourcefile); | |
106 | log_it("contents:"); | |
107 | log_it(contents); | |
108 | length = contents ? strlen(contents) : 0; | |
109 | write(fd, contents, length); | |
110 | close(fd); | |
111 | tmpfile = 1; | |
112 | } | |
113 | char command[strlen(path) + 11]; | |
114 | sprintf(command, "file -b '%s'", path); | |
115 | FILE *f = popen(command, "r"); | |
116 | if (f) { | |
117 | fgets(line, sizeof(line), f); | |
118 | char *eol = line + strlen(line); | |
119 | for (p = line; p < eol; p++) *p = tolower(*p); | |
120 | p = strstr(line, "script text"); | |
121 | if (p && p == line) { // /^script text(?: executable)? for \w/ | |
122 | p = strstr(line, "for "); | |
123 | if (p) { | |
124 | p += 4; | |
125 | pe = p; | |
126 | while (isalnum(*pe)) pe++; | |
127 | length = pe - p; | |
128 | strncpy(buf, p, length); | |
129 | buf[length] = '\0'; | |
130 | struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); | |
131 | if (rl) language = rl->name; | |
132 | } | |
133 | } else if (p) { // /(\w+)(?: -\w+)* script text/ | |
134 | do { | |
135 | p--; | |
136 | pe = p; | |
137 | while (*p == ' ') p--; | |
138 | while (p != line && isalnum(*(p - 1))) p--; | |
139 | if (p != line && *(p - 1) == '-') p--; | |
140 | } while (*p == '-'); // Skip over any switches. | |
141 | length = pe - p; | |
142 | strncpy(buf, p, length); | |
143 | buf[length] = '\0'; | |
144 | struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); | |
145 | if (rl) language = rl->name; | |
146 | } else if (strstr(line, "xml")) language = LANG_XML; | |
147 | pclose(f); | |
148 | if (tmpfile) { | |
149 | remove(path); | |
150 | free(path); | |
151 | } | |
152 | if (language) return language; | |
153 | } | |
154 | ||
155 | return NULL; | |
156 | } | |
157 | ||
158 | const char *disambiguate_aspx(SourceFile *sourcefile) { | |
159 | char *p = ohcount_sourcefile_get_contents(sourcefile); | |
160 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
161 | for (; p < eof; p++) { | |
162 | // /<%@\s*Page[^>]+Language="VB"[^>]+%>/ | |
163 | p = strstr(p, "<%@"); | |
164 | if (!p) | |
165 | break; | |
166 | char *pe = strstr(p, "%>"); | |
167 | if (p && pe) { | |
168 | p += 3; | |
169 | const int length = pe - p; | |
170 | char buf[length]; | |
171 | strncpy(buf, p, length); | |
172 | buf[length] = '\0'; | |
173 | char *eol = buf + strlen(buf); | |
174 | for (p = buf; p < eol; p++) *p = tolower(*p); | |
175 | p = buf; | |
176 | while (*p == ' ' || *p == '\t') p++; | |
177 | if (strncmp(p, "page", 4) == 0) { | |
178 | p += 4; | |
179 | if (strstr(p, "language=\"vb\"")) | |
180 | return LANG_VB_ASPX; | |
181 | } | |
182 | } | |
183 | } | |
184 | return LANG_CS_ASPX; | |
185 | } | |
186 | ||
187 | const char *disambiguate_b(SourceFile *sourcefile) { | |
188 | char *p = ohcount_sourcefile_get_contents(sourcefile); | |
189 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
190 | while (p < eof) { | |
191 | // /(implement[ \t])|(include[ \t]+"[^"]*";)| | |
192 | // ((return|break|continue).*;|(pick|case).*\{)/ | |
193 | if (strncmp(p, "implement", 9) == 0 && | |
194 | (*(p + 9) == ' ' || *(p + 9) == '\t')) | |
195 | return LANG_LIMBO; | |
196 | else if (strncmp(p, "include", 7) == 0 && | |
197 | (*(p + 7) == ' ' || *(p + 7) == '\t')) { | |
198 | p += 7; | |
199 | while (*p == ' ' || *p == '\t') p++; | |
200 | if (*p == '"') { | |
201 | while (*p != '"' && p < eof) p++; | |
202 | if (*p == '"' && *(p + 1) == ';') | |
203 | return LANG_LIMBO; | |
204 | } | |
205 | } else if (strncmp(p, "return", 6) == 0 || | |
206 | strncmp(p, "break", 5) == 0 || | |
207 | strncmp(p, "continue", 8) == 0) { | |
208 | if (strstr(p, ";")) | |
209 | return LANG_LIMBO; | |
210 | } else if (strncmp(p, "pick", 4) == 0 || | |
211 | strncmp(p, "case", 4) == 0) { | |
212 | if (strstr(p, "{")) | |
213 | return LANG_LIMBO; | |
214 | } | |
215 | p++; | |
216 | } | |
217 | return disambiguate_basic(sourcefile); | |
218 | } | |
219 | ||
220 | const char *disambiguate_basic(SourceFile *sourcefile) { | |
221 | char *p, *pe; | |
222 | int length; | |
223 | ||
224 | // Attempt to detect based on file contents. | |
225 | char line[81]; | |
226 | p = ohcount_sourcefile_get_contents(sourcefile); | |
227 | pe = p; | |
228 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
229 | while (pe < eof) { | |
230 | // Get a line at a time. | |
231 | while (pe < eof && *pe != '\r' && *pe != '\n') pe++; | |
232 | length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); | |
233 | strncpy(line, p, length); | |
234 | line[length] = '\0'; | |
235 | char *line_end = pe; | |
236 | ||
237 | p = line; | |
238 | if (isdigit(*p)) { | |
239 | // /^\d+\s+\w/ | |
240 | p++; | |
241 | while (isdigit(*p)) p++; | |
242 | if (*p == ' ' || *p == '\t') { | |
243 | p++; | |
244 | while (*p == ' ' || *p == '\t') p++; | |
245 | if (isalnum(*p)) | |
246 | return LANG_CLASSIC_BASIC; | |
247 | } | |
248 | } | |
249 | ||
250 | // Next line. | |
251 | pe = line_end; | |
252 | while (*pe == '\r' || *pe == '\n') pe++; | |
253 | p = pe; | |
254 | } | |
255 | ||
256 | // Attempt to detect from associated VB files in file context. | |
257 | char **filenames = ohcount_sourcefile_get_filenames(sourcefile); | |
258 | if (filenames) { | |
259 | int i; | |
260 | for (i = 0; filenames[i] != NULL; i++) { | |
261 | pe = filenames[i] + strlen(filenames[i]); | |
262 | p = pe; | |
263 | while (p > filenames[i] && *(p - 1) != '.') p--; | |
264 | length = pe - p; | |
265 | if (length == 3 && | |
266 | (strncmp(p, "frm", length) == 0 || | |
267 | strncmp(p, "frx", length) == 0 || | |
268 | strncmp(p, "vba", length) == 0 || | |
269 | strncmp(p, "vbp", length) == 0 || | |
270 | strncmp(p, "vbs", length) == 0)) { | |
271 | return LANG_VISUALBASIC; | |
272 | } | |
273 | } | |
274 | } | |
275 | ||
276 | return LANG_STRUCTURED_BASIC; | |
277 | } | |
278 | ||
279 | const char *disambiguate_cs(SourceFile *sourcefile) { | |
280 | // Attempt to detect based on file contents. | |
281 | char *contents = ohcount_sourcefile_get_contents(sourcefile); | |
282 | if (contents && strstr(contents, "<?cs")) | |
283 | return LANG_CLEARSILVER_TEMPLATE; | |
284 | else | |
285 | return LANG_CSHARP; | |
286 | } | |
287 | ||
288 | const char *disambiguate_fortran(SourceFile *sourcefile) { | |
289 | char *p, *pe; | |
290 | ||
291 | p = ohcount_sourcefile_get_contents(sourcefile); | |
292 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
293 | while (p < eof) { | |
294 | if (*p == ' ' && p + 5 < eof) { | |
295 | int i; | |
296 | for (i = 1; i <= 5; i++) | |
297 | if (!isdigit(*(p + i)) && *(p + i) != ' ') | |
298 | return LANG_FORTRANFIXED; // definately not f77 | |
299 | // Possibly fixed (doesn't match /^\s*\d+\s*$/). | |
300 | pe = p; | |
301 | while (*pe == ' ' || *pe == '\t') pe++; | |
302 | if (pe - p <= 5) { | |
303 | if (!isdigit(*pe)) | |
304 | return LANG_FORTRANFIXED; | |
305 | while (isdigit(*pe)) pe++; | |
306 | while (*pe == ' ' || *pe == '\t') pe++; | |
307 | if (*pe != '\r' && *pe != '\n' && pe - p == 5) | |
308 | return LANG_FORTRANFIXED; | |
309 | } | |
310 | } | |
311 | while (*p != '\r' && *p != '\n' && *p != '&' && p < eof) p++; | |
312 | if (*p == '&') { | |
313 | p++; | |
314 | // Look for free-form continuation. | |
315 | while (*p == ' ' || *p == '\t') p++; | |
316 | if (*p == '\r' || *p == '\n') { | |
317 | pe = p; | |
318 | while (*pe == '\r' || *pe == '\n' || *pe == ' ' || *pe == '\t') pe++; | |
319 | if (*pe == '&') | |
320 | return LANG_FORTRANFREE; | |
321 | } | |
322 | } | |
323 | while (*p == '\r' || *p == '\n') p++; | |
324 | } | |
325 | return LANG_FORTRANFREE; // might as well be free-form | |
326 | } | |
327 | ||
328 | const char *disambiguate_h(SourceFile *sourcefile) { | |
329 | char *p, *pe; | |
330 | int length; | |
331 | ||
332 | // If the directory contains a matching *.m file, likely Objective C. | |
333 | length = strlen(sourcefile->filename); | |
334 | if (strcmp(sourcefile->ext, "h") == 0) { | |
335 | char path[length]; | |
336 | strncpy(path, sourcefile->filename, length); | |
337 | path[length] = '\0'; | |
338 | *(path + length - 1) = 'm'; | |
339 | char **filenames = ohcount_sourcefile_get_filenames(sourcefile); | |
340 | if (filenames) { | |
341 | int i; | |
342 | for (i = 0; filenames[i] != NULL; i++) | |
343 | if (strcmp(path, filenames[i]) == 0) | |
344 | return LANG_OBJECTIVE_C; | |
345 | } | |
346 | } | |
347 | ||
348 | // Attempt to detect based on file contents. | |
349 | char line[81], buf[81]; | |
350 | p = ohcount_sourcefile_get_contents(sourcefile); | |
351 | pe = p; | |
352 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
353 | while (pe < eof) { | |
354 | // Get a line at a time. | |
355 | while (pe < eof && *pe != '\r' && *pe != '\n') pe++; | |
356 | length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); | |
357 | strncpy(line, p, length); | |
358 | line[length] = '\0'; | |
359 | char *eol = line + strlen(line); | |
360 | char *line_end = pe; | |
361 | ||
362 | // Look for C++ headers. | |
363 | if (*line == '#') { | |
364 | p = line + 1; | |
365 | while (*p == ' ' || *p == '\t') p++; | |
366 | if (strncmp(p, "include", 7) == 0 && | |
367 | (*(p + 7) == ' ' || *(p + 7) == '\t')) { | |
368 | // /^#\s*include\s+[<"][^>"]+[>"]/ | |
369 | p += 8; | |
370 | while (*p == ' ' || *p == '\t') p++; | |
371 | if (*p == '<' || *p == '"') { | |
372 | // Is the header file a C++ header file? | |
373 | p++; | |
374 | pe = p; | |
375 | while (pe < eol && *pe != '>' && *pe != '"') pe++; | |
376 | length = pe - p; | |
377 | strncpy(buf, p, length); | |
378 | buf[length] = '\0'; | |
379 | if (ohcount_hash_is_cppheader(buf, length)) | |
380 | return LANG_CPP; | |
381 | // Is the extension for the header file a C++ file? | |
382 | p = pe; | |
383 | while (p > line && *(p - 1) != '.') p--; | |
384 | length = pe - p; | |
385 | strncpy(buf, p, length); | |
386 | buf[length] = '\0'; | |
387 | struct ExtensionMap *re = ohcount_hash_language_from_ext(buf, length); | |
388 | if (re && strcmp(re->value, LANG_CPP) == 0) | |
389 | return LANG_CPP; | |
390 | } | |
391 | } | |
392 | } | |
393 | ||
394 | // Look for C++ keywords. | |
395 | p = line; | |
396 | while (p < eol) { | |
397 | if (islower(*p) && p != line && !isalnum(*(p - 1)) && *(p - 1) != '_') { | |
398 | pe = p; | |
399 | while (islower(*pe)) pe++; | |
400 | if (!isalnum(*pe) && *pe != '_') { | |
401 | length = pe - p; | |
402 | strncpy(buf, p, length); | |
403 | buf[length] = '\0'; | |
404 | if (strcmp(buf, "class") == 0 || | |
405 | strcmp(buf, "namespace") == 0 || | |
406 | strcmp(buf, "template") == 0 || | |
407 | strcmp(buf, "typename") == 0) | |
408 | return LANG_CPP; | |
409 | } | |
410 | p = pe + 1; | |
411 | } else p++; | |
412 | } | |
413 | ||
414 | // Next line. | |
415 | pe = line_end; | |
416 | while (*pe == '\r' || *pe == '\n') pe++; | |
417 | p = pe; | |
418 | } | |
419 | ||
420 | // Nothing to suggest C++. | |
421 | return LANG_C; | |
422 | } | |
423 | ||
424 | const char *disambiguate_in(SourceFile *sourcefile) { | |
425 | char *p, *pe; | |
426 | int length; | |
427 | const char *language = NULL; | |
428 | ||
429 | p = sourcefile->filepath; | |
430 | pe = p + strlen(p) - 3; | |
431 | if (strstr(p, ".") <= pe) { | |
432 | // Only if the filename has an extension prior to the .in | |
433 | length = pe - p; | |
434 | char buf[length]; | |
435 | strncpy(buf, p, length); | |
436 | buf[length] = '\0'; | |
437 | SourceFile *undecorated = ohcount_sourcefile_new(buf); | |
438 | p = ohcount_sourcefile_get_contents(sourcefile); | |
439 | if (!p) { | |
440 | return NULL; | |
441 | } | |
442 | // The filepath without the '.in' extension does not exist on disk. The | |
443 | // sourcefile->diskpath field must be set incase the detector needs to run | |
444 | // 'file -b' on the file. | |
445 | ohcount_sourcefile_set_diskpath(undecorated, sourcefile->filepath); | |
446 | ohcount_sourcefile_set_contents(undecorated, p); | |
447 | char **filenames = ohcount_sourcefile_get_filenames(sourcefile); | |
448 | ohcount_sourcefile_set_filenames(undecorated, filenames); | |
449 | language = ohcount_sourcefile_get_language(undecorated); | |
450 | ohcount_sourcefile_free(undecorated); | |
451 | } | |
452 | return language; | |
453 | } | |
454 | ||
455 | const char *disambiguate_inc(SourceFile *sourcefile) { | |
456 | char *p = ohcount_sourcefile_get_contents(sourcefile); | |
457 | char *eof = p + strlen(p); | |
458 | while (p < eof) { | |
459 | if (*p == '\0') | |
460 | return BINARY; | |
461 | else if (*p == '?' && strncmp(p + 1, "php", 3) == 0) | |
462 | return LANG_PHP; | |
463 | p++; | |
464 | } | |
465 | return NULL; | |
466 | } | |
467 | ||
468 | const char *disambiguate_m(SourceFile *sourcefile) { | |
469 | char *p, *pe; | |
470 | int length; | |
471 | ||
472 | // Attempt to detect based on a weighted heuristic of file contents. | |
473 | int matlab_score = 0; | |
474 | int objective_c_score = 0; | |
475 | int limbo_score = 0; | |
476 | int octave_syntax_detected = 0; | |
477 | ||
478 | int i, has_h_headers = 0, has_c_files = 0; | |
479 | char **filenames = ohcount_sourcefile_get_filenames(sourcefile); | |
480 | if (filenames) { | |
481 | for (i = 0; filenames[i] != NULL; i++) { | |
482 | p = filenames[i]; | |
483 | pe = p + strlen(p); | |
484 | if (pe - p >= 4) { | |
485 | if (*(pe - 4) == '.' && *(pe - 3) == 'c' && | |
486 | ((*(pe - 2) == 'p' && *(pe - 1) == 'p') || | |
487 | (*(pe - 2) == '+' && *(pe - 1) == '+') || | |
488 | (*(pe - 2) == 'x' && *(pe - 1) == 'x'))) { | |
489 | has_c_files = 1; | |
490 | break; // short circuit | |
491 | } | |
492 | } else if (pe - p >= 3) { | |
493 | if (*(pe - 3) == '.' && *(pe - 2) == 'c' && *(pe - 1) == 'c') { | |
494 | has_c_files = 1; | |
495 | break; // short circuit | |
496 | } | |
497 | } else if (pe - p >= 2) { | |
498 | if (*(pe - 2) == '.') { | |
499 | if (*(pe - 1) == 'h') | |
500 | has_h_headers = 1; | |
501 | else if (*(pe - 1) == 'c' || *(pe - 1) == 'C') { | |
502 | has_c_files = 1; | |
503 | break; // short circuit | |
504 | } | |
505 | } | |
506 | } | |
507 | } | |
508 | } | |
509 | if (has_h_headers && !has_c_files) | |
510 | objective_c_score += 5; | |
511 | ||
512 | char line[81], buf[81]; | |
513 | p = ohcount_sourcefile_get_contents(sourcefile); | |
514 | pe = p; | |
515 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
516 | while (pe < eof) { | |
517 | // Get a line at a time. | |
518 | while (pe < eof && *pe != '\r' && *pe != '\n') pe++; | |
519 | length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); | |
520 | strncpy(line, p, length); | |
521 | line[length] = '\0'; | |
522 | char *eol = line + strlen(line); | |
523 | char *line_end = pe; | |
524 | ||
525 | // Look for tell-tale lines. | |
526 | p = line; | |
527 | while (*p == ' ' || *p == '\t') p++; | |
528 | if (*p == '%') { // Matlab comment | |
529 | matlab_score++; | |
530 | } else if (*p == '#' && strncmp(p, "#import", 7) == 0) { // Objective C | |
531 | objective_c_score++; | |
532 | } else if (*p == '#') { // Limbo or Octave comment | |
533 | while (*p == '#') p++; | |
534 | if (*p == ' ' || *p == '\t') { | |
535 | limbo_score++; | |
536 | matlab_score++; | |
537 | octave_syntax_detected = 1; | |
538 | } | |
539 | } else if (*p == '/' && *(p + 1) == '/' || *(p + 1) == '*') { | |
540 | objective_c_score++; // Objective C comment | |
541 | } else if (*p == '+' || *p == '-') { // Objective C method signature | |
542 | objective_c_score++; | |
543 | } else if (*p == '@' || *p == '#') { // Objective C method signature | |
544 | if (strncmp(p, "@implementation", 15) == 0 || | |
545 | strncmp(p, "@interface", 10) == 0) | |
546 | objective_c_score++; | |
547 | } else if (strncmp(p, "function", 8) == 0) { // Matlab or Octave function | |
548 | p += 8; | |
549 | while (*p == ' ' || *p == '\t') p++; | |
550 | if (*p == '(') | |
551 | matlab_score++; | |
552 | } else if (strncmp(p, "include", 7) == 0) { // Limbo include | |
553 | // /^include[ \t]+"[^"]+\.m";/ | |
554 | p += 7; | |
555 | if (*p == ' ' || *p == '\t') { | |
556 | while (*p == ' ' || *p == '\t') p++; | |
557 | if (*p == '"') { | |
558 | while (*p != '"' && p < eol) p++; | |
559 | if (*p == '"' && *(p - 2) == '.' && *(p - 1) == 'm') | |
560 | limbo_score++; | |
561 | } | |
562 | } | |
563 | } | |
564 | ||
565 | // Look for Octave keywords. | |
566 | p = line; | |
567 | while (p < eol) { | |
568 | if (islower(*p) && p != line && !isalnum(*(p - 1))) { | |
569 | pe = p; | |
570 | while (islower(*pe) || *pe == '_') pe++; | |
571 | if (!isalnum(*pe)) { | |
572 | length = pe - p; | |
573 | strncpy(buf, p, length); | |
574 | buf[length] = '\0'; | |
575 | if (strcmp(buf, "end_try_catch") == 0 || | |
576 | strcmp(buf, "end_unwind_protect") == 0 || | |
577 | strcmp(buf, "endfunction") == 0 || | |
578 | strcmp(buf, "endwhile") == 0) | |
579 | octave_syntax_detected = 1; | |
580 | } | |
581 | p = pe + 1; | |
582 | } else p++; | |
583 | } | |
584 | ||
585 | // Look for Limbo declarations | |
586 | p = line; | |
587 | while (p < eol) { | |
588 | if (*p == ':' && (*(p + 1) == ' ' || *(p + 1) == '\t')) { | |
589 | // /:[ \t]+(module|adt|fn ?\(|con[ \t])/ | |
590 | p += 2; | |
591 | if (strncmp(p, "module", 6) == 0 && !isalnum(*(p + 6)) || | |
592 | strncmp(p, "adt", 3) == 0 && !isalnum(*(p + 3)) || | |
593 | strncmp(p, "fn", 2) == 0 && | |
594 | (*(p + 2) == ' ' && *(p + 3) == '(' || *(p + 2) == '(') || | |
595 | strncmp(p, "con", 3) == 0 && | |
596 | (*(p + 3) == ' ' || *(p + 3) == '\t')) | |
597 | limbo_score++; | |
598 | } else p++; | |
599 | } | |
600 | ||
601 | // Next line. | |
602 | pe = line_end; | |
603 | while (*pe == '\r' || *pe == '\n') pe++; | |
604 | p = pe; | |
605 | } | |
606 | ||
607 | if (limbo_score > objective_c_score && limbo_score > matlab_score) | |
608 | return LANG_LIMBO; | |
609 | else if (objective_c_score > matlab_score) | |
610 | return LANG_OBJECTIVE_C; | |
611 | else | |
612 | return octave_syntax_detected ? LANG_OCTAVE : LANG_MATLAB; | |
613 | } | |
614 | ||
615 | #define QMAKE_SOURCES_SPACE "SOURCES +=" | |
616 | #define QMAKE_SOURCES "SOURCES+=" | |
617 | #define QMAKE_CONFIG_SPACE "CONFIG +=" | |
618 | #define QMAKE_CONFIG "CONFIG+=" | |
619 | ||
620 | const char *disambiguate_pro(SourceFile *sourcefile) { | |
621 | char *p = ohcount_sourcefile_get_contents(sourcefile); | |
622 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
623 | for (; p < eof; p++) { | |
624 | if (strncmp(p, QMAKE_SOURCES_SPACE, strlen(QMAKE_SOURCES_SPACE)) == 0 || | |
625 | strncmp(p, QMAKE_SOURCES, strlen(QMAKE_SOURCES)) == 0 || | |
626 | strncmp(p, QMAKE_CONFIG_SPACE, strlen(QMAKE_CONFIG_SPACE)) == 0 || | |
627 | strncmp(p, QMAKE_CONFIG, strlen(QMAKE_CONFIG)) == 0) | |
628 | return LANG_MAKE; // really QMAKE | |
629 | } | |
630 | return LANG_IDL_PVWAVE; | |
631 | } | |
632 | ||
633 | const char *disambiguate_st(SourceFile *sourcefile) { | |
634 | char *p, *pe; | |
635 | int length; | |
636 | ||
637 | // Attempt to detect based on file contents. | |
638 | int found_assignment = 0, found_block_start = 0, found_block_end = 0; | |
639 | ||
640 | char line[81]; | |
641 | p = ohcount_sourcefile_get_contents(sourcefile); | |
642 | pe = p; | |
643 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
644 | while (pe < eof) { | |
645 | // Get a line at a time. | |
646 | while (p < eof && *pe != '\r' && *pe != '\n') pe++; | |
647 | length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); | |
648 | strncpy(line, p, length); | |
649 | line[length] = '\0'; | |
650 | char *eol = line + strlen(line); | |
651 | char *line_end = pe; | |
652 | ||
653 | for (p = line; p < eol; p++) { | |
654 | if (*p == ':') { | |
655 | p++; | |
656 | while (p < eol && (*p == ' ' || *p == '\t')) p++; | |
657 | if (*p == '=') | |
658 | found_assignment = 1; | |
659 | else if (*p == '[') | |
660 | found_block_start = 1; | |
661 | } else if (*p == ']' && *(p + 1) == '.') found_block_end = 1; | |
662 | if (found_assignment && found_block_start && found_block_end) | |
663 | return LANG_SMALLTALK; | |
664 | } | |
665 | ||
666 | // Next line. | |
667 | pe = line_end; | |
668 | while (*pe == '\r' || *pe == '\n') pe++; | |
669 | p = pe; | |
670 | } | |
671 | ||
672 | return NULL; | |
673 | } | |
674 | ||
675 | int ohcount_is_binary_filename(const char *filename) { | |
676 | char *p = (char *)filename + strlen(filename); | |
677 | while (p > filename && *(p - 1) != '.') p--; | |
678 | if (p > filename) { | |
679 | struct ExtensionMap *re; | |
680 | int length = strlen(p); | |
681 | re = ohcount_hash_language_from_ext(p, length); | |
682 | if (re) return ISBINARY(re->value); | |
683 | // Try the lower-case version of this extension. | |
684 | char lowerext[length]; | |
685 | strncpy(lowerext, p, length); | |
686 | lowerext[length] = '\0'; | |
687 | for (p = lowerext; p < lowerext + length; p++) *p = tolower(*p); | |
688 | re = ohcount_hash_language_from_ext(lowerext, length); | |
689 | if (re) return ISBINARY(re->value); | |
690 | } | |
691 | return 0; | |
692 | } |
0 | // detector_test.h written by Mitchell Foral. mitchell<att>caladbolg.net. | |
1 | // See COPYING for license information. | |
2 | ||
3 | #include <assert.h> | |
4 | #include <stdlib.h> | |
5 | #include <string.h> | |
6 | ||
7 | #include "../../src/detector.h" | |
8 | #include "../../src/languages.h" | |
9 | #include "../../src/sourcefile.h" | |
10 | ||
11 | #define ASSERT_DETECT(x, y) { \ | |
12 | SourceFile *sf = ohcount_sourcefile_new("../detect_files/" y); \ | |
13 | const char *lang = ohcount_detect_language(sf); \ | |
14 | assert(lang); \ | |
15 | assert(strcmp(x, lang) == 0); \ | |
16 | ohcount_sourcefile_free(sf); \ | |
17 | } | |
18 | #define ASSERT_NODETECT(x) { \ | |
19 | SourceFile *sf = ohcount_sourcefile_new("../detect_files/" x); \ | |
20 | assert(ohcount_detect_language(sf) == NULL); \ | |
21 | ohcount_sourcefile_free(sf); \ | |
22 | } | |
23 | ||
24 | void test_detector_smalltalk() { | |
25 | ASSERT_DETECT(LANG_SMALLTALK, "example.st"); | |
26 | ASSERT_NODETECT("english.st"); | |
27 | } | |
28 | ||
29 | void test_detector_disambiguate_m() { | |
30 | ASSERT_DETECT(LANG_OBJECTIVE_C, "t1.m"); | |
31 | ASSERT_DETECT(LANG_OBJECTIVE_C, "t2.m"); | |
32 | ASSERT_DETECT(LANG_OBJECTIVE_C, "TCPSocket.m"); | |
33 | ASSERT_DETECT(LANG_OBJECTIVE_C, "foo_objective_c.m"); | |
34 | ASSERT_DETECT(LANG_MATLAB, "foo_matlab.m"); | |
35 | ASSERT_DETECT(LANG_OCTAVE, "foo_octave.m"); | |
36 | } | |
37 | ||
38 | void test_detector_disambiguate_in() { | |
39 | ASSERT_NODETECT("empty.in"); | |
40 | } | |
41 | void test_detector_disambiguate_pro() { | |
42 | ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); | |
43 | ASSERT_DETECT(LANG_MAKE, "qmake.pro"); | |
44 | } | |
45 | ||
46 | void test_detector_fortran_fixedfree() { | |
47 | ASSERT_DETECT(LANG_FORTRANFIXED, "fortranfixed.f"); | |
48 | ASSERT_DETECT(LANG_FORTRANFREE, "fortranfree.f"); | |
49 | } | |
50 | ||
51 | void test_detector_detect_polyglot() { | |
52 | ASSERT_DETECT(LANG_C, "foo.c"); | |
53 | ASSERT_DETECT(LANG_C, "uses_no_cpp.h"); | |
54 | ASSERT_DETECT(LANG_CPP, "uses_cpp_headers.h"); | |
55 | ASSERT_DETECT(LANG_CPP, "uses_cpp_stdlib_headers.h"); | |
56 | ASSERT_DETECT(LANG_CPP, "uses_cpp_keywords.h"); | |
57 | ASSERT_DETECT(LANG_RUBY, "foo.rb"); | |
58 | ASSERT_DETECT(LANG_MAKE, "foo.mk"); | |
59 | ASSERT_DETECT(LANG_OBJECTIVE_C, "foo_objective_c.h"); | |
60 | ASSERT_DETECT(LANG_PHP, "upper_case_php"); | |
61 | ASSERT_DETECT(LANG_SMALLTALK, "example.st"); | |
62 | ASSERT_DETECT(LANG_VALA, "foo.vala"); | |
63 | ASSERT_DETECT(LANG_TEX, "foo.tex"); | |
64 | ASSERT_DETECT(LANG_XSLT, "example.xsl"); | |
65 | ASSERT_DETECT(LANG_LISP, "core.lisp"); | |
66 | ASSERT_DETECT(LANG_DMD, "foo.d"); | |
67 | ASSERT_DETECT(LANG_VIM, "foo.vim"); | |
68 | ASSERT_DETECT(LANG_EBUILD, "foo.ebuild"); | |
69 | ASSERT_DETECT(LANG_EBUILD, "foo.eclass"); | |
70 | ASSERT_DETECT(LANG_EXHERES, "foo.exheres-0"); | |
71 | ASSERT_DETECT(LANG_EXHERES, "foo.exlib"); | |
72 | ASSERT_DETECT(LANG_EIFFEL, "eiffel.e"); | |
73 | ASSERT_DETECT(LANG_OCAML, "ocaml.ml"); | |
74 | ASSERT_DETECT(LANG_STRATEGO, "stratego.str"); | |
75 | ASSERT_DETECT(LANG_R, "foo.R"); | |
76 | ASSERT_DETECT(LANG_GLSL, "foo.glsl"); | |
77 | ASSERT_DETECT(LANG_GLSL, "foo_glsl.vert"); | |
78 | ASSERT_DETECT(LANG_GLSL, "foo_glsl.frag"); | |
79 | ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); | |
80 | ASSERT_DETECT(LANG_ASSEMBLER, "foo.z80"); | |
81 | ASSERT_DETECT(LANG_PHP, "php.inc"); | |
82 | ASSERT_DETECT(LANG_FSHARP, "fs1.fs"); | |
83 | } | |
84 | ||
85 | void test_detector_upper_case_extensions() { | |
86 | ASSERT_DETECT(LANG_CPP, "foo_upper_case.C"); | |
87 | ASSERT_DETECT(LANG_RUBY, "foo_upper_case.RB"); | |
88 | } | |
89 | ||
90 | void test_detector_no_extensions() { | |
91 | ASSERT_DETECT(LANG_PYTHON, "py_script"); | |
92 | ASSERT_DETECT(LANG_RUBY, "ruby_script"); | |
93 | ASSERT_DETECT(LANG_SHELL, "bourne_again_script"); | |
94 | ASSERT_DETECT(LANG_SHELL, "bash_script"); | |
95 | ASSERT_DETECT(LANG_PERL, "perl_w"); | |
96 | ASSERT_DETECT(LANG_DMD, "d_script"); | |
97 | ASSERT_DETECT(LANG_TCL, "tcl_script"); | |
98 | ASSERT_DETECT(LANG_PYTHON, "python.data"); | |
99 | ASSERT_DETECT(LANG_PYTHON, "python2.data"); | |
100 | } | |
101 | ||
102 | void test_detector_csharp_or_clearsilver() { | |
103 | ASSERT_DETECT(LANG_CSHARP, "cs1.cs"); | |
104 | ASSERT_DETECT(LANG_CLEARSILVER_TEMPLATE, "clearsilver_template1.cs"); | |
105 | } | |
106 | ||
107 | void test_detector_basic() { | |
108 | ASSERT_DETECT(LANG_VISUALBASIC, "visual_basic.bas"); | |
109 | ASSERT_DETECT(LANG_CLASSIC_BASIC, "classic_basic.b"); | |
110 | system("mv ../detect_files/frx1.frx ../detect_files/frx1.frx2"); | |
111 | ASSERT_DETECT(LANG_STRUCTURED_BASIC, "visual_basic.bas"); | |
112 | ASSERT_DETECT(LANG_STRUCTURED_BASIC, "structured_basic.b"); | |
113 | system("mv ../detect_files/frx1.frx2 ../detect_files/frx1.frx"); | |
114 | } | |
115 | ||
116 | void test_detector_xml_with_custom_extension() { | |
117 | ASSERT_DETECT(LANG_XML, "xml.custom_ext"); | |
118 | } | |
119 | ||
120 | void all_detector_tests() { | |
121 | test_detector_smalltalk(); | |
122 | test_detector_disambiguate_m(); | |
123 | test_detector_disambiguate_in(); | |
124 | test_detector_disambiguate_pro(); | |
125 | test_detector_fortran_fixedfree(); | |
126 | test_detector_detect_polyglot(); | |
127 | test_detector_upper_case_extensions(); | |
128 | test_detector_no_extensions(); | |
129 | test_detector_csharp_or_clearsilver(); | |
130 | test_detector_basic(); | |
131 | test_detector_xml_with_custom_extension(); | |
132 | } |
0 | // detector.c written by Mitchell Foral. mitchell<att>caladbolg.net. | |
1 | // See COPYING for license information. | |
2 | ||
3 | #include <ctype.h> | |
4 | #include <stdio.h> | |
5 | #include <stdlib.h> | |
6 | #include <string.h> | |
7 | #include <unistd.h> | |
8 | ||
9 | #include "detector.h" | |
10 | #include "languages.h" | |
11 | #include "log.h" | |
12 | ||
13 | #include "hash/cppheader_hash.h" | |
14 | #include "hash/disambiguatefunc_hash.h" | |
15 | #include "hash/extension_hash.h" | |
16 | #include "hash/filename_hash.h" | |
17 | ||
18 | #define ISBINARY(x) (x[0] == '\1') | |
19 | #define ISAMBIGUOUS(x) (x[0] == '\2') | |
20 | #define DISAMBIGUATEWHAT(x) &x[1] | |
21 | ||
22 | const char *ohcount_detect_language(SourceFile *sourcefile) { | |
23 | const char *language = NULL; | |
24 | char *p, *pe; | |
25 | int length; | |
26 | ||
27 | // Attempt to detect based on file extension. | |
28 | length = strlen(sourcefile->ext); | |
29 | struct ExtensionMap *re = ohcount_hash_language_from_ext(sourcefile->ext, | |
30 | length); | |
31 | if (re) language = re->value; | |
32 | if (language == NULL) { | |
33 | // Try the lower-case version of this extension. | |
34 | char lowerext[length + 1]; | |
35 | strncpy(lowerext, sourcefile->ext, length); | |
36 | lowerext[length] = '\0'; | |
37 | for (p = lowerext; p < lowerext + length; p++) *p = tolower(*p); | |
38 | struct ExtensionMap *re = ohcount_hash_language_from_ext(lowerext, length); | |
39 | if (re) return re->value; | |
40 | } | |
41 | if (language) { | |
42 | if (ISAMBIGUOUS(language)) { | |
43 | // Call the appropriate function for disambiguation. | |
44 | length = strlen(DISAMBIGUATEWHAT(language)); | |
45 | struct DisambiguateFuncsMap *rd = | |
46 | ohcount_hash_disambiguate_func_from_id(DISAMBIGUATEWHAT(language), | |
47 | length); | |
48 | if (rd) return rd->value(sourcefile); | |
49 | } else return ISBINARY(language) ? NULL : language; | |
50 | } | |
51 | ||
52 | // Attempt to detect based on filename. | |
53 | length = strlen(sourcefile->filename); | |
54 | struct FilenameMap *rf = | |
55 | ohcount_hash_language_from_filename(sourcefile->filename, length); | |
56 | if (rf) return rf->value; | |
57 | ||
58 | char line[81] = { '\0' }, buf[81]; | |
59 | ||
60 | // Attempt to detect using Emacs mode line (/^-\*-\s*mode[\s:]*\w/i). | |
61 | p = ohcount_sourcefile_get_contents(sourcefile); | |
62 | pe = p; | |
63 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
64 | while (pe < eof) { | |
65 | // Get the contents of the first line. | |
66 | while (pe < eof && *pe != '\r' && *pe != '\n') pe++; | |
67 | length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); | |
68 | strncpy(line, p, length); | |
69 | line[length] = '\0'; | |
70 | if (*line == '#' && *(line + 1) == '!') { | |
71 | // First line was sh-bang; loop to get contents of second line. | |
72 | while (*pe == '\r' || *pe == '\n') pe++; | |
73 | p = pe; | |
74 | } else break; | |
75 | } | |
76 | char *eol = line + strlen(line); | |
77 | for (p = line; p < eol; p++) *p = tolower(*p); | |
78 | p = strstr(line, "-*-"); | |
79 | if (p) { | |
80 | p += 3; | |
81 | while (*p == ' ' || *p == '\t') p++; | |
82 | if (strncmp(p, "mode", 4) == 0) { | |
83 | p += 4; | |
84 | while (*p == ' ' || *p == '\t' || *p == ':') p++; | |
85 | } | |
86 | pe = p; | |
87 | while (isalnum(*pe)) pe++; | |
88 | length = pe - p; | |
89 | strncpy(buf, p, length); | |
90 | buf[length] = '\0'; | |
91 | struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); | |
92 | if (rl) return rl->name; | |
93 | } | |
94 | ||
95 | // Attempt to detect based on Unix 'file' command. | |
96 | int tmpfile = 0; | |
97 | char *path = sourcefile->filepath; | |
98 | if (sourcefile->diskpath) | |
99 | path = sourcefile->diskpath; | |
100 | if (access(path, F_OK) != 0) { // create temporary file | |
101 | path = malloc(21); | |
102 | strncpy(path, "/tmp/ohcount_XXXXXXX", 20); | |
103 | *(path + 21) = '\0'; | |
104 | int fd = mkstemp(path); | |
105 | char *contents = ohcount_sourcefile_get_contents(sourcefile); | |
106 | log_it("contents:"); | |
107 | log_it(contents); | |
108 | length = contents ? strlen(contents) : 0; | |
109 | write(fd, contents, length); | |
110 | close(fd); | |
111 | tmpfile = 1; | |
112 | } | |
113 | char command[strlen(path) + 11]; | |
114 | sprintf(command, "file -b '%s'", path); | |
115 | FILE *f = popen(command, "r"); | |
116 | if (f) { | |
117 | fgets(line, sizeof(line), f); | |
118 | char *eol = line + strlen(line); | |
119 | for (p = line; p < eol; p++) *p = tolower(*p); | |
120 | p = strstr(line, "script text"); | |
121 | if (p && p == line) { // /^script text(?: executable)? for \w/ | |
122 | p = strstr(line, "for "); | |
123 | if (p) { | |
124 | p += 4; | |
125 | pe = p; | |
126 | while (isalnum(*pe)) pe++; | |
127 | length = pe - p; | |
128 | strncpy(buf, p, length); | |
129 | buf[length] = '\0'; | |
130 | struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); | |
131 | if (rl) language = rl->name; | |
132 | } | |
133 | } else if (p) { // /(\w+)(?: -\w+)* script text/ | |
134 | do { | |
135 | p--; | |
136 | pe = p; | |
137 | while (*p == ' ') p--; | |
138 | while (p != line && isalnum(*(p - 1))) p--; | |
139 | if (p != line && *(p - 1) == '-') p--; | |
140 | } while (*p == '-'); // Skip over any switches. | |
141 | length = pe - p; | |
142 | strncpy(buf, p, length); | |
143 | buf[length] = '\0'; | |
144 | struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); | |
145 | if (rl) language = rl->name; | |
146 | } else if (strstr(line, "xml")) language = LANG_XML; | |
147 | pclose(f); | |
148 | if (tmpfile) { | |
149 | remove(path); | |
150 | free(path); | |
151 | } | |
152 | if (language) return language; | |
153 | } | |
154 | ||
155 | return NULL; | |
156 | } | |
157 | ||
158 | const char *disambiguate_aspx(SourceFile *sourcefile) { | |
159 | char *p = ohcount_sourcefile_get_contents(sourcefile); | |
160 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
161 | for (; p < eof; p++) { | |
162 | // /<%@\s*Page[^>]+Language="VB"[^>]+%>/ | |
163 | p = strstr(p, "<%@"); | |
164 | if (!p) | |
165 | break; | |
166 | char *pe = strstr(p, "%>"); | |
167 | if (p && pe) { | |
168 | p += 3; | |
169 | const int length = pe - p; | |
170 | char buf[length]; | |
171 | strncpy(buf, p, length); | |
172 | buf[length] = '\0'; | |
173 | char *eol = buf + strlen(buf); | |
174 | for (p = buf; p < eol; p++) *p = tolower(*p); | |
175 | p = buf; | |
176 | while (*p == ' ' || *p == '\t') p++; | |
177 | if (strncmp(p, "page", 4) == 0) { | |
178 | p += 4; | |
179 | if (strstr(p, "language=\"vb\"")) | |
180 | return LANG_VB_ASPX; | |
181 | } | |
182 | } | |
183 | } | |
184 | return LANG_CS_ASPX; | |
185 | } | |
186 | ||
187 | const char *disambiguate_b(SourceFile *sourcefile) { | |
188 | char *p = ohcount_sourcefile_get_contents(sourcefile); | |
189 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
190 | while (p < eof) { | |
191 | // /(implement[ \t])|(include[ \t]+"[^"]*";)| | |
192 | // ((return|break|continue).*;|(pick|case).*\{)/ | |
193 | if (strncmp(p, "implement", 9) == 0 && | |
194 | (*(p + 9) == ' ' || *(p + 9) == '\t')) | |
195 | return LANG_LIMBO; | |
196 | else if (strncmp(p, "include", 7) == 0 && | |
197 | (*(p + 7) == ' ' || *(p + 7) == '\t')) { | |
198 | p += 7; | |
199 | while (*p == ' ' || *p == '\t') p++; | |
200 | if (*p == '"') { | |
201 | while (*p != '"' && p < eof) p++; | |
202 | if (*p == '"' && *(p + 1) == ';') | |
203 | return LANG_LIMBO; | |
204 | } | |
205 | } else if (strncmp(p, "return", 6) == 0 || | |
206 | strncmp(p, "break", 5) == 0 || | |
207 | strncmp(p, "continue", 8) == 0) { | |
208 | if (strstr(p, ";")) | |
209 | return LANG_LIMBO; | |
210 | } else if (strncmp(p, "pick", 4) == 0 || | |
211 | strncmp(p, "case", 4) == 0) { | |
212 | if (strstr(p, "{")) | |
213 | return LANG_LIMBO; | |
214 | } | |
215 | p++; | |
216 | } | |
217 | return disambiguate_basic(sourcefile); | |
218 | } | |
219 | ||
220 | const char *disambiguate_basic(SourceFile *sourcefile) { | |
221 | char *p, *pe; | |
222 | int length; | |
223 | ||
224 | // Attempt to detect based on file contents. | |
225 | char line[81]; | |
226 | p = ohcount_sourcefile_get_contents(sourcefile); | |
227 | pe = p; | |
228 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
229 | while (pe < eof) { | |
230 | // Get a line at a time. | |
231 | while (pe < eof && *pe != '\r' && *pe != '\n') pe++; | |
232 | length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); | |
233 | strncpy(line, p, length); | |
234 | line[length] = '\0'; | |
235 | char *line_end = pe; | |
236 | ||
237 | p = line; | |
238 | if (isdigit(*p)) { | |
239 | // /^\d+\s+\w/ | |
240 | p++; | |
241 | while (isdigit(*p)) p++; | |
242 | if (*p == ' ' || *p == '\t') { | |
243 | p++; | |
244 | while (*p == ' ' || *p == '\t') p++; | |
245 | if (isalnum(*p)) | |
246 | return LANG_CLASSIC_BASIC; | |
247 | } | |
248 | } | |
249 | ||
250 | // Next line. | |
251 | pe = line_end; | |
252 | while (*pe == '\r' || *pe == '\n') pe++; | |
253 | p = pe; | |
254 | } | |
255 | ||
256 | // Attempt to detect from associated VB files in file context. | |
257 | char **filenames = ohcount_sourcefile_get_filenames(sourcefile); | |
258 | if (filenames) { | |
259 | int i; | |
260 | for (i = 0; filenames[i] != NULL; i++) { | |
261 | pe = filenames[i] + strlen(filenames[i]); | |
262 | p = pe; | |
263 | while (p > filenames[i] && *(p - 1) != '.') p--; | |
264 | length = pe - p; | |
265 | if (length == 3 && | |
266 | (strncmp(p, "frm", length) == 0 || | |
267 | strncmp(p, "frx", length) == 0 || | |
268 | strncmp(p, "vba", length) == 0 || | |
269 | strncmp(p, "vbp", length) == 0 || | |
270 | strncmp(p, "vbs", length) == 0)) { | |
271 | return LANG_VISUALBASIC; | |
272 | } | |
273 | } | |
274 | } | |
275 | ||
276 | return LANG_STRUCTURED_BASIC; | |
277 | } | |
278 | ||
279 | const char *disambiguate_cs(SourceFile *sourcefile) { | |
280 | // Attempt to detect based on file contents. | |
281 | char *contents = ohcount_sourcefile_get_contents(sourcefile); | |
282 | if (contents && strstr(contents, "<?cs")) | |
283 | return LANG_CLEARSILVER_TEMPLATE; | |
284 | else | |
285 | return LANG_CSHARP; | |
286 | } | |
287 | ||
288 | const char *disambiguate_fortran(SourceFile *sourcefile) { | |
289 | char *p, *pe; | |
290 | ||
291 | p = ohcount_sourcefile_get_contents(sourcefile); | |
292 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
293 | while (p < eof) { | |
294 | if (*p == ' ' && p + 5 < eof) { | |
295 | int i; | |
296 | for (i = 1; i <= 5; i++) | |
297 | if (!isdigit(*(p + i)) && *(p + i) != ' ') | |
298 | return LANG_FORTRANFIXED; // definately not f77 | |
299 | // Possibly fixed (doesn't match /^\s*\d+\s*$/). | |
300 | pe = p; | |
301 | while (*pe == ' ' || *pe == '\t') pe++; | |
302 | if (pe - p <= 5) { | |
303 | if (!isdigit(*pe)) | |
304 | return LANG_FORTRANFIXED; | |
305 | while (isdigit(*pe)) pe++; | |
306 | while (*pe == ' ' || *pe == '\t') pe++; | |
307 | if (*pe != '\r' && *pe != '\n' && pe - p == 5) | |
308 | return LANG_FORTRANFIXED; | |
309 | } | |
310 | } | |
311 | while (*p != '\r' && *p != '\n' && *p != '&' && p < eof) p++; | |
312 | if (*p == '&') { | |
313 | p++; | |
314 | // Look for free-form continuation. | |
315 | while (*p == ' ' || *p == '\t') p++; | |
316 | if (*p == '\r' || *p == '\n') { | |
317 | pe = p; | |
318 | while (*pe == '\r' || *pe == '\n' || *pe == ' ' || *pe == '\t') pe++; | |
319 | if (*pe == '&') | |
320 | return LANG_FORTRANFREE; | |
321 | } | |
322 | } | |
323 | while (*p == '\r' || *p == '\n') p++; | |
324 | } | |
325 | return LANG_FORTRANFREE; // might as well be free-form | |
326 | } | |
327 | ||
328 | const char *disambiguate_h(SourceFile *sourcefile) { | |
329 | char *p, *pe; | |
330 | int length; | |
331 | ||
332 | // If the directory contains a matching *.m file, likely Objective C. | |
333 | length = strlen(sourcefile->filename); | |
334 | if (strcmp(sourcefile->ext, "h") == 0) { | |
335 | char path[length]; | |
336 | strncpy(path, sourcefile->filename, length); | |
337 | path[length] = '\0'; | |
338 | *(path + length - 1) = 'm'; | |
339 | char **filenames = ohcount_sourcefile_get_filenames(sourcefile); | |
340 | if (filenames) { | |
341 | int i; | |
342 | for (i = 0; filenames[i] != NULL; i++) | |
343 | if (strcmp(path, filenames[i]) == 0) | |
344 | return LANG_OBJECTIVE_C; | |
345 | } | |
346 | } | |
347 | ||
348 | // Attempt to detect based on file contents. | |
349 | char line[81], buf[81]; | |
350 | p = ohcount_sourcefile_get_contents(sourcefile); | |
351 | pe = p; | |
352 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
353 | while (pe < eof) { | |
354 | // Get a line at a time. | |
355 | while (pe < eof && *pe != '\r' && *pe != '\n') pe++; | |
356 | length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); | |
357 | strncpy(line, p, length); | |
358 | line[length] = '\0'; | |
359 | char *eol = line + strlen(line); | |
360 | char *line_end = pe; | |
361 | ||
362 | // Look for C++ headers. | |
363 | if (*line == '#') { | |
364 | p = line + 1; | |
365 | while (*p == ' ' || *p == '\t') p++; | |
366 | if (strncmp(p, "include", 7) == 0 && | |
367 | (*(p + 7) == ' ' || *(p + 7) == '\t')) { | |
368 | // /^#\s*include\s+[<"][^>"]+[>"]/ | |
369 | p += 8; | |
370 | while (*p == ' ' || *p == '\t') p++; | |
371 | if (*p == '<' || *p == '"') { | |
372 | // Is the header file a C++ header file? | |
373 | p++; | |
374 | pe = p; | |
375 | while (pe < eol && *pe != '>' && *pe != '"') pe++; | |
376 | length = pe - p; | |
377 | strncpy(buf, p, length); | |
378 | buf[length] = '\0'; | |
379 | if (ohcount_hash_is_cppheader(buf, length)) | |
380 | return LANG_CPP; | |
381 | // Is the extension for the header file a C++ file? | |
382 | p = pe; | |
383 | while (p > line && *(p - 1) != '.') p--; | |
384 | length = pe - p; | |
385 | strncpy(buf, p, length); | |
386 | buf[length] = '\0'; | |
387 | struct ExtensionMap *re = ohcount_hash_language_from_ext(buf, length); | |
388 | if (re && strcmp(re->value, LANG_CPP) == 0) | |
389 | return LANG_CPP; | |
390 | } | |
391 | } | |
392 | } | |
393 | ||
394 | // Look for C++ keywords. | |
395 | p = line; | |
396 | while (p < eol) { | |
397 | if (islower(*p) && p != line && !isalnum(*(p - 1)) && *(p - 1) != '_') { | |
398 | pe = p; | |
399 | while (islower(*pe)) pe++; | |
400 | if (!isalnum(*pe) && *pe != '_') { | |
401 | length = pe - p; | |
402 | strncpy(buf, p, length); | |
403 | buf[length] = '\0'; | |
404 | if (strcmp(buf, "class") == 0 || | |
405 | strcmp(buf, "namespace") == 0 || | |
406 | strcmp(buf, "template") == 0 || | |
407 | strcmp(buf, "typename") == 0) | |
408 | return LANG_CPP; | |
409 | } | |
410 | p = pe + 1; | |
411 | } else p++; | |
412 | } | |
413 | ||
414 | // Next line. | |
415 | pe = line_end; | |
416 | while (*pe == '\r' || *pe == '\n') pe++; | |
417 | p = pe; | |
418 | } | |
419 | ||
420 | // Nothing to suggest C++. | |
421 | return LANG_C; | |
422 | } | |
423 | ||
424 | const char *disambiguate_in(SourceFile *sourcefile) { | |
425 | char *p, *pe; | |
426 | int length; | |
427 | const char *language = NULL; | |
428 | ||
429 | p = sourcefile->filepath; | |
430 | pe = p + strlen(p) - 3; | |
431 | if (strstr(p, ".") <= pe) { | |
432 | // Only if the filename has an extension prior to the .in | |
433 | length = pe - p; | |
434 | char buf[length]; | |
435 | strncpy(buf, p, length); | |
436 | buf[length] = '\0'; | |
437 | SourceFile *undecorated = ohcount_sourcefile_new(buf); | |
438 | p = ohcount_sourcefile_get_contents(sourcefile); | |
439 | // The filepath without the '.in' extension does not exist on disk. The | |
440 | // sourcefile->diskpath field must be set incase the detector needs to run | |
441 | // 'file -b' on the file. | |
442 | ohcount_sourcefile_set_diskpath(undecorated, sourcefile->filepath); | |
443 | ohcount_sourcefile_set_contents(undecorated, p); | |
444 | char **filenames = ohcount_sourcefile_get_filenames(sourcefile); | |
445 | ohcount_sourcefile_set_filenames(undecorated, filenames); | |
446 | language = ohcount_sourcefile_get_language(undecorated); | |
447 | ohcount_sourcefile_free(undecorated); | |
448 | } | |
449 | return language; | |
450 | } | |
451 | ||
452 | const char *disambiguate_inc(SourceFile *sourcefile) { | |
453 | char *p = ohcount_sourcefile_get_contents(sourcefile); | |
454 | char *eof = p + strlen(p); | |
455 | while (p < eof) { | |
456 | if (*p == '\0') | |
457 | return BINARY; | |
458 | else if (*p == '?' && strncmp(p + 1, "php", 3) == 0) | |
459 | return LANG_PHP; | |
460 | p++; | |
461 | } | |
462 | return NULL; | |
463 | } | |
464 | ||
465 | const char *disambiguate_m(SourceFile *sourcefile) { | |
466 | char *p, *pe; | |
467 | int length; | |
468 | ||
469 | // Attempt to detect based on a weighted heuristic of file contents. | |
470 | int matlab_score = 0; | |
471 | int objective_c_score = 0; | |
472 | int limbo_score = 0; | |
473 | int octave_syntax_detected = 0; | |
474 | ||
475 | int i, has_h_headers = 0, has_c_files = 0; | |
476 | char **filenames = ohcount_sourcefile_get_filenames(sourcefile); | |
477 | if (filenames) { | |
478 | for (i = 0; filenames[i] != NULL; i++) { | |
479 | p = filenames[i]; | |
480 | pe = p + strlen(p); | |
481 | if (pe - p >= 4) { | |
482 | if (*(pe - 4) == '.' && *(pe - 3) == 'c' && | |
483 | ((*(pe - 2) == 'p' && *(pe - 1) == 'p') || | |
484 | (*(pe - 2) == '+' && *(pe - 1) == '+') || | |
485 | (*(pe - 2) == 'x' && *(pe - 1) == 'x'))) { | |
486 | has_c_files = 1; | |
487 | break; // short circuit | |
488 | } | |
489 | } else if (pe - p >= 3) { | |
490 | if (*(pe - 3) == '.' && *(pe - 2) == 'c' && *(pe - 1) == 'c') { | |
491 | has_c_files = 1; | |
492 | break; // short circuit | |
493 | } | |
494 | } else if (pe - p >= 2) { | |
495 | if (*(pe - 2) == '.') { | |
496 | if (*(pe - 1) == 'h') | |
497 | has_h_headers = 1; | |
498 | else if (*(pe - 1) == 'c' || *(pe - 1) == 'C') { | |
499 | has_c_files = 1; | |
500 | break; // short circuit | |
501 | } | |
502 | } | |
503 | } | |
504 | } | |
505 | } | |
506 | if (has_h_headers && !has_c_files) | |
507 | objective_c_score += 5; | |
508 | ||
509 | char line[81], buf[81]; | |
510 | p = ohcount_sourcefile_get_contents(sourcefile); | |
511 | pe = p; | |
512 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
513 | while (pe < eof) { | |
514 | // Get a line at a time. | |
515 | while (pe < eof && *pe != '\r' && *pe != '\n') pe++; | |
516 | length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); | |
517 | strncpy(line, p, length); | |
518 | line[length] = '\0'; | |
519 | char *eol = line + strlen(line); | |
520 | char *line_end = pe; | |
521 | ||
522 | // Look for tell-tale lines. | |
523 | p = line; | |
524 | while (*p == ' ' || *p == '\t') p++; | |
525 | if (*p == '%') { // Matlab comment | |
526 | matlab_score++; | |
527 | } else if (*p == '#' && strncmp(p, "#import", 7) == 0) { // Objective C | |
528 | objective_c_score++; | |
529 | } else if (*p == '#') { // Limbo or Octave comment | |
530 | while (*p == '#') p++; | |
531 | if (*p == ' ' || *p == '\t') { | |
532 | limbo_score++; | |
533 | matlab_score++; | |
534 | octave_syntax_detected = 1; | |
535 | } | |
536 | } else if (*p == '/' && *(p + 1) == '/' || *(p + 1) == '*') { | |
537 | objective_c_score++; // Objective C comment | |
538 | } else if (*p == '+' || *p == '-') { // Objective C method signature | |
539 | objective_c_score++; | |
540 | } else if (*p == '@' || *p == '#') { // Objective C method signature | |
541 | if (strncmp(p, "@implementation", 15) == 0 || | |
542 | strncmp(p, "@interface", 10) == 0) | |
543 | objective_c_score++; | |
544 | } else if (strncmp(p, "function", 8) == 0) { // Matlab or Octave function | |
545 | p += 8; | |
546 | while (*p == ' ' || *p == '\t') p++; | |
547 | if (*p == '(') | |
548 | matlab_score++; | |
549 | } else if (strncmp(p, "include", 7) == 0) { // Limbo include | |
550 | // /^include[ \t]+"[^"]+\.m";/ | |
551 | p += 7; | |
552 | if (*p == ' ' || *p == '\t') { | |
553 | while (*p == ' ' || *p == '\t') p++; | |
554 | if (*p == '"') { | |
555 | while (*p != '"' && p < eol) p++; | |
556 | if (*p == '"' && *(p - 2) == '.' && *(p - 1) == 'm') | |
557 | limbo_score++; | |
558 | } | |
559 | } | |
560 | } | |
561 | ||
562 | // Look for Octave keywords. | |
563 | p = line; | |
564 | while (p < eol) { | |
565 | if (islower(*p) && p != line && !isalnum(*(p - 1))) { | |
566 | pe = p; | |
567 | while (islower(*pe) || *pe == '_') pe++; | |
568 | if (!isalnum(*pe)) { | |
569 | length = pe - p; | |
570 | strncpy(buf, p, length); | |
571 | buf[length] = '\0'; | |
572 | if (strcmp(buf, "end_try_catch") == 0 || | |
573 | strcmp(buf, "end_unwind_protect") == 0 || | |
574 | strcmp(buf, "endfunction") == 0 || | |
575 | strcmp(buf, "endwhile") == 0) | |
576 | octave_syntax_detected = 1; | |
577 | } | |
578 | p = pe + 1; | |
579 | } else p++; | |
580 | } | |
581 | ||
582 | // Look for Limbo declarations | |
583 | p = line; | |
584 | while (p < eol) { | |
585 | if (*p == ':' && (*(p + 1) == ' ' || *(p + 1) == '\t')) { | |
586 | // /:[ \t]+(module|adt|fn ?\(|con[ \t])/ | |
587 | p += 2; | |
588 | if (strncmp(p, "module", 6) == 0 && !isalnum(*(p + 6)) || | |
589 | strncmp(p, "adt", 3) == 0 && !isalnum(*(p + 3)) || | |
590 | strncmp(p, "fn", 2) == 0 && | |
591 | (*(p + 2) == ' ' && *(p + 3) == '(' || *(p + 2) == '(') || | |
592 | strncmp(p, "con", 3) == 0 && | |
593 | (*(p + 3) == ' ' || *(p + 3) == '\t')) | |
594 | limbo_score++; | |
595 | } else p++; | |
596 | } | |
597 | ||
598 | // Next line. | |
599 | pe = line_end; | |
600 | while (*pe == '\r' || *pe == '\n') pe++; | |
601 | p = pe; | |
602 | } | |
603 | ||
604 | if (limbo_score > objective_c_score && limbo_score > matlab_score) | |
605 | return LANG_LIMBO; | |
606 | else if (objective_c_score > matlab_score) | |
607 | return LANG_OBJECTIVE_C; | |
608 | else | |
609 | return octave_syntax_detected ? LANG_OCTAVE : LANG_MATLAB; | |
610 | } | |
611 | ||
612 | #define QMAKE_SOURCES_SPACE "SOURCES +=" | |
613 | #define QMAKE_SOURCES "SOURCES+=" | |
614 | #define QMAKE_CONFIG_SPACE "CONFIG +=" | |
615 | #define QMAKE_CONFIG "CONFIG+=" | |
616 | ||
617 | const char *disambiguate_pro(SourceFile *sourcefile) { | |
618 | char *p = ohcount_sourcefile_get_contents(sourcefile); | |
619 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
620 | for (; p < eof; p++) { | |
621 | if (strncmp(p, QMAKE_SOURCES_SPACE, strlen(QMAKE_SOURCES_SPACE)) == 0 || | |
622 | strncmp(p, QMAKE_SOURCES, strlen(QMAKE_SOURCES)) == 0 || | |
623 | strncmp(p, QMAKE_CONFIG_SPACE, strlen(QMAKE_CONFIG_SPACE)) == 0 || | |
624 | strncmp(p, QMAKE_CONFIG, strlen(QMAKE_CONFIG)) == 0) | |
625 | return LANG_MAKE; // really QMAKE | |
626 | } | |
627 | return LANG_IDL_PVWAVE; | |
628 | } | |
629 | ||
630 | const char *disambiguate_st(SourceFile *sourcefile) { | |
631 | char *p, *pe; | |
632 | int length; | |
633 | ||
634 | // Attempt to detect based on file contents. | |
635 | int found_assignment = 0, found_block_start = 0, found_block_end = 0; | |
636 | ||
637 | char line[81]; | |
638 | p = ohcount_sourcefile_get_contents(sourcefile); | |
639 | pe = p; | |
640 | char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); | |
641 | while (pe < eof) { | |
642 | // Get a line at a time. | |
643 | while (p < eof && *pe != '\r' && *pe != '\n') pe++; | |
644 | length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); | |
645 | strncpy(line, p, length); | |
646 | line[length] = '\0'; | |
647 | char *eol = line + strlen(line); | |
648 | char *line_end = pe; | |
649 | ||
650 | for (p = line; p < eol; p++) { | |
651 | if (*p == ':') { | |
652 | p++; | |
653 | while (p < eol && (*p == ' ' || *p == '\t')) p++; | |
654 | if (*p == '=') | |
655 | found_assignment = 1; | |
656 | else if (*p == '[') | |
657 | found_block_start = 1; | |
658 | } else if (*p == ']' && *(p + 1) == '.') found_block_end = 1; | |
659 | if (found_assignment && found_block_start && found_block_end) | |
660 | return LANG_SMALLTALK; | |
661 | } | |
662 | ||
663 | // Next line. | |
664 | pe = line_end; | |
665 | while (*pe == '\r' || *pe == '\n') pe++; | |
666 | p = pe; | |
667 | } | |
668 | ||
669 | return NULL; | |
670 | } | |
671 | ||
672 | int ohcount_is_binary_filename(const char *filename) { | |
673 | char *p = (char *)filename + strlen(filename); | |
674 | while (p > filename && *(p - 1) != '.') p--; | |
675 | if (p > filename) { | |
676 | struct ExtensionMap *re; | |
677 | int length = strlen(p); | |
678 | re = ohcount_hash_language_from_ext(p, length); | |
679 | if (re) return ISBINARY(re->value); | |
680 | // Try the lower-case version of this extension. | |
681 | char lowerext[length]; | |
682 | strncpy(lowerext, p, length); | |
683 | lowerext[length] = '\0'; | |
684 | for (p = lowerext; p < lowerext + length; p++) *p = tolower(*p); | |
685 | re = ohcount_hash_language_from_ext(lowerext, length); | |
686 | if (re) return ISBINARY(re->value); | |
687 | } | |
688 | return 0; | |
689 | } |
0 | // detector_test.h written by Mitchell Foral. mitchell<att>caladbolg.net. | |
1 | // See COPYING for license information. | |
2 | ||
3 | #include <assert.h> | |
4 | #include <stdlib.h> | |
5 | #include <string.h> | |
6 | ||
7 | #include "../../src/detector.h" | |
8 | #include "../../src/languages.h" | |
9 | #include "../../src/sourcefile.h" | |
10 | ||
11 | #define ASSERT_DETECT(x, y) { \ | |
12 | SourceFile *sf = ohcount_sourcefile_new("../detect_files/" y); \ | |
13 | const char *lang = ohcount_detect_language(sf); \ | |
14 | assert(lang); \ | |
15 | assert(strcmp(x, lang) == 0); \ | |
16 | ohcount_sourcefile_free(sf); \ | |
17 | } | |
18 | #define ASSERT_NODETECT(x) { \ | |
19 | SourceFile *sf = ohcount_sourcefile_new("../detect_files/" x); \ | |
20 | assert(ohcount_detect_language(sf) == NULL); \ | |
21 | ohcount_sourcefile_free(sf); \ | |
22 | } | |
23 | ||
24 | void test_detector_smalltalk() { | |
25 | ASSERT_DETECT(LANG_SMALLTALK, "example.st"); | |
26 | ASSERT_NODETECT("english.st"); | |
27 | } | |
28 | ||
29 | void test_detector_disambiguate_m() { | |
30 | ASSERT_DETECT(LANG_OBJECTIVE_C, "t1.m"); | |
31 | ASSERT_DETECT(LANG_OBJECTIVE_C, "t2.m"); | |
32 | ASSERT_DETECT(LANG_OBJECTIVE_C, "TCPSocket.m"); | |
33 | ASSERT_DETECT(LANG_OBJECTIVE_C, "foo_objective_c.m"); | |
34 | ASSERT_DETECT(LANG_MATLAB, "foo_matlab.m"); | |
35 | ASSERT_DETECT(LANG_OCTAVE, "foo_octave.m"); | |
36 | } | |
37 | ||
38 | void test_detector_disambiguate_pro() { | |
39 | ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); | |
40 | ASSERT_DETECT(LANG_MAKE, "qmake.pro"); | |
41 | } | |
42 | ||
43 | void test_detector_fortran_fixedfree() { | |
44 | ASSERT_DETECT(LANG_FORTRANFIXED, "fortranfixed.f"); | |
45 | ASSERT_DETECT(LANG_FORTRANFREE, "fortranfree.f"); | |
46 | } | |
47 | ||
48 | void test_detector_detect_polyglot() { | |
49 | ASSERT_DETECT(LANG_C, "foo.c"); | |
50 | ASSERT_DETECT(LANG_C, "uses_no_cpp.h"); | |
51 | ASSERT_DETECT(LANG_CPP, "uses_cpp_headers.h"); | |
52 | ASSERT_DETECT(LANG_CPP, "uses_cpp_stdlib_headers.h"); | |
53 | ASSERT_DETECT(LANG_CPP, "uses_cpp_keywords.h"); | |
54 | ASSERT_DETECT(LANG_RUBY, "foo.rb"); | |
55 | ASSERT_DETECT(LANG_MAKE, "foo.mk"); | |
56 | ASSERT_DETECT(LANG_OBJECTIVE_C, "foo_objective_c.h"); | |
57 | ASSERT_DETECT(LANG_PHP, "upper_case_php"); | |
58 | ASSERT_DETECT(LANG_SMALLTALK, "example.st"); | |
59 | ASSERT_DETECT(LANG_VALA, "foo.vala"); | |
60 | ASSERT_DETECT(LANG_TEX, "foo.tex"); | |
61 | ASSERT_DETECT(LANG_XSLT, "example.xsl"); | |
62 | ASSERT_DETECT(LANG_LISP, "core.lisp"); | |
63 | ASSERT_DETECT(LANG_DMD, "foo.d"); | |
64 | ASSERT_DETECT(LANG_VIM, "foo.vim"); | |
65 | ASSERT_DETECT(LANG_EBUILD, "foo.ebuild"); | |
66 | ASSERT_DETECT(LANG_EBUILD, "foo.eclass"); | |
67 | ASSERT_DETECT(LANG_EXHERES, "foo.exheres-0"); | |
68 | ASSERT_DETECT(LANG_EXHERES, "foo.exlib"); | |
69 | ASSERT_DETECT(LANG_EIFFEL, "eiffel.e"); | |
70 | ASSERT_DETECT(LANG_OCAML, "ocaml.ml"); | |
71 | ASSERT_DETECT(LANG_STRATEGO, "stratego.str"); | |
72 | ASSERT_DETECT(LANG_R, "foo.R"); | |
73 | ASSERT_DETECT(LANG_GLSL, "foo.glsl"); | |
74 | ASSERT_DETECT(LANG_GLSL, "foo_glsl.vert"); | |
75 | ASSERT_DETECT(LANG_GLSL, "foo_glsl.frag"); | |
76 | ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); | |
77 | ASSERT_DETECT(LANG_ASSEMBLER, "foo.z80"); | |
78 | ASSERT_DETECT(LANG_PHP, "php.inc"); | |
79 | ASSERT_DETECT(LANG_FSHARP, "fs1.fs"); | |
80 | } | |
81 | ||
82 | void test_detector_upper_case_extensions() { | |
83 | ASSERT_DETECT(LANG_CPP, "foo_upper_case.C"); | |
84 | ASSERT_DETECT(LANG_RUBY, "foo_upper_case.RB"); | |
85 | } | |
86 | ||
87 | void test_detector_no_extensions() { | |
88 | ASSERT_DETECT(LANG_PYTHON, "py_script"); | |
89 | ASSERT_DETECT(LANG_RUBY, "ruby_script"); | |
90 | ASSERT_DETECT(LANG_SHELL, "bourne_again_script"); | |
91 | ASSERT_DETECT(LANG_SHELL, "bash_script"); | |
92 | ASSERT_DETECT(LANG_PERL, "perl_w"); | |
93 | ASSERT_DETECT(LANG_DMD, "d_script"); | |
94 | ASSERT_DETECT(LANG_TCL, "tcl_script"); | |
95 | ASSERT_DETECT(LANG_PYTHON, "python.data"); | |
96 | ASSERT_DETECT(LANG_PYTHON, "python2.data"); | |
97 | } | |
98 | ||
99 | void test_detector_csharp_or_clearsilver() { | |
100 | ASSERT_DETECT(LANG_CSHARP, "cs1.cs"); | |
101 | ASSERT_DETECT(LANG_CLEARSILVER_TEMPLATE, "clearsilver_template1.cs"); | |
102 | } | |
103 | ||
104 | void test_detector_basic() { | |
105 | ASSERT_DETECT(LANG_VISUALBASIC, "visual_basic.bas"); | |
106 | ASSERT_DETECT(LANG_CLASSIC_BASIC, "classic_basic.b"); | |
107 | system("mv ../detect_files/frx1.frx ../detect_files/frx1.frx2"); | |
108 | ASSERT_DETECT(LANG_STRUCTURED_BASIC, "visual_basic.bas"); | |
109 | ASSERT_DETECT(LANG_STRUCTURED_BASIC, "structured_basic.b"); | |
110 | system("mv ../detect_files/frx1.frx2 ../detect_files/frx1.frx"); | |
111 | } | |
112 | ||
113 | void test_detector_xml_with_custom_extension() { | |
114 | ASSERT_DETECT(LANG_XML, "xml.custom_ext"); | |
115 | } | |
116 | ||
117 | void all_detector_tests() { | |
118 | test_detector_smalltalk(); | |
119 | test_detector_disambiguate_m(); | |
120 | test_detector_disambiguate_pro(); | |
121 | test_detector_fortran_fixedfree(); | |
122 | test_detector_detect_polyglot(); | |
123 | test_detector_upper_case_extensions(); | |
124 | test_detector_no_extensions(); | |
125 | test_detector_csharp_or_clearsilver(); | |
126 | test_detector_basic(); | |
127 | test_detector_xml_with_custom_extension(); | |
128 | } |
0 | #!/usr/bin/env bash | |
1 | # Build script for Ohcount. | |
2 | # Written by Mitchell Foral. mitchell<att>caladbolg.net. | |
3 | ||
4 | # Options | |
5 | # Change these for your system configuration. | |
6 | if [ `uname` != "Darwin" ] | |
7 | then | |
8 | # Linux | |
9 | INC_DIR= | |
10 | LIB_DIR= | |
11 | ||
12 | if [ `uname` == "FreeBSD" ] | |
13 | then | |
14 | INC_DIR=/usr/local/include | |
15 | LIB_DIR=/usr/local/lib | |
16 | fi | |
17 | ||
18 | # You shouldn't have to change the following. | |
19 | CFLAGS=-O3 | |
20 | CFLAGS="$CFLAGS -DTMP_FILES_ARE_DT_UNKNOWN" # workaround bug on centos/SF servers | |
21 | WARN="-Wall -Wno-pointer-to-int-cast -Wno-parentheses" | |
22 | SHARED=-shared | |
23 | SHARED_NAME=libohcount.so | |
24 | RB_SHARED=-shared | |
25 | RB_SHARED_NAME=ohcount.so | |
26 | else | |
27 | # Mac OSX | |
28 | INC_DIR=/opt/local/include | |
29 | LIB_DIR=/opt/local/lib | |
30 | # You shouldn't have to change the following. | |
31 | CFLAGS="-fno-common -g" | |
32 | WARN="-Wall -Wno-parentheses" | |
33 | SHARED="-dynamiclib -L$LIB_DIR -lpcre" | |
34 | SHARED_NAME=libohcount.dylib | |
35 | RB_SHARED="-dynamic -bundle -lruby" | |
36 | RB_SHARED_NAME=ohcount.bundle | |
37 | fi | |
38 | ||
39 | # C compiler and flags | |
40 | cc="gcc -fPIC -g $CFLAGS $WARN -I$INC_DIR -L$LIB_DIR" | |
41 | ||
42 | # Ohcount source files | |
43 | files="src/sourcefile.c \ | |
44 | src/detector.c \ | |
45 | src/licenses.c \ | |
46 | src/parser.o \ | |
47 | src/loc.c \ | |
48 | src/log.c \ | |
49 | src/diff.c \ | |
50 | src/parsed_language.c \ | |
51 | src/hash/language_hash.c" | |
52 | ||
53 | # If any src/hash/*.gperf file is newer than the header files (which were | |
54 | # presumably generated together), regenerate the headers. | |
55 | build_hash_headers() | |
56 | { | |
57 | if [[ -z `ls src/hash/ | grep "_hash.h$"` || | |
58 | ! -z `find src/hash/*.gperf -newer src/hash/parser_hash.h` ]] | |
59 | then | |
60 | echo "Generating hash headers" | |
61 | sh -c "cd src/hash/ && ./generate_headers" || exit 1 | |
62 | fi | |
63 | } | |
64 | ||
65 | # If src/parser.o does not exist, or if there are Ragel parsers or parser | |
66 | # header files newer than the existing parser.o, recompile parser.o. | |
67 | build_parser_o() | |
68 | { | |
69 | if [[ ! -f src/parser.o || | |
70 | ! -z `find src/parsers/*.{h,rl} -newer src/parser.o` ]] | |
71 | then | |
72 | bash -c "cd src/parsers/ && bash ./compile" || exit 1 | |
73 | echo "Building src/parser.c (will take a while)" | |
74 | bash -c "$cc -c src/parser.c -o src/parser.o" || exit 1 | |
75 | fi | |
76 | } | |
77 | ||
78 | build_shared() | |
79 | { | |
80 | build_hash_headers | |
81 | build_parser_o | |
82 | if [[ ! -f src/$SHARED_NAME || | |
83 | ! -z `find src/*.{h,c} -newer src/$SHARED_NAME` ]] | |
84 | then | |
85 | echo "Building shared library" | |
86 | sh -c "$cc $SHARED $files -o src/$SHARED_NAME" || exit 1 | |
87 | fi | |
88 | } | |
89 | ||
90 | build_ohcount() | |
91 | { | |
92 | build_hash_headers | |
93 | build_parser_o | |
94 | echo "Building Ohcount" | |
95 | mkdir -p bin/ | |
96 | sh -c "$cc src/ohcount.c $files -o bin/ohcount -lpcre" || exit 1 | |
97 | } | |
98 | ||
99 | build_test_suite() | |
100 | { | |
101 | build_hash_headers | |
102 | build_parser_o | |
103 | echo "Building test suite" | |
104 | sh -c "$cc test/unit/all_tests.c $files -o test/unit/run_tests -lpcre" \ | |
105 | || exit 1 | |
106 | } | |
107 | ||
108 | run_test_suite() | |
109 | { | |
110 | echo "Running test suite" | |
111 | echo "disabled test suite, does not work" | |
112 | } | |
113 | ||
114 | build_ruby_bindings() | |
115 | { | |
116 | arch=`ruby -rmkmf -e 'print Config::expand(CONFIG["arch"])'` | |
117 | echo "Generating Ruby bindings for $arch" | |
118 | sh -c "swig -ruby -o ruby/ohcount_wrap.c ruby/ohcount.i" || exit 1 | |
119 | mkdir -p ruby/$arch | |
120 | sh -c "$cc $RB_SHARED ruby/ohcount_wrap.c $files -o ruby/$arch/$RB_SHARED_NAME \ | |
121 | -I`ruby -rmkmf -e 'print Config::expand(CONFIG["archdir"])'` \ | |
122 | -lpcre" || exit 1 | |
123 | sh -c "cd test/unit/ruby && ruby ruby_test.rb" || exit 1 | |
124 | } | |
125 | ||
126 | if [ $# -eq 0 ] || [ $1 == "all" ] | |
127 | then | |
128 | build_ohcount | |
129 | build_test_suite | |
130 | run_test_suite | |
131 | echo $success | |
132 | elif [ $1 == "shared" ] | |
133 | then | |
134 | build_shared | |
135 | echo "Build successful; $SHARED_NAME is in src/" | |
136 | elif [ $1 == "ohcount" ] | |
137 | then | |
138 | build_ohcount | |
139 | echo "Build successful; ohcount is in bin/" | |
140 | elif [ $1 == "tests" ] | |
141 | then | |
142 | build_test_suite | |
143 | run_test_suite | |
144 | elif [ $1 == "ruby" ] | |
145 | then | |
146 | build_ruby_bindings | |
147 | echo "Build successful; $RB_SHARED_NAME is in ruby/$arch" | |
148 | elif [ $1 == "clean" ] | |
149 | then | |
150 | rm -f bin/ohcount | |
151 | rm -f test/unit/run_tests | |
152 | rm -f src/parser.o | |
153 | rm -f src/parsers/*.h | |
154 | rm -f src/hash/*.h | |
155 | rm -f src/hash/*.c | |
156 | rm -f src/$SHARED_NAME | |
157 | rm -f ruby/$RB_SHARED_NAME | |
158 | rm -rf ruby/`ruby -rmkmf -e 'print Config::expand(CONFIG["arch"])'`/* | |
159 | else | |
160 | echo "Usage: build [all|ohcount|shared|tests|ruby|clean]" | |
161 | fi |
0 | %{ | |
1 | #include "../languages.h" | |
2 | ||
3 | #define BINARY "\1" | |
4 | #define DISAMBIGUATE(x) ("\2" x) | |
5 | %} | |
6 | struct ExtensionMap { const char *key; const char *value; }; | |
7 | %% | |
8 | C, LANG_CPP | |
9 | H, LANG_CPP | |
10 | ada, LANG_ADA | |
11 | adb, LANG_ADA | |
12 | ads, LANG_ADA | |
13 | aiff, BINARY | |
14 | as, LANG_ACTIONSCRIPT | |
15 | ascx, DISAMBIGUATE("aspx") | |
16 | asm, LANG_ASSEMBLER | |
17 | aspx, DISAMBIGUATE("aspx") | |
18 | au, BINARY | |
19 | avi, BINARY | |
20 | awk, LANG_AWK | |
21 | b, DISAMBIGUATE("b") | |
22 | bas, DISAMBIGUATE("basic") | |
23 | bat, LANG_BAT | |
24 | bi, DISAMBIGUATE("basic") | |
25 | bmp, BINARY | |
26 | bmx, LANG_BLITZMAX | |
27 | boo, LANG_BOO | |
28 | c, LANG_C | |
29 | c++, LANG_CPP | |
30 | cache, BINARY | |
31 | cc, LANG_CPP | |
32 | cmake, LANG_CMAKE | |
33 | com, LANG_DCL | |
34 | cpp, LANG_CPP | |
35 | cs, DISAMBIGUATE("cs") | |
36 | csproj, LANG_XML | |
37 | css, LANG_CSS | |
38 | ctp, LANG_PHP | |
39 | cxx, LANG_CPP | |
40 | d, LANG_DMD | |
41 | dat, BINARY | |
42 | di, LANG_DMD | |
43 | doc, BINARY | |
44 | dylan, LANG_DYLAN | |
45 | e, LANG_EIFFEL | |
46 | ebuild, LANG_EBUILD | |
47 | eclass, LANG_EBUILD | |
48 | el, LANG_EMACSLISP | |
49 | erl, LANG_ERLANG | |
50 | exheres-0, LANG_EXHERES | |
51 | exlib, LANG_EXHERES | |
52 | f, DISAMBIGUATE("fortran") | |
53 | f03, DISAMBIGUATE("fortran") | |
54 | f77, DISAMBIGUATE("fortran") | |
55 | f90, DISAMBIGUATE("fortran") | |
56 | f95, DISAMBIGUATE("fortran") | |
57 | factor, LANG_FACTOR | |
58 | frag, LANG_GLSL | |
59 | frm, LANG_VISUALBASIC | |
60 | frx, LANG_VISUALBASIC | |
61 | fs, LANG_FSHARP | |
62 | ftn, DISAMBIGUATE("fortran") | |
63 | gif, BINARY | |
64 | glsl, LANG_GLSL | |
65 | groovy, LANG_GROOVY | |
66 | gz, BINARY | |
67 | h, DISAMBIGUATE("h") | |
68 | h++, LANG_CPP | |
69 | haml, LANG_HAML | |
70 | hh, LANG_CPP | |
71 | hpp, LANG_CPP | |
72 | hrl, LANG_ERLANG | |
73 | hs, LANG_HASKELL | |
74 | htm, LANG_HTML | |
75 | html, LANG_HTML | |
76 | hx, LANG_HAXE | |
77 | hxx, LANG_CPP | |
78 | icns, BINARY | |
79 | in, DISAMBIGUATE("in") | |
80 | inc, DISAMBIGUATE("inc") | |
81 | j, LANG_OBJECTIVE_J | |
82 | jar, BINARY | |
83 | java, LANG_JAVA | |
84 | jpeg, BINARY | |
85 | jpg, BINARY | |
86 | js, LANG_JAVASCRIPT | |
87 | jsp, LANG_JSP | |
88 | kdebuild-1, LANG_EBUILD | |
89 | latex, LANG_TEX | |
90 | lisp, LANG_LISP | |
91 | lsp, LANG_LISP | |
92 | ltx, LANG_TEX | |
93 | lua, LANG_LUA | |
94 | m, DISAMBIGUATE("m") | |
95 | m4a, BINARY | |
96 | mf, LANG_METAFONT | |
97 | mk, LANG_MAKE | |
98 | ml, LANG_OCAML | |
99 | ml4, LANG_OCAML | |
100 | mli, LANG_OCAML | |
101 | mm, LANG_OBJECTIVE_C | |
102 | mov, BINARY | |
103 | mp, LANG_METAPOST_WITH_TEX | |
104 | mp3, BINARY | |
105 | mpg, BINARY | |
106 | mxml, LANG_MXML | |
107 | nix, LANG_NIX | |
108 | nse, LANG_LUA | |
109 | ogg, BINARY | |
110 | p6, LANG_PERL | |
111 | pas, LANG_PASCAL | |
112 | perl, LANG_PERL | |
113 | pdf, BINARY | |
114 | ph, LANG_PERL | |
115 | php, LANG_PHP | |
116 | php3, LANG_PHP | |
117 | php4, LANG_PHP | |
118 | php5, LANG_PHP | |
119 | pike, LANG_PIKE | |
120 | pl, LANG_PERL | |
121 | pm, LANG_PERL | |
122 | pmc, LANG_C | |
123 | pmod, LANG_PIKE | |
124 | png, BINARY | |
125 | pnt, BINARY | |
126 | pod, LANG_PERL | |
127 | pp, LANG_PASCAL | |
128 | ppt, BINARY | |
129 | pro, DISAMBIGUATE("pro") | |
130 | py, LANG_PYTHON | |
131 | qt, BINARY | |
132 | r, LANG_R | |
133 | ra, BINARY | |
134 | rb, LANG_RUBY | |
135 | rex, LANG_REXX | |
136 | rexx, LANG_REXX | |
137 | rhtml, LANG_RHTML | |
138 | s, LANG_ASSEMBLER | |
139 | sc, LANG_SCHEME | |
140 | scala, LANG_SCALA | |
141 | sce, LANG_SCILAB | |
142 | sci, LANG_SCILAB | |
143 | scm, LANG_SCHEME | |
144 | sh, LANG_SHELL | |
145 | sls, LANG_SCHEME | |
146 | sps, LANG_SCHEME | |
147 | sql, LANG_SQL | |
148 | ss, LANG_SCHEME | |
149 | st, DISAMBIGUATE("st") | |
150 | str, LANG_STRATEGO | |
151 | svg, BINARY | |
152 | svgz, BINARY | |
153 | svn, BINARY | |
154 | swf, BINARY | |
155 | t, LANG_PERL | |
156 | tar, BINARY | |
157 | tcl, LANG_TCL | |
158 | tex, LANG_TEX | |
159 | tgz, BINARY | |
160 | tif, BINARY | |
161 | tiff, BINARY | |
162 | tpl, LANG_HTML | |
163 | vala, LANG_VALA | |
164 | vb, LANG_VISUALBASIC | |
165 | vba, LANG_VISUALBASIC | |
166 | vbs, LANG_VISUALBASIC | |
167 | vert, LANG_GLSL | |
168 | vhd, LANG_VHDL | |
169 | vhdl, LANG_VHDL | |
170 | vim, LANG_VIM | |
171 | wav, BINARY | |
172 | xaml, LANG_XAML | |
173 | xls, BINARY | |
174 | xlw, BINARY | |
175 | xml, LANG_XML | |
176 | xs, LANG_C | |
177 | xsd, LANG_XMLSCHEMA | |
178 | xsl, LANG_XSLT | |
179 | z80, LANG_ASSEMBLER | |
180 | zip, BINARY |
0 | == Ohcount | |
1 | ||
2 | NOTE: THE PRIMARY DOCUMENTATION FOR OHCOUNT IS EXTRACTED FROM SOURCE CODE | |
3 | BY DOXYGEN. FOR THE MOST UP-TO-DATE DOCS, PLEASE SEE BELOW FOR INFO | |
4 | ON BUILDING AND REFERING TO THE DOXYGEN DOCS. | |
5 | ||
6 | Ohloh/SourceForge's source code line counter. | |
7 | ||
8 | This program is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License Version 2 as | |
10 | published by the Free Software Foundation. | |
11 | ||
12 | Ohcount is specifically licensed under GPL v2.0, and no later version. | |
13 | ||
14 | This program is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with this program. If not, see <http://www.gnu.org/licenses/>. | |
21 | ||
22 | == Overview | |
23 | ||
24 | Ohcount is a library for counting lines of source code. | |
25 | It was originally developed at Ohloh, and is used to generate | |
26 | the reports at www.ohloh.net. | |
27 | ||
28 | Ohcount supports multiple languages within a single file: for example, | |
29 | a complex HTML document might include regions of both CSS and JavaScript. | |
30 | ||
31 | Ohcount has two main components: a detector which determines the primary | |
32 | language family used by a particular source file, and a parser which | |
33 | provides a line-by-line breakdown of the contents of a source file. | |
34 | ||
35 | Ohcount includes a command line tool that allows you to count individual | |
36 | files or whole directory trees. It also allows you to find source code | |
37 | files by language family, or to create a detailed annotation of an | |
38 | individual source file. | |
39 | ||
40 | Ohcount includes a Ruby binding which allows you to directly access its | |
41 | language detection features from a Ruby application. | |
42 | ||
43 | == System Requirements | |
44 | ||
45 | Ohcount is supported on Mac OS X 10.4 and 10.5 and Ubuntu 8.04 LTS. Other Linux | |
46 | environments should also work, but your mileage may vary. | |
47 | ||
48 | Ohcount does not support Windows. | |
49 | ||
50 | Ohcount targets Ruby 1.8.6. The build script requires a bash shell. You | |
51 | also need a C compiler to build the native extensions. | |
52 | ||
53 | == Source Code == | |
54 | ||
55 | Ohcount source code is available as a Git repository: | |
56 | ||
57 | git clone git://github.com/andyverprauskus/ohcount.git | |
58 | ||
59 | == Doc files == | |
60 | ||
61 | To build the more extensive Doxygen docs, do | |
62 | > cd doc | |
63 | > Doxygen Doxyfile | |
64 | ||
65 | After building the docs, view them with a browser by opening doc/html/index.html. | |
66 | On a mac, you can install Doxygen with "sudo port install Doxygen". | |
67 | On Debian/Ubuntu, install with "sudo apt-get instal doxygen". | |
68 | ||
69 | == Building Ohcount == | |
70 | ||
71 | You will need ragel 6.3 or higher, bash, pcre, gcc (version 4.1.2 or greater) and SWIG to build ohcount. Once you have them, go to the top directory of ohcount and type: | |
72 | ||
73 | > bash build | |
74 | or > ./build | |
75 | ||
76 | == Using Ohcount == | |
77 | ||
78 | Once you've building ohcount, the executable program will be at bin/ohcount. The most basic use is to count lines of code in a directory tree, run: | |
79 | "ohcount" to count the current directory and source code in any child directories | |
80 | ||
81 | == For additional docs, including how to add a new language, see the Doxygen docs == | |
82 | ||
83 | Particularly, for instructions on adding a new language, follow the instructions at doc/html/detector_doc.html | |
84 | Read http://labs.ohloh.net/ohcount/wiki/HowToSubmitPatches for information about having your patch accepted. | |
85 | ||
86 | ||
87 | DEPENDENCIES | |
88 | ============ | |
89 | SWIG, pcre, ragel, bash |
0 | Ohcount | |
1 | ======= | |
2 | ||
3 | Ohloh's source code line counter. | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License Version 2 as | |
7 | published by the Free Software Foundation. | |
8 | ||
9 | License | |
10 | ------- | |
11 | ||
12 | Ohcount is specifically licensed under GPL v2.0, and no later version. | |
13 | ||
14 | This program is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with this program. If not, see <http://www.gnu.org/licenses/>. | |
21 | ||
22 | Overview | |
23 | -------- | |
24 | ||
25 | Ohcount is a library for counting lines of source code. | |
26 | It was originally developed at Ohloh, and is used to generate | |
27 | the reports at www.openhub.net. | |
28 | ||
29 | Ohcount supports multiple languages within a single file: for example, | |
30 | a complex HTML document might include regions of both CSS and JavaScript. | |
31 | ||
32 | Ohcount has two main components: a detector which determines the primary | |
33 | language family used by a particular source file, and a parser which | |
34 | provides a line-by-line breakdown of the contents of a source file. | |
35 | ||
36 | Ohcount includes a command line tool that allows you to count individual | |
37 | files or whole directory trees. It also allows you to find source code | |
38 | files by language family, or to create a detailed annotation of an | |
39 | individual source file. | |
40 | ||
41 | Ohcount includes a Ruby binding which allows you to directly access its | |
42 | language detection features from a Ruby application. | |
43 | ||
44 | System Requirements | |
45 | ------------------- | |
46 | ||
47 | Ohcount is supported on Ubuntu 14.04 LTS. Other Linux | |
48 | environments should also work, but your mileage may vary. | |
49 | ||
50 | Ohcount does not support Windows. | |
51 | ||
52 | Ohcount targets Ruby 1.9.3. The build script requires a bash shell. You | |
53 | also need a C compiler to build the native extensions. | |
54 | ||
55 | Source Code | |
56 | ----------- | |
57 | ||
58 | Ohcount source code is available as a Git repository: | |
59 | ||
60 | git clone git://github.com/blackducksw/ohcount.git | |
61 | ||
62 | Building Ohcount | |
63 | ---------------- | |
64 | ||
65 | You will need ragel 6.8 or higher, bash, gperf, libpcre3-dev, libmagic-dev, gcc (version 4.8.2 or greater) | |
66 | and SWIG (2.0.11). Once you have them, go to the top directory of ohcount and run | |
67 | ||
68 | ``` | |
69 | ./build | |
70 | ``` | |
71 | ||
72 | Using Ohcount | |
73 | ------------- | |
74 | ||
75 | Once you've built ohcount, the executable program will be at bin/ohcount. The most basic use is to count lines of code in a directory tree. run: | |
76 | ||
77 | ``` | |
78 | bin/ohcount | |
79 | ``` | |
80 | ||
81 | Ohcount support several options. Run `ohcount --help` for more information. | |
82 | ||
83 | Building Ruby and Python Libraries | |
84 | ---------------------------------- | |
85 | ||
86 | To build the ruby wrapper: | |
87 | ||
88 | ``` | |
89 | ./build ruby | |
90 | ``` | |
91 | ||
92 | To build the python wrapper, run | |
93 | ||
94 | ``` | |
95 | python python/setup.py build | |
96 | python python/setup.py install | |
97 | ``` | |
98 | ||
99 | The python wrapper is currently unsupported. |
17 | 17 | |
18 | 18 | # You shouldn't have to change the following. |
19 | 19 | CFLAGS=-O3 |
20 | CFLAGS="$CFLAGS -DTMP_FILES_ARE_DT_UNKNOWN" # workaround bug on centos/SF servers | |
21 | 20 | WARN="-Wall -Wno-pointer-to-int-cast -Wno-parentheses" |
22 | 21 | SHARED=-shared |
23 | 22 | SHARED_NAME=libohcount.so |
38 | 37 | |
39 | 38 | # C compiler and flags |
40 | 39 | cc="gcc -fPIC -g $CFLAGS $WARN -I$INC_DIR -L$LIB_DIR" |
40 | ||
41 | # ARCHITECTURE | |
42 | arch=`ruby/print_arch` | |
41 | 43 | |
42 | 44 | # Ohcount source files |
43 | 45 | files="src/sourcefile.c \ |
93 | 95 | build_parser_o |
94 | 96 | echo "Building Ohcount" |
95 | 97 | mkdir -p bin/ |
96 | sh -c "$cc src/ohcount.c $files -o bin/ohcount -lpcre" || exit 1 | |
98 | sh -c "$cc src/ohcount.c $files -o bin/ohcount -lpcre -lmagic" || exit 1 | |
97 | 99 | } |
98 | 100 | |
99 | 101 | build_test_suite() |
101 | 103 | build_hash_headers |
102 | 104 | build_parser_o |
103 | 105 | echo "Building test suite" |
104 | sh -c "$cc test/unit/all_tests.c $files -o test/unit/run_tests -lpcre" \ | |
106 | sh -c "$cc test/unit/all_tests.c $files -o test/unit/run_tests -lpcre -lmagic" \ | |
105 | 107 | || exit 1 |
106 | 108 | } |
107 | 109 | |
108 | 110 | run_test_suite() |
109 | 111 | { |
110 | 112 | echo "Running test suite" |
111 | echo "disabled test suite, does not work" | |
113 | sh -c "cd test/unit/ && ./run_tests" | |
112 | 114 | } |
115 | ||
116 | RUBY_HEADER_DIR=`ruby -rmkmf -e 'print RbConfig::expand(CONFIG["rubyhdrdir"])'` | |
117 | rbconfig_arch=`ruby -rmkmf -e 'print RbConfig::expand(CONFIG["arch"])'` | |
118 | RUBY_CONFIG_DIR="$RUBY_HEADER_DIR/$rbconfig_arch" | |
113 | 119 | |
114 | 120 | build_ruby_bindings() |
115 | 121 | { |
116 | arch=`ruby -rmkmf -e 'print RbConfig::expand(RbConfig::CONFIG["arch"])'` | |
117 | 122 | echo "Generating Ruby bindings for $arch" |
118 | 123 | sh -c "swig -ruby -o ruby/ohcount_wrap.c ruby/ohcount.i" || exit 1 |
119 | 124 | mkdir -p ruby/$arch |
120 | 125 | sh -c "$cc $RB_SHARED ruby/ohcount_wrap.c $files -o ruby/$arch/$RB_SHARED_NAME \ |
121 | -I`ruby -rmkmf -e 'print RbConfig::expand(RbConfig::CONFIG["archdir"])'` \ | |
122 | -lpcre" || exit 1 | |
126 | -I$RUBY_HEADER_DIR -I$RUBY_CONFIG_DIR \ | |
127 | -lpcre -lmagic" || exit 1 | |
123 | 128 | sh -c "cd test/unit/ruby && ruby ruby_test.rb" || exit 1 |
124 | 129 | } |
125 | 130 | |
128 | 133 | build_ohcount |
129 | 134 | build_test_suite |
130 | 135 | run_test_suite |
136 | build_ruby_bindings | |
131 | 137 | echo $success |
132 | 138 | elif [ $1 == "shared" ] |
133 | 139 | then |
155 | 161 | rm -f src/hash/*.c |
156 | 162 | rm -f src/$SHARED_NAME |
157 | 163 | rm -f ruby/$RB_SHARED_NAME |
158 | rm -rf ruby/`ruby -rmkmf -e 'print RbConfig::expand(RbConfig::CONFIG["arch"])'`/* | |
164 | rm -rf ruby/$arch/* | |
165 | rm -f ruby/ohcount_wrap.c | |
159 | 166 | else |
160 | 167 | echo "Usage: build [all|ohcount|shared|tests|ruby|clean]" |
161 | 168 | fi |
0 | ohcount (3.0.0-8.4) unstable; urgency=medium | |
1 | ||
2 | * Standards-Version updated to 4.1.3 | |
3 | * Update of Vcs-* | |
4 | * Update of the homepage | |
5 | * Add a watch file | |
6 | ||
7 | -- Sylvestre Ledru <sylvestre@debian.org> Sun, 14 Jan 2018 19:03:49 +0100 | |
8 | ||
9 | ohcount (3.0.0-8.3) unstable; urgency=medium | |
10 | ||
11 | * Non-maintainer upload. | |
12 | * Remove ruby files from ohcount-doc, which only get installed | |
13 | when building for Arch: all. (Closes: #818239) | |
14 | ||
15 | -- Christian Hofstaedtler <zeha@debian.org> Thu, 22 Dec 2016 06:54:28 +0000 | |
16 | ||
17 | ohcount (3.0.0-8.2) unstable; urgency=medium | |
18 | ||
19 | * Non-maintainer upload. | |
20 | * Source-ful, binary-less upload to get rid of /ruby directory. | |
21 | Probably somehow my fault? (Closes: #818239) | |
22 | ||
23 | -- Christian Hofstaedtler <zeha@debian.org> Sun, 17 Jul 2016 19:58:32 +0000 | |
24 | ||
25 | ohcount (3.0.0-8.1) unstable; urgency=medium | |
26 | ||
27 | * Non-maintainer upload. | |
28 | * Fix build system being broken by removal of deprecated "Config" | |
29 | object in Ruby 2.2. (Closes: #805674) | |
30 | ||
31 | -- Christian Hofstaedtler <zeha@debian.org> Tue, 01 Mar 2016 22:02:31 +0100 | |
32 | ||
33 | ohcount (3.0.0-8) unstable; urgency=low | |
34 | ||
35 | * Remove the explicit dependency on ruby 1.8 | |
36 | Thanks to Jonas Genannt (Closes: #733724) | |
37 | * Switch from cdbs to dh. Thanks to Jonas Genannt | |
38 | * Standards-Version updated to 3.9.5 | |
39 | ||
40 | -- Sylvestre Ledru <sylvestre@debian.org> Thu, 16 Jan 2014 16:26:45 +0100 | |
41 | ||
42 | ohcount (3.0.0-7) unstable; urgency=low | |
43 | ||
44 | * Standards-Version updated to 3.9.4 | |
45 | * libdifflcs-ruby dep renamed to ruby-diff-lcs (Closes: #707792) | |
46 | * Remove Torsten from the uploaders (I have been DD for a while :) | |
47 | * ACK NMU (thanks btw) | |
48 | ||
49 | -- Sylvestre Ledru <sylvestre@debian.org> Sat, 11 May 2013 19:17:57 +0200 | |
50 | ||
51 | ohcount (3.0.0-6.1) unstable; urgency=low | |
52 | ||
53 | * Non-maintainer upload. | |
54 | * Add dependency on file (Closes: #677494). | |
55 | ||
56 | -- Luk Claes <luk@debian.org> Wed, 04 Jul 2012 17:18:12 +0000 | |
57 | ||
58 | ohcount (3.0.0-6) unstable; urgency=low | |
59 | ||
60 | * Update some issues with the documentation (Closes: #650685) | |
61 | ||
62 | -- Sylvestre Ledru <sylvestre@debian.org> Sat, 10 Dec 2011 19:38:15 +0100 | |
63 | ||
64 | ohcount (3.0.0-5) unstable; urgency=low | |
65 | ||
66 | * Oups. Plug back the patches | |
67 | * Manpage of ohcount added | |
68 | ||
69 | -- Sylvestre Ledru <sylvestre@debian.org> Fri, 30 Sep 2011 21:37:34 +0200 | |
70 | ||
71 | ohcount (3.0.0-4) unstable; urgency=low | |
72 | ||
73 | * Support of the txx extension (considered as C++). Thanks to Sébastien Dinot | |
74 | for the patch. | |
75 | * Switch to dpkg-source 3.0 (quilt) format | |
76 | * Standards-Version updated to version 3.9.2 | |
77 | * Fix debian-rules-uses-deprecated-makefile lintian warning | |
78 | ||
79 | -- Sylvestre Ledru <sylvestre@debian.org> Mon, 26 Sep 2011 13:42:49 +0200 | |
80 | ||
81 | ohcount (3.0.0-3) unstable; urgency=low | |
82 | ||
83 | * Standards-Version updated to version 3.9.1 | |
84 | * Fix a seg fault when checking lintian source code. Thanks to | |
85 | Raphael Geissert for investigating for me. (Closes: #608837) | |
86 | (LP: #605631) | |
87 | * Fix lintian warning copyright-refers-to-deprecated-bsd-license-file | |
88 | ||
89 | -- Sylvestre Ledru <sylvestre@debian.org> Sat, 15 Jan 2011 09:34:05 +0100 | |
90 | ||
91 | ohcount (3.0.0-2) unstable; urgency=low | |
92 | ||
93 | * Missing dependency (Closes: #558491) | |
94 | ||
95 | -- Sylvestre Ledru <sylvestre@debian.org> Sun, 29 Nov 2009 18:19:46 +0100 | |
96 | ||
97 | ohcount (3.0.0-1) unstable; urgency=low | |
98 | ||
99 | * New upstream release | |
100 | * New package ohcount-doc added | |
101 | * Homepage updated | |
102 | * Vcs-* added | |
103 | * Many changes on the debian/rules due to a refactoring from upstream which | |
104 | has been done (patches are now obsolete or upstream) | |
105 | * Upstream has redeveloped ohcount with C (instead of ruby). (Closes: #542892) | |
106 | * Update of the watch file | |
107 | * Repack script updated (upstream has a .so) | |
108 | * Standards-Version updated to version 3.8.3 | |
109 | * Change of my email address since I am now DD | |
110 | * Standards-Version updated to 3.8.3 | |
111 | * DM-Upload-Allowed removed | |
112 | ||
113 | -- Sylvestre Ledru <sylvestre@debian.org> Fri, 27 Nov 2009 11:22:21 +0100 | |
114 | ||
115 | ohcount (2.0.1-1) unstable; urgency=low | |
116 | ||
117 | * Initial release (Closes: #523006) | |
118 | ||
119 | -- Sylvestre Ledru <sylvestre.ledru@inria.fr> Tue, 07 Apr 2009 20:18:38 +0200 |
0 | Source: ohcount | |
1 | Section: utils | |
2 | Priority: optional | |
3 | Maintainer: Sylvestre Ledru <sylvestre@debian.org> | |
4 | Build-Depends: debhelper (>= 7), libpcre3-dev, gem2deb, rake, | |
5 | ragel (>= 6.3), ruby-diff-lcs, doxygen, gperf, file | |
6 | Standards-Version: 4.1.3 | |
7 | Homepage: https://github.com/blackducksoftware/ohcount | |
8 | Vcs-Git: https://salsa.debian.org/debian/ohcount.git | |
9 | Vcs-Browser: https://salsa.debian.org/debian/ohcount | |
10 | XS-Ruby-Versions: all | |
11 | ||
12 | Package: ohcount | |
13 | XB-Ruby-Versions: ${ruby:Versions} | |
14 | Architecture: any | |
15 | Depends: ruby | ruby-interpreter, ${shlibs:Depends}, ${misc:Depends}, | |
16 | ruby-diff-lcs, file | |
17 | Suggests: ohcount-doc | |
18 | Description: Source code line counter | |
19 | Ohcount supports over 70 popular programming languages. | |
20 | Ohcount does more than just count lines of code. It can also detect | |
21 | popular open source licenses such as GPL within a large directory of source | |
22 | code. It can also detect code that targets a particular programming API, | |
23 | such as Win32 or KDE. | |
24 | Ohcount is the line counter which powers http://www.ohloh.net/ | |
25 | . | |
26 | ||
27 | Package: ohcount-doc | |
28 | Section: doc | |
29 | Architecture: all | |
30 | Depends: ${shlibs:Depends}, ${misc:Depends} | |
31 | Description: Source code line counter - Documentation | |
32 | Ohcount supports over 70 popular programming languages. | |
33 | Ohcount does more than just count lines of code. It can also detect | |
34 | popular open source licenses such as GPL within a large directory of source | |
35 | code. It can also detect code that targets a particular programming API, | |
36 | such as Win32 or KDE. | |
37 | Ohcount is the line counter which powers http://www.ohloh.net/ | |
38 | . | |
39 | This package contains the documentation. |
0 | This package was debianized by Sylvestre Ledru <sylvestre.ledru@inria.fr> on | |
1 | Tue, 07 Apr 2009 20:18:38 +0200. | |
2 | ||
3 | It was downloaded from <http://labs.ohloh.net/ohcount/> | |
4 | ||
5 | Upstream Author: | |
6 | ||
7 | Ohloh <info@ohloh.net> | |
8 | ||
9 | Copyright: | |
10 | ||
11 | Copyright (C) 2007-2009 Ohloh | |
12 | ||
13 | License: | |
14 | ||
15 | This program is free software; you can redistribute it and/or modify | |
16 | it under the terms of the GNU General Public License as published by | |
17 | the Free Software Foundation; either version 2 of the License, or | |
18 | (at your option) any later version. | |
19 | ||
20 | This program is distributed in the hope that it will be useful, | |
21 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 | GNU General Public License for more details. | |
24 | ||
25 | You should have received a copy of the GNU General Public License along | |
26 | with this program; if not, write to the Free Software Foundation, Inc., | |
27 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
28 | ||
29 | The full text of the license can be found in | |
30 | `/usr/share/common-licenses/GPL-2'. | |
31 | ||
32 | The Debian packaging is (C) 2009, Sylvestre Ledru <sylvestre.ledru@inria.fr> and | |
33 | is licensed under the GPL, see `/usr/share/common-licenses/GPL'. | |
34 | ||
35 | ohcount incorporates some piece of code in order to test during build time | |
36 | its capabilities. These files are not included in the binary. | |
37 | ||
38 | ||
39 | Files: test/expected_dir/haxe1.hx test/src_dir/haxe1.hx | |
40 | ||
41 | Copyright: | |
42 | Thomas Pfeiffer - kiroukou | |
43 | Niel Drummond | |
44 | ||
45 | License: | |
46 | Copyright the original author or authors. | |
47 | Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License"); | |
48 | you may not use this file except in compliance with the License. | |
49 | You may obtain a copy of the License at | |
50 | http://www.mozilla.org/MPL/MPL-1.1.html | |
51 | Unless required by applicable law or agreed to in writing, software | |
52 | distributed under the License is distributed on an "AS IS" BASIS, | |
53 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
54 | See the License for the specific language governing permissions and | |
55 | limitations under the License. | |
56 | ||
57 | Files: test/src_dir/pascal2.pp test/expected_dir/pascal2.pp | |
58 | ||
59 | Copyright: | |
60 | Simon Steele 1998-2000 | |
61 | ||
62 | License: | |
63 | BSD | |
64 | Redistribution and use in source and binary forms, with or without | |
65 | modification, are permitted provided that the following conditions are | |
66 | met: | |
67 | ||
68 | * Redistributions of source code must retain the above copyright | |
69 | notice, this list of conditions and the following disclaimer. | |
70 | * Redistributions in binary form must reproduce the above copyright | |
71 | notice, this list of conditions and the following disclaimer in the | |
72 | documentation and/or other materials provided with the distribution. | |
73 | * Neither the name of the <ORGANIZATION> nor the names of its | |
74 | contributors may be used to endorse or promote products derived from | |
75 | this software without specific prior written permission. | |
76 | ||
77 | Files: test/src_dir/js1.js test/expected_dir/js1.js | |
78 | ||
79 | Copyright: | |
80 | 2005-2008 Sam Stephenson | |
81 | ||
82 | License: | |
83 | MIT | |
84 | ||
85 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
86 | of this software and associated documentation files (the "Software"), to deal | |
87 | in the Software without restriction, including without limitation the rights | |
88 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
89 | copies of the Software, and to permit persons to whom the Software is | |
90 | furnished to do so, subject to the following conditions: | |
91 | ||
92 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
93 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
94 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
95 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
96 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
97 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
98 | SOFTWARE. | |
99 | ||
100 | ||
101 | Files: test/src_dir/foo.ebuild test/detect_files/foo.ebuild | |
102 | ||
103 | License: | |
104 | GPL-2 | |
105 | ||
106 | Files: test/src_dir/as1.as test/expected_dir/as1.as | |
107 | ||
108 | Copyright: | |
109 | Sean Chatman and Garrett Woodworth 2008 | |
110 | ||
111 | License: | |
112 | MIT | |
113 | ||
114 | Files: test/src_dir/perl_module.pm test/expected_dir/perl_module.pm | |
115 | ||
116 | Copyright: | |
117 | Audrey Tang 2003-2007 | |
118 | ||
119 | License: | |
120 | This program is free software; you can redistribute it and/or modify it | |
121 | under the same terms as Perl itself. | |
122 | ||
123 | a) the GNU General Public License as published by the Free Software | |
124 | Foundation; either version 1, or (at your option) any later | |
125 | version, or | |
126 | ||
127 | b) the "Artistic License" which comes with Perl. | |
128 | ||
129 | On Debian GNU/Linux systems, the complete text of the GNU General | |
130 | Public License can be found in `/usr/share/common-licenses/GPL' and | |
131 | the Artistic Licence in `/usr/share/common-licenses/Artistic'. |
0 | Document: ohcount | |
1 | Title: Debian ohcount Manual | |
2 | Author: Ohloh | |
3 | Abstract: ohcount manual | |
4 | Section: Programming/Ruby | |
5 | ||
6 | Format: HTML | |
7 | Index: /usr/share/doc/ohcount-doc/index.html | |
8 | Files: /usr/share/doc/ohcount-doc/* |
0 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.39.4. | |
1 | .TH OHCOUNT "1" "September 2011" "ohcount 3.0.0" "User Commands" | |
2 | .SH NAME | |
3 | ohcount \- manual page for ohcount 3.0.0 | |
4 | .SH SYNOPSIS | |
5 | .B ohcount | |
6 | [\fIoption\fR] [\fIpaths\fR...] | |
7 | .SH DESCRIPTION | |
8 | Ohloh source code line counter command line tool. | |
9 | .IP | |
10 | http://www.ohloh.net/ | |
11 | .SS "[option] can be one of the following:" | |
12 | .HP | |
13 | \fB\-a\fR, \fB\-\-annotate\fR | |
14 | .HP | |
15 | \fB\-d\fR, \fB\-\-detect\fR | |
16 | .HP | |
17 | \fB\-h\fR, \fB\-\-help\fR | |
18 | .HP | |
19 | \fB\-i\fR, \fB\-\-individual\fR | |
20 | .HP | |
21 | \fB\-l\fR, \fB\-\-license\fR | |
22 | .HP | |
23 | \fB\-re\fR | |
24 | .HP | |
25 | \fB\-s\fR, \fB\-\-summary\fR | |
26 | .PP | |
27 | \fB\-a\fR, \fB\-\-annotate\fR Show annotated source code | |
28 | .IP | |
29 | The contents of all source code files found within the given | |
30 | paths will be emitted to stdout. Each line will be prefixed with | |
31 | a tab\-delimited language name and semantic categorization (code, | |
32 | comment, or blank). | |
33 | .PP | |
34 | \fB\-d\fR, \fB\-\-detect\fR Find source code files | |
35 | .IP | |
36 | Recursively find all source code files within the given paths. | |
37 | For each source code file found, the file name will be emitted to | |
38 | stdout prefixed with a tab\-delimited language name. | |
39 | .PP | |
40 | \fB\-h\fR, \fB\-\-help\fR Display this message | |
41 | .PP | |
42 | \fB\-i\fR, \fB\-\-individual\fR Count lines of code per file | |
43 | .IP | |
44 | Count lines in all source code files within the given paths, and | |
45 | emit a report of the lines of code, comments, and blanks in each | |
46 | language per file. | |
47 | .PP | |
48 | \fB\-l\fR, \fB\-\-license\fR | |
49 | .IP | |
50 | Displays detected licensing information contained in each source | |
51 | code file. | |
52 | .PP | |
53 | \fB\-re\fR | |
54 | .IP | |
55 | Prints raw entity information to the screen (mainly for debugging). | |
56 | .PP | |
57 | \fB\-s\fR, \fB\-\-summary\fR Count lines of code (default) | |
58 | .IP | |
59 | Count lines in all source code files within the given paths, and | |
60 | emit a report of the total number of lines of code, comments, | |
61 | and blanks in each language. This is the default action. | |
62 | .PP | |
63 | [paths] can refer to any number of individual files or directories. | |
64 | .IP | |
65 | Directories will be probed recursively. If no path is given, | |
66 | the current directory will be used. |
0 | #!/bin/sh -e | |
1 | ||
2 | # called by uscan with '--upstream-version' <version> <file> | |
3 | DIR=ohcount-$2 | |
4 | TAR=../ohcount_$2.orig.tar.gz | |
5 | ||
6 | # clean up the upstream tarball | |
7 | tar zxf $3 | |
8 | # Remove vendor/ because it is including | |
9 | tar -c -z -X debian/orig-tar.exclude -f $TAR $DIR/ | |
10 | rm -rf $DIR | |
11 | ||
12 | # move to directory 'tarballs' | |
13 | if [ -r .svn/deb-layout ]; then | |
14 | . .svn/deb-layout | |
15 | mv $TAR $origDir | |
16 | echo "moved $TAR to $origDir" | |
17 | fi | |
18 |
0 | Description: disable test suite on build time, does not work | |
1 | Author: Jonas Genannt <jonas.genannt@capi2name.de> | |
2 | Forwarded: not-needed | |
3 | ||
4 | --- a/build | |
5 | +++ b/build | |
6 | @@ -109,7 +109,7 @@ build_test_suite() | |
7 | run_test_suite() | |
8 | { | |
9 | echo "Running test suite" | |
10 | - sh -c "cd test/unit/ && ./run_tests" | |
11 | + echo "disabled test suite, does not work" | |
12 | } | |
13 | ||
14 | build_ruby_bindings() |
0 | From a6783afcf61f18e9f1aef3e2655b30af7501c902 Mon Sep 17 00:00:00 2001 | |
1 | From: Robin Luckey <robin@ohloh.net> | |
2 | Date: Thu, 1 Oct 2009 14:32:16 -0700 | |
3 | Subject: [PATCH] [FIX] Avoid null dereference in disambiguate_inc() | |
4 | ||
5 | --- | |
6 | src/detector.c | 18 ++++++++++-------- | |
7 | test/unit/detector_test.h | 1 + | |
8 | 2 files changed, 11 insertions(+), 8 deletions(-) | |
9 | create mode 100644 test/detect_files/empty.inc | |
10 | ||
11 | diff --git a/src/detector.c b/src/detector.c | |
12 | index 4d0e1f4..9b4d8d2 100644 | |
13 | --- a/src/detector.c | |
14 | +++ b/src/detector.c | |
15 | @@ -452,14 +452,16 @@ const char *disambiguate_in(SourceFile *sourcefile) { | |
16 | ||
17 | const char *disambiguate_inc(SourceFile *sourcefile) { | |
18 | char *p = ohcount_sourcefile_get_contents(sourcefile); | |
19 | - char *eof = p + strlen(p); | |
20 | - while (p < eof) { | |
21 | - if (*p == '\0') | |
22 | - return BINARY; | |
23 | - else if (*p == '?' && strncmp(p + 1, "php", 3) == 0) | |
24 | - return LANG_PHP; | |
25 | - p++; | |
26 | - } | |
27 | + if (p) { | |
28 | + char *eof = p + strlen(p); | |
29 | + while (p < eof) { | |
30 | + if (*p == '\0') | |
31 | + return BINARY; | |
32 | + else if (*p == '?' && strncmp(p + 1, "php", 3) == 0) | |
33 | + return LANG_PHP; | |
34 | + p++; | |
35 | + } | |
36 | + } | |
37 | return NULL; | |
38 | } | |
39 | ||
40 | diff --git a/test/detect_files/empty.inc b/test/detect_files/empty.inc | |
41 | new file mode 100644 | |
42 | index 0000000..e69de29 | |
43 | diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h | |
44 | index cd36b6d..628b6cc 100644 | |
45 | --- a/test/unit/detector_test.h | |
46 | +++ b/test/unit/detector_test.h | |
47 | @@ -77,6 +77,7 @@ void test_detector_detect_polyglot() { | |
48 | ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); | |
49 | ASSERT_DETECT(LANG_ASSEMBLER, "foo.z80"); | |
50 | ASSERT_DETECT(LANG_PHP, "php.inc"); | |
51 | + ASSERT_NODETECT("empty.inc"); | |
52 | ASSERT_DETECT(LANG_FSHARP, "fs1.fs"); | |
53 | } | |
54 | ||
55 | -- | |
56 | 1.7.0.1 | |
57 |
0 | From c0b28d67f27f6e954c93dabd71d098854896d679 Mon Sep 17 00:00:00 2001 | |
1 | From: Robin Luckey <robin@ohloh.net> | |
2 | Date: Thu, 1 Oct 2009 15:43:42 -0700 | |
3 | Subject: [PATCH] [FIX] Null dereference error in disambiguate_in() | |
4 | ||
5 | --- | |
6 | src/detector.c | 3 +++ | |
7 | test/unit/detector_test.h | 4 ++++ | |
8 | 2 files changed, 7 insertions(+), 0 deletions(-) | |
9 | create mode 100644 test/detect_files/empty.in | |
10 | ||
11 | diff --git a/src/detector.c b/src/detector.c | |
12 | index 9b4d8d2..863b379 100644 | |
13 | --- a/src/detector.c | |
14 | +++ b/src/detector.c | |
15 | @@ -437,6 +437,9 @@ const char *disambiguate_in(SourceFile *sourcefile) { | |
16 | buf[length] = '\0'; | |
17 | SourceFile *undecorated = ohcount_sourcefile_new(buf); | |
18 | p = ohcount_sourcefile_get_contents(sourcefile); | |
19 | + if (!p) { | |
20 | + return NULL; | |
21 | + } | |
22 | // The filepath without the '.in' extension does not exist on disk. The | |
23 | // sourcefile->diskpath field must be set incase the detector needs to run | |
24 | // 'file -b' on the file. | |
25 | diff --git a/test/detect_files/empty.in b/test/detect_files/empty.in | |
26 | new file mode 100644 | |
27 | index 0000000..e69de29 | |
28 | diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h | |
29 | index 628b6cc..a26adaa 100644 | |
30 | --- a/test/unit/detector_test.h | |
31 | +++ b/test/unit/detector_test.h | |
32 | @@ -36,6 +36,9 @@ void test_detector_disambiguate_m() { | |
33 | ASSERT_DETECT(LANG_OCTAVE, "foo_octave.m"); | |
34 | } | |
35 | ||
36 | +void test_detector_disambiguate_in() { | |
37 | + ASSERT_NODETECT("empty.in"); | |
38 | +} | |
39 | void test_detector_disambiguate_pro() { | |
40 | ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); | |
41 | ASSERT_DETECT(LANG_MAKE, "qmake.pro"); | |
42 | @@ -119,6 +122,7 @@ void test_detector_xml_with_custom_extension() { | |
43 | void all_detector_tests() { | |
44 | test_detector_smalltalk(); | |
45 | test_detector_disambiguate_m(); | |
46 | + test_detector_disambiguate_in(); | |
47 | test_detector_disambiguate_pro(); | |
48 | test_detector_fortran_fixedfree(); | |
49 | test_detector_detect_polyglot(); | |
50 | -- | |
51 | 1.7.0.1 | |
52 |
0 | Index: ohcount-3.0.0/build | |
1 | =================================================================== | |
2 | --- ohcount-3.0.0.orig/build | |
3 | +++ ohcount-3.0.0/build | |
4 | @@ -114,12 +114,12 @@ run_test_suite() | |
5 | ||
6 | build_ruby_bindings() | |
7 | { | |
8 | - arch=`ruby -rmkmf -e 'print Config::expand(CONFIG["arch"])'` | |
9 | + arch=`ruby -rmkmf -e 'print RbConfig::expand(RbConfig::CONFIG["arch"])'` | |
10 | echo "Generating Ruby bindings for $arch" | |
11 | sh -c "swig -ruby -o ruby/ohcount_wrap.c ruby/ohcount.i" || exit 1 | |
12 | mkdir -p ruby/$arch | |
13 | sh -c "$cc $RB_SHARED ruby/ohcount_wrap.c $files -o ruby/$arch/$RB_SHARED_NAME \ | |
14 | - -I`ruby -rmkmf -e 'print Config::expand(CONFIG["archdir"])'` \ | |
15 | + -I`ruby -rmkmf -e 'print RbConfig::expand(RbConfig::CONFIG["archdir"])'` \ | |
16 | -lpcre" || exit 1 | |
17 | sh -c "cd test/unit/ruby && ruby ruby_test.rb" || exit 1 | |
18 | } | |
19 | @@ -156,7 +156,7 @@ then | |
20 | rm -f src/hash/*.c | |
21 | rm -f src/$SHARED_NAME | |
22 | rm -f ruby/$RB_SHARED_NAME | |
23 | - rm -rf ruby/`ruby -rmkmf -e 'print Config::expand(CONFIG["arch"])'`/* | |
24 | + rm -rf ruby/`ruby -rmkmf -e 'print RbConfig::expand(RbConfig::CONFIG["arch"])'`/* | |
25 | else | |
26 | echo "Usage: build [all|ohcount|shared|tests|ruby|clean]" | |
27 | fi |
0 | fix_null_dereference_2.patch | |
1 | fix_null_dereference.patch | |
2 | txx_support.patch | |
3 | disabled_test_suite.patch | |
4 | rbconfig.patch |
0 | diff -Naur ohcount-3.0.0/src/hash/extensions.gperf ohcount-3.0.1/src/hash/extensions.gperf | |
1 | --- ohcount-3.0.0/src/hash/extensions.gperf 2009-09-30 17:30:19.000000000 +0000 | |
2 | +++ ohcount-3.0.1/src/hash/extensions.gperf 2011-09-26 09:32:34.000000000 +0000 | |
3 | @@ -161,6 +161,7 @@ | |
4 | tif, BINARY | |
5 | tiff, BINARY | |
6 | tpl, LANG_HTML | |
7 | +txx, LANG_CPP | |
8 | vala, LANG_VALA | |
9 | vb, LANG_VISUALBASIC | |
10 | vba, LANG_VISUALBASIC | |
11 |
0 | #!/usr/bin/make -f | |
1 | ||
2 | %: | |
3 | dh $@ --buildsystem=ruby --with ruby | |
4 | ||
5 | override_dh_auto_clean: | |
6 | dh_auto_clean -O--buildsystem=ruby | |
7 | ./build clean | |
8 | rm -rf doc_build | |
9 | ||
10 | override_dh_install: | |
11 | ./build all | |
12 | dh_install --buildsystem=ruby --with ruby | |
13 | install -d debian/ohcount/usr/lib/ruby/vendor_ruby/ohcount | |
14 | install -d debian/ohcount/usr/bin | |
15 | install -d debian/ohcount-doc/usr/share/doc/ohcount-doc | |
16 | cp bin/ohcount debian/ohcount/usr/bin/ | |
17 | cp -R ruby/gestalt ruby/gestalt.rb ruby/ohcount.rb debian/ohcount/usr/lib/ruby/vendor_ruby/ohcount/ | |
18 | # build doxygen | |
19 | mkdir doc_build | |
20 | cp -aR doc/* doc_build/ | |
21 | (cd doc_build && doxygen Doxyfile) | |
22 | cp -aR doc_build/html/* debian/ohcount-doc/usr/share/doc/ohcount-doc | |
23 | rm -rf debian/ohcount/ruby debian/ohcount-doc/ruby | |
24 | ||
25 | get-orig-source: | |
26 | uscan --force-download |
0 | version=4 | |
1 | opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ohcount-$1.tar.gz%" \ | |
2 | https://github.com/blackducksoftware/ohcount/tags \ | |
3 | (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate | |
4 | ||
5 |
0 | 0 | %%{ |
1 | 1 | machine c; |
2 | 2 | write data; |
3 | include "common.rl"; | |
3 | include common "common.rl"; | |
4 | 4 | |
5 | 5 | ... |
6 | 6 | }%% |
0 | import os, collections | |
1 | from abc import abstractmethod | |
2 | import ohcount | |
3 | ||
4 | class _OhcountBase(object): | |
5 | ||
6 | def __init__(self, base): | |
7 | self._base = base | |
8 | ||
9 | def __getattr__(self, name): | |
10 | if name == '_base': | |
11 | return object.__getattr__(self, name) | |
12 | raise AttributeError | |
13 | ||
14 | def __setattr__(self, name, value): | |
15 | if name == '_base': | |
16 | return object.__setattr__(self, name, value) | |
17 | raise AttributeError | |
18 | ||
19 | class _OhcountDict(_OhcountBase, collections.Mapping, collections.KeysView): | |
20 | ||
21 | def __init__(self, base, mapping): | |
22 | _OhcountBase.__init__(self, base) | |
23 | collections.KeysView.__init__(self, mapping) | |
24 | ||
25 | def __getattr__(self, name): | |
26 | if name == '_mapping': | |
27 | return collections.KeysView.__getattr__(self, name) | |
28 | try: | |
29 | return _OhcountBase.__getattr__(self, name) | |
30 | except AttributeError: | |
31 | try: | |
32 | return self.__getitem__(name) | |
33 | except KeyError: | |
34 | raise AttributeError | |
35 | except: | |
36 | raise | |
37 | ||
38 | def __setattr__(self, name, value): | |
39 | if name == '_mapping': | |
40 | return collections.KeysView.__setattr__(self, name, value) | |
41 | try: | |
42 | return _OhcountBase.__setattr__(self, name, value) | |
43 | except AttributeError: | |
44 | try: | |
45 | return self.__setitem__(name, value) | |
46 | except KeyError: | |
47 | raise AttributeError | |
48 | except: | |
49 | raise | |
50 | ||
51 | def keys(self): | |
52 | return self._mapping | |
53 | ||
54 | def __setitem__(self, key, item): | |
55 | raise KeyError | |
56 | ||
57 | def __delitem__(self, key): | |
58 | raise KeyError | |
59 | ||
60 | def __str__(self): | |
61 | return dict([(key, self[key]) for key in self.keys()]).__str__() | |
62 | ||
63 | def iterkeys(self): | |
64 | return iter(self.keys()) | |
65 | ||
66 | def itervalues(self): | |
67 | for key in self.keys(): | |
68 | yield self[key] | |
69 | ||
70 | def iteritems(self): | |
71 | for key in self.keys(): | |
72 | yield (key, self[key]) | |
73 | ||
74 | def items(self): | |
75 | return [(key, self[key]) for key in self.keys()] | |
76 | ||
77 | def values(self): | |
78 | return [self[key] for key in self.keys()] | |
79 | ||
80 | class _OhcountList(_OhcountBase): | |
81 | ||
82 | @abstractmethod | |
83 | def _get_value(self, inner): | |
84 | raise NotImplementedError | |
85 | ||
86 | def __len__(self): | |
87 | count = 0 | |
88 | for e in self: | |
89 | count += 1 | |
90 | return count | |
91 | ||
92 | def __iter__(self): | |
93 | return self.next() | |
94 | ||
95 | def next(self): | |
96 | iter = self._base.head | |
97 | while iter is not None: | |
98 | yield self._get_value(iter) | |
99 | iter = iter.next | |
100 | ||
101 | def __str__(self): | |
102 | return [v for v in self].__str__() | |
103 | ||
104 | class License(_OhcountDict): | |
105 | ||
106 | def __init__(self, base): | |
107 | _OhcountDict.__init__(self, base, | |
108 | ['name','url','nice_name']) | |
109 | ||
110 | def __getitem__(self, key): | |
111 | if key == 'name': | |
112 | return self._base.name | |
113 | if key == 'url': | |
114 | return self._base.url | |
115 | if key == 'nice_name': | |
116 | return self._base.nice_name | |
117 | raise KeyError | |
118 | ||
119 | class Loc(_OhcountDict): | |
120 | ||
121 | def __init__(self, base): | |
122 | _OhcountDict.__init__(self, base, | |
123 | ['lang','code','comments','blanks','filecount','total']) | |
124 | ||
125 | def __getitem__(self, key): | |
126 | if key == 'lang' or key == 'language': | |
127 | return self._base.language | |
128 | if key == 'code': | |
129 | return self._base.code | |
130 | if key == 'comments': | |
131 | return self._base.comments | |
132 | if key == 'blanks': | |
133 | return self._base.blanks | |
134 | if key == 'filecount': | |
135 | return self._base.filecount | |
136 | if key == 'total': | |
137 | return self._base.total() | |
138 | raise KeyError | |
139 | ||
140 | class LocList(_OhcountDict, _OhcountList): | |
141 | ||
142 | def __init__(self, base): | |
143 | _OhcountDict.__init__(self, base, | |
144 | ['code','comments','blanks','filecount','total']) | |
145 | ||
146 | def _get_value(self, inner): | |
147 | return Loc(inner.loc) | |
148 | ||
149 | def __getitem__(self, key): | |
150 | if key == 'code': | |
151 | return self._base.code() | |
152 | if key == 'comments': | |
153 | return self._base.comments() | |
154 | if key == 'blanks': | |
155 | return self._base.blanks() | |
156 | if key == 'filecount': | |
157 | return self._base.filecount() | |
158 | if key == 'total': | |
159 | return self._base.total() | |
160 | raise KeyError | |
161 | ||
162 | def __str__(self): | |
163 | return _OhcountDict.__str__(self) | |
164 | ||
165 | def compact(self): | |
166 | return LocList(self._base.compact()) | |
167 | ||
168 | class SourceFile(_OhcountDict): | |
169 | ||
170 | def __init__(self, base): | |
171 | _OhcountDict.__init__(self, base, | |
172 | ['filepath','filename','ext','contents','size','language', | |
173 | 'licenses','locs']) | |
174 | ||
175 | def _get_licenses(self): | |
176 | result = [] | |
177 | list = self._base.get_license_list() | |
178 | if list is not None: | |
179 | iter = list.head | |
180 | while iter is not None: | |
181 | result.append(License(iter.lic)) | |
182 | iter = iter.next | |
183 | return result | |
184 | ||
185 | def _get_locs(self): | |
186 | return LocList(self._base.get_loc_list()) | |
187 | ||
188 | def __getitem__(self, key): | |
189 | if key == 'filepath': | |
190 | return self._base.filepath | |
191 | if key == 'filename': | |
192 | return self._base.filename | |
193 | if key == 'ext': | |
194 | return self._base.ext | |
195 | if key == 'contents': | |
196 | return self._base.get_contents() | |
197 | if key == 'size': | |
198 | return self._base.contents_size() | |
199 | if key == 'language': | |
200 | return self._base.get_language() | |
201 | if key == 'licenses': | |
202 | return self._get_licenses() | |
203 | if key == 'locs': | |
204 | return self._get_locs() | |
205 | raise AttributeError | |
206 | ||
207 | def annotate(self): | |
208 | return self._base.annotate() | |
209 | ||
210 | def raw_entities(self): | |
211 | return self._base.raw_entities() | |
212 | ||
213 | class SourceFileList(_OhcountList): | |
214 | ||
215 | def __init__(self, **kwargs): | |
216 | _OhcountList.__init__(self, ohcount.SourceFileList(kwargs)) | |
217 | ||
218 | def _get_value(self, inner): | |
219 | return SourceFile(inner.sf) | |
220 | ||
221 | def analyze_languages(self): | |
222 | return LocList( self._base.analyze_languages() ) | |
223 | ||
224 | def add_directory(self, path): | |
225 | if not os.path.isdir(path): | |
226 | raise SyntaxError('Input path is not a directory: %s' % path) | |
227 | self._base.add_directory(path) | |
228 | ||
229 | def add_file(self, filepath): | |
230 | if not os.path.isfile(filepath): | |
231 | raise SyntaxError('Input path is not a file: %s' % filepath) | |
232 | self._base.add_file(filepath) | |
233 |
0 | #=== mingw_setup.py by Phillip J. Eby | |
1 | """Create pythonNN.def and libpythonNN.a in 'PythonNN/libs' directory | |
2 | ||
3 | This script makes it possible to use the MinGW compiler tools to | |
4 | build C extensions that work with the standard Windows Python | |
5 | distribution. | |
6 | ||
7 | Before running, you should have installed the MinGW compiler toolset, | |
8 | and placed its 'bin' directory on your PATH. An easy way to do this | |
9 | is to install Cygwin's "binutils", "gcc", and "mingw-*" packages, | |
10 | then run this script from the Cygwin shell. (Be sure to use *Windows* | |
11 | Python, not Cygwin python!) | |
12 | ||
13 | Once this script has been run, you should be able to build extensions | |
14 | using distutils in the standard way, as long as you select the | |
15 | 'mingw32' compiler, and the required tools are on your PATH. See | |
16 | the "Installing Python Modules" manual for more information on | |
17 | selecting a compiler. | |
18 | """ | |
19 | ||
20 | ||
21 | from distutils.spawn import find_executable | |
22 | from distutils.sysconfig import get_config_var | |
23 | from distutils import __file__ as distutils_file | |
24 | import os, re, sys | |
25 | ||
26 | if sys.platform=='cygwin': | |
27 | print "Please run this script using Windows python,", | |
28 | print "not Cygwin python. E.g, try:" | |
29 | ||
30 | print "/cygdrive/c/PythonNN/python", " ".join(sys.argv) | |
31 | ||
32 | print "(where NN is the major/minor python version number)" | |
33 | sys.exit() | |
34 | ||
35 | basename = 'python%d%d' % sys.version_info[:2] | |
36 | ||
37 | libs_dir = os.path.join(get_config_var('prefix'),'libs') | |
38 | lib_file = os.path.join(libs_dir,basename+'.lib') | |
39 | def_file = os.path.join(libs_dir,basename+'.def') | |
40 | ming_lib = os.path.join(libs_dir,'lib%s.a' % basename) | |
41 | ||
42 | distutils_cfg = os.path.join(os.path.dirname(distutils_file),'distutils.cfg') | |
43 | ||
44 | export_match = re.compile(r"^_imp__(.*) in python\d+\.dll").match | |
45 | ||
46 | nm = find_executable('nm') | |
47 | dlltool = find_executable('dlltool') | |
48 | ||
49 | if not nm or not dlltool: | |
50 | print "'nm' and/or 'dlltool' were not found;" | |
51 | print "Please make sure they're on your PATH." | |
52 | sys.exit() | |
53 | ||
54 | nm_command = '%s -Cs %s' % (nm, lib_file) | |
55 | ||
56 | print "Building", def_file, "using", nm_command | |
57 | f = open(def_file,'w') | |
58 | print >>f, "LIBRARY %s.dll" % basename | |
59 | print >>f, "EXPORTS" | |
60 | ||
61 | ||
62 | nm_pipe = os.popen(nm_command) | |
63 | for line in nm_pipe.readlines(): | |
64 | m = export_match(line) | |
65 | if m: | |
66 | print >>f, m.group(1) | |
67 | f.close() | |
68 | ||
69 | exit = nm_pipe.close() | |
70 | if exit: | |
71 | print "nm exited with status", exit | |
72 | print "Please check that", lib_file, "exists and is valid." | |
73 | sys.exit() | |
74 | ||
75 | ||
76 | print "Building",ming_lib,"using",dlltool | |
77 | dlltool_pipe = os.popen( | |
78 | "%s --dllname %s.dll --def %s --output-lib %s" % | |
79 | (dlltool, basename, def_file, ming_lib) | |
80 | ) | |
81 | ||
82 | dlltool_pipe.readlines() | |
83 | exit = dlltool_pipe.close() | |
84 | if exit: | |
85 | print "dlltool exited with status", exit | |
86 | print "Unable to proceed." | |
87 | sys.exit() | |
88 | ||
89 | ||
90 | print "Installation complete. You may wish to add the following" | |
91 | print "lines to", distutils_cfg, ':' | |
92 | ||
93 | print "[build]" | |
94 | print "compiler = mingw32" | |
95 | ||
96 | print "This will make the distutils use MinGW as the default" | |
97 | print "compiler, so that you don't need to configure this for" | |
98 | print "every 'setup.py' you run." | |
99 |
0 | #!/usr/bin/env python | |
1 | ||
2 | import distutils.ccompiler | |
3 | from distutils.core import setup, Extension | |
4 | from distutils.command.build import build | |
5 | from distutils.command.build_ext import build_ext | |
6 | from distutils.command.install_lib import install_lib | |
7 | import os, sys | |
8 | from glob import glob | |
9 | ||
10 | if not hasattr(sys, 'version_info') or sys.version_info < (2,6,0,'final'): | |
11 | raise SystemExit("Ohcount requires Python 2.6 or later.") | |
12 | ||
13 | class build_ohcount(build): | |
14 | """Ohcount already have a script named 'build', from the original package, | |
15 | so it conflicts with Python default build path. To solve this, setup.py | |
16 | will use the directory 'build-python' instead. The original distutils | |
17 | execute 'build_py' before 'build_ext', but we need the wrapper ohcount.py | |
18 | created by SWIG to be installed too, so we need to invert this order. | |
19 | """ | |
20 | ||
21 | sub_commands = [('build_ext', build.has_ext_modules), # changed | |
22 | ('build_py', build.has_pure_modules), # changed | |
23 | ('build_clib', build.has_c_libraries), | |
24 | ('build_scripts', build.has_scripts), | |
25 | ] | |
26 | ||
27 | def initialize_options(self): | |
28 | build.initialize_options(self) | |
29 | self.build_base = 'build-python' | |
30 | ||
31 | def newer_than(srclist, dstlist): | |
32 | for left, right in zip(srclist, dstlist): | |
33 | if not os.path.exists(right): | |
34 | return True | |
35 | left_stat = os.lstat(left) | |
36 | right_stat = os.lstat(right) | |
37 | if left_stat.st_mtime > right_stat.st_mtime: | |
38 | return True | |
39 | return False | |
40 | ||
41 | class build_ohcount_ext(build_ext): | |
42 | """This class implements extra steps needed by Ohcount build process.""" | |
43 | ||
44 | def run(self): | |
45 | parsers = glob('src/parsers/*.rl') | |
46 | parsers_h = [f.replace('.rl', '.h') for f in parsers] | |
47 | if newer_than(parsers, parsers_h): | |
48 | os.system('cd src/parsers/ && bash ./compile') | |
49 | hash_files = glob('src/hash/*.gperf') | |
50 | hash_srcs = [] | |
51 | for f in hash_files: | |
52 | if not f.endswith('languages.gperf'): | |
53 | hash_srcs.append(f.replace('s.gperf', '_hash.h')) | |
54 | else: | |
55 | hash_srcs.append(f.replace('s.gperf', '_hash.c')) | |
56 | if newer_than(hash_files, hash_srcs): | |
57 | os.system('cd src/hash/ && bash ./generate_headers') | |
58 | return build_ext.run(self) | |
59 | ||
60 | # Overwrite default Mingw32 compiler | |
61 | (module_name, class_name, long_description) = \ | |
62 | distutils.ccompiler.compiler_class['mingw32'] | |
63 | module_name = "distutils." + module_name | |
64 | __import__(module_name) | |
65 | module = sys.modules[module_name] | |
66 | Mingw32CCompiler = vars(module)[class_name] | |
67 | ||
68 | class Mingw32CCompiler_ohcount(Mingw32CCompiler): | |
69 | """Ohcount CCompiler version for Mingw32. There is a problem linking | |
70 | against msvcrXX for Python 2.6.4: as both DLLs msvcr and msvcr90 are | |
71 | loaded, it seems to happen some unexpected segmentation faults in | |
72 | several function calls.""" | |
73 | ||
74 | def __init__(self, *args, **kwargs): | |
75 | Mingw32CCompiler.__init__(self, *args, **kwargs) | |
76 | self.dll_libraries=[] # empty link libraries list | |
77 | ||
78 | _new_compiler = distutils.ccompiler.new_compiler | |
79 | ||
80 | def ohcount_new_compiler(plat=None,compiler=None,verbose=0,dry_run=0,force=0): | |
81 | if compiler == 'mingw32': | |
82 | inst = Mingw32CCompiler_ohcount(None, dry_run, force) | |
83 | else: | |
84 | inst = _new_compiler(plat,compiler,verbose,dry_run,force) | |
85 | return inst | |
86 | ||
87 | distutils.ccompiler.new_compiler = ohcount_new_compiler | |
88 | ||
89 | # Ohcount python extension | |
90 | ext_modules=[ | |
91 | Extension( | |
92 | name='ohcount._ohcount', | |
93 | sources= [ | |
94 | 'ruby/ohcount.i', | |
95 | 'src/sourcefile.c', | |
96 | 'src/detector.c', | |
97 | 'src/licenses.c', | |
98 | 'src/parser.c', | |
99 | 'src/loc.c', | |
100 | 'src/log.c', | |
101 | 'src/diff.c', | |
102 | 'src/parsed_language.c', | |
103 | 'src/hash/language_hash.c', | |
104 | ], | |
105 | libraries=['pcre'], | |
106 | swig_opts=['-outdir', './python/'], | |
107 | ) | |
108 | ] | |
109 | ||
110 | setup( | |
111 | name='ohcount', | |
112 | version = '3.0.0', | |
113 | description = 'Ohcount is the source code line counter that powers Ohloh.', | |
114 | long_description = | |
115 | 'Ohcount supports over 70 popular programming languages, and has been ' | |
116 | 'used to count over 6 billion lines of code by 300,000 developers! ' | |
117 | 'Ohcount does more more than just count lines of code. It can also ' | |
118 | 'detect popular open source licenses such as GPL within a large ' | |
119 | 'directory of source code. It can also detect code that targets a ' | |
120 | 'particular programming API, such as Win32 or KDE.', | |
121 | author = 'Mitchell Foral', | |
122 | author_email = 'mitchell@caladbolg.net', | |
123 | license = 'GNU GPL', | |
124 | platforms = ['Linux','Mac OSX'], | |
125 | keywords = ['ohcount','ohloh','loc','source','code','line','counter'], | |
126 | url = 'http://www.ohloh.net/p/ohcount', | |
127 | download_url = 'http://sourceforge.net/projects/ohcount/files/', | |
128 | packages = ['ohcount'], | |
129 | package_dir = {'ohcount': 'python'}, | |
130 | classifiers = [ | |
131 | 'Development Status :: 5 - Production/Stable', | |
132 | 'License :: OSI Approved :: GNU General Public License (GPL)' | |
133 | 'Intended Audience :: Developers', | |
134 | 'Natural Language :: English', | |
135 | 'Programming Language :: C', | |
136 | 'Programming Language :: Python', | |
137 | 'Topic :: Software Development :: Libraries :: Python Modules', | |
138 | ], | |
139 | ext_modules=ext_modules, | |
140 | cmdclass={ | |
141 | 'build': build_ohcount, | |
142 | 'build_ext': build_ohcount_ext, | |
143 | }, | |
144 | ) | |
145 |
12 | 12 | require 'gestalt/rules/gestalt_rule' |
13 | 13 | require 'gestalt/rules/java_import_rule' |
14 | 14 | require 'gestalt/rules/csharp_using_rule' |
15 | require 'gestalt/rules/find_java_imports_rule' | |
16 | 15 | require 'gestalt/rules/maven_parser' |
17 | 16 | require 'gestalt/rules/maven_rule' |
18 | 17 | require 'gestalt/rules/csproj_parser' |