/** * Wrapper around SG_utf8__to_utf32 that allows empty strings. * I'm not sure why that function doesn't allow them, but I didn't want to change * something so low-level right now, so I'm wrapping it instead. Will log something * to have it looked into later. */ static void _utf8_to_utf32( SG_context* pCtx, //< [in] [out] Error and context info. const char* szUtf8, //< [in] UTF8 string to convert, may be empty but not NULL. SG_int32** ppUtf32, //< [out] Converted UTF32 string. SG_uint32* pLength //< [out] Length of converted UTF32 string, in characters. ) { SG_int32* pUtf32 = NULL; SG_uint32 uLength = 0u; SG_NULLARGCHECK(szUtf8); SG_NULLARGCHECK(ppUtf32); if (szUtf8[0] == 0) { SG_alloc1(pCtx, pUtf32); pUtf32[0] = 0; uLength = 0u; } else { SG_ERR_CHECK( SG_utf8__to_utf32__sz(pCtx, szUtf8, &pUtf32, &uLength) ); } *ppUtf32 = pUtf32; pUtf32 = NULL; if (pLength != NULL) { *pLength = uLength; } fail: SG_NULLFREE(pCtx, pUtf32); return; }
/** * Wrapper around SG_utf8__from_utf32 that allows empty strings. * I'm not sure why that function doesn't allow them, but I didn't want to change * something so low-level right now, so I'm wrapping it instead. Will log something * to have it looked into later. */ static void _utf32_to_utf8( SG_context* pCtx, //< [in] [out] Error and context info. SG_int32* pUtf32, //< [in] UTF32 string to convert, may be empty but not NULL. char** ppUtf8, //< [in] Converted UTF8 string. SG_uint32* pLength //< [out] Length of converted UTF32 string, in bytes. ) { char* szUtf8 = NULL; SG_uint32 uLength = 0u; SG_NULLARGCHECK(pUtf32); SG_NULLARGCHECK(ppUtf8); if (pUtf32[0] == 0) { SG_alloc1(pCtx, szUtf8); szUtf8[0] = 0; uLength = 1u; } else { SG_ERR_CHECK( SG_utf8__from_utf32(pCtx, pUtf32, &szUtf8, &uLength) ); } *ppUtf8 = szUtf8; szUtf8 = NULL; if (pLength != NULL) { *pLength = uLength; } fail: SG_NULLFREE(pCtx, szUtf8); return; }
void SG_mergereview__continue(SG_context * pCtx, SG_repo * pRepo, SG_varray * pContinuationToken, SG_bool singleMergeReview, SG_vhash * pMergeBaselines, SG_uint32 resultLimit, SG_varray ** ppResults, SG_uint32 * pCountResults, SG_varray ** ppContinuationToken) { _tree_t tree; SG_uint16 firstVariantType; SG_zero(tree); SG_ASSERT(pCtx!=NULL); SG_NULLARGCHECK(pRepo); SG_NULLARGCHECK(pContinuationToken); if(resultLimit==0) resultLimit = SG_UINT32_MAX; SG_NULLARGCHECK(ppResults); SG_ERR_CHECK( SG_varray__typeof(pCtx, pContinuationToken, 0, &firstVariantType) ); if(firstVariantType==SG_VARIANT_TYPE_SZ) { const char * szHead = NULL; SG_ERR_CHECK( SG_varray__get__sz(pCtx, pContinuationToken, 0, &szHead) ); SG_ERR_CHECK( _tree__init(pCtx, &tree, szHead, pRepo) ); } else { SG_ERR_CHECK( _tree__init__continuation(pCtx, &tree, pContinuationToken, pRepo) ); } SG_ERR_CHECK( _sg_mergereview(pCtx, &tree, singleMergeReview, SG_FALSE, pMergeBaselines, resultLimit, ppResults, pCountResults, ppContinuationToken) ); _tree__uninit(pCtx, &tree); return; fail: _tree__uninit(pCtx, &tree); }
void SG_password__get( SG_context *pCtx, const char *szRepoSpec, const char *username, SG_string **pPassword) { SG_byte *pwdata = NULL; SG_uint32 pwlen; SG_string *password = NULL; SG_string *path = NULL; SG_string *server = NULL; SecProtocolType proto; SG_uint32 port; SG_bool isValid = SG_FALSE; OSStatus findRes; SG_NULLARGCHECK_RETURN(pPassword); *pPassword = NULL; SG_NULLARGCHECK(username); SG_NULLARGCHECK(szRepoSpec); SG_ERR_CHECK( _sg_password__parse_url(pCtx, szRepoSpec, &isValid, &proto, &server, &path, &port) ); if (! isValid) SG_ERR_THROW(SG_ERR_NOTIMPLEMENTED); findRes = SecKeychainFindInternetPassword( NULL, SG_STRLEN( SG_string__sz(server) ), SG_string__sz(server), 0, NULL, SG_STRLEN(username), username, SG_STRLEN( SG_string__sz(path) ), SG_string__sz(path), port, proto, kSecAuthenticationTypeDefault, (UInt32 *)&pwlen, (void **)&pwdata, NULL); if (findRes == errSecItemNotFound || findRes == errSecInteractionNotAllowed) goto fail; else if (findRes != errSecSuccess) _SG_THROW_MAC_SEC_ERROR(findRes); SG_ERR_CHECK( SG_STRING__ALLOC__BUF_LEN(pCtx, &password, pwdata, pwlen) ); *pPassword = password; password = NULL; fail: if (pwdata) SecKeychainItemFreeContent(NULL, pwdata); SG_STRING_NULLFREE(pCtx, path); SG_STRING_NULLFREE(pCtx, server); SG_STRING_NULLFREE(pCtx, password); }
void SG_password__set( SG_context* pCtx, const char *szRepoSpec, SG_string *pUserName, SG_string *pPassword) { const char *username; const char *password; SG_string *path = NULL; SG_string *server = NULL; SG_string *proto = NULL; SG_uint32 port; SG_bool isValid = SG_FALSE; GnomeKeyringResult saveRes = 0; guint32 itemid = 0; if (! SG_password__supported()) goto fail; SG_NULLARGCHECK(pUserName); SG_NULLARGCHECK(pPassword); SG_NULLARGCHECK(szRepoSpec); username = SG_string__sz(pUserName); password = SG_string__sz(pPassword); SG_ERR_CHECK( _sg_password__parse_url(pCtx, szRepoSpec, &isValid, &proto, &server, &path, &port) ); if (! isValid) SG_ERR_THROW(SG_ERR_NOTIMPLEMENTED); saveRes = gnome_keyring_set_network_password_sync( NULL, username, NULL, SG_string__sz(server), SG_string__sz(path), SG_string__sz(proto), NULL, (guint32)port, password, &itemid); if ((saveRes != GNOME_KEYRING_RESULT_OK) && (saveRes != GNOME_KEYRING_RESULT_NO_MATCH) && (saveRes != GNOME_KEYRING_RESULT_CANCELLED)) _SG_THROW_LINUX_SEC_ERROR(saveRes); fail: SG_STRING_NULLFREE(pCtx, path); SG_STRING_NULLFREE(pCtx, server); SG_STRING_NULLFREE(pCtx, proto); }
void sg_wc__status__find_status__single_item(SG_context * pCtx, const SG_varray * pva_statuses, const char * psz_repo_path, //This must be the repo path, exactly as it appears in the status results. SG_vhash ** ppvh_status_result) { SG_vhash * pvh_status = NULL; SG_uint32 nArraySize = 0; SG_uint32 index = 0; const char * psz_repo_path_to_check = NULL; SG_bool bFound = SG_FALSE; SG_NULLARGCHECK(pva_statuses); SG_ERR_CHECK( SG_varray__count(pCtx, pva_statuses, &nArraySize) ); for (index = 0; index < nArraySize; index++) { SG_ERR_CHECK( SG_varray__get__vhash(pCtx, pva_statuses, index, &pvh_status) ); SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvh_status, "path", &psz_repo_path_to_check) ); if (SG_strcmp__null(psz_repo_path, psz_repo_path_to_check) == 0) { bFound = SG_TRUE; break; } } if (bFound) SG_RETURN_AND_NULL(pvh_status, ppvh_status_result); fail: return; }
void SG_validate__sanitize__trim( 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 ) { char* szTrimmed = NULL; SG_NULLARGCHECK(ppSanitized); // trim the value (will return NULL if the value is NULL or trims to nothing) SG_ERR_CHECK( SG_sz__trim(pCtx, szValue, NULL, &szTrimmed) ); // sanitize the trimmed value if (szTrimmed == NULL) { SG_ERR_CHECK( SG_validate__sanitize(pCtx, "", uMin, uMax, szInvalids, uFixFlags, szReplace, szAdd, ppSanitized) ); } else { SG_ERR_CHECK( SG_validate__sanitize(pCtx, szTrimmed, uMin, uMax, szInvalids, uFixFlags, szReplace, szAdd, ppSanitized) ); } fail: SG_NULLFREE(pCtx, szTrimmed); return; }
void sg_repo__bind_vtable(SG_context* pCtx, SG_repo * pRepo, const char * pszStorage) { SG_uint32 count_vtables = 0; SG_NULLARGCHECK(pRepo); if (pRepo->p_vtable) // can only be bound once { SG_ERR_THROW2(SG_ERR_INVALIDARG, (pCtx, "pRepo->p_vtable is already bound")); } if (pRepo->pvh_descriptor) { SG_ERR_THROW2(SG_ERR_INVALIDARG, (pCtx, "pRepo->pvh_descriptor is already bound")); } if (!g_prb_repo_vtables) { SG_ERR_THROW2(SG_ERR_UNKNOWN_STORAGE_IMPLEMENTATION, (pCtx, "There are no repo storage plugins installed")); } SG_ERR_CHECK( SG_rbtree__count(pCtx, g_prb_repo_vtables, &count_vtables) ); if (0 == count_vtables) { SG_ERR_THROW2(SG_ERR_UNKNOWN_STORAGE_IMPLEMENTATION, (pCtx, "There are no repo storage plugins installed")); } if (!pszStorage || !*pszStorage) { if (1 == count_vtables) { SG_bool b = SG_FALSE; SG_ERR_CHECK( SG_rbtree__iterator__first(pCtx, NULL, g_prb_repo_vtables, &b, NULL, (void**) &pRepo->p_vtable) ); SG_ASSERT(pRepo->p_vtable); } else { SG_ERR_THROW2(SG_ERR_UNKNOWN_STORAGE_IMPLEMENTATION, (pCtx, "Multiple repo storage plugins installed. Must specify.")); } } else { SG_bool b = SG_FALSE; SG_ERR_CHECK( SG_rbtree__find(pCtx, g_prb_repo_vtables, pszStorage, &b, (void**) &pRepo->p_vtable) ); if (!b || !pRepo->p_vtable) { SG_ERR_THROW(SG_ERR_UNKNOWN_STORAGE_IMPLEMENTATION); } } fail: ; }
void SG_mergereview(SG_context * pCtx, SG_repo * pRepo, const char * szHidHead, SG_bool singleMergeReview, SG_vhash * pMergeBaselines, SG_uint32 resultLimit, SG_varray ** ppResults, SG_uint32 * pCountResults, SG_varray ** ppContinuationToken) { _tree_t tree; SG_ASSERT(pCtx!=NULL); SG_NULLARGCHECK(pRepo); SG_NONEMPTYCHECK(szHidHead); if(resultLimit==0) resultLimit = SG_UINT32_MAX; SG_NULLARGCHECK(ppResults); SG_ERR_CHECK( _tree__init(pCtx, &tree, szHidHead, pRepo) ); SG_ERR_CHECK( _sg_mergereview(pCtx, &tree, singleMergeReview, SG_TRUE, pMergeBaselines, resultLimit, ppResults, pCountResults, ppContinuationToken) ); _tree__uninit(pCtx, &tree); return; fail: _tree__uninit(pCtx, &tree); }
/** * Create a label for one side of a UNIFIED DIFF. This will appear on one of * the header lines after the "+++ " or "--- ". (We DO NOT create the "+++ " * portion.) * * Gnu-diff (when --label is not used) creates something like: * +++ %s\t%s with the file's relative pathname and date-time-modified. * * --- d1/date2 1970-01-01 00:00:00.000000000 +0000 * +++ d2/date2 2009-04-30 13:10:57.000000000 +0000 * * BZR's diff command creates something like: * * --- d2/date2 2009-04-30 12:38:41 +0000 * +++ d2/date2 2009-04-30 13:10:57 +0000 * * GIT's diff command creates something like: * * --- a/eeeeee.txt * +++ b/eeeeee.txt * * So, we can pretty much do whatever we want here. * * I'm going to try the following and see if we like it: * [] for a historical version, print: * +++ %s\t%s with the repo-path and the HID. * * we don't have a valid date-stamp to print. (our caller might have * the date-stamp on the changeset, but that doesn't have anything to * to with the date on an indivdual file (the file might not have even * been modified in that changeset). * * the HID may be useful later. * * [] for a working-directory version, print: * +++ %s\t%s with the repo-path and the live date-time-stamp. * * since the file is in the working-directory, the date stamp has * some validity (it doesn't mean that they changed the file or reflect * the last change (it could be date of the last get-latest for all we * know)). * * [] just for sanity, we allow a repo-path only version: * +++ %s * * In all cases we print the complete repo-path "@/a/b/c/foo.c". * The repo-path is as computed in SG_treediff2 and reflects all pathname * renames/moves. * * TODO do we care about feeding this output to PATCH and how it digests * pathnames and with the various -p0 -p1 ... arguments? * * We return a string that you must free. */ void SG_diff_utils__make_label(SG_context * pCtx, const char * szRepoPath, const char * szHid, const char * szDate, SG_string ** ppStringLabel) { SG_string * pString = NULL; SG_NONEMPTYCHECK_RETURN(szRepoPath); if (szHid && szDate) // allow zero or one, but not both SG_ERR_THROW_RETURN( SG_ERR_INVALIDARG ); SG_NULLARGCHECK(ppStringLabel); SG_ERR_CHECK_RETURN( SG_STRING__ALLOC(pCtx,&pString) ); ////////////////////////////////////////////////////////////////// // WARNING: All of the input arguments are in our internal NFC UTF-8 format // WARNING: (as is everything). SG_exec__() will convert whatever we construct // WARNING: here to an os-buffer (utf-8, locale, or wchar_t) before giving it // WARNING: to execvp() or CreateProcessW(). // WARNING: // WARNING: I *think* this is what we want. // WARNING: // WARNING: We can't be sure how the child process will handle the label text // WARNING: when it prints it to its STDOUT. This may cause some confusion. // WARNING: For example, NFC/NFD issues on MAC or some '?' characters getting // WARNING: printed by cygwin's version of gnu-diff and etc. // WARNING: // WARNING: I don't know if there are actually any issues here or not or if // WARNING: so whether they will cause a problem. ////////////////////////////////////////////////////////////////// if (szHid) SG_ERR_CHECK( SG_string__sprintf(pCtx, pString,"%s\t%s", szRepoPath,szHid) ); else if (szDate) SG_ERR_CHECK( SG_string__sprintf(pCtx, pString,"%s\t%s", szRepoPath,szDate) ); else SG_ERR_CHECK( SG_string__set__sz(pCtx,pString,szRepoPath) ); *ppStringLabel = pString; return; fail: SG_STRING_NULLFREE(pCtx, pString); }
void SG_validate__check__trim( SG_context* pCtx, const char* szValue, SG_uint32 uMin, SG_uint32 uMax, const char* szInvalids, SG_bool bControls, SG_uint32* pResult, char** ppTrimmed ) { char* szTrimmed = NULL; SG_NULLARGCHECK(pResult); // trim the value (will return NULL if the value is NULL or trims to nothing) SG_ERR_CHECK( SG_sz__trim(pCtx, szValue, NULL, &szTrimmed) ); // validate the trimmed value if (szTrimmed == NULL) { SG_ERR_CHECK( SG_validate__check(pCtx, "", uMin, uMax, szInvalids, bControls, pResult) ); } else { SG_ERR_CHECK( SG_validate__check(pCtx, szTrimmed, uMin, uMax, szInvalids, bControls, pResult) ); } // if it's valid and they want the trimmed value, return it if (*pResult == SG_VALIDATE__RESULT__VALID && ppTrimmed != NULL) { *ppTrimmed = szTrimmed; szTrimmed = NULL; } fail: SG_NULLFREE(pCtx, szTrimmed); return; }
static void make_request( SG_context* pCtx, const char* pszUrl, const char* psz_method, const char* psz_data, CFHTTPMessageRef* pp ) { CFStringRef url = NULL; CFURLRef myURL = NULL; CFStringRef requestMethod = NULL; CFHTTPMessageRef myRequest = NULL; url = CFStringCreateWithCString(kCFAllocatorDefault, pszUrl,kCFStringEncodingUTF8); SG_NULLARGCHECK(url); myURL = CFURLCreateWithString(kCFAllocatorDefault, url, NULL); SG_NULLARGCHECK(myURL); requestMethod = CFStringCreateWithCString(kCFAllocatorDefault, psz_method,kCFStringEncodingUTF8); SG_NULLARGCHECK(requestMethod); myRequest = CFHTTPMessageCreateRequest( kCFAllocatorDefault, requestMethod, myURL, kCFHTTPVersion1_1 ); SG_NULLARGCHECK(myRequest); if (psz_data) { CFStringRef s = CFStringCreateWithCString(kCFAllocatorDefault, psz_data, kCFStringEncodingUTF8); CFDataRef bodyData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, s, kCFStringEncodingUTF8, 0); CFRelease(s); CFHTTPMessageSetBody(myRequest, bodyData); CFRelease(bodyData); } *pp = myRequest; myRequest = NULL; fail: if (myRequest) { CFRelease(myRequest); myRequest = NULL; } if (myURL) { CFRelease(myURL); myURL = NULL; } if (requestMethod) { CFRelease(requestMethod); requestMethod = NULL; } if (url) { CFRelease(url); url = NULL; } }
void SG_password__set( SG_context *pCtx, const char *szRepoSpec, SG_string *pUserName, SG_string *pPassword) { const char *username, *password; SG_string *path = NULL; SG_string *server = NULL; SecProtocolType proto; SG_uint32 port; SG_bool isValid = SG_FALSE; OSStatus saveRes, findRes; SecKeychainItemRef item = NULL; SG_NULLARGCHECK(pUserName); SG_NULLARGCHECK(pPassword); SG_NULLARGCHECK(szRepoSpec); username = SG_string__sz(pUserName); password = SG_string__sz(pPassword); SG_ERR_CHECK( _sg_password__parse_url(pCtx, szRepoSpec, &isValid, &proto, &server, &path, &port) ); if (! isValid) SG_ERR_THROW(SG_ERR_NOTIMPLEMENTED); findRes = SecKeychainFindInternetPassword( NULL, SG_STRLEN( SG_string__sz(server) ), SG_string__sz(server), 0, NULL, SG_STRLEN(username), username, SG_STRLEN( SG_string__sz(path) ), SG_string__sz(path), port, proto, kSecAuthenticationTypeDefault, NULL, NULL, &item); if (findRes == errSecSuccess) { saveRes = SecKeychainItemModifyAttributesAndData(item, NULL, SG_STRLEN(password), password); } else { saveRes = SecKeychainAddInternetPassword( NULL, SG_STRLEN( SG_string__sz(server) ), SG_string__sz(server), 0, NULL, SG_STRLEN(username), username, SG_STRLEN( SG_string__sz(path) ), SG_string__sz(path), port, proto, kSecAuthenticationTypeDefault, SG_STRLEN(password), password, NULL); } if (saveRes != errSecSuccess) _SG_THROW_MAC_SEC_ERROR(saveRes); fail: if (item) CFRelease(item); SG_STRING_NULLFREE(pCtx, path); SG_STRING_NULLFREE(pCtx, server); }
static void _sg_password__parse_url( SG_context *pCtx, const char *url, SG_bool *pIsValid, SG_string **ppProto, SG_string **ppServer, SG_string **ppPath, SG_uint32 *pPort ) { const char *slash, *colon, *ss; SG_string *server = NULL; SG_string *path = NULL; SG_string *proto = NULL; SG_NULLARGCHECK(url); *pIsValid = SG_FALSE; if (strncmp("http://", url, 7) == 0) { SG_ERR_CHECK( SG_STRING__ALLOC__SZ(pCtx, &proto, "http") ); *pPort = 80; url += 7; } else if (strncmp("https://", url, 8) == 0) { SG_ERR_CHECK( SG_STRING__ALLOC__SZ(pCtx, &proto, "https") ); *pPort = 443; url += 8; } else goto fail; slash = strchr(url, '/'); if (! slash) goto fail; SG_ERR_CHECK( SG_STRING__ALLOC__BUF_LEN(pCtx, &server, (const SG_byte *)url, (SG_uint32)(slash - url)) ); ss = SG_string__sz(server); colon = strchr(ss, ':'); if (colon) { SG_uint32 port = atoi(colon + 1); SG_uint32 plen = colon - ss; if (port == 0) goto fail; *pPort = port; SG_ERR_CHECK( SG_string__remove(pCtx, server, plen, SG_STRLEN(ss) - plen) ); } SG_ERR_CHECK( SG_STRING__ALLOC__SZ(pCtx, &path, "/") ); *ppPath = path; path = NULL; *ppServer = server; server = NULL; *ppProto = proto; proto = NULL; *pIsValid = SG_TRUE; fail: SG_STRING_NULLFREE(pCtx, server); SG_STRING_NULLFREE(pCtx, path); SG_STRING_NULLFREE(pCtx, proto); }
void SG_password__get( SG_context *pCtx, const char *szRepoSpec, const char *username, SG_string **ppstrPassword) { SG_string *password = NULL; SG_string *path = NULL; SG_string *server = NULL; SG_string *proto = NULL; SG_uint32 port; SG_bool isValid = SG_FALSE; GnomeKeyringResult saveRes = 0; GList *results = NULL; guint count = 0; SG_NULLARGCHECK(username); SG_NULLARGCHECK(ppstrPassword); SG_NULLARGCHECK(szRepoSpec); if (! SG_password__supported()) goto fail; SG_ERR_CHECK( _sg_password__parse_url(pCtx, szRepoSpec, &isValid, &proto, &server, &path, &port) ); if (! isValid) SG_ERR_THROW(SG_ERR_NOTIMPLEMENTED); saveRes = gnome_keyring_find_network_password_sync( username, NULL, SG_string__sz(server), SG_string__sz(path), SG_string__sz(proto), NULL, (guint32)port, &results); if ((saveRes != GNOME_KEYRING_RESULT_OK) && (saveRes != GNOME_KEYRING_RESULT_NO_MATCH) && (saveRes != GNOME_KEYRING_RESULT_CANCELLED)) _SG_THROW_LINUX_SEC_ERROR(saveRes); if (results != NULL) count = g_list_length(results); if (count > 0) { const char *pw = ""; GnomeKeyringNetworkPasswordData *entry = g_list_nth_data(results, 0); SG_ASSERT(entry != NULL); if (entry->password) pw = entry->password; SG_ERR_CHECK( SG_string__alloc__sz(pCtx, &password, pw) ); } *ppstrPassword = password; password = NULL; fail: SG_STRING_NULLFREE(pCtx, path); SG_STRING_NULLFREE(pCtx, server); SG_STRING_NULLFREE(pCtx, proto); SG_STRING_NULLFREE(pCtx, password); if (results) gnome_keyring_network_password_list_free(results); }
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; }
/** * Finds any character from a given set within a string and replaces them with a * specified replacement string. */ static void _replace_chars_with_string( SG_context* pCtx, //< [in] [out] Error and context info. SG_string* sValue, //< [in] [out] String to perform replacements in. const char* szChars, //< [in] Set of characters to replace, as a string. //< NULL is treated as an empty string. const char* szReplacement //< [in] String to use as a replacement for the characters. //< This whole string is a replacement for each found character. //< NULL is treated as an empty string. ) { SG_int32* pValue32 = NULL; SG_uint32 uValue32 = 0u; SG_int32* pChars32 = NULL; SG_uint32 uChars32 = 0u; SG_int32* pReplacement32 = NULL; SG_uint32 uReplacement32 = 0u; SG_int32* pResult32 = NULL; SG_uint32 uResult32 = 0u; char* szResult = NULL; SG_uint32 uResult = 0u; SG_uint32 uValueIndex = 0u; SG_NULLARGCHECK(sValue); // treat NULLs as empty strings if (szChars == NULL) { szChars = ""; } if (szReplacement == NULL) { szReplacement = ""; } // convert everything to UTF32 // I couldn't come up with a way to do this directly in UTF8 using the APIs // available in sg_utf8. SG_ERR_CHECK( _utf8_to_utf32(pCtx, SG_string__sz(sValue), &pValue32, &uValue32) ); SG_ERR_CHECK( _utf8_to_utf32(pCtx, szChars, &pChars32, &uChars32) ); SG_ERR_CHECK( _utf8_to_utf32(pCtx, szReplacement, &pReplacement32, &uReplacement32) ); // allocate a result buffer if (uReplacement32 > 1u) { // largest possible size we could end up with is if we replace every single // character in the value with the replacement string SG_ERR_CHECK( SG_allocN(pCtx, (uReplacement32 * uValue32) + 1u, pResult32) ); } else { // largest possible size we could end up with is if we do no replacements // at all and are left with exactly the input value SG_ERR_CHECK( SG_allocN(pCtx, uValue32 + 1u, pResult32) ); } // run through each character in the value for (uValueIndex = 0u; uValueIndex < uValue32; ++uValueIndex) { SG_int32 iValueChar = pValue32[uValueIndex]; SG_bool bReplace = SG_FALSE; SG_uint32 uCharsIndex = 0u; // check if this character should be replaced for (uCharsIndex = 0u; uCharsIndex < uChars32; ++uCharsIndex) { if (iValueChar == pChars32[uCharsIndex]) { bReplace = SG_TRUE; break; } } if (bReplace == SG_FALSE) { // append the character to the output pResult32[uResult32] = iValueChar; ++uResult32; } else { // append the replacement string to the output memcpy((void*)(pResult32 + uResult32), (void*)pReplacement32, uReplacement32 * sizeof(SG_int32)); uResult32 += uReplacement32; } } // NULL-terminate the result and convert it back to UTF8 pResult32[uResult32] = 0; SG_ERR_CHECK( _utf32_to_utf8(pCtx, pResult32, &szResult, &uResult) ); // return the result by replacing the original value's contents SG_ERR_CHECK( SG_string__adopt_buffer(pCtx, sValue, szResult, uResult) ); szResult = NULL; fail: SG_NULLFREE(pCtx, pValue32); SG_NULLFREE(pCtx, pChars32); SG_NULLFREE(pCtx, pReplacement32); SG_NULLFREE(pCtx, pResult32); SG_NULLFREE(pCtx, szResult); return; }
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); }
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) ); } }