void SG_group__list( SG_context* pCtx, SG_repo* pRepo, SG_varray** ppva ) { SG_string* pstr_where = NULL; SG_stringarray* psa_results = NULL; char* psz_hid_cs_leaf = NULL; SG_vhash* pvh_group = NULL; SG_varray* pva_result = NULL; SG_stringarray* psa_fields = NULL; SG_ERR_CHECK( SG_zing__get_leaf__fail_if_needs_merge(pCtx, pRepo, SG_DAGNUM__USERS, &psz_hid_cs_leaf) ); SG_ERR_CHECK( SG_STRINGARRAY__ALLOC(pCtx, &psa_fields, 2) ); SG_ERR_CHECK( SG_stringarray__add(pCtx, psa_fields, "recid") ); SG_ERR_CHECK( SG_stringarray__add(pCtx, psa_fields, "name") ); SG_ERR_CHECK( SG_zing__query(pCtx, pRepo, SG_DAGNUM__USERS, psz_hid_cs_leaf, "group", NULL, "name #ASC", 0, 0, psa_fields, &pva_result) ); *ppva = pva_result; pva_result = NULL; fail: SG_VHASH_NULLFREE(pCtx, pvh_group); SG_NULLFREE(pCtx, psz_hid_cs_leaf); SG_VARRAY_NULLFREE(pCtx, pva_result); SG_STRINGARRAY_NULLFREE(pCtx, psa_results); SG_STRING_NULLFREE(pCtx, pstr_where); SG_STRINGARRAY_NULLFREE(pCtx, psa_fields); }
void SG_user__lookup_by_email( SG_context* pCtx, SG_repo* pRepo, const char* psz_email, SG_vhash** ppvh ) { char* psz_hid_cs_leaf = NULL; SG_vhash* pvh_user = NULL; char buf_where[256 + 64]; SG_stringarray* psa_fields = NULL; SG_ERR_CHECK( SG_zing__get_leaf__fail_if_needs_merge(pCtx, pRepo, SG_DAGNUM__USERS, &psz_hid_cs_leaf) ); if (psz_hid_cs_leaf) { SG_ERR_CHECK( SG_sprintf(pCtx, buf_where, sizeof(buf_where), "email == '%s'", psz_email) ); SG_ERR_CHECK( SG_STRINGARRAY__ALLOC(pCtx, &psa_fields, 4) ); SG_ERR_CHECK( SG_stringarray__add(pCtx, psa_fields, "recid") ); SG_ERR_CHECK( SG_stringarray__add(pCtx, psa_fields, "email") ); //SG_ERR_CHECK( SG_stringarray__add(pCtx, psa_fields, "prefix") ); SG_ERR_CHECK( SG_stringarray__add(pCtx, psa_fields, "key") ); SG_ERR_CHECK( SG_zing__query__one(pCtx, pRepo, SG_DAGNUM__USERS, psz_hid_cs_leaf, "user", buf_where, psa_fields, &pvh_user) ); } *ppvh = pvh_user; pvh_user = NULL; fail: SG_STRINGARRAY_NULLFREE(pCtx, psa_fields); SG_VHASH_NULLFREE(pCtx, pvh_user); SG_NULLFREE(pCtx, psz_hid_cs_leaf); }
void SG_treendx__get_all_paths(SG_context* pCtx, SG_treendx* pTreeNdx, const char* psz_gid, SG_stringarray ** ppResults) { sqlite3_stmt* pStmt = NULL; SG_stringarray * pResults = NULL; int rc; SG_ERR_CHECK_RETURN( SG_gid__argcheck(pCtx, psz_gid) ); SG_ERR_CHECK( SG_STRINGARRAY__ALLOC(pCtx,&pResults, 1) ); SG_ERR_CHECK( sg_sqlite__prepare(pCtx, pTreeNdx->psql, &pStmt, "SELECT strpath FROM treendx WHERE gid='%s' ORDER BY strpath;", psz_gid) ); while ((rc = sqlite3_step(pStmt)) == SQLITE_ROW) { const char* pszPath = (const char*) sqlite3_column_text(pStmt, 0); SG_ERR_CHECK( SG_stringarray__add(pCtx, pResults, pszPath) ); } if (rc != SQLITE_DONE) { SG_ERR_THROW(SG_ERR_SQLITE(rc)); } SG_ERR_CHECK( sg_sqlite__finalize(pCtx, pStmt) ); *ppResults = pResults; return; fail: if (pStmt) { SG_ERR_IGNORE( sg_sqlite__finalize(pCtx, pStmt) ); } }
void SG_stringarray__alloc__copy( SG_context* pCtx, SG_stringarray** ppThis, const SG_stringarray* pOther ) { SG_uint32 count = 0; SG_stringarray * pThis = NULL; SG_uint32 i; SG_ASSERT(pCtx!=NULL); SG_NULLARGCHECK_RETURN(ppThis); SG_NULLARGCHECK_RETURN(pOther); SG_ERR_CHECK( SG_stringarray__count(pCtx, pOther, &count) ); SG_ERR_CHECK( SG_stringarray__alloc(pCtx, &pThis, count) ); for(i=0;i<count;++i) { const char * sz = NULL; SG_ERR_CHECK( SG_stringarray__get_nth(pCtx, pOther, i, &sz) ); SG_ERR_CHECK( SG_stringarray__add(pCtx, pThis, sz) ); } *ppThis = pThis; return; fail: SG_STRINGARRAY_NULLFREE(pCtx, pThis); }
void SG_util__convert_argv_into_stringarray(SG_context * pCtx, SG_uint32 argc, const char ** argv, SG_stringarray ** ppsa) { SG_stringarray * psa = NULL; SG_uint32 nrKept = 0; SG_uint32 k; if (argc && argv) { SG_ERR_CHECK( SG_STRINGARRAY__ALLOC(pCtx, &psa, argc) ); for (k=0; k<argc; k++) { if (!argv[k]) // argv ends at first null pointer regardless of what argc says. break; if (argv[k][0]) // skip over empty "" strings. { SG_ERR_CHECK( SG_stringarray__add(pCtx, psa, argv[k]) ); nrKept++; } } if (nrKept == 0) SG_STRINGARRAY_NULLFREE(pCtx, psa); } *ppsa = psa; return; fail: SG_STRINGARRAY_NULLFREE(pCtx, psa); }
/** * build an ordered stringarray of the GIDs of all of the issues. * i need to have the list of GIDs be independent of pPendingTree * and pvaIssues so that FIX can do incremental SAVES of the * pendingtree (which trashes the ptnodes and/or requires a reload). */ static void _resolve__get_all_issue_gids(SG_context * pCtx, struct _resolve_data * pData, SG_bool bWantResolved, SG_bool bWantUnresolved) { const SG_varray * pvaIssues; // varray[pvhIssue *] of all issues -- we do not own this SG_bool bHaveIssues; SG_uint32 k; SG_uint32 nrIssues = 0; SG_bool bWantBoth = (bWantResolved && bWantUnresolved); SG_ERR_CHECK( SG_pendingtree__get_wd_issues__ref(pCtx, pData->pPendingTree, &bHaveIssues, &pvaIssues) ); if (bHaveIssues) SG_ERR_CHECK( SG_varray__count(pCtx, pvaIssues, &nrIssues) ); SG_ERR_CHECK( SG_STRINGARRAY__ALLOC(pCtx, &pData->psaGids, nrIssues) ); for (k=0; k<nrIssues; k++) { const SG_vhash * pvhIssue_k; const char * pszGid_k; SG_bool bWantThisOne; SG_ERR_CHECK( SG_varray__get__vhash(pCtx, pvaIssues, k, (SG_vhash **)&pvhIssue_k) ); if (bWantBoth) bWantThisOne = SG_TRUE; else { SG_int64 s; SG_pendingtree_wd_issue_status status; SG_bool bResolved; SG_ERR_CHECK_RETURN( SG_vhash__get__int64(pCtx, pvhIssue_k, "status", &s) ); status = (SG_pendingtree_wd_issue_status)s; bResolved = ((status & SG_ISSUE_STATUS__MARKED_RESOLVED) == SG_ISSUE_STATUS__MARKED_RESOLVED); bWantThisOne = ((bWantResolved && bResolved) || (bWantUnresolved && !bResolved)); } if (bWantThisOne) { SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvhIssue_k, "gid", &pszGid_k) ); SG_ERR_CHECK( SG_stringarray__add(pCtx, pData->psaGids, pszGid_k) ); } } fail: return; }
void SG_cmd_util__dump_log( SG_context * pCtx, SG_console_stream cs, SG_repo* pRepo, const char* psz_hid_cs, SG_vhash* pvhCleanPileOfBranches, SG_bool bShowOnlyOpenBranchNames, SG_bool bShowFullComments) { SG_history_result* pHistResult = NULL; SG_stringarray * psaHids = NULL; SG_STRINGARRAY__ALLOC(pCtx, &psaHids, 1); SG_ERR_CHECK( SG_stringarray__add(pCtx, psaHids, psz_hid_cs) ); SG_history__get_revision_details(pCtx, pRepo, psaHids, NULL, &pHistResult); if (SG_context__err_equals(pCtx, SG_ERR_NOT_FOUND)) { /* There's a branch that references a changeset that doesn't exist. Show what we can. */ SG_vhash* pvhRefClosedBranches = NULL; SG_vhash* pvhRefBranchValues = NULL; SG_context__err_reset(pCtx); if (pvhCleanPileOfBranches) { SG_bool bHas = SG_FALSE; SG_ERR_CHECK( SG_vhash__has(pCtx, pvhCleanPileOfBranches, "closed", &bHas) ); if (bHas) SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvhCleanPileOfBranches, "closed", &pvhRefClosedBranches) ); SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvhCleanPileOfBranches, "values", &pvhRefBranchValues) ); } SG_ERR_CHECK( SG_console(pCtx, cs, "\n\t%8s: %s\n", "revision", psz_hid_cs) ); SG_ERR_CHECK( _dump_branch_name(pCtx, cs, psz_hid_cs, bShowOnlyOpenBranchNames, pvhRefBranchValues, pvhRefClosedBranches) ); SG_ERR_CHECK( SG_console(pCtx, cs, "\t%8s %s\n", "", "(not present in repository)") ); } else { SG_ERR_CHECK_CURRENT; SG_ERR_CHECK( SG_cmd_util__dump_history_results(pCtx, cs, pHistResult, pvhCleanPileOfBranches, bShowOnlyOpenBranchNames, bShowFullComments, SG_FALSE) ); } fail: SG_HISTORY_RESULT_NULLFREE(pCtx, pHistResult); SG_STRINGARRAY_NULLFREE(pCtx, psaHids); }
// Helper function for _tree__init__continuation() static void _tree__add_subtoken(SG_context * pCtx, _tree_t * pTree, _node_t * pParent, SG_varray * pSubtoken) { SG_int64 revno = 0; char * szHid = NULL; _node_t * pNodeRef = NULL; SG_uint32 count = 0; SG_uint32 i = 0; SG_uint16 lastElementType = 0; SG_varray * pSubsubtoken = NULL; SG_stringarray * psa = NULL; ++pTree->indentLevel; SG_ERR_CHECK( SG_varray__get__int64(pCtx, pSubtoken, 0, &revno) ); SG_ERR_CHECK( SG_repo__find_dagnode_by_rev_id(pCtx, pTree->pRepoRef, SG_DAGNUM__VERSION_CONTROL, (SG_uint32)revno, &szHid) ); SG_ERR_CHECK( _tree__add_new_node(pCtx, pTree, pParent, szHid, &pNodeRef) ); pNodeRef->isPending = SG_FALSE; SG_NULLFREE(pCtx, szHid); SG_ERR_CHECK( SG_varray__count(pCtx, pSubtoken, &count) ); SG_ERR_CHECK( SG_varray__typeof(pCtx, pSubtoken, count-1, &lastElementType) ); if(lastElementType==SG_VARIANT_TYPE_VARRAY) { SG_ERR_CHECK( SG_varray__get__varray(pCtx, pSubtoken, count-1, &pSubsubtoken) ); --count; } for(i=1; i<count; ++i) { _node_t * pRefChildNode = NULL; SG_ERR_CHECK( SG_varray__get__int64(pCtx, pSubtoken, i, &revno) ); if(i==1 && revno==0) { // Revno 0 in the as the first child means "Use the LCA for the baseline". SG_uint32 j = 0; if(pSubsubtoken!=NULL) { // LCA would not include nodes in the sub-token. Just error out. SG_ERR_THROW(SG_ERR_INVALIDARG); } if(count-2<2) { // This would be interpreted as merging a node with itself or with nothing. SG_ERR_THROW(SG_ERR_INVALIDARG); } SG_ERR_CHECK( SG_STRINGARRAY__ALLOC(pCtx, &psa, count-2) ); for(j=2; j<count; ++j) { SG_ERR_CHECK( SG_varray__get__int64(pCtx, pSubtoken, j, &revno) ); SG_ERR_CHECK( SG_repo__find_dagnode_by_rev_id(pCtx, pTree->pRepoRef, SG_DAGNUM__VERSION_CONTROL, (SG_uint32)revno, &szHid) ); SG_ERR_CHECK( SG_stringarray__add(pCtx, psa, szHid) ); SG_NULLFREE(pCtx, szHid); } SG_ERR_CHECK( SG_dagquery__highest_revno_common_ancestor(pCtx, pTree->pRepoRef, SG_DAGNUM__VERSION_CONTROL, psa, &szHid) ); SG_STRINGARRAY_NULLFREE(pCtx, psa); } else { SG_ERR_CHECK( SG_repo__find_dagnode_by_rev_id(pCtx, pTree->pRepoRef, SG_DAGNUM__VERSION_CONTROL, (SG_uint32)revno, &szHid) ); } SG_ERR_CHECK( _tree__add_new_node(pCtx, pTree, pNodeRef, szHid, &pRefChildNode) ); pTree->pNextResult = pRefChildNode; SG_ERR_CHECK( _node_list__append(pCtx, &pTree->pending, &pRefChildNode) ); SG_NULLFREE(pCtx, szHid); } if(pSubsubtoken!=NULL) { SG_ERR_CHECK( _tree__add_subtoken(pCtx, pTree, pNodeRef, pSubsubtoken) ); } return; fail: SG_NULLFREE(pCtx, szHid); SG_STRINGARRAY_NULLFREE(pCtx, psa); }
static void _s2__do_cset_vs_cset(SG_context * pCtx, const SG_option_state * pOptSt, const SG_stringarray * psaArgs, SG_uint32 * pNrErrors) { SG_varray * pvaStatus = NULL; SG_varray * pvaStatusDirtyFiles = NULL; SG_stringarray * psa1 = NULL; SG_string * pStringGidRepoPath = NULL; SG_string * pStringErr = NULL; SG_uint32 nrErrors = 0; SG_ERR_CHECK( SG_vv2__status(pCtx, pOptSt->psz_repo, pOptSt->pRevSpec, psaArgs, WC__GET_DEPTH(pOptSt), SG_FALSE, // bNoSort &pvaStatus, NULL) ); if (pvaStatus) { if (pOptSt->bInteractive) { // Filter list down to just modified files and show them one-by-one. SG_ERR_CHECK( _get_dirty_files(pCtx, pvaStatus, &pvaStatusDirtyFiles) ); if (pvaStatusDirtyFiles) SG_ERR_CHECK( _do_gui_diffs(pCtx, SG_FALSE, pOptSt, pvaStatusDirtyFiles, &nrErrors) ); } else { SG_uint32 k, nrItems; // Print the changes with PATCH-like headers. // Accumulate any tool errors. SG_ERR_CHECK( SG_varray__count(pCtx, pvaStatus, &nrItems) ); for (k=0; k<nrItems; k++) { SG_vhash * pvhItem; const char * pszGid = NULL; SG_ERR_CHECK( SG_varray__get__vhash(pCtx, pvaStatus, k, &pvhItem) ); // TODO 2013/02/22 Our pvhItem has all of the details for the diff, // TODO but we don't yet have a public API to let it be // TODO used as is. So we build a @gid repo-path and // TODO run the old historical diff code on a 1-item array // TODO containing this @gid. // TODO // TODO We should fix this to just pass down the pvhItem // TOOD so that it doesn't have to repeat the status lookup. SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvhItem, "gid", &pszGid) ); SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &pStringGidRepoPath) ); SG_ERR_CHECK( SG_string__sprintf(pCtx, pStringGidRepoPath, "@%s", pszGid) ); SG_ERR_CHECK( SG_STRINGARRAY__ALLOC(pCtx, &psa1, 1) ); SG_ERR_CHECK( SG_stringarray__add(pCtx, psa1, SG_string__sz(pStringGidRepoPath)) ); SG_vv2__diff_to_stream__throw(pCtx, pOptSt->psz_repo, pOptSt->pRevSpec, psa1, 0, SG_TRUE, // bNoSort -- doesn't matter only 1 item in list SG_FALSE, // bInteractive, pOptSt->psz_tool); // Don't throw the error from the tool. Just print it on STDERR // and remember that we had an error so that don't stop showing // the diffs just because we stumble over a changed binary file // or mis-configured tool, for example. if (SG_context__has_err(pCtx)) { SG_context__err_to_string(pCtx, SG_FALSE, &pStringErr); SG_context__err_reset(pCtx); SG_ERR_CHECK( SG_console__raw(pCtx, SG_CS_STDERR, SG_string__sz(pStringErr)) ); SG_STRING_NULLFREE(pCtx, pStringErr); nrErrors++; } SG_STRING_NULLFREE(pCtx, pStringGidRepoPath); SG_STRINGARRAY_NULLFREE(pCtx, psa1); } } } *pNrErrors = nrErrors; fail: SG_VARRAY_NULLFREE(pCtx, pvaStatus); SG_VARRAY_NULLFREE(pCtx, pvaStatusDirtyFiles); SG_STRINGARRAY_NULLFREE(pCtx, psa1); SG_STRING_NULLFREE(pCtx, pStringGidRepoPath); SG_STRING_NULLFREE(pCtx, pStringErr); }
/** * Do diff of an individual item. * When WC-based, we have a "DiffStep" vhash. * When historical, we have an item from a pvaStatus. * */ static void _do_diff1(SG_context * pCtx, SG_bool bWC, const SG_option_state * pOptSt, const SG_vhash * pvhItem, SG_uint32 * piResult) { SG_string * pStringGidRepoPath = NULL; SG_vhash * pvhResultCodes = NULL; SG_stringarray * psa1 = NULL; const char * pszGid; SG_int64 i64Result = 0; SG_string * pStringErr = NULL; SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvhItem, "gid", &pszGid) ); if (bWC) { SG_pathname * pPathWc = NULL; SG_bool bHasTool = SG_FALSE; // With the __diff__setup() and __diff__run() changes, we have already // examined the items during the __setup() step and recorded a tool for // the *FILE* that have changed content. So if "tool" isn't set in the // DiffStep/Item, we don't need to diff it -- it could be a structural // change, a non-file, a found item, etc. // // we do not use SG_wc__diff__throw() because we already have the diff info // and we want to control the result-code processing below. SG_ERR_CHECK( SG_vhash__has(pCtx, pvhItem, "tool", &bHasTool) ); if (bHasTool) SG_ERR_CHECK( SG_wc__diff__run(pCtx, pPathWc, pvhItem, &pvhResultCodes) ); } else { SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &pStringGidRepoPath) ); SG_ERR_CHECK( SG_string__sprintf(pCtx, pStringGidRepoPath, "@%s", pszGid) ); SG_ERR_CHECK( SG_STRINGARRAY__ALLOC(pCtx, &psa1, 1) ); SG_ERR_CHECK( SG_stringarray__add(pCtx, psa1, SG_string__sz(pStringGidRepoPath)) ); // we do not use the __throw() version of this routine so we can control // result-code processing below. SG_ERR_CHECK( SG_vv2__diff_to_stream(pCtx, pOptSt->psz_repo, pOptSt->pRevSpec, psa1, 0, SG_FALSE, // bNoSort SG_TRUE, // bInteractive, pOptSt->psz_tool, &pvhResultCodes) ); } if (pvhResultCodes) { SG_vhash * pvhResult; // we do not own this SG_ERR_CHECK( SG_vhash__check__vhash(pCtx, pvhResultCodes, pszGid, &pvhResult) ); if (pvhResult) { const char * pszTool; SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvhResult, "tool", &pszTool) ); SG_ERR_CHECK( SG_vhash__get__int64(pCtx, pvhResult, "result", &i64Result) ); SG_difftool__check_result_code__throw(pCtx, i64Result, pszTool); if (SG_context__has_err(pCtx)) { SG_context__err_to_string(pCtx, SG_FALSE, &pStringErr); SG_context__err_reset(pCtx); SG_ERR_CHECK( SG_console__raw(pCtx, SG_CS_STDERR, SG_string__sz(pStringErr)) ); // eat the tool error. the result code is set. } } } if (piResult) *piResult = (SG_uint32)i64Result; fail: SG_STRING_NULLFREE(pCtx, pStringGidRepoPath); SG_VHASH_NULLFREE(pCtx, pvhResultCodes); SG_STRINGARRAY_NULLFREE(pCtx, psa1); SG_STRING_NULLFREE(pCtx, pStringErr); }
/** * Assuming that we have something of the form: * * vv resolve [--foo] <arg_0> [<arg_1> [<arg_2> ...]] * * where each <arg_x> is an absolute or relative path in the WD * (probably not a repo-path). * * Use the PENDINGTREE to lookup each path and get the entry's GID. * Use the GID to search for an ISSUE in the list of issues. If we * find it, add the GID to the stringarray we are building. If not, * throw an error. */ static void _resolve__map_args_to_gids(SG_context * pCtx, struct _resolve_data * pData, SG_uint32 count_args, const char ** paszArgs, SG_bool bWantResolved, SG_bool bWantUnresolved) { SG_pathname * pPath_k = NULL; char * pszGid_k = NULL; SG_uint32 kArg; SG_bool bWantBoth = (bWantResolved && bWantUnresolved); SG_ERR_CHECK( SG_STRINGARRAY__ALLOC(pCtx, &pData->psaGids, count_args) ); for (kArg=0; kArg<count_args; kArg++) { const SG_vhash * pvhIssue_k; SG_bool bFound; SG_bool bDuplicate; SG_bool bWantThisOne; // take each <arg_k> and get a full pathname for it and // search for it in the pendingtree and get its GID. // in theory, if an entry has an issue, it is dirty and // should have a ptnode. if (paszArgs[kArg][0] == '@') SG_ERR_CHECK( SG_workingdir__construct_absolute_path_from_repo_path2(pCtx, pData->pPendingTree, paszArgs[kArg], &pPath_k) ); else SG_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx, &pPath_k, paszArgs[kArg]) ); SG_ERR_CHECK( SG_pendingtree__get_gid_from_local_path(pCtx, pData->pPendingTree, pPath_k, &pszGid_k) ); #if 0 && defined(DEBUG) SG_ERR_IGNORE( SG_console(pCtx, SG_CS_STDERR, ("Mapped arg[%d] '%s' to:\n" "\t%s\n" "\t[gid %s]\n"), kArg, paszArgs[kArg], SG_pathname__sz(pPath_k), pszGid_k) ); #endif // see if there is an ISSUE for this GID. SG_ERR_CHECK( SG_pendingtree__find_wd_issue_by_gid(pCtx, pData->pPendingTree, pszGid_k, &bFound, &pvhIssue_k) ); if (!bFound) SG_ERR_THROW2( SG_ERR_ISSUE_NOT_FOUND, (pCtx, "No issue found for '%s': %s", paszArgs[kArg], SG_pathname__sz(pPath_k)) ); if (bWantBoth) bWantThisOne = SG_TRUE; else { SG_int64 s; SG_pendingtree_wd_issue_status status; SG_bool bResolved; SG_ERR_CHECK_RETURN( SG_vhash__get__int64(pCtx, pvhIssue_k, "status", &s) ); status = (SG_pendingtree_wd_issue_status)s; bResolved = ((status & SG_ISSUE_STATUS__MARKED_RESOLVED) == SG_ISSUE_STATUS__MARKED_RESOLVED); bWantThisOne = ((bWantResolved && bResolved) || (bWantUnresolved && !bResolved)); } if (bWantThisOne) { // check for duplicate args on command line. (or rather, args that // map to the same GID.) SG_ERR_CHECK( SG_stringarray__find(pCtx, pData->psaGids, pszGid_k, 0, &bDuplicate, NULL) ); if (bDuplicate) SG_ERR_THROW2( SG_ERR_DUPLICATE_ISSUE, (pCtx, "Argument '%s' maps to an issue already named.", paszArgs[kArg]) ); SG_ERR_CHECK( SG_stringarray__add(pCtx, pData->psaGids, pszGid_k) ); } SG_NULLFREE(pCtx, pszGid_k); SG_PATHNAME_NULLFREE(pCtx, pPath_k); } return; fail: SG_NULLFREE(pCtx, pszGid_k); SG_PATHNAME_NULLFREE(pCtx, pPath_k); }
void SG_dagquery__find_new_since_common( SG_context * pCtx, SG_repo * pRepo, SG_uint64 dagnum, const char * pszOldNodeHid, const char * pszNewNodeHid, SG_stringarray ** ppResults ) { _fnsc_work_queue_t workQueue = {NULL, 0, 0, 0, NULL}; SG_uint32 i; SG_dagnode * pDagnode = NULL; SG_stringarray * pResults = NULL; SG_ASSERT(pCtx!=NULL); SG_NULLARGCHECK(pRepo); SG_NONEMPTYCHECK(pszOldNodeHid); SG_NONEMPTYCHECK(pszNewNodeHid); SG_NULLARGCHECK(ppResults); SG_ERR_CHECK( SG_allocN(pCtx, _FNSC_WORK_QUEUE_INIT_LENGTH, workQueue.p) ); workQueue.allocatedLength = _FNSC_WORK_QUEUE_INIT_LENGTH; SG_ERR_CHECK( SG_RBTREE__ALLOC(pCtx, &workQueue.pRevnoCache) ); SG_ERR_CHECK( _fnsc_work_queue__insert(pCtx, &workQueue, pszOldNodeHid, dagnum, pRepo, _ANCESTOR_OF_OLD) ); SG_ERR_CHECK( _fnsc_work_queue__insert(pCtx, &workQueue, pszNewNodeHid, dagnum, pRepo, _ANCESTOR_OF_NEW) ); SG_ERR_CHECK( SG_STRINGARRAY__ALLOC(pCtx, &pResults, 32) ); while(workQueue.numAncestorsOfNewOnTheQueue > 0) { const char * pszHidRef = NULL; SG_byte isAncestorOf = 0; SG_ERR_CHECK( _fnsc_work_queue__pop(pCtx, &workQueue, &pDagnode, &pszHidRef, &isAncestorOf) ); if (isAncestorOf==_ANCESTOR_OF_NEW) SG_ERR_CHECK( SG_stringarray__add(pCtx, pResults, pszHidRef) ); { 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( _fnsc_work_queue__insert(pCtx, &workQueue, parents[i], dagnum, pRepo, isAncestorOf) ); } SG_DAGNODE_NULLFREE(pCtx, pDagnode); } for(i=0; i<workQueue.length; ++i) SG_DAGNODE_NULLFREE(pCtx, workQueue.p[i].pDagnode); SG_NULLFREE(pCtx, workQueue.p); SG_RBTREE_NULLFREE(pCtx, workQueue.pRevnoCache); *ppResults = pResults; return; fail: for(i=0; i<workQueue.length; ++i) SG_DAGNODE_NULLFREE(pCtx, workQueue.p[i].pDagnode); SG_NULLFREE(pCtx, workQueue.p); SG_RBTREE_NULLFREE(pCtx, workQueue.pRevnoCache); SG_DAGNODE_NULLFREE(pCtx, pDagnode); SG_STRINGARRAY_NULLFREE(pCtx, pResults); }