static curlioerr _my_ioctl__file(CURL *handle, int cmd, void *clientp) { _sg_curl* pMe = (_sg_curl*)clientp; SG_UNUSED(handle); if (cmd == CURLIOCMD_NOP) { SG_context__push_level(pMe->pCtx); SG_log__report_verbose(pMe->pCtx, "SG_curl handling CURLIOCMD_NOP."); SG_context__pop_level(pMe->pCtx); return CURLIOE_OK; } else if (cmd == CURLIOCMD_RESTARTREAD) { SG_context__push_level(pMe->pCtx); SG_log__report_verbose(pMe->pCtx, "SG_curl handling CURLIOCMD_RESTARTREAD."); SG_context__pop_level(pMe->pCtx); SG_file__seek(pMe->pCtx, pMe->readState.pFile, 0); if(SG_context__has_err(pMe->pCtx)) return CURLIOE_FAILRESTART; pMe->readState.pos = 0; pMe->readState.finished = SG_FALSE; return CURLIOE_OK; } else { return CURLIOE_UNKNOWNCMD; } }
static int _my_seek__file(void *instream, curl_off_t offset, int origin) { _sg_curl* pMe = (_sg_curl*)instream; if (origin == SEEK_SET) { SG_context__push_level(pMe->pCtx); SG_log__report_verbose(pMe->pCtx, "SG_curl handling SEEK_SET."); SG_context__pop_level(pMe->pCtx); SG_file__seek(pMe->pCtx, pMe->readState.pFile, (SG_uint64)offset); if(SG_context__has_err(pMe->pCtx)) return CURL_SEEKFUNC_FAIL; pMe->readState.pos = (SG_uint64)offset; pMe->readState.finished = SG_FALSE; return CURL_SEEKFUNC_OK; } else if (origin == SEEK_CUR) { SG_uint64 new_pos = (SG_uint64)((SG_int64)pMe->readState.pos+(SG_int64)offset); SG_context__push_level(pMe->pCtx); SG_log__report_verbose(pMe->pCtx, "SG_curl handling SEEK_CUR."); SG_context__pop_level(pMe->pCtx); SG_file__seek(pMe->pCtx, pMe->readState.pFile, new_pos); if(SG_context__has_err(pMe->pCtx)) return CURL_SEEKFUNC_FAIL; pMe->readState.pos = new_pos; pMe->readState.finished = SG_FALSE; return CURL_SEEKFUNC_OK; } else if (origin == SEEK_END) { SG_uint64 new_pos = (SG_uint64)((SG_int64)pMe->readState.len+(SG_int64)offset); SG_context__push_level(pMe->pCtx); SG_log__report_verbose(pMe->pCtx, "SG_curl handling SEEK_END."); SG_context__pop_level(pMe->pCtx); SG_file__seek(pMe->pCtx, pMe->readState.pFile, new_pos); if(SG_context__has_err(pMe->pCtx)) return CURL_SEEKFUNC_FAIL; pMe->readState.pos = new_pos; pMe->readState.finished = SG_FALSE; return CURL_SEEKFUNC_OK; } else { return CURL_SEEKFUNC_CANTSEEK; } }
SG_error SG_context__err_to_console(SG_context* pCtx, SG_console_stream cs) { SG_error err; SG_string* pErrStr = NULL; SG_ASSERT( pCtx ); // SG_ASSERT( pCtx->level < SG_CONTEXT_MAX_ERROR_LEVELS ); if (pCtx->level > 0) // when in an error-on-error (level > 0), there is NO error string. return SG_ERR_OK; // so we don't need to do anything. // get the full error string about the error at the current level. err = SG_context__err_to_string(pCtx, &pErrStr); if (SG_IS_ERROR(err)) // an allocation/formatting error, just give up. return err; // write the error string/message to the console. we push a new level // so that any problems converting the message to the user's locale or // writing to the console device don't trash the current error context. // // ***DO NOT JUMP OUT OF THIS PUSH..POP BLOCK.*** SG_context__push_level(pCtx); { SG_console(pCtx, cs, SG_string__sz(pErrStr)); err = pCtx->errValues[pCtx->level]; // we return the error value of the conversion/writing. } SG_context__pop_level(pCtx); SG_STRING_NULLFREE(pCtx, pErrStr); return err; }
SG_error SG_context__err_set_description(SG_context* pCtx, const char* szFormat, ...) { SG_error err; va_list ap; 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 alter the description. SG_ASSERT( (SG_IS_ERROR(pCtx->errValues[pCtx->level])) ); // assume __err or __err__generic just set error SG_context__push_level(pCtx); // format extra info on new level so that we don't trash error info in current level { va_start(ap,szFormat); SG_vsprintf_truncate(pCtx, pCtx->szDescription,SG_CONTEXT_LEN_DESCRIPTION + 1,szFormat,ap); va_end(ap); err = pCtx->errValues[pCtx->level]; // the error result of the sprintf } SG_context__pop_level(pCtx); return err; }
void MyFn(alloc__copy__deep)(SG_context * pCtx) { static const SG_uint32 uSize = 100u; SG_vector* pVector = NULL; SG_vector* pCopy = NULL; SG_uint32 uIndex = 0u; SG_uint32 uOutput1 = 0u; SG_uint32 uOutput2 = 0u; void* pOutput1 = NULL; void* pOutput2 = NULL; VERIFY_ERR_CHECK( SG_VECTOR__ALLOC(pCtx, &pVector, uSize) ); // add some allocated data to the vector for (uIndex = 0u; uIndex < uSize; ++uIndex) { SG_uint32* pValue = NULL; VERIFY_ERR_CHECK( SG_alloc1(pCtx, pValue) ); *pValue = uIndex; VERIFY_ERR_CHECK( SG_vector__append(pCtx, pVector, pValue, &uOutput1) ); VERIFY_COND("Added item has unexpected index.", uOutput1 == uIndex); } // copy the vector VERIFY_ERR_CHECK( SG_VECTOR__ALLOC__COPY(pCtx, pVector, MyFn(copy_uint32), MyFn(free_uint32), &pCopy) ); // verify that the copy matches the original VERIFY_ERR_CHECK( SG_vector__length(pCtx, pVector, &uOutput1) ); VERIFY_ERR_CHECK( SG_vector__length(pCtx, pCopy, &uOutput2) ); VERIFY_COND("Copied vector's length doesn't match added item count.", uOutput1 == uSize); VERIFY_COND("Copied vector's length doesn't match original.", uOutput1 == uOutput2); for (uIndex = 0u; uIndex < uOutput1; ++uIndex) { VERIFY_ERR_CHECK( SG_vector__get(pCtx, pVector, uIndex, &pOutput1) ); VERIFY_ERR_CHECK( SG_vector__get(pCtx, pCopy, uIndex, &pOutput2) ); VERIFYP_COND("Copied vector's pointer value matches original after deep copy.", pOutput1 != pOutput2, ("index(%d)", uIndex)); uOutput1 = *((SG_uint32*)pOutput1); uOutput2 = *((SG_uint32*)pOutput2); VERIFYP_COND("Copied vector's pointed-to value doesn't match original after deep copy.", uOutput1 == uOutput2, ("index(%d)", uIndex)); } fail: SG_context__push_level(pCtx); SG_vector__free__with_assoc(pCtx, pVector, MyFn(free_uint32)); SG_vector__free__with_assoc(pCtx, pCopy, MyFn(free_uint32)); SG_context__pop_level(pCtx); }
void SG_tag__remove(SG_context * pCtx, SG_repo * pRepo, const char* pszRev, SG_bool bRev, SG_uint32 count_args, const char** paszArgs) { SG_audit q; char* psz_hid_given = NULL; char* psz_hid_assoc_with_tag = NULL; SG_uint32 count_valid_tags = 0; const char** paszValidArgs = NULL; SG_uint32 i = 0; if (0 == count_args) return; SG_ERR_CHECK( SG_audit__init(pCtx,&q,pRepo,SG_AUDIT__WHEN__NOW,SG_AUDIT__WHO__FROM_SETTINGS) ); if (pszRev) { if (bRev) SG_repo__hidlookup__dagnode(pCtx, pRepo, SG_DAGNUM__VERSION_CONTROL, pszRev, &psz_hid_given); else SG_vc_tags__lookup__tag(pCtx, pRepo, pszRev, &psz_hid_given); if (SG_context__has_err(pCtx)) { if (SG_context__err_equals(pCtx, SG_ERR_AMBIGUOUS_ID_PREFIX)) { SG_context__push_level(pCtx); SG_console(pCtx, SG_CS_STDERR, "The revision or tag could not be found: %s\n", pszRev); SG_context__pop_level(pCtx); SG_ERR_RETHROW; } else SG_ERR_RETHROW; } } // SG_vc_tags__remove will throw on the first non-existant tag and stop // we don't want to issue errors, just warnings and keep going // weed out all the invalid tags here before calling SG_vc_tags__remove SG_ERR_CHECK( SG_alloc(pCtx, count_args, sizeof(const char*), &paszValidArgs) ); for (i =0; i < count_args; i++) { SG_ERR_CHECK( SG_vc_tags__lookup__tag(pCtx, pRepo, paszArgs[i], &psz_hid_assoc_with_tag) ); if (psz_hid_assoc_with_tag) // tag exists { if (psz_hid_given) { if (strcmp(psz_hid_given, psz_hid_assoc_with_tag) == 0) // tag is assoc with given changeset paszValidArgs[count_valid_tags++] = paszArgs[i]; else // tag not assoc with given changeset, no error, but warn SG_ERR_IGNORE( SG_console(pCtx, SG_CS_STDOUT, "Tag not associated with given revision: %s\n", paszArgs[i]) ); } else paszValidArgs[count_valid_tags++] = paszArgs[i]; } else { SG_ERR_IGNORE( SG_console(pCtx, SG_CS_STDOUT, "Tag not found: %s\n", paszArgs[i]) ); } SG_NULLFREE(pCtx, psz_hid_assoc_with_tag); psz_hid_assoc_with_tag = NULL; } SG_ERR_CHECK( SG_vc_tags__remove(pCtx, pRepo, &q, count_valid_tags, paszValidArgs) ); fail: SG_NULLFREE(pCtx, paszValidArgs); SG_NULLFREE(pCtx, psz_hid_given); SG_NULLFREE(pCtx, psz_hid_assoc_with_tag); }
SG_error SG_context__err_to_string(SG_context* pCtx, SG_string** ppErrString) { SG_error err = SG_ERR_OK; char szErr[SG_ERROR_BUFFER_SIZE]; SG_string* pTempStr = NULL; SG_uint32 lenRequired; SG_ASSERT( pCtx ); // SG_ASSERT( pCtx->level < SG_CONTEXT_MAX_ERROR_LEVELS ); if (!ppErrString) return SG_ERR_INVALIDARG; if (pCtx->level > 0) { // when in an error-on-error (level > 0), the error string DOES NOT belong to the // error context/level that we are in. The full message is only defined for the // original error that triggered things. *ppErrString = NULL; return SG_ERR_OK; } SG_error__get_message(pCtx->errValues[pCtx->level], szErr, sizeof(szErr)); lenRequired = ( strlen(szErr) + strlen(pCtx->szDescription) + pCtx->lenStackTrace + 100); // do all of the formatting in an error-on-error context/level // so that none of the string allocation/manipulation trashes // the current error context. // // ***DO NOT JUMP OUT OF THIS PUSH..POP BLOCK.*** SG_context__push_level(pCtx); { SG_STRING__ALLOC__RESERVE(pCtx,&pTempStr,lenRequired); if (SG_IS_OK(pCtx->errValues[pCtx->level])) { // since we pre-reserved all of the space we require, we // don't expect any of the appends to fail. So we can // ignore intermediate errors after each step. if one of // them does have a problem, the subsequent statements will // fail because we already have an error at this level. // either way, we don't care because we're going to pop the // level in a minute anyway. if (szErr[0] != 0) { SG_string__append__sz(pCtx, pTempStr, szErr); if (pCtx->szDescription[0] != 0) SG_string__append__sz(pCtx, pTempStr, ": "); else SG_string__append__sz(pCtx, pTempStr, "."); } if (pCtx->szDescription[0] != 0) SG_string__append__sz(pCtx, pTempStr, pCtx->szDescription); if (szErr[0] != 0 || pCtx->szDescription[0] != 0) SG_string__append__sz(pCtx, pTempStr, "\n"); SG_string__append__sz(pCtx, pTempStr, pCtx->szStackTrace); // if all of the formating works, we return the allocated string. // if not, we delete it and return the formatting error. if (SG_IS_OK(pCtx->errValues[pCtx->level])) *ppErrString = pTempStr; else SG_STRING_NULLFREE(pCtx, pTempStr); } err = pCtx->errValues[pCtx->level]; // we return the error value of the allocation/formatting } SG_context__pop_level(pCtx); return err; }
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; }