Initial import of files for generating Doxygen documentation.
[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     "   -g, --gestalt\n"
80     "   -i, --individual\n"
81     "   -l, --license\n"
82     "   -re\n"
83     "   -s, --summary\n"
84     "\n"
85     "-a, --annotate                  Show annotated source code\n"
86     "\n"
87     "   The contents of all source code files found within the given\n"
88     "   paths will be emitted to stdout. Each line will be prefixed with\n"
89     "   a tab-delimited language name and semantic categorization (code,\n"
90     "   comment, or blank).\n"
91     "\n"
92     "-d, --detect                    Find source code files\n"
93     "\n"
94     "   Recursively find all source code files within the given paths.\n"
95     "   For each source code file found, the file name will be emitted to\n"
96     "   stdout prefixed with a tab-delimited language name.\n"
97     "\n"
98     "-h, --help                      Display this message\n"
99     "\n"
100     "-g, --gestalt                   Project Properties\n"
101     "\n"
102     "   Inspects project contents to determine what platform(s) the project\n"
103     "   runs on, as well as any detected tools/IDEs used to develop it.\n"
104     "\n"
105     "-i, --individual                Count lines of code per file\n"
106     "\n"
107     "   Count lines in all source code files within the given paths, and\n"
108     "   emit a report of the lines of code, comments, and blanks in each\n"
109     "   language per file.\n"
110     "\n"
111     "-l, --license\n"
112     "\n"
113     "   Displays detected licensing information contained in each source\n"
114     "   code file.\n"
115     "\n"
116     "-re\n"
117     "\n"
118     "   Prints raw entity information to the screen (mainly for debugging).\n"
119     "\n"
120     "-s, --summary                   Count lines of code (default)\n"
121     "\n"
122     "   Count lines in all source code files within the given paths, and\n"
123     "   emit a report of the total number of lines of code, comments,\n"
124     "   and blanks in each language. This is the default action.\n"
125     "\n"
126     "[paths] can refer to any number of individual files or directories.\n"
127     "   Directories will be probed recursively. If no path is given,\n"
128     "   the current directory will be used.\n"
129   );
130 }
131
132 void sort_loc_list_by_language(LocList *list) {
133   LocList *iter = list->head;
134   while (iter) {
135     LocList *min = iter;
136     LocList *iter2 = iter->next;
137     while (iter2) {
138       if (strcmp(iter2->loc->language, min->loc->language) < 0)
139         min = iter2;
140       iter2 = iter2->next;
141     }
142     if (iter != min) {
143       Loc *temp = iter->loc;
144       iter->loc = min->loc;
145       min->loc = temp;
146     }
147     iter = iter->next;
148   }
149 }
150
151 void individual(SourceFileList *list) {
152   int count = 0;
153   SourceFileList *titer = list->head;
154   while (titer) {
155     count++;
156     titer = titer->next;
157   }
158   printf(
159     "Examining %i file(s)\n"
160     "                              Ohloh Line Count                              \n"
161     "Language               Code    Comment  Comment %%      Blank      Total  File\n"
162     "----------------  ---------  ---------  ---------  ---------  ---------  -----------------------------------------------\n"
163     , count);
164   SourceFileList *iter = list->head;
165   while (iter) {
166     LocList *loc_list = ohcount_sourcefile_get_loc_list(iter->sf);
167     sort_loc_list_by_language(loc_list);
168     LocList *liter = loc_list->head;
169     while (liter) {
170       printf("%-16s", liter->loc->language);
171       printf(" %10d", liter->loc->code);
172       printf(" %10d", liter->loc->comments);
173       if (liter->loc->comments + liter->loc->code > 0)
174         printf(" %9.1f%%",
175                (float)liter->loc->comments / (liter->loc->comments +
176                  liter->loc->code) * 100);
177       else
178         printf("           ");
179       printf(" %10d", liter->loc->blanks);
180       printf(" %10d",
181              liter->loc->code + liter->loc->comments + liter->loc->blanks);
182       printf("  %s\n", iter->sf->filename);
183       liter = liter->next;
184     }
185     iter = iter->next;
186   }
187 }
188
189 void sort_loc_list_by_code(LocList *list) {
190   LocList *iter = list->head;
191   while (iter) {
192     LocList *max = iter;
193     LocList *iter2 = iter->next;
194     while (iter2) {
195       if (iter2->loc->code > max->loc->code)
196         max = iter2;
197       iter2 = iter2->next;
198     }
199     if (iter != max) {
200       Loc *temp = iter->loc;
201       iter->loc = max->loc;
202       max->loc = temp;
203     }
204     iter = iter->next;
205   }
206 }
207
208 void summary(SourceFileList *list) {
209   int count = 0;
210   SourceFileList *tmpiter = list->head;
211   while (tmpiter) {
212     count++;
213     tmpiter = tmpiter->next;
214   }
215   printf("Examining %i file(s)\n", count);
216   LocList *loc_list = ohcount_sourcefile_list_analyze_languages(list);
217   sort_loc_list_by_code(loc_list);
218   printf(
219     "\n"
220     "                          Ohloh Line Count Summary                          \n"
221     "\n"
222     "Language          Files       Code    Comment  Comment %%      Blank      Total\n"
223     "----------------  -----  ---------  ---------  ---------  ---------  ---------\n");
224   LocList *iter = loc_list->head;
225   while (iter) {
226     printf("%-16s", iter->loc->language);
227     printf(" %6d", iter->loc->filecount);
228     printf(" %10d", iter->loc->code);
229     printf(" %10d", iter->loc->comments);
230     if (iter->loc->comments + iter->loc->code > 0)
231       printf(" %9.1f%%",
232              (float)iter->loc->comments / (iter->loc->comments +
233                iter->loc->code) * 100);
234     else
235       printf("       0.0%%");
236     printf(" %10d", iter->loc->blanks);
237     printf(" %10d\n",
238            iter->loc->code + iter->loc->comments + iter->loc->blanks);
239     iter = iter->next;
240   }
241   printf("----------------  -----  ---------  ---------  ---------  ---------  ---------\n");
242   int code = ohcount_loc_list_code(loc_list);
243   int comments = ohcount_loc_list_comments(loc_list);
244   int blanks = ohcount_loc_list_blanks(loc_list);
245   printf("%-16s", "Total");
246   printf(" %6d", ohcount_loc_list_filecount(loc_list));
247   printf(" %10d", code);
248   printf(" %10d", comments);
249   if (comments + code > 0)
250     printf(" %9.1f%%", (float)comments / (comments + code) * 100);
251   else
252     printf("       0.0%%");
253   printf(" %10d", blanks);
254   printf(" %10d\n", code + comments + blanks);
255   ohcount_loc_list_free(loc_list);
256 }
257
258 int main(int argc, char *argv[]) {
259   int command = 0;
260   if (argc > 1) {
261     struct OhcountOption *opt = ohcount_hash_command_from_flag(argv[1],
262                                                                strlen(argv[1]));
263     if (opt)
264       command = opt->value;
265   }
266   int i = 1;
267   if (command == 0)
268     command = COMMAND_SUMMARY;
269   else
270     i = 2; // parameter is not a file or directory
271
272   SourceFileList *list = ohcount_sourcefile_list_new();
273   if (i == argc)
274     ohcount_sourcefile_list_add_directory(list, ".");
275   for (; i < argc; i++) {
276     DIR *dir = opendir(argv[i]);
277     if (dir) {
278       ohcount_sourcefile_list_add_directory(list, argv[i]);
279       closedir(dir);
280     } else {
281       FILE *f = fopen(argv[i], "r");
282       if (f) {
283         ohcount_sourcefile_list_add_file(list, argv[i]);
284         fclose(f);
285       } else printf("Bad argument: %s\n", argv[i]);
286     }
287   }
288   switch (command) {
289   case COMMAND_ANNOTATE:
290     annotate(list);
291     break;
292   case COMMAND_DETECT:
293     detect(list);
294     break;
295   case COMMAND_HELP:
296     help();
297     break;
298   case COMMAND_GESTALT:
299     break;
300   case COMMAND_INDIVIDUAL:
301     individual(list);
302     break;
303   case COMMAND_LICENSES:
304     licenses(list);
305     break;
306   case COMMAND_RAWENTITIES:
307     raw_entities(list);
308     break;
309   case COMMAND_SUMMARY:
310     summary(list);
311     break;
312   }
313   ohcount_sourcefile_list_free(list);
314
315   return 0;
316 }