I have an application that builds file path names through a series of string concatenations using pieces of text to create a complete file path name.
The question is whether an approach to handle concatenating a small but arbitrary number of strings of text together depends on Undefined Behavior for success.
Is the order of evaluation of a series of nested functions guaranteed or not?
I found this question Nested function calls order of evaluation however it seems to be more about multiple functions in the argument list rather than a sequence of nesting functions.
Please excuse the names in the following code samples. It is congruent with the rest of the source code and I am testing things out a bit first.
My first cut on the need to concatenate several strings was a function that looked like the following which would concatenate up to three text strings into a single string.
typedef wchar_t TCHAR;
TCHAR *RflCatFilePath(TCHAR *tszDest, int nDestLen, TCHAR *tszPath, TCHAR *tszPath2, TCHAR *tszFileName)
{
if (tszDest && nDestLen > 0) {
TCHAR *pDest = tszDest;
TCHAR *pLast = tszDest;
*pDest = 0; // ensure empty string if no path data provided.
if (tszPath) for (pDest = pLast; nDestLen > 0 && (*pDest++ = *tszPath++); nDestLen--) pLast = pDest;
if (tszPath2) for (pDest = pLast; nDestLen > 0 && (*pDest++ = *tszPath2++); nDestLen--) pLast = pDest;
if (tszFileName) for (pDest = pLast; nDestLen > 0 && (*pDest++ = *tszFileName++); nDestLen--) pLast = pDest;
}
return tszDest;
}
Then I ran into a case where I had four pieces of text to put together.
Thinking through this it seemed that most probably there would also be a case for five that would be uncovered shortly so I wondered if there was a different way for an arbitrary number of strings.
What I came up with is two functions as follows.
typedef wchar_t TCHAR;
typedef struct {
TCHAR *pDest;
TCHAR *pLast;
int destLen;
} RflCatStruct;
RflCatStruct RflCatFilePathX(const TCHAR *pPath, RflCatStruct x)
{
TCHAR *pDest = x.pLast;
if (pDest && pPath) for ( ; x.destLen > 0 && (*pDest++ = *pPath++); x.destLen--) x.pLast = pDest;
return x;
}
RflCatStruct RflCatFilePathY(TCHAR *buffDest, int nLen, const TCHAR *pPath)
{
RflCatStruct x = { 0 };
TCHAR *pDest = x.pDest = buffDest;
x.pLast = buffDest;
x.destLen = nLen;
if (buffDest && nLen > 0) { // ensure there is room for at least one character.
*pDest = 0; // ensure empty string if no path data provided.
if (pPath) for (pDest = x.pLast; x.destLen > 0 && (*pDest++ = *pPath++); x.destLen--) x.pLast = pDest;
}
return x;
}
Examples of using these two functions is as follows. This code with the two functions appears to work fine with Visual Studio 2013.
TCHAR buffDest[512] = { 0 };
TCHAR *pPath = L"C:\\flashdisk\\ncr\\database";
TCHAR *pPath2 = L"\\";
TCHAR *pFilename = L"filename.ext";
RflCatFilePathX(pFilename, RflCatFilePathX(pPath2, RflCatFilePathY(buffDest, 512, pPath)));
printf("dest t = \"%S\"\n", buffDest);
printf("dest t = \"%S\"\n", RflCatFilePathX(pFilename, RflCatFilePathX(pPath2, RflCatFilePathY(buffDest, 512, pFilename))).pDest);
RflCatStruct dStr = RflCatFilePathX(pPath2, RflCatFilePathY(buffDest, 512, pPath));
// other stuff then
printf("dest t = \"%S\"\n", RflCatFilePathX(pFilename, dStr).pDest);