1d1b2b5caSJohn Marino /*
2d1b2b5caSJohn Marino * $Id: duration.c 4518 2011-02-24 15:39:09Z matthijs $
3d1b2b5caSJohn Marino *
4d1b2b5caSJohn Marino * Copyright (c) 2009 NLNet Labs. All rights reserved.
5d1b2b5caSJohn Marino *
6d1b2b5caSJohn Marino * Redistribution and use in source and binary forms, with or without
7d1b2b5caSJohn Marino * modification, are permitted provided that the following conditions
8d1b2b5caSJohn Marino * are met:
9d1b2b5caSJohn Marino * 1. Redistributions of source code must retain the above copyright
10d1b2b5caSJohn Marino * notice, this list of conditions and the following disclaimer.
11d1b2b5caSJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
12d1b2b5caSJohn Marino * notice, this list of conditions and the following disclaimer in the
13d1b2b5caSJohn Marino * documentation and/or other materials provided with the distribution.
14d1b2b5caSJohn Marino *
15d1b2b5caSJohn Marino * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16d1b2b5caSJohn Marino * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17d1b2b5caSJohn Marino * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18d1b2b5caSJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19d1b2b5caSJohn Marino * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20d1b2b5caSJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21d1b2b5caSJohn Marino * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22d1b2b5caSJohn Marino * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23d1b2b5caSJohn Marino * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24d1b2b5caSJohn Marino * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25d1b2b5caSJohn Marino * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26d1b2b5caSJohn Marino *
27d1b2b5caSJohn Marino */
28d1b2b5caSJohn Marino
29d1b2b5caSJohn Marino /**
30d1b2b5caSJohn Marino *
31d1b2b5caSJohn Marino * This file is copied from the OpenDNSSEC source repository
32d1b2b5caSJohn Marino * and only slightly adapted to make it fit.
33d1b2b5caSJohn Marino */
34d1b2b5caSJohn Marino
35d1b2b5caSJohn Marino /**
36d1b2b5caSJohn Marino *
37d1b2b5caSJohn Marino * Durations.
38d1b2b5caSJohn Marino */
39d1b2b5caSJohn Marino
40d1b2b5caSJohn Marino #include <ldns/config.h>
41d1b2b5caSJohn Marino #include <ldns/duration.h>
42d1b2b5caSJohn Marino
43d1b2b5caSJohn Marino #include <stdio.h>
44d1b2b5caSJohn Marino #include <stdlib.h>
45d1b2b5caSJohn Marino #include <string.h>
46d1b2b5caSJohn Marino #include <time.h>
47d1b2b5caSJohn Marino
48d1b2b5caSJohn Marino
49d1b2b5caSJohn Marino /**
50d1b2b5caSJohn Marino * Create a new 'instant' duration.
51d1b2b5caSJohn Marino *
52d1b2b5caSJohn Marino */
53d1b2b5caSJohn Marino ldns_duration_type*
ldns_duration_create(void)54d1b2b5caSJohn Marino ldns_duration_create(void)
55d1b2b5caSJohn Marino {
56d1b2b5caSJohn Marino ldns_duration_type* duration;
57d1b2b5caSJohn Marino
58d1b2b5caSJohn Marino duration = malloc(sizeof(ldns_duration_type));
59d1b2b5caSJohn Marino if (!duration) {
60d1b2b5caSJohn Marino return NULL;
61d1b2b5caSJohn Marino }
62d1b2b5caSJohn Marino duration->years = 0;
63d1b2b5caSJohn Marino duration->months = 0;
64d1b2b5caSJohn Marino duration->weeks = 0;
65d1b2b5caSJohn Marino duration->days = 0;
66d1b2b5caSJohn Marino duration->hours = 0;
67d1b2b5caSJohn Marino duration->minutes = 0;
68d1b2b5caSJohn Marino duration->seconds = 0;
69d1b2b5caSJohn Marino return duration;
70d1b2b5caSJohn Marino }
71d1b2b5caSJohn Marino
72d1b2b5caSJohn Marino
73d1b2b5caSJohn Marino /**
74d1b2b5caSJohn Marino * Compare durations.
75d1b2b5caSJohn Marino *
76d1b2b5caSJohn Marino */
77d1b2b5caSJohn Marino int
ldns_duration_compare(const ldns_duration_type * d1,const ldns_duration_type * d2)785340022aSzrj ldns_duration_compare(const ldns_duration_type* d1, const ldns_duration_type* d2)
79d1b2b5caSJohn Marino {
80d1b2b5caSJohn Marino if (!d1 && !d2) {
81d1b2b5caSJohn Marino return 0;
82d1b2b5caSJohn Marino }
83d1b2b5caSJohn Marino if (!d1 || !d2) {
84d1b2b5caSJohn Marino return d1?-1:1;
85d1b2b5caSJohn Marino }
86d1b2b5caSJohn Marino
87d1b2b5caSJohn Marino if (d1->years != d2->years) {
88d1b2b5caSJohn Marino return (int) (d1->years - d2->years);
89d1b2b5caSJohn Marino }
90d1b2b5caSJohn Marino if (d1->months != d2->months) {
91d1b2b5caSJohn Marino return (int) (d1->months - d2->months);
92d1b2b5caSJohn Marino }
93d1b2b5caSJohn Marino if (d1->weeks != d2->weeks) {
94d1b2b5caSJohn Marino return (int) (d1->weeks - d2->weeks);
95d1b2b5caSJohn Marino }
96d1b2b5caSJohn Marino if (d1->days != d2->days) {
97d1b2b5caSJohn Marino return (int) (d1->days - d2->days);
98d1b2b5caSJohn Marino }
99d1b2b5caSJohn Marino if (d1->hours != d2->hours) {
100d1b2b5caSJohn Marino return (int) (d1->hours - d2->hours);
101d1b2b5caSJohn Marino }
102d1b2b5caSJohn Marino if (d1->minutes != d2->minutes) {
103d1b2b5caSJohn Marino return (int) (d1->minutes - d2->minutes);
104d1b2b5caSJohn Marino }
105d1b2b5caSJohn Marino if (d1->seconds != d2->seconds) {
106d1b2b5caSJohn Marino return (int) (d1->seconds - d2->seconds);
107d1b2b5caSJohn Marino }
108d1b2b5caSJohn Marino
109d1b2b5caSJohn Marino return 0;
110d1b2b5caSJohn Marino }
111d1b2b5caSJohn Marino
112d1b2b5caSJohn Marino
113d1b2b5caSJohn Marino /**
114d1b2b5caSJohn Marino * Create a duration from string.
115d1b2b5caSJohn Marino *
116d1b2b5caSJohn Marino */
117d1b2b5caSJohn Marino ldns_duration_type*
ldns_duration_create_from_string(const char * str)118d1b2b5caSJohn Marino ldns_duration_create_from_string(const char* str)
119d1b2b5caSJohn Marino {
120d1b2b5caSJohn Marino ldns_duration_type* duration = ldns_duration_create();
121d1b2b5caSJohn Marino char* P, *X, *T, *W;
122d1b2b5caSJohn Marino int not_weeks = 0;
123d1b2b5caSJohn Marino
124d1b2b5caSJohn Marino if (!duration) {
125d1b2b5caSJohn Marino return NULL;
126d1b2b5caSJohn Marino }
127d1b2b5caSJohn Marino if (!str) {
128d1b2b5caSJohn Marino return duration;
129d1b2b5caSJohn Marino }
130d1b2b5caSJohn Marino
131d1b2b5caSJohn Marino P = strchr(str, 'P');
132d1b2b5caSJohn Marino if (!P) {
133d1b2b5caSJohn Marino ldns_duration_cleanup(duration);
134d1b2b5caSJohn Marino return NULL;
135d1b2b5caSJohn Marino }
136d1b2b5caSJohn Marino
137d1b2b5caSJohn Marino T = strchr(str, 'T');
138d1b2b5caSJohn Marino X = strchr(str, 'Y');
139d1b2b5caSJohn Marino if (X) {
140d1b2b5caSJohn Marino duration->years = (time_t) atoi(str+1);
141d1b2b5caSJohn Marino str = X;
142d1b2b5caSJohn Marino not_weeks = 1;
143d1b2b5caSJohn Marino }
144d1b2b5caSJohn Marino X = strchr(str, 'M');
145d1b2b5caSJohn Marino if (X && (!T || (size_t) (X-P) < (size_t) (T-P))) {
146d1b2b5caSJohn Marino duration->months = (time_t) atoi(str+1);
147d1b2b5caSJohn Marino str = X;
148d1b2b5caSJohn Marino not_weeks = 1;
149d1b2b5caSJohn Marino }
150d1b2b5caSJohn Marino X = strchr(str, 'D');
151d1b2b5caSJohn Marino if (X) {
152d1b2b5caSJohn Marino duration->days = (time_t) atoi(str+1);
153d1b2b5caSJohn Marino str = X;
154d1b2b5caSJohn Marino not_weeks = 1;
155d1b2b5caSJohn Marino }
156d1b2b5caSJohn Marino if (T) {
157d1b2b5caSJohn Marino str = T;
158d1b2b5caSJohn Marino not_weeks = 1;
159d1b2b5caSJohn Marino }
160d1b2b5caSJohn Marino X = strchr(str, 'H');
161d1b2b5caSJohn Marino if (X && T) {
162d1b2b5caSJohn Marino duration->hours = (time_t) atoi(str+1);
163d1b2b5caSJohn Marino str = X;
164d1b2b5caSJohn Marino not_weeks = 1;
165d1b2b5caSJohn Marino }
166d1b2b5caSJohn Marino X = strrchr(str, 'M');
167d1b2b5caSJohn Marino if (X && T && (size_t) (X-P) > (size_t) (T-P)) {
168d1b2b5caSJohn Marino duration->minutes = (time_t) atoi(str+1);
169d1b2b5caSJohn Marino str = X;
170d1b2b5caSJohn Marino not_weeks = 1;
171d1b2b5caSJohn Marino }
172d1b2b5caSJohn Marino X = strchr(str, 'S');
173d1b2b5caSJohn Marino if (X && T) {
174d1b2b5caSJohn Marino duration->seconds = (time_t) atoi(str+1);
175d1b2b5caSJohn Marino str = X;
176d1b2b5caSJohn Marino not_weeks = 1;
177d1b2b5caSJohn Marino }
178d1b2b5caSJohn Marino
179d1b2b5caSJohn Marino W = strchr(str, 'W');
180d1b2b5caSJohn Marino if (W) {
181d1b2b5caSJohn Marino if (not_weeks) {
182d1b2b5caSJohn Marino ldns_duration_cleanup(duration);
183d1b2b5caSJohn Marino return NULL;
184d1b2b5caSJohn Marino } else {
185d1b2b5caSJohn Marino duration->weeks = (time_t) atoi(str+1);
186d1b2b5caSJohn Marino }
187d1b2b5caSJohn Marino }
188d1b2b5caSJohn Marino return duration;
189d1b2b5caSJohn Marino }
190d1b2b5caSJohn Marino
191d1b2b5caSJohn Marino
192d1b2b5caSJohn Marino /**
193*ee791febSAntonio Huete Jimenez * Helper func for ldns_duration2string below. If t > 0,
194*ee791febSAntonio Huete Jimenez * scan print t and c on buf, forwarding buf. Return 0 on success.
195d1b2b5caSJohn Marino */
dur_scan_print(char ** buf,char * eob,char c,time_t t)196*ee791febSAntonio Huete Jimenez static inline int dur_scan_print(char **buf, char *eob, char c, time_t t)
197d1b2b5caSJohn Marino {
198*ee791febSAntonio Huete Jimenez if (t > 0) {
199*ee791febSAntonio Huete Jimenez int r = snprintf(*buf, eob - *buf, "%u%c", (unsigned)t, c);
200*ee791febSAntonio Huete Jimenez if (r < 0 || (*buf += r) >= eob)
201*ee791febSAntonio Huete Jimenez return -1;
202d1b2b5caSJohn Marino }
203*ee791febSAntonio Huete Jimenez return 0;
204d1b2b5caSJohn Marino }
205d1b2b5caSJohn Marino
206d1b2b5caSJohn Marino /**
207d1b2b5caSJohn Marino * Convert a duration to a string.
208d1b2b5caSJohn Marino *
209d1b2b5caSJohn Marino */
210d1b2b5caSJohn Marino char*
ldns_duration2string(const ldns_duration_type * d)211*ee791febSAntonio Huete Jimenez ldns_duration2string(const ldns_duration_type* d)
212d1b2b5caSJohn Marino {
213*ee791febSAntonio Huete Jimenez /* Max string size should be 7 * 40 + 3 on a 127 bits machine
214*ee791febSAntonio Huete Jimenez * So 300 (< 273) is more than enough.
215*ee791febSAntonio Huete Jimenez */
216*ee791febSAntonio Huete Jimenez char buf[300] = "P0D", *eob = buf + sizeof(buf), *p = buf + 1;
217d1b2b5caSJohn Marino
218*ee791febSAntonio Huete Jimenez if (!d)
219*ee791febSAntonio Huete Jimenez return NULL;
220*ee791febSAntonio Huete Jimenez
221*ee791febSAntonio Huete Jimenez if (dur_scan_print(&p, eob, 'Y', d->years)
222*ee791febSAntonio Huete Jimenez || dur_scan_print(&p, eob, 'M', d->months)
223*ee791febSAntonio Huete Jimenez || dur_scan_print(&p, eob, 'W', d->weeks)
224*ee791febSAntonio Huete Jimenez || dur_scan_print(&p, eob, 'D', d->days))
225*ee791febSAntonio Huete Jimenez return NULL;
226*ee791febSAntonio Huete Jimenez
227*ee791febSAntonio Huete Jimenez if (d->hours || d->minutes || d->seconds) {
228*ee791febSAntonio Huete Jimenez if (p > (eob - 2))
229*ee791febSAntonio Huete Jimenez return NULL; /* Error; no space left on buf for 'T' */
230*ee791febSAntonio Huete Jimenez
231*ee791febSAntonio Huete Jimenez *p++ = 'T'; *p = 0;
232*ee791febSAntonio Huete Jimenez if (dur_scan_print(&p, eob, 'H', d->hours)
233*ee791febSAntonio Huete Jimenez || dur_scan_print(&p, eob, 'M', d->minutes)
234*ee791febSAntonio Huete Jimenez || dur_scan_print(&p, eob, 'S', d->seconds))
235d1b2b5caSJohn Marino return NULL;
236d1b2b5caSJohn Marino }
237*ee791febSAntonio Huete Jimenez return strdup(buf);
238d1b2b5caSJohn Marino }
239d1b2b5caSJohn Marino
240d1b2b5caSJohn Marino
241d1b2b5caSJohn Marino /**
242d1b2b5caSJohn Marino * Convert a duration to a time.
243d1b2b5caSJohn Marino *
244d1b2b5caSJohn Marino */
245d1b2b5caSJohn Marino time_t
ldns_duration2time(const ldns_duration_type * duration)2465340022aSzrj ldns_duration2time(const ldns_duration_type* duration)
247d1b2b5caSJohn Marino {
248d1b2b5caSJohn Marino time_t period = 0;
249d1b2b5caSJohn Marino
250d1b2b5caSJohn Marino if (duration) {
251d1b2b5caSJohn Marino period += (duration->seconds);
252d1b2b5caSJohn Marino period += (duration->minutes)*60;
253d1b2b5caSJohn Marino period += (duration->hours)*3600;
254d1b2b5caSJohn Marino period += (duration->days)*86400;
255d1b2b5caSJohn Marino period += (duration->weeks)*86400*7;
256d1b2b5caSJohn Marino period += (duration->months)*86400*31;
257d1b2b5caSJohn Marino period += (duration->years)*86400*365;
258d1b2b5caSJohn Marino
259d1b2b5caSJohn Marino /* [TODO] calculate correct number of days in this month/year */
260d1b2b5caSJohn Marino /*
261d1b2b5caSJohn Marino if (duration->months || duration->years) {
262d1b2b5caSJohn Marino }
263d1b2b5caSJohn Marino */
264d1b2b5caSJohn Marino }
265d1b2b5caSJohn Marino return period;
266d1b2b5caSJohn Marino }
267d1b2b5caSJohn Marino
268d1b2b5caSJohn Marino
269d1b2b5caSJohn Marino /**
270d1b2b5caSJohn Marino * Clean up duration.
271d1b2b5caSJohn Marino *
272d1b2b5caSJohn Marino */
273d1b2b5caSJohn Marino void
ldns_duration_cleanup(ldns_duration_type * duration)274d1b2b5caSJohn Marino ldns_duration_cleanup(ldns_duration_type* duration)
275d1b2b5caSJohn Marino {
276d1b2b5caSJohn Marino if (!duration) {
277d1b2b5caSJohn Marino return;
278d1b2b5caSJohn Marino }
279d1b2b5caSJohn Marino free(duration);
280d1b2b5caSJohn Marino return;
281d1b2b5caSJohn Marino }
282