Deleted the code the new Ragel parser obsoletes.
[ohcount] / ext / ohcount_native / ruby_binding.c
1 #include "ruby.h"
2 #include "common.h"
3
4 static VALUE rb_module_ohcount;
5 static VALUE rb_class_language_breakdown;
6
7
8 /*****************************************************************************
9                                LanguageBreakdown
10 *****************************************************************************/
11
12 static void _language_breakdown_free(LanguageBreakdown *language_breakdown) {
13         language_breakdown_free(language_breakdown);
14         free(language_breakdown);
15 }
16
17 static VALUE _language_breakdown_allocate(VALUE klass) {
18         int _my_language_id;
19         int _my_buffer_size;
20         _my_language_id = 0;
21         _my_buffer_size = 100;
22         LanguageBreakdown *language_breakdown = (LanguageBreakdown *) malloc(sizeof(LanguageBreakdown));
23         language_breakdown_initialize(language_breakdown, "", _my_buffer_size);
24
25         /* bs initializers */
26         strcpy(language_breakdown->name, "");
27         strcpy(language_breakdown->code, "");
28         strcpy(language_breakdown->comment, "");
29         return Data_Wrap_Struct(klass, 0, _language_breakdown_free, language_breakdown);
30 }
31
32 static VALUE _language_breakdown_initialize(VALUE self, VALUE name, VALUE code, VALUE comment, VALUE blanks) {
33         /* validation */
34         Check_Type(name, T_STRING);
35         Check_Type(code, T_STRING);
36         Check_Type(comment, T_STRING);
37         Check_Type(blanks, T_FIXNUM);
38
39         LanguageBreakdown *lb;
40         Data_Get_Struct (self, LanguageBreakdown, lb);
41
42         /* name */
43         strncpy(lb->name, rb_string_value_ptr(&name), MAX_LANGUAGE_NAME);
44
45         /* code */
46         if (lb->code != NULL) {
47                 free(lb->code);
48         }
49         lb->code = (char*)malloc(RSTRING(code)->len);
50         strcpy(lb->code, rb_string_value_ptr(&code));
51
52         /* comment */
53         if (lb->comment != NULL) {
54                 free(lb->comment);
55         }
56         lb->comment = (char*)malloc(RSTRING(comment)->len);
57         strcpy(lb->comment, rb_string_value_ptr(&comment));
58
59         /* blanks */
60         lb->blank_count = NUM2INT(blanks);
61
62         return self;
63 }
64
65 static VALUE _language_breakdown_name(VALUE self) {
66         LanguageBreakdown *lb;
67         Data_Get_Struct (self, LanguageBreakdown, lb);
68         return rb_str_new2(lb->name);
69 }
70
71 static VALUE _language_breakdown_code(VALUE self) {
72         LanguageBreakdown *lb;
73         Data_Get_Struct (self, LanguageBreakdown, lb);
74         return rb_str_new2(lb->code);
75 }
76
77 static VALUE _language_breakdown_comment(VALUE self) {
78         LanguageBreakdown *lb;
79         Data_Get_Struct (self, LanguageBreakdown, lb);
80         return rb_str_new2(lb->comment);
81 }
82
83 static VALUE _language_breakdown_blanks(VALUE self) {
84         LanguageBreakdown *lb;
85         Data_Get_Struct (self, LanguageBreakdown, lb);
86         return INT2NUM(lb->blank_count);
87 }
88
89
90 /*
91  * Ohcount::parse is the main entry point to Ohcount.
92  *
93  * It takes two parameters: a string buffer, and a string Monoglot or Polyglot name.
94  * The buffer will be parsed using the specified glot.
95  *
96  * The method returns an array of LanguageBreakdown objects. One
97  * LanguageBreakdown will be returned for each language found in the buffer.
98  *
99  * You may optionally pass a block of Ruby code. As each line in the buffer
100  * is parsed, it will be yielded to the block, along with the language name
101  * and code semantic determined for that line.
102  *
103  * Ruby example:
104  *
105  *   # Print each line to the console, labeled as code or comments
106  *   buffer = File.read("helloworld.c")
107  *   results = Ohcount::parse(buffer, 'c') do |language, semantic, line|
108  *     puts "#{semantic.to_s} #{line}"
109  *   end
110  *
111  * Another example:
112  *
113  *   # Print total lines of code
114  *   buffer = File.read("helloworld.c")
115  *   results = Ohcount::parse(buffer, 'c')
116  *   results.each do |result|
117  *     puts "Lines of #{result.name} code: #{ result.code.split("\n").size }"
118  *   end
119  *
120  * You must pass the name of a glot appropriate to the buffer you want to parse.
121  * If you are not sure which glot is correct, use the Detector to pick a glot.
122  */
123 static VALUE _ohcount_parse(VALUE self, VALUE buffer, VALUE polyglot_name_value) {
124         ParseResult pr;
125
126         char *polyglot_name = RSTRING(polyglot_name_value)->ptr;
127         if (ragel_parser_parse(&pr, 1, RSTRING(buffer)->ptr, RSTRING(buffer)->len, polyglot_name)) {
128                 // create array we'll return all the language_breakdowns in
129                 VALUE ary = rb_ary_new2(pr.language_breakdown_count);
130
131                 int i_pr;
132                 for(i_pr = 0; i_pr < pr.language_breakdown_count; i_pr++) {
133                         LanguageBreakdown *lb = (LanguageBreakdown *) malloc(sizeof(LanguageBreakdown));
134                         LanguageBreakdown *src_lb = &(pr.language_breakdowns[i_pr]);
135                         strcpy(lb->name,src_lb->name);
136                         lb->code = src_lb->code;
137                         lb->comment = src_lb->comment;
138                         lb->blank_count = src_lb->blank_count;
139                         rb_ary_store(ary, i_pr, Data_Wrap_Struct(rb_class_language_breakdown, 0, _language_breakdown_free, lb));
140                 }
141
142                 return ary;
143         }
144   rb_raise(rb_eStandardError,"Polyglot name invalid: '%s'", polyglot_name);
145         return Qnil;
146 }
147
148
149 /**
150  * Parses a source file's entities (if available).
151  * An entity is each comment, string, number, keyword, etc. that occurs in a
152  * source file.
153  *
154  * You must pass a Ruby block to this function of the form:
155  *   |language, entity, s, e| where:
156  *     language is the language's name (symbol) e.g. ruby.
157  *     entity is the entity's name (symbol) e.g. comment.
158  *     s is the entity's start position in the buffer (number).
159  *     e is the entity's end position in the buffer non-inclusive (number).
160  * If an entity parser is not available for the given language, the block will
161  * never be called. There is currently no way to dynamically test if a language
162  * has an entity parser.
163  *
164  * @param buffer The buffer to parse.
165  * @param language String language name to parse the buffer as. If you are
166  *   unsure which language name is correct, use Ohcount::Detector.detect(file).
167  * @return nil
168  *
169  * @usage
170  *
171  *   # Print each entity and its position in the buffer
172  *   buffer = File.read("helloworld.c")
173  *   Ohcount::parse_entities(buffer, 'c') do |lang, entity, s, e|
174  *     puts "#{lang}\t#{entity}\t#{s}\t#{e}"
175  *   end
176  */
177 static VALUE _ohcount_parse_entities(VALUE self, VALUE buffer, VALUE polyglot_name_value) {
178         char *polyglot_name = RSTRING(polyglot_name_value)->ptr;
179         ParseResult pr;
180         if (!ragel_parser_parse(&pr, 0, RSTRING(buffer)->ptr, RSTRING(buffer)->len, polyglot_name))
181                 rb_raise(rb_eStandardError,"Polyglot name invalid: '%s'", polyglot_name);
182         return Qnil;
183 }
184
185
186 void Init_ohcount_native () {
187         rb_module_ohcount = rb_define_module("Ohcount");
188         rb_define_module_function(rb_module_ohcount, "parse", _ohcount_parse, 2);
189         rb_define_module_function(rb_module_ohcount, "parse_entities", _ohcount_parse_entities, 2);
190
191         // define language_breakdown
192         rb_class_language_breakdown = rb_define_class_under( rb_module_ohcount, "LanguageBreakdown", rb_cObject);
193         rb_define_alloc_func (rb_class_language_breakdown, _language_breakdown_allocate);
194         rb_define_method (rb_class_language_breakdown, "initialize", _language_breakdown_initialize, 4);
195         rb_define_method (rb_class_language_breakdown, "name", _language_breakdown_name, 0);
196         rb_define_method (rb_class_language_breakdown, "code", _language_breakdown_code, 0);
197         rb_define_method (rb_class_language_breakdown, "comment", _language_breakdown_comment, 0);
198         rb_define_method (rb_class_language_breakdown, "blanks", _language_breakdown_blanks, 0);
199 }
200