xref: /freebsd/contrib/ldns/duration.c (revision 5afab0e5e56fe90a378fb57249600e7924e1cab2)
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          }
187      }
188      return duration;
189  }
190  
191  
192  /**
193   * Helper func for ldns_duration2string below. If t > 0,
194   * scan print t and c on buf, forwarding buf. Return 0 on success.
195   */
dur_scan_print(char ** buf,char * eob,char c,time_t t)196  static inline int dur_scan_print(char **buf, char *eob, char c, time_t t)
197  {
198  	if (t > 0) {
199  		int r = snprintf(*buf, eob - *buf, "%u%c", (unsigned)t, c);
200  		if (r < 0 || (*buf += r) >= eob)
201  			return -1;
202  	}
203  	return 0;
204  }
205  
206  /**
207   * Convert a duration to a string.
208   *
209   */
210  char*
ldns_duration2string(const ldns_duration_type * d)211  ldns_duration2string(const ldns_duration_type* d)
212  {
213   	/* Max string size should be 7 * 40 + 3 on a 127 bits machine
214  	 * So 300 (< 273) is more than enough.
215  	 */
216  	char buf[300] = "P0D", *eob = buf + sizeof(buf), *p = buf + 1;
217  
218  	if (!d)
219  		return NULL;
220  
221  	if (dur_scan_print(&p, eob, 'Y', d->years)
222  	||  dur_scan_print(&p, eob, 'M', d->months)
223  	||  dur_scan_print(&p, eob, 'W', d->weeks)
224  	||  dur_scan_print(&p, eob, 'D', d->days))
225  		return NULL;
226  
227  	if (d->hours || d->minutes || d->seconds) {
228  		if (p > (eob - 2))
229  			return NULL; /* Error; no space left on buf for 'T' */
230  
231  		*p++ = 'T'; *p = 0;
232  		if (dur_scan_print(&p, eob, 'H', d->hours)
233  		||  dur_scan_print(&p, eob, 'M', d->minutes)
234  		||  dur_scan_print(&p, eob, 'S', d->seconds))
235  			return NULL;
236  	}
237  	return strdup(buf);
238  }
239  
240  
241  /**
242   * Convert a duration to a time.
243   *
244   */
245  time_t
ldns_duration2time(const ldns_duration_type * duration)246  ldns_duration2time(const ldns_duration_type* duration)
247  {
248      time_t period = 0;
249  
250      if (duration) {
251          period += (duration->seconds);
252          period += (duration->minutes)*60;
253          period += (duration->hours)*3600;
254          period += (duration->days)*86400;
255          period += (duration->weeks)*86400*7;
256          period += (duration->months)*86400*31;
257          period += (duration->years)*86400*365;
258  
259          /* [TODO] calculate correct number of days in this month/year */
260  	/*
261          if (duration->months || duration->years) {
262          }
263  	*/
264      }
265      return period;
266  }
267  
268  
269  /**
270   * Clean up duration.
271   *
272   */
273  void
ldns_duration_cleanup(ldns_duration_type * duration)274  ldns_duration_cleanup(ldns_duration_type* duration)
275  {
276      if (!duration) {
277          return;
278      }
279      free(duration);
280      return;
281  }
282