void SG_random__select_2_random_rbtree_nodes(SG_context * pCtx, SG_rbtree * pRbtree, const char ** ppKey1, void ** ppAssocData1, const char ** ppKey2, void ** ppAssocData2) { SG_uint32 count, r1, r2, i; SG_rbtree_iterator * p = NULL; SG_bool ok = SG_FALSE; const char * pKey = NULL; void * pAssocData = NULL; const char * pKey1 = NULL; void * pAssocData1 = NULL; const char * pKey2 = NULL; void * pAssocData2 = NULL; SG_NULLARGCHECK_RETURN(pRbtree); SG_ERR_CHECK( SG_rbtree__count(pCtx, pRbtree, &count) ); SG_ARGCHECK(count>=2, pRbtree); r1 = SG_random_uint32(count); r2 = (r1+1+SG_random_uint32(count-1))%count; SG_ERR_CHECK( SG_rbtree__iterator__first(pCtx, &p, pRbtree, &ok, &pKey, &pAssocData) ); for(i=0;i<=r1||i<=r2;++i) { SG_ASSERT(ok); if(i==r1) { pKey1 = pKey; pAssocData1 = pAssocData; } else if(i==r2) { pKey2 = pKey; pAssocData2 = pAssocData; } SG_ERR_CHECK( SG_rbtree__iterator__next(pCtx, p, &ok, &pKey, &pAssocData) ); } SG_RBTREE_ITERATOR_NULLFREE(pCtx, p); if(ppKey1!=NULL) *ppKey1 = pKey1; if(ppAssocData1!=NULL) *ppAssocData1 = pAssocData1; if(ppKey2!=NULL) *ppKey2 = pKey2; if(ppAssocData2!=NULL) *ppAssocData2 = pAssocData2; return; fail: SG_RBTREE_ITERATOR_NULLFREE(pCtx, p); }
void SG_random__select_random_rbtree_node(SG_context * pCtx, SG_rbtree * pRbtree, const char ** ppKey, void ** ppAssocData) { SG_uint32 count, i; SG_rbtree_iterator * p = NULL; SG_bool ok; const char * pKey; void * pAssocData; SG_NULLARGCHECK_RETURN(pRbtree); SG_ERR_CHECK( SG_rbtree__count(pCtx, pRbtree, &count) ); SG_ARGCHECK(count!=0, pRbtree); i = SG_random_uint32(count); SG_ERR_CHECK( SG_rbtree__iterator__first(pCtx, &p, pRbtree, &ok, &pKey, &pAssocData) ); SG_ASSERT(ok); while(i>0) { --i; SG_ERR_CHECK( SG_rbtree__iterator__next(pCtx, p, &ok, &pKey, &pAssocData) ); SG_ASSERT(ok); } SG_RBTREE_ITERATOR_NULLFREE(pCtx, p); if(ppKey!=NULL) *ppKey = pKey; if(ppAssocData!=NULL) *ppAssocData = pAssocData; return; fail: SG_RBTREE_ITERATOR_NULLFREE(pCtx, p); }
void SG_validate__sanitize( SG_context* pCtx, const char* szValue, SG_uint32 uMin, SG_uint32 uMax, const char* szInvalids, SG_uint32 uFixFlags, const char* szReplace, const char* szAdd, SG_string** ppSanitized ) { SG_string* sSanitized = NULL; SG_NULLARGCHECK(ppSanitized); // treat NULL replacement string as empty if (szReplace == NULL) { szReplace = ""; } // allocate our result string SG_ERR_CHECK( SG_STRING__ALLOC__SZ(pCtx, &sSanitized, szValue) ); // if we need to sanitize bad characters, do that // Note: We do this first because sanitizing characters might change the // length of the string and affect the min/max length check. if (uFixFlags & SG_VALIDATE__RESULT__INVALID_CHARACTER) { SG_ERR_CHECK( _replace_chars_with_string(pCtx, sSanitized, szInvalids, szReplace) ); } if (uFixFlags & SG_VALIDATE__RESULT__CONTROL_CHARACTER) { SG_ERR_CHECK( _replace_chars_with_string(pCtx, sSanitized, SG_VALIDATE__CHARS__CONTROL, szReplace) ); } // if we need to lengthen the string, do that // Note: We do this prior to checking the max length because we have more fine // grained control over reducing length than we do over expanding it. We // can remove individual characters, but only add characters in blocks of // strlen(szAdd). If uMin and uMax are close to each other, then adding // a single szAdd might take us over uMax. If that happens, we want to // be able to trim that back down to uMax afterward. if (uFixFlags & SG_VALIDATE__RESULT__TOO_SHORT) { SG_uint32 uSanitized = 0u; SG_uint32 uAdd = 0u; SG_ARGCHECK(szAdd != NULL && SG_STRLEN(szAdd) > 0u, szAdd); // get the length of both strings SG_ERR_CHECK( SG_utf8__length_in_characters__sz(pCtx, SG_string__sz(sSanitized), &uSanitized) ); SG_ERR_CHECK( SG_utf8__length_in_characters__sz(pCtx, szAdd, &uAdd) ); // keep adding until the sanitized string is long enough while (uSanitized < uMin) { SG_ERR_CHECK( SG_string__append__sz(pCtx, sSanitized, szAdd) ); uSanitized += uAdd; } } // if we need to shorten the string, do that if (uFixFlags & SG_VALIDATE__RESULT__TOO_LONG) { SG_ERR_CHECK( _truncate_string(pCtx, sSanitized, uMax) ); } // return the sanitized result *ppSanitized = sSanitized; sSanitized = NULL; fail: SG_STRING_NULLFREE(pCtx, sSanitized); return; }
void SG_validate__check( SG_context* pCtx, const char* szValue, SG_uint32 uMin, SG_uint32 uMax, const char* szInvalids, SG_bool bControls, SG_uint32* pResult ) { SG_uint32 uResult = 0u; SG_uint32 uLength = 0u; SG_ARGCHECK(uMin <= uMax, uMin|uMax); SG_NULLARGCHECK(pResult); // treat NULL as an empty string if (szValue == NULL) { szValue = ""; } // validate minimum length uLength = SG_STRLEN(szValue); if (uLength < uMin) { uResult |= SG_VALIDATE__RESULT__TOO_SHORT; } // validate maximum length if (uLength > uMax) { uResult |= SG_VALIDATE__RESULT__TOO_LONG; } // validate specified characters if (szInvalids != NULL) { SG_bool bShares = SG_FALSE; SG_ERR_CHECK( SG_utf8__shares_characters(pCtx, szValue, szInvalids, &bShares) ); if (bShares != SG_FALSE) { uResult |= SG_VALIDATE__RESULT__INVALID_CHARACTER; } } // validate control characters if (bControls != SG_FALSE) { SG_bool bShares = SG_FALSE; SG_ERR_CHECK( SG_utf8__shares_characters(pCtx, szValue, SG_VALIDATE__CHARS__CONTROL, &bShares) ); if (bShares != SG_FALSE) { uResult |= SG_VALIDATE__RESULT__CONTROL_CHARACTER; } } *pResult = uResult; fail: return; }
void SG_dagquery__highest_revno_common_ancestor( SG_context * pCtx, SG_repo * pRepo, SG_uint64 dagnum, const SG_stringarray * pInputNodeHids, char ** ppOutputNodeHid ) { const char * const * paszInputNodeHids = NULL; SG_uint32 countInputNodes = 0; SG_repo_fetch_dagnodes_handle * pDagnodeFetcher = NULL; _hrca_work_queue_t workQueue = {NULL, 0, 0, NULL}; SG_uint32 i; SG_dagnode * pDagnode = NULL; const char * pszHidRef = NULL; SG_bitvector * pIsAncestorOf = NULL; SG_uint32 countIsAncestorOf = 0; SG_ASSERT(pCtx!=NULL); SG_NULLARGCHECK(pRepo); SG_NULLARGCHECK(pInputNodeHids); SG_ERR_CHECK( SG_stringarray__sz_array_and_count(pCtx, pInputNodeHids, &paszInputNodeHids, &countInputNodes) ); SG_ARGCHECK(countInputNodes>0, pInputNodeHids); SG_NULLARGCHECK(ppOutputNodeHid); SG_ERR_CHECK( SG_repo__fetch_dagnodes__begin(pCtx, pRepo, dagnum, &pDagnodeFetcher) ); SG_ERR_CHECK( SG_allocN(pCtx, _HRCA_WORK_QUEUE_INIT_LENGTH, workQueue.p) ); workQueue.allocatedLength = _HRCA_WORK_QUEUE_INIT_LENGTH; SG_ERR_CHECK( SG_RBTREE__ALLOC(pCtx, &workQueue.pRevnoCache) ); SG_ERR_CHECK( SG_BITVECTOR__ALLOC(pCtx, &pIsAncestorOf, countInputNodes) ); for(i=0; i<countInputNodes; ++i) { SG_ERR_CHECK( SG_bitvector__zero(pCtx, pIsAncestorOf) ); SG_ERR_CHECK( SG_bitvector__set_bit(pCtx, pIsAncestorOf, i, SG_TRUE) ); SG_ERR_CHECK( _hrca_work_queue__insert(pCtx, &workQueue, paszInputNodeHids[i], pRepo, pDagnodeFetcher, pIsAncestorOf) ); } SG_BITVECTOR_NULLFREE(pCtx, pIsAncestorOf); SG_ERR_CHECK( _hrca_work_queue__pop(pCtx, &workQueue, &pDagnode, &pszHidRef, &pIsAncestorOf) ); SG_ERR_CHECK( SG_bitvector__count_set_bits(pCtx, pIsAncestorOf, &countIsAncestorOf) ); while(countIsAncestorOf < countInputNodes) { SG_uint32 count_parents = 0; const char** parents = NULL; SG_ERR_CHECK( SG_dagnode__get_parents__ref(pCtx, pDagnode, &count_parents, &parents) ); for(i=0; i<count_parents; ++i) SG_ERR_CHECK( _hrca_work_queue__insert(pCtx, &workQueue, parents[i], pRepo, pDagnodeFetcher, pIsAncestorOf) ); SG_DAGNODE_NULLFREE(pCtx, pDagnode); SG_BITVECTOR_NULLFREE(pCtx, pIsAncestorOf); SG_ERR_CHECK( _hrca_work_queue__pop(pCtx, &workQueue, &pDagnode, &pszHidRef, &pIsAncestorOf) ); SG_ERR_CHECK( SG_bitvector__count_set_bits(pCtx, pIsAncestorOf, &countIsAncestorOf) ); } SG_ERR_CHECK( SG_strdup(pCtx, pszHidRef, ppOutputNodeHid) ); SG_DAGNODE_NULLFREE(pCtx, pDagnode); SG_BITVECTOR_NULLFREE(pCtx, pIsAncestorOf); for(i=0; i<workQueue.length; ++i) { SG_DAGNODE_NULLFREE(pCtx, workQueue.p[i].pDagnode); SG_BITVECTOR_NULLFREE(pCtx, workQueue.p[i].pIsAncestorOf); } SG_NULLFREE(pCtx, workQueue.p); SG_RBTREE_NULLFREE(pCtx, workQueue.pRevnoCache); SG_ERR_CHECK( SG_repo__fetch_dagnodes__end(pCtx, pRepo, &pDagnodeFetcher) ); return; fail: for(i=0; i<workQueue.length; ++i) { SG_DAGNODE_NULLFREE(pCtx, workQueue.p[i].pDagnode); SG_BITVECTOR_NULLFREE(pCtx, workQueue.p[i].pIsAncestorOf); } SG_NULLFREE(pCtx, workQueue.p); SG_RBTREE_NULLFREE(pCtx, workQueue.pRevnoCache); SG_DAGNODE_NULLFREE(pCtx, pDagnode); SG_BITVECTOR_NULLFREE(pCtx, pIsAncestorOf); if(pDagnodeFetcher!=NULL) { SG_ERR_IGNORE( SG_repo__fetch_dagnodes__end(pCtx, pRepo, &pDagnodeFetcher) ); } }
void SG_localsettings__split_full_name( SG_context* pCtx, const char* szFullName, SG_uint32* uSplitIndex, SG_string* pScopeName, SG_string* pSettingName ) { SG_uint32 uSlashCount = 0; SG_uint32 uCurrent = 0; SG_ARGCHECK(szFullName[0] == '/', szFullName); // this is basically implemented by locating the Nth '/' character // where N depends on which scope the name is in if (0 == strncmp(szFullName, SG_LOCALSETTING__SCOPE__INSTANCE, strlen(SG_LOCALSETTING__SCOPE__INSTANCE))) { uSlashCount = 2; } else if (0 == strncmp(szFullName, SG_LOCALSETTING__SCOPE__REPO, strlen(SG_LOCALSETTING__SCOPE__REPO))) { uSlashCount = 2; } else if (0 == strncmp(szFullName, SG_LOCALSETTING__SCOPE__ADMIN, strlen(SG_LOCALSETTING__SCOPE__ADMIN))) { uSlashCount = 2; } else if (0 == strncmp(szFullName, SG_LOCALSETTING__SCOPE__MACHINE, strlen(SG_LOCALSETTING__SCOPE__MACHINE))) { uSlashCount = 1; } else { uSlashCount = 1; } // iterate through the string until we find the slash that we're looking for while (szFullName[uCurrent] != '\0' && uSlashCount > 0u) { // the first time through, this will always skip the leading slash character // this is why uSlashCount is one less than it seems like it should be uCurrent = uCurrent + 1u; // if this is a slash, update our count if (szFullName[uCurrent] == '/') { uSlashCount = uSlashCount - 1; } } // if the caller wants the index, fill it in if (uSplitIndex != NULL) { *uSplitIndex = uCurrent; } // if the caller wants the scope name, fill it in if (pScopeName != NULL) { SG_ERR_CHECK( SG_string__set__buf_len(pCtx, pScopeName, (const SG_byte*)szFullName, uCurrent) ); } // if the caller wants the setting name, fill it in if (pSettingName != NULL) { SG_ERR_CHECK( SG_string__set__sz(pCtx, pSettingName, szFullName + uCurrent + 1) ); } fail: return; }