void test_options() { String *pat = String::create(state, "."); Regexp* re = Regexp::create(state); re->initialize(state, pat, Fixnum::from(0)); TS_ASSERT_EQUALS(as<Integer>(re->options(state))->to_native(), 0); }
/** Send a TPDU through whatever gateway is available. */ short_code_action submitSMS(const char *imsi, const TLSubmit& submit, const std::string &body, short_code_params *scp) { LOG(INFO) << "from " << imsi << " message: " << submit; const TLAddress& address = submit.DA(); // Check for direct e-mail address at start of message body. // FIXME -- This doesn't really follow the spec. See GSM 03.40 3.8. static const Regexp emailAddress("^[[:graph:]]+@[[:graph:]]+ "); if (emailAddress.match(body.data())) { // FIXME -- Get the sender's E.164 to put in the subject line. char bodyCopy[body.length()+2]; strcpy(bodyCopy,body.data()); char* SMTPAddress = bodyCopy; char* term = strchr(bodyCopy,' '); // If term's NULL, the regexp is broken. assert(term); *term = '\0'; char* SMTPPayload = term+1; LOG(INFO) << "sending SMTP to " << SMTPAddress << ": " << SMTPPayload; if (SMTPPayload) return sendEMail(SMTPAddress,SMTPPayload,"from OpenBTS gateway"); else return sendEMail(SMTPAddress,"(empty)","from OpenBTS gateway"); } // Send to smqueue or HTTP gateway, depending on what's defined in the config. if (gConfig.defines("SMS.HTTP.Gateway")) // If there is an external HTTP gateway, use it. return sendHTTP(address.digits(), body); else // Otherwise, we are looking for a SIP interface to smqueue. return sendSIP_init(imsi, submit, body, scp); }
void test_initialize() { String *pat = String::create(state, "."); Regexp* re = Regexp::create(state); re->initialize(state, pat, Fixnum::from(0)); TS_ASSERT_EQUALS(re->source(), pat); TS_ASSERT_EQUALS(re->names(), cNil); }
void test_create_with_named_captures() { String *pat = String::create(state, "(?<blah>.)"); Regexp* re = Regexp::create(state); re->initialize(state, pat, Fixnum::from(0)); TS_ASSERT_EQUALS(re->source(), pat); TS_ASSERT(re->names()->kind_of_p(state, G(lookuptable))); }
void test_create_with_bad_pattern() { char buf[1024]; memset(buf, 0, 1024); String *pat = String::create(state, "(?"); Regexp* re = Regexp::create(state); TS_ASSERT_THROWS(re->initialize(state, pat, Fixnum::from(0)), const RubyException &); }
void test_match_region_without_matches() { String *pat = String::create(state, "d"); Regexp* re = Regexp::create(state); re->initialize(state, pat, Fixnum::from(0)); String *input = String::create(state, "abc"); Fixnum* start = Fixnum::from(0); Fixnum* end = Fixnum::from(3); Object* forward = cTrue; MatchData* matches = (MatchData*)re->match_region(state, input, start, end, forward); TS_ASSERT(matches->nil_p()); }
/** Send a TPDU through whatever gateway is available. */ short_code_action submitSMS(const char *imsi, const TLSubmit& submit, const std::string &body, short_code_params *scp) { LOG(INFO) << "from " << imsi << " message: " << submit; const TLAddress& address = submit.DA(); //#if 0 //This is broken under Unbuntu becasue of changes in the "mail" program. // Check for direct e-mail address at start of message body. // FIXME -- This doesn't really follow the spec. See GSM 03.40 3.8. static const Regexp emailAddress("^[[:graph:]]+@[[:graph:]]+ "); if (emailAddress.match(body.data())) { char bodyCopy[body.length()+2]; strcpy(bodyCopy,body.data()); char* SMTPAddress = bodyCopy; char* term = strchr(bodyCopy,' '); // If term's NULL, the regexp emailAddress is broken. assert(term); *term = '\0'; char* SMTPPayload = term+1; // Get the sender's E.164 to put in the subject line. char* clid = scp->scp_smq->my_hlr.getCLIDLocal(imsi); char subjectLine[200]; if (!clid) sprintf(subjectLine,"from %s",imsi); else { sprintf(subjectLine,"from %s",clid); free(clid); } // Send it. LOG(INFO) << "sending SMTP to " << SMTPAddress << ": " << SMTPPayload; if (SMTPPayload) return sendEMail(SMTPAddress,SMTPPayload,subjectLine); else return sendEMail(SMTPAddress,"(empty)","from OpenBTS gateway"); } //#endif char* destinationNumber = scp->scp_smq->my_hlr.getIMSI2(address.digits()); // Send to smqueue or HTTP gateway, depending on what's defined in the config. // And whether of not we can resolve the destination, and a global relay does not exist, // AND the message is not to a shortcode. if (gConfig.getStr("SIP.GlobalRelay.IP").length() == 0 && gConfig.getStr("SMS.HTTPGateway.URL").length() != 0 && !destinationNumber) // If there is an external HTTP gateway, use it. return sendHTTP(address.digits(), body); free(destinationNumber); return sendSIP_init(imsi, submit, body, scp); }
void test_match_start() { String *pat = String::create(state, "."); Regexp* re = Regexp::create(state); re->initialize(state, pat, Fixnum::from(0)); String *input = String::create(state, "abc"); Fixnum* start = Fixnum::from(1); MatchData* matches = (MatchData*)re->match_start(state, input, start); TS_ASSERT(!matches->nil_p()); TS_ASSERT_EQUALS(matches->region()->num_fields(), 0); TS_ASSERT_EQUALS(as<Integer>(matches->full()->at(state, 0))->to_native(), 1); TS_ASSERT_EQUALS(as<Integer>(matches->full()->at(state, 1))->to_native(), 2); }
double ExmapTest::get_pid_size_from_ps(pid_t pid) { list<string> lines; list<string> captures; ok(read_proc_output("ps -e -o pid,vsz", lines), "can read proc output"); Regexp re; stringstream sstr; sstr << "\\s*" << pid << "\\s"; re.compile(sstr.str()); re.grep(lines); is((int) lines.size(), 1, "found line for pid"); re.compile("\\s*(\\d+)\\s+(\\d+)$"); re.match_capture(lines.front(), captures); is((int) captures.size(), 2, "Found my captures"); int size = atoi(captures.back().c_str()); return size * 1024.0; }
void test_match_region() { String *pat = String::create(state, "."); Regexp* re = Regexp::create(state); re->initialize(state, pat, Fixnum::from(0), Qnil); String *input = String::create(state, "abc"); Fixnum* start = Fixnum::from(0); Fixnum* end = Fixnum::from(3); Object* forward = Qtrue; MatchData* matches = (MatchData*)re->match_region(state, input, start, end, forward); TS_ASSERT(!matches->nil_p()); TS_ASSERT_EQUALS(matches->region()->num_fields(), 0U); TS_ASSERT_EQUALS(as<Integer>(matches->full()->at(state, 0))->to_native(), 0); TS_ASSERT_EQUALS(as<Integer>(matches->full()->at(state, 1))->to_native(), 1); }
void test_match_region_with_backward_captures() { String *pat = String::create(state, ".(.)"); Regexp* re = Regexp::create(state); re->initialize(state, pat, Fixnum::from(0)); String *input = String::create(state, "abc"); Fixnum* start = Fixnum::from(0); Fixnum* end = Fixnum::from(3); Object* forward = cFalse; MatchData* matches = re->match_region(state, input, start, end, forward); TS_ASSERT(!matches->nil_p()); TS_ASSERT_EQUALS(as<Integer>(matches->full()->at(state, 0))->to_native(), 1); TS_ASSERT_EQUALS(as<Integer>(matches->full()->at(state, 1))->to_native(), 3); TS_ASSERT_EQUALS(matches->region()->num_fields(), 1); TS_ASSERT_EQUALS(as<Integer>(as<Tuple>(matches->region()->at(state, 0))->at(state, 0))->to_native(), 2); TS_ASSERT_EQUALS(as<Integer>(as<Tuple>(matches->region()->at(state, 0))->at(state, 1))->to_native(), 3); }
boolean FileBrowser::Acceptable(const char* name) { boolean dir1 = IsADirectory(name); int m = dir1 ? directory_mode : mode; Regexp* r = dir1 ? directory_regexp : regexp; boolean mode_ok, name_ok; if (m != 0) { struct stat st; mode_ok = stat((char*)name, &st) == 0 && (st.st_mode & m) != 0; } else { mode_ok = true; } if (r != nil) { name_ok = r->Match(name, strlen(name), 0) >= 0; } else { name_ok = true; } return mode_ok && name_ok; }
bool FallBackHandler::received(Message &msg) { switch (m_type) { case Answered: { GenObject* route = s_fallbacklist[msg.getValue("targetid")]; s_fallbacklist.remove(route); return false; } break; case Hangup: { GenObject* route = s_fallbacklist[msg.getValue("id")]; s_fallbacklist.remove(route); return false; } break; case Disconnect: { String reason=msg.getValue("reason"); if (m_stoperror && m_stoperror.matches(reason)) { //stop fallback on this error GenObject* route = s_fallbacklist[msg.getValue("id")]; s_fallbacklist.remove(route); return false; } FallBackRoute* route = static_cast<FallBackRoute*>(s_fallbacklist[msg.getValue("id")]); if (route) { Message* r = route->get(); if (r) { r->userData(msg.userData()); Engine::enqueue(r); return true; } s_fallbacklist.remove(route); } return false; } break; } return false; }
int SPString::m(Regexp & r) { return r.match(*this); }
bool ExmapTest::run() { SysInfoPtr sysinfo(new LinuxSysInfo); Snapshot snap(sysinfo); is(snap.num_procs(), 0, "zero procs before load"); ok(snap.load(), "can load snapshot"); ok(snap.num_procs() > 0, "some procs after load"); list<ProcessPtr> allprocs = snap.procs(); ok(!allprocs.empty(), "can get a list of procs"); list<ProcessPtr>::iterator proc_it; list<ProcessPtr> procs; bool failed_to_get_sizes = false; SizesPtr sizes; for (proc_it = allprocs.begin(); proc_it != allprocs.end(); ++proc_it) { string cmdline = (*proc_it)->cmdline(); if (cmdline== SA_EXE) { procs.push_back(*proc_it); } sizes = (*proc_it)->sizes(); if (!sizes) { failed_to_get_sizes = true; } } ok(!failed_to_get_sizes, "can get sizes for every proc"); is((int) procs.size(), NUM_INSTANCES, "can find all our sharedarray procs"); ProcessPtr proc = procs.front(); sizes = proc->sizes(); ok(sizes->val(Sizes::VM) > NUM_ARRAYS * ARRAY_SIZE, "image is big enough"); double ps_size = get_pid_size_from_ps(proc->pid()); is_approx_rel(sizes->val(Sizes::VM), ps_size, 0.001, "exmap info matches ps output"); ok(sizes->val(Sizes::RESIDENT) > 0, "nonzero resident size"); ok(sizes->val(Sizes::EFFECTIVE_RESIDENT) > 0, "nonzero eff resident size"); ok(sizes->val(Sizes::EFFECTIVE_RESIDENT) < sizes->val(Sizes::RESIDENT), "effective is smaller than eff resident"); ok(sizes->val(Sizes::MAPPED) > 0, "nonzero mapped size"); ok(sizes->val(Sizes::EFFECTIVE_MAPPED) > 0, "nonzero eff mapped size"); ok(sizes->val(Sizes::EFFECTIVE_MAPPED) < sizes->val(Sizes::MAPPED), "effective is smaller than eff mapped"); list<FilePtr> files; list<FilePtr>::iterator file_it; list<FilePtr> all_files = snap.files(); ok(all_files.size() > 0, "can find some files"); Regexp re; re.compile(SA_LIB + "$"); failed_to_get_sizes = false; for (file_it = all_files.begin(); file_it != all_files.end(); ++file_it) { string name = (*file_it)->name(); if (re.matches(name)) { files.push_back(*file_it); } sizes = (*file_it)->sizes(); if (!sizes) { failed_to_get_sizes = true; } } ok(!failed_to_get_sizes, "can get sizes for every file"); is((int) files.size(), 1, "shared lib only listed once"); FilePtr shlib_file = files.front(); ok(shlib_file->is_elf(), "shared lib recognised as elf file"); list<ProcessPtr> procs_per_file = shlib_file->procs(); is((int) procs_per_file.size(), NUM_INSTANCES, "right number of procs mapping the file"); for (proc_it = procs_per_file.begin(); proc_it != procs_per_file.end(); ++proc_it) { ok(proc->cmdline() == SA_EXE, "each proc has correct cmdline"); } for (proc_it = procs.begin(); proc_it != procs.end(); ++proc_it) { sizes = proc->sizes(shlib_file); long arrays_size = NUM_ARRAYS * ARRAY_SIZE; float delta = std::abs(arrays_size - (long) sizes->val(Sizes::VM)); delta /= arrays_size; ok(delta < 0.01, "Shared lib has correct size in each proc"); } Elf::SectionPtr text = shlib_file->elf()->section(".text"); ok(text, "can find text section"); ok(text->size() > 0, "text section has nonzero size"); sizes = procs.front()->sizes(shlib_file, text->mem_range()); /// This appears to be compiler and system dependent... /* is_approx_rel(sizes->val(Sizes::RESIDENT), 2.0 * text->size(), 0.001, "lib text is resident and mapped twice (!)"); */ Elf::SectionPtr bss = shlib_file->elf()->section(".bss"); ok(bss, "can find bss section"); ok(bss->size() > 0, "bss section has nonzero size"); SizesPtr bss_sizes = procs.front()->sizes(shlib_file, bss->mem_range()); ok(bss_sizes, "can get sizes for bss section"); Elf::SectionPtr data = shlib_file->elf()->section(".data"); ok(data, "can find data section"); ok(data->size() > 0, "data section has nonzero size"); SizesPtr data_sizes = procs.front()->sizes(shlib_file, data->mem_range()); ok(data_sizes, "can get sizes for data section"); is(data->size(), bss->size(), "data and bss sections have same size"); is_approx(data_sizes->val(Sizes::MAPPED), bss_sizes->val(Sizes::MAPPED), Elf::page_size(), "data and bss mapped within page of each other"); is_approx(data_sizes->val(Sizes::RESIDENT), bss_sizes->val(Sizes::RESIDENT), Elf::page_size(), "data and bss resident within page of each other"); // Now get the all-proc sizes from the file sizes = shlib_file->sizes(bss->mem_range()); // The totals should be a multiple of the individual is(sizes->val(Sizes::RESIDENT), bss_sizes->val(Sizes::RESIDENT) * NUM_INSTANCES, "Total resident for all procs the same as multiplying up one proc"); is(sizes->val(Sizes::MAPPED), bss_sizes->val(Sizes::MAPPED) * NUM_INSTANCES, "Total mapped for all procs the same as multiplying up one proc"); double bss_resident_arrays_size = 0; double data_resident_arrays_size = 0; double bss_writable_arrays_size = 0; double data_writable_arrays_size = 0; for (int i = 0; i < NUM_ARRAYS; ++i) { if (ARRAY_INFO[i].initialised) { data_resident_arrays_size += ARRAY_SIZE * ARRAY_INFO[i].resident_percent / 100; data_writable_arrays_size += ARRAY_SIZE * ARRAY_INFO[i].writable_percent / 100; } else { bss_resident_arrays_size += ARRAY_SIZE * ARRAY_INFO[i].resident_percent / 100; bss_writable_arrays_size += ARRAY_SIZE * ARRAY_INFO[i].writable_percent / 100; } } for (proc_it = procs.begin(); proc_it != procs.end(); ++proc_it) { sizes = proc->sizes(shlib_file, data->mem_range()); is_approx(sizes->val(Sizes::RESIDENT), data_resident_arrays_size, Elf::page_size(), "resident size for data in proc correct with a page"); is_approx(sizes->val(Sizes::WRITABLE), data_writable_arrays_size, Elf::page_size(), "writable size for data in proc correct with a page"); sizes = proc->sizes(shlib_file, bss->mem_range()); is_approx_rel(sizes->val(Sizes::RESIDENT), bss_resident_arrays_size, 0.001, "correct resident size for bss in proc"); is_approx_rel(sizes->val(Sizes::WRITABLE), bss_writable_arrays_size, 0.001, "correct writable size for bss in proc"); } for (int i = 0; i < NUM_ARRAYS; ++i) { const struct array_info *info = ARRAY_INFO + i; string symname = info->name; Elf::SymbolPtr sym = shlib_file->elf()->symbol(symname); ok(sym, "can find symbol " + symname); is(sym->size(), ARRAY_SIZE, symname + " has correct size"); sizes = proc->sizes(shlib_file, sym->range()); is_approx_rel((int) sizes->val(Sizes::RESIDENT), ARRAY_SIZE * info->resident_percent / 100, 0.001, symname + " has correct resident size"); is_approx_rel(sizes->val(Sizes::WRITABLE), ARRAY_SIZE * info->writable_percent / 100.0, 0.001, symname + " has correct writable size"); // Uninitialised space which is only read appears to be shared // amongst every proc in the system (a 'zero page'?). This is // good from a low-memusage point of view, but it means that // it is shared among nearly all running procs to varying // degrees. So we can't really account for it. if (symname == "uninit_readme" || symname == "uninit_readhalf") { continue; } int expected_eff_resident = ARRAY_SIZE * info->resident_percent / 100; if (info->shared) { expected_eff_resident /= NUM_INSTANCES; } // approximate match since the percentage (fixed pt) // arithmetic could put us off by a factor of 1/100 (and does...:-) is_approx((int) sizes->val(Sizes::EFFECTIVE_RESIDENT), expected_eff_resident, 1 + (expected_eff_resident / 100), symname + " has correct effective size"); } // Non-elf maps procs.clear(); for (proc_it = allprocs.begin(); proc_it != allprocs.end(); ++proc_it) { string cmdline = (*proc_it)->cmdline(); if (cmdline == MI_EXE) { procs.push_back(*proc_it); } } is((int) procs.size(), NUM_INSTANCES, "can find all our mapit procs"); proc = procs.front(); files.clear(); re.compile("/" + MI_DAT + "$"); for (file_it = all_files.begin(); file_it != all_files.end(); ++file_it) { string name = (*file_it)->name(); if (re.matches(name)) { files.push_back(*file_it); } } is((int) files.size(), 1, MI_DAT + " file only listed once"); FilePtr mapped_file = files.front(); ok(!mapped_file->is_elf(), MI_DAT + " isn't an elf file"); off_t fsize = 0; double mi_data_size = 0; ok(file_size(MI_DAT, fsize), "can get file size"); mi_data_size = fsize; ok(mi_data_size > 0, "file has nonzero size"); for (proc_it = procs.begin(); proc_it != procs.end(); ++proc_it) { sizes = (*proc_it)->sizes(mapped_file); is_approx_rel(sizes->val(Sizes::VM), mi_data_size, 0.001, "correct data file size"); is_approx_rel(sizes->val(Sizes::RESIDENT), mi_data_size, 0.001, "whole data file is resident"); is_approx_rel(sizes->val(Sizes::EFFECTIVE_RESIDENT), mi_data_size / NUM_INSTANCES, 0.001, "data file is shared between instances correctly"); } return true; }
// Decode the message line // Command: verb transaction endpoint proto_name proto_version ... // Response: code transaction comment ... MGCPMessage* MGCPMessage::decodeMessage(const char* line, unsigned int len, unsigned int& trans, String& error, MGCPEngine* engine) { String name, ver; int code = -1; unsigned int trID = 0; MGCPEndpointId id; #ifdef PARSER_DEBUG String msgLine(line,len); Debug(engine,DebugAll,"Parse message line (len=%u): %s", msgLine.length(),msgLine.c_str()); #endif for (unsigned int item = 1; true; item++) { if (item == 6) { #ifdef DEBUG if (len) { String rest(line,len); Debug(engine,DebugAll,"Unparsed data on message line: '%s'",rest.c_str()); } #endif break; } // Response: the 3rd item is the comment bool comment = (item == 3) && (code != -1); // Get current item if (!(skipBlanks(line,len) || comment)) { error = "Unexpected end of line"; return 0; } unsigned int itemLen = 0; if (comment) itemLen = len; else for (; itemLen < len && !isBlank(line[itemLen]); itemLen++) ; String tmp(line,itemLen); len -= itemLen; line += itemLen; switch (item) { // 1st item: verb (command or notification) or response code // Verbs must be 4-character long. Responses must be numbers in the interval [0..999] case 1: if (tmp.length() == 3) { code = tmp.toInteger(-1,10); if (code < 0 || code > 999) error << "Invalid response code " << tmp; } else if (tmp.length() == 4) name = tmp.toUpper(); else error << "Invalid first item '" << tmp << "' length " << tmp.length(); break; // 2nd item: the transaction id // Restriction: must be a number in the interval [1..999999999] case 2: trID = tmp.toInteger(-1,10); if (!trID || trID > 999999999) error << "Invalid transaction id '" << tmp << "'"; // Set trans for command messages so they can be responded on error else if (code == -1) trans = trID; break; // 3rd item: endpoint id (code is -1) or response comment (code != -1) case 3: if (code != -1) name = tmp; else { id.set(tmp); if (!id.valid()) error << "Invalid endpoint id '" << tmp << "'"; } break; // 4th item: protocol name if this is a verb (command) case 4: ver = tmp.toUpper(); if (ver != "MGCP") error << "Invalid protocol '" << tmp << "'"; break; // 5th item: protocol version if this is a verb (command) case 5: { static const Regexp r("^[0-9]\\.[0-9]\\+$"); if (!r.matches(tmp)) error << "Invalid protocol version '" << tmp << "'"; } ver << " " << tmp; break; } if (error) return 0; // Stop parse the rest if this is a response if (comment) break; } // Check known commands if (code == -1 && !(engine && (engine->allowUnkCmd() || engine->knownCommand(name)))) { error << "Unknown cmd '" << name << "'"; return 0; } return new MGCPMessage(engine,name,code,trID,id.id(),ver); }
// 'self' is passed in automatically by the primitive glue Regexp* Regexp::allocate(STATE, Object* self) { Regexp* re = Regexp::create(state); re->onig_data = NULL; re->klass(state, as<Class>(self)); return re; }
void test_allocate() { Class* sub = ontology::new_class(state, "RegexpSub", G(regexp), 0); Regexp* re = Regexp::allocate(state, sub); TS_ASSERT_EQUALS(re->klass(), sub); }
void Regexp::make_managed(STATE) { Regexp* obj = this; regex_t* reg = onig_data; assert(reg->chain == 0); ByteArray* reg_ba = ByteArray::create(state, sizeof(regex_t)); memcpy(reg_ba->raw_bytes(), reg, sizeof(regex_t)); regex_t* old_reg = reg; reg = reinterpret_cast<regex_t*>(reg_ba->raw_bytes()); obj->onig_data = reg; write_barrier(state, reg_ba); if(reg->p) { ByteArray* pattern = ByteArray::create(state, reg->alloc); memcpy(pattern->raw_bytes(), reg->p, reg->alloc); reg->p = reinterpret_cast<unsigned char*>(pattern->raw_bytes()); obj->write_barrier(state, pattern); } if(reg->exact) { int exact_size = reg->exact_end - reg->exact; ByteArray* exact = ByteArray::create(state, exact_size); memcpy(exact->raw_bytes(), reg->exact, exact_size); reg->exact = reinterpret_cast<unsigned char*>(exact->raw_bytes()); reg->exact_end = reg->exact + exact_size; obj->write_barrier(state, exact); } int int_map_size = sizeof(int) * ONIG_CHAR_TABLE_SIZE; if(reg->int_map) { ByteArray* intmap = ByteArray::create(state, int_map_size); memcpy(intmap->raw_bytes(), reg->int_map, int_map_size); reg->int_map = reinterpret_cast<int*>(intmap->raw_bytes()); obj->write_barrier(state, intmap); } if(reg->int_map_backward) { ByteArray* intmap_back = ByteArray::create(state, int_map_size); memcpy(intmap_back->raw_bytes(), reg->int_map_backward, int_map_size); reg->int_map_backward = reinterpret_cast<int*>(intmap_back->raw_bytes()); obj->write_barrier(state, intmap_back); } if(reg->repeat_range) { int rrange_size = sizeof(OnigRepeatRange) * reg->repeat_range_alloc; ByteArray* rrange = ByteArray::create(state, rrange_size); memcpy(rrange->raw_bytes(), reg->repeat_range, rrange_size); reg->repeat_range = reinterpret_cast<OnigRepeatRange*>(rrange->raw_bytes()); obj->write_barrier(state, rrange); } onig_free(old_reg); }
void test_create() { Regexp* re = Regexp::create(state); TS_ASSERT(re->source()->nil_p()); TS_ASSERT(re->names()->nil_p()); TS_ASSERT_EQUALS(re->klass(), G(regexp)); }
// 'self' is passed in automatically by the primitive glue Regexp* Regexp::allocate(STATE, Object* self) { Regexp* re = Regexp::create(state); re->onig_data = 0; re->klass(state, (Class*)self); return re; }