static int ft_strict_match_to_bucket_index(ft_instance_t ft, of_match_t *match, uint16_t priority) { uint32_t h = FT_HASH_SEED; h = murmur_hash(match, sizeof(*match), h); h = murmur_hash(&priority, sizeof(priority), h); return h % ft->config.strict_match_bucket_count; }
int hash_remove (hash_t *ht, const char *name) { unsigned int hash, clump; // Array for remembering all stores that need to be rehashed store_t **rehash; int rehash_count,i; ht->used--; // Find the start of the collision clump // This includes all hashes that are the same // as the one we are looking up for ( hash = murmur_hash (name, strlen (name)), clump = (hash - 1) % ht->size; ht->table[clump] != NULL && murmur_hash (ht->table[clump]->name, strlen(ht->table[clump]->name)) == hash; clump = (clump - 1) % ht->size) ; // Stores that need to be rehashed are those that fall in the // same collision clump as the hash we're removing for ( clump = (clump + 1) % ht->size, rehash = NULL, rehash_count = 0; ht->table[clump] != NULL; clump = (clump + 1) % ht->size, rehash_count++) { rehash = (store_t **) realloc (rehash, (rehash_count + 1) * sizeof (store_t *)); rehash[rehash_count] = ht->table[clump]; ht->table[clump] = NULL; } // If there was nothing nothing at all to rehash, exit if (rehash == NULL) return 0; // Rehash everything except for the one being removed for (i = 0; i < rehash_count; i++) { if (strcmp (rehash[i]->name, name)) { hash_insert (ht, rehash[i]); } else { ht->remove_callback (rehash[i]); } } free (rehash); return 1; }
/** Hash of key that may be zero or space terminated. */ int skey_hash(const void *v) { assert(v); const char *key = v; size_t len = skey_len(key); return murmur_hash(key, len); }
define_t *search_defines (const char *name) { define_t *result = NULL; char *search_name; list_t *curr_arg_set = arg_list; unsigned int curr_hash; //make name uppercase if needed for case-insensitivity if (!case_sensitive) search_name = strup (name); else search_name = (char *)name; //first search all the sets of arguments in order while (curr_arg_set) { result = (define_t *)hash_lookup ((hash_t *)(curr_arg_set->data), search_name); if (result) break; curr_arg_set = curr_arg_set->next; } //if that doesn't work, look in the global define table if (!result) result = (define_t *)hash_lookup (define_table, search_name); #define MHASH(Z) (murmur_hash(Z, strlen(Z))) curr_hash = murmur_hash (search_name, strlen (search_name)); // Search all SPASM predefined values if (curr_hash == MHASH("__LINE")) { char line_buf[32]; sprintf (line_buf, "%d", line_num); if (result) set_define (result, line_buf, -1, false); } else if (curr_hash == MHASH("__FILE")) { char fn_buf[MAX_PATH + 2]; sprintf (fn_buf, "\"%s\"", curr_input_file); if (result) set_define (result, fn_buf, -1, false); } //printf("fail: %s %08x\n", search_name, murmur_hash(search_name, strlen(search_name))); if (!case_sensitive) free (search_name); //make sure any empty arguments get returned as undefined //if (result && result->contents == NULL) result = NULL; return result; }
void *hash_lookup (hash_t *ht, const char *name) { unsigned int hash = murmur_hash (name, strlen (name)); if (ht == NULL) { return NULL; } hash %= ht->size; // Search the entire clump while (ht->table[hash] != NULL && strcmp (name, ht->table[hash]->name)) hash = (hash + 1) % ht->size; // Return the store -- could be NULL (which indicates no entry) return ht->table[hash]; }
void ipcGetSkinIcons(THeaderIPC *ipch) { TSlotProtoIcons spi; char szTmp[64]; int protoCount; PROTOACCOUNT **pp; if ( CallService(MS_PROTO_ENUMACCOUNTS, WPARAM(&protoCount), LPARAM(&pp)) == 0 && protoCount != 0) { spi.pid = GetCurrentProcessId(); while (protoCount > 0) { PROTOACCOUNT *pa = *pp; lstrcpyA(szTmp, pa->szModuleName); lstrcatA(szTmp, PS_GETCAPS); DWORD dwCaps = CallService(szTmp, PFLAGNUM_1, 0); if (dwCaps & PF1_FILESEND) { TSlotIPC *pct = ipcAlloc(ipch, sizeof(TSlotProtoIcons)); if (pct != NULL) { // capture all the icons! spi.hProto = murmur_hash(pa->szModuleName); for (int j = 0; j <= 10; j++) spi.hIcons[j] = LoadSkinnedProtoIcon(pa->szModuleName, ID_STATUS_OFFLINE + j); pct->fType = REQUEST_NEWICONS; memcpy(LPSTR(pct) + sizeof(TSlotIPC), &spi, sizeof(TSlotProtoIcons)); if (ipch->NewIconsBegin == NULL) ipch->NewIconsBegin = pct; } } pp++; protoCount--; } } // add Miranda icon TSlotIPC *pct = ipcAlloc(ipch, sizeof(TSlotProtoIcons)); if (pct != NULL) { ZeroMemory(&spi.hIcons, sizeof(spi.hIcons)); spi.hProto = 0; // no protocol spi.hIcons[0] = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA); pct->fType = REQUEST_NEWICONS; memcpy(LPSTR(pct) + sizeof(TSlotIPC), &spi, sizeof(TSlotProtoIcons)); if (ipch->NewIconsBegin == NULL) ipch->NewIconsBegin = pct; } }
void *hash_insert (hash_t *ht, void *store) { const char *name = ((store_t *)store)->name; unsigned int hash = murmur_hash(name, strlen (name)); ht->used++; hash %= ht->size; //if (mht->table[hash] != NULL) //printf("collision (%s:%8x %s:%8x)!\n", ((store_t *)store)->name, hash, mht->table[hash]->name, hash); //int clump_size = 0; while (ht->table[hash] != NULL) { hash = (hash + 1) % ht->size; //clump_size++; } //if (clump_size != 0) printf("collision: clump size: %d\n", clump_size); ht->table[hash] = (store_t *)store; return store; }
static int ft_flow_id_to_bucket_index(ft_instance_t ft, indigo_flow_id_t *flow_id) { return (murmur_hash(flow_id, sizeof(*flow_id), FT_HASH_SEED) % ft->config.flow_id_bucket_count); }
static void commit_lua_upload(indigo_cxn_id_t cxn_id, of_object_t *msg) { uint16_t flags; of_bsn_lua_upload_flags_get(msg, &flags); /* TODO use stronger hash function */ uint32_t new_checksum = murmur_hash(xbuf_data(&upload_chunks), xbuf_length(&upload_chunks), 0); if (!(flags & OFP_BSN_LUA_UPLOAD_FORCE) && checksum == new_checksum) { AIM_LOG_VERBOSE("Skipping Lua commit, checksums match"); goto cleanup; } checksum = 0; reset_lua(); uint32_t offset = 0; while (offset < xbuf_length(&upload_chunks)) { struct upload_chunk *chunk = xbuf_data(&upload_chunks) + offset; offset += sizeof(*chunk) + chunk->size; AIM_LOG_VERBOSE("Loading Lua chunk %s, %u bytes", chunk->filename, chunk->size); char name[64]; snprintf(name, sizeof(name), "=%s", chunk->filename); if (luaL_loadbuffer(lua, chunk->data, chunk->size, name) != 0) { AIM_LOG_ERROR("Failed to load code: %s", lua_tostring(lua, -1)); indigo_cxn_send_error_reply( cxn_id, msg, OF_ERROR_TYPE_BAD_REQUEST, OF_REQUEST_FAILED_EPERM); goto cleanup; } /* Set the environment of the new chunk to the sandbox */ lua_getglobal(lua, "sandbox"); lua_setfenv(lua, -2); if (lua_pcall(lua, 0, 1, 0) != 0) { AIM_LOG_ERROR("Failed to execute code %s: %s", chunk->filename, lua_tostring(lua, -1)); indigo_cxn_send_error_reply( cxn_id, msg, OF_ERROR_TYPE_BAD_REQUEST, OF_REQUEST_FAILED_EPERM); goto cleanup; } /* Save the return value in the "modules" table, used by require */ char *module_name = aim_strdup(chunk->filename); char *dot = strrchr(module_name, '.'); if (dot) *dot = 0; /* strip file extension */ lua_getglobal(lua, "modules"); lua_pushstring(lua, module_name); lua_pushvalue(lua, -3); /* return value from pcall */ lua_rawset(lua, -3); /* modules[filename] = return_value */ lua_pop(lua, 2); /* pop modules and return value */ free(module_name); } checksum = new_checksum; cleanup: cleanup_lua_upload(); return; }
bool ipcGetSortedContacts(THeaderIPC *ipch, int *pSlot, bool bGroupMode) { DBVARIANT dbv; int n, rc; bool Result = false; // hide offliners? bool bHideOffline = db_get_b(0, "CList", "HideOffline", 0) == 1; // do they wanna hide the offline people anyway? if (db_get_b(0, SHLExt_Name, SHLExt_ShowNoOffline, 0) == 1) // hide offline people bHideOffline = true; // get the number of contacts int dwContacts = (int)CallService(MS_DB_CONTACT_GETCOUNT, 0, 0); if (dwContacts == 0) return false; // get the contacts in the array to be sorted by status, trim out anyone // who doesn't wanna be seen. TSlotInfo *pContacts = (TSlotInfo*)mir_alloc((dwContacts + 2) * sizeof(TSlotInfo)); int i = 0; int dwOnline = 0; for (MCONTACT hContact = db_find_first(); hContact != 0; hContact = db_find_next(hContact)) { if (i >= dwContacts) break; // do they have a running protocol? char *szProto = GetContactProto(hContact); if (szProto != NULL) { // does it support file sends? DWORD dwCaps = ProtoCallService(szProto, PS_GETCAPS, PFLAGNUM_1, 0); if ((dwCaps & PF1_FILESEND) == 0) continue; int dwStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE); if (dwStatus != ID_STATUS_OFFLINE) dwOnline++; else if (bHideOffline) continue; // is HIT on? if (BST_UNCHECKED == db_get_b(0, SHLExt_Name, SHLExt_UseHITContacts, BST_UNCHECKED)) { // don't show people who are "Hidden" "NotOnList" or Ignored if (db_get_b(hContact, "CList", "Hidden", 0) == 1 || db_get_b(hContact, "CList", "NotOnList", 0) == 1 || CallService(MS_IGNORE_ISIGNORED, hContact, IGNOREEVENT_MESSAGE | IGNOREEVENT_URL | IGNOREEVENT_FILE) != 0) continue; } // is HIT2 off? if (BST_UNCHECKED == db_get_b(0, SHLExt_Name, SHLExt_UseHIT2Contacts, BST_UNCHECKED)) if (db_get_w(hContact, szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE) continue; // store pContacts[i].hContact = hContact; pContacts[i].dwStatus = dwStatus; pContacts[i].hProto = murmur_hash(szProto); i++; } } // if no one is online and the CList isn't showing offliners, quit if (dwOnline == 0 && bHideOffline) { mir_free(pContacts); return false; } dwContacts = i; qsort(pContacts, dwContacts, sizeof(TSlotInfo), SortContact); // create an IPC slot for each contact and store display name, etc for (i=0; i < dwContacts; i++) { char *szContact = (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)pContacts[i].hContact, 0); if (szContact != NULL) { n = 0; rc = 1; if (bGroupMode) { rc = db_get_s(pContacts[i].hContact, "CList", "Group", &dbv); if (!rc) n = lstrlenA(dbv.pszVal) + 1; } int cch = lstrlenA(szContact) + 1; TSlotIPC *pct = ipcAlloc(ipch, cch + 1 + n); if (pct == NULL) { db_free(&dbv); break; } // lie about the actual size of the TSlotIPC pct->cbStrSection = cch; LPSTR szSlot = LPSTR(pct) + sizeof(TSlotIPC); lstrcpyA(szSlot, szContact); pct->fType = REQUEST_CONTACTS; pct->hContact = pContacts[i].hContact; pct->Status = pContacts[i].dwStatus; pct->hProto = pContacts[i].hProto; pct->MRU = db_get_b(pct->hContact, SHLExt_Name, SHLExt_MRU, 0); if (ipch->ContactsBegin == NULL) ipch->ContactsBegin = pct; szSlot += cch + 1; if (rc == 0) { pct->hGroup = murmur_hash(dbv.pszVal); lstrcpyA(szSlot, dbv.pszVal); db_free(&dbv); } else { pct->hGroup = 0; *szSlot = 0; } pSlot[0]++; } } mir_free(pContacts); return true; }
static uint32_t hash_id(uint32_t id) { return murmur_hash(&id, sizeof(id), 0); }
static void BuildMenus(TEnumData *lParam) { LPSTR Token; TMenuDrawInfo *psd; HANDLE hDllHeap = lParam->Self->hDllHeap; HMENU hBaseMenu = lParam->Self->hRootMenu; // build an in memory tree of the groups TGroupNodeList j = { 0, 0 }; TSlotIPC *pg = lParam->ipch->GroupsBegin; while (pg != NULL) { if (pg->cbSize != sizeof(TSlotIPC) || pg->fType != REQUEST_GROUPS) break; UINT Depth = 0; TGroupNode *p = j.First; // start at root again // get the group Token = strtok(LPSTR(pg) + sizeof(TSlotIPC), "\\"); while (Token != NULL) { UINT Hash = murmur_hash(Token); // if the (sub)group doesn't exist, create it. TGroupNode *q = FindGroupNode(p, Hash, Depth); if (q == NULL) { q = AllocGroupNode(&j, p, Depth); q->Depth = Depth; // this is the hash of this group node, but it can be anywhere // i.e. Foo\Foo this is because each node has a different depth // trouble is contacts don't come with depths! q->Hash = Hash; // don't assume that pg->hGroup's hash is valid for this token // since it maybe Miranda\Blah\Blah and we have created the first node // which maybe Miranda, thus giving the wrong hash // since "Miranda" can be a group of it's own and a full path q->cchGroup = lstrlenA(Token); q->szGroup = (LPSTR)HeapAlloc(hDllHeap, 0, q->cchGroup + 1); lstrcpyA(q->szGroup, Token); q->dwItems = 0; } p = q; Depth++; Token = strtok(NULL, "\\"); } pg = pg->Next; } // build the menus inserting into hGroupMenu which will be a submenu of // the instance menu item. e.g. Miranda -> [Groups ->] contacts HMENU hGroupMenu = CreatePopupMenu(); // allocate MRU menu, this will be associated with the higher up menu // so doesn't need to be freed (unless theres no MRUs items attached) // This menu is per process but the handle is stored globally (like a stack) lParam->Self->hRecentMenu = CreatePopupMenu(); lParam->Self->RecentCount = 0; // create group menus only if they exist! if (lParam->ipch->GroupsBegin != NULL) { BuildMenuGroupTree(j.First, lParam, hGroupMenu); // add contacts that have a group somewhere BuildContactTree(j.First, lParam); } MENUITEMINFOA mii = { 0 }; mii.cbSize = sizeof(mii); mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_DATA; // add all the contacts that have no group (which maybe all of them) pg = lParam->ipch->ContactsBegin; while (pg != NULL) { if (pg->cbSize != sizeof(TSlotIPC) || pg->fType != REQUEST_CONTACTS) break; if (pg->hGroup == 0) { DecideMenuItemInfo(pg, NULL, mii, lParam); BuildMRU(pg, mii, lParam); InsertMenuItemA(hGroupMenu, 0xFFFFFFFF, true, &mii); } pg = pg->Next; } // insert MRU menu as a submenu of the contact menu only if // the MRU list has been created, the menu popup will be deleted by itself if (lParam->Self->RecentCount > 0) { // insert seperator and 'clear list' menu mii.fType = MFT_SEPARATOR; mii.fMask = MIIM_TYPE; InsertMenuItemA(lParam->Self->hRecentMenu, 0xFFFFFFFF, true, &mii); // insert 'clear MRU' item and setup callback mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_DATA; mii.wID = lParam->idCmdFirst; lParam->idCmdFirst++; mii.fType = MFT_STRING; mii.dwTypeData = lParam->ipch->ClearEntries; // "Clear entries" // allocate menu substructure psd = (TMenuDrawInfo*)HeapAlloc(hDllHeap, 0, sizeof(TMenuDrawInfo)); psd->fTypes = dtCommand; psd->MenuCommandCallback = &ClearMRUIPC; psd->wID = mii.wID; // this is needed because there is a clear list command per each process. psd->pid = lParam->pid; mii.dwItemData = (LPARAM)psd; InsertMenuItemA(lParam->Self->hRecentMenu, 0xFFFFFFFF, true, &mii); // insert MRU submenu into group menu (with) ownerdraw support as needed psd = (TMenuDrawInfo*)HeapAlloc(hDllHeap, 0, sizeof(TMenuDrawInfo)); psd->szProfile = "MRU"; psd->fTypes = dtGroup; // the IPC string pointer wont be around forever, must make a copy psd->cch = (int)strlen(lParam->ipch->MRUMenuName); psd->szText = (LPSTR)HeapAlloc(hDllHeap, 0, psd->cch + 1); lstrcpynA(psd->szText, lParam->ipch->MRUMenuName, sizeof(lParam->ipch->MRUMenuName) - 1); mii.dwItemData = (LPARAM)psd; if (lParam->bOwnerDrawSupported && lParam->bShouldOwnerDraw) { mii.fType = MFT_OWNERDRAW; mii.dwTypeData = (LPSTR)psd; } else mii.dwTypeData = lParam->ipch->MRUMenuName; // 'Recent'; mii.wID = lParam->idCmdFirst; lParam->idCmdFirst++; mii.fMask = MIIM_TYPE | MIIM_SUBMENU | MIIM_DATA | MIIM_ID; mii.hSubMenu = lParam->Self->hRecentMenu; InsertMenuItemA(hGroupMenu, 0, true, &mii); } else { // no items were attached to the MRU, delete the MRU menu DestroyMenu(lParam->Self->hRecentMenu); lParam->Self->hRecentMenu = 0; } // allocate display info/memory for "Miranda" string mii.cbSize = sizeof(mii); if (bIsVistaPlus) mii.fMask = MIIM_ID | MIIM_DATA | MIIM_FTYPE | MIIM_SUBMENU | MIIM_STRING | MIIM_BITMAP; else mii.fMask = MIIM_ID | MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU; mii.hSubMenu = hGroupMenu; // by default, the menu will have space for icons and checkmarks (on Vista+) && we don't need this RemoveCheckmarkSpace(hGroupMenu); psd = (TMenuDrawInfo*)HeapAlloc(hDllHeap, 0, sizeof(TMenuDrawInfo)); psd->cch = (int)strlen(lParam->ipch->MirandaName); psd->szText = (LPSTR)HeapAlloc(hDllHeap, 0, psd->cch + 1); lstrcpynA(psd->szText, lParam->ipch->MirandaName, sizeof(lParam->ipch->MirandaName) - 1); // there may not be a profile name pg = lParam->ipch->DataPtr; psd->szProfile = NULL; if (pg != NULL && pg->Status == STATUS_PROFILENAME) { psd->szProfile = (LPSTR)HeapAlloc(hDllHeap, 0, pg->cbStrSection); lstrcpyA(psd->szProfile, LPSTR(UINT_PTR(pg) + sizeof(TSlotIPC))); } // owner draw menus need ID's mii.wID = lParam->idCmdFirst; lParam->idCmdFirst++; psd->fTypes = dtEntry; psd->wID = mii.wID; psd->hContact = 0; // get Miranda's icon or bitmap UINT c = lParam->Self->ProtoIconsCount; TSlotProtoIcons *pp = lParam->Self->ProtoIcons; while (c > 0) { c--; if (pp[c].pid == lParam->pid && pp[c].hProto == 0) { // either of these can be 0 psd->hStatusIcon = pp[c].hIcons[0]; mii.hbmpItem = pp[c].hBitmaps[0]; break; } } mii.dwItemData = (UINT_PTR)psd; if (lParam->bOwnerDrawSupported && lParam->bShouldOwnerDraw) { mii.fType = MFT_OWNERDRAW; mii.dwTypeData = (LPSTR)psd; } else { mii.fType = MFT_STRING; mii.dwTypeData = lParam->ipch->MirandaName; mii.cch = sizeof(lParam->ipch->MirandaName) - 1; } // add it all InsertMenuItemA(hBaseMenu, 0, true, &mii); // free the group tree FreeGroupTreeAndEmptyGroups(hGroupMenu, NULL, j.First); }
void BuildContactTree(TGroupNode *group, TEnumData *lParam) { // set up the menu item MENUITEMINFOA mii = { sizeof(mii) }; mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_DATA; // go thru all the contacts TSlotIPC *pct = lParam->ipch->ContactsBegin; while (pct != NULL && pct->cbSize == sizeof(TSlotIPC) && pct->fType == REQUEST_CONTACTS) { if (pct->hGroup != 0) { // at the } of the slot header is the contact's display name // && after a double NULL char there is the group string, which has the full path of the group // this must be tokenised at '\' and we must walk the in memory group tree til we find our group // this is faster than the old version since we only ever walk one or at most two levels of the tree // per tokenised section, and it doesn't matter if two levels use the same group name (which is valid) // as the tokens processed is equatable to depth of the tree char *sz = strtok(LPSTR(UINT_PTR(pct) + sizeof(TSlotIPC) + UINT_PTR(pct->cbStrSection) + 1), "\\"); // restore the root TGroupNode *pg = group; int Depth = 0; while (sz != NULL) { UINT Hash = murmur_hash(sz); // find this node within while (pg != NULL) { // does this node have the right hash and the right depth? if (Hash == pg->Hash && Depth == pg->Depth) break; // each node may have a left pointer going to a sub tree // the path syntax doesn't know if a group is a group at the same level // or a nested one, which means the search node can be anywhere TGroupNode *px = pg->Left; if (px != NULL) { // keep searching this level while (px != NULL) { if (Hash == px->Hash && Depth == px->Depth) { // found the node we're looking for at the next level to pg, px is now pq for next time pg = px; goto grouploop; } px = px->Right; } } pg = pg->Right; } grouploop: Depth++; // process next token sz = strtok(NULL, "\\"); } // tokenisation finished, if pg != NULL the group is found if (pg != NULL) { DecideMenuItemInfo(pct, NULL, mii, lParam); BuildMRU(pct, mii, lParam); InsertMenuItemA(pg->hMenu, 0xFFFFFFFF, true, &mii); pg->dwItems++; } } pct = pct->Next; } }
int ft_match_to_bucket_index(ft_instance_t ft, of_match_t *match) { return (murmur_hash(match, sizeof(*match), FT_HASH_SEED) % ft->config.match_bucket_count); }
int ft_prio_to_bucket_index(ft_instance_t ft, uint16_t priority) { return (murmur_hash(&priority, sizeof(priority), FT_HASH_SEED) % ft->config.prio_bucket_count); }
define_t *search_defines (const char *name, bool search_local) { define_t *result = NULL; char *search_name; list_t *curr_arg_set = arg_list; size_t curr_hash; //make name uppercase if needed for case-insensitivity if (!case_sensitive) search_name = strup (name); else search_name = (char *)name; //first search all the sets of arguments in order if (search_local) { while (curr_arg_set) { result = (define_t *)hash_lookup ((hash_t *)(curr_arg_set->data), search_name); if (result) break; curr_arg_set = curr_arg_set->next; } } //if that doesn't work, look in the global define table if (!result) result = (define_t *)hash_lookup (define_table, search_name); #define MHASH(Z) (murmur_hash(Z, strlen(Z))) curr_hash = murmur_hash (search_name, strlen (search_name)); // Search all SPASM predefined values if (!strcmp(search_name, "__LINE")) { char line_buf[32]; sprintf (line_buf, "%d", line_num); if (result) set_define (result, line_buf, -1, false); } else if (!strcmp(search_name, "__FILE")) { char fn_buf[MAX_PATH * 2] = { 0 }; char *buf_ptr = fn_buf; *buf_ptr++ = '"'; char *fn_ptr = curr_input_file; if (fn_ptr != NULL) { while (*fn_ptr != '\0') { if (*fn_ptr == '\\') { *buf_ptr++ = '\\'; } *buf_ptr++ = *fn_ptr++; } } *buf_ptr++ = '"'; if (result) { set_define(result, fn_buf, -1, false); } } //printf("fail: %s %08x\n", search_name, murmur_hash(search_name, strlen(search_name))); if (!case_sensitive) free (search_name); //make sure any empty arguments get returned as undefined //if (result && result->contents == NULL) result = NULL; return result; }