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(ldns_duration_type* d1, 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 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 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* 216 ldns_duration2string(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 319 ldns_duration2time(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 347 ldns_duration_cleanup(ldns_duration_type* duration) 348 { 349 if (!duration) { 350 return; 351 } 352 free(duration); 353 return; 354 } 355