blob: b1ca9766f37ac039e117595f03b7c5fa979eab6b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 - 2013 ACIN, Profactor GmbH, fortiss GmbH, nxtControl 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, Monika Wenger, Matthias Plasch, Martin Melik Markumians,
* Ingo Hegny, Stanislav Meduna
* - initial implementation and rework communication infrastructure
*******************************************************************************/
#include "forte_any_elementary.h"
#ifdef FORTE_ENABLE_GENERATED_SOURCE_CPP
#include "forte_any_elementary_gen.cpp"
#endif
#include <stdlib.h>
#include <errno.h>
#include "forte_sint.h"
#include "forte_int.h"
#include "forte_dint.h"
#include "forte_usint.h"
#include "forte_uint.h"
#include "forte_udint.h"
#include "forte_lint.h"
#include "forte_ulint.h"
DEFINE_FIRMWARE_DATATYPE(ANY_ELEMENTARY, g_nStringIdANY_ELEMENTARY)
const CStringDictionary::TStringId CIEC_ANY_ELEMENTARY::scm_anTypeNameStringIds[] = { g_nStringIdANY, g_nStringIdBOOL, g_nStringIdSINT, g_nStringIdINT, g_nStringIdDINT, g_nStringIdLINT, g_nStringIdUSINT, g_nStringIdUINT, g_nStringIdUDINT, g_nStringIdULINT, g_nStringIdBYTE, g_nStringIdWORD, g_nStringIdDWORD, g_nStringIdLWORD, g_nStringIdDATE, g_nStringIdTIME_OF_DAY, g_nStringIdDATE_AND_TIME, g_nStringIdTIME, //until here simple Datatypes
g_nStringIdREAL, g_nStringIdLREAL, g_nStringIdSTRING, //e_STRING,
g_nStringIdWSTRING, //e_WSTRING,
CStringDictionary::scm_nInvalidStringId, //e_DerivedData,
CStringDictionary::scm_nInvalidStringId, //e_DirectlyDerivedData,
CStringDictionary::scm_nInvalidStringId, //e_EnumeratedData,
CStringDictionary::scm_nInvalidStringId, //e_SubrangeData,
CStringDictionary::scm_nInvalidStringId, //e_ARRAY,
CStringDictionary::scm_nInvalidStringId, //e_STRUCT,
CStringDictionary::scm_nInvalidStringId, //e_External,
CStringDictionary::scm_nInvalidStringId, //e_Max
};
int CIEC_ANY_ELEMENTARY::toString(char* paValue, size_t paBufferSize) const {
int nRetVal = 0;
TLargestUIntValueType nDivisor = 0;
TLargestUIntValueType nUBuffer = 0;
TLargestIntValueType nSBuffer = 0;
bool bSigned = true;
switch (getDataTypeID()){
case e_SINT:
nSBuffer = getTINT8();
nDivisor = 100;
break;
case e_USINT:
case e_BYTE:
nUBuffer = getTUINT8();
nDivisor = 100;
bSigned = false;
break;
case e_INT:
nSBuffer = getTINT16();
nDivisor = 10000;
break;
case e_UINT:
case e_WORD:
nUBuffer = getTUINT16();
nDivisor = 10000;
bSigned = false;
break;
case e_DINT:
nSBuffer = getTINT32();
nDivisor = 1000000000L;
break;
case e_UDINT:
case e_DWORD:
nUBuffer = getTUINT32();
nDivisor = 1000000000L;
bSigned = false;
break;
#ifdef FORTE_USE_64BIT_DATATYPES
case e_LINT:
nSBuffer = getTINT64();
nDivisor = 1000000000000000000LL;
break;
case e_ULINT:
case e_LWORD:
nUBuffer = getTUINT64();
nDivisor = 10000000000000000000ULL;
bSigned = false;
break;
#endif
default:
return CIEC_ANY::toString(paValue, paBufferSize);
}
if(true == bSigned){
if(nSBuffer < 0){
if(nRetVal >= static_cast<int>(paBufferSize)) {
return -1;
}
paValue[nRetVal] = '-';
nRetVal++;
nSBuffer *= -1;
}
nUBuffer = static_cast<TLargestUIntValueType>(nSBuffer);
}
bool bLeadingZeros = true;
do{
if((0 == nUBuffer / nDivisor) && (true == bLeadingZeros)){
nDivisor /= 10;
continue;
}
else{
bLeadingZeros = false;
}
if(nRetVal >= static_cast<int>(paBufferSize)) {
return -1;
}
paValue[nRetVal] = static_cast<char>(static_cast<char>(nUBuffer / nDivisor) + '0');
nUBuffer = nUBuffer - (paValue[nRetVal] - '0') * nDivisor;
nDivisor /= 10;
nRetVal++;
} while(nDivisor > 1);
if(nRetVal >= static_cast<int>(paBufferSize)) {
return -1;
}
paValue[nRetVal] = static_cast<char>(static_cast<char>(nUBuffer / nDivisor) + '0');
nRetVal++;
if(nRetVal >= static_cast<int>(paBufferSize)) {
return -1;
}
paValue[nRetVal] = '\0';
return nRetVal;
}
int CIEC_ANY_ELEMENTARY::fromString(const char *pa_pacValue){
int nRetVal = -1;
const char *pacRunner = pa_pacValue;
if((0 == pa_pacValue) || ('\0' == *pa_pacValue)){
return -1;
}
if(e_ANY == getDataTypeID()){
nRetVal = CIEC_ANY::fromString(pa_pacValue);
//TODO think of a check if it is really an any elementary that has been created
}
else{
const char *acHashPos = strchr(pa_pacValue, '#');
int nMultiplier = 10;
bool bSigned = true;
if((0 != acHashPos) && (!forte::core::util::isDigit(*pa_pacValue))){
//if we have a hash and the first character is not a digit it has to be a type identifier
nRetVal = checkTypeSpec(pa_pacValue, acHashPos);
if(nRetVal < 0){
return -1;
}
pacRunner += (nRetVal + 1); //put the runner one after the hash
nRetVal = -1;
}
TLargestUIntValueType nUUpperBound = 0;
TLargestIntValueType nSUpperBound = 0;
TLargestIntValueType nSLowerBound = 0;
if('#' == pacRunner[1]){
switch (pacRunner[0]){
case '2':
nMultiplier = 2;
break;
case '8':
nMultiplier = 8;
break;
default:
return -1;
break;
}
pacRunner = pacRunner + 2;
}
else if('\0' != pacRunner[1] && '#' == pacRunner[2]){
if('1' == pacRunner[0]){
if('6' == pacRunner[1]){
nMultiplier = 16;
}
else{
if('0' != pacRunner[1]){
return -1;
}
}
} else {
return -1;
}
pacRunner = pacRunner + 3;
}
EDataTypeID eID = getDataTypeID();
switch (eID){
case e_SINT:
nSUpperBound = CIEC_SINT::scm_nMaxVal;
nSLowerBound = CIEC_SINT::scm_nMinVal;
break;
case e_INT:
nSUpperBound = CIEC_INT::scm_nMaxVal;
nSLowerBound = CIEC_INT::scm_nMinVal;
break;
case e_DINT:
nSUpperBound = CIEC_DINT::scm_nMaxVal;
nSLowerBound = CIEC_DINT::scm_nMinVal;
break;
#ifdef FORTE_USE_64BIT_DATATYPES
case e_LINT:
nSUpperBound = CIEC_LINT::scm_nMaxVal;
nSLowerBound = CIEC_LINT::scm_nMinVal;
break;
#endif
case e_USINT:
case e_BYTE:
nUUpperBound = CIEC_USINT::scm_nMaxVal;
bSigned = false;
break;
case e_UINT:
case e_WORD:
nUUpperBound = CIEC_UINT::scm_nMaxVal;
bSigned = false;
break;
case e_UDINT:
case e_DWORD:
nUUpperBound = CIEC_UDINT::scm_nMaxVal;
bSigned = false;
break;
#ifdef FORTE_USE_64BIT_DATATYPES
case e_ULINT:
case e_LWORD:
nUUpperBound = CIEC_ULINT::scm_nMaxVal;
bSigned = false;
break;
#endif
default:
return false;
}
if((bSigned) && (10 != nMultiplier)){
//only decimal numbers have a sign
bSigned = false;
nUUpperBound = 2 * nSUpperBound + 1;
}
char *pacEndPtr;
errno = 0; //erno is not cleared by the strto* functions
if(true == bSigned){
#ifdef FORTE_USE_64BIT_DATATYPES
TForteInt64 nValue = forte::core::util::strtoll(pacRunner, &pacEndPtr, nMultiplier);
#else
TForteInt32 nValue = forte::core::util::strtol(pacRunner, &pacEndPtr, nMultiplier);
#endif
if((ERANGE != errno)&& (nValue <= nSUpperBound) && (nValue
>= nSLowerBound)){
setLargestInt(nValue);
nRetVal = static_cast<int>(pacEndPtr - pa_pacValue);
}
}
else{
if ('-' != *pacRunner){
//The strtou* functions will correctly parse also negative numbers and provide their two complement as value
#ifdef FORTE_USE_64BIT_DATATYPES
TForteUInt64 nValue = forte::core::util::strtoull(pacRunner, &pacEndPtr, nMultiplier);
#else
TForteUInt32 nValue = forte::core::util::strtoul(pacRunner, &pacEndPtr, nMultiplier);
#endif //FORTE_USE_64BIT_DATATYPES
if ((ERANGE != errno) && (nValue <= nUUpperBound)){
setLargestUInt(nValue);
nRetVal = static_cast<int>(pacEndPtr - pa_pacValue);
}
}
}
if(0 == nRetVal){
// at this point a length of zero means broken string so return -1
nRetVal = -1;
}
}
return nRetVal;
}
int CIEC_ANY_ELEMENTARY::checkTypeSpec(const char *pa_pacValue, const char *pa_pacHashPos){
int nRetVal = -1;
CStringDictionary::TStringId nTypeNameId = parseTypeName(pa_pacValue, pa_pacHashPos);
if((CStringDictionary::scm_nInvalidStringId != nTypeNameId) && (scm_anTypeNameStringIds[getDataTypeID()] == nTypeNameId)){
nRetVal = static_cast<int>(pa_pacHashPos - pa_pacValue);
}
return nRetVal;
}