void SG_dagfrag_debug__dump(SG_context * pCtx, SG_dagfrag * pFrag, const char * szLabel, SG_uint32 indent, SG_string * pStringOutput) { char buf[4000]; struct _dump_data dump_data; dump_data.indent = indent+4; dump_data.nrDigits = 6; dump_data.pStringOutput = pStringOutput; SG_ERR_CHECK_RETURN( SG_sprintf(pCtx, buf,SG_NrElements(buf),"%*cDagFrag[%p] [%s]\n",indent,' ',pFrag,szLabel) ); SG_ERR_CHECK_RETURN( SG_string__append__sz(pCtx, pStringOutput,buf) ); dump_data.stateWanted = SG_DFS_START_MEMBER; SG_ERR_CHECK_RETURN( SG_sprintf(pCtx, buf,SG_NrElements(buf),"%*cStartMembers:\n",indent+2,' ') ); SG_ERR_CHECK_RETURN( SG_string__append__sz(pCtx, pStringOutput,buf) ); SG_ERR_CHECK_RETURN( SG_rbtree__foreach(pCtx, pFrag->m_pRB_Cache,_dump_cb,&dump_data) ); dump_data.stateWanted = SG_DFS_INTERIOR_MEMBER; SG_ERR_CHECK_RETURN( SG_sprintf(pCtx,buf,SG_NrElements(buf),"%*cInteriorMembers:\n",indent+2,' ') ); SG_ERR_CHECK_RETURN( SG_string__append__sz(pCtx,pStringOutput,buf) ); SG_ERR_CHECK_RETURN( SG_rbtree__foreach(pCtx,pFrag->m_pRB_Cache,_dump_cb,&dump_data) ); dump_data.stateWanted = SG_DFS_END_FRINGE; SG_ERR_CHECK_RETURN( SG_sprintf(pCtx,buf,SG_NrElements(buf),"%*cEndFringe:\n",indent+2,' ') ); SG_ERR_CHECK_RETURN( SG_string__append__sz(pCtx,pStringOutput,buf) ); SG_ERR_CHECK_RETURN( SG_rbtree__foreach(pCtx,pFrag->m_pRB_Cache,_dump_cb,&dump_data) ); }
void u0051_hidlookup__create_file__numbers( SG_context* pCtx, SG_pathname* pPath, const char* pszName, const SG_uint32 countLines ) { SG_pathname* pPathFile = NULL; SG_uint32 i; SG_file* pFile = NULL; VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pPathFile, pPath, pszName) ); VERIFY_ERR_CHECK( SG_file__open__pathname(pCtx, pPathFile, SG_FILE_CREATE_NEW | SG_FILE_RDWR, 0600, &pFile) ); for (i=0; i<countLines; i++) { char buf[64]; VERIFY_ERR_CHECK( SG_sprintf(pCtx, buf, sizeof(buf), "%d\n", i) ); VERIFY_ERR_CHECK( SG_file__write(pCtx, pFile, (SG_uint32) strlen(buf), (SG_byte*) buf, NULL) ); } VERIFY_ERR_CHECK( SG_file__close(pCtx, &pFile) ); SG_PATHNAME_NULLFREE(pCtx, pPathFile); return; fail: SG_FILE_NULLCLOSE(pCtx, pFile); SG_PATHNAME_NULLFREE(pCtx, pPathFile); }
void SG_time__format_local__i64(SG_context* pCtx, SG_int64 iTime, char * pBuf, SG_uint32 lenBuf) { // do simple formatting of time value and generate a localtime-based, human-readable time. // this is like ctime(3), asctime(3), gmtime(3), localtime(3) only i don't currently // care about all the various formatting options. // // that is, we don't care about: // [] which fields we show, // [] localization (which order we show the fields and month names), // [] 12 vs 24 hour time. // [] UTF8. // // we are given a buffer that must be SG_TIME_FORMAT_LENGTH+1 characters or larger. SG_time tm; SG_NULLARGCHECK_RETURN( pBuf ); SG_ARGCHECK_RETURN( (lenBuf >= SG_TIME_FORMAT_LENGTH+1), lenBuf ); // convert milliseconds-since-epoch into individual fields. SG_ERR_CHECK_RETURN( SG_time__decode__local(pCtx, iTime,&tm) ); SG_ERR_CHECK_RETURN( SG_sprintf(pCtx, pBuf,lenBuf,"%04d/%02d/%02d %02d:%02d:%02d.%03d %+03d%02d", tm.year,tm.month,tm.mday, tm.hour,tm.min,tm.sec,tm.msec, tm.offsetUTC/3600,abs((tm.offsetUTC/60)%60)) ); }
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); }
const char* SG_thread__sz( SG_context* pCtx, SG_thread_id cThread, char* pBuffer ) { SG_ERR_CHECK( SG_sprintf(pCtx, pBuffer, SG_THREAD_TO_STRING_BUFFER_LENGTH, "%d", cThread) ); fail: return pBuffer; }
void SG_time__formatRFC850(SG_context* pCtx, SG_int64 utcms, char *formatted, SG_uint32 buflen) { SG_time tm; SG_NULLARGCHECK_RETURN(formatted); // convert milliseconds-since-epoch into individual fields. SG_ERR_CHECK_RETURN( SG_time__decode(pCtx, utcms, &tm) ); //Tue, 16 Mar 2010 14:11:13 EDT SG_ERR_CHECK_RETURN( SG_sprintf(pCtx, formatted, buflen, "%s, %02d %s %04d %02d:%02d:%02d GMT", weekdays[tm.wday], tm.mday, months[tm.month - 1], tm.year, tm.hour,tm.min,tm.sec) ); }
void SG_time__format_local__i64_ns(SG_context* pCtx, SG_int64 iTime_ns, char * pBuf, SG_uint32 lenBuf) { SG_int64 iTime_ms = iTime_ns / 1000000; SG_int32 remainder = (SG_int32)(iTime_ns % 1000000); SG_time tm; SG_NULLARGCHECK_RETURN( pBuf ); SG_ARGCHECK_RETURN( (lenBuf >= SG_TIME_FORMAT_LENGTH+1), lenBuf ); // convert milliseconds-since-epoch into individual fields. SG_ERR_CHECK_RETURN( SG_time__decode__local(pCtx, iTime_ms, &tm) ); SG_ERR_CHECK_RETURN( SG_sprintf(pCtx, pBuf,lenBuf,"%04d/%02d/%02d %02d:%02d:%02d.%03d%06d %+03d%02d", tm.year,tm.month,tm.mday, tm.hour,tm.min,tm.sec,tm.msec,remainder, tm.offsetUTC/3600,abs((tm.offsetUTC/60)%60)) ); }
void SG_vc_hooks__lookup_by_interface( SG_context* pCtx, SG_repo* pRepo, const char* psz_interface, SG_varray** ppva ) { char* psz_hid_cs_leaf = NULL; SG_varray* pva_fields = NULL; SG_varray* pva = NULL; char buf_where[SG_HID_MAX_BUFFER_LENGTH + 64]; char *iEscape = NULL; const char *ivar = NULL; SG_ERR_CHECK( SG_zing__get_leaf(pCtx, pRepo, NULL, SG_DAGNUM__VC_HOOKS, &psz_hid_cs_leaf) ); SG_ASSERT(psz_hid_cs_leaf); SG_ERR_CHECK( SG_sqlite__escape(pCtx, psz_interface, &iEscape) ); if (iEscape) ivar = iEscape; else ivar = psz_interface; SG_ERR_CHECK( SG_sprintf(pCtx, buf_where, sizeof(buf_where), "interface == '%s'", ivar) ); SG_ERR_CHECK( SG_VARRAY__ALLOC(pCtx, &pva_fields) ); SG_ERR_CHECK( SG_varray__append__string__sz(pCtx, pva_fields, "js") ); SG_ERR_CHECK( SG_varray__append__string__sz(pCtx, pva_fields, "module") ); SG_ERR_CHECK( SG_varray__append__string__sz(pCtx, pva_fields, "version") ); SG_ERR_CHECK( SG_varray__append__string__sz(pCtx, pva_fields, SG_ZING_FIELD__HIDREC) ); SG_ERR_CHECK( SG_zing__query(pCtx, pRepo, SG_DAGNUM__VC_HOOKS, psz_hid_cs_leaf, "hook", buf_where, NULL, 0, 0, pva_fields, &pva) ); *ppva = pva; pva= NULL; fail: SG_VARRAY_NULLFREE(pCtx, pva); SG_VARRAY_NULLFREE(pCtx, pva_fields); SG_NULLFREE(pCtx, psz_hid_cs_leaf); SG_NULLFREE(pCtx, iEscape); }
void sg_vv2__status__assert_in_work_queue(SG_context * pCtx, sg_vv2status * pST, sg_vv2status_od * pOD, SG_uint32 depthInQueue) { char buf[SG_GID_BUFFER_LENGTH + 20]; SG_bool bFound; sg_vv2status_od * pOD_test; SG_ERR_CHECK_RETURN( SG_sprintf(pCtx, buf,SG_NrElements(buf), "%08d.%s", depthInQueue,pOD->bufGidObject) ); SG_ERR_CHECK_RETURN( SG_rbtree__find(pCtx, pST->prbWorkQueue,buf,&bFound,(void **)&pOD_test) ); SG_ASSERT_RELEASE_RETURN2( (bFound), (pCtx, "Object [GID %s][depth %d] should have been in work-queue.", pOD->bufGidObject, depthInQueue) ); }
static void my_dump_id(SG_context * pCtx, const char* psz_hid, SG_uint32 nrDigits, SG_uint32 indent, SG_string * pStringOutput) { char buf[4000]; // we can abbreviate the full IDs. nrDigits = SG_MIN(nrDigits, SG_HID_MAX_BUFFER_LENGTH); nrDigits = SG_MAX(nrDigits, 4); // create: // Dagnode[addr]: <child_id> <gen> [<parent_id>...] SG_ERR_CHECK_RETURN( SG_sprintf(pCtx,buf,SG_NrElements(buf),"%*c ",indent,' ') ); SG_ERR_CHECK_RETURN( SG_string__append__sz(pCtx,pStringOutput,buf) ); SG_ERR_CHECK_RETURN( SG_string__append__buf_len(pCtx,pStringOutput,(SG_byte *)(psz_hid),nrDigits) ); SG_ERR_CHECK_RETURN( SG_string__append__sz(pCtx,pStringOutput,"\n") ); }
void sg_vv2__status__remove_from_work_queue(SG_context * pCtx, sg_vv2status * pST, sg_vv2status_od * pOD, SG_uint32 depthInQueue) { char buf[SG_GID_BUFFER_LENGTH + 20]; SG_ERR_CHECK_RETURN( SG_sprintf(pCtx, buf,SG_NrElements(buf), "%08d.%s", depthInQueue,pOD->bufGidObject) ); #if TRACE_VV2_STATUS SG_console(pCtx, SG_CS_STDERR, "TD_RMQUE [GID %s][minDepth %d] (short circuit)\n", pOD->bufGidObject,depthInQueue); SG_ERR_DISCARD; #endif SG_ERR_CHECK_RETURN( SG_rbtree__remove(pCtx,pST->prbWorkQueue,buf) ); }
/** * create (depth,ObjectGID) key and add entry to work-queue. */ void sg_vv2__status__add_to_work_queue(SG_context * pCtx, sg_vv2status * pST, sg_vv2status_od * pOD) { char buf[SG_GID_BUFFER_LENGTH + 20]; SG_ERR_CHECK_RETURN( SG_sprintf(pCtx, buf,SG_NrElements(buf), "%08d.%s", pOD->minDepthInTree,pOD->bufGidObject) ); #if TRACE_VV2_STATUS SG_console(pCtx, SG_CS_STDERR, "TD_ADQUE [GID %s][minDepth %d] type[%d,%d] depth[%d,%d]\n", pOD->bufGidObject,pOD->minDepthInTree, (int)((pOD->apInst[SG_VV2__OD_NDX_ORIG]) ? (int)pOD->apInst[SG_VV2__OD_NDX_ORIG]->typeInst : -1), (int)((pOD->apInst[SG_VV2__OD_NDX_DEST]) ? (int)pOD->apInst[SG_VV2__OD_NDX_DEST]->typeInst : -1), ((pOD->apInst[SG_VV2__OD_NDX_ORIG]) ? pOD->apInst[SG_VV2__OD_NDX_ORIG]->depthInTree : -1), ((pOD->apInst[SG_VV2__OD_NDX_DEST]) ? pOD->apInst[SG_VV2__OD_NDX_DEST]->depthInTree : -1)); SG_ERR_DISCARD; #endif SG_ERR_CHECK_RETURN( SG_rbtree__add__with_assoc(pCtx,pST->prbWorkQueue,buf,pOD) ); }
static void _sg_dagfrag__my_create_generation_sorted_member_cache_callback(SG_context * pCtx, const char * szKey, void * pAssocData, void * pVoidFrag) { // a standard SG_rbtree_foreach_callback. // // insert a parallel item in the SORTED CACHE for this item from the regular CACHE. // we only want items of type START_MEMBER and INTERIOR_MEMBER in our sorted cache. _my_data * pMyData = (_my_data *)pAssocData; SG_dagfrag * pFrag = (SG_dagfrag *)pVoidFrag; char bufSortKey[SG_HID_MAX_BUFFER_LENGTH + 20]; switch (pMyData->m_state) { default: //case SG_DFS_UNKNOWN: //case SG_DFS_END_FRINGE: return; case SG_DFS_START_MEMBER: case SG_DFS_INTERIOR_MEMBER: break; } // the sort key looks like <generation>.<hid> "%08lx.%s" SG_ERR_CHECK_RETURN( SG_sprintf(pCtx, bufSortKey,SG_NrElements(bufSortKey), "%08lx.%s", pMyData->m_genDagnode,szKey) ); SG_ERR_CHECK_RETURN( SG_rbtree__update__with_assoc(pCtx, pFrag->m_pRB_GenerationSortedMemberCache,bufSortKey,pMyData,NULL) ); }
void sg_pack__do_blob(SG_context* pCtx, const char* psz_gid, const char* psz_hid, SG_int32 gen, SG_rbtree* prb_blobs, SG_rbtree* prb_new) { SG_rbtree* prb = NULL; SG_bool b = SG_FALSE; char buf[64]; SG_ERR_CHECK( SG_rbtree__find(pCtx, prb_new, psz_hid, &b, NULL) ); if (b) { SG_ERR_CHECK( SG_rbtree__find(pCtx, prb_blobs, psz_gid, &b, (void**) &prb) ); if (!b) { SG_ERR_CHECK( SG_RBTREE__ALLOC(pCtx, &prb) ); SG_ERR_CHECK( SG_rbtree__add__with_assoc(pCtx, prb_blobs, psz_gid, prb) ); } SG_ERR_CHECK( SG_sprintf(pCtx, buf, sizeof(buf), "%05d", (int) gen) ); SG_ERR_CHECK( SG_rbtree__add__with_pooled_sz(pCtx, prb, buf, psz_hid) ); } return; fail: return; }
void MyFn(test__wide_dag)(SG_context* pCtx) { char bufTopDir[SG_TID_MAX_BUFFER_LENGTH]; SG_pathname* pPathTopDir = NULL; char buf_client_repo_name[SG_TID_MAX_BUFFER_LENGTH]; char buf_server_repo_name[SG_TID_MAX_BUFFER_LENGTH]; SG_pathname* pPathWorkingDir = NULL; SG_vhash* pvh = NULL; SG_repo* pClientRepo = NULL; SG_client* pClient = NULL; char* pszidFirstChangeset = NULL; SG_pathname* pPathCsDir = NULL; SG_uint32 lines; SG_uint32 i, j; SG_repo* pServerRepo = NULL; SG_bool bMatch = SG_FALSE; char buf_filename[7]; SG_varray* pvaZingMergeLog = NULL; SG_varray* pvaZingMergeErr = NULL; VERIFY_ERR_CHECK( SG_tid__generate2(pCtx, bufTopDir, sizeof(bufTopDir), 32) ); VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__SZ(pCtx,&pPathTopDir,bufTopDir) ); VERIFY_ERR_CHECK( SG_fsobj__mkdir__pathname(pCtx,pPathTopDir) ); VERIFY_ERR_CHECK( SG_tid__generate2(pCtx, buf_client_repo_name, sizeof(buf_client_repo_name), 32) ); VERIFY_ERR_CHECK( SG_tid__generate2(pCtx, buf_server_repo_name, sizeof(buf_server_repo_name), 32) ); INFOP("test__wide_dag", ("client repo: %s", buf_client_repo_name)); INFOP("test__wide_dag", ("server repo: %s", buf_server_repo_name)); /* create the repo */ VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pPathWorkingDir, pPathTopDir, buf_server_repo_name) ); VERIFY_ERR_CHECK( SG_fsobj__mkdir__pathname(pCtx, pPathWorkingDir) ); VERIFY_ERR_CHECK( _ut_pt__new_repo2(pCtx, buf_server_repo_name, pPathWorkingDir, &pszidFirstChangeset) ); /* open that repo */ VERIFY_ERR_CHECK( SG_repo__open_repo_instance(pCtx, buf_server_repo_name, &pServerRepo) ); /* create an empty clone to pull into */ VERIFY_ERR_CHECK( SG_repo__create_empty_clone(pCtx, buf_server_repo_name, buf_client_repo_name) ); VERIFY_ERR_CHECK( SG_repo__open_repo_instance(pCtx, buf_client_repo_name, &pClientRepo) ); /* add stuff to server repo */ for (i = 0; i < 20; i++) // number of changesets { VERIFY_ERR_CHECK( _ut_pt__set_baseline(pCtx, pPathWorkingDir, pszidFirstChangeset) ); VERIFY_ERR_CHECK( SG_sprintf(pCtx, buf_filename, sizeof(buf_filename), "%d", i) ); VERIFY_ERR_CHECK( SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &pPathCsDir, pPathWorkingDir, buf_filename) ); VERIFY_ERR_CHECK( SG_fsobj__mkdir__pathname(pCtx, pPathCsDir) ); for (j = 0; j < 1; j++) // number of files added per changeset { VERIFY_ERR_CHECK( SG_sprintf(pCtx, buf_filename, sizeof(buf_filename), "%d", j) ); lines = (int)(2500.0 * (rand() / (RAND_MAX + 1.0))); VERIFY_ERR_CHECK( MyFn(create_file__numbers)(pCtx, pPathCsDir, buf_filename, lines) ); } SG_PATHNAME_NULLFREE(pCtx, pPathCsDir); VERIFY_ERR_CHECK( _ut_pt__addremove(pCtx, pPathWorkingDir) ); VERIFY_ERR_CHECK( MyFn(commit_all)(pCtx, pPathWorkingDir, NULL) ); } /* verify pre-pull repos are different */ VERIFY_ERR_CHECK( SG_sync__compare_repo_dags(pCtx, pClientRepo, pServerRepo, &bMatch) ); VERIFY_COND_FAIL("pre-pull repos differ", !bMatch); /* get a client and pull from server repo to empty client repo */ VERIFY_ERR_CHECK( SG_client__open(pCtx, buf_server_repo_name, NULL_CREDENTIAL, &pClient) ); // TODO Credentials VERIFY_ERR_CHECK( SG_pull__all(pCtx, buf_client_repo_name, pClient, &pvaZingMergeErr, &pvaZingMergeLog) ); VERIFY_COND("", !pvaZingMergeErr); /* verify post-pull repos are identical */ VERIFY_ERR_CHECK( SG_sync__compare_repo_dags(pCtx, pClientRepo, pServerRepo, &bMatch) ); VERIFY_COND_FAIL("post-pull repo DAGs differ", bMatch); VERIFY_ERR_CHECK( SG_sync__compare_repo_blobs(pCtx, pClientRepo, pServerRepo, &bMatch) ); VERIFY_COND_FAIL("post-pull repo blobs differ", bMatch); VERIFY_ERR_CHECK( SG_repo__check_integrity(pCtx, pClientRepo, SG_REPO__CHECK_INTEGRITY__DAG_CONSISTENCY, SG_DAGNUM__VERSION_CONTROL, NULL, NULL) ); SG_REPO_NULLFREE(pCtx, pClientRepo); /* Make another copy with clone */ VERIFY_ERR_CHECK( SG_tid__generate2(pCtx, buf_client_repo_name, sizeof(buf_client_repo_name), 32) ); SG_ERR_CHECK( SG_repo__create_empty_clone_from_remote(pCtx, pClient, buf_client_repo_name) ); VERIFY_ERR_CHECK( SG_pull__clone(pCtx, buf_client_repo_name, pClient) ); /* verify post-clone repos are identical */ VERIFY_ERR_CHECK( SG_repo__open_repo_instance(pCtx, buf_client_repo_name, &pClientRepo) ); VERIFY_ERR_CHECK( SG_sync__compare_repo_dags(pCtx, pClientRepo, pServerRepo, &bMatch) ); VERIFY_COND_FAIL("post-clone repo DAGs differ", bMatch); VERIFY_ERR_CHECK( SG_sync__compare_repo_blobs(pCtx, pClientRepo, pServerRepo, &bMatch) ); VERIFY_COND_FAIL("post-clone repo blobs differ", bMatch); VERIFY_ERR_CHECK( SG_repo__check_integrity(pCtx, pClientRepo, SG_REPO__CHECK_INTEGRITY__DAG_CONSISTENCY, SG_DAGNUM__VERSION_CONTROL, NULL, NULL) ); /* TODO: verify more stuff? */ /* Fall through to common cleanup */ fail: /* close client */ SG_CLIENT_NULLFREE(pCtx, pClient); /* close both repos */ SG_REPO_NULLFREE(pCtx, pServerRepo); SG_REPO_NULLFREE(pCtx, pClientRepo); SG_NULLFREE(pCtx, pszidFirstChangeset); SG_PATHNAME_NULLFREE(pCtx, pPathTopDir); SG_PATHNAME_NULLFREE(pCtx, pPathWorkingDir); SG_PATHNAME_NULLFREE(pCtx, pPathCsDir); SG_VHASH_NULLFREE(pCtx, pvh); SG_PATHNAME_NULLFREE(pCtx, pPathWorkingDir); SG_VARRAY_NULLFREE(pCtx, pvaZingMergeLog); SG_VARRAY_NULLFREE(pCtx, pvaZingMergeErr); }
SG_error SG_context__err_stackframe_add(SG_context* pCtx, const char* szFilename, SG_uint32 linenum) { SG_error err = SG_ERR_OK; SG_uint32 len_needed; SG_uint32 len_avail; char buf[20]; SG_ASSERT( pCtx ); // SG_ASSERT( pCtx->level < SG_CONTEXT_MAX_ERROR_LEVELS ); if (pCtx->level > 0) // when in an error-on-error (level > 0), return SG_ERR_OK; // we don't add to the stack trace. SG_ASSERT( (szFilename && *szFilename) ); SG_ASSERT( (linenum) ); SG_ASSERT( (SG_IS_ERROR(pCtx->errValues[pCtx->level])) ); SG_ASSERT( (!pCtx->bStackTraceAtLimit) ); // do all of the formatting in an error-on-error level so that none of // the string manipulation trashes the current error context. // // ***DO NOT JUMP OUT OF THIS PUSH..POP BLOCK.*** SG_context__push_level(pCtx); { SG_uint32 lenFilename; SG_uint32 lenLineNr; SG_sprintf(pCtx, buf, sizeof(buf), "%d", linenum); lenLineNr = strlen(buf); lenFilename = strlen(szFilename); len_needed = lenFilename + lenLineNr + 3; // 3 == \t, :, and \n. // TODO should 5 be 6 to account for the NULL byte? // 5 == "\t...\n" len_avail = SG_NrElements(pCtx->szStackTrace) - pCtx->lenStackTrace - 5; if (len_needed > len_avail) { pCtx->bStackTraceAtLimit = SG_TRUE; memmove(&pCtx->szStackTrace[pCtx->lenStackTrace],"\t...\n",5); pCtx->lenStackTrace += 5; pCtx->szStackTrace[pCtx->lenStackTrace] = 0; } else { pCtx->szStackTrace[pCtx->lenStackTrace] = '\t'; pCtx->lenStackTrace++; memmove(&pCtx->szStackTrace[pCtx->lenStackTrace],szFilename,lenFilename); pCtx->lenStackTrace+=lenFilename; pCtx->szStackTrace[pCtx->lenStackTrace] = ':'; pCtx->lenStackTrace++; memmove(&pCtx->szStackTrace[pCtx->lenStackTrace],buf,lenLineNr); pCtx->lenStackTrace+=lenLineNr; pCtx->szStackTrace[pCtx->lenStackTrace] = '\n'; pCtx->lenStackTrace++; pCtx->szStackTrace[pCtx->lenStackTrace] = 0; } err = pCtx->errValues[pCtx->level]; // we return the error value from the formatting. } SG_context__pop_level(pCtx); return err; }