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)  );
	}
}
Example #6
0
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;
}