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* 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 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* 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 */ 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* 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 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 274 ldns_duration_cleanup(ldns_duration_type* duration) 275 { 276 if (!duration) { 277 return; 278 } 279 free(duration); 280 return; 281 } 282