blob: 9140789df4fa25c7246fc10ffa20f95bb0475a1d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 fortiss GmbH
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Alois Zoitl
* - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "string_utils.h"
#include <forte_dint.h>
#include <forte_udint.h>
#include <forte_lint.h>
#include <forte_ulint.h>
#include "../../arch/devlog.h"
#include <errno.h>
#include <string.h>
bool forte::core::util::isAtoFChar(char pa_cValue){
pa_cValue = static_cast<char>(toupper(pa_cValue));
return ((pa_cValue >= 'A') && (pa_cValue <= 'F'));
}
TForteInt8 forte::core::util::charAtoFToInt(char pa_cValue){
return static_cast<TForteInt8>((toupper(pa_cValue) - 'A') + 10);
}
long int forte::core::util::strtol(const char *nptr, char **endptr, int base) {
long int nRetVal = 0;
bool bNegativeNumber = false;
errno = 0;
//in difference to IEC 611313-3 literals base 16 literals may have a leading -
if((*nptr) == '-'){
bNegativeNumber = true;
++nptr;
}
if(16 == base && (('0' == (*nptr)) && ('x' == nptr[1]))){
//we have a preceding 0x step over it
nptr += 2;
}
long nLimit1 = (bNegativeNumber ? -(CIEC_DINT::scm_nMinVal / base) : (CIEC_DINT::scm_nMaxVal / base));
long nLimit2 = (bNegativeNumber ? -(CIEC_DINT::scm_nMinVal % base) : (CIEC_DINT::scm_nMaxVal % base));
if (nLimit2 < 0) // Rounding direction for negative numbers is implementation defined
{
nLimit1--;
nLimit2 = base-nLimit2;
}
for(; *nptr; ++nptr){ //Do until '/0'
if((!isDigit(*nptr)) && (!((16 == base) && isAtoFChar(*nptr)))){
//we have an invalid character
break;
}
TForteInt8 nCharVal = charHexDigitToInt(*nptr);
if(nRetVal > nLimit1 || (nRetVal == nLimit1 && nCharVal > nLimit2)) {
nRetVal = (bNegativeNumber) ? CIEC_DINT::scm_nMinVal : CIEC_DINT::scm_nMaxVal;
errno = ERANGE;
break;
}
nRetVal = base * nRetVal + nCharVal;
}
if((bNegativeNumber) && (ERANGE != errno)){
nRetVal = -nRetVal;
}
if(0 != endptr){
*endptr = const_cast<char*>(nptr);
}
return nRetVal;
}
unsigned long int forte::core::util::strtoul(const char *nptr, char **endptr, int base){
unsigned long int unRetVal = 0;
unsigned long int unLimit1 = (CIEC_UDINT::scm_nMaxVal / base);
unsigned long int unLimit2 = (CIEC_UDINT::scm_nMaxVal % base);
errno = 0;
if((16 == base) && ('0' == (*nptr)) && ('x' == nptr[1])){
//we have a preceding 0x step over it
nptr += 2;
}
for(; *nptr; ++nptr){ //Do until '/0'
if((!isDigit(*nptr)) && (!((16 == base) && isAtoFChar(*nptr)))){
//we have an invalid character
break;
}
TForteInt8 nCharVal = charHexDigitToInt(*nptr);
if(unRetVal > unLimit1 || (unRetVal == unLimit1 && (unsigned long int) nCharVal > unLimit2)){
//in this round we would exceed the limit of the data type
unRetVal = CIEC_UDINT::scm_nMaxVal;
errno = ERANGE;
break;
}
unRetVal = base * unRetVal + nCharVal;
}
if(0 != endptr){
*endptr = const_cast<char*>(nptr);
}
return unRetVal;
}
#ifdef FORTE_USE_64BIT_DATATYPES
long long int forte::core::util::strtoll(const char *nptr, char **endptr, int base) {
long long int nRetVal = 0;
bool bNegativeNumber = false;
errno = 0;
//in difference to IEC 611313-3 literals base 16 literals may have a leading -
if((*nptr) == '-'){
bNegativeNumber = true;
++nptr;
}
if(16 == base && ('0' == (*nptr)) && ('x' == nptr[1])){
//we have a preceding 0x step over it
nptr += 2;
}
long long nLimit1;
long long nLimit2;
if (bNegativeNumber){
volatile long long nLimMinDiv = CIEC_LINT::scm_nMinVal / base;
volatile long long nLimMinMod = CIEC_LINT::scm_nMinVal % base;
nLimit1 = -nLimMinDiv;
nLimit2 = -nLimMinMod;
if (nLimit2 < 0) // Rounding direction for negative numbers is implementation defined
{
nLimit1--;
nLimit2 = base-nLimit2;
}
}
else{
nLimit1 = CIEC_LINT::scm_nMaxVal / base;
nLimit2 = CIEC_LINT::scm_nMaxVal % base;
}
for(; *nptr; ++nptr){ //Do until '/0'
if((!isDigit(*nptr)) && (!((16 == base) && isAtoFChar(*nptr)))){
//we have an invalid character
break;
}
TForteInt8 nCharVal = charHexDigitToInt(*nptr);
if(nRetVal > nLimit1 || (nRetVal == nLimit1 && nCharVal > nLimit2)){
nRetVal = (bNegativeNumber) ? CIEC_LINT::scm_nMinVal : CIEC_LINT::scm_nMaxVal;
errno = ERANGE;
break;
}
nRetVal = base * nRetVal + nCharVal;
}
if((bNegativeNumber) && (ERANGE != errno)){
nRetVal = -nRetVal;
}
if(0 != endptr){
*endptr = const_cast<char*>(nptr);
}
return nRetVal;
}
unsigned long long int forte::core::util::strtoull(const char *nptr, char **endptr, int base){
unsigned long long int unRetVal = 0;
unsigned long long int unLimit1 = (CIEC_ULINT::scm_nMaxVal / base);
unsigned long long int unLimit2 = (CIEC_ULINT::scm_nMaxVal % base);
errno = 0;
if((16 == base) && ('0' == (*nptr)) && ('x' == nptr[1])){
//we have a preceding 0x step over it
nptr += 2;
}
for(; *nptr; ++nptr){ //Do until '/0'
if((!isDigit(*nptr)) && (!((16 == base) && isAtoFChar(*nptr)))){
//we have an invalid character
break;
}
TForteInt8 nCharVal = charHexDigitToInt(*nptr);
if(unRetVal > unLimit1 || (unRetVal == unLimit1 && (unsigned long long int) nCharVal > unLimit2)){
//in this round we would exceed the limit of the data type
unRetVal = CIEC_ULINT::scm_nMaxVal;
errno = ERANGE;
break;
}
unRetVal = base * unRetVal + nCharVal;
}
if(0 != endptr){
*endptr = const_cast<char*>(nptr);
}
return unRetVal;
}
#endif
size_t forte::core::util::getExtraSizeForXMLEscapedChars(const char* paString){
size_t retVal = 0;
while(0 != *paString){
for(size_t i = 0; i < sizeof(forte::core::util::scReplacementForXMLEscapedCharacters) / sizeof(const char* const); i++){
if(forte::core::util::scXMLEscapedCharacters[i] == *paString){
retVal += strlen(forte::core::util::scReplacementForXMLEscapedCharacters[i]) - 1;
break;
}
}
paString++;
}
return retVal;
}
size_t forte::core::util::transformNonEscapedToEscapedXMLText(char* const paString){
size_t retVal = 0;
char* runner = strchr(paString, '\0');
char* originalEnd = runner;
runner--;
while(paString <= runner){
const char* toCopy = 0;
for(size_t i = 0; i < sizeof(forte::core::util::scReplacementForXMLEscapedCharacters) / sizeof(const char* const ); i++){
if(forte::core::util::scXMLEscapedCharacters[i] == *runner){
toCopy = forte::core::util::scReplacementForXMLEscapedCharacters[i];
break;
}
}
if(0 != toCopy){
size_t toMove = strlen(toCopy);
memmove(&runner[toMove], runner + 1, originalEnd - runner + retVal);
memcpy(runner, toCopy, toMove);
retVal += toMove - 1;
}
runner--;
}
return retVal;
}
size_t forte::core::util::transformEscapedXMLToNonEscapedText(char* const paString){
char* runner = paString;
char *endRunner = strchr(paString, '\0');
size_t retVal = 0;
while(runner <= endRunner){
if('&' == *runner){
char toCopy = 0;
size_t toMove = 0;
for(size_t i = 0; i < sizeof(forte::core::util::scReplacementForXMLEscapedCharacters) / sizeof(const char* const ); i++){
if(0 == strncmp(runner, forte::core::util::scReplacementForXMLEscapedCharacters[i], strlen(forte::core::util::scReplacementForXMLEscapedCharacters[i]))){
toCopy = forte::core::util::scXMLEscapedCharacters[i];
toMove = strlen(forte::core::util::scReplacementForXMLEscapedCharacters[i]);
break;
}
}
if(0 != toCopy){
*runner = toCopy;
memmove(runner + 1, &runner[toMove], (endRunner - &runner[toMove]) + 1);
endRunner -= toMove - 1;
retVal += toMove - 1;
}
else{
DEVLOG_ERROR("[XML Transformer] The given XML text has & character but it's none of the known escaped characters");
}
}
runner++;
}
return retVal;
}
char * forte::core::util::lookForNonEscapedChar(char **paString, char paChar, char paEscapingChar) {
char *foundChar = 0;
char* initialPosition = *paString;
while(!foundChar && '\0' != **paString) {
foundChar = strchr(*paString, paChar);
if(0 != foundChar) {
*paString = foundChar;
if(isEscaped(foundChar, initialPosition, paEscapingChar)) {
while('\0' != *foundChar) { //move the rest of the string one char back
*(foundChar - 1) = *foundChar;
foundChar++;
}
*(foundChar - 1) = *foundChar; //move also the ending \0
foundChar = 0; //reset to keep looking
} else {
*foundChar = '\0';
(*paString)++;
}
} else { //there's no paChar in the string
break;
}
}
return foundChar;
}
bool forte::core::util::isEscaped(char *paChar, char *paBeginLimit, char paEscapingChar) {
size_t noOfScapingSigns = 0;
while(paBeginLimit != paChar) { //count the amount of \ signs before paChar to know if the \ signs was also escaped.
paChar--;
if(paEscapingChar == *paChar) {
noOfScapingSigns++;
} else {
break;
}
}
return (noOfScapingSigns % 2); //an even number of \ (or zero) means paChar was not escaped
}
void forte::core::util::removeEscapedSigns(char **paString, char paEscapingChar) {
char *runner = *paString;
while('\0' != *runner) {
if(paEscapingChar == *runner && paEscapingChar == *(runner + 1)) {
char *copier = runner + 1;
while('\0' != *copier) {
*(copier - 1) = *copier;
copier++;
}
*(copier - 1) = *copier; //move also the ending \0
}
runner++;
}
}