void OWQ_destroy(struct one_wire_query *owq) { if ( owq == NO_ONE_WIRE_QUERY) { return ; } if ( OWQ_cleanup(owq) & owq_cleanup_buffer ) { owfree(OWQ_buffer(owq)) ; } if ( OWQ_cleanup(owq) & owq_cleanup_rbuffer ) { //owfree(OWQ_read_buffer(owq)) ; } if ( OWQ_cleanup(owq) & owq_cleanup_array ) { owfree(OWQ_array(owq)) ; } if ( OWQ_cleanup(owq) & owq_cleanup_pn ) { FS_ParsedName_destroy(PN(owq)) ; } if ( OWQ_cleanup(owq) & owq_cleanup_owq ) { owfree(owq) ; } else { OWQ_cleanup(owq) = owq_cleanup_none ; } }
static char * unquote_parse( char * raw_string ) { if ( raw_string == NULL ) { return NULL ; } switch ( raw_string[0] ) { case '"': case '\'': if ( raw_string[1] == '\0' ) { owfree( raw_string ) ; return owstrdup("") ; } else { char * unquoted = owstrdup( raw_string+1 ) ; char * unquoted_end = unquoted + strlen(unquoted) -1 ; if ( unquoted_end[0] == raw_string[0] ) { unquoted_end[0] = '\0' ; } owfree( raw_string ) ; return unquoted ; } break ; default: return raw_string ; } }
enum Netlink_Read_Status W1_Process_Response( void (* nrs_callback)( struct netlink_parse * nlp, void * v, const struct parsedname * pn), SEQ_OR_ERROR seq, void * v, const struct parsedname * pn ) { struct connection_in * in = pn->selected_connection ; FILE_DESCRIPTOR_OR_ERROR file_descriptor ; int bus ; if ( seq == SEQ_BAD ) { return nrs_bad_send ; } if ( in == NO_CONNECTION ) { // Send to main netlink rather than a particular bus file_descriptor = FILE_DESCRIPTOR_BAD ; bus = 0 ; } else { // Bus-specifc file_descriptor = in->master.w1.netlink_pipe[fd_pipe_read] ; bus = in->master.w1.id ; } while ( GOOD( W1PipeSelect_timeout(file_descriptor)) ) { struct netlink_parse nlp ; nlp.nlm = NULL ; LEVEL_DEBUG("Loop waiting for netlink piped message"); if ( BAD( Get_and_Parse_Pipe( file_descriptor, &nlp )) ) { LEVEL_DEBUG("Error reading pipe for w1_bus_master%d",bus); // Don't need to free since nlm not set if BAD return nrs_error ; } if ( NL_SEQ(nlp.nlm->nlmsg_seq) != (unsigned int) seq ) { LEVEL_DEBUG("Netlink sequence number out of order"); owfree(nlp.nlm) ; continue ; } if ( nlp.w1m->status != 0) { owfree(nlp.nlm) ; return nrs_nodev ; } if ( nrs_callback == NULL ) { // status message owfree(nlp.nlm) ; return nrs_complete ; } LEVEL_DEBUG("About to call nrs_callback"); nrs_callback( &nlp, v, pn ) ; LEVEL_DEBUG("Called nrs_callback"); owfree(nlp.nlm) ; if ( nlp.cn->ack != 0 ) { if ( nlp.w1m->type == W1_LIST_MASTERS ) { continue ; // look for more data } if ( nlp.w1c && (nlp.w1c->cmd==W1_CMD_SEARCH || nlp.w1c->cmd==W1_CMD_ALARM_SEARCH) ) { continue ; // look for more data } } nrs_callback = NULL ; // now look for status message } return nrs_timeout ; }
void ow_regexec_free( struct ow_regmatch * orm ) { if ( orm != NULL ) { int i ; for ( i = 0 ; i < orm->number + 1 ; ++ i ) { if ( orm->pre[i] != NULL ) { owfree( orm->pre[i] ) ; } } owfree( orm->pre ) ; } }
static char * trim_parse( char * raw_string ) { char * start_position ; char * end_position ; char * return_string ; // trim off preamble whitespace for ( start_position = raw_string ; start_position[0] ; ++ start_position ) { switch ( start_position[0] ) { case ' ': case '\t': // ignore these characters continue ; case '\n': case '\r': // end of the line -- empty string return owfree( raw_string ); return owstrdup("") ; default: break ; } // getting here means a valid character found break ; } // delete old string and use new copy starting at first non whitespace position return_string = owstrdup ( start_position ) ; owfree( raw_string ) ; // trim off for ( end_position = return_string + strlen( return_string ) ; end_position >= return_string ; -- end_position ) { switch ( end_position[0] ) { case ' ': case '\0': case '\r': case '\n': case '\t': // ignorable end char -- make null end_position[0] = '\0' ; continue ; default: // good char break ; } // getting here means a valid character found break ; } return return_string ; }
/* allocate buffer but free unless able to read and parse nlm fully */ static GOOD_OR_BAD Get_and_Parse_Pipe( FILE_DESCRIPTOR_OR_ERROR file_descriptor, struct netlink_parse * nlp ) { struct nlmsghdr peek_nlm ; struct nlmsghdr * nlm ; size_t payload_length ; // first read start of message to get length and details if ( read( file_descriptor, &peek_nlm, W1_NLM_LENGTH ) != W1_NLM_LENGTH ) { ERROR_DEBUG("Pipe (w1) read header error"); return gbBAD ; } LEVEL_DEBUG("Pipe header: len=%u type=%u seq=%u|%u pid=%u ",peek_nlm.nlmsg_len,peek_nlm.nlmsg_type,NL_BUS(peek_nlm.nlmsg_seq),NL_SEQ(peek_nlm.nlmsg_seq),peek_nlm.nlmsg_pid); // allocate space nlm = owmalloc( peek_nlm.nlmsg_len ) ; nlp->nlm = nlm ; if ( nlm == NULL ) { LEVEL_DEBUG("Netlink (w1) Cannot allocate %d byte buffer for data", peek_nlm.nlmsg_len ) ; return gbBAD ; } memcpy( nlm, &peek_nlm, W1_NLM_LENGTH ) ; // copy header // read rest of packet if ( peek_nlm.nlmsg_len <= W1_NLM_LENGTH ) { owfree(nlm) ; LEVEL_DEBUG( "W1 packet error. Length is too short." ) ; return gbBAD ; } payload_length = peek_nlm.nlmsg_len - W1_NLM_LENGTH ; if ( read( file_descriptor, NLMSG_DATA(nlm), payload_length ) != (ssize_t) payload_length ) { owfree(nlm) ; nlp->nlm = NULL ; ERROR_DEBUG("Pipe (w1) read payload error"); return gbBAD ; } if ( BAD( Netlink_Parse_Buffer( nlp )) ) { LEVEL_DEBUG("Buffer parsing error"); owfree(nlm) ; nlp->nlm = NULL ; return gbBAD ; } // Good, the receiving routine should owfree buffer LEVEL_DEBUG("Pipe read --------------------"); Netlink_Parse_Show( nlp ) ; return gbGOOD ; }
// Delete a serial number's alias // Safe to call if no alias exists // Also deletes from linked alias_sn file void Cache_Del_Alias(const BYTE * sn) { ASCII * alias_name ; struct tree_node *tn; size_t size ; alias_name = Cache_Get_Alias( sn ) ; if ( alias_name == NULL ) { // doesn't exist // (or a memory error -- unlikely) return ; } LEVEL_DEBUG("Deleting alias %s from "SNformat, alias_name, SNvar(sn)) ; size = strlen( alias_name ) ; tn = (struct tree_node *) owmalloc(sizeof(struct tree_node) + size + 1 ); if ( tn != NULL ) { tn->expires = NOW_TIME; tn->dsize = size; memcpy((ASCII *)TREE_DATA(tn), alias_name, size+1); // includes NULL LoadTK( sn, Alias_Marker, 0, tn ) ; Del_Stat(&cache_pst, Cache_Del_Persistent(tn)); Cache_Del_Alias_SN( alias_name ) ; } owfree( alias_name ) ; }
/* Callback function to FS_dir */ static void ShowDirCallback(void *v, const struct parsedname *pn_entry) { /* uncached tag */ /* device name */ /* Have to allocate all buffers to make it work for Coldfire */ FILE *out = v; const char *nam; const char *typ; char * escaped_path = httpescape( pn_entry->path ) ; if (IsDir(pn_entry)) { nam = FS_DirName(pn_entry); typ = name_directory; } else { nam = pn_entry->selected_device->readable_name; typ = name_onewire_chip; } fprintf(out, "<TR><TD><A HREF='%s'><CODE><B><BIG>%s</BIG></B></CODE></A></TD><TD>%s</TD><TD>%s</TD></TR>", escaped_path==NULL ? pn_entry->path : escaped_path, FS_DirName(pn_entry), nam, typ); if ( escaped_path ) { owfree( escaped_path ) ; } }
static void Cache_Add_Alias_Persistent(struct alias_tree_node *atn) { struct tree_opaque *opaque; PERSISTENT_WLOCK; opaque = tsearch(atn, &cache.persistent_alias_tree, alias_tree_compare) ; if ( opaque != NULL ) { if ( (void *) atn != (void *) (opaque->key) ) { owfree(opaque->key); opaque->key = (void *) atn; } } else { // nothing found or added?!? free our memory segment owfree(atn); } PERSISTENT_WUNLOCK; }
void FreeOutAll(void) { struct connection_out *next = Outbound_Control.head; struct connection_out *now; Outbound_Control.head = NULL; Outbound_Control.active = 0; while (next) { now = next; next = now->next; LEVEL_DEBUG("Freeing outbound %s #%d",now->zero.name,now->index); SAFEFREE(now->zero.name) ; SAFEFREE(now->zero.type) ; SAFEFREE(now->zero.domain) ; SAFEFREE(now->name) ; SAFEFREE(now->host) ; SAFEFREE(now->service) ; if (now->ai) { freeaddrinfo(now->ai); now->ai = NULL; } #if OW_ZERO if (libdnssd != NULL) { if (now->sref0) { DNSServiceRefDeallocate(now->sref0); } if (now->sref1) { DNSServiceRefDeallocate(now->sref1); } } #endif owfree(now); } }
/* Parse a path/file combination */ ZERO_OR_ERROR FS_ParsedNamePlus(const char *path, const char *file, struct parsedname *pn) { ZERO_OR_ERROR ret = 0; char *fullpath; if (path == NO_PATH) { path = "" ; } if (file == NULL) { file = "" ; } fullpath = owmalloc(strlen(file) + strlen(path) + 2); if (fullpath == NO_PATH) { RETURN_CODE_RETURN( 79 ) ; // unable to allocate memory } strcpy(fullpath, path); if (fullpath[strlen(fullpath) - 1] != '/') { strcat(fullpath, "/"); } strcat(fullpath, file); //printf("PARSENAMEPLUS path=%s pre\n",fullpath) ; ret = FS_ParsedName(fullpath, pn); //printf("PARSENAMEPLUS path=%s post\n",fullpath) ; owfree(fullpath); //printf("PARSENAMEPLUS free\n") ; return ret; }
static void AddPropertyToTree( char * s_property, char * s_family, enum ft_format s_format, size_t s_array, enum ag_combined s_combined, enum ag_index s_index_type, size_t s_length, enum fc_change s_change, char * s_read, char * s_write, char * s_data, char * s_other, enum external_type et ) { struct property_node * n ; struct { struct property_node * key ; char other[0] ; } * opaque ; NonNull( s_property ) NonNull( s_family ) NonNull( s_read ) NonNull( s_write ) NonNull( s_data ) NonNull( s_other ) n = create_property_node( s_property, s_family, s_format, s_array, s_combined, s_index_type, s_length, s_change, s_read, s_write, s_data, s_other, et ) ; opaque = tsearch( (void *) n, &property_tree, property_compare ) ; if ( opaque->key != n ) { // already exists LEVEL_DEBUG("Duplicate property entry: %s,%s,%s,%s,%s,%s",s_property,s_family,s_read,s_write,s_data,s_other); owfree( n ) ; } else { LEVEL_DEBUG("New property entry: %s,%s,%s,%s,%s,%s",s_property,s_family,s_read,s_write,s_data,s_other); } }
/* return 0 if good, 1 if not */ static GOOD_OR_BAD Cache_Add_Common(struct tree_node *tn) { struct tree_opaque *opaque; enum { no_add, yes_add, just_update } state = no_add; node_show(tn); LEVEL_DEBUG("Add to cache sn " SNformat " pointer=%p index=%d size=%d", SNvar(tn->tk.sn), tn->tk.p, tn->tk.extension, tn->dsize); CACHE_WLOCK; if (cache.time_to_kill < NOW_TIME) { // old database has timed out FlipTree() ; } if (Globals.cache_size && (cache.old_ram_size + cache.new_ram_size > Globals.cache_size)) { // failed size test owfree(tn); } else if ((opaque = tsearch(tn, &cache.temporary_tree_new, tree_compare))) { //printf("Cache_Add_Common to %p\n",opaque); if (tn != opaque->key) { cache.new_ram_size += sizeof(tn) - sizeof(opaque->key); owfree(opaque->key); opaque->key = tn; state = just_update; } else { state = yes_add; cache.new_ram_size += sizeof(tn); } } else { // nothing found or added?!? free our memory segment owfree(tn); } CACHE_WUNLOCK; /* Added or updated, update statistics */ switch (state) { case yes_add: // add new entry STATLOCK; AVERAGE_IN(&new_avg); ++cache_adds; /* statistics */ STATUNLOCK; return gbGOOD; case just_update: // update the time mark and data STATLOCK; AVERAGE_MARK(&new_avg); ++cache_adds; /* statistics */ STATUNLOCK; return gbGOOD; default: // unable to add return gbBAD; } }
/* * name * family * description * */ void AddSensor( char * input_string ) { char * s_name = NULL ; char * s_family = NULL ; char * s_description = NULL ; char * s_data = NULL ; char * start_pointer = input_string ; if ( input_string == NULL ) { return ; } if ( ! Globals.allow_external ) { LEVEL_DEBUG("External prgroams not supported by %s",Globals.argv[0]) ; return ; } // name GetQuotedString( name ) ; // family GetQuotedString( family ) ; // description GetQuotedString( description ) ; // data GetQuotedString( data ) ; if ( strlen(s_name) > 0 && strlen(s_family) > 0 ) { // Actually add AddFamilyToTree( s_family ) ; AddSensorToTree( s_name, s_family, s_description, s_data ) ; create_just_print( "family", s_family, s_family ) ; create_just_print( "type", s_family, "external" ) ; } // Clean up owfree( s_name ); owfree( s_family ) ; owfree( s_description ) ; owfree( s_data ) ; }
/* All ow library closeup */ void PIDstop(void) { if (pid_created && pid_file) { if (unlink(pid_file)) { ERROR_CONNECT("Cannot remove PID file: %s", pid_file); } owfree(pid_file); pid_file = NULL; } }
static void Browse_Struct_Destroy(struct BrowseStruct *browse_struct) { if ( browse_struct == NULL ) { return; } SAFEFREE(browse_struct->name ) ; SAFEFREE(browse_struct->type ) ; SAFEFREE(browse_struct->domain) ; owfree(browse_struct); }
/* look in persistent alias->sn tree */ static void Cache_Del_Alias_Persistent( struct alias_tree_node * atn) { struct tree_opaque *opaque; struct alias_tree_node *atn_found = NULL; PERSISTENT_RLOCK; opaque = tfind(atn, &cache.persistent_alias_tree, alias_tree_compare) ; if ( opaque != NULL ) { atn_found = (struct alias_tree_node *) (opaque->key); } PERSISTENT_RUNLOCK; owfree(atn_found) ; }
/* return 0 if good, 1 if not */ static GOOD_OR_BAD Cache_Add_Persistent(struct tree_node *tn) { struct tree_opaque *opaque; enum { no_add, yes_add, just_update } state = no_add; LEVEL_DEBUG("Adding data to permanent store"); PERSISTENT_WLOCK; opaque = tsearch(tn, &cache.persistent_tree, tree_compare) ; if ( opaque != NULL ) { //printf("CACHE ADD pointer=%p, key=%p\n",tn,opaque->key); if (tn != opaque->key) { owfree(opaque->key); opaque->key = tn; state = just_update; } else { state = yes_add; } } else { // nothing found or added?!? free our memory segment owfree(tn); } PERSISTENT_WUNLOCK; switch (state) { case yes_add: STATLOCK; AVERAGE_IN(&store_avg); STATUNLOCK; return gbGOOD; case just_update: STATLOCK; AVERAGE_MARK(&store_avg); STATUNLOCK; return gbGOOD; default: return gbBAD; } }
static void create_subdirs( char * s_prop, char * s_family ) { char * slash ; char * subdir = owstrdup( s_prop ) ; if ( subdir == NULL ) { return ; } while ( (slash = strrchr( subdir, '/' )) != NULL ) { slash[0] = '\0' ; AddPropertyToTree( subdir, s_family, ft_subdir, 1, ag_separate, ag_numbers, 0, fc_subdir, "", "", "", "", et_none ) ; } owfree(subdir) ; }
/* retire the cache (flip) if too old, and start a new one (keep the old one for a while) */ static void Cache_Add_Alias_Common(struct alias_tree_node *atn) { struct tree_opaque *opaque; CACHE_WLOCK; if (cache.time_to_kill < NOW_TIME) { // old database has timed out FlipTree() ; } if (Globals.cache_size && (cache.old_ram_size + cache.new_ram_size > Globals.cache_size)) { // failed size test owfree(atn); } else if ((opaque = tsearch(atn, &cache.temporary_alias_tree_new, alias_tree_compare))) { if ( (void *)atn != (void *) (opaque->key) ) { cache.new_ram_size += sizeof(atn) - sizeof(opaque->key); owfree(opaque->key); opaque->key = (void *) atn; } else { cache.new_ram_size += sizeof(atn); } } else { // nothing found or added?!? free our memory segment owfree(atn); } CACHE_WUNLOCK; }
static void AddSensorToTree( char * s_name, char * s_family, char * s_description, char * s_data ) { struct sensor_node * n = create_sensor_node( s_name, s_family, s_description, s_data ) ; struct { struct sensor_node * key ; char other[0] ; } * opaque = tsearch( (void *) n, &sensor_tree, sensor_compare ) ; if ( opaque->key != n ) { // already exists LEVEL_DEBUG("Duplicate sensor entry: %s,%s,%s,%s",s_name,s_family,s_description,s_data); owfree( n ) ; } else { LEVEL_DEBUG("New sensor entry: %s,%s,%s,%s",s_name,s_family,s_description,s_data); } }
static void AddFamilyToTree( char * s_family ) { struct family_node * n = create_family_node( s_family ) ; struct { struct family_node * key ; char other[0] ; } * opaque = tsearch( (void *) n, &family_tree, family_compare ) ; if ( opaque->key != n ) { // already exists LEVEL_DEBUG("Duplicate family entry: %s",s_family); owfree( n ) ; } else { ARG_External(NULL); LEVEL_DEBUG("New family entry: %s",s_family); } }
void PIDstart(void) { /* store the PID */ pid_t pid_num = getpid(); if (pid_file) { FILE *pid = fopen(pid_file, "w+"); if (pid == NULL) { ERROR_CONNECT("Cannot open PID file: %s", pid_file); owfree(pid_file); pid_file = NULL; } else { fprintf(pid, "%lu", (unsigned long int) pid_num); fclose(pid); pid_created = 1; } } }
/* look in persistent alias->sn tree */ static enum cache_task_return Cache_Get_Alias_Persistent( BYTE * sn, struct alias_tree_node * atn) { struct tree_opaque *opaque; GOOD_OR_BAD ret = gbBAD ; PERSISTENT_RLOCK; opaque = tfind(atn, &cache.persistent_alias_tree, alias_tree_compare) ; if ( opaque != NULL ) { memcpy( sn, ((struct alias_tree_node *)(opaque->key))->sn, SERIAL_NUMBER_SIZE ) ; LEVEL_DEBUG("Lookup of %s gives "SNformat, CONST_ALIAS_TREE_DATA(atn), SNvar(sn) ) ; ret = gbGOOD ; } else { LEVEL_DEBUG("Lookup of %s unsuccessful",CONST_ALIAS_TREE_DATA(atn)) ; } PERSISTENT_RUNLOCK; owfree(atn) ; return ret; }
/* Misnamed. Actually all directory */ void ShowDir(FILE * out, struct parsedname * pn) { int b = Backup(pn->path); // length of string to get to higher level if (pn->state & ePS_text) { ShowDirText(out, pn); return; } else if (pn->state & ePS_json) { ShowDirJson(out, pn); return; } HTTPstart(out, "200 OK", ct_html); HTTPtitle(out, "Directory"); if (NotRealDir(pn)) { /* return whole path since tree structure could be much deeper now */ /* first / is stripped off */ HTTPheader(out, &pn->path[1]); } else if (pn->state) { /* return whole path since tree structure could be much deeper now */ /* first / is stripped off */ HTTPheader(out, &pn->path[1]); } else { HTTPheader(out, "directory"); } fprintf(out, "<TABLE BGCOLOR=\"#DDDDDD\" BORDER=1>"); if (b != 1) { char * escaped_path = httpescape( pn->path ) ; fprintf(out, "<TR><TD><A HREF='%.*s'><CODE><B><BIG>up</BIG></B></CODE></A></TD><TD>higher level</TD><TD>directory</TD></TR>", b, escaped_path==NULL ? pn->path : escaped_path ); if ( escaped_path ) { owfree( escaped_path ) ; } } else { fprintf(out, "<TR><TD><A HREF='/'><CODE><B><BIG>top</BIG></B></CODE></A></TD><TD>highest level</TD><TD>directory</TD></TR>"); } FS_dir(ShowDirCallback, out, pn); fprintf(out, "</TABLE>"); HTTPfoot(out); }
ZERO_OR_ERROR FS_r_external( struct one_wire_query * owq ) { ZERO_OR_ERROR zoe = -ENOENT ; // default char * device_property = owstrdup( PN(owq)->device_name ) ; // copy of device/property part of path if ( device_property != NULL ) { char * property = device_property ; char * device = strsep( &property, "/" ) ; // separate out property char * extension = property ; if ( property != NULL ) { // pare off extension property = strsep( &extension, "." ) ; } zoe = OW_trees_for_read( device, property, owq ) ; owfree( device_property ) ; // clean up } return zoe ; }
// Unlock the device void DeviceLockRelease(struct parsedname *pn) { if (pn->lock) { // this is the stored pointer to the device in the appropriate device tree // Free the device _MUTEX_UNLOCK(pn->lock->lock); /* Serg: This coredump on his 64-bit server */ // Now mark our disinterest in the device tree (and possibly reap the node)) DEVTREE_LOCK(pn); --pn->lock->users; // remove our interest if (pn->lock->users == 0) { // Nobody's interested! tdelete(pn->lock, &(pn->selected_connection->dev_db), dev_compare); /* Serg: Address 0x5A0D750 is 0 bytes inside a block of size 32 free'd */ _MUTEX_DESTROY(pn->lock->lock); owfree(pn->lock); } DEVTREE_UNLOCK(pn); pn->lock = NULL; } }
/* Add new license into device */ ZERO_OR_ERROR FS_w_PBM_activationcode(struct one_wire_query *owq) { struct connection_in * in = PN(owq)->selected_connection ; size_t size = OWQ_size(owq) ; BYTE * cmd_string = owmalloc( size+5 ) ; if ( cmd_string == NULL ) { return -ENOMEM ; } cmd_string[0] = 'k'; cmd_string[1] = 'a'; memcpy(&cmd_string[2], OWQ_buffer(owq), size ) ; cmd_string[size+2] = '\r'; // Writes from and to cmd_string PBM_SendCMD(cmd_string, size + 3, cmd_string, size + 3, in, 500); owfree(cmd_string) ; return 0; }
/* Alias name must be a null-terminated string */ INDEX_OR_ERROR Cache_Get_Alias_Bus(const ASCII * alias_name) { // allocate space for the node and data size_t datasize = strlen(alias_name) ; struct alias_tree_node *atn = (struct alias_tree_node *) owmalloc(sizeof(struct alias_tree_node) + datasize + 1); if (atn==NULL) { return INDEX_BAD ; } if (datasize==0) { owfree(atn) ; return INDEX_BAD ; } // populate the node structure with data atn->size = datasize; memcpy( ALIAS_TREE_DATA(atn), alias_name, datasize+1 ) ; return Cache_Get_Alias_Common( atn ) ; }
// Add a reg comp to tree if doesn't already exist static enum e_regcomp_test regcomp_test( regex_t * reg ) { struct s_regex * pnode = owmalloc( sizeof( struct s_regex ) ) ; struct s_regex * found ; void * result ; if ( pnode == NULL ) { LEVEL_DEBUG("memory exhuasted") ; return e_regcomp_error ; } pnode->reg = reg ; result = tsearch( (void *) pnode, ®ex_tree, reg_compare ) ; found = *(struct s_regex **) result ; if ( found == pnode ) { // new entry return e_regcomp_new ; } // existing entry owfree( pnode ) ; return e_regcomp_exists ; }