From 0cbf7414a401e892bd0dd537e2d01b74cff561ab Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Thu, 30 May 2024 09:16:05 -0500 Subject: [PATCH] Refactor/snprintf next common shift function (#656) --- src/bacnet/bacapp.c | 321 ++++++--------------------------- src/bacnet/bacapp.h | 6 + src/bacnet/bacdest.c | 319 +++++++++++++++++--------------- src/bacnet/datalink/bvlc6.c | 61 ++++--- test/bacnet/bacdest/src/main.c | 16 +- 5 files changed, 277 insertions(+), 446 deletions(-) diff --git a/src/bacnet/bacapp.c b/src/bacnet/bacapp.c index 081f8110..7493a37e 100644 --- a/src/bacnet/bacapp.c +++ b/src/bacnet/bacapp.c @@ -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; diff --git a/src/bacnet/bacapp.h b/src/bacnet/bacapp.h index b5d77fb7..136aad45 100644 --- a/src/bacnet/bacapp.h +++ b/src/bacnet/bacapp.h @@ -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, diff --git a/src/bacnet/bacdest.c b/src/bacnet/bacdest.c index 7b771a92..1c7f9138 100644 --- a/src/bacnet/bacdest.c +++ b/src/bacnet/bacdest.c @@ -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 != ')'); diff --git a/src/bacnet/datalink/bvlc6.c b/src/bacnet/datalink/bvlc6.c index 5a22f4d7..46ebd388 100644 --- a/src/bacnet/datalink/bvlc6.c +++ b/src/bacnet/datalink/bvlc6.c @@ -35,7 +35,10 @@ #include /* for standard integer types uint8_t etc. */ #include /* for the standard bool type. */ #include -#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); } } diff --git a/test/bacnet/bacdest/src/main.c b/test/bacnet/bacdest/src/main.c index 42b80a81..22a8f64a 100644 --- a/test/bacnet/bacdest/src/main.c +++ b/test/bacnet/bacdest/src/main.c @@ -117,7 +117,7 @@ static void test_BACnetDestination_ASCII(void) #endif { BACNET_DESTINATION destination = { 0 }, test_destination = { 0 }; - int len = 0, test_len = 0; + int len = 0, test_len = 0, null_len = 0; const char *ascii = "(" "ValidDays=[1,2,3,4,5,6,7];" "FromTime=0:00:00.0;ToTime=23:59:59.99;" @@ -135,13 +135,17 @@ static void test_BACnetDestination_ASCII(void) status = bacnet_destination_same(&destination, &test_destination); zassert_true(status, NULL); /* get the length */ - len = bacnet_destination_to_ascii(&test_destination, NULL, 0); - if (len > 0) { - test_ascii = calloc(len, 1); + null_len = bacnet_destination_to_ascii(&test_destination, NULL, 0); + if (null_len > 0) { + test_ascii = calloc(null_len, 1); if (test_ascii) { test_len = - bacnet_destination_to_ascii(&test_destination, test_ascii, len); - zassert_equal(len, test_len, NULL); + bacnet_destination_to_ascii(&test_destination, test_ascii, null_len); + zassert_equal(null_len, test_len, NULL); + while (--test_len) { + len = bacnet_destination_to_ascii(&test_destination, test_ascii, test_len); + zassert_equal(len, null_len, NULL); + } free(test_ascii); } }