xref: /freebsd/contrib/ldns/duration.c (revision 5afab0e5)
17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav  * $Id: duration.c 4518 2011-02-24 15:39:09Z matthijs $
37b5038d7SDag-Erling Smørgrav  *
47b5038d7SDag-Erling Smørgrav  * Copyright (c) 2009 NLNet Labs. All rights reserved.
57b5038d7SDag-Erling Smørgrav  *
67b5038d7SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
77b5038d7SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
87b5038d7SDag-Erling Smørgrav  * are met:
97b5038d7SDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
107b5038d7SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
117b5038d7SDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
127b5038d7SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
137b5038d7SDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
147b5038d7SDag-Erling Smørgrav  *
157b5038d7SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
167b5038d7SDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
177b5038d7SDag-Erling Smørgrav  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
187b5038d7SDag-Erling Smørgrav  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
197b5038d7SDag-Erling Smørgrav  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
207b5038d7SDag-Erling Smørgrav  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
217b5038d7SDag-Erling Smørgrav  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
227b5038d7SDag-Erling Smørgrav  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
237b5038d7SDag-Erling Smørgrav  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
247b5038d7SDag-Erling Smørgrav  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
257b5038d7SDag-Erling Smørgrav  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
267b5038d7SDag-Erling Smørgrav  *
277b5038d7SDag-Erling Smørgrav  */
287b5038d7SDag-Erling Smørgrav 
297b5038d7SDag-Erling Smørgrav /**
307b5038d7SDag-Erling Smørgrav  *
317b5038d7SDag-Erling Smørgrav  * This file is copied from the OpenDNSSEC source repository
327b5038d7SDag-Erling Smørgrav  * and only slightly adapted to make it fit.
337b5038d7SDag-Erling Smørgrav  */
347b5038d7SDag-Erling Smørgrav 
357b5038d7SDag-Erling Smørgrav /**
367b5038d7SDag-Erling Smørgrav  *
377b5038d7SDag-Erling Smørgrav  * Durations.
387b5038d7SDag-Erling Smørgrav  */
397b5038d7SDag-Erling Smørgrav 
407b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
417b5038d7SDag-Erling Smørgrav #include <ldns/duration.h>
427b5038d7SDag-Erling Smørgrav 
437b5038d7SDag-Erling Smørgrav #include <stdio.h>
447b5038d7SDag-Erling Smørgrav #include <stdlib.h>
457b5038d7SDag-Erling Smørgrav #include <string.h>
467b5038d7SDag-Erling Smørgrav #include <time.h>
477b5038d7SDag-Erling Smørgrav 
487b5038d7SDag-Erling Smørgrav 
497b5038d7SDag-Erling Smørgrav /**
507b5038d7SDag-Erling Smørgrav  * Create a new 'instant' duration.
517b5038d7SDag-Erling Smørgrav  *
527b5038d7SDag-Erling Smørgrav  */
537b5038d7SDag-Erling Smørgrav ldns_duration_type*
ldns_duration_create(void)547b5038d7SDag-Erling Smørgrav ldns_duration_create(void)
557b5038d7SDag-Erling Smørgrav {
567b5038d7SDag-Erling Smørgrav     ldns_duration_type* duration;
577b5038d7SDag-Erling Smørgrav 
587b5038d7SDag-Erling Smørgrav     duration = malloc(sizeof(ldns_duration_type));
597b5038d7SDag-Erling Smørgrav     if (!duration) {
607b5038d7SDag-Erling Smørgrav         return NULL;
617b5038d7SDag-Erling Smørgrav     }
627b5038d7SDag-Erling Smørgrav     duration->years = 0;
637b5038d7SDag-Erling Smørgrav     duration->months = 0;
647b5038d7SDag-Erling Smørgrav     duration->weeks = 0;
657b5038d7SDag-Erling Smørgrav     duration->days = 0;
667b5038d7SDag-Erling Smørgrav     duration->hours = 0;
677b5038d7SDag-Erling Smørgrav     duration->minutes = 0;
687b5038d7SDag-Erling Smørgrav     duration->seconds = 0;
697b5038d7SDag-Erling Smørgrav     return duration;
707b5038d7SDag-Erling Smørgrav }
717b5038d7SDag-Erling Smørgrav 
727b5038d7SDag-Erling Smørgrav 
737b5038d7SDag-Erling Smørgrav /**
747b5038d7SDag-Erling Smørgrav  * Compare durations.
757b5038d7SDag-Erling Smørgrav  *
767b5038d7SDag-Erling Smørgrav  */
777b5038d7SDag-Erling Smørgrav int
ldns_duration_compare(const ldns_duration_type * d1,const ldns_duration_type * d2)78986ba33cSDag-Erling Smørgrav ldns_duration_compare(const ldns_duration_type* d1, const ldns_duration_type* d2)
797b5038d7SDag-Erling Smørgrav {
807b5038d7SDag-Erling Smørgrav     if (!d1 && !d2) {
817b5038d7SDag-Erling Smørgrav         return 0;
827b5038d7SDag-Erling Smørgrav     }
837b5038d7SDag-Erling Smørgrav     if (!d1 || !d2) {
847b5038d7SDag-Erling Smørgrav         return d1?-1:1;
857b5038d7SDag-Erling Smørgrav     }
867b5038d7SDag-Erling Smørgrav 
877b5038d7SDag-Erling Smørgrav     if (d1->years != d2->years) {
887b5038d7SDag-Erling Smørgrav         return (int) (d1->years - d2->years);
897b5038d7SDag-Erling Smørgrav     }
907b5038d7SDag-Erling Smørgrav     if (d1->months != d2->months) {
917b5038d7SDag-Erling Smørgrav         return (int) (d1->months - d2->months);
927b5038d7SDag-Erling Smørgrav     }
937b5038d7SDag-Erling Smørgrav     if (d1->weeks != d2->weeks) {
947b5038d7SDag-Erling Smørgrav         return (int) (d1->weeks - d2->weeks);
957b5038d7SDag-Erling Smørgrav     }
967b5038d7SDag-Erling Smørgrav     if (d1->days != d2->days) {
977b5038d7SDag-Erling Smørgrav         return (int) (d1->days - d2->days);
987b5038d7SDag-Erling Smørgrav     }
997b5038d7SDag-Erling Smørgrav     if (d1->hours != d2->hours) {
1007b5038d7SDag-Erling Smørgrav         return (int) (d1->hours - d2->hours);
1017b5038d7SDag-Erling Smørgrav     }
1027b5038d7SDag-Erling Smørgrav     if (d1->minutes != d2->minutes) {
1037b5038d7SDag-Erling Smørgrav         return (int) (d1->minutes - d2->minutes);
1047b5038d7SDag-Erling Smørgrav     }
1057b5038d7SDag-Erling Smørgrav     if (d1->seconds != d2->seconds) {
1067b5038d7SDag-Erling Smørgrav         return (int) (d1->seconds - d2->seconds);
1077b5038d7SDag-Erling Smørgrav     }
1087b5038d7SDag-Erling Smørgrav 
1097b5038d7SDag-Erling Smørgrav     return 0;
1107b5038d7SDag-Erling Smørgrav }
1117b5038d7SDag-Erling Smørgrav 
1127b5038d7SDag-Erling Smørgrav 
1137b5038d7SDag-Erling Smørgrav /**
1147b5038d7SDag-Erling Smørgrav  * Create a duration from string.
1157b5038d7SDag-Erling Smørgrav  *
1167b5038d7SDag-Erling Smørgrav  */
1177b5038d7SDag-Erling Smørgrav ldns_duration_type*
ldns_duration_create_from_string(const char * str)1187b5038d7SDag-Erling Smørgrav ldns_duration_create_from_string(const char* str)
1197b5038d7SDag-Erling Smørgrav {
1207b5038d7SDag-Erling Smørgrav     ldns_duration_type* duration = ldns_duration_create();
1217b5038d7SDag-Erling Smørgrav     char* P, *X, *T, *W;
1227b5038d7SDag-Erling Smørgrav     int not_weeks = 0;
1237b5038d7SDag-Erling Smørgrav 
1247b5038d7SDag-Erling Smørgrav     if (!duration) {
1257b5038d7SDag-Erling Smørgrav         return NULL;
1267b5038d7SDag-Erling Smørgrav     }
1277b5038d7SDag-Erling Smørgrav     if (!str) {
1287b5038d7SDag-Erling Smørgrav         return duration;
1297b5038d7SDag-Erling Smørgrav     }
1307b5038d7SDag-Erling Smørgrav 
1317b5038d7SDag-Erling Smørgrav     P = strchr(str, 'P');
1327b5038d7SDag-Erling Smørgrav     if (!P) {
1337b5038d7SDag-Erling Smørgrav 	ldns_duration_cleanup(duration);
1347b5038d7SDag-Erling Smørgrav         return NULL;
1357b5038d7SDag-Erling Smørgrav     }
1367b5038d7SDag-Erling Smørgrav 
1377b5038d7SDag-Erling Smørgrav     T = strchr(str, 'T');
1387b5038d7SDag-Erling Smørgrav     X = strchr(str, 'Y');
1397b5038d7SDag-Erling Smørgrav     if (X) {
1407b5038d7SDag-Erling Smørgrav         duration->years = (time_t) atoi(str+1);
1417b5038d7SDag-Erling Smørgrav         str = X;
1427b5038d7SDag-Erling Smørgrav         not_weeks = 1;
1437b5038d7SDag-Erling Smørgrav     }
1447b5038d7SDag-Erling Smørgrav     X = strchr(str, 'M');
1457b5038d7SDag-Erling Smørgrav     if (X && (!T || (size_t) (X-P) < (size_t) (T-P))) {
1467b5038d7SDag-Erling Smørgrav         duration->months = (time_t) atoi(str+1);
1477b5038d7SDag-Erling Smørgrav         str = X;
1487b5038d7SDag-Erling Smørgrav         not_weeks = 1;
1497b5038d7SDag-Erling Smørgrav     }
1507b5038d7SDag-Erling Smørgrav     X = strchr(str, 'D');
1517b5038d7SDag-Erling Smørgrav     if (X) {
1527b5038d7SDag-Erling Smørgrav         duration->days = (time_t) atoi(str+1);
1537b5038d7SDag-Erling Smørgrav         str = X;
1547b5038d7SDag-Erling Smørgrav         not_weeks = 1;
1557b5038d7SDag-Erling Smørgrav     }
1567b5038d7SDag-Erling Smørgrav     if (T) {
1577b5038d7SDag-Erling Smørgrav         str = T;
1587b5038d7SDag-Erling Smørgrav         not_weeks = 1;
1597b5038d7SDag-Erling Smørgrav     }
1607b5038d7SDag-Erling Smørgrav     X = strchr(str, 'H');
1617b5038d7SDag-Erling Smørgrav     if (X && T) {
1627b5038d7SDag-Erling Smørgrav         duration->hours = (time_t) atoi(str+1);
1637b5038d7SDag-Erling Smørgrav         str = X;
1647b5038d7SDag-Erling Smørgrav         not_weeks = 1;
1657b5038d7SDag-Erling Smørgrav     }
1667b5038d7SDag-Erling Smørgrav     X = strrchr(str, 'M');
1677b5038d7SDag-Erling Smørgrav     if (X && T && (size_t) (X-P) > (size_t) (T-P)) {
1687b5038d7SDag-Erling Smørgrav         duration->minutes = (time_t) atoi(str+1);
1697b5038d7SDag-Erling Smørgrav         str = X;
1707b5038d7SDag-Erling Smørgrav         not_weeks = 1;
1717b5038d7SDag-Erling Smørgrav     }
1727b5038d7SDag-Erling Smørgrav     X = strchr(str, 'S');
1737b5038d7SDag-Erling Smørgrav     if (X && T) {
1747b5038d7SDag-Erling Smørgrav         duration->seconds = (time_t) atoi(str+1);
1757b5038d7SDag-Erling Smørgrav         str = X;
1767b5038d7SDag-Erling Smørgrav         not_weeks = 1;
1777b5038d7SDag-Erling Smørgrav     }
1787b5038d7SDag-Erling Smørgrav 
1797b5038d7SDag-Erling Smørgrav     W = strchr(str, 'W');
1807b5038d7SDag-Erling Smørgrav     if (W) {
1817b5038d7SDag-Erling Smørgrav         if (not_weeks) {
1827b5038d7SDag-Erling Smørgrav             ldns_duration_cleanup(duration);
1837b5038d7SDag-Erling Smørgrav             return NULL;
1847b5038d7SDag-Erling Smørgrav         } else {
1857b5038d7SDag-Erling Smørgrav             duration->weeks = (time_t) atoi(str+1);
1867b5038d7SDag-Erling Smørgrav         }
1877b5038d7SDag-Erling Smørgrav     }
1887b5038d7SDag-Erling Smørgrav     return duration;
1897b5038d7SDag-Erling Smørgrav }
1907b5038d7SDag-Erling Smørgrav 
1917b5038d7SDag-Erling Smørgrav 
1927b5038d7SDag-Erling Smørgrav /**
193*5afab0e5SDag-Erling Smørgrav  * Helper func for ldns_duration2string below. If t > 0,
194*5afab0e5SDag-Erling Smørgrav  * scan print t and c on buf, forwarding buf. Return 0 on success.
1957b5038d7SDag-Erling Smørgrav  */
dur_scan_print(char ** buf,char * eob,char c,time_t t)196*5afab0e5SDag-Erling Smørgrav static inline int dur_scan_print(char **buf, char *eob, char c, time_t t)
1977b5038d7SDag-Erling Smørgrav {
198*5afab0e5SDag-Erling Smørgrav 	if (t > 0) {
199*5afab0e5SDag-Erling Smørgrav 		int r = snprintf(*buf, eob - *buf, "%u%c", (unsigned)t, c);
200*5afab0e5SDag-Erling Smørgrav 		if (r < 0 || (*buf += r) >= eob)
201*5afab0e5SDag-Erling Smørgrav 			return -1;
2027b5038d7SDag-Erling Smørgrav 	}
203*5afab0e5SDag-Erling Smørgrav 	return 0;
2047b5038d7SDag-Erling Smørgrav }
2057b5038d7SDag-Erling Smørgrav 
2067b5038d7SDag-Erling Smørgrav /**
2077b5038d7SDag-Erling Smørgrav  * Convert a duration to a string.
2087b5038d7SDag-Erling Smørgrav  *
2097b5038d7SDag-Erling Smørgrav  */
2107b5038d7SDag-Erling Smørgrav char*
ldns_duration2string(const ldns_duration_type * d)211*5afab0e5SDag-Erling Smørgrav ldns_duration2string(const ldns_duration_type* d)
2127b5038d7SDag-Erling Smørgrav {
213*5afab0e5SDag-Erling Smørgrav  	/* Max string size should be 7 * 40 + 3 on a 127 bits machine
214*5afab0e5SDag-Erling Smørgrav 	 * So 300 (< 273) is more than enough.
215*5afab0e5SDag-Erling Smørgrav 	 */
216*5afab0e5SDag-Erling Smørgrav 	char buf[300] = "P0D", *eob = buf + sizeof(buf), *p = buf + 1;
2177b5038d7SDag-Erling Smørgrav 
218*5afab0e5SDag-Erling Smørgrav 	if (!d)
219*5afab0e5SDag-Erling Smørgrav 		return NULL;
220*5afab0e5SDag-Erling Smørgrav 
221*5afab0e5SDag-Erling Smørgrav 	if (dur_scan_print(&p, eob, 'Y', d->years)
222*5afab0e5SDag-Erling Smørgrav 	||  dur_scan_print(&p, eob, 'M', d->months)
223*5afab0e5SDag-Erling Smørgrav 	||  dur_scan_print(&p, eob, 'W', d->weeks)
224*5afab0e5SDag-Erling Smørgrav 	||  dur_scan_print(&p, eob, 'D', d->days))
225*5afab0e5SDag-Erling Smørgrav 		return NULL;
226*5afab0e5SDag-Erling Smørgrav 
227*5afab0e5SDag-Erling Smørgrav 	if (d->hours || d->minutes || d->seconds) {
228*5afab0e5SDag-Erling Smørgrav 		if (p > (eob - 2))
229*5afab0e5SDag-Erling Smørgrav 			return NULL; /* Error; no space left on buf for 'T' */
230*5afab0e5SDag-Erling Smørgrav 
231*5afab0e5SDag-Erling Smørgrav 		*p++ = 'T'; *p = 0;
232*5afab0e5SDag-Erling Smørgrav 		if (dur_scan_print(&p, eob, 'H', d->hours)
233*5afab0e5SDag-Erling Smørgrav 		||  dur_scan_print(&p, eob, 'M', d->minutes)
234*5afab0e5SDag-Erling Smørgrav 		||  dur_scan_print(&p, eob, 'S', d->seconds))
2357b5038d7SDag-Erling Smørgrav 			return NULL;
2367b5038d7SDag-Erling Smørgrav 	}
237*5afab0e5SDag-Erling Smørgrav 	return strdup(buf);
2387b5038d7SDag-Erling Smørgrav }
2397b5038d7SDag-Erling Smørgrav 
2407b5038d7SDag-Erling Smørgrav 
2417b5038d7SDag-Erling Smørgrav /**
2427b5038d7SDag-Erling Smørgrav  * Convert a duration to a time.
2437b5038d7SDag-Erling Smørgrav  *
2447b5038d7SDag-Erling Smørgrav  */
2457b5038d7SDag-Erling Smørgrav time_t
ldns_duration2time(const ldns_duration_type * duration)246986ba33cSDag-Erling Smørgrav ldns_duration2time(const ldns_duration_type* duration)
2477b5038d7SDag-Erling Smørgrav {
2487b5038d7SDag-Erling Smørgrav     time_t period = 0;
2497b5038d7SDag-Erling Smørgrav 
2507b5038d7SDag-Erling Smørgrav     if (duration) {
2517b5038d7SDag-Erling Smørgrav         period += (duration->seconds);
2527b5038d7SDag-Erling Smørgrav         period += (duration->minutes)*60;
2537b5038d7SDag-Erling Smørgrav         period += (duration->hours)*3600;
2547b5038d7SDag-Erling Smørgrav         period += (duration->days)*86400;
2557b5038d7SDag-Erling Smørgrav         period += (duration->weeks)*86400*7;
2567b5038d7SDag-Erling Smørgrav         period += (duration->months)*86400*31;
2577b5038d7SDag-Erling Smørgrav         period += (duration->years)*86400*365;
2587b5038d7SDag-Erling Smørgrav 
2597b5038d7SDag-Erling Smørgrav         /* [TODO] calculate correct number of days in this month/year */
2607b5038d7SDag-Erling Smørgrav 	/*
2617b5038d7SDag-Erling Smørgrav         if (duration->months || duration->years) {
2627b5038d7SDag-Erling Smørgrav         }
2637b5038d7SDag-Erling Smørgrav 	*/
2647b5038d7SDag-Erling Smørgrav     }
2657b5038d7SDag-Erling Smørgrav     return period;
2667b5038d7SDag-Erling Smørgrav }
2677b5038d7SDag-Erling Smørgrav 
2687b5038d7SDag-Erling Smørgrav 
2697b5038d7SDag-Erling Smørgrav /**
2707b5038d7SDag-Erling Smørgrav  * Clean up duration.
2717b5038d7SDag-Erling Smørgrav  *
2727b5038d7SDag-Erling Smørgrav  */
2737b5038d7SDag-Erling Smørgrav void
ldns_duration_cleanup(ldns_duration_type * duration)2747b5038d7SDag-Erling Smørgrav ldns_duration_cleanup(ldns_duration_type* duration)
2757b5038d7SDag-Erling Smørgrav {
2767b5038d7SDag-Erling Smørgrav     if (!duration) {
2777b5038d7SDag-Erling Smørgrav         return;
2787b5038d7SDag-Erling Smørgrav     }
2797b5038d7SDag-Erling Smørgrav     free(duration);
2807b5038d7SDag-Erling Smørgrav     return;
2817b5038d7SDag-Erling Smørgrav }
282