"Fossies" - the Fresh Open Source Software Archive

Member "opendnssec-2.1.4/common/duration.c" (16 May 2019, 12639 Bytes) of package /linux/misc/dns/opendnssec-2.1.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "duration.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (c) 2009 NLNet Labs. All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
   17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
   19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
   23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24  *
   25  */
   26 
   27 /**
   28  *
   29  * Durations.
   30  */
   31 
   32 #include "status.h"
   33 #include "duration.h"
   34 #include "log.h"
   35 
   36 #include <stdio.h>
   37 #include <stdlib.h>
   38 #include <string.h>
   39 #include <time.h>
   40 #include <ctype.h>
   41 
   42 static const char* duration_str = "duration";
   43 
   44 
   45 /**
   46  * Create a new 'instant' duration.
   47  *
   48  */
   49 duration_type*
   50 duration_create(void)
   51 {
   52     duration_type* duration;
   53 
   54     CHECKALLOC(duration = (duration_type*) malloc(sizeof(duration_type)));
   55     duration->years = 0;
   56     duration->months = 0;
   57     duration->weeks = 0;
   58     duration->days = 0;
   59     duration->hours = 0;
   60     duration->minutes = 0;
   61     duration->seconds = 0;
   62     return duration;
   63 }
   64 
   65 
   66 /**
   67  * Compare durations.
   68  *
   69  */
   70 int
   71 duration_compare(duration_type* d1, duration_type* d2)
   72 {
   73     if (!d1 && !d2) {
   74         return 0;
   75     }
   76     if (!d1 || !d2) {
   77         return d1?-1:1;
   78     }
   79 
   80     if (d1->years != d2->years) {
   81         return d1->years - d2->years;
   82     }
   83     if (d1->months != d2->months) {
   84         return d1->months - d2->months;
   85     }
   86     if (d1->weeks != d2->weeks) {
   87         return d1->weeks - d2->weeks;
   88     }
   89     if (d1->days != d2->days) {
   90         return d1->days - d2->days;
   91     }
   92     if (d1->hours != d2->hours) {
   93         return d1->hours - d2->hours;
   94     }
   95     if (d1->minutes != d2->minutes) {
   96         return d1->minutes - d2->minutes;
   97     }
   98     if (d1->seconds != d2->seconds) {
   99         return d1->seconds - d2->seconds;
  100     }
  101 
  102     return 0;
  103 }
  104 
  105 
  106 /**
  107  * Create a duration from string.
  108  *
  109  */
  110 duration_type*
  111 duration_create_from_string(const char* str)
  112 {
  113     duration_type* duration = duration_create();
  114     char* P, *X, *T, *W;
  115     int not_weeks = 0;
  116 
  117     if (!duration) {
  118         ods_log_error("[%s] cannot create from string %s: create failed",
  119             duration_str, str);
  120         return NULL;
  121     }
  122     if (!str) {
  123         return duration;
  124     }
  125 
  126     P = strchr(str, 'P');
  127     if (!P) {
  128         ods_log_error("[%s] cannot create from string %s: P not found",
  129             duration_str, str);
  130         duration_cleanup(duration);
  131         return NULL;
  132     }
  133 
  134     T = strchr(str, 'T');
  135     X = strchr(str, 'Y');
  136     if (X) {
  137         duration->years = atoi(str+1);
  138         str = X;
  139         not_weeks = 1;
  140     }
  141     X = strchr(str, 'M');
  142     if (X && (!T || (size_t) (X-P) < (size_t) (T-P))) {
  143         duration->months = atoi(str+1);
  144         str = X;
  145         not_weeks = 1;
  146     }
  147     X = strchr(str, 'D');
  148     if (X) {
  149         duration->days = atoi(str+1);
  150         str = X;
  151         not_weeks = 1;
  152     }
  153     if (T) {
  154         str = T;
  155         not_weeks = 1;
  156     }
  157     X = strchr(str, 'H');
  158     if (X && T) {
  159         duration->hours = atoi(str+1);
  160         str = X;
  161         not_weeks = 1;
  162     }
  163     X = strrchr(str, 'M');
  164     if (X && T && (size_t) (X-P) > (size_t) (T-P)) {
  165         duration->minutes = atoi(str+1);
  166         str = X;
  167         not_weeks = 1;
  168     }
  169     X = strchr(str, 'S');
  170     if (X && T) {
  171         duration->seconds = atoi(str+1);
  172         str = X;
  173         not_weeks = 1;
  174     }
  175 
  176     W = strchr(str, 'W');
  177     if (W) {
  178         if (not_weeks) {
  179             ods_log_error("[%s] cannot create from string: parse error",
  180                 duration_str);
  181             duration_cleanup(duration);
  182             return NULL;
  183         } else {
  184             duration->weeks = atoi(str+1);
  185             str = W;
  186         }
  187     }
  188     return duration;
  189 }
  190 
  191 
  192 /**
  193  * Get the number of digits in a number.
  194  *
  195  */
  196 static size_t
  197 digits_in_number(time_t duration)
  198 {
  199     uint32_t period = (uint32_t) duration;
  200     size_t count = 0;
  201     if (!period) {
  202         return 1;
  203     }
  204     while (period > 0) {
  205         count++;
  206         period /= 10;
  207     }
  208     return count;
  209 }
  210 
  211 
  212 /**
  213  * Convert a duration to a string.
  214  *
  215  */
  216 char*
  217 duration2string(duration_type* duration)
  218 {
  219     char* str = NULL, *num = NULL;
  220     size_t count = 2;
  221     int T = 0, D = 0;
  222 
  223     if (!duration) {
  224         return NULL;
  225     }
  226 
  227     if (duration->years > 0) {
  228         count = count + 1 + digits_in_number(duration->years);
  229         D = 1;
  230     }
  231     if (duration->months > 0) {
  232         count = count + 1 + digits_in_number(duration->months);
  233         D = 1;
  234     }
  235     if (duration->weeks > 0) {
  236         count = count + 1 + digits_in_number(duration->weeks);
  237         D = 1;
  238     }
  239     if (duration->days > 0) {
  240         count = count + 1 + digits_in_number(duration->days);
  241         D = 1;
  242     }
  243     if (duration->hours > 0) {
  244         count = count + 1 + digits_in_number(duration->hours);
  245         T = 1;
  246     }
  247     if (duration->minutes > 0) {
  248         count = count + 1 + digits_in_number(duration->minutes);
  249         T = 1;
  250     }
  251     if (duration->seconds > 0 ||
  252         (!D && !duration->hours && !duration->minutes)) {
  253         count = count + 1 + digits_in_number(duration->seconds);
  254         T = 1;
  255     }
  256     if (T) {
  257         count++;
  258     }
  259 
  260     str = (char*) calloc(count, sizeof(char));
  261     str[0] = 'P';
  262     str[1] = '\0';
  263 
  264     if (duration->years > 0) {
  265         count = digits_in_number(duration->years);
  266         num = (char*) calloc(count+2, sizeof(char));
  267         if (num) {
  268         snprintf(num, count+2, "%uY", (uint32_t) duration->years);
  269         str = strncat(str, num, count+2);
  270         free((void*) num);
  271         } else {
  272             goto duration2string_num_calloc_failed;
  273         }
  274     }
  275     if (duration->months > 0) {
  276         count = digits_in_number(duration->months);
  277         num = (char*) calloc(count+2, sizeof(char));
  278         if (num) {
  279         snprintf(num, count+2, "%uM", (uint32_t) duration->months);
  280         str = strncat(str, num, count+2);
  281         free((void*) num);
  282         } else {
  283             goto duration2string_num_calloc_failed;
  284         }
  285     }
  286     if (duration->weeks > 0) {
  287         count = digits_in_number(duration->weeks);
  288         num = (char*) calloc(count+2, sizeof(char));
  289         if (num) {
  290             snprintf(num, count+2, "%uW", (uint32_t) duration->weeks);
  291             str = strncat(str, num, count+2);
  292             free((void*) num);
  293         } else {
  294             goto duration2string_num_calloc_failed;
  295         }
  296     }
  297     if (duration->days > 0) {
  298         count = digits_in_number(duration->days);
  299         num = (char*) calloc(count+2, sizeof(char));
  300         if (num) {
  301         snprintf(num, count+2, "%uD", (uint32_t) duration->days);
  302         str = strncat(str, num, count+2);
  303         free((void*) num);
  304         } else {
  305             goto duration2string_num_calloc_failed;
  306         }
  307     }
  308     if (T) {
  309         str = strncat(str, "T", 1);
  310     }
  311     if (duration->hours > 0) {
  312         count = digits_in_number(duration->hours);
  313         num = (char*) calloc(count+2, sizeof(char));
  314         if (num) {
  315         snprintf(num, count+2, "%uH", (uint32_t) duration->hours);
  316         str = strncat(str, num, count+2);
  317         free((void*) num);
  318         } else {
  319             goto duration2string_num_calloc_failed;
  320         }
  321     }
  322     if (duration->minutes > 0) {
  323         count = digits_in_number(duration->minutes);
  324         num = (char*) calloc(count+2, sizeof(char));
  325         if (num) {
  326         snprintf(num, count+2, "%uM", (uint32_t) duration->minutes);
  327         str = strncat(str, num, count+2);
  328         free((void*) num);
  329         } else {
  330             goto duration2string_num_calloc_failed;
  331     }
  332     }
  333     if (duration->seconds > 0 ||
  334         (!D && !duration->hours && !duration->minutes)) {
  335         count = digits_in_number(duration->seconds);
  336         num = (char*) calloc(count+2, sizeof(char));
  337         if (num) {
  338         snprintf(num, count+2, "%uS", (uint32_t) duration->seconds);
  339         str = strncat(str, num, count+2);
  340         free((void*) num);
  341         } else {
  342             goto duration2string_num_calloc_failed;
  343         }
  344     }
  345     return str;
  346 
  347 duration2string_num_calloc_failed:
  348     ods_log_error("[%s] cannot create string: malloc error", duration_str);
  349     free((void*) str);
  350     return NULL;
  351 }
  352 
  353 
  354 /**
  355  * Convert a duration to a time.
  356  *
  357  */
  358 time_t
  359 duration2time(duration_type* duration)
  360 {
  361     time_t period = 0;
  362     char* dstr = NULL;
  363 
  364     if (duration) {
  365         period += (duration->seconds);
  366         period += (duration->minutes)*60;
  367         period += (duration->hours)*3600;
  368         period += (duration->days)*86400;
  369         period += (duration->weeks)*86400*7;
  370         period += (duration->months)*86400*31;
  371         period += (duration->years)*86400*365;
  372 
  373         if (duration->months || duration->years) {
  374             /* [TODO] calculate correct number of days in this month/year */
  375             dstr = duration2string(duration);
  376             free((void*) dstr);
  377         }
  378     }
  379     return period;
  380 }
  381 
  382 /**
  383  * Set the duration based on a time_t.
  384  */
  385 int duration_set_time(duration_type* duration, time_t time) {
  386     if (!duration) {
  387         return 1;
  388     }
  389 
  390     duration->years = time / (86400*365);
  391     time -= duration->years * 86400*365;
  392     duration->months = time / (86400*31);
  393     time -= duration->months * 86400*31;
  394     duration->days = time / 86400;
  395     time -= duration->days * 86400;
  396     duration->hours = time / 3600;
  397     time -= duration->hours * 3600;
  398     duration->minutes = time / 60;
  399     time -= duration->minutes * 60;
  400     duration->seconds = time;
  401     
  402     duration->weeks = 0;
  403 
  404     return 0;
  405 }
  406 
  407 /**
  408  * Return a random time.
  409  *
  410  */
  411 time_t
  412 ods_rand(time_t mod)
  413 {
  414 #ifdef HAVE_ARC4RANDOM_UNIFORM
  415     return (time_t) (arc4random_uniform((uint32_t) mod+1));
  416 #elif HAVE_ARC4RANDOM
  417     return (time_t) (arc4random() % (unsigned) mod+1);
  418 #else
  419     return (time_t) (random() % (unsigned) mod+1);
  420 #endif
  421 }
  422 
  423 static time_t time_now_set = 0;
  424 
  425 /**
  426  * Set the time_now to a new value.
  427  * As long as this value is later than the real time now 
  428  * the overriden value is returned.
  429  *
  430  */
  431 void
  432 set_time_now(time_t now)
  433 {
  434     time_now_set = now;
  435 }
  436 
  437 int
  438 set_time_now_str(char* time_arg)
  439 {
  440     char* endptr;
  441     time_t epoch;
  442     struct tm tm;
  443     if (time_arg == NULL) {
  444         epoch = 0;
  445     } else if (strptime(time_arg, "%Y-%m-%d-%H:%M:%S", &tm)) {
  446         tm.tm_isdst = -1; /* OS handles daylight savings */
  447         epoch = mktime(&tm);
  448     } else {
  449         while (isspace(*time_arg))
  450             ++time_arg;
  451         epoch = strtol(time_arg, &endptr, 0);
  452         if (endptr != time_arg) {
  453             while (isspace(*endptr))
  454                 ++endptr;
  455             if (*endptr != '\0')
  456                 return -1;
  457         } else
  458             return -2;
  459     }
  460     set_time_now(epoch);
  461     return 0;
  462 }
  463 
  464 /**
  465  * Return the time since Epoch, measured in seconds.
  466  *
  467  */
  468 time_t
  469 time_now(void)
  470 {
  471     return time_now_set ? time_now_set: time(NULL);
  472 }
  473 
  474 /**
  475  * copycode: This code is based on the EXAMPLE in the strftime manual.
  476  *
  477  */
  478 uint32_t
  479 time_datestamp(time_t tt, const char* format, char** str)
  480 {
  481     time_t t;
  482     struct tm datetime;
  483     struct tm *tmp;
  484     uint32_t ut = 0;
  485     char outstr[32];
  486 
  487     if (tt) {
  488         t = tt;
  489     } else {
  490         t = time_now();
  491     }
  492 
  493     tmp = localtime_r(&t,&datetime);
  494     if (tmp == NULL) {
  495         ods_log_error("[%s] time_datestamp: localtime_r() failed", duration_str);
  496         return 0;
  497     }
  498 
  499     if (strftime(outstr, sizeof(outstr), format, tmp) == 0) {
  500         ods_log_error("[%s] time_datestamp: strftime() failed", duration_str);
  501         return 0;
  502     }
  503 
  504     ut = (uint32_t) strtoul(outstr, NULL, 10);
  505     if (str) {
  506         *str = strdup(outstr);
  507     }
  508     return ut;
  509 }
  510 
  511 /**
  512  * Clean up duration.
  513  *
  514  */
  515 void
  516 duration_cleanup(duration_type* duration)
  517 {
  518     if (!duration) {
  519         return;
  520     }
  521     free(duration);
  522 }