%option prefix="<%= scanner.function_prefix %>" %option full %option never-interactive %option read %option nounput %option noyywrap noreject noyymore nodefault %{ #include #include /* Data types */ typedef struct { char *key; char *value; } KVPAIR; const KVPAIR EOF_KVPAIR = {"EOF", "EOF"}; /* prototypes */ char *strip_ends(char *); VALUE <%= scanner.main_function_name %>(VALUE); void new_uuid(char *str_ptr); void raise_error_for_string_too_long(VALUE string); void include_message_in_token_hash(VALUE message, VALUE token_hash); void add_uuid_to_token_hash(VALUE token_hash); void push_kv_pair_to_hash(KVPAIR key_value, VALUE token_hash); void concat_word_to_string(KVPAIR key_value, VALUE token_hash); /* Set the scanner name, and return type */ #define YY_DECL KVPAIR <%= scanner.entry_point %>(void) #define yyterminate() return EOF_KVPAIR /* Ruby 1.8 and 1.9 compatibility */ #if !defined(RSTRING_LEN) # define RSTRING_LEN(x) (RSTRING(x)->len) # define RSTRING_PTR(x) (RSTRING(x)->ptr) #endif %} /* Definitions */ CATCHALL (.|"\n") <% scanner.scanner_defns.each do |scanner_defn| %> <%= scanner_defn.scanner_code %> <% end %> %% /* Actions */ <% scanner.scanner_rules.each do |scanner_rule| %> <%= scanner_rule.scanner_code %> <% end %> {CATCHALL} /* ignore */ %% char *strip_ends(char *string) { string[yyleng-1] = '\0'; ++string; return string; } void uuid_unparse_upper_sans_dash(const uuid_t uu, char *out) { sprintf(out, "%02X%02X%02X%02X" "%02X%02X" "%02X%02X" "%02X%02X" "%02X%02X%02X%02X%02X%02X", uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7], uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]); } void new_uuid(char *str_ptr){ uuid_t new_uuid; uuid_generate_time(new_uuid); uuid_unparse_upper_sans_dash(new_uuid, str_ptr); } void raise_error_for_string_too_long(VALUE string){ if( RSTRING_LEN(string) > 1000000){ rb_raise(rb_eArgError, "string too long for <%=scanner.scanner_name %>! max length is 1,000,000 chars"); } } <%= scanner.rdoc %> VALUE <%= scanner.main_function_name %>(VALUE self) { KVPAIR kv_result; int scan_complete = 0; int building_words_to_string = 0; VALUE token_hash = rb_hash_new(); BEGIN(INITIAL); /* error out on absurdly large strings */ raise_error_for_string_too_long(self); /* {:message => self()} */ include_message_in_token_hash(self, token_hash); /* {:id => UUID} */ add_uuid_to_token_hash(token_hash); yy_scan_string(RSTRING_PTR(self)); while (scan_complete == 0) { kv_result = <%= scanner.entry_point %>(); if (kv_result.key == "EOF"){ scan_complete = 1; } else if (kv_result.key == "strings"){ /* build a string until we get a non-word */ if (building_words_to_string == 0){ building_words_to_string = 1; push_kv_pair_to_hash(kv_result, token_hash); } else{ concat_word_to_string(kv_result, token_hash); } } else { building_words_to_string = 0; push_kv_pair_to_hash(kv_result, token_hash); } } yy_delete_buffer(YY_CURRENT_BUFFER); return rb_obj_dup(token_hash); } void add_uuid_to_token_hash(VALUE token_hash) { char new_uuid_str[33]; new_uuid(new_uuid_str); VALUE hsh_key_id = ID2SYM(rb_intern("id")); VALUE hsh_val_id = rb_tainted_str_new2(new_uuid_str); rb_hash_aset(token_hash, hsh_key_id, hsh_val_id); } void include_message_in_token_hash(VALUE message, VALUE token_hash) { /* {:message => self()} */ VALUE hsh_key_msg = ID2SYM(rb_intern("message")); rb_hash_aset(token_hash, hsh_key_msg, message); } void concat_word_to_string(KVPAIR key_value, VALUE token_hash) { char * space = " "; VALUE hsh_key = ID2SYM(rb_intern(key_value.key)); VALUE hsh_value = rb_hash_aref(token_hash, hsh_key); VALUE string = rb_ary_entry(hsh_value, -1); rb_str_cat(string, space, 1); rb_str_cat(string, key_value.value, yyleng); } void push_kv_pair_to_hash(KVPAIR key_value, VALUE token_hash) { VALUE hsh_key = ID2SYM(rb_intern(key_value.key)); VALUE hsh_value = rb_hash_aref(token_hash, hsh_key); VALUE ary_for_token_type = rb_ary_new(); switch (TYPE(hsh_value)) { case T_NIL: rb_ary_push(ary_for_token_type, rb_tainted_str_new2(key_value.value)); rb_hash_aset(token_hash, hsh_key, ary_for_token_type); break; case T_ARRAY: rb_ary_push(hsh_value, rb_tainted_str_new2(key_value.value)); break; } } void <%=scanner.init_function_name %>() { rb_define_method(rb_cString, "<%= scanner.scanner_name %>", <%= scanner.main_function_name %>, 0); }