[CHANGE] diff large files from the shell
[ohcount] / src / ohcount.c
1 // ohcount.c written by Mitchell Foral. mitchell<att>caladbolg.net.
2 // See COPYING for license information.
3
4 #include <dirent.h>
5 #include <stdio.h>
6 #include <string.h>
7
8 #include "hash/option_hash.h"
9 #include "sourcefile.h"
10 #include "ohcount.h"
11
12 void annotate_callback(const char *language, const char *entity, int start,
13                        int end, void *userdata) {
14   SourceFile *sf = (SourceFile *)userdata;
15   int length = end - start;
16   char buf[length];
17   strncpy(buf, (const char*)sf->contents + start, length); // field exists
18   buf[length] = '\0';
19   printf("%s\t%s\t%s", language, entity, buf);
20 }
21
22 void annotate(SourceFileList *list) {
23   SourceFileList *iter = list->head;
24   while (iter) {
25     ohcount_sourcefile_parse_with_callback(iter->sf, annotate_callback,
26                                            iter->sf);
27     iter = iter->next;
28   }
29 }
30
31 void detect(SourceFileList *list) {
32   SourceFileList *iter = list->head;
33   while (iter) {
34     printf("%s\t%s\n", ohcount_sourcefile_get_language(iter->sf),
35            iter->sf->filepath);
36     iter = iter->next;
37   }
38 }
39
40 void licenses(SourceFileList *list) {
41   SourceFileList *iter = list->head;
42   while (iter) {
43     LicenseList *liter = ohcount_sourcefile_get_license_list(iter->sf)->head;
44     while (liter) {
45       printf("%s%s ", liter->lic->name, (liter->next != NULL) ? "," : "");
46       printf("%s\n", iter->sf->filename);
47       liter = liter->next;
48     }
49     iter = iter->next;
50   }
51 }
52
53 void raw_entities_callback(const char *language, const char *entity, int start,
54                            int end, void *userdata) {
55   printf("%s\t%s\t%i\t%i\n", language, entity, start, end);
56 }
57
58 void raw_entities(SourceFileList *list) {
59   SourceFileList *iter = list->head;
60   while (iter) {
61     ohcount_sourcefile_parse_entities_with_callback(iter->sf,
62                                                     raw_entities_callback,
63                                                     NULL);
64     iter = iter->next;
65   }
66 }
67
68 void help() {
69   printf(
70     "Usage: ohcount [option] [paths...]\n"
71     "\n"
72     "Ohloh source code line counter command line tool.\n"
73     "   http://www.ohloh.net/\n"
74     "\n"
75     "[option] can be one of the following:\n"
76     "   -a, --annotate\n"
77     "   -d, --detect\n"
78     "   -h, --help\n"
79     "   -i, --individual\n"
80     "   -l, --license\n"
81     "   -re\n"
82     "   -s, --summary\n"
83     "\n"
84     "-a, --annotate                  Show annotated source code\n"
85     "\n"
86     "   The contents of all source code files found within the given\n"
87     "   paths will be emitted to stdout. Each line will be prefixed with\n"
88     "   a tab-delimited language name and semantic categorization (code,\n"
89     "   comment, or blank).\n"
90     "\n"
91     "-d, --detect                    Find source code files\n"
92     "\n"
93     "   Recursively find all source code files within the given paths.\n"
94     "   For each source code file found, the file name will be emitted to\n"
95     "   stdout prefixed with a tab-delimited language name.\n"
96     "\n"
97     "-h, --help                      Display this message\n"
98     "\n"
99     "-i, --individual                Count lines of code per file\n"
100     "\n"
101     "   Count lines in all source code files within the given paths, and\n"
102     "   emit a report of the lines of code, comments, and blanks in each\n"
103     "   language per file.\n"
104     "\n"
105     "-l, --license\n"
106     "\n"
107     "   Displays detected licensing information contained in each source\n"
108     "   code file.\n"
109     "\n"
110     "-re\n"
111     "\n"
112     "   Prints raw entity information to the screen (mainly for debugging).\n"
113     "\n"
114     "-s, --summary                   Count lines of code (default)\n"
115     "\n"
116     "   Count lines in all source code files within the given paths, and\n"
117     "   emit a report of the total number of lines of code, comments,\n"
118     "   and blanks in each language. This is the default action.\n"
119     "\n"
120     "[paths] can refer to any number of individual files or directories.\n"
121     "   Directories will be probed recursively. If no path is given,\n"
122     "   the current directory will be used.\n"
123   );
124 }
125
126 void sort_loc_list_by_language(LocList *list) {
127   LocList *iter = list->head;
128   while (iter) {
129     LocList *min = iter;
130     LocList *iter2 = iter->next;
131     while (iter2) {
132       if (strcmp(iter2->loc->language, min->loc->language) < 0)
133         min = iter2;
134       iter2 = iter2->next;
135     }
136     if (iter != min) {
137       Loc *temp = iter->loc;
138       iter->loc = min->loc;
139       min->loc = temp;
140     }
141     iter = iter->next;
142   }
143 }
144
145 void individual(SourceFileList *list) {
146   int count = 0;
147   SourceFileList *titer = list->head;
148   while (titer) {
149     count++;
150     titer = titer->next;
151   }
152   printf(
153     "Examining %i file(s)\n"
154     "                              Ohloh Line Count                              \n"
155     "Language               Code    Comment  Comment %%      Blank      Total  File\n"
156     "----------------  ---------  ---------  ---------  ---------  ---------  -----------------------------------------------\n"
157     , count);
158   SourceFileList *iter = list->head;
159   while (iter) {
160     LocList *loc_list = ohcount_sourcefile_get_loc_list(iter->sf);
161     sort_loc_list_by_language(loc_list);
162     LocList *liter = loc_list->head;
163     while (liter) {
164       printf("%-16s", liter->loc->language);
165       printf(" %10d", liter->loc->code);
166       printf(" %10d", liter->loc->comments);
167       if (liter->loc->comments + liter->loc->code > 0)
168         printf(" %9.1f%%",
169                (float)liter->loc->comments / (liter->loc->comments +
170                  liter->loc->code) * 100);
171       else
172         printf("           ");
173       printf(" %10d", liter->loc->blanks);
174       printf(" %10d",
175              liter->loc->code + liter->loc->comments + liter->loc->blanks);
176       printf("  %s\n", iter->sf->filename);
177       liter = liter->next;
178     }
179     iter = iter->next;
180   }
181 }
182
183 void sort_loc_list_by_code(LocList *list) {
184   LocList *iter = list->head;
185   while (iter) {
186     LocList *max = iter;
187     LocList *iter2 = iter->next;
188     while (iter2) {
189       if (iter2->loc->code > max->loc->code)
190         max = iter2;
191       iter2 = iter2->next;
192     }
193     if (iter != max) {
194       Loc *temp = iter->loc;
195       iter->loc = max->loc;
196       max->loc = temp;
197     }
198     iter = iter->next;
199   }
200 }
201
202 void summary(SourceFileList *list) {
203   int count = 0;
204   SourceFileList *tmpiter = list->head;
205   while (tmpiter) {
206     count++;
207     tmpiter = tmpiter->next;
208   }
209   printf("Examining %i file(s)\n", count);
210   LocList *loc_list = ohcount_sourcefile_list_analyze_languages(list);
211   sort_loc_list_by_code(loc_list);
212   printf(
213     "\n"
214     "                          Ohloh Line Count Summary                          \n"
215     "\n"
216     "Language          Files       Code    Comment  Comment %%      Blank      Total\n"
217     "----------------  -----  ---------  ---------  ---------  ---------  ---------\n");
218   LocList *iter = loc_list->head;
219   while (iter) {
220     printf("%-16s", iter->loc->language);
221     printf(" %6d", iter->loc->filecount);
222     printf(" %10d", iter->loc->code);
223     printf(" %10d", iter->loc->comments);
224     if (iter->loc->comments + iter->loc->code > 0)
225       printf(" %9.1f%%",
226              (float)iter->loc->comments / (iter->loc->comments +
227                iter->loc->code) * 100);
228     else
229       printf("       0.0%%");
230     printf(" %10d", iter->loc->blanks);
231     printf(" %10d\n",
232            iter->loc->code + iter->loc->comments + iter->loc->blanks);
233     iter = iter->next;
234   }
235   printf("----------------  -----  ---------  ---------  ---------  ---------  ---------\n");
236   int code = ohcount_loc_list_code(loc_list);
237   int comments = ohcount_loc_list_comments(loc_list);
238   int blanks = ohcount_loc_list_blanks(loc_list);
239   printf("%-16s", "Total");
240   printf(" %6d", ohcount_loc_list_filecount(loc_list));
241   printf(" %10d", code);
242   printf(" %10d", comments);
243   if (comments + code > 0)
244     printf(" %9.1f%%", (float)comments / (comments + code) * 100);
245   else
246     printf("       0.0%%");
247   printf(" %10d", blanks);
248   printf(" %10d\n", code + comments + blanks);
249   ohcount_loc_list_free(loc_list);
250 }
251
252 int main(int argc, char *argv[]) {
253   int command = 0;
254   if (argc > 1) {
255     struct OhcountOption *opt = ohcount_hash_command_from_flag(argv[1],
256                                                                strlen(argv[1]));
257     if (opt)
258       command = opt->value;
259   }
260   int i = 1;
261   if (command == 0)
262     command = COMMAND_SUMMARY;
263   else
264     i = 2; // parameter is not a file or directory
265
266   SourceFileList *list = ohcount_sourcefile_list_new();
267   if (i == argc)
268     ohcount_sourcefile_list_add_directory(list, ".");
269   for (; i < argc; i++) {
270     DIR *dir = opendir(argv[i]);
271     if (dir) {
272       ohcount_sourcefile_list_add_directory(list, argv[i]);
273       closedir(dir);
274     } else {
275       FILE *f = fopen(argv[i], "r");
276       if (f) {
277         ohcount_sourcefile_list_add_file(list, argv[i]);
278         fclose(f);
279       } else printf("Bad argument: %s\n", argv[i]);
280     }
281   }
282   switch (command) {
283   case COMMAND_ANNOTATE:
284     annotate(list);
285     break;
286   case COMMAND_DETECT:
287     detect(list);
288     break;
289   case COMMAND_HELP:
290     help();
291     break;
292   case COMMAND_INDIVIDUAL:
293     individual(list);
294     break;
295   case COMMAND_LICENSES:
296     licenses(list);
297     break;
298   case COMMAND_RAWENTITIES:
299     raw_entities(list);
300     break;
301   case COMMAND_SUMMARY:
302     summary(list);
303     break;
304   }
305   ohcount_sourcefile_list_free(list);
306
307   return 0;
308 }