PosNextTR)
{
// leave current position unchanged
fseek (FileSrc,CurPos,SEEK_SET);
return Str;
}
Str_FindStrInFile (FileSrc,">",Str_NO_SKIP_HTML_COMMENTS);
for (EndCellFound = false;
!EndCellFound;
)
{
if ((Ch = Str_ReadCharAndSkipComments (FileSrc,Str_SKIP_HTML_COMMENTS)) == EOF) // Set pointer to '<' if not comment, or to first character after comment if comment
break;
/***** Skip directives except | *****/
DirectiveFound = (Ch == (int) '<');
if (DirectiveFound) // Start of directive, not a comment
{
/* Check if it's */
if (!strcasecmp (Str_GetNextStrFromFileConvertingToLower (FileSrc,StrAux,1),"/")) // It's
if (!strcasecmp (Str_GetNextStrFromFileConvertingToLower (FileSrc,StrAux,1),"t")) // It's ")) // It's
EndCellFound = true; // found
if (!EndCellFound)
{
/* Skip directive */
Str_FindStrInFileBack (FileSrc,"<",Str_NO_SKIP_HTML_COMMENTS);
Str_FindStrInFile (FileSrc,">",Str_NO_SKIP_HTML_COMMENTS);
}
}
if (!EndCellFound)
{
if (DirectiveFound)
Ch = (int) ' '; // Replace directive for ' ' (separator)
else
{
/***** Check for space or *****/
SpaceFound = false;
if (Ch == (int) '&')
{
/* Check for (case insensitive) */
if (strcasecmp (Str_GetNextStrFromFileConvertingToLower (FileSrc,StrAux,1),"n"))
{ // It's not &n
Str_FindStrInFileBack (FileSrc,"&",Str_NO_SKIP_HTML_COMMENTS); // Back until &
Str_FindStrInFile (FileSrc,"&",Str_NO_SKIP_HTML_COMMENTS); // Skip &
}
else if (strcasecmp (Str_GetNextStrFromFileConvertingToLower (FileSrc,StrAux,1),"b"))
{ // It's not &nb
Str_FindStrInFileBack (FileSrc,"&",Str_NO_SKIP_HTML_COMMENTS); // Back until &
Str_FindStrInFile (FileSrc,"&",Str_NO_SKIP_HTML_COMMENTS); // Skip &
}
else if (strcasecmp (Str_GetNextStrFromFileConvertingToLower (FileSrc,StrAux,1),"s"))
{ // It's not &nbs
Str_FindStrInFileBack (FileSrc,"&",Str_NO_SKIP_HTML_COMMENTS); // Back until &
Str_FindStrInFile (FileSrc,"&",Str_NO_SKIP_HTML_COMMENTS); // Skip &
}
else if (strcasecmp (Str_GetNextStrFromFileConvertingToLower (FileSrc,StrAux,1),"p"))
{ // It's not  
Str_FindStrInFileBack (FileSrc,"&",Str_NO_SKIP_HTML_COMMENTS); // Back until &
Str_FindStrInFile (FileSrc,"&",Str_NO_SKIP_HTML_COMMENTS); // Skip &
}
else if (strcasecmp (Str_GetNextStrFromFileConvertingToLower (FileSrc,StrAux,1),";"))
{ // It's not
Str_FindStrInFileBack (FileSrc,"&",Str_NO_SKIP_HTML_COMMENTS); // Back until &
Str_FindStrInFile (FileSrc,"&",Str_NO_SKIP_HTML_COMMENTS); // Skip &
}
else // It's
SpaceFound = true;
}
/***** Skip spaces *****/
if (isspace (Ch) ||
Ch == 0xA0) // Unicode translation for
SpaceFound = true;
if (SpaceFound)
Ch = (int) ' '; // Replace any kind of space for ' ' (separator)
}
if (i < MaxLength)
Str[i++] = (char) Ch;
}
}
Str[i] = '\0';
return Str;
}
/*****************************************************************************/
/******************* Read the next N characters in a string ******************/
/*****************************************************************************/
/*
Read from the file FileSrc the next N characters converting them
to lowercase and store them in Str. Return a pointer to the string.
*/
char *Str_GetNextStrFromFileConvertingToLower (FILE *FileSrc,char *Str, int N)
{
int i,Ch;
for (i = 0;
i < N;
i++)
{
if ((Ch = fgetc (FileSrc)) == EOF)
break;
Str[i] = Str_ConvertToLowerLetter ((char) Ch);
}
Str[i] = '\0';
return Str;
}
/*****************************************************************************/
/********** Get from StrSrc into StrDst the next string until space **********/
/*****************************************************************************/
// Modifies *StrSrc
void Str_GetNextStringUntilSpace (const char **StrSrc,char *StrDst,size_t MaxLength)
{
size_t i = 0;
int Ch;
/***** Skip leading spaces *****/
do
{
if ((Ch = (int) **StrSrc) != 0)
(*StrSrc)++;
}
while (isspace (Ch) ||
Ch == 0xA0); // Unicode translation for
/***** Copy string while non-space characters *****/
while (Ch &&
!(isspace (Ch) ||
Ch == 0xA0)) // Unicode translation for
{
if (i < MaxLength)
StrDst[i++] = (char) Ch;
if ((Ch = (int) **StrSrc) != 0)
(*StrSrc)++;
}
StrDst[i] = '\0';
}
/*****************************************************************************/
/******* Get from StrSrc into StrDst the next string until separator *********/
/*****************************************************************************/
// Modifies *StrSrc
void Str_GetNextStringUntilSeparator (const char **StrSrc,char *StrDst,size_t MaxLength)
{
size_t i = 0;
int Ch;
/***** Skip separators *****/
do
{
if ((Ch = (int) **StrSrc) != 0)
(*StrSrc)++;
}
while (isspace (Ch) ||
Ch == 0xA0 || // Unicode translation for
Ch == (int) ',' ||
Ch == (int) ';');
/***** Copy string while no separator found *****/
while (Ch &&
!(isspace (Ch) ||
Ch == 0xA0 || // Unicode translation for
Ch == (int) ',' ||
Ch == (int) ';'))
{
if (i < MaxLength)
StrDst[i++] = (char) Ch;
if ((Ch = (int) **StrSrc) != 0)
(*StrSrc)++;
}
StrDst[i] = '\0';
}
/*****************************************************************************/
/********** Get from StrSrc into StrDst the next string until comma **********/
/*****************************************************************************/
// Modifies *StrSrc
// Leading spaces are not copied
// Trailing spaces are removed at end
void Str_GetNextStringUntilComma (const char **StrSrc,char *StrDst,size_t MaxLength)
{
int Ch;
char *Ptr;
size_t i = 0;
/***** Skip leading spaces and ',' *****/
Ch = (int) **StrSrc;
while (isspace (Ch) ||
Ch == 0xA0 || // Unicode translation for
Ch == (int) ',')
{
(*StrSrc)++;
Ch = (int) **StrSrc;
}
/***** Copy string until ',' or end *****/
Ptr = StrDst;
while (Ch && Ch != (int) ',')
{
if (i < MaxLength)
{
*Ptr++ = (char) Ch;
i++;
}
(*StrSrc)++;
Ch = (int) **StrSrc;
}
/***** Remove trailing spaces *****/
for (Ptr--;
Ptr >= *StrSrc;
Ptr--)
if (!(isspace ((int) *Ptr) ||
*Ptr == '\xA0')) // Unicode translation for
break;
*(Ptr + 1) = '\0';
}
/*****************************************************************************/
/***************** Replace several spaces of a string for one ****************/
/*****************************************************************************/
void Str_ReplaceSeveralSpacesForOne (char *Str)
{
char *PtrSrc, *PtrDst;
bool PreviousWasSpace = false;
/***** Do the replacing *****/
for (PtrDst = PtrSrc = Str;
*PtrSrc;)
if (isspace ((int) *PtrSrc) ||
*PtrSrc == '\xA0') // Unicode translation for
{
if (!PreviousWasSpace)
*PtrDst++ = ' ';
PreviousWasSpace = true;
PtrSrc++;
}
else
{
PreviousWasSpace = false;
*PtrDst++ = *PtrSrc++;
}
*PtrDst = '\0';
}
/*****************************************************************************/
/************* Copy a string to another changing ' ' to '%20' ****************/
/*****************************************************************************/
void Str_CopyStrChangingSpaces (const char *StringWithSpaces,char *StringWithoutSpaces,unsigned MaxLength)
{
const char *PtrSrc;
char *PtrDst;
unsigned Length = 0;
for (PtrSrc = StringWithSpaces, PtrDst = StringWithoutSpaces;
*PtrSrc && Length <= MaxLength;
PtrSrc++)
if (*PtrSrc == ' ')
{
Length += 3;
if (Length <= MaxLength)
{
*PtrDst++ = '%';
*PtrDst++ = '2';
*PtrDst++ = '0';
}
}
else
{
Length++;
if (Length <= MaxLength)
*PtrDst++ = *PtrSrc;
}
*PtrDst = '\0';
if (Length > MaxLength)
Lay_ShowErrorAndExit ("Path is too long.");
}
/*****************************************************************************/
/* Convert string with a code (of group type, group, degree, etc.) to long **/
/*****************************************************************************/
// Return -1L if code not found in Str
long Str_ConvertStrCodToLongCod (const char *Str)
{
long Code;
if (!Str)
return -1L;
if (Str[0] == '\0')
return -1L;
if (sscanf (Str,"%ld",&Code) != 1)
return -1L;
return Code;
}
/*****************************************************************************/
/**** Compute length of root (all except extension) of the name of a file ****/
/*****************************************************************************/
size_t Str_GetLengthRootFileName (const char *FileName)
{
char *PtrToDot = strrchr (FileName,(int) '.');
size_t LengthFileName = strlen (FileName);
if (PtrToDot)
return LengthFileName - strlen (PtrToDot);
else
return LengthFileName;
}
/*****************************************************************************/
/************** Get the name of a file from a complete path ******************/
/*****************************************************************************/
// Split a full path in path (without ending '/' ) and a file name
void Str_SplitFullPathIntoPathAndFileName (const char FullPath[PATH_MAX + 1],
char PathWithoutFileName[PATH_MAX + 1],
char FileName[NAME_MAX + 1])
{
const char *PtrFileName;
size_t LengthUntilFileName;
/***** Find the start of filename *****/
if ((PtrFileName = strrchr (FullPath,(int) '/')) != NULL)
PtrFileName++;
else if ((PtrFileName = strrchr (FullPath,(int) '\\')) != NULL)
PtrFileName++;
else
PtrFileName = FullPath;
/***** Get PathWithoutFileName *****/
LengthUntilFileName = (size_t) (PtrFileName - FullPath); // Last slash included
if (LengthUntilFileName > 1)
{
Str_Copy (PathWithoutFileName,FullPath,
PATH_MAX);
PathWithoutFileName[LengthUntilFileName - 1] = '\0'; // Do not copy ending slash
}
else
PathWithoutFileName[0] = '\0';
/***** Get FileName *****/
Str_Copy (FileName,PtrFileName,
NAME_MAX);
}
/*****************************************************************************/
/************** Check if the extension of a file is .Extension ***************/
/*****************************************************************************/
// Return true if FileName ends by .Extension
// Else return false
bool Str_FileIs (const char *FileName,const char *Extension)
{
int i;
int j;
size_t LengthExtension = strlen (Extension);
/***** Check length of extension. Extension valid are, for example "zip", "html", "mhtml" *****/
if (LengthExtension < Fil_MIN_BYTES_FILE_EXTENSION ||
LengthExtension > Fil_MAX_BYTES_FILE_EXTENSION)
return false;
/***** Check the extension *****/
for (i = strlen (FileName) - 1, j = LengthExtension - 1;
i > 0 && j >= 0;
i--, j--)
if (Str_ConvertToLowerLetter (FileName[i]) != Str_ConvertToLowerLetter (Extension[j]))
return false;
if (j >= 0) /* If all the characters of the extension have not been checked
due to the name of the file is too short */
return false;
/***** Check the dot before the extension *****/
return (FileName[i] == '.');
}
/*****************************************************************************/
/**************** Check if the extension of a file is .html ******************/
/*****************************************************************************/
// Return true if FileName ends by .htm or .html
// Else return false
bool Str_FileIsHTML (const char *FileName)
{
if (Str_FileIs (FileName,"htm"))
return true;
return Str_FileIs (FileName,"html");
}
/*****************************************************************************/
/********************* Check if Path1 starts by Path2 ************************/
/*****************************************************************************/
bool Str_Path1BeginsByPath2 (const char *Path1,const char *Path2)
{
/* The string Path1 must start by the complete string Path2 */
while (*Path2)
if (*Path2++ != *Path1++)
return false;
/* The string Path1 starts by the complete string Path2 */
/* Check that the next character of Path1 is '\0' or '/' */
return (bool) (*Path1 == '\0' || *Path1 == '/');
}
/*****************************************************************************/
/** Skip spaces in a file seeking it before of reading the first non-blank ***/
/*****************************************************************************/
void Str_SkipSpacesInFile (FILE *FileSrc)
{
int Ch;
while ((Ch = fgetc (FileSrc)) != EOF)
if (!(isspace (Ch) ||
Ch == 0xA0)) // Unicode translation for
{
fseek (FileSrc,-1L,SEEK_CUR);
break;
}
}
/*****************************************************************************/
/***************** Write a string to a file changing *************************/
/*****************
or
for return *************************/
/***************** and for space *************************/
/*****************************************************************************/
void Str_FilePrintStrChangingBRToRetAndNBSPToSpace (FILE *FileTgt,const char *Str)
{
while (*Str)
{
/* Is ? */
if (*Str == '&')
{
if (*(Str + 1) == 'N' || *(Str + 1) == 'n')
if (*(Str + 2) == 'B' || *(Str + 2) == 'b')
if (*(Str + 3) == 'S' || *(Str + 3) == 's')
if (*(Str + 4) == 'P' || *(Str + 4) == 'p')
if (*(Str + 5) == ';')
{
fputc ((int) ' ',FileTgt);
Str += 6;
continue;
}
}
/* Is
or
? */
else if (*Str == '<')
{
if (*(Str + 1) == 'B' || *(Str + 1) == 'b')
if (*(Str + 2) == 'R' || *(Str + 2) == 'r')
{
if (*(Str + 3) == '>')
{
fputc ((int) '\n',FileTgt);
Str += 4;
continue;
}
else if (*(Str + 3) == ' ')
{
if (*(Str + 4) == '/')
if (*(Str + 5) == '>')
{
fputc ((int) '\n',FileTgt);
Str += 6;
continue;
}
}
}
}
fputc ((int) *Str,FileTgt);
Str++;
}
}
/*****************************************************************************/
/*************** Search a string in a file and/or in a string ****************/
/*****************************************************************************/
/*
Search in the file FileSrc the string StrDelimit.
Write in the file FileTgt and/or StrDst the characters read from FileSrc, not including StrDelimit!.
StrDst can be NULL if you don't want to use them.
If StrDelimit is found, return 1.
If what is read exceed MaxLength, abort and return 0.
If StrDelimit is not found, return -1.
*/
#define Str_MAX_BYTES_BOUNDARY_STR 100
int Str_ReadFileUntilBoundaryStr (FILE *FileSrc,char *StrDst,
const char *BoundaryStr,
unsigned LengthBoundaryStr,
unsigned long long MaxLength)
{
unsigned NumBytesIdentical; // Number of characters identical in each iteration of the loop
unsigned NumBytesReadButNotDiscarded; // Number of characters read from the source file...
// ...and not fully discarded in search
int Buffer[Str_MAX_BYTES_BOUNDARY_STR + 1];
unsigned StartIndex;
unsigned i;
char *Ptr; // Pointer used to go through StrDst writing characters
unsigned long long LengthDst;
/***** Checkings on boundary string *****/
if (!LengthBoundaryStr)
{
if (StrDst != NULL)
*StrDst = '\0';
return 1;
}
if (LengthBoundaryStr > Str_MAX_BYTES_BOUNDARY_STR)
Lay_ShowErrorAndExit ("Delimiter string too large.");
Ptr = StrDst;
StartIndex = 0;
NumBytesReadButNotDiscarded = 0;
LengthDst = 0;
for (;;)
{
if (!NumBytesReadButNotDiscarded)
{ // Read next character
Buffer[StartIndex] = fgetc (FileSrc);
if (feof (FileSrc))
{
if (StrDst != NULL)
*Ptr = '\0';
return -1;
}
NumBytesReadButNotDiscarded++;
}
if (Buffer[StartIndex] == (int) BoundaryStr[0]) // First character identical
{
for (NumBytesIdentical = 1, i = (StartIndex + 1) % LengthBoundaryStr;
NumBytesIdentical < LengthBoundaryStr;
NumBytesIdentical++, i = (i + 1) % LengthBoundaryStr)
{
if (NumBytesReadButNotDiscarded == NumBytesIdentical) // Last character is identical
{
Buffer[i] = fgetc (FileSrc); // Read next character
if (feof (FileSrc))
{
if (StrDst != NULL)
*Ptr = '\0';
return -1;
}
NumBytesReadButNotDiscarded++;
}
if (Buffer[i] != (int) BoundaryStr[NumBytesIdentical]) // Next character is different
break;
}
if (NumBytesIdentical == LengthBoundaryStr) // Boundary found
{
if (StrDst != NULL)
*Ptr = '\0';
return 1;
}
}
if (LengthDst == MaxLength)
{
if (StrDst != NULL)
*Ptr = '\0';
return 0;
}
if (StrDst != NULL)
*Ptr++ = (char) Buffer[StartIndex];
StartIndex = (StartIndex + 1) % LengthBoundaryStr;
NumBytesReadButNotDiscarded--;
LengthDst++;
}
return 0; // Not reached
}
/*****************************************************************************/
/****** Convert invalid characters in a file name to valid characters ********/
/*****************************************************************************/
// Return true if the name of the file o folder is valid
// If the name is not valid, Gbl.Alert.Txt will contain feedback text
// File names with heading and trailing spaces are allowed
bool Str_ConvertFilFolLnkNameToValid (char *FileName)
{
extern const char *Txt_UPLOAD_FILE_X_invalid_name_NO_HTML;
extern const char *Txt_UPLOAD_FILE_X_invalid_name;
extern const char *Txt_UPLOAD_FILE_Invalid_name_NO_HTML;
extern const char *Txt_UPLOAD_FILE_Invalid_name;
char *Ptr;
unsigned NumAlfanum = 0;
unsigned NumSpaces = 0;
unsigned NumPoints = 0;
bool FileNameIsOK = false;
Ptr = FileName;
if (*Ptr) // FileName is not empty
{
for (;
*Ptr;
Ptr++)
{
if (*Ptr == ' ')
{
NumPoints = 0;
if (++NumSpaces > 1)
{
*Ptr = '_';
NumAlfanum++;
NumSpaces = NumPoints = 0;
}
}
else if (*Ptr == '.')
{
if (++NumPoints > 1) // Don't allow ".."
{
*Ptr = '_';
NumAlfanum++;
NumSpaces = NumPoints = 0;
}
}
else
{
switch (*Ptr)
{
case 'á': *Ptr = 'a'; break;
case 'é': *Ptr = 'e'; break;
case 'í': *Ptr = 'i'; break;
case 'ó': *Ptr = 'o'; break;
case 'ú': *Ptr = 'u'; break;
case 'ñ': *Ptr = 'n'; break;
case 'ä': *Ptr = 'a'; break;
case 'ë': *Ptr = 'e'; break;
case 'ï': *Ptr = 'i'; break;
case 'ö': *Ptr = 'o'; break;
case 'ü': *Ptr = 'u'; break;
case 'ç': *Ptr = 'c'; break;
case 'Á': *Ptr = 'A'; break;
case 'É': *Ptr = 'E'; break;
case 'Í': *Ptr = 'I'; break;
case 'Ó': *Ptr = 'O'; break;
case 'Ú': *Ptr = 'U'; break;
case 'Ñ': *Ptr = 'N'; break;
case 'Ä': *Ptr = 'A'; break;
case 'Ë': *Ptr = 'E'; break;
case 'Ï': *Ptr = 'I'; break;
case 'Ö': *Ptr = 'O'; break;
case 'Ü': *Ptr = 'U'; break;
case 'Ç': *Ptr = 'C'; break;
}
if ((*Ptr >= 'a' && *Ptr <= 'z') ||
(*Ptr >= 'A' && *Ptr <= 'Z') ||
(*Ptr >= '0' && *Ptr <= '9') ||
*Ptr == '_' ||
*Ptr == '-')
{
NumAlfanum++;
NumSpaces = NumPoints = 0;
}
else
{
*Ptr = '_';
NumAlfanum++;
NumSpaces = NumPoints = 0;
}
}
}
if (NumAlfanum)
FileNameIsOK = true;
else
snprintf (Gbl.Alert.Txt,sizeof (Gbl.Alert.Txt),
Gbl.FileBrowser.UploadingWithDropzone ? Txt_UPLOAD_FILE_X_invalid_name_NO_HTML :
Txt_UPLOAD_FILE_X_invalid_name,
FileName);
}
else // FileName is empty
Str_Copy (Gbl.Alert.Txt,
Gbl.FileBrowser.UploadingWithDropzone ? Txt_UPLOAD_FILE_Invalid_name_NO_HTML :
Txt_UPLOAD_FILE_Invalid_name,
Ale_MAX_BYTES_ALERT);
return FileNameIsOK;
}
/*****************************************************************************/
/************ Convert a string to a valid name of file or folder *************/
/*****************************************************************************/
void Str_ConvertToValidFileName (char *Str)
{
char *Ptr;
for (Ptr = Str;
*Ptr;
Ptr++)
{
if ((*Ptr >= 'a' && *Ptr <= 'z') ||
(*Ptr >= 'A' && *Ptr <= 'Z') ||
(*Ptr >= '0' && *Ptr <= '9') ||
*Ptr == '_' ||
*Ptr == '-')
continue;
if (isspace ((int) *Ptr) ||
*Ptr == '\xA0')
*Ptr = '_';
else
switch (*Ptr)
{
case 'á': case 'à': case 'ä': case 'â': *Ptr = 'a'; break;
case 'é': case 'è': case 'ë': case 'ê': *Ptr = 'e'; break;
case 'í': case 'ì': case 'ï': case 'î': *Ptr = 'i'; break;
case 'ó': case 'ò': case 'ö': case 'ô': *Ptr = 'o'; break;
case 'ú': case 'ù': case 'ü': case 'û': *Ptr = 'u'; break;
case 'ñ': *Ptr = 'n'; break;
case 'ç': *Ptr = 'c'; break;
case 'Á': case 'À': case 'Ä': case 'Â': *Ptr = 'A'; break;
case 'É': case 'È': case 'Ë': case 'Ê': *Ptr = 'E'; break;
case 'Í': case 'Ì': case 'Ï': case 'Î': *Ptr = 'I'; break;
case 'Ó': case 'Ò': case 'Ö': case 'Ô': *Ptr = 'O'; break;
case 'Ú': case 'Ù': case 'Ü': case 'Û': *Ptr = 'U'; break;
case 'Ñ': *Ptr = 'N'; break;
case 'Ç': *Ptr = 'C'; break;
default: *Ptr = '-'; break;
}
}
}
/*****************************************************************************/
/******************* Create a random alphanumeric string *********************/
/*****************************************************************************/
#define NUM_ALPHANUM_CHARS (10 + 26 + 26)
void Str_CreateRandomAlphanumStr (char *Str,size_t Length)
{
static const char CharTable[NUM_ALPHANUM_CHARS] =
{'0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'
};
size_t i;
/***** Set random chars in string *****/
for (i = 0;
i DstSize)
{
snprintf (Gbl.Alert.Txt,sizeof (Gbl.Alert.Txt),
"Trying to copy %lu chars into a %lu-chars buffer.",
LengthSrc,DstSize);
Lay_ShowErrorAndExit (Gbl.Alert.Txt);
}
/***** Copy source into destination *****/
strcpy (Dst,Src);
}
/*****************************************************************************/
/************************** Safe string concatenation ************************/
/*****************************************************************************/
// DstSize does not include ending byte '\0'
void Str_Concat (char *Dst,const char *Src,size_t DstSize)
{
size_t LengthDst;
size_t LengthSrc;
size_t FreeSpace;
/***** Check if buffer has already overflowed *****/
LengthDst = strlen (Dst);
if (LengthDst > DstSize)
{
snprintf (Gbl.Alert.Txt,sizeof (Gbl.Alert.Txt),
"%lu-chars buffer has %lu chars!",
DstSize,LengthDst);
Lay_ShowErrorAndExit (Gbl.Alert.Txt);
}
/***** Check if buffer has enough space for source *****/
// DstSize >= LengthDst ==> FreeSpace >= 0
FreeSpace = DstSize - LengthDst;
LengthSrc = strlen (Src);
if (FreeSpace < LengthSrc)
{
snprintf (Gbl.Alert.Txt,sizeof (Gbl.Alert.Txt),
"Trying to concatenate %lu chars to a %lu-chars buffer with free space for only %lu chars!",
LengthSrc,DstSize,FreeSpace);
Lay_ShowErrorAndExit (Gbl.Alert.Txt);
}
/***** Concatenate ******/
strcat (Dst,Src);
}