void list_keys_in_hash( struct hash * current, struct list * result, char * prefix ) { int siglen = strlen(current->sigstr); int prefixlen = strlen(prefix); char * path = malloc( ( prefixlen + siglen + 2 ) * sizeof(char) ); // Extra child char. strcpy( path, prefix ); strcat( path, current->sigstr ); path[ prefixlen + siglen + 1 ] = path[ prefixlen + siglen ] = '\0'; char * chars_in_child = chars_in( current->child, 0, 0 ); char child_char = '\0'; struct hash * child_hash = NULL; int i = current->num_children; while ( i-- ) { // Recurse through all children. child_char = chars_in_child[i]; if ( child_char == '\0' ) { // No keys to recurse through. continue; } path[ prefixlen + siglen ] = child_char; // Get the path prefix for this child. child_hash = charhashlookup( current->child, child_char )->data; list_keys_in_hash( child_hash, result, path ); } // Decide if the path to this node needs to be included in the list of keys. if ( current->data ) { path[ prefixlen + siglen ] = '\0'; append_to_list( result, (void *) path ); } else { free(path); } free(chars_in_child); return; }
struct hash_search_state hash_search( struct hash * root, char * key ) { struct hash * parent = NULL; struct hash * node = root; struct hash * child; char * str = key; int num_matched; char config; char parent_choice = '\0'; char next_char = '\0'; struct charhash * child_charhash; while ( node ) { num_matched = longest_common_prefix( str, node->sigstr, &config ); if ( config != 'c' ) { break; } next_char = *( str + num_matched ); if ( !( child_charhash = charhashlookup( node->child, next_char ) ) ) { break; // No child corresponding to this character. } str += ( num_matched + 1 ); parent = node; node = child_charhash->data; parent_choice = next_char; } struct hash_search_state search_state = { parent, node, parent_choice, str, num_matched, config }; return search_state; }
void destroy_hash( struct hash * current ) { char * child_chars = chars_in( current->child, 0, 0 ); int i = current->num_children; struct hash * child_hash; while ( i-- ) { child_hash = charhashlookup( current->child, child_chars[i] )->data; destroy_hash( child_hash ); } free(child_chars); free(current->sigstr); destroy_charhash(current->child); return; }
void add_to_trie( struct trie_node * trie, char * path, char * accepting_type ) { struct trie_node * current_node = trie; struct trie_node * next_node = NULL; char c; int i; int path_len = strlen( path ); for ( i = 0; i < path_len; i++ ) { c = path[i]; struct charhash * looked_up = charhashlookup( current_node->child, c ); if ( ! looked_up ) { next_node = new_trie_node(); add_to_charhash( current_node->child, c, (void *) next_node ); } else { next_node = looked_up->data; } if ( i == path_len - 1 ) { // Last char gets accepting type. next_node->accepting_type = accepting_type; } current_node = next_node; } return; }
void absorb_single_hash_child( struct hash_search_state search_state ) { // Figure out what character the single child is listed under. char * decision_char = chars_in( search_state.node->child, '\0', 0 ); // 1-char string struct hash * child = charhashlookup( search_state.node->child, *decision_char )->data; // Concatenate the decision_char and the child's sigstr onto search_state node's sigstr. int extension_length = strlen(child->sigstr); int sigstr_length = strlen(search_state.node->sigstr); char * new_sigstr = malloc( ( sigstr_length + 1 + extension_length ) * sizeof(char) ); strcpy( new_sigstr, search_state.node->sigstr ); strcat( new_sigstr, decision_char ); strcat( new_sigstr, child->sigstr ); free(search_state.node->sigstr); search_state.node->sigstr = new_sigstr; // Copy the child node's info. destroy_charhash(search_state.node->child); search_state.node->child = child->child; search_state.node->data = child->data; search_state.node->num_children = child->num_children; free(child); return; }
struct token * get_next_token( char * string, int start ) { struct token * next_token = new_token(); if ( string[start] == '\0' ) { next_token->type = "end"; next_token->first = start; next_token->last = start; return next_token; } struct trie_node * current_node = TRIE; struct charhash * next_node = NULL; int i = start; char input_char; while ( input_char = string[i] ) { // Loop characters of string. if ( next_node = charhashlookup( current_node->child, input_char ) ) { current_node = next_node->data; i = i + 1; } else { // No transition for this character. if ( current_node->accepting_type ) { i = i - 1; // "Push" this character back on the input. } break; } } // End characters of string loop. if ( input_char == '\0' ) { i = i - 1; } next_token->first = start; next_token->last = i; next_token->type = current_node->accepting_type; if ( ! current_node->accepting_type ) { next_token->type = "text"; } return next_token; }
char * hashtreeprint( struct hash * current, char * prefixstr) { char * nextprefixstr; int num_children, childinfolen, childformatchars, treeformatchars; struct hash * nexthash; // Get the info string for the current node. char * currentinfostr = hashinfo( current, prefixstr); // Get a pointer to an array containing the characters in the child charhash. char * c = chars_in( current->child, 0, 0 ); // Record the number of children. num_children = strlen(c); // Allocate an array of strings ( one for each child ). char ** childstrings = malloc( num_children * sizeof(char*) ); if( ! childstrings ) { return("Out of memory!"); } // Go down each branch, creating childstrings. int i; childinfolen = 0; nextprefixstr = malloc( 2 * sizeof(char) ); if( ! nextprefixstr ) { return("Out of memory!"); } childformatchars = 9; // For the <td></td>. nextprefixstr[1] = '\0'; // Only the first character will change. for( i = 0; i < num_children; i++ ) { // Loop children. nexthash = ( struct hash * ) charhashlookup( current->child, c[i] )->data; nextprefixstr[0] = c[i]; // Recurse to the next hash. childstrings[i] = hashtreeprint( nexthash, nextprefixstr ); // Increment the info length. childinfolen += ( strlen(childstrings[i]) + childformatchars ); } // End children loop. // Prepare child info string. char * childinfostr = malloc((childinfolen + 1) * sizeof(char)); if( ! childinfostr ) { return("Out of memory!"); } *childinfostr = '\0'; // Prepare to strcat onto this. // Surround each child with <td> tags. for( i = 0; i < num_children; i++ ) { // Loop children again. strcat( childinfostr, "<td>" ); strcat( childinfostr, childstrings[i] ); strcat( childinfostr, "</td>" ); } // End children again loop. // Allocate a result string, with correct length. treeformatchars = 149; // All table formatting. char * resultstr = malloc( (strlen(childinfostr) + strlen(currentinfostr) + treeformatchars + 1) * sizeof(char) ); if( ! resultstr ) { return "Out of memory!"; } // Now fill out the template. *resultstr = '\0'; // For strcat. strcat(resultstr, "<table><tr align=center><td>" ); strcat(resultstr, currentinfostr ); strcat(resultstr, "</td></tr><tr align=center><td>" ); strcat(resultstr, "<table cellpadding=5><tr align=center valign=top>" ); strcat(resultstr, childinfostr ); strcat(resultstr, "</tr></table></td></tr></table>" ); // Free up resources allocated. free(childinfostr); free(nextprefixstr); free(childstrings); return resultstr; } // End function hashtreeprint.