Refactor/snprintf next common shift function (#656)

This commit is contained in:
Steve Karg
2024-05-30 09:16:05 -05:00
committed by GitHub
parent 309964e929
commit 0cbf7414a4
5 changed files with 277 additions and 446 deletions
+54 -267
View File
@@ -1864,6 +1864,31 @@ int bacapp_data_len(
return total_len;
}
/**
* @brief Shift the buffer pointer and decrease the size after an snprintf
* @param len - number of bytes (excluding terminating NULL byte) from snprintf
* @param buf - pointer to the buffer pointer
* @param buf_size - pointer to the buffer size
* @return number of bytes (excluding terminating NULL byte) from snprintf
*/
int bacapp_snprintf_shift(int len, char **buf, size_t *buf_size)
{
if (buf) {
if (*buf) {
*buf += len;
}
}
if (buf_size) {
if ((*buf_size) >= len) {
*buf_size -= len;
} else {
*buf_size = 0;
}
}
return len;
}
#if defined(BACAPP_DATE)
/**
* @brief Print a date value to a string for EPICS
@@ -1891,29 +1916,13 @@ static int bacapp_snprintf_date(char *str, size_t str_len, BACNET_DATE *bdate)
/* cppcheck-suppress nullPointer */
/* cppcheck-suppress ctunullpointer */
slen = snprintf(str, str_len, "%s, %s", weekday_text, month_text);
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (bdate->day == 255) {
slen = snprintf(str, str_len, " (unspecified), ");
} else {
slen = snprintf(str, str_len, " %u, ", (unsigned)bdate->day);
}
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (bdate->year == 2155) {
slen = snprintf(str, str_len, "(unspecified)");
} else {
@@ -1949,43 +1958,19 @@ static int bacapp_snprintf_time(char *str, size_t str_len, BACNET_TIME *btime)
/* cppcheck-suppress nullPointer */
slen = snprintf(str, str_len, "%02u:", (unsigned)btime->hour);
}
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (btime->min == 255) {
slen = snprintf(str, str_len, "**:");
} else {
slen = snprintf(str, str_len, "%02u:", (unsigned)btime->min);
}
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (btime->sec == 255) {
slen = snprintf(str, str_len, "**.");
} else {
slen = snprintf(str, str_len, "%02u.", (unsigned)btime->sec);
}
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (btime->hundredths == 255) {
slen = snprintf(str, str_len, "**");
} else {
@@ -2043,16 +2028,7 @@ static int bacapp_snprintf_weeklyschedule(char *str,
slen = snprintf(
str, str_len, "(%s; ", bactext_application_tag_name(inner_tag));
}
ret_val += slen;
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
for (wi = 0; wi < loopend; wi++) {
BACNET_DAILY_SCHEDULE *ds = &ws->weeklySchedule[wi];
if (arrayIndex == BACNET_ARRAY_ALL) {
@@ -2063,81 +2039,28 @@ static int bacapp_snprintf_weeklyschedule(char *str,
? weekdaynames[arrayIndex - 1]
: "???");
}
ret_val += slen;
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
for (ti = 0; ti < ds->TV_Count; ti++) {
slen =
bacapp_snprintf_time(str, str_len, &ds->Time_Values[ti].Time);
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
slen = snprintf(str, str_len, " ");
ret_val += slen;
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
bacnet_primitive_to_application_data_value(
&dummyDataValue, &ds->Time_Values[ti].Value);
dummyPropValue.value = &dummyDataValue;
dummyPropValue.object_property = PROP_PRESENT_VALUE;
dummyPropValue.object_type = OBJECT_SCHEDULE;
slen = bacapp_snprintf_value(str, str_len, &dummyPropValue);
ret_val += slen;
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (ti < ds->TV_Count - 1) {
slen = snprintf(str, str_len, ", ");
ret_val += slen;
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
}
}
if (wi < loopend - 1) {
slen = snprintf(str, str_len, "]; ");
ret_val += slen;
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
}
}
slen = snprintf(str, str_len, "])");
@@ -2219,16 +2142,8 @@ int bacapp_snprintf_value(
octet_str = octetstring_value(&value->type.Octet_String);
for (i = 0; i < len; i++) {
slen = snprintf(str, str_len, "%02X", *octet_str);
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
octet_str++;
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
}
}
break;
@@ -2238,15 +2153,7 @@ int bacapp_snprintf_value(
len = characterstring_length(&value->type.Character_String);
char_str = characterstring_value(&value->type.Character_String);
slen = snprintf(str, str_len, "\"");
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
#if (__STDC_VERSION__ >= 199901L) && defined(__STDC_ISO_10646__)
if (characterstring_encoding(&value->type.Character_String) ==
CHARACTER_UTF8) {
@@ -2266,15 +2173,7 @@ int bacapp_snprintf_value(
}
/* For portability, cast wchar_t to wint_t */
slen = snprintf(str, str_len, "%lc", (wint_t)wc);
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (len > wclen) {
len -= wclen;
char_str += wclen;
@@ -2291,15 +2190,7 @@ int bacapp_snprintf_value(
} else {
slen = snprintf(str, str_len, "%c", '.');
}
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
char_str++;
}
}
@@ -2311,39 +2202,15 @@ int bacapp_snprintf_value(
case BACNET_APPLICATION_TAG_BIT_STRING:
len = bitstring_bits_used(&value->type.Bit_String);
slen = snprintf(str, str_len, "{");
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
for (i = 0; i < len; i++) {
bool bit;
bit = bitstring_bit(&value->type.Bit_String, (uint8_t)i);
slen = snprintf(str, str_len, "%s", bit ? "true" : "false");
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (i < (len - 1)) {
slen = snprintf(str, str_len, ",");
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
}
}
slen = snprintf(str, str_len, "}");
@@ -2464,15 +2331,7 @@ int bacapp_snprintf_value(
#if defined(BACAPP_OBJECT_ID)
case BACNET_APPLICATION_TAG_OBJECT_ID:
slen = snprintf(str, str_len, "(");
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (value->type.Object_Id.type <= BACNET_OBJECT_TYPE_LAST) {
slen = snprintf(str, str_len, "%s, ",
bactext_object_type_name(value->type.Object_Id.type));
@@ -2484,15 +2343,7 @@ int bacapp_snprintf_value(
slen = snprintf(str, str_len, "proprietary %u, ",
(unsigned)value->type.Object_Id.type);
}
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
slen = snprintf(str, str_len, "%lu)",
(unsigned long)value->type.Object_Id.instance);
ret_val += slen;
@@ -2502,25 +2353,9 @@ int bacapp_snprintf_value(
case BACNET_APPLICATION_TAG_DATERANGE:
slen = bacapp_snprintf_date(
str, str_len, &value->type.Date_Range.startdate);
ret_val += slen;
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
slen = snprintf(str, str_len, "..");
ret_val += slen;
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
slen = bacapp_snprintf_date(
str, str_len, &value->type.Date_Range.enddate);
ret_val += slen;
@@ -2537,25 +2372,9 @@ int bacapp_snprintf_value(
case BACNET_APPLICATION_TAG_DATETIME:
slen = bacapp_snprintf_date(
str, str_len, &value->type.Date_Time.date);
ret_val += slen;
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
slen = snprintf(str, str_len, "-");
ret_val += slen;
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
slen = bacapp_snprintf_time(
str, str_len, &value->type.Date_Time.time);
ret_val += slen;
@@ -2578,27 +2397,11 @@ int bacapp_snprintf_value(
case BACNET_APPLICATION_TAG_COLOR_COMMAND:
/* BACnetColorCommand */
slen = snprintf(str, str_len, "(");
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
slen = snprintf(str, str_len, "%s",
bactext_color_operation_name(
value->type.Color_Command.operation));
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
/* FIXME: add the Lighting Command optional values */
slen = snprintf(str, str_len, ")");
ret_val += slen;
@@ -2641,31 +2444,15 @@ int bacapp_snprintf_value(
len = characterstring_length(name);
char_str = characterstring_value(name);
slen = snprintf(str, str_len, "\"");
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
ret_val += slen;
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
for (i = 0; i < len; i++) {
if (isprint(*((unsigned char *)char_str))) {
slen = snprintf(str, str_len, "%c", *char_str);
} else {
slen = snprintf(str, str_len, "%c", '.');
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
char_str++;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
ret_val += slen;
}
slen = snprintf(str, str_len, "\"");
ret_val += slen;
+6
View File
@@ -314,6 +314,12 @@ extern "C" {
#define BACAPP_PRINT_ENABLED
#endif
#endif
BACNET_STACK_EXPORT
int bacapp_snprintf_shift(
int len,
char **buf,
size_t *buf_size);
BACNET_STACK_EXPORT
int bacapp_snprintf_value(
char *str,
+174 -145
View File
@@ -71,8 +71,7 @@ void bacnet_destination_default_init(BACNET_DESTINATION *destination)
* @param r2 - BACnetRecipient 2 structure
* @return true if r1 and r2 are the same
*/
bool bacnet_recipient_same(
BACNET_RECIPIENT *r1, BACNET_RECIPIENT *r2)
bool bacnet_recipient_same(BACNET_RECIPIENT *r1, BACNET_RECIPIENT *r2)
{
bool status = false;
@@ -103,8 +102,7 @@ bool bacnet_recipient_same(
* @param src - BACnetRecipient 1 structure
* @param dest - BACnetRecipient 2 structure
*/
void bacnet_recipient_copy(
BACNET_RECIPIENT *dest, BACNET_RECIPIENT *src)
void bacnet_recipient_copy(BACNET_RECIPIENT *dest, BACNET_RECIPIENT *src)
{
if (dest && src) {
memmove(dest, src, sizeof(BACNET_RECIPIENT));
@@ -170,8 +168,7 @@ bool bacnet_destination_same(BACNET_DESTINATION *d1, BACNET_DESTINATION *d2)
status = (datetime_compare_time(&d1->ToTime, &d2->ToTime) == 0);
}
if (status) {
status = bacnet_recipient_same(
&d1->Recipient, &d2->Recipient);
status = bacnet_recipient_same(&d1->Recipient, &d2->Recipient);
}
if (status) {
status = (d1->ProcessIdentifier == d2->ProcessIdentifier);
@@ -252,7 +249,8 @@ int bacnet_destination_encode(uint8_t *apdu, BACNET_DESTINATION *destination)
apdu += len;
}
if (destination->Recipient.tag == BACNET_RECIPIENT_TAG_DEVICE) {
len = encode_context_object_id(apdu, 0, OBJECT_DEVICE,
len = encode_context_object_id(
apdu, 0, OBJECT_DEVICE,
destination->Recipient.type.device.instance);
apdu_len += len;
if (apdu) {
@@ -392,7 +390,8 @@ int bacnet_destination_decode(
if (decode_is_context_tag(apdu, BACNET_RECIPIENT_TAG_DEVICE)) {
/* device [0] BACnetObjectIdentifier */
destination->Recipient.tag = BACNET_RECIPIENT_TAG_DEVICE;
len = decode_context_object_id(apdu, BACNET_RECIPIENT_TAG_DEVICE,
len = decode_context_object_id(
apdu, BACNET_RECIPIENT_TAG_DEVICE,
&destination->Recipient.type.device.type,
&destination->Recipient.type.device.instance);
if (len == BACNET_STATUS_ERROR) {
@@ -462,56 +461,52 @@ int bacnet_destination_decode(
return apdu_len;
}
#define LEN_BRANCH(snprintf_expr) \
do { \
len = snprintf_expr; \
output_len += len; \
if (buf) { \
if (len > buf_size) { \
return -1; \
} else { \
buf += len; \
buf_size -= len; \
} \
} \
} while (0)
/**
* Convert BACnet_Destination to ASCII for printing
*
* Output format:
*
* (ValidDays=[1,2,5,6,7];FromTime=0:00:00.0;ToTime=23:59:59.9;Recipient=Device(type=8,instance=15);ProcessIdentifier=0;ConfirmedNotify=false;Transitions=[to-offnormal,to-fault,to-normal])
* (
* ValidDays=[1,2,5,6,7];
* FromTime=0:00:00.0;
* ToTime=23:59:59.9;
* Recipient=Device(type=8,instance=15);
* ProcessIdentifier=0;
* ConfirmedNotify=false;
* Transitions=[to-offnormal,to-fault,to-normal]
* )
*
* - ValidDays ... array of numbers, 1=Mon through 7=Sun
* - FromTime, ToTime ... HH:MM:SS.s
* - Recipient ... two variants: Recipient=Device(type=8,instance=15) or Recipient=Address(net=1234,mac=c0:a8:00:0f)
* - Recipient ... two variants: Recipient=Device(type=8,instance=15) or
* Recipient=Address(net=1234,mac=c0:a8:00:0f)
* - type ... bacnet object type enum
* - instance ... bacnet object instance
* - net ... bacnet network number
* - mac ... bacnet MAC address; can be separated by colons or periods.
* - ProcessIdentifier ... 32bit unsigned int, process ID
* - ConfirmedNotify ... true or false
* - Transitions ... array with any of the three items: to-offnormal, to-fault, to-normal
* - Transitions ... array with any of the three items: to-offnormal, to-fault,
* to-normal
*
* @param bacdest - Destination struct to convert to ASCII
* @param buf - ASCII output buffer
* @param buf_size - ASCII output buffer capacity
*
* @return the number of characters which would be generated for the given
* input, excluding the trailing null. negative is returned if the capacity was not sufficient.
* input, excluding the trailing null.
* @note buf and buf_size may be null and zero to return only the size
*/
int bacnet_destination_to_ascii(const BACNET_DESTINATION *bacdest, char *buf, size_t buf_size)
int bacnet_destination_to_ascii(
const BACNET_DESTINATION *bacdest, char *buf, size_t buf_size)
{
int len = 0;
int output_len = 0;
int buf_len = 0;
bool comma;
int i;
LEN_BRANCH(snprintf(buf, buf_size, "("));
len = snprintf(buf, buf_size, "(");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
/*
BACnetDaysOfWeek ::= BIT STRING {
monday (0),
@@ -523,68 +518,80 @@ int bacnet_destination_to_ascii(const BACNET_DESTINATION *bacdest, char *buf, si
sunday (6)
}
*/
/* Use numbers 1-7 (ISO 8601) */
LEN_BRANCH(snprintf(buf, buf_size, "ValidDays=["));
len = snprintf(buf, buf_size, "ValidDays=[");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
comma = false;
for (i = 0; i < 7; i++) {
if (bitstring_bit((BACNET_BIT_STRING *) &bacdest->ValidDays, i)) {
if (bitstring_bit((BACNET_BIT_STRING *)&bacdest->ValidDays, i)) {
if (comma) {
LEN_BRANCH(snprintf(buf, buf_size, ","));
len = snprintf(buf, buf_size, ",");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
}
LEN_BRANCH(snprintf(buf, buf_size, "%d", i + 1));
len = snprintf(buf, buf_size, "%d", i + 1);
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
comma = true;
}
}
LEN_BRANCH(snprintf(buf, buf_size, "];"));
LEN_BRANCH(snprintf(buf, buf_size, "FromTime=%d:%02d:%02d.%02d;",
bacdest->FromTime.hour,
bacdest->FromTime.min,
bacdest->FromTime.sec,
bacdest->FromTime.hundredths
));
LEN_BRANCH(snprintf(buf, buf_size, "ToTime=%d:%02d:%02d.%02d;",
bacdest->ToTime.hour,
bacdest->ToTime.min,
bacdest->ToTime.sec,
bacdest->ToTime.hundredths
));
LEN_BRANCH(snprintf(buf, buf_size, "Recipient="));
len = snprintf(buf, buf_size, "];");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
len = snprintf(
buf, buf_size, "FromTime=%d:%02d:%02d.%02d;", bacdest->FromTime.hour,
bacdest->FromTime.min, bacdest->FromTime.sec,
bacdest->FromTime.hundredths);
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
len = snprintf(
buf, buf_size, "ToTime=%d:%02d:%02d.%02d;", bacdest->ToTime.hour,
bacdest->ToTime.min, bacdest->ToTime.sec, bacdest->ToTime.hundredths);
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
len = snprintf(buf, buf_size, "Recipient=");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
if (bacdest->Recipient.tag == BACNET_RECIPIENT_TAG_DEVICE) {
LEN_BRANCH(snprintf(buf, buf_size, "Device(type=%d,instance=%lu)",
bacdest->Recipient.type.device.type,
(unsigned long)bacdest->Recipient.type.device.instance));
len = snprintf(
buf, buf_size, "Device(type=%d,instance=%lu)",
bacdest->Recipient.type.device.type,
(unsigned long)bacdest->Recipient.type.device.instance);
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
} else {
/*
BACnetAddress ::= SEQUENCE {
network-number Unsigned16, -- A value of 0 indicates the local network
mac-address OCTET STRING -- A string of length 0 indicates a broadcast
network-number Unsigned16, -- A value of 0 indicates the local
network mac-address OCTET STRING -- A string of length 0 indicates
a broadcast
}
*/
LEN_BRANCH(snprintf(buf, buf_size, "Address(net=%d,mac=", bacdest->Recipient.type.address.net));
len = snprintf(
buf, buf_size,
"Address(net=%d,mac=", bacdest->Recipient.type.address.net);
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
/* TODO determine if it's IPv4+port or Ethernet mac address and print it nicer - how? Both are 6 bytes long. */
/* TODO determine if it's IPv4+port or Ethernet mac address and print it
* nicer - how? Both are 6 bytes long. */
for (i = 0; i < bacdest->Recipient.type.address.mac_len; i++) {
if (i > 0) {
LEN_BRANCH(snprintf(buf, buf_size, ":"));
len = snprintf(buf, buf_size, ":");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
}
LEN_BRANCH(snprintf(buf, buf_size, "%02x", bacdest->Recipient.type.address.mac[i]));
len = snprintf(
buf, buf_size, "%02x", bacdest->Recipient.type.address.mac[i]);
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
}
LEN_BRANCH(snprintf(buf, buf_size, ")"));
len = snprintf(buf, buf_size, ")");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
}
LEN_BRANCH(snprintf(buf, buf_size, ";"));
len = snprintf(buf, buf_size, ";");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
LEN_BRANCH(snprintf(buf, buf_size, "ProcessIdentifier=%lu;",
(unsigned long)bacdest->ProcessIdentifier));
len = snprintf(
buf, buf_size, "ProcessIdentifier=%lu;",
(unsigned long)bacdest->ProcessIdentifier);
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
LEN_BRANCH(snprintf(buf, buf_size, "ConfirmedNotify=%s;",
bacdest->ConfirmedNotify ? "true" : "false"
));
len = snprintf(
buf, buf_size, "ConfirmedNotify=%s;",
bacdest->ConfirmedNotify ? "true" : "false");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
/*
BACnetEventTransitionBits ::= BIT STRING {
@@ -593,36 +600,49 @@ int bacnet_destination_to_ascii(const BACNET_DESTINATION *bacdest, char *buf, si
to-normal (2)
}
*/
LEN_BRANCH(snprintf(buf, buf_size, "Transitions=["));
len = snprintf(buf, buf_size, "Transitions=[");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
comma = false;
/* TODO remove casting when bitstring_bit() has const added - Github issue #320 */
if (bitstring_bit((BACNET_BIT_STRING *) &bacdest->Transitions, TRANSITION_TO_OFFNORMAL)) {
LEN_BRANCH(snprintf(buf, buf_size, "to-offnormal"));
/* TODO remove casting when bitstring_bit() has const added - Github issue
* #320 */
if (bitstring_bit(
(BACNET_BIT_STRING *)&bacdest->Transitions,
TRANSITION_TO_OFFNORMAL)) {
len = snprintf(buf, buf_size, "to-offnormal");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
comma = true;
}
if (bitstring_bit((BACNET_BIT_STRING *) &bacdest->Transitions, TRANSITION_TO_FAULT)) {
if (bitstring_bit(
(BACNET_BIT_STRING *)&bacdest->Transitions, TRANSITION_TO_FAULT)) {
if (comma) {
LEN_BRANCH(snprintf(buf, buf_size, ","));
len = snprintf(buf, buf_size, ",");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
}
LEN_BRANCH(snprintf(buf, buf_size, "to-fault"));
len = snprintf(buf, buf_size, "to-fault");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
comma = true;
}
if (bitstring_bit((BACNET_BIT_STRING *) &bacdest->Transitions, TRANSITION_TO_NORMAL)) {
if (bitstring_bit(
(BACNET_BIT_STRING *)&bacdest->Transitions, TRANSITION_TO_NORMAL)) {
if (comma) {
LEN_BRANCH(snprintf(buf, buf_size, ","));
len = snprintf(buf, buf_size, ",");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
}
LEN_BRANCH(snprintf(buf, buf_size, "to-normal"));
len = snprintf(buf, buf_size, "to-normal");
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
}
LEN_BRANCH(snprintf(buf, buf_size, "])")); /* end of the outer paren */
len = snprintf(buf, buf_size, "])"); /* end of the outer paren */
buf_len += bacapp_snprintf_shift(len, &buf, &buf_size);
return output_len;
return buf_len;
}
/**
* Parse BACnet_Destination from ASCII string (as entered by user)
*
* @param bacdest - Destination struct to pupulate with data from the ASCII string
* @param bacdest - Destination struct to pupulate with data from the ASCII
* string
* @param buf - ASCII string, zero terminated
* @return true on success
*/
@@ -658,14 +678,9 @@ bool bacnet_destination_from_ascii(BACNET_DESTINATION *bacdest, const char *buf)
enum ParseKeyword kw = 0;
BACNET_TIME *ptime;
BACNET_MAC_ADDRESS tmpmac;
static const char * KW_LOOKUP[] = {
"ValidDays",
"FromTime",
"ToTime",
"Recipient",
"ProcessIdentifier",
"ConfirmedNotify",
"Transitions",
static const char *KW_LOOKUP[] = {
"ValidDays", "FromTime", "ToTime", "Recipient",
"ProcessIdentifier", "ConfirmedNotify", "Transitions",
};
if (bacdest == NULL || buf == NULL) {
@@ -674,7 +689,6 @@ bool bacnet_destination_from_ascii(BACNET_DESTINATION *bacdest, const char *buf)
bacnet_destination_default_init(bacdest);
/* Helper macros to simplify the parser ... */
/* true if the character is whitespace */
@@ -682,48 +696,49 @@ bool bacnet_destination_from_ascii(BACNET_DESTINATION *bacdest, const char *buf)
/* Discard characters while they match a given test. Goes to parse_end on NUL.
* ctest is a boolean expression where c is the tested character */
#define DISCARD_WHILE(ctest) \
do { \
while(1) { \
c = buf[pos]; \
if (c == 0) { \
goto parse_end; \
} \
if ((ctest)) { \
pos++; \
continue; \
} \
break; \
} \
} while(0)
#define DISCARD_WHILE(ctest) \
do { \
while (1) { \
c = buf[pos]; \
if (c == 0) { \
goto parse_end; \
} \
if ((ctest)) { \
pos++; \
continue; \
} \
break; \
} \
} while (0)
/* Discard all whitespace. Goes to parse_end on NUL. */
#define DISCARD_WHITESPACE() DISCARD_WHILE(ISWHITE(c))
/* Must consume a given word; return false otherwise. */
#define MUST_CONSUME(s) \
do { \
_must_consume_tmplen = strlen(s); \
if (0 == strncmp(&buf[pos], s, _must_consume_tmplen)) { \
pos += _must_consume_tmplen; \
} else { \
return false; \
} \
} while(0)
#define MUST_CONSUME(s) \
do { \
_must_consume_tmplen = strlen(s); \
if (0 == strncmp(&buf[pos], s, _must_consume_tmplen)) { \
pos += _must_consume_tmplen; \
} else { \
return false; \
} \
} while (0)
/* Collect a decimal number and store the result into tmp; stop on a non-digit. Clobbers "c" and "tmp". TODO replace with strtol? */
#define COLLECT_NUMBER_TMP(maxdigits) \
do { \
tmp = 0; \
for (_number_i = 0; _number_i < (maxdigits); _number_i++) { \
c = buf[pos]; \
if (c >= '0' && c <= '9') { \
tmp = (tmp * 10) + (c - '0'); \
pos++; \
} else { \
break; \
} \
} \
/* Collect a decimal number and store the result into tmp; stop on a non-digit.
* Clobbers "c" and "tmp". TODO replace with strtol? */
#define COLLECT_NUMBER_TMP(maxdigits) \
do { \
tmp = 0; \
for (_number_i = 0; _number_i < (maxdigits); _number_i++) { \
c = buf[pos]; \
if (c >= '0' && c <= '9') { \
tmp = (tmp * 10) + (c - '0'); \
pos++; \
} else { \
break; \
} \
} \
} while (0)
/* Go through all key=value pieces in the string */
@@ -763,7 +778,9 @@ bool bacnet_destination_from_ascii(BACNET_DESTINATION *bacdest, const char *buf)
}
break;
case PH_VALUE_SPACER: /* Equals between key and value, also consuming opening square bracket if present. */
case PH_VALUE_SPACER: /* Equals between key and value, also
consuming opening square bracket if
present. */
DISCARD_WHITESPACE();
MUST_CONSUME("=");
DISCARD_WHILE(c == '[' || ISWHITE(c));
@@ -792,7 +809,8 @@ bool bacnet_destination_from_ascii(BACNET_DESTINATION *bacdest, const char *buf)
}
if (j == 0) {
if (c >= '1' && c <= '7') {
bitstring_set_bit(&bacdest->ValidDays, c - '1', true);
bitstring_set_bit(
&bacdest->ValidDays, c - '1', true);
pos++;
j = 1;
} else {
@@ -815,7 +833,8 @@ bool bacnet_destination_from_ascii(BACNET_DESTINATION *bacdest, const char *buf)
ptime = &bacdest->ToTime;
}
/* TODO implemented in bacapp_parse_application_data - extract & reuse? */
/* TODO implemented in bacapp_parse_application_data -
* extract & reuse? */
/* Hour */
COLLECT_NUMBER_TMP(2);
@@ -887,17 +906,20 @@ bool bacnet_destination_from_ascii(BACNET_DESTINATION *bacdest, const char *buf)
if (j == 0) {
if (0 ==
strncmp(&buf[pos], "to-offnormal", 12)) {
bitstring_set_bit(&bacdest->Transitions,
bitstring_set_bit(
&bacdest->Transitions,
TRANSITION_TO_OFFNORMAL, true);
pos += 12;
} else if (0 ==
strncmp(&buf[pos], "to-fault", 8)) {
bitstring_set_bit(&bacdest->Transitions,
} else if (
0 == strncmp(&buf[pos], "to-fault", 8)) {
bitstring_set_bit(
&bacdest->Transitions,
TRANSITION_TO_FAULT, true);
pos += 8;
} else if (0 ==
strncmp(&buf[pos], "to-normal", 9)) {
bitstring_set_bit(&bacdest->Transitions,
} else if (
0 == strncmp(&buf[pos], "to-normal", 9)) {
bitstring_set_bit(
&bacdest->Transitions,
TRANSITION_TO_NORMAL, true);
pos += 9;
} else {
@@ -914,7 +936,8 @@ bool bacnet_destination_from_ascii(BACNET_DESTINATION *bacdest, const char *buf)
case KW_Recipient:
if (0 == strncmp(&buf[pos], "Device", 6)) {
pos += 6;
bacdest->Recipient.tag = BACNET_RECIPIENT_TAG_DEVICE;
bacdest->Recipient.tag =
BACNET_RECIPIENT_TAG_DEVICE;
DISCARD_WHITESPACE();
MUST_CONSUME("(");
@@ -943,7 +966,8 @@ bool bacnet_destination_from_ascii(BACNET_DESTINATION *bacdest, const char *buf)
} else if (0 == strncmp(&buf[pos], "Address", 7)) {
pos += 7;
bacdest->Recipient.tag = BACNET_RECIPIENT_TAG_ADDRESS;
bacdest->Recipient.tag =
BACNET_RECIPIENT_TAG_ADDRESS;
DISCARD_WHITESPACE();
MUST_CONSUME("(");
@@ -964,13 +988,18 @@ bool bacnet_destination_from_ascii(BACNET_DESTINATION *bacdest, const char *buf)
MUST_CONSUME("=");
DISCARD_WHITESPACE();
if (!bacnet_address_mac_from_ascii(&tmpmac, &buf[pos])) {
if (!bacnet_address_mac_from_ascii(
&tmpmac, &buf[pos])) {
return false;
}
bacdest->Recipient.type.address.mac_len = tmpmac.len;
memcpy(&bacdest->Recipient.type.address.mac, &tmpmac.adr, MAX_MAC_LEN);
bacdest->Recipient.type.address.mac_len =
tmpmac.len;
memcpy(
&bacdest->Recipient.type.address.mac,
&tmpmac.adr, MAX_MAC_LEN);
/* address_mac_from_ascii doesn't return number of digits
/* address_mac_from_ascii doesn't return number of
* digits
* - we have to discard until ) */
DISCARD_WHILE(c != ')');
+33 -28
View File
@@ -35,7 +35,10 @@
#include <stdint.h> /* for standard integer types uint8_t etc. */
#include <stdbool.h> /* for the standard bool type. */
#include <stdio.h>
#include "bacnet/bacenum.h"
/* BACnet Stack defines - first */
#include "bacnet/bacdef.h"
/* BACnet Stack API */
#include "bacnet/bacapp.h"
#include "bacnet/bacdcode.h"
#include "bacnet/bacint.h"
#include "bacnet/datalink/bvlc6.h"
@@ -641,6 +644,32 @@ bool bvlc6_address_get(BACNET_IP6_ADDRESS *addr,
return status;
}
/**
* @brief Shift the buffer pointer and decrease the size after an snprintf
* @param len - number of bytes (excluding terminating NULL byte) from snprintf
* @param buf - pointer to the buffer pointer
* @param buf_size - pointer to the buffer size
* @return number of bytes (excluding terminating NULL byte) from snprintf
*/
static int snprintf_shift(int len, char **buf, size_t *buf_size)
{
if (buf) {
if (*buf) {
*buf += len;
}
}
if (buf_size) {
if ((*buf_size) >= len) {
*buf_size -= len;
} else {
*buf_size = 0;
}
}
return len;
}
/** Convert IPv6 Address from ASCII
*
* IPv6 addresses are represented as eight groups, separated by colons,
@@ -689,41 +718,17 @@ int bvlc6_address_to_ascii(BACNET_IP6_ADDRESS *addr, char *buf, size_t buf_size)
if ((a == 0) && (f >= 0)) {
if (f++ == 0) {
len = snprintf(buf, buf_size, "::");
if (buf) {
buf += len;
}
if (len > buf_size) {
buf_size = 0;
} else {
buf_size -= len;
}
n += len;
n += snprintf_shift(len, &buf, &buf_size);
}
} else {
if (f > 0) {
f = -1;
} else if (i > 0) {
len = snprintf(buf, buf_size, ":");
if (buf) {
buf += len;
}
if (len > buf_size) {
buf_size = 0;
} else {
buf_size -= len;
}
n += len;
n += snprintf_shift(len, &buf, &buf_size);
}
len = snprintf(buf, buf_size, "%x", a);
if (buf) {
buf += len;
}
if (len > buf_size) {
buf_size = 0;
} else {
buf_size -= len;
}
n += len;
n += snprintf_shift(len, &buf, &buf_size);
}
}