/**
- * Get the number of digits in a number.
- *
+ * Helper func for ldns_duration2string below. If t > 0,
+ * scan print t and c on buf, forwarding buf. Return 0 on success.
*/
-static size_t
-digits_in_number(time_t duration)
+static inline int dur_scan_print(char **buf, char *eob, char c, time_t t)
{
- unsigned int i = (unsigned int) duration;
- size_t n = 1;
-
- while (i >= 100000000) {
- n += 8;
- i /= 100000000;
+ if (t > 0) {
+ int r = snprintf(*buf, eob - *buf, "%u%c", (unsigned)t, c);
+ if (r < 0 || (*buf += r) >= eob)
+ return -1;
}
- if (i >= 10000) { n += 4; i /= 10000; }
- if (i >= 100 ) { n += 2; i /= 100; }
- if (i >= 10 ) { n += 1; }
- return n;
+ return 0;
}
-
/**
* Convert a duration to a string.
*
*/
char*
-ldns_duration2string(const ldns_duration_type* duration)
+ldns_duration2string(const ldns_duration_type* d)
{
- char* str = NULL;
- size_t count = 2;
- int T = 0;
- char num[sizeof(unsigned int) + 2];
-
- if (!duration) {
- return NULL;
- }
-
- if (duration->years > 0) {
- count = count + 1 + digits_in_number(duration->years);
- }
- if (duration->months > 0) {
- count = count + 1 + digits_in_number(duration->months);
- }
- if (duration->weeks > 0) {
- count = count + 1 + digits_in_number(duration->weeks);
- }
- if (duration->days > 0) {
- count = count + 1 + digits_in_number(duration->days);
- }
- if (duration->hours > 0) {
- count = count + 1 + digits_in_number(duration->hours);
- T = 1;
- }
- if (duration->minutes > 0) {
- count = count + 1 + digits_in_number(duration->minutes);
- T = 1;
- }
- if (duration->seconds > 0) {
- count = count + 1 + digits_in_number(duration->seconds);
- T = 1;
- }
- if (T) {
- count++;
- }
-
- if (!(str = (char*) calloc(count, sizeof(char))))
- return NULL;
- str[0] = 'P';
- str[1] = '\0';
-
- if (duration->years > 0) {
- count = digits_in_number(duration->years);
- assert(count <= sizeof(num) - 2);
- snprintf(num, count+2, "%uY", (unsigned int) duration->years);
- str = strncat(str, num, count+2);
- }
- if (duration->months > 0) {
- count = digits_in_number(duration->months);
- assert(count <= sizeof(num) - 2);
- snprintf(num, count+2, "%uM", (unsigned int) duration->months);
- str = strncat(str, num, count+2);
- }
- if (duration->weeks > 0) {
- count = digits_in_number(duration->weeks);
- assert(count <= sizeof(num) - 2);
- snprintf(num, count+2, "%uW", (unsigned int) duration->weeks);
- str = strncat(str, num, count+2);
- }
- if (duration->days > 0) {
- count = digits_in_number(duration->days);
- assert(count <= sizeof(num) - 2);
- snprintf(num, count+2, "%uD", (unsigned int) duration->days);
- str = strncat(str, num, count+2);
- }
- if (T) {
- str = strcat(str, "T");
- }
- if (duration->hours > 0) {
- count = digits_in_number(duration->hours);
- assert(count <= sizeof(num) - 2);
- snprintf(num, count+2, "%uH", (unsigned int) duration->hours);
- str = strncat(str, num, count+2);
- }
- if (duration->minutes > 0) {
- count = digits_in_number(duration->minutes);
- assert(count <= sizeof(num) - 2);
- snprintf(num, count+2, "%uM", (unsigned int) duration->minutes);
- str = strncat(str, num, count+2);
- }
- if (duration->seconds > 0) {
- count = digits_in_number(duration->seconds);
- assert(count <= sizeof(num) - 2);
- snprintf(num, count+2, "%uS", (unsigned int) duration->seconds);
- str = strncat(str, num, count+2);
- }
- return str;
+ /* Max string size should be 7 * 40 + 3 on a 127 bits machine
+ * So 300 (< 273) is more than enough.
+ */
+ char buf[300] = "P0D", *eob = buf + sizeof(buf), *p = buf + 1;
+
+ if (!d)
+ return NULL;
+
+ if (dur_scan_print(&p, eob, 'Y', d->years)
+ || dur_scan_print(&p, eob, 'M', d->months)
+ || dur_scan_print(&p, eob, 'W', d->weeks)
+ || dur_scan_print(&p, eob, 'D', d->days))
+ return NULL;
+
+ if (d->hours || d->minutes || d->seconds) {
+ if (p > (eob - 2))
+ return NULL; /* Error; no space left on buf for 'T' */
+
+ *p++ = 'T'; *p = 0;
+ if (dur_scan_print(&p, eob, 'H', d->hours)
+ || dur_scan_print(&p, eob, 'M', d->minutes)
+ || dur_scan_print(&p, eob, 'S', d->seconds))
+ return NULL;
+ }
+ return strdup(buf);
}
#include <ldns/ldns.h>
+int test_duration(void)
+{
+ ldns_duration_type *d1 = NULL, *d2 = NULL;
+ char *s1 = NULL, *s2 = NULL, *s3 = NULL;
+ int r = -1;
+
+ if (!(d1 = ldns_duration_create()))
+ fprintf(stderr, "ldns_duration_create() returned NULL\n");
+
+ else if (!(s1 = ldns_duration2string(d1)))
+ fprintf(stderr, "ldns_duration2string() returned NULL\n");
+
+ else if (!(d2 = ldns_duration_create_from_string("PT0S")))
+ fprintf( stderr
+ , "ldns_duration_create_from_string(\"P0D\") returned NULL\n");
+
+ else if (ldns_duration_compare(d1, d2))
+ fprintf(stderr, "0 durations not equal\n");
+
+ else if ((d1->years = 1), (d1->months = 3), 0)
+ ; /* pass */
+
+ else if (!(s2 = ldns_duration2string(d1)))
+ fprintf(stderr, "ldns_duration2string() returned NULL\n");
+
+ else if (strcmp(s2, "P1Y3M"))
+ fprintf(stderr, "\"%s\" should have been \"P1Y3M\"\n", s2);
+
+ else if ((d1->minutes = 3), 0)
+ ; /* pass */
+
+ else if (!(s3 = ldns_duration2string(d1)))
+ fprintf(stderr, "ldns_duration2string() returned NULL\n");
+
+ else if (strcmp(s3, "P1Y3MT3M"))
+ fprintf(stderr, "\"%s\" should have been \"P1Y3MT3M\"\n", s3);
+
+ else if (ldns_duration_compare(d1, d2) <= 0)
+ fprintf(stderr, "ldns_duration_compare() error\n");
+ else
+ r = 0;
+
+ if (d1) ldns_duration_cleanup(d1);
+ if (d2) ldns_duration_cleanup(d2);
+ if (s1) free(s1);
+ if (s2) free(s2);
+ if (s3) free(s3);
+ return r;
+}
+
+
void print_data_ar(const uint8_t *data, const size_t len) {
size_t i;
}
free(data);
+ if (test_duration())
+ result = EXIT_FAILURE;
+
printf("unit test is %s\n", result==EXIT_SUCCESS?"ok":"fail");
exit(result);
}