/*
* Copyright (c) 2020 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/kernel/vdoStringUtils.c#1 $
*/
#include "vdoStringUtils.h"
#include "errors.h"
#include "logger.h"
#include "memoryAlloc.h"
#include "stringUtils.h"
#include "statusCodes.h"
/**********************************************************************/
char *vAppendToBuffer(char *buffer,
char *bufEnd,
const char *fmt,
va_list args)
{
size_t n = vsnprintf(buffer, bufEnd - buffer, fmt, args);
if (n >= (size_t) (bufEnd - buffer)) {
buffer = bufEnd;
} else {
buffer += n;
}
return buffer;
}
/**********************************************************************/
char *appendToBuffer(char *buffer, char *bufEnd, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
char *pos = vAppendToBuffer(buffer, bufEnd, fmt, ap);
va_end(ap);
return pos;
}
/**********************************************************************/
void freeStringArray(char **stringArray)
{
for (unsigned int offset = 0; stringArray[offset] != NULL; offset++) {
FREE(stringArray[offset]);
}
FREE(stringArray);
}
/**********************************************************************/
int splitString(const char *string, char separator, char ***substringArrayPtr)
{
unsigned int substringCount = 1;
for (const char *s = string; *s != 0; s++) {
if (*s == separator) {
substringCount++;
}
}
char **substrings;
int result = ALLOCATE(substringCount + 1, char *, "string-splitting array",
&substrings);
if (result != UDS_SUCCESS) {
return result;
}
unsigned int currentSubstring = 0;
for (const char *s = string; *s != 0; s++) {
if (*s == separator) {
ptrdiff_t length = s - string;
result = ALLOCATE(length + 1, char, "split string",
&substrings[currentSubstring]);
if (result != UDS_SUCCESS) {
freeStringArray(substrings);
return result;
}
// Trailing NUL is already in place after allocation; deal with
// the zero or more non-NUL bytes in the string.
if (length > 0) {
memcpy(substrings[currentSubstring], string, length);
}
string = s + 1;
currentSubstring++;
BUG_ON(currentSubstring >= substringCount);
}
}
// Process final string, with no trailing separator.
BUG_ON(currentSubstring != (substringCount - 1));
ptrdiff_t length = strlen(string);
result = ALLOCATE(length + 1, char, "split string",
&substrings[currentSubstring]);
if (result != UDS_SUCCESS) {
freeStringArray(substrings);
return result;
}
memcpy(substrings[currentSubstring], string, length);
currentSubstring++;
// substrings[currentSubstring] is NULL already
*substringArrayPtr = substrings;
return UDS_SUCCESS;
}
/**********************************************************************/
int joinStrings(char **substringArray,
size_t arrayLength,
char separator,
char **stringPtr)
{
size_t stringLength = 0;
for (size_t i = 0; (i < arrayLength) && (substringArray[i] != NULL); i++) {
stringLength += strlen(substringArray[i]) + 1;
}
char *output;
int result = ALLOCATE(stringLength, char, __func__, &output);
if (result != VDO_SUCCESS) {
return result;
}
char *currentPosition = &output[0];
for (size_t i = 0; (i < arrayLength) && (substringArray[i] != NULL); i++) {
currentPosition = appendToBuffer(currentPosition, output + stringLength,
"%s", substringArray[i]);
*currentPosition = separator;
currentPosition++;
}
// We output one too many separators; replace the last with a zero byte.
if (currentPosition != output) {
*(currentPosition - 1) = '\0';
}
*stringPtr = output;
return UDS_SUCCESS;
}
/**********************************************************************/
int stringToUInt(const char *input, unsigned int *valuePtr)
{
unsigned long longValue;
int result = kstrtoul(input, 10, &longValue);
if (result != 0) {
return result;
}
if (longValue > UINT_MAX) {
return -ERANGE;
}
*valuePtr = longValue;
return UDS_SUCCESS;
}