static void _check_for_and_handle_json_500(SG_context* pCtx, SG_curl* pCurl, char* buffer, SG_uint32 bufLen) { SG_int32 responseCode = 0; _sg_curl* pMe = (_sg_curl*)pCurl; SG_ERR_CHECK( SG_curl__getinfo__int32(pCtx, pCurl, CURLINFO_RESPONSE_CODE, &responseCode) ); if (responseCode == 500 || responseCode == 410) { if (pMe->pstrErr == NULL) { SG_int32 lenResponse = 0; /* We assume an HTTP 500 response will be small enough to fit into an SG_string. */ SG_ERR_CHECK( SG_curl__getinfo__int32(pCtx, pCurl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &lenResponse) ); if (lenResponse > 0) SG_ERR_CHECK( SG_STRING__ALLOC__RESERVE(pCtx, &pMe->pstrErr, (SG_uint32)lenResponse + 1) ); else SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &pMe->pstrErr) ); } SG_ERR_CHECK( SG_string__append__buf_len(pCtx, pMe->pstrErr, (const SG_byte*)buffer, bufLen) ); } fail: ; }
// http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTHEADERFUNCTION static size_t _read_header( void *ptr, size_t size, size_t nmemb, void *userdata) { _sg_curl * pMe = (_sg_curl*)userdata; SG_context * pCtx = pMe->pCtx; SG_ERR_IGNORE( SG_string__append__buf_len(pCtx, pMe->pstrRawHeaders, (SG_byte*)ptr, (SG_uint32) (size * nmemb)) ); return size * nmemb; }
static void _write_string_chunk(SG_context* pCtx, SG_curl* pCurl, char* buffer, SG_uint32 bufLen, void* pVoidState, SG_uint32* pLenHandled) { SG_string* pstrResponse = (SG_string*)pVoidState; //_sg_curl* pMe = (_sg_curl*)pCurl; *pLenHandled = 0; SG_ERR_CHECK_RETURN( _check_for_and_handle_json_500(pCtx, pCurl, buffer, bufLen) ); if (bufLen) // libcurl docs say we may be called with zero length if file is empty { if (pstrResponse) SG_ERR_CHECK_RETURN( SG_string__append__buf_len(pCtx, pstrResponse, (const SG_byte*)buffer, bufLen) ); *pLenHandled = bufLen; } }
void _read_template_file( SG_context *pCtx, const char *templateFn, SG_string **pContent, /**< we allocate, we free on error, else caller owns it */ const _request_headers *pRequestHeaders, _replacer_cb replacer) { SG_pathname *tpath = NULL; SG_file *pFile = NULL; SG_uint32 got = 0; char tbuf[1024]; //todo: make this thread-safe: if(_sg_uridispatch__templatePath==NULL) SG_ERR_CHECK( _sgui_set_templatePath(pCtx) ); SG_ERR_CHECK( SG_PATHNAME__ALLOC__COPY(pCtx, &tpath, _sg_uridispatch__templatePath) ); SG_ERR_CHECK( SG_pathname__append__from_sz(pCtx, tpath, templateFn) ); SG_ERR_CHECK( SG_file__open__pathname(pCtx, tpath, SG_FILE_RDONLY|SG_FILE_OPEN_EXISTING, 0644, &pFile) ); SG_PATHNAME_NULLFREE(pCtx, tpath); SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, pContent) ); do { SG_file__read(pCtx, pFile, sizeof(tbuf), (SG_byte *)tbuf, &got); if (SG_context__err_equals(pCtx, SG_ERR_EOF)) { SG_context__err_reset(pCtx); break; } SG_ERR_CHECK_CURRENT; SG_ERR_CHECK( SG_string__append__buf_len(pCtx, *pContent, (const SG_byte *)tbuf, got) ); } while (got > 0); SG_ERR_CHECK( SG_file__close(pCtx, &pFile) ); SG_ERR_CHECK( _templatize(pCtx, *pContent, pRequestHeaders, replacer) ); return; fail: SG_STRING_NULLFREE(pCtx, *pContent); SG_FILE_NULLCLOSE(pCtx, pFile); SG_PATHNAME_NULLFREE(pCtx, tpath); }
/** * Construct a pathname to a personal TEMP directory within the WD * and hidden in .sgdrawer. This directory will be used for the various * versions of a single file/item so that we can use external tools * during the AUTOMERGE and/or RESOLVE. * * We want this temp directory to be local to the WD (so that files can be * moved/linked rather than copied -- both for input to diff3 and for the * auto-merge result -- IF THAT IS APPROPRIATE. (And so that we don't have * to create a bunch of trash in the user's WD.) * * We want this TEMP directory to be for the duration of the MERGE/RESOLVE/ * COMMIT effort. That is, if MERGE needs to create a set of Ancestor/Mine/ * Other files for an unresolved file conflict, RESOLVE will know where to * find them and COMMIT will clean up the mess. This allows RESOLVE to have * a "redo-merge" option with a different tool, for example. It also allows * us to keep the trash out of the working directory -- both for neatness * and to avoid having baggage if there is also a move/rename for the file. * * We create a pathname and store it in the conflict structure * so that all versions of this file in this conflict can use it. * * The directory on disk should be deleted when this item has been committed * or reverted and the pvhIssue has been deleted. (I'm not talking about * resolve here.) * */ static void _sg_mrg__ensure_temp_dir_for_file_conflict(SG_context * pCtx, SG_mrg * pMrg, SG_mrg_cset_entry_conflict * pMrgCSetEntryConflict) { SG_string * pString = NULL; const SG_byte * pszGid = (const SG_byte *)pMrgCSetEntryConflict->pMrgCSetEntry_Ancestor->bufGid_Entry; if (pMrgCSetEntryConflict->pPathTempDirForFile) return; // create something like: "<sgtemp>/<gid7>_YYYYMMDD_<k>/" SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &pString) ); SG_ERR_CHECK( SG_string__append__buf_len(pCtx, pString, pszGid, 7) ); SG_ERR_CHECK( SG_workingdir__generate_and_create_temp_dir_for_purpose(pCtx, pMrg->pWcTx->pDb->pPathWorkingDirectoryTop, SG_string__sz(pString), &pMrgCSetEntryConflict->pPathTempDirForFile) ); fail: SG_STRING_NULLFREE(pCtx, pString); }
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") ); }
static void read_entire_stream__string( SG_context* pCtx, CFReadStreamRef myReadStream, SG_string** ppstr, CFHTTPMessageRef* pp ) { SG_string* pstr = NULL; CFHTTPMessageRef myResponse = NULL; CFIndex numBytesRead = 0; SG_ERR_CHECK( SG_string__alloc__sz(pCtx, &pstr, "") ); do { UInt8 buf[8192]; // TODO numBytesRead = CFReadStreamRead(myReadStream, buf, sizeof(buf)); if( numBytesRead > 0 ) { SG_ERR_CHECK( SG_string__append__buf_len(pCtx, pstr, buf, numBytesRead) ); if (!myResponse) { myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader); } } else if( numBytesRead < 0 ) { CFStreamError myErr = CFReadStreamGetError(myReadStream); // TODO clean this up if (myErr.domain == kCFStreamErrorDomainPOSIX) { if (ETIMEDOUT == myErr.error) { usleep(5000); numBytesRead = 0; } else { // Interpret myErr.error as a UNIX errno. SG_ERR_THROW( SG_ERR_ERRNO(myErr.error) ); } } else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) { // Interpret myErr.error as a MacOS error code. // TODO SG_ERR_THROW( SG_ERR_MAC((OSStatus) myErr.error) ); SG_ERR_THROW( SG_ERR_UNSPECIFIED ); } } } while( numBytesRead > 0 ); if (!myResponse) { myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader); } *pp = myResponse; myResponse = NULL; *ppstr = pstr; pstr = NULL; fail: if (myResponse) { CFRelease(myResponse); } SG_STRING_NULLFREE(pCtx, pstr); }
void my_strip_comments( SG_context* pCtx, char* pjson, SG_string** ppstr ) { char *p = pjson; SG_string* pstr = NULL; SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &pstr) ); while (*p) { char *q = NULL; char *r = NULL; q = p; while (*q) { if (13 == *q) { q++; if (10 == *q) { q++; } break; } else if (10 == *q) { q++; break; } q++; } // now q points to the char after the EOL, or to the zero terminator r = p; while ( (r < q) && ( (' ' == *r) || ('\t' == *r) ) ) { r++; } if ( *r && ('/' == r[0]) && ('/' == r[1]) ) { // this is a comment. skip it. } else { SG_ERR_CHECK( SG_string__append__buf_len(pCtx, pstr, (void*) p, q - p) ); } p = q; } *ppstr = pstr; pstr = NULL; fail: SG_STRING_NULLFREE(pCtx, pstr); }
static void _templatize( SG_context *pCtx, SG_string *content, const _request_headers *pRequestHeaders, _replacer_cb replacer) { SG_string *instr = NULL; const char *next = NULL; SG_string *piece = NULL; SG_string *replacement = NULL; SG_string *inclusion = NULL; SG_string *replaceRaw = NULL; SG_ERR_CHECK( SG_STRING__ALLOC__COPY(pCtx, &instr, content) ); SG_ERR_CHECK( SG_string__clear(pCtx, content) ); SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &piece) ); SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &replacement) ); SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &replaceRaw) ); next = SG_string__sz(instr); while (*next) { const char *delim = strstr(next, "{{{"); if (delim == NULL) { SG_ERR_CHECK( SG_string__append__sz(pCtx, content, next) ); break; } else { const char *rest = delim + 3; const char *end = strstr(rest, "}}}"); if (end == NULL) { SG_ERR_CHECK( SG_string__append__sz(pCtx, content, next) ); break; } SG_ERR_CHECK( SG_string__append__buf_len(pCtx, content, (const SG_byte *)next, (delim - next) * sizeof(char)) ); SG_ERR_CHECK( SG_string__clear(pCtx, piece) ); SG_ERR_CHECK( SG_string__clear(pCtx, replacement) ); SG_ERR_CHECK( SG_string__append__buf_len(pCtx, piece, (const SG_byte *)rest, (end - rest) * sizeof(char)) ); SG_ERR_CHECK( SG_string__append__string(pCtx, replacement, piece) ); if (SG_string__sz(piece)[0] == '<') { SG_string__remove(pCtx, piece, 0, 1); SG_ASSERT(inclusion == NULL); SG_ERR_CHECK( _read_template_file(pCtx, SG_string__sz(piece), &inclusion, pRequestHeaders, replacer) ); SG_STRING_NULLFREE(pCtx, replacement); replacement = inclusion; inclusion = NULL; } else { SG_bool needEncoding = SG_TRUE; SG_ERR_CHECK( replacer(pCtx, pRequestHeaders, piece, replaceRaw) ); // no verb-specific replacement? try generics if (sgeq(piece, replacement)) { SG_ERR_CHECK( _default_replacer(pCtx, pRequestHeaders, piece, replaceRaw, &needEncoding) ); } if (needEncoding) SG_ERR_CHECK( SG_htmlencode(pCtx, replaceRaw, replacement) ); else SG_ERR_CHECK( SG_string__set__string(pCtx, replacement, replaceRaw) ); } SG_ERR_CHECK( SG_string__append__string(pCtx, content, replacement) ); next = end + 3; } } fail: SG_STRING_NULLFREE(pCtx, instr); SG_STRING_NULLFREE(pCtx, piece); SG_STRING_NULLFREE(pCtx, replacement); SG_STRING_NULLFREE(pCtx, replaceRaw); SG_STRING_NULLFREE(pCtx, inclusion); }