1 /*
2 * $Id: duration.c 4518 2011-02-24 15:39:09Z matthijs $
3 *
4 * Copyright (c) 2009 NLNet Labs. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29 /**
30 *
31 * This file is copied from the OpenDNSSEC source repository
32 * and only slightly adapted to make it fit.
33 */
34
35 /**
36 *
37 * Durations.
38 */
39
40 #include <ldns/config.h>
41 #include <ldns/duration.h>
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47
48
49 /**
50 * Create a new 'instant' duration.
51 *
52 */
53 ldns_duration_type*
ldns_duration_create(void)54 ldns_duration_create(void)
55 {
56 ldns_duration_type* duration;
57
58 duration = malloc(sizeof(ldns_duration_type));
59 if (!duration) {
60 return NULL;
61 }
62 duration->years = 0;
63 duration->months = 0;
64 duration->weeks = 0;
65 duration->days = 0;
66 duration->hours = 0;
67 duration->minutes = 0;
68 duration->seconds = 0;
69 return duration;
70 }
71
72
73 /**
74 * Compare durations.
75 *
76 */
77 int
ldns_duration_compare(const ldns_duration_type * d1,const ldns_duration_type * d2)78 ldns_duration_compare(const ldns_duration_type* d1, const ldns_duration_type* d2)
79 {
80 if (!d1 && !d2) {
81 return 0;
82 }
83 if (!d1 || !d2) {
84 return d1?-1:1;
85 }
86
87 if (d1->years != d2->years) {
88 return (int) (d1->years - d2->years);
89 }
90 if (d1->months != d2->months) {
91 return (int) (d1->months - d2->months);
92 }
93 if (d1->weeks != d2->weeks) {
94 return (int) (d1->weeks - d2->weeks);
95 }
96 if (d1->days != d2->days) {
97 return (int) (d1->days - d2->days);
98 }
99 if (d1->hours != d2->hours) {
100 return (int) (d1->hours - d2->hours);
101 }
102 if (d1->minutes != d2->minutes) {
103 return (int) (d1->minutes - d2->minutes);
104 }
105 if (d1->seconds != d2->seconds) {
106 return (int) (d1->seconds - d2->seconds);
107 }
108
109 return 0;
110 }
111
112
113 /**
114 * Create a duration from string.
115 *
116 */
117 ldns_duration_type*
ldns_duration_create_from_string(const char * str)118 ldns_duration_create_from_string(const char* str)
119 {
120 ldns_duration_type* duration = ldns_duration_create();
121 char* P, *X, *T, *W;
122 int not_weeks = 0;
123
124 if (!duration) {
125 return NULL;
126 }
127 if (!str) {
128 return duration;
129 }
130
131 P = strchr(str, 'P');
132 if (!P) {
133 ldns_duration_cleanup(duration);
134 return NULL;
135 }
136
137 T = strchr(str, 'T');
138 X = strchr(str, 'Y');
139 if (X) {
140 duration->years = (time_t) atoi(str+1);
141 str = X;
142 not_weeks = 1;
143 }
144 X = strchr(str, 'M');
145 if (X && (!T || (size_t) (X-P) < (size_t) (T-P))) {
146 duration->months = (time_t) atoi(str+1);
147 str = X;
148 not_weeks = 1;
149 }
150 X = strchr(str, 'D');
151 if (X) {
152 duration->days = (time_t) atoi(str+1);
153 str = X;
154 not_weeks = 1;
155 }
156 if (T) {
157 str = T;
158 not_weeks = 1;
159 }
160 X = strchr(str, 'H');
161 if (X && T) {
162 duration->hours = (time_t) atoi(str+1);
163 str = X;
164 not_weeks = 1;
165 }
166 X = strrchr(str, 'M');
167 if (X && T && (size_t) (X-P) > (size_t) (T-P)) {
168 duration->minutes = (time_t) atoi(str+1);
169 str = X;
170 not_weeks = 1;
171 }
172 X = strchr(str, 'S');
173 if (X && T) {
174 duration->seconds = (time_t) atoi(str+1);
175 str = X;
176 not_weeks = 1;
177 }
178
179 W = strchr(str, 'W');
180 if (W) {
181 if (not_weeks) {
182 ldns_duration_cleanup(duration);
183 return NULL;
184 } else {
185 duration->weeks = (time_t) atoi(str+1);
186 str = W;
187 }
188 }
189 return duration;
190 }
191
192
193 /**
194 * Get the number of digits in a number.
195 *
196 */
197 static size_t
digits_in_number(time_t duration)198 digits_in_number(time_t duration)
199 {
200 uint32_t period = (uint32_t) duration;
201 size_t count = 0;
202
203 while (period > 0) {
204 count++;
205 period /= 10;
206 }
207 return count;
208 }
209
210
211 /**
212 * Convert a duration to a string.
213 *
214 */
215 char*
ldns_duration2string(const ldns_duration_type * duration)216 ldns_duration2string(const ldns_duration_type* duration)
217 {
218 char* str = NULL, *num = NULL;
219 size_t count = 2;
220 int T = 0;
221
222 if (!duration) {
223 return NULL;
224 }
225
226 if (duration->years > 0) {
227 count = count + 1 + digits_in_number(duration->years);
228 }
229 if (duration->months > 0) {
230 count = count + 1 + digits_in_number(duration->months);
231 }
232 if (duration->weeks > 0) {
233 count = count + 1 + digits_in_number(duration->weeks);
234 }
235 if (duration->days > 0) {
236 count = count + 1 + digits_in_number(duration->days);
237 }
238 if (duration->hours > 0) {
239 count = count + 1 + digits_in_number(duration->hours);
240 T = 1;
241 }
242 if (duration->minutes > 0) {
243 count = count + 1 + digits_in_number(duration->minutes);
244 T = 1;
245 }
246 if (duration->seconds > 0) {
247 count = count + 1 + digits_in_number(duration->seconds);
248 T = 1;
249 }
250 if (T) {
251 count++;
252 }
253
254 str = (char*) calloc(count, sizeof(char));
255 str[0] = 'P';
256 str[1] = '\0';
257
258 if (duration->years > 0) {
259 count = digits_in_number(duration->years);
260 num = (char*) calloc(count+2, sizeof(char));
261 snprintf(num, count+2, "%uY", (unsigned int) duration->years);
262 str = strncat(str, num, count+2);
263 free((void*) num);
264 }
265 if (duration->months > 0) {
266 count = digits_in_number(duration->months);
267 num = (char*) calloc(count+2, sizeof(char));
268 snprintf(num, count+2, "%uM", (unsigned int) duration->months);
269 str = strncat(str, num, count+2);
270 free((void*) num);
271 }
272 if (duration->weeks > 0) {
273 count = digits_in_number(duration->weeks);
274 num = (char*) calloc(count+2, sizeof(char));
275 snprintf(num, count+2, "%uW", (unsigned int) duration->weeks);
276 str = strncat(str, num, count+2);
277 free((void*) num);
278 }
279 if (duration->days > 0) {
280 count = digits_in_number(duration->days);
281 num = (char*) calloc(count+2, sizeof(char));
282 snprintf(num, count+2, "%uD", (unsigned int) duration->days);
283 str = strncat(str, num, count+2);
284 free((void*) num);
285 }
286 if (T) {
287 str = strncat(str, "T", 1);
288 }
289 if (duration->hours > 0) {
290 count = digits_in_number(duration->hours);
291 num = (char*) calloc(count+2, sizeof(char));
292 snprintf(num, count+2, "%uH", (unsigned int) duration->hours);
293 str = strncat(str, num, count+2);
294 free((void*) num);
295 }
296 if (duration->minutes > 0) {
297 count = digits_in_number(duration->minutes);
298 num = (char*) calloc(count+2, sizeof(char));
299 snprintf(num, count+2, "%uM", (unsigned int) duration->minutes);
300 str = strncat(str, num, count+2);
301 free((void*) num);
302 }
303 if (duration->seconds > 0) {
304 count = digits_in_number(duration->seconds);
305 num = (char*) calloc(count+2, sizeof(char));
306 snprintf(num, count+2, "%uS", (unsigned int) duration->seconds);
307 str = strncat(str, num, count+2);
308 free((void*) num);
309 }
310 return str;
311 }
312
313
314 /**
315 * Convert a duration to a time.
316 *
317 */
318 time_t
ldns_duration2time(const ldns_duration_type * duration)319 ldns_duration2time(const ldns_duration_type* duration)
320 {
321 time_t period = 0;
322
323 if (duration) {
324 period += (duration->seconds);
325 period += (duration->minutes)*60;
326 period += (duration->hours)*3600;
327 period += (duration->days)*86400;
328 period += (duration->weeks)*86400*7;
329 period += (duration->months)*86400*31;
330 period += (duration->years)*86400*365;
331
332 /* [TODO] calculate correct number of days in this month/year */
333 /*
334 if (duration->months || duration->years) {
335 }
336 */
337 }
338 return period;
339 }
340
341
342 /**
343 * Clean up duration.
344 *
345 */
346 void
ldns_duration_cleanup(ldns_duration_type * duration)347 ldns_duration_cleanup(ldns_duration_type* duration)
348 {
349 if (!duration) {
350 return;
351 }
352 free(duration);
353 return;
354 }
355