mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-12 10:04:14 +02:00
More efficient memory allocation for Strings and String Variants.
The vast majority of Strings are never modified so for most cases allocate memory for the string with the object. This results in one allocation in most cases instead of two. Use strNew() if strCat*() functions are needed. Update varNewStr() in the same way since String Variants can never be modified. This results in one allocation in all cases instead of three. Also update varNewStrZ() to use STR() instead of strNewZ() to save two more allocations.
This commit is contained in:
parent
208641ac7f
commit
b7e17d80ea
@ -38,7 +38,8 @@ bldDefineRender(const String *const define, const String *const value)
|
||||
__attribute__((always_inline)) static inline String *
|
||||
bldHeader(const char *const module, const char *const description)
|
||||
{
|
||||
return strNewFmt(
|
||||
return strCatFmt(
|
||||
strNew(),
|
||||
COMMENT_BLOCK_BEGIN "\n"
|
||||
"%s\n"
|
||||
"\n"
|
||||
|
@ -32,7 +32,7 @@ Build enum from a string
|
||||
static String *
|
||||
bldEnum(const char *const prefix, const String *const value)
|
||||
{
|
||||
String *const result = strNewZ(prefix);
|
||||
String *const result = strCatZ(strNew(), prefix);
|
||||
const char *const valuePtr = strZ(value);
|
||||
|
||||
bool upper = true;
|
||||
@ -82,7 +82,8 @@ Render config.auto.h
|
||||
static void
|
||||
bldCfgRenderConfigAutoH(const Storage *const storageRepo, const BldCfg bldCfg)
|
||||
{
|
||||
String *config = strNewFmt(
|
||||
String *config = strCatFmt(
|
||||
strNew(),
|
||||
"%s"
|
||||
"#ifndef CONFIG_CONFIG_AUTO_H\n"
|
||||
"#define CONFIG_CONFIG_AUTO_H\n",
|
||||
|
@ -48,7 +48,8 @@ Render error.auto.h
|
||||
static void
|
||||
bldErrRenderErrorAutoH(const Storage *const storageRepo, const BldErr bldErr)
|
||||
{
|
||||
String *error = strNewFmt(
|
||||
String *error = strCatFmt(
|
||||
strNew(),
|
||||
"%s"
|
||||
"#ifndef COMMON_ERROR_AUTO_H\n"
|
||||
"#define COMMON_ERROR_AUTO_H\n",
|
||||
@ -122,7 +123,7 @@ bldErrRenderErrorAutoC(const Storage *const storageRepo, const BldErr bldErr)
|
||||
}
|
||||
|
||||
strCatZ(
|
||||
error,
|
||||
error,
|
||||
" NULL,\n"
|
||||
"};\n");
|
||||
|
||||
|
@ -291,7 +291,8 @@ bldHlpRenderHelpAutoC(const Storage *const storageRepo, const BldCfg bldCfg, con
|
||||
// Convert buffer to bytes
|
||||
const Buffer *const buffer = bldHlpRenderHelpAutoCCmp(bldCfg, bldHlp);
|
||||
|
||||
String *const help = strNewFmt(
|
||||
String *const help = strCatFmt(
|
||||
strNew(),
|
||||
"%s"
|
||||
"static const unsigned char helpData[%zu] =\n"
|
||||
"{\n",
|
||||
|
@ -1023,7 +1023,7 @@ cmdArchiveGetAsync(void)
|
||||
{
|
||||
LOG_WARN_FMT("[%s] %s", errorTypeName(checkResult.errorType), strZ(checkResult.errorMessage));
|
||||
|
||||
String *message = strDup(checkResult.errorMessage);
|
||||
String *message = strCat(strNew(), checkResult.errorMessage);
|
||||
|
||||
if (!strLstEmpty(checkResult.warnList))
|
||||
strCatFmt(message, "\n%s", strZ(strLstJoin(checkResult.warnList, "\n")));
|
||||
|
@ -140,7 +140,7 @@ archivePushFile(
|
||||
}
|
||||
|
||||
// Set archive destination initially to the archive file, this will be updated later for wal segments
|
||||
String *archiveDestination = strDup(archiveFile);
|
||||
String *archiveDestination = strCat(strNew(), archiveFile);
|
||||
|
||||
// Assume that all repos need a copy of the archive file
|
||||
bool destinationCopyAny = true;
|
||||
|
@ -70,7 +70,7 @@ backupRegExp(BackupRegExpParam param)
|
||||
String *result = NULL;
|
||||
|
||||
// Start the expression with the anchor, date/time regexp and full backup indicator
|
||||
result = strNewZ("^" DATE_TIME_REGEX "F");
|
||||
result = strCatZ(strNew(), "^" DATE_TIME_REGEX "F");
|
||||
|
||||
// Add the diff and/or incr expressions if requested
|
||||
if (param.differential || param.incremental)
|
||||
|
@ -172,7 +172,7 @@ cmdBegin(void)
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Basic info on command start
|
||||
String *info = strNewFmt("%s command begin", strZ(cfgCommandRoleName()));
|
||||
String *info = strCatFmt(strNew(), "%s command begin", strZ(cfgCommandRoleName()));
|
||||
|
||||
// Free the old option string if it exists. This is needed when more than one command is run in a row so an option
|
||||
// string gets created for the new command.
|
||||
@ -213,7 +213,7 @@ cmdEnd(int code, const String *errorMessage)
|
||||
LOG_DETAIL_FMT("statistics: %s", strZ(jsonFromKv(statKv)));
|
||||
|
||||
// Basic info on command end
|
||||
String *info = strNewFmt("%s command end: ", strZ(cfgCommandRoleName()));
|
||||
String *info = strCatFmt(strNew(), "%s command end: ", strZ(cfgCommandRoleName()));
|
||||
|
||||
if (errorMessage == NULL)
|
||||
{
|
||||
|
@ -238,7 +238,7 @@ helpRender(const Buffer *const helpData)
|
||||
FUNCTION_LOG_PARAM(BUFFER, helpData);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
String *result = strNewZ(PROJECT_NAME " " PROJECT_VERSION);
|
||||
String *result = strCatZ(strNew(), PROJECT_NAME " " PROJECT_VERSION);
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
@ -441,7 +441,8 @@ helpRender(const Buffer *const helpData)
|
||||
ConfigOption optionId = varUInt(varLstGet(optionList, optionIdx));
|
||||
|
||||
// Get option summary and lower-case first letter if it does not appear to be part of an acronym
|
||||
String *summary = strNewN(strZ(optionData[optionId].summary), strSize(optionData[optionId].summary) - 1);
|
||||
String *summary = strCatN(
|
||||
strNew(), optionData[optionId].summary, strSize(optionData[optionId].summary) - 1);
|
||||
ASSERT(strSize(summary) > 1);
|
||||
|
||||
if (!isupper(strZ(summary)[1]) && !isdigit(strZ(summary)[1]))
|
||||
|
@ -1069,7 +1069,7 @@ formatTextDb(
|
||||
}
|
||||
}
|
||||
|
||||
String *resultCurrent = strNewZ("\n db (current)");
|
||||
String *resultCurrent = strCatZ(strNew(), "\n db (current)");
|
||||
bool displayCurrent = false;
|
||||
|
||||
for (unsigned int dbGrpIdx = backupDbGrpIdxMin; dbGrpIdx < backupDbGrpIdxMax; dbGrpIdx++)
|
||||
|
@ -1675,7 +1675,7 @@ restoreRecoveryConf(unsigned int pgVersion, const String *restoreLabel)
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
result = strNewFmt("# Recovery settings generated by " PROJECT_NAME " restore on %s\n", strZ(restoreLabel));
|
||||
result = strCatFmt(strNew(), "# Recovery settings generated by " PROJECT_NAME " restore on %s\n", strZ(restoreLabel));
|
||||
|
||||
// Output all recovery options
|
||||
KeyValue *optionKv = restoreRecoveryOption(pgVersion);
|
||||
@ -2073,7 +2073,7 @@ restoreJobResult(const Manifest *manifest, ProtocolParallelJob *job, RegExp *zer
|
||||
bool zeroed = restoreFileZeroed(file->name, zeroExp);
|
||||
bool copy = pckReadBoolP(protocolParallelJobResult(job));
|
||||
|
||||
String *log = strNewZ("restore");
|
||||
String *log = strCatZ(strNew(), "restore");
|
||||
|
||||
// Note if file was zeroed (i.e. selective restore)
|
||||
if (zeroed)
|
||||
@ -2285,8 +2285,9 @@ cmdRestore(void)
|
||||
restoreManifestValidate(jobData.manifest, backupData.backupSet);
|
||||
|
||||
// Log the backup set to restore. If the backup was online then append the time recovery will start from.
|
||||
String *const message = strNewFmt(
|
||||
"repo%u: restore backup set %s", cfgOptionGroupIdxToKey(cfgOptGrpRepo, backupData.repoIdx), strZ(backupData.backupSet));
|
||||
String *const message = strCatFmt(
|
||||
strNew(), "repo%u: restore backup set %s", cfgOptionGroupIdxToKey(cfgOptGrpRepo, backupData.repoIdx),
|
||||
strZ(backupData.backupSet));
|
||||
|
||||
if (manifestData(jobData.manifest)->backupOptionOnline)
|
||||
{
|
||||
|
@ -227,7 +227,7 @@ verifyInfoFile(const String *pathFileName, bool keepFile, const String *cipherPa
|
||||
CATCH_ANY()
|
||||
{
|
||||
result.errorCode = errorCode();
|
||||
String *errorMsg = strNewZ(errorMessage());
|
||||
String *errorMsg = strCatZ(strNew(), errorMessage());
|
||||
|
||||
if (result.errorCode == errorTypeCode(&ChecksumError))
|
||||
strCat(errorMsg, strNewFmt(" %s", strZ(pathFileName)));
|
||||
@ -1252,7 +1252,7 @@ verifyRender(List *archiveIdResultList, List *backupResultList)
|
||||
ASSERT(archiveIdResultList != NULL);
|
||||
ASSERT(backupResultList != NULL);
|
||||
|
||||
String *result = strNewZ("Results:");
|
||||
String *result = strCatZ(strNew(), "Results:");
|
||||
|
||||
// Render archive results
|
||||
if (lstEmpty(archiveIdResultList))
|
||||
|
@ -88,7 +88,8 @@ exitErrorDetail(void)
|
||||
FUNCTION_TEST_VOID();
|
||||
|
||||
FUNCTION_TEST_RETURN(
|
||||
strNewFmt(
|
||||
strCatFmt(
|
||||
strNew(),
|
||||
"--------------------------------------------------------------------\n"
|
||||
"If SUBMITTING AN ISSUE please provide the following information:\n"
|
||||
"\n"
|
||||
@ -148,7 +149,7 @@ exitSafe(int result, bool error, SignalType signalType)
|
||||
// On process terminate
|
||||
if (result == errorTypeCode(&TermError))
|
||||
{
|
||||
errorMessage = strNewZ("terminated on signal ");
|
||||
errorMessage = strCatZ(strNew(), "terminated on signal ");
|
||||
|
||||
// Terminate from a child
|
||||
if (signalType == signalTypeNone)
|
||||
|
@ -95,7 +95,7 @@ httpHeaderAdd(HttpHeader *this, const String *key, const String *value)
|
||||
{
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
String *valueAppend = strDup(varStr(valueVar));
|
||||
String *const valueAppend = strCat(strNew(), varStr(valueVar));
|
||||
strCatZ(valueAppend, ", ");
|
||||
strCatZ(valueAppend, strZ(value));
|
||||
|
||||
@ -177,7 +177,7 @@ httpHeaderRedact(const HttpHeader *this, const String *key)
|
||||
String *
|
||||
httpHeaderToLog(const HttpHeader *this)
|
||||
{
|
||||
String *result = strNewZ("{");
|
||||
String *result = strCatZ(strNew(), "{");
|
||||
const StringList *keyList = httpHeaderList(this);
|
||||
|
||||
for (unsigned int keyIdx = 0; keyIdx < strLstSize(keyList); keyIdx++)
|
||||
|
@ -291,7 +291,7 @@ httpQueryRender(const HttpQuery *this, HttpQueryRenderParam param)
|
||||
String *
|
||||
httpQueryToLog(const HttpQuery *this)
|
||||
{
|
||||
String *result = strNewZ("{");
|
||||
String *result = strCatZ(strNew(), "{");
|
||||
const StringList *keyList = httpQueryList(this);
|
||||
|
||||
for (unsigned int keyIdx = 0; keyIdx < strLstSize(keyList); keyIdx++)
|
||||
|
@ -96,7 +96,8 @@ httpRequestProcess(HttpRequest *this, bool waitForResponse, bool contentCache)
|
||||
|
||||
// Format the request and user agent
|
||||
String *requestStr =
|
||||
strNewFmt(
|
||||
strCatFmt(
|
||||
strNew(),
|
||||
"%s %s%s%s " HTTP_VERSION CRLF_Z HTTP_HEADER_USER_AGENT ":" PROJECT_NAME "/" PROJECT_VERSION CRLF_Z,
|
||||
strZ(httpRequestVerb(this)), strZ(httpRequestPath(this)), httpRequestQuery(this) == NULL ? "" : "?",
|
||||
httpRequestQuery(this) == NULL ? "" : strZ(httpQueryRenderP(httpRequestQuery(this))));
|
||||
@ -242,7 +243,7 @@ httpRequestError(const HttpRequest *this, HttpResponse *response)
|
||||
ASSERT(response != NULL);
|
||||
|
||||
// Error code
|
||||
String *error = strNewFmt("HTTP request failed with %u", httpResponseCode(response));
|
||||
String *error = strCatFmt(strNew(), "HTTP request failed with %u", httpResponseCode(response));
|
||||
|
||||
// Add reason when present
|
||||
if (strSize(httpResponseReason(response)) > 0)
|
||||
|
@ -787,7 +787,7 @@ jsonFromKvInternal(const KeyValue *kv)
|
||||
|
||||
ASSERT(kv != NULL);
|
||||
|
||||
String *result = strNewZ("{");
|
||||
String *result = strCatZ(strNew(), "{");
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
|
@ -39,6 +39,21 @@ STRING_EXTERN(TRUE_STR, TRUE_Z);
|
||||
STRING_EXTERN(Y_STR, Y_Z);
|
||||
STRING_EXTERN(ZERO_STR, ZERO_Z);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Buffer macros
|
||||
***********************************************************************************************************************************/
|
||||
// Fixed size buffer allocated at the end of the object allocation
|
||||
#define STR_FIXED_BUFFER (char *)(this + 1)
|
||||
|
||||
// Is the string using the fixed size buffer?
|
||||
#define STR_IS_FIXED_BUFFER() (this->pub.buffer == STR_FIXED_BUFFER)
|
||||
|
||||
// Empty buffer
|
||||
#define STR_EMPTY_BUFFER (EMPTY_STR->pub.buffer)
|
||||
|
||||
// Is the string using the empty buffer?
|
||||
#define STR_IS_EMPTY_BUFFER() (this->pub.buffer == STR_EMPTY_BUFFER)
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Maximum size of a string
|
||||
***********************************************************************************************************************************/
|
||||
@ -74,15 +89,38 @@ strNew(void)
|
||||
{
|
||||
.pub =
|
||||
{
|
||||
// A zero-length string is not very useful so assume this string is being created for appending and allocate extra space
|
||||
.extra = STRING_EXTRA_MIN,
|
||||
// Set empty so nothing is allocated until needed
|
||||
.buffer = STR_EMPTY_BUFFER,
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
|
||||
// Allocate and assign string
|
||||
this->pub.buffer = memNew(STRING_EXTRA_MIN + 1);
|
||||
this->pub.buffer[0] = '\0';
|
||||
FUNCTION_TEST_RETURN(this);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Create fixed size String
|
||||
***********************************************************************************************************************************/
|
||||
static String *
|
||||
strNewFixed(const size_t size)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(SIZE, size);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
CHECK_SIZE(size);
|
||||
|
||||
String *this = memNew(sizeof(String) + size + 1);
|
||||
|
||||
*this = (String)
|
||||
{
|
||||
.pub =
|
||||
{
|
||||
.size = (unsigned int)size,
|
||||
.buffer = STR_FIXED_BUFFER,
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
|
||||
FUNCTION_TEST_RETURN(this);
|
||||
}
|
||||
@ -97,25 +135,12 @@ strNewZ(const char *const string)
|
||||
|
||||
ASSERT(string != NULL);
|
||||
|
||||
// Check size
|
||||
size_t stringSize = strlen(string);
|
||||
CHECK_SIZE(stringSize);
|
||||
|
||||
// Create object
|
||||
String *this = memNew(sizeof(String));
|
||||
String *this = strNewFixed(strlen(string));
|
||||
|
||||
*this = (String)
|
||||
{
|
||||
.pub =
|
||||
{
|
||||
.size = (unsigned int)stringSize,
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
|
||||
// Allocate and assign string
|
||||
this->pub.buffer = memNew(strSize(this) + this->pub.extra + 1);
|
||||
strcpy(this->pub.buffer, string);
|
||||
// Assign string
|
||||
strncpy(this->pub.buffer, string, strSize(this));
|
||||
this->pub.buffer[strSize(this)] = '\0';
|
||||
|
||||
FUNCTION_TEST_RETURN(this);
|
||||
}
|
||||
@ -144,23 +169,10 @@ strNewBuf(const Buffer *buffer)
|
||||
|
||||
ASSERT(buffer != NULL);
|
||||
|
||||
// Check size
|
||||
CHECK_SIZE(bufUsed(buffer));
|
||||
|
||||
// Create object
|
||||
String *this = memNew(sizeof(String));
|
||||
String *this = strNewFixed(bufUsed(buffer));
|
||||
|
||||
*this = (String)
|
||||
{
|
||||
.pub =
|
||||
{
|
||||
.size = (unsigned int)bufUsed(buffer),
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
|
||||
// Allocate and assign string
|
||||
this->pub.buffer = memNew(strSize(this) + 1);
|
||||
// Assign string
|
||||
memcpy(this->pub.buffer, bufPtrConst(buffer), strSize(this));
|
||||
this->pub.buffer[strSize(this)] = 0;
|
||||
|
||||
@ -178,24 +190,10 @@ strNewEncode(EncodeType type, const Buffer *buffer)
|
||||
|
||||
ASSERT(buffer != NULL);
|
||||
|
||||
// Check encoded size
|
||||
size_t size = encodeToStrSize(type, bufUsed(buffer));
|
||||
CHECK_SIZE(size);
|
||||
|
||||
// Create object
|
||||
String *this = memNew(sizeof(String));
|
||||
String *this = strNewFixed(encodeToStrSize(type, bufUsed(buffer)));
|
||||
|
||||
*this = (String)
|
||||
{
|
||||
.pub =
|
||||
{
|
||||
.size = (unsigned int)size,
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
|
||||
// Allocate and encode buffer
|
||||
this->pub.buffer = memNew(strSize(this) + 1);
|
||||
// Encode buffer
|
||||
encodeToStr(type, bufPtrConst(buffer), bufUsed(buffer), this->pub.buffer);
|
||||
|
||||
FUNCTION_TEST_RETURN(this);
|
||||
@ -211,26 +209,13 @@ strNewFmt(const char *format, ...)
|
||||
|
||||
ASSERT(format != NULL);
|
||||
|
||||
// Create object
|
||||
String *this = memNew(sizeof(String));
|
||||
|
||||
*this = (String)
|
||||
{
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
|
||||
// Determine how long the allocated string needs to be
|
||||
// Determine how long the allocated string needs to be and create object
|
||||
va_list argumentList;
|
||||
va_start(argumentList, format);
|
||||
size_t formatSize = (size_t)vsnprintf(NULL, 0, format, argumentList);
|
||||
String *this = strNewFixed((size_t)vsnprintf(NULL, 0, format, argumentList));
|
||||
va_end(argumentList);
|
||||
|
||||
// Check size
|
||||
CHECK_SIZE(formatSize);
|
||||
|
||||
// Allocate and assign string
|
||||
this->pub.size = (unsigned int)formatSize;
|
||||
this->pub.buffer = memNew(strSize(this) + 1);
|
||||
// Format string
|
||||
va_start(argumentList, format);
|
||||
vsnprintf(this->pub.buffer, strSize(this) + 1, format, argumentList);
|
||||
va_end(argumentList);
|
||||
@ -249,27 +234,13 @@ strNewN(const char *string, size_t size)
|
||||
|
||||
ASSERT(string != NULL);
|
||||
|
||||
// Check size
|
||||
CHECK_SIZE(size);
|
||||
|
||||
// Create object
|
||||
String *this = memNew(sizeof(String));
|
||||
String *this = strNewFixed(size);
|
||||
|
||||
*this = (String)
|
||||
{
|
||||
.pub =
|
||||
{
|
||||
.size = (unsigned int)size,
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
|
||||
// Allocate and assign string
|
||||
this->pub.buffer = memNew(strSize(this) + 1);
|
||||
// Assign string
|
||||
strncpy(this->pub.buffer, string, strSize(this));
|
||||
this->pub.buffer[strSize(this)] = 0;
|
||||
|
||||
// Return buffer
|
||||
FUNCTION_TEST_RETURN(this);
|
||||
}
|
||||
|
||||
@ -351,6 +322,9 @@ strResize(String *this, size_t requested)
|
||||
|
||||
if (requested > this->pub.extra)
|
||||
{
|
||||
// Fixed size strings may not be resized
|
||||
CHECK(!STR_IS_FIXED_BUFFER());
|
||||
|
||||
// Check size
|
||||
CHECK_SIZE(strSize(this) + requested);
|
||||
|
||||
@ -363,7 +337,10 @@ strResize(String *this, size_t requested)
|
||||
|
||||
MEM_CONTEXT_BEGIN(this->memContext)
|
||||
{
|
||||
this->pub.buffer = memResize(this->pub.buffer, strSize(this) + this->pub.extra + 1);
|
||||
if (STR_IS_EMPTY_BUFFER())
|
||||
this->pub.buffer = memNew(strSize(this) + this->pub.extra + 1);
|
||||
else
|
||||
this->pub.buffer = memResize(this->pub.buffer, strSize(this) + this->pub.extra + 1);
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
}
|
||||
@ -400,13 +377,16 @@ strCatZ(String *this, const char *cat)
|
||||
// Determine length of string to append
|
||||
size_t sizeGrow = strlen(cat);
|
||||
|
||||
// Ensure there is enough space to grow the string
|
||||
strResize(this, sizeGrow);
|
||||
if (sizeGrow != 0)
|
||||
{
|
||||
// Ensure there is enough space to grow the string
|
||||
strResize(this, sizeGrow);
|
||||
|
||||
// Append the string
|
||||
strcpy(this->pub.buffer + strSize(this), cat);
|
||||
this->pub.size += (unsigned int)sizeGrow;
|
||||
this->pub.extra -= (unsigned int)sizeGrow;
|
||||
// Append the string
|
||||
strcpy(this->pub.buffer + strSize(this), cat);
|
||||
this->pub.size += (unsigned int)sizeGrow;
|
||||
this->pub.extra -= (unsigned int)sizeGrow;
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(this);
|
||||
}
|
||||
@ -421,22 +401,41 @@ strCatZN(String *this, const char *cat, size_t size)
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(this != NULL);
|
||||
ASSERT(cat != NULL);
|
||||
|
||||
// Ensure there is enough space to grow the string
|
||||
strResize(this, size);
|
||||
if (size != 0)
|
||||
{
|
||||
ASSERT(cat != NULL);
|
||||
|
||||
// Append the string
|
||||
strncpy(this->pub.buffer + strSize(this), cat, size);
|
||||
this->pub.buffer[strSize(this) + size] = '\0';
|
||||
// Ensure there is enough space to grow the string
|
||||
strResize(this, size);
|
||||
|
||||
// Update size/extra
|
||||
this->pub.size += (unsigned int)size;
|
||||
this->pub.extra -= (unsigned int)size;
|
||||
// Append the string
|
||||
strncpy(this->pub.buffer + strSize(this), cat, size);
|
||||
this->pub.buffer[strSize(this) + size] = '\0';
|
||||
|
||||
// Update size/extra
|
||||
this->pub.size += (unsigned int)size;
|
||||
this->pub.extra -= (unsigned int)size;
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(this);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
String *
|
||||
strCatBuf(String *const this, const Buffer *const buffer)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(STRING, this);
|
||||
FUNCTION_TEST_PARAM(BUFFER, buffer);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(this != NULL);
|
||||
ASSERT(buffer != NULL);
|
||||
|
||||
FUNCTION_TEST_RETURN(strCatZN(this, (char *)bufPtrConst(buffer), bufUsed(buffer)));
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
String *
|
||||
strCatChr(String *this, char cat)
|
||||
@ -473,16 +472,20 @@ strCatEncode(String *this, EncodeType type, const Buffer *buffer)
|
||||
ASSERT(this != NULL);
|
||||
ASSERT(buffer != NULL);
|
||||
|
||||
// Ensure there is enough space to grow the string
|
||||
size_t encodeSize = encodeToStrSize(type, bufUsed(buffer));
|
||||
strResize(this, encodeSize);
|
||||
|
||||
// Append the encoded string
|
||||
encodeToStr(type, bufPtrConst(buffer), bufUsed(buffer), this->pub.buffer + strSize(this));
|
||||
if (encodeSize != 0)
|
||||
{
|
||||
// Ensure there is enough space to grow the string
|
||||
strResize(this, encodeSize);
|
||||
|
||||
// Update size/extra
|
||||
this->pub.size += (unsigned int)encodeSize;
|
||||
this->pub.extra -= (unsigned int)encodeSize;
|
||||
// Append the encoded string
|
||||
encodeToStr(type, bufPtrConst(buffer), bufUsed(buffer), this->pub.buffer + strSize(this));
|
||||
|
||||
// Update size/extra
|
||||
this->pub.size += (unsigned int)encodeSize;
|
||||
this->pub.extra -= (unsigned int)encodeSize;
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(this);
|
||||
}
|
||||
@ -505,16 +508,19 @@ strCatFmt(String *this, const char *format, ...)
|
||||
size_t sizeGrow = (size_t)vsnprintf(NULL, 0, format, argumentList);
|
||||
va_end(argumentList);
|
||||
|
||||
// Ensure there is enough space to grow the string
|
||||
strResize(this, sizeGrow);
|
||||
if (sizeGrow != 0)
|
||||
{
|
||||
// Ensure there is enough space to grow the string
|
||||
strResize(this, sizeGrow);
|
||||
|
||||
// Append the formatted string
|
||||
va_start(argumentList, format);
|
||||
vsnprintf(this->pub.buffer + strSize(this), sizeGrow + 1, format, argumentList);
|
||||
va_end(argumentList);
|
||||
// Append the formatted string
|
||||
va_start(argumentList, format);
|
||||
vsnprintf(this->pub.buffer + strSize(this), sizeGrow + 1, format, argumentList);
|
||||
va_end(argumentList);
|
||||
|
||||
this->pub.size += (unsigned int)sizeGrow;
|
||||
this->pub.extra -= (unsigned int)sizeGrow;
|
||||
this->pub.size += (unsigned int)sizeGrow;
|
||||
this->pub.extra -= (unsigned int)sizeGrow;
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(this);
|
||||
}
|
||||
@ -695,9 +701,8 @@ strUpper(String *this)
|
||||
|
||||
ASSERT(this != NULL);
|
||||
|
||||
if (strSize(this) > 0)
|
||||
for (size_t idx = 0; idx <= strSize(this); idx++)
|
||||
this->pub.buffer[idx] = (char)toupper(this->pub.buffer[idx]);
|
||||
for (size_t idx = 0; idx < strSize(this); idx++)
|
||||
this->pub.buffer[idx] = (char)toupper(this->pub.buffer[idx]);
|
||||
|
||||
FUNCTION_TEST_RETURN(this);
|
||||
}
|
||||
@ -712,9 +717,8 @@ strLower(String *this)
|
||||
|
||||
ASSERT(this != NULL);
|
||||
|
||||
if (strSize(this) > 0)
|
||||
for (size_t idx = 0; idx <= strSize(this); idx++)
|
||||
this->pub.buffer[idx] = (char)tolower(this->pub.buffer[idx]);
|
||||
for (size_t idx = 0; idx < strSize(this); idx++)
|
||||
this->pub.buffer[idx] = (char)tolower(this->pub.buffer[idx]);
|
||||
|
||||
FUNCTION_TEST_RETURN(this);
|
||||
}
|
||||
@ -947,20 +951,13 @@ strTrim(String *this)
|
||||
|
||||
if (begin != this->pub.buffer || newSize < strSize(this))
|
||||
{
|
||||
// Calculate new size
|
||||
// Calculate new size and extra
|
||||
this->pub.extra = (unsigned int)(strSize(this) - newSize);
|
||||
this->pub.size = (unsigned int)newSize;
|
||||
|
||||
// Move the substr to the beginning of the buffer
|
||||
memmove(this->pub.buffer, begin, strSize(this));
|
||||
this->pub.buffer[strSize(this)] = 0;
|
||||
this->pub.extra = 0;
|
||||
|
||||
MEM_CONTEXT_BEGIN(this->memContext)
|
||||
{
|
||||
// Resize the buffer
|
||||
this->pub.buffer = memResize(this->pub.buffer, strSize(this) + 1);
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1005,16 +1002,9 @@ strTrunc(String *this, int idx)
|
||||
if (strSize(this) > 0)
|
||||
{
|
||||
// Reset the size to end at the index
|
||||
this->pub.size = (unsigned int)(idx);
|
||||
this->pub.extra = (unsigned int)(strSize(this) - (size_t)idx);
|
||||
this->pub.size = (unsigned int)idx;
|
||||
this->pub.buffer[strSize(this)] = 0;
|
||||
this->pub.extra = 0;
|
||||
|
||||
MEM_CONTEXT_BEGIN(this->memContext)
|
||||
{
|
||||
// Resize the buffer
|
||||
this->pub.buffer = memResize(this->pub.buffer, strSize(this) + 1);
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(this);
|
||||
@ -1095,7 +1085,9 @@ strFree(String *this)
|
||||
{
|
||||
MEM_CONTEXT_BEGIN(this->memContext)
|
||||
{
|
||||
memFree(this->pub.buffer);
|
||||
if (!STR_IS_EMPTY_BUFFER() && !STR_IS_FIXED_BUFFER())
|
||||
memFree(this->pub.buffer);
|
||||
|
||||
memFree(this);
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
|
@ -41,31 +41,38 @@ typedef struct String String;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Constructors
|
||||
|
||||
Only strings created with strNew() can use strCat*() functions. If a string needs to be concatenated then start with, .e.g.:
|
||||
|
||||
String *example = strCatZ(strNew(), "example");
|
||||
|
||||
This syntax signals that the string will be modified so the string is allocated separately from the object so it can be resized when
|
||||
needed. Most strings never need to be modified and can be stored more efficiently by allocating their memory with the object.
|
||||
***********************************************************************************************************************************/
|
||||
// Create a new empty string
|
||||
// Create a new empty string for concatenation
|
||||
String *strNew(void);
|
||||
|
||||
// Create a new string from a zero-terminated string
|
||||
// Create a new fixed length string from a zero-terminated string
|
||||
String *strNewZ(const char *const string);
|
||||
|
||||
// Create a new string from a buffer. If the buffer has a NULL character this may not work as expected. All the data will be copied
|
||||
// but only the data before the NULL character will be used as a string.
|
||||
// Create a new fixed length string from a buffer. If the buffer has a NULL character this may not work as expected. All the data
|
||||
// will be copied but only the data before the NULL character will be used as a string.
|
||||
String *strNewBuf(const Buffer *buffer);
|
||||
|
||||
// Create a new string by converting the double value
|
||||
// Create a new fixed length string by converting the double value
|
||||
String *strNewDbl(double value);
|
||||
|
||||
// Create a new string encoded with the specified type (e.g. encodeBase64) from a buffer
|
||||
// Create a new fixed length string encoded with the specified type (e.g. encodeBase64) from a buffer
|
||||
String *strNewEncode(EncodeType type, const Buffer *buffer);
|
||||
|
||||
// Create a new string from a format string with parameters (i.e. sprintf)
|
||||
// Create a new fixed length string from a format string with parameters (i.e. sprintf)
|
||||
String *strNewFmt(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
// Create a new string from a string with a specific length. The string may or may not be zero-terminated but we'll use that
|
||||
// nomenclature since we're not concerned about the end of the string.
|
||||
// Create a new fixed length string from a zero-terminated string with a specific length. The string may or may not be
|
||||
// zero-terminated but we'll use that nomenclature since we're not concerned about the end of the string.
|
||||
String *strNewN(const char *string, size_t size);
|
||||
|
||||
// Duplicate a string
|
||||
// Create a new fixed length string from a string
|
||||
String *strDup(const String *this);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@ -110,6 +117,9 @@ bool strBeginsWithZ(const String *this, const char *beginsWith);
|
||||
String *strCat(String *this, const String *cat);
|
||||
String *strCatZ(String *this, const char *cat);
|
||||
|
||||
// Append a buffer
|
||||
String *strCatBuf(String *this, const Buffer *buffer);
|
||||
|
||||
// Append a character
|
||||
String *strCatChr(String *this, char cat);
|
||||
|
||||
@ -123,6 +133,13 @@ String *strCatFmt(String *this, const char *format, ...) __attribute__((format(p
|
||||
// N is <= the end of the string being concatenated.
|
||||
String *strCatZN(String *this, const char *cat, size_t size);
|
||||
|
||||
__attribute__((always_inline)) static inline String *
|
||||
strCatN(String *this, const String *const cat, const size_t size)
|
||||
{
|
||||
ASSERT_INLINE(cat != NULL);
|
||||
return strCatZN(this, strZ(cat), size);
|
||||
}
|
||||
|
||||
// Return the index to the location of the first occurrence of a character within a string, else -1
|
||||
int strChr(const String *this, char chr);
|
||||
|
||||
|
@ -808,19 +808,36 @@ varNewStr(const String *data)
|
||||
FUNCTION_TEST_PARAM(STRING, data);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Allocate memory for the variant and set the type and data
|
||||
VariantString *this = memNew(sizeof(VariantString));
|
||||
// Allocate memory for the variant
|
||||
VariantString *this = memNew(sizeof(VariantString) + (data != NULL ? sizeof(StringPub) + strSize(data) + 1 : 0));
|
||||
|
||||
*this = (VariantString)
|
||||
{
|
||||
.pub =
|
||||
{
|
||||
.type = varTypeString,
|
||||
.data = strDup(data),
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
// Point the String after the VariantString struct
|
||||
StringPub *const pubData = (StringPub *)(this + 1);
|
||||
this->pub.data = (String *)pubData;
|
||||
|
||||
// Assign the string size and buffer (after StringPub struct)
|
||||
*pubData = (StringPub)
|
||||
{
|
||||
.size = (unsigned int)strSize(data),
|
||||
.buffer = (char *)(pubData + 1),
|
||||
};
|
||||
|
||||
// Assign the string
|
||||
strncpy(pubData->buffer, strZ(data), strSize(data));
|
||||
pubData->buffer[strSize(data)] = '\0';
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN((Variant *)this);
|
||||
}
|
||||
|
||||
@ -831,7 +848,7 @@ varNewStrZ(const char *data)
|
||||
FUNCTION_TEST_PARAM(STRINGZ, data);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(varNewStr(data == NULL ? NULL : strNewZ(data)));
|
||||
FUNCTION_TEST_RETURN(varNewStr(data == NULL ? NULL : STR(data)));
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
@ -1031,7 +1048,6 @@ varFree(Variant *this)
|
||||
|
||||
case varTypeString:
|
||||
memContext = ((VariantString *)this)->memContext;
|
||||
strFree(((VariantString *)this)->pub.data);
|
||||
break;
|
||||
|
||||
case varTypeUInt:
|
||||
|
@ -333,7 +333,8 @@ cfgLoadLogFile(void)
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Construct log filename prefix
|
||||
String *logFile = strNewFmt(
|
||||
String *logFile = strCatFmt(
|
||||
strNew(),
|
||||
"%s/%s-%s", strZ(cfgOptionStr(cfgOptLogPath)),
|
||||
cfgOptionTest(cfgOptStanza) ? strZ(cfgOptionStr(cfgOptStanza)): "all", cfgCommandName());
|
||||
|
||||
|
@ -515,7 +515,7 @@ cfgParseCommandRoleName(const ConfigCommand commandId, const ConfigCommandRole c
|
||||
FUNCTION_TEST_PARAM(STRING, separator);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
String *result = strNewZ(cfgParseCommandName(commandId));
|
||||
String *result = strCatZ(strNew(), cfgParseCommandName(commandId));
|
||||
|
||||
if (commandRoleId != cfgCmdRoleMain)
|
||||
strCatFmt(result, "%s%s", strZ(separator), strZ(cfgParseCommandRoleStr(commandRoleId)));
|
||||
@ -1097,14 +1097,14 @@ cfgFileLoad( // NOTE: Pas
|
||||
|
||||
// Convert the contents of the file buffer to the config string object
|
||||
if (buffer != NULL)
|
||||
result = strNewBuf(buffer);
|
||||
result = strCatBuf(strNew(), buffer);
|
||||
else if (strEq(configFileName, optConfigDefaultCurrent))
|
||||
{
|
||||
// If config is current default and it was not found, attempt to load the config file from the old default location
|
||||
buffer = storageGetP(storageNewReadP(storage, origConfigDefault, .ignoreMissing = !configRequired));
|
||||
|
||||
if (buffer != NULL)
|
||||
result = strNewBuf(buffer);
|
||||
result = strCatBuf(strNew(), buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,7 +277,8 @@ dbBackupStartQuery(unsigned int pgVersion, bool startFast)
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Build query to return start lsn and WAL segment name
|
||||
String *result = strNewFmt(
|
||||
String *result = strCatFmt(
|
||||
strNew(),
|
||||
"select lsn::text as lsn,\n"
|
||||
" pg_catalog.pg_%sfile_name(lsn)::text as wal_segment_name\n"
|
||||
" from pg_catalog.pg_start_backup('" PROJECT_NAME " backup started at ' || current_timestamp",
|
||||
@ -372,7 +373,8 @@ dbBackupStopQuery(unsigned int pgVersion)
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Build query to return start lsn and WAL segment name
|
||||
String *result = strNewFmt(
|
||||
String *result = strCatFmt(
|
||||
strNew(),
|
||||
"select lsn::text as lsn,\n"
|
||||
" pg_catalog.pg_%sfile_name(lsn)::text as wal_segment_name",
|
||||
strZ(pgWalName(pgVersion)));
|
||||
@ -510,7 +512,8 @@ dbReplayWait(Db *this, const String *targetLsn, TimeMSec timeout)
|
||||
do
|
||||
{
|
||||
// Build the query
|
||||
String *query = strNewFmt(
|
||||
String *query = strCatFmt(
|
||||
strNew(),
|
||||
"select replayLsn::text,\n"
|
||||
" (replayLsn > '%s')::bool as targetReached",
|
||||
strZ(targetLsn));
|
||||
|
@ -506,7 +506,7 @@ infoLoad(const String *error, InfoLoadCallback *callbackFunction, void *callback
|
||||
if (loadErrorType == NULL)
|
||||
{
|
||||
loadErrorType = errorType();
|
||||
loadErrorMessage = strNewFmt("%s:", strZ(error));
|
||||
loadErrorMessage = strCatFmt(strNew(), "%s:", strZ(error));
|
||||
}
|
||||
// Else if the error type is different
|
||||
else if (loadErrorType != errorType())
|
||||
|
@ -2847,7 +2847,7 @@ manifestTargetPath(const Manifest *this, const ManifestTarget *target)
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
String *pgPath = strPath(manifestPathPg(target->name));
|
||||
String *pgPath = strCat(strNew(), strPath(manifestPathPg(target->name)));
|
||||
|
||||
if (strSize(pgPath) != 0)
|
||||
strCatZ(pgPath, "/");
|
||||
|
@ -101,7 +101,7 @@ pgClientEscape(const String *string)
|
||||
|
||||
ASSERT(string != NULL);
|
||||
|
||||
String *result = strNewZ("'");
|
||||
String *result = strCatZ(strNew(), "'");
|
||||
|
||||
// Iterate all characters in the string
|
||||
for (unsigned stringIdx = 0; stringIdx < strSize(string); stringIdx++)
|
||||
@ -134,7 +134,7 @@ pgClientOpen(PgClient *this)
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Base connection string
|
||||
String *connInfo = strNewFmt("dbname=%s port=%u", strZ(pgClientEscape(this->database)), this->port);
|
||||
String *connInfo = strCatFmt(strNew(), "dbname=%s port=%u", strZ(pgClientEscape(this->database)), this->port);
|
||||
|
||||
// Add user if specified
|
||||
if (this->user != NULL)
|
||||
|
@ -209,7 +209,7 @@ protocolServerProcess(
|
||||
if (errType == NULL)
|
||||
{
|
||||
errType = errorType();
|
||||
errMessage = strNewZ(errorMessage());
|
||||
errMessage = strCatZ(strNew(), errorMessage());
|
||||
errMessageFirst = strNewZ(errorMessage());
|
||||
errStackTrace = strNewZ(errorStackTrace());
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ storageGcsAuthJwt(StorageGcs *this, time_t timeBegin)
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Static header with dot delimiter
|
||||
String *result = strNewZ("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.");
|
||||
String *result = strCatZ(strNew(), "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.");
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
@ -382,7 +382,7 @@ storageGcsRequestAsync(StorageGcs *this, const String *verb, StorageGcsRequestAs
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Generate path
|
||||
String *path = strNewFmt("%s/storage/v1/b", param.upload ? "/upload" : "");
|
||||
String *path = strCatFmt(strNew(), "%s/storage/v1/b", param.upload ? "/upload" : "");
|
||||
|
||||
if (!param.noBucket)
|
||||
strCatFmt(path, "/%s/o", strZ(this->bucket));
|
||||
|
@ -306,9 +306,9 @@ storageRepoPathExpression(const String *expression, const String *path)
|
||||
{
|
||||
// Construct the base path
|
||||
if (storageHelper.stanza != NULL)
|
||||
result = strNewFmt(STORAGE_PATH_ARCHIVE "/%s", strZ(storageHelper.stanza));
|
||||
result = strCatFmt(strNew(), STORAGE_PATH_ARCHIVE "/%s", strZ(storageHelper.stanza));
|
||||
else
|
||||
result = strNewZ(STORAGE_PATH_ARCHIVE);
|
||||
result = strCatZ(strNew(), STORAGE_PATH_ARCHIVE);
|
||||
|
||||
// If a subpath should be appended, determine if it is WAL path, else just append the subpath
|
||||
if (path != NULL)
|
||||
@ -326,9 +326,9 @@ storageRepoPathExpression(const String *expression, const String *path)
|
||||
{
|
||||
// Construct the base path
|
||||
if (storageHelper.stanza != NULL)
|
||||
result = strNewFmt(STORAGE_PATH_BACKUP "/%s", strZ(storageHelper.stanza));
|
||||
result = strCatFmt(strNew(), STORAGE_PATH_BACKUP "/%s", strZ(storageHelper.stanza));
|
||||
else
|
||||
result = strNewZ(STORAGE_PATH_BACKUP);
|
||||
result = strCatZ(strNew(), STORAGE_PATH_BACKUP);
|
||||
|
||||
// Append subpath if provided
|
||||
if (path != NULL)
|
||||
|
@ -174,8 +174,8 @@ storageS3Auth(
|
||||
const StringList *headerList = strLstSort(strLstDup(httpHeaderList(httpHeader)), sortOrderAsc);
|
||||
String *signedHeaders = NULL;
|
||||
|
||||
String *canonicalRequest = strNewFmt(
|
||||
"%s\n%s\n%s\n", strZ(verb), strZ(path), query == NULL ? "" : strZ(httpQueryRenderP(query)));
|
||||
String *canonicalRequest = strCatFmt(
|
||||
strNew(), "%s\n%s\n%s\n", strZ(verb), strZ(path), query == NULL ? "" : strZ(httpQueryRenderP(query)));
|
||||
|
||||
for (unsigned int headerIdx = 0; headerIdx < strLstSize(headerList); headerIdx++)
|
||||
{
|
||||
@ -189,7 +189,7 @@ storageS3Auth(
|
||||
strCatFmt(canonicalRequest, "%s:%s\n", strZ(headerKeyLower), strZ(httpHeaderGet(httpHeader, headerKey)));
|
||||
|
||||
if (signedHeaders == NULL)
|
||||
signedHeaders = strDup(headerKeyLower);
|
||||
signedHeaders = strCat(strNew(), headerKeyLower);
|
||||
else
|
||||
strCatFmt(signedHeaders, ";%s", strZ(headerKeyLower));
|
||||
}
|
||||
|
@ -349,7 +349,7 @@ hrnLogReplace(void)
|
||||
}
|
||||
|
||||
// Build replacement string. If versioned then append the version number.
|
||||
String *replace = strNewFmt("[%s", strZ(logReplace->replacement));
|
||||
String *replace = strCatFmt(strNew(), "[%s", strZ(logReplace->replacement));
|
||||
|
||||
if (logReplace->version)
|
||||
{
|
||||
|
@ -188,7 +188,7 @@ testStorageGet(const Storage *const storage, const char *const file, const char
|
||||
ASSERT(storage != NULL);
|
||||
ASSERT(file != NULL);
|
||||
|
||||
String *fileFull = storagePathP(storage, STR(file));
|
||||
String *fileFull = strCat(strNew(), storagePathP(storage, STR(file)));
|
||||
|
||||
// Add compression extension if one exists
|
||||
compressExtCat(fileFull, param.compressType);
|
||||
@ -433,7 +433,7 @@ hrnStoragePut(
|
||||
ASSERT(file != NULL);
|
||||
|
||||
// Add compression extension to file name
|
||||
String *fileStr = strNewZ(file);
|
||||
String *fileStr = strCatZ(strNew(), file);
|
||||
compressExtCat(fileStr, param.compressType);
|
||||
|
||||
// Create file
|
||||
|
@ -876,7 +876,7 @@ testRun(void)
|
||||
TEST_TITLE("encrypted/compressed file in backup");
|
||||
|
||||
// Create a compressed encrypted repo file in backup
|
||||
filePathName = strNewZ(STORAGE_REPO_BACKUP "/testfile");
|
||||
filePathName = strCatZ(strNew(), STORAGE_REPO_BACKUP "/testfile");
|
||||
HRN_STORAGE_PUT_Z(
|
||||
storageRepoWrite(), strZ(filePathName), fileContents, .compressType = compressTypeGz, .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = "pass");
|
||||
|
@ -370,7 +370,7 @@ testRun(void)
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("compressExtCat()");
|
||||
|
||||
String *file = strNewZ("file");
|
||||
String *file = strCatZ(strNew(), "file");
|
||||
TEST_RESULT_VOID(compressExtCat(file, compressTypeGz), "cat gz ext");
|
||||
TEST_RESULT_STR_Z(file, "file.gz", " check gz ext");
|
||||
|
||||
|
@ -42,6 +42,7 @@ testRun(void)
|
||||
TEST_ERROR(CHECK_SIZE(STRING_SIZE_MAX + 1), AssertError, "string size must be <= 1073741824 bytes");
|
||||
|
||||
String *string = strNewZ("static string");
|
||||
TEST_RESULT_BOOL(string->pub.buffer == (char *)(string + 1), true, "string has fixed buffer");
|
||||
TEST_RESULT_STR_Z(string, "static string", "new with static string");
|
||||
TEST_RESULT_UINT(strSize(string), 13, "check size");
|
||||
TEST_RESULT_BOOL(strEmpty(string), false, "is not empty");
|
||||
@ -77,8 +78,10 @@ testRun(void)
|
||||
TEST_TITLE("empty string is allocated extra space");
|
||||
|
||||
TEST_ASSIGN(string, strNew(), "new empty string");
|
||||
TEST_RESULT_UINT(string->pub.size, 0, " check size");
|
||||
TEST_RESULT_UINT(string->pub.extra, 64, " check extra");
|
||||
TEST_RESULT_UINT(string->pub.size, 0, "check size");
|
||||
TEST_RESULT_UINT(string->pub.extra, 0, "check extra");
|
||||
TEST_RESULT_PTR(string->pub.buffer, EMPTY_STR->pub.buffer, "check buffer");
|
||||
TEST_RESULT_VOID(strFree(string), "free string");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("strNewEncode()");
|
||||
@ -122,23 +125,34 @@ testRun(void)
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("strCat*()"))
|
||||
{
|
||||
String *string = strNewZ("XXXX");
|
||||
String *string = strCatZ(strNew(), "XXX");
|
||||
String *string2 = strNewZ("ZZZZ");
|
||||
|
||||
TEST_RESULT_STR_Z(strCat(string, STRDEF("YYYY")), "XXXXYYYY", "cat string");
|
||||
TEST_RESULT_STR_Z(strCatN(string, STRDEF("XX"), 1), "XXXX", "cat N chars");
|
||||
TEST_RESULT_UINT(string->pub.extra, 60, "check extra");
|
||||
TEST_RESULT_STR_Z(strCatFmt(string, "%05d", 777), "XXXXYYYY00777", "cat formatted string");
|
||||
TEST_RESULT_STR_Z(strCatZ(string, ""), "XXXX", "cat empty string");
|
||||
TEST_RESULT_UINT(string->pub.extra, 60, "check extra");
|
||||
TEST_RESULT_STR_Z(strCatEncode(string, encodeBase64, BUFSTRDEF("")), "XXXX", "cat empty encode");
|
||||
TEST_RESULT_UINT(string->pub.extra, 60, "check extra");
|
||||
TEST_RESULT_STR_Z(strCat(string, STRDEF("YYYY")), "XXXXYYYY", "cat string");
|
||||
TEST_RESULT_UINT(string->pub.extra, 56, "check extra");
|
||||
TEST_RESULT_STR_Z(strCatZN(string, NULL, 0), "XXXXYYYY", "cat 0");
|
||||
TEST_RESULT_UINT(string->pub.extra, 56, "check extra");
|
||||
TEST_RESULT_STR_Z(strCatBuf(string, BUFSTRDEF("?")), "XXXXYYYY?", "cat buf");
|
||||
TEST_RESULT_UINT(string->pub.extra, 55, "check extra");
|
||||
TEST_RESULT_STR_Z(strCatChr(string, '!'), "XXXXYYYY00777!", "cat chr");
|
||||
TEST_RESULT_UINT(string->pub.extra, 54, "check extra");
|
||||
TEST_RESULT_STR_Z(strCatFmt(string, "%05d", 777), "XXXXYYYY?00777", "cat formatted string");
|
||||
TEST_RESULT_UINT(string->pub.extra, 50, "check extra");
|
||||
TEST_RESULT_STR_Z(strCatChr(string, '!'), "XXXXYYYY?00777!", "cat chr");
|
||||
TEST_RESULT_UINT(string->pub.extra, 49, "check extra");
|
||||
TEST_RESULT_STR_Z(
|
||||
strCatZN(string, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*", 55),
|
||||
"XXXXYYYY00777!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "cat chr");
|
||||
TEST_RESULT_UINT(string->pub.extra, 34, "check extra");
|
||||
"XXXXYYYY?00777!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "cat chr");
|
||||
TEST_RESULT_UINT(string->pub.extra, 35, "check extra");
|
||||
TEST_RESULT_STR_Z(
|
||||
strCatEncode(string, encodeBase64, BUFSTRDEF("zzzzz")),
|
||||
"XXXXYYYY00777!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$enp6eno=", "cat encode");
|
||||
TEST_RESULT_UINT(string->pub.extra, 26, "check extra");
|
||||
"XXXXYYYY?00777!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$enp6eno=", "cat encode");
|
||||
TEST_RESULT_UINT(string->pub.extra, 27, "check extra");
|
||||
TEST_RESULT_VOID(strFree(string), "free string");
|
||||
|
||||
TEST_RESULT_STR_Z(string2, "ZZZZ", "check unaltered string");
|
||||
}
|
||||
@ -262,7 +276,7 @@ testRun(void)
|
||||
TEST_RESULT_INT(strChr(STRDEF("abcd"), 'i'), -1, "i not found");
|
||||
TEST_RESULT_INT(strChr(STRDEF(""), 'x'), -1, "empty string - x not found");
|
||||
|
||||
String *val = strNewZ("abcdef");
|
||||
String *val = strCatZ(strNew(), "abcdef");
|
||||
TEST_ERROR(
|
||||
strTrunc(val, (int)(strSize(val) + 1)), AssertError,
|
||||
"assertion 'idx >= 0 && (size_t)idx <= strSize(this)' failed");
|
||||
|
@ -221,7 +221,7 @@ testRun(void)
|
||||
{
|
||||
CHECK(TEST_SCALE <= 10000);
|
||||
|
||||
String *iniStr = strNewZ("[section1]\n");
|
||||
String *iniStr = strCatZ(strNew(), "[section1]\n");
|
||||
unsigned int iniMax = 100000 * (unsigned int)TEST_SCALE;
|
||||
|
||||
for (unsigned int keyIdx = 0; keyIdx < iniMax; keyIdx++)
|
||||
|
@ -40,7 +40,7 @@ typedef struct TestRequestParam
|
||||
static void
|
||||
testRequest(IoWrite *write, const char *verb, const char *path, TestRequestParam param)
|
||||
{
|
||||
String *request = strNewFmt("%s /" TEST_ACCOUNT "/" TEST_CONTAINER, verb);
|
||||
String *request = strCatFmt(strNew(), "%s /" TEST_ACCOUNT "/" TEST_CONTAINER, verb);
|
||||
|
||||
// When SAS spit out the query and merge in the SAS key
|
||||
if (driver->sasKey != NULL)
|
||||
@ -125,7 +125,7 @@ testResponse(IoWrite *write, TestResponseParam param)
|
||||
param.code = param.code == 0 ? 200 : param.code;
|
||||
|
||||
// Output header and code
|
||||
String *response = strNewFmt("HTTP/1.1 %u ", param.code);
|
||||
String *response = strCatFmt(strNew(), "HTTP/1.1 %u ", param.code);
|
||||
|
||||
// Add reason for some codes
|
||||
switch (param.code)
|
||||
|
@ -82,7 +82,8 @@ typedef struct TestRequestParam
|
||||
static void
|
||||
testRequest(IoWrite *write, const char *verb, TestRequestParam param)
|
||||
{
|
||||
String *request = strNewFmt("%s %s/storage/v1/b%s", verb, param.upload ? "/upload" : "", param.noBucket ? "" : "/bucket/o");
|
||||
String *request = strCatFmt(
|
||||
strNew(), "%s %s/storage/v1/b%s", verb, param.upload ? "/upload" : "", param.noBucket ? "" : "/bucket/o");
|
||||
|
||||
// Add object
|
||||
if (param.object != NULL)
|
||||
@ -140,7 +141,7 @@ testResponse(IoWrite *write, TestResponseParam param)
|
||||
param.code = param.code == 0 ? 200 : param.code;
|
||||
|
||||
// Output header and code
|
||||
String *response = strNewFmt("HTTP/1.1 %u ", param.code);
|
||||
String *response = strCatFmt(strNew(), "HTTP/1.1 %u ", param.code);
|
||||
|
||||
// Add reason for some codes
|
||||
switch (param.code)
|
||||
@ -335,7 +336,8 @@ testRun(void)
|
||||
const char *const preamble = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=";
|
||||
const String *const jwt = storageGcsAuthJwt(((StorageGcs *)storageDriver(storage)), time(NULL));
|
||||
|
||||
String *const authRequest = strNewFmt(
|
||||
String *const authRequest = strCatFmt(
|
||||
strNew(),
|
||||
"POST /token HTTP/1.1\r\n"
|
||||
"user-agent:" PROJECT_NAME "/" PROJECT_VERSION "\r\n"
|
||||
"content-length:%zu\r\n"
|
||||
|
@ -51,7 +51,7 @@ testRequest(IoWrite *write, Storage *s3, const char *verb, const char *path, Tes
|
||||
}
|
||||
|
||||
// Add request
|
||||
String *request = strNewFmt("%s %s HTTP/1.1\r\nuser-agent:" PROJECT_NAME "/" PROJECT_VERSION "\r\n", verb, path);
|
||||
String *request = strCatFmt(strNew(), "%s %s HTTP/1.1\r\nuser-agent:" PROJECT_NAME "/" PROJECT_VERSION "\r\n", verb, path);
|
||||
|
||||
// Add authorization header when s3 service
|
||||
if (s3 != NULL)
|
||||
@ -142,7 +142,7 @@ testResponse(IoWrite *write, TestResponseParam param)
|
||||
param.code = param.code == 0 ? 200 : param.code;
|
||||
|
||||
// Output header and code
|
||||
String *response = strNewFmt("HTTP/%s %u ", param.http == NULL ? "1.1" : param.http, param.code);
|
||||
String *response = strCatFmt(strNew(), "HTTP/%s %u ", param.http == NULL ? "1.1" : param.http, param.code);
|
||||
|
||||
// Add reason for some codes
|
||||
switch (param.code)
|
||||
|
Loading…
Reference in New Issue
Block a user