Add timestamp snprintf. Fix bacapp snprintf to account for string size zero behavior of snprintf.

This commit is contained in:
Steve Karg
2024-04-23 10:04:46 -05:00
parent 8729c00dbd
commit e73520a974
7 changed files with 299 additions and 142 deletions
+164 -139
View File
@@ -1865,15 +1865,20 @@ int bacapp_data_len(
}
#if defined(BACAPP_DATE)
/* 135.1-4.4 Notational Rules for Parameter Values
(j)
dates are represented enclosed in parenthesis:
(Monday, 24-January-1998).
Any "wild card" or unspecified field is shown by an asterisk (X'2A'):
(Monday, *-January-1998).
The omission of day of week implies that the day is unspecified:
(24-January-1998);
*/
/**
* @brief Print a date value to a string for EPICS
* @param str - destination string, or NULL for length only
* @param str_len - length of the destination string, or 0 for length only
* @param bdate - date value to print
* @return number of characters written
* @note 135.1-4.4 Notational Rules for Parameter Values
* (j) dates are represented enclosed in parenthesis:
* (Monday, 24-January-1998).
* Any "wild card" or unspecified field is shown by an asterisk (X'2A'):
* (Monday, *-January-1998).
* The omission of day of week implies that the day is unspecified:
* (24-January-1998);
*/
static int bacapp_snprintf_date(char *str, size_t str_len, BACNET_DATE *bdate)
{
int ret_val = 0;
@@ -1888,11 +1893,11 @@ static int bacapp_snprintf_date(char *str, size_t str_len, BACNET_DATE *bdate)
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;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
if (bdate->day == 255) {
@@ -1902,11 +1907,11 @@ static int bacapp_snprintf_date(char *str, size_t str_len, BACNET_DATE *bdate)
}
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
if (bdate->year == 2155) {
@@ -1921,11 +1926,17 @@ static int bacapp_snprintf_date(char *str, size_t str_len, BACNET_DATE *bdate)
#endif
#if defined(BACAPP_TIME)
/* 135.1-4.4 Notational Rules for Parameter Values
(k)
times are represented as hours, minutes, seconds, hundredths in the format
hh:mm:ss.xx: 2:05:44.00, 16:54:59.99. Any "wild card" field is shown by an
asterisk (X'2A'): 16:54:*.*; */
/**
* @brief Print a time value to a string for EPICS
* @param str - destination string, or NULL for length only
* @param str_len - length of the destination string, or 0 for length only
* @param btime - date value to print
* @return number of characters written
* @note 135.1-4.4 Notational Rules for Parameter Values
* (k) times are represented as hours, minutes, seconds, hundredths
* in the format hh:mm:ss.xx: 2:05:44.00, 16:54:59.99.
* Any "wild card" field is shown by an asterisk (X'2A'): 16:54:*.*;
*/
static int bacapp_snprintf_time(char *str, size_t str_len, BACNET_TIME *btime)
{
int ret_val = 0;
@@ -1940,11 +1951,11 @@ static int bacapp_snprintf_time(char *str, size_t str_len, BACNET_TIME *btime)
}
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
if (btime->min == 255) {
@@ -1954,11 +1965,11 @@ static int bacapp_snprintf_time(char *str, size_t str_len, BACNET_TIME *btime)
}
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
if (btime->sec == 255) {
@@ -1968,11 +1979,11 @@ static int bacapp_snprintf_time(char *str, size_t str_len, BACNET_TIME *btime)
}
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
if (btime->hundredths == 255) {
@@ -1987,6 +1998,14 @@ static int bacapp_snprintf_time(char *str, size_t str_len, BACNET_TIME *btime)
#endif
#if defined(BACAPP_WEEKLY_SCHEDULE)
/**
* @brief Print a weekly schedule value to a string for EPICS
* @param str - destination string, or NULL for length only
* @param str_len - length of the destination string, or 0 for length only
* @param ws - weekly schedule value to print
* @param arrayIndex - index of the weekly schedule to print
* @return number of characters written
*/
static int bacapp_snprintf_weeklyschedule(char *str,
size_t str_len,
BACNET_WEEKLY_SCHEDULE *ws,
@@ -2027,11 +2046,11 @@ static int bacapp_snprintf_weeklyschedule(char *str,
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
for (wi = 0; wi < loopend; wi++) {
@@ -2047,11 +2066,11 @@ static int bacapp_snprintf_weeklyschedule(char *str,
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
for (ti = 0; ti < ds->TV_Count; ti++) {
@@ -2071,13 +2090,12 @@ static int bacapp_snprintf_weeklyschedule(char *str,
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
bacnet_primitive_to_application_data_value(
&dummyDataValue, &ds->Time_Values[ti].Value);
dummyPropValue.value = &dummyDataValue;
@@ -2088,11 +2106,11 @@ static int bacapp_snprintf_weeklyschedule(char *str,
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
if (ti < ds->TV_Count - 1) {
@@ -2100,11 +2118,11 @@ static int bacapp_snprintf_weeklyschedule(char *str,
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
}
@@ -2114,11 +2132,11 @@ static int bacapp_snprintf_weeklyschedule(char *str,
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
}
@@ -2131,7 +2149,7 @@ static int bacapp_snprintf_weeklyschedule(char *str,
/**
* @brief Extract the value into a text string
* @param str - the buffer to store the extracted value, or NULL for length
* @param str_len - the size of the buffer
* @param str_len - the size of the buffer, or 0 for length only
* @param object_value - ptr to BACnet object value from which to extract str
* @return number of bytes (excluding terminating NULL byte) that were stored
* to the output string.
@@ -2204,11 +2222,11 @@ int bacapp_snprintf_value(
octet_str++;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
}
@@ -2222,11 +2240,11 @@ int bacapp_snprintf_value(
slen = snprintf(str, str_len, "\"");
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
#if (__STDC_VERSION__ >= 199901L) && defined(__STDC_ISO_10646__)
@@ -2250,11 +2268,11 @@ int bacapp_snprintf_value(
slen = snprintf(str, str_len, "%lc", (wint_t)wc);
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
if (len > wclen) {
@@ -2275,11 +2293,11 @@ int bacapp_snprintf_value(
}
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
char_str++;
@@ -2295,11 +2313,11 @@ int bacapp_snprintf_value(
slen = snprintf(str, str_len, "{");
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
for (i = 0; i < len; i++) {
@@ -2308,22 +2326,22 @@ int bacapp_snprintf_value(
slen = snprintf(str, str_len, "%s", bit ? "true" : "false");
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
if (i < (len - 1)) {
slen = snprintf(str, str_len, ",");
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
}
@@ -2448,11 +2466,11 @@ int bacapp_snprintf_value(
slen = snprintf(str, str_len, "(");
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
if (value->type.Object_Id.type <= BACNET_OBJECT_TYPE_LAST) {
@@ -2468,11 +2486,11 @@ int bacapp_snprintf_value(
}
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
ret_val += slen;
slen = snprintf(str, str_len, "%lu)",
@@ -2487,16 +2505,22 @@ int bacapp_snprintf_value(
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
slen = snprintf(str, str_len, "..");
ret_val += slen;
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
slen = bacapp_snprintf_date(
str, str_len, &value->type.Date_Range.enddate);
ret_val += slen;
@@ -2504,17 +2528,8 @@ int bacapp_snprintf_value(
#endif
#if defined(BACAPP_TIMESTAMP)
case BACNET_APPLICATION_TAG_TIMESTAMP:
/*ISO 8601 format */
slen = snprintf(str, str_len,
"%04u-%02u-%02uT%02u:%02u:%02u.%03u",
(unsigned)value->type.Time_Stamp.value.dateTime.date.year,
(unsigned)value->type.Time_Stamp.value.dateTime.date.month,
(unsigned)value->type.Time_Stamp.value.dateTime.date.day,
(unsigned)value->type.Time_Stamp.value.dateTime.time.hour,
(unsigned)value->type.Time_Stamp.value.dateTime.time.min,
(unsigned)value->type.Time_Stamp.value.dateTime.time.sec,
(unsigned)
value->type.Time_Stamp.value.dateTime.time.hundredths);
slen = bacapp_timestamp_to_ascii(str, str_len,
&value->type.Time_Stamp);
ret_val += slen;
break;
#endif
@@ -2525,11 +2540,21 @@ int bacapp_snprintf_value(
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
slen = snprintf(str, str_len, "-");
ret_val += slen;
if (str) {
str += slen;
}
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
slen = bacapp_snprintf_time(
str, str_len, &value->type.Date_Time.time);
+50 -1
View File
@@ -1344,6 +1344,30 @@ bool datetime_date_init_ascii(BACNET_DATE *bdate, const char *ascii)
return status;
}
/**
* @brief Print the date as an ascii string 2021/12/31
* @param bdate - pointer to a BACnetDate
* @param str - pointer to the string, or NULL for length only
* @param str_size - size of the string, or 0 for length only
* @return number of characters printed
*/
int datetime_date_to_ascii(BACNET_DATE *bdate, char *str, size_t str_size)
{
int str_len = 0;
if (!bdate) {
return 0;
}
/* 2021/12/31 */
str_len = snprintf(str, str_size,
"%04u/%02u/%02u",
(unsigned)bdate->year,
(unsigned)bdate->month,
(unsigned)bdate->day);
return str_len;
}
/**
* @brief Parse an ascii string for the time formatted 23:59:59.99
* @param btime - #BACNET_TIME structure
@@ -1381,6 +1405,31 @@ bool datetime_time_init_ascii(BACNET_TIME *btime, const char *ascii)
return status;
}
/**
* @brief Print the time as an ascii string 23:59:59.99
* @param btime - pointer to a BACnetTime
* @param str - pointer to the string, or NULL for length only
* @param str_size - size of the string, or 0 for length only
* @return number of characters printed
*/
int datetime_time_to_ascii(BACNET_TIME *btime, char *str, size_t str_size)
{
int str_len = 0;
if (!btime) {
return 0;
}
/* 23:59:59.99 */
str_len = snprintf(str, str_size,
"%02u:%02u:%02u.%02u",
(unsigned)btime->hour,
(unsigned)btime->min,
(unsigned)btime->sec,
(unsigned)btime->hundredths);
return str_len;
}
/**
* @brief Parse an ascii string for the date+time 2021/12/31 23:59:59.99
* @param bdate - #BACNET_DATE_TIME structure
@@ -1394,7 +1443,7 @@ bool datetime_init_ascii(BACNET_DATE_TIME *bdatetime, const char *ascii)
int hour = 0, min = 0, sec = 0, hundredths = 0;
int count = 0;
count = sscanf(ascii, "%4d/%3d/%3d %3d:%3d:%3d.%3d", &year, &month, &day,
count = sscanf(ascii, "%4d/%3d/%3d-%3d:%3d:%3d.%3d", &year, &month, &day,
&hour, &min, &sec, &hundredths);
if (count >= 3) {
datetime_set_date(
+4
View File
@@ -250,8 +250,12 @@ bool datetime_utc_to_local(BACNET_DATE_TIME *local_time,
BACNET_STACK_EXPORT
bool datetime_date_init_ascii(BACNET_DATE *bdate, const char *ascii);
BACNET_STACK_EXPORT
int datetime_date_to_ascii(BACNET_DATE *bdate, char *str, size_t str_size);
BACNET_STACK_EXPORT
bool datetime_time_init_ascii(BACNET_TIME *btime, const char *ascii);
BACNET_STACK_EXPORT
int datetime_time_to_ascii(BACNET_TIME *btime, char *str, size_t str_size);
BACNET_STACK_EXPORT
bool datetime_init_ascii(BACNET_DATE_TIME *bdatetime, const char *ascii);
BACNET_STACK_EXPORT
+52 -2
View File
@@ -31,9 +31,11 @@
License.
-------------------------------------------
####COPYRIGHTEND####*/
#include <stdbool.h>
#include <stdint.h>
#include <assert.h>
#include <stdio.h>
#include "bacnet/bacapp.h"
#include "bacnet/datetime.h"
#include "bacnet/timestamp.h"
/** @file timestamp.c Encode/Decode BACnet Timestamps */
@@ -182,7 +184,6 @@ int bacapp_encode_timestamp(uint8_t *apdu, BACNET_TIMESTAMP *value)
default:
len = 0;
assert(len);
break;
}
}
@@ -457,3 +458,52 @@ bool bacapp_timestamp_init_ascii(BACNET_TIMESTAMP *timestamp, const char *ascii)
return status;
}
/**
* @brief Print the timestamp to a string
* @param str - pointer to the string, or NULL for length only
* @param str_size - size of the string, or 0 for length only
* @param ts - pointer to the timestamp
* @return number of characters printed
*/
int bacapp_timestamp_to_ascii(char *str, size_t str_size,
BACNET_TIMESTAMP *timestamp)
{
int str_len = 0;
if (!timestamp) {
return 0;
}
switch (timestamp->tag) {
case TIME_STAMP_TIME:
/* 23:59:59.99 */
str_len = snprintf(str, str_size,
"%02u:%02u:%02u.%02u",
(unsigned)timestamp->value.time.hour,
(unsigned)timestamp->value.time.min,
(unsigned)timestamp->value.time.sec,
(unsigned)timestamp->value.time.hundredths);
break;
case TIME_STAMP_SEQUENCE:
/* 65535 */
str_len = snprintf(str, str_size, "%u",
(unsigned)timestamp->value.sequenceNum);
break;
case TIME_STAMP_DATETIME:
/* 2021/12/31-23:59:59.99 */
str_len = snprintf(str, str_size,
"%04u/%02u/%02u-%02u:%02u:%02u.%02u",
(unsigned)timestamp->value.dateTime.date.year,
(unsigned)timestamp->value.dateTime.date.month,
(unsigned)timestamp->value.dateTime.date.day,
(unsigned)timestamp->value.dateTime.time.hour,
(unsigned)timestamp->value.dateTime.time.min,
(unsigned)timestamp->value.dateTime.time.sec,
(unsigned)timestamp->value.dateTime.time.hundredths);
break;
default:
break;
}
return str_len;
}
+5
View File
@@ -113,6 +113,11 @@ extern "C" {
bool bacapp_timestamp_init_ascii(
BACNET_TIMESTAMP *timestamp,
const char *ascii);
BACNET_STACK_EXPORT
int bacapp_timestamp_to_ascii(
char *str,
size_t str_size,
BACNET_TIMESTAMP *timestamp);
#ifdef __cplusplus
}
+16
View File
@@ -520,6 +520,8 @@ static void testDatetimeCodec(void)
int apdu_len;
int test_len;
int null_len;
int str_len;
char str[64];
int diff;
bool status;
@@ -541,6 +543,20 @@ static void testDatetimeCodec(void)
zassert_true(apdu_len > 0, NULL);
diff = datetime_compare(&datetimeOut, &datetimeIn);
zassert_equal(diff, 0, NULL);
/* test time stringify */
str_len = datetime_time_to_ascii(&datetimeIn.time, str, sizeof(str));
zassert_true(str_len > 0, NULL);
status = datetime_time_init_ascii(&datetimeIn.time, str);
zassert_true(status, NULL);
diff = datetime_compare(&datetimeOut, &datetimeIn);
zassert_equal(diff, 0, NULL);
/* test date stringify */
str_len = datetime_date_to_ascii(&datetimeIn.date, str, sizeof(str));
zassert_true(str_len > 0, NULL);
status = datetime_date_init_ascii(&datetimeIn.date, str);
zassert_true(status, NULL);
diff = datetime_compare(&datetimeOut, &datetimeIn);
zassert_equal(diff, 0, NULL);
/* test for invalid date tag */
apdu_len = bacapp_encode_datetime(apdu, &datetimeIn);
encode_tag(apdu, BACNET_APPLICATION_TAG_REAL, false, 4);
+8
View File
@@ -54,6 +54,8 @@ static void testTimestampTime(void)
BACNET_TIMESTAMP testTimestampIn;
BACNET_TIMESTAMP testTimestampOut;
uint8_t buffer[MAX_APDU];
bool status = false;
char str[64] = "";
int len;
int test_len;
@@ -78,6 +80,12 @@ static void testTimestampTime(void)
testTimestampIn.value.time.sec, testTimestampOut.value.time.sec, NULL);
zassert_equal(testTimestampIn.value.time.hundredths,
testTimestampOut.value.time.hundredths, NULL);
bacapp_timestamp_to_ascii(str, sizeof(str), &testTimestampIn);
status = bacapp_timestamp_init_ascii(&testTimestampOut, str);
zassert_true(status, NULL);
status = bacapp_timestamp_same(&testTimestampIn, &testTimestampOut);
zassert_true(status, NULL);
}
#if defined(CONFIG_ZTEST_NEW_API)