• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

/srv/bpo/opendnssec/opendnssec-1.3.2/enforcer/ksm/datetime.c

Go to the documentation of this file.
00001 /*
00002  * $Id: datetime.c 4654 2011-03-25 08:43:46Z sion $
00003  *
00004  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00016  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00019  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00021  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00023  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00024  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00025  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  *
00027  */
00028 
00029 /*+
00030  * datetime - Miscellaneous Date/Time Utilities
00031  *
00032  * Description:
00033  *      Miscellaneous date/time utility functions used by the commands.
00034 -*/
00035 
00036 #define _GNU_SOURCE /* glibc2 needs this */
00037 #include "config.h"
00038 
00039 #include <assert.h>
00040 #include <ctype.h>
00041 #include <stdio.h>
00042 #include <string.h>
00043 #include <time.h>
00044 #include <limits.h>
00045 
00046 #include "compat.h"
00047 
00048 #include "ksm/ksm.h"
00049 #include "ksm/datetime.h"
00050 #include "ksm/message.h"
00051 #include "ksm/kmedef.h"
00052 #include "ksm/string_util.h"
00053 #include "ksm/string_util2.h"
00054 
00055 /* Macros to copy characters from one array to another */
00056 
00057 #define COPY1(src, srcidx, dst, dstidx) \
00058     { \
00059         (dst)[(dstidx)] = (src)[(srcidx)];\
00060     }
00061 #define COPY2(src, srcidx, dst, dstidx) \
00062     { \
00063         COPY1((src), (srcidx), (dst), (dstidx)); \
00064         COPY1((src), (srcidx) + 1, (dst), (dstidx) + 1); \
00065     }
00066 #define COPY3(src, srcidx, dst, dstidx) \
00067     { \
00068         COPY2((src), (srcidx), (dst), (dstidx)); \
00069         COPY1((src), (srcidx) + 2, (dst), (dstidx) + 2); \
00070     }
00071 #define COPY4(src, srcidx, dst, dstidx) \
00072     { \
00073         COPY3((src), (srcidx), (dst), (dstidx)); \
00074         COPY1((src), (srcidx) + 3, (dst), (dstidx) + 3); \
00075     }
00076 
00077 
00078 
00079 /*+
00080  * DtDateTimeNow - Return Current Date and Time
00081  *
00082  * Description:
00083  *      Returns a structure containing the current date and time.
00084  *
00085  * Arguments:
00086  *      struct tm* datetime
00087  *          Returned structure holding the current date and time.
00088  *
00089  * Returns:
00090  *      int
00091  *          0       Success
00092  *          1       Some error
00093 -*/
00094 
00095 int DtNow(struct tm* datetime)
00096 {
00097     time_t  curtime;    /* Current time */
00098     struct tm *ptr;     /* Pointer to returned result */
00099 
00100 #ifdef ENFORCER_TIMESHIFT
00101     char *override;
00102     int status;
00103 
00104     override = getenv("ENFORCER_TIMESHIFT");
00105     if (override) {
00106         (void) MsgLog(KME_TIMESHIFT, override);
00107         status = DtParseDateTime(override, datetime);
00108 
00109         if (status) {
00110                 printf("Couldn't turn \"%s\" into a date, quitting...\n", override);
00111                 exit(1);
00112         }
00113 
00114         return status;
00115     }
00116 #endif /* ENFORCER_TIMESHIFT */
00117 
00118     (void) time(&curtime);
00119     ptr = localtime_r(&curtime, datetime);
00120     return (ptr ? 0 : 1);
00121 }
00122 
00123 
00124 
00125 
00126 /*+
00127  * DtNumeric - Parse Numeric Date and Timestrncat
00128  *
00129  * Description:
00130  *      Given a string of the form YYYY[MM[DD[HH[MM[SS]]]]], return a struct tm
00131  *      structure holding the interpreted date and time.
00132  *
00133  * Arguments:
00134  *      const char* string
00135  *          String.  All the characters are known to be digits.
00136  *
00137  *      struct tm* datetime
00138  *          Returned structure holding the current date and time.
00139  *
00140  * Returns:
00141  *      int
00142  *          0       Success
00143  *          1       Some error
00144 -*/
00145 
00146 int DtNumeric(const char* string, struct tm* datetime)
00147 {
00148     int     i;              /* Loop counter */
00149     int     length;         /* Length of the string */
00150     char    buffer[15];     /* Fully expanded string */
00151     char    ebuffer[20];    /* Expanded string with spaces between */
00152     int     status = 0;     /* Assumed success return */
00153     char*   ptr;            /* Result pointer */
00154 
00155     /*
00156      * A numeric string is only valid if:
00157      *
00158      * a) it contains an even number of characters.
00159      * b) It has a minimum of 8 characters
00160      * c) It has a maximum of 14 characters.
00161      */
00162 
00163     length = strlen(string);
00164     if ((length >= 8) && (length <= 14) && ((length % 2) == 0)) {
00165 
00166         /* Valid string length, pad out to 14 characters with zeroes */
00167 
00168         strlcpy(buffer, string, 15);
00169         for (i = length; i < (int) (sizeof(buffer) - 1); ++i) {
00170             buffer[i] = '0';
00171         }
00172         buffer[sizeof(buffer) - 1] = '\0';
00173 
00174         /* Expand the character array to allow strptime to work */
00175 
00176         memset(ebuffer, ' ', sizeof(ebuffer));
00177         ebuffer[sizeof(ebuffer) - 1] = '\0';
00178 
00179         COPY4(buffer,  0, ebuffer,  0);
00180         COPY2(buffer,  4, ebuffer,  5);
00181         COPY2(buffer,  6, ebuffer,  8);
00182         COPY2(buffer,  8, ebuffer, 11);
00183         COPY2(buffer, 10, ebuffer, 14);
00184         COPY2(buffer, 12, ebuffer, 17);
00185 
00186         /* ... and convert */
00187 
00188         ptr = strptime(ebuffer, "%Y %m %d %H %M %S", datetime);
00189         status = ptr ? 0 : 1;
00190     }
00191     else {
00192 
00193         /* Wrong number of characters */
00194 
00195         status = 1;
00196     }
00197 
00198     return status;
00199 }
00200 
00201 
00202 /*+
00203  * DtAppendTime - Append Time to Date
00204  *
00205  * Description:
00206  *      Interprets the time part of a date/time string and appends it to the
00207  *      normalized date/time field.
00208  *
00209  * Arguments:
00210  *      char* fulldt
00211  *          Full date and time.  On entry, this points to a buffer holding the
00212  *          date part of the full date and time.  On exit, the data in the
00213  *          buffer is extended to include the time part.
00214  *
00215  *          Note: The buffer holding the full date and time is assumed to be
00216  *          big enough to allow the string in it to be extended by nine
00217  *          characters (i.e. _00:00:00).
00218  *
00219  *      const char* timepart
00220  *          Time part to append.  This must be one of the following allowed time
00221  *          formats:
00222  *
00223  *                  [[:| ]hh[:mm[:ss]]]
00224  *
00225  *          i.e. the first characters is a space or a colon, followed by a two-
00226  *          digit hour.  If minutes are present, they are separated from the
00227  *          hour by a colon, and likewise for seconds.
00228  *
00229  *          Any absent fields are assumed to be "00".
00230  *
00231  * Returns:
00232  *      int
00233  *          Status return
00234  *              0       Success
00235  *              1       Some problem with the date
00236 -*/
00237 
00238 int DtAppendTime(char* fulldt, const char* timepart)
00239 {
00240     int     length;         /* Length of the time part */
00241     int     status = 0;     /* Return status, assumed success */
00242 
00243     if (fulldt == NULL) {
00244         return 1;
00245     }
00246 
00247     if ((timepart == NULL) || (*timepart == '\0')) {
00248 
00249         /* No time part, set default */
00250 
00251         strcat(fulldt, " 00:00:00");
00252     }
00253     else {
00254         if ((*timepart == ' ') || (*timepart == ':')) {
00255 
00256             /* Valid separator */
00257 
00258             length = strlen(timepart);  /* Must be > 0 */
00259 
00260             /*
00261              * Now just check lengths.  If the length is correct
00262              * but the string is incorrect, it will be caught when
00263              * we try to interpret the time.
00264              */
00265 
00266             if (length == 3) {
00267                 strcat(fulldt, timepart);
00268                 strcat(fulldt, ":00:00");
00269             }
00270             else if (length == 6) {
00271                 strcat(fulldt, timepart);
00272                 strcat(fulldt, ":00");
00273             }
00274             else if (length == 9) {
00275                 strcat(fulldt, timepart);
00276             }
00277             else {
00278                 status = 1;
00279             }
00280         }
00281         else {
00282 
00283             /* Time part did not start with ' ' or ':' */
00284 
00285             status = 1;
00286         }
00287     }
00288 
00289     return status;
00290 }
00291 
00292 
00293 
00294 /*+
00295  * DtGeneral - Parse Date and Time
00296  *
00297  * Description:
00298  *      Given a string that represents a date, parse it and fill in a struct tm
00299  *      tm structure holding the interpreted date and time.
00300  *
00301  *      Allowed date/time strings are of the form:
00302  *
00303  *      YYYYMMDD[HH[MM[SS]]]                (all numeric)
00304  *
00305  *      or  D-MMM-YYYY[:| ]HH[:MM[:SS]]     (alphabetic  month)
00306  *      or  DD-MMM-YYYY[:| ]HH[:MM[:SS]]    (alphabetic  month)
00307  *      or  YYYY-MMM-DD[:| ]HH[:MM[:SS]]    (alphabetic month)
00308  *
00309  *          D-MM-YYYY[:| ]HH[:MM[:SS]]      (numeric month)
00310  *          DD-MM-YYYY[:| ]HH[:MM[:SS]]     (numeric month)
00311  *      or  YYYY-MM-DD[:| ]HH[:MM[:SS]]     (numeric month)
00312  *
00313  *      ... and the distinction between them is given by the location of the
00314  *      hyphens.
00315  *
00316  * Arguments:
00317  *      const char* string (input)
00318  *          String to check.  This is known to be non-null and not all spaces.
00319  *
00320  *      struct tm* datetime (modified)
00321  *          Structure which is returned holding the current date and time.
00322  *
00323  * Returns:
00324  *      int
00325  *          0       Success
00326  *          <>0     Some error
00327 -*/
00328 
00329 int DtGeneral(const char* string, struct tm* datetime)
00330 {
00331     int     alphadate = 0;      /* Set 1 if alphabetic form of the date */
00332     int     length;             /* Length of the string */
00333     char    copy[32];           /* Copy of input string */
00334     char    fulldt[32];         /* Full date and time */
00335     char*   ptr;                /* Pointer to tm structure */
00336     int     status = 0;         /* Return status */
00337     int     timeoff;            /* Offset of time part in given string */
00338 
00339     /* Assert what we know about the input */
00340 
00341     if (string == NULL || *string == '\0') {
00342         return 1;
00343     }
00344 
00345     /* Check the string */
00346 
00347     if (StrIsDigits(string)) {
00348 
00349         /* Possibly a numeric date/time - perform analysis */
00350 
00351         status = DtNumeric(string, datetime);
00352     }
00353     else {
00354         length = strlen(string);
00355         if (length >= 9) {
00356 
00357             /*
00358              * String has minimum length to be valid.  Copy it to a buffer of
00359              * a known length to ensure that all future index references are
00360              * valid (even if they do reference null characters).
00361              */
00362 
00363             memset(copy, 0, sizeof(copy));
00364             StrStrncpy(copy, string, sizeof(copy));
00365 
00366             /*
00367              * Normalize alphabetic dates to DD-MMM-YYYY, and numeric dates to
00368              * [D]D-MM-YYYY.  Characters are copied via individual assignments, 
00369              * this being assumed to be faster than copying via memcpy when the
00370              * call/return overhead is taken into account.
00371              */
00372 
00373             if ((copy[1] == '-')  && (copy[5] == '-')) {    /* D-MMM-YYYY */
00374                 strcpy(fulldt, "0");                
00375                 strlcat(fulldt + 1, copy, 11);
00376                 /* *(fulldt + 11) = '\0';  */
00377                 timeoff = 10;
00378                 alphadate = 1;
00379             }
00380             else if ((copy[1] == '-')  && (copy[4] == '-')) {   /* D-MM-YYYY */
00381                 strcpy(fulldt, "0");                
00382                 strlcat(fulldt + 1, copy, 10);
00383                 /* *(fulldt + 10) = '\0';  */
00384                 timeoff = 9;
00385                 alphadate = 0;
00386             }
00387             else if ((copy[2] == '-') && (copy[6] == '-')) {/* DD-MMM-YYYY */
00388                 strlcpy(fulldt, copy, 12);
00389                 /* *(fulldt + 11) = '\0'; */
00390                 timeoff = 11;
00391                 alphadate = 1;
00392             }
00393             else if ((copy[2] == '-')  && (copy[5] == '-')) {   /* DD-MM-YYYY */
00394                 strlcpy(fulldt, copy, 11);
00395                 /* *(fulldt + 10) = '\0';  */
00396                 timeoff = 10;
00397                 alphadate = 0;
00398             }
00399             else if ((copy[4] == '-') && (copy[8] == '-')) {/* YYYY-MMM-DD */
00400                 COPY2(copy, 9, fulldt, 0);
00401                 *(fulldt + 2) = '-';
00402                 COPY3(copy, 5, fulldt, 3);
00403                 *(fulldt + 6) = '-';
00404                 COPY4(copy, 0, fulldt, 7);
00405                 *(fulldt + 11) = '\0';  
00406                 timeoff = 11;
00407                 alphadate = 1;
00408             }
00409             else if ((copy[4] == '-')  && (copy[7] == '-')) {/* YYYY-MM-DD */
00410                 COPY2(copy, 8, fulldt, 0);
00411                 *(fulldt + 2) = '-';
00412                 COPY2(copy, 5, fulldt, 3);
00413                 *(fulldt + 5) = '-';
00414                 COPY4(copy, 0, fulldt, 6);
00415                 *(fulldt + 10) = '\0';
00416                 timeoff = 10;
00417                 alphadate = 0;
00418             }
00419             else {
00420                 status = 1;     /* Unrecognised format */
00421             }
00422 
00423             if (status == 0) {
00424 
00425                 /* Date OK, so process time part (if any). First set delimiter to space if it is ':' */
00426                                 if (copy[timeoff] == ':') {
00427                                         copy[timeoff] = ' ';
00428                                 }
00429 
00430                 status = DtAppendTime(fulldt, &copy[timeoff]);
00431                 if (status == 0) {
00432                     if (alphadate) {
00433                         ptr = strptime(fulldt, "%d-%b-%Y %H:%M:%S", datetime);
00434                     }
00435                     else {
00436                         ptr = strptime(fulldt, "%d-%m-%Y %H:%M:%S", datetime);
00437                     }
00438                     status = ptr ? 0 : 2;
00439                 }
00440             }
00441             else {
00442 
00443                 /* String is too short to be a valid date/time */
00444 
00445                 status = 3;
00446             }
00447         }
00448         else {
00449             status = 3;     /* Too short */
00450         }
00451     }
00452 
00453     return status;
00454 }
00455 
00456 
00457 /*+
00458  * DtGeneralString - Parse Date and Time
00459  *
00460  * Description:
00461  *      As DtGeneral, but returns the result in a string of the form
00462  *
00463  *          YYYY-MM-DD HH:MM:SS
00464  *
00465  *      ... which is suitable for ASCII input into MySql (after surrounding it
00466  *      with quotes).
00467  *
00468  * Arguments:
00469  *      const char* string (input)
00470  *          String to analyze.  This is known to be non-null and not all spaces.
00471  *
00472  * Returns:
00473  *      char*
00474  *          String of the form YYYY-MM-DD HH:MM:SS representing the date
00475  *          and time.  If NULL, there was some error.
00476  *
00477  *          The string should be freed via a call to StrFree.
00478 -*/
00479 
00480 char* DtGeneralString(const char* string)
00481 {
00482     struct tm   datetime;       /* Used for getting the date/time */
00483     char        buffer[KSM_TIME_LENGTH]; /* YYYY-MM-DD HH:MM:SS + NULL */
00484     char*       retval = NULL;  /* Returned string */
00485     int         status;         /* Status return */
00486 
00487     if (string == NULL) {
00488         return NULL;
00489     }
00490 
00491     status = DtGeneral(string, &datetime);
00492     if (status == 0) {
00493         snprintf(buffer, KSM_TIME_LENGTH, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
00494             datetime.tm_year + 1900, datetime.tm_mon + 1, datetime.tm_mday,
00495             datetime.tm_hour, datetime.tm_min, datetime.tm_sec);
00496         retval = StrStrdup(buffer);
00497     }
00498 
00499     return retval;
00500 }
00501 
00502 
00503 
00504 /*+
00505  * DtParseDateTime - Parse Date and Time
00506  *
00507  * Description:
00508  *      Date/times can be specified in one of several formats:
00509  *
00510  *          now
00511  *          YYYYMMDDHHMMSS
00512  *          YYYY-MM-DD HH:MM:SS
00513  *          DD-MMM-YYYY HH:MM:SS
00514  *          DD-MMM-YYYY:HH:MM:SS
00515  *          DD-MM-YYYY HH:MM:SS
00516  *          DD-MM-YYYY:HH:MM:SS
00517  *
00518  *      In the all strings, trailing time fields can be omitted and default to
00519  *      00:00:00 on the current day.
00520  *
00521  *          YYYY-MM-DD  Defaults to 00:00:00 on the day specified.
00522  *          YYYYMMDD    Defaults to 00:00:00 on the day specified.
00523  *          DD-MM-YYYY  Defaults to 00:00:00 on the day specified.
00524  *          YYYYMMDDHH  Defaults to 00:00:00 on the day specified.
00525  *          DD-MM-YYYY:HH Defaults to HH o'clock of the day specified
00526  *
00527  *      Also, leading DDs can be abbreviated to a single character.
00528  *
00529  *      The other specification is:
00530  *
00531  *          now         The date/time at which the command is executed
00532  *
00533  * Arguments:
00534  *      const char* string
00535  *          The input string to parse.
00536  *
00537  *      struct tm* datetime
00538  *          Output time/date
00539  *
00540  * Returns:
00541  *      int
00542  *          0   Success
00543  *          1   Parse error
00544 -*/
00545 
00546 int DtParseDateTime(const char* string, struct tm* datetime)
00547 {
00548     char*   buffer;     /* Duplicate of the string to parse */
00549     int     len;        /* Length of the string */
00550     int     status = 0; /* Return status */
00551     char*   text;       /* First non-blank character in duplicated string */
00552 
00553     /* Can only work if the string is non-null */
00554 
00555     if (string) {
00556 
00557         /* Normalise the string */
00558 
00559         buffer = StrStrdup(string);
00560         StrTrimR(buffer);
00561         text = StrTrimL(buffer);
00562         StrToLower(text);
00563 
00564         len = strlen(text);
00565         if (len != 0) {
00566 
00567             /* Something in the string, decide what to do */
00568 
00569             if (strcmp(text, "now") == 0) {
00570                 status = DtNow(datetime);
00571             }
00572             else {
00573                 status = DtGeneral(text, datetime);
00574             }
00575         }
00576         else {
00577 
00578             /* Nothing in the normalized string */
00579 
00580             status = 1;
00581         }
00582 
00583         /* Free up allocated memory */
00584 
00585         StrFree(buffer);
00586     }
00587     else {
00588 
00589         /* Passed pointer is NULL */
00590 
00591         status = 1;
00592     }
00593 
00594     return status;
00595 }
00596 
00597 
00598 /*+
00599  * DtParseDateTimeString - Parse Date And Time
00600  *
00601  * Description:
00602  *      As DtParseDateTime, but returns the result in a dynamically-allocated
00603  *      string.
00604  *
00605  * Arguments:
00606  *      const char* string (input)
00607  *          String to analyze.
00608  *
00609  * Returns:
00610  *      char*
00611  *          String of the form YYYY-MM-DD HH:MM:SS representing the date
00612  *          and time.  If NULL, there was some error.
00613  *
00614  *          The string should be freed via a call to StrFree.
00615 -*/
00616 
00617 char* DtParseDateTimeString(const char* string)
00618 {
00619     char    buffer[KSM_TIME_LENGTH]; /* Length of YYYY-MM-DD HH:MM:SS + NULL */
00620     struct  tm datetime;         /* Local date and time */
00621     char*   retval = NULL;      /* Result string */
00622     int     status;             /* Status return from called function */
00623 
00624     if (string && *string) {
00625         status = DtParseDateTime(string, &datetime);
00626         if (status == 0) {
00627             snprintf(buffer, KSM_TIME_LENGTH, 
00628                     "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
00629                     datetime.tm_year + 1900, datetime.tm_mon + 1, 
00630                     datetime.tm_mday, datetime.tm_hour, datetime.tm_min, 
00631                     datetime.tm_sec);
00632             retval = StrStrdup(buffer);
00633         }
00634     }
00635 
00636     return retval;
00637 }
00638 
00639 
00640 /*+
00641  * DtIntervalSeconds - Parse Interval String
00642  *
00643  * Description:
00644  *      Parses an interval string which is of the form:
00645  *
00646  *          <number>
00647  *      or  <number><interval-type>
00648  *
00649  *      Without an interval type, the interval is assumed to be in seconds.
00650  *      Otherwise, the following interval types recognised are:
00651  *
00652  *          s       Seconds
00653  *          m       Minutes - multiply number by 60 (no. seconds in a minute)
00654  *          h       Hours - multiple number by 3600 (no. seconds in an hour)
00655  *          d       Day - multiple number by 86400 (no. seconds in a day)
00656  *          w       Week - multiple number by 604,800 (no. seconds in a week)
00657  *
00658  *      Upper-case characters are not recognised.
00659  *
00660  *      Example: The string 2d would translate to 172,800
00661  *
00662  * Arguments:
00663  *      const char* text
00664  *          Interval as a string.
00665  *
00666  *      long* interval
00667  *          Returned interval.
00668  *
00669  * Returns:
00670  *      int
00671  *          0       Success, string translated OK
00672  *          1       Error - invalid interval-type
00673  *          2       Error - unable to translate string.
00674  *          3       Error - string too long to be a number.
00675  *          4       Error - invalid pointers or text string NULL.
00676 -*/
00677 
00678 int DtIntervalSeconds(const char* text, int* interval)
00679 {
00680     char    number[32];     /* Long enough for any number */
00681     int     status = 0;     /* Status return */
00682     int     length;         /* Lengthof the string */
00683     long    multiplier = 1; /* Multiplication factor */
00684 
00685     if (text && interval && *text) {
00686 
00687         /* Is there a multiplier? If so, interpret it. */
00688 
00689         length = strlen(text);
00690         if (isdigit(text[length - 1])) {
00691             multiplier = 1;     /* No, set the factor to 1 */
00692         }
00693         else {
00694             switch (text[length - 1]) {
00695             case 's':
00696                 multiplier = 1;
00697                 break;
00698 
00699             case 'm':
00700                 multiplier = 60;
00701                 break;
00702 
00703             case 'h':
00704                 multiplier = 60 * 60;
00705                 break;
00706 
00707             case 'd':
00708                 multiplier = 24 * 60 * 60;
00709                 break;
00710 
00711             case 'w':
00712                 multiplier = 7 * 24 * 60 * 60;
00713                 break;
00714 
00715             default:
00716                 status = 1;
00717             }
00718             --length;           /* Reduce bytes we are going to copy */
00719         }
00720 
00721         if (status == 0) {
00722 
00723             /* Copy all but the multiplier to the buffer for interpretation */
00724 
00725             if (length <= (long) (sizeof(number) - 1)) {
00726                 (void) memcpy(number, text, length);
00727                 number[length] = '\0';
00728                 status = StrStrtoi(number, interval);
00729                 if (status == 0) {
00730 
00731                     /* Successful, conversion, factor in the multiplier */
00732 
00733                     *interval *= multiplier;
00734                 }
00735                 else {
00736                     status = 2;     /* Can't translate string/overflow */
00737                 }
00738             }
00739             else {
00740 
00741                 /* String is too long to be a valid number */
00742 
00743                 status = 3;
00744             }
00745         }
00746     }
00747     else {
00748 
00749         /* Input pointers NULL or empty string */
00750 
00751         status = 4;
00752     }
00753 
00754     return status;
00755 }
00756 
00757 
00758 /*+
00759  * DtSecondsInterval - Convert Seconds to Interval
00760  *
00761  * Description:
00762  *      Given an interval in seconds, convert to an interval if possible.
00763  *      A suffix is added to indicate the result.
00764  *
00765  * Arguments:
00766  *      int interval
00767  *          Interval to convert.
00768  *
00769  *      char* text
00770  *          Converted text (possibly truncated) is placed here.  The buffer
00771  *          should be about 32 characters long (maximum).
00772  *
00773  *      size_t textlen
00774  *          Length of the buffer pointed to by "text".
00775 -*/
00776 
00777 void DtSecondsInterval(int interval, char* text, size_t textlen)
00778 {
00779     char    buffer[64];
00780 
00781     if (text && (textlen > 0)) {
00782         if (interval != 0) {
00783             if (interval % (60 * 60 * 24 * 7) == 0) {
00784                 snprintf(buffer, 64, "%dw", interval / (60 * 60 * 24 * 7));
00785             }
00786             else if (interval % (60 * 60 * 24) == 0) {
00787                 snprintf(buffer, 64,"%dd", interval / (60 * 60 * 24));
00788             }
00789             else if (interval % (60 * 60) == 0) {
00790                 snprintf(buffer, 64, "%dh", interval / (60 * 60));
00791             }
00792             else if (interval % 60 == 0) {
00793                 snprintf(buffer, 64, "%dm", interval / 60);
00794             }
00795             else {
00796                 snprintf(buffer, 64, "%ds", interval);
00797             }
00798         }
00799         else {
00800             strcpy(buffer, "0s");
00801         }
00802 
00803         StrStrncpy(text, buffer, textlen);
00804     }
00805 
00806     return;
00807 }
00808 
00809 
00810 /*+
00811  * DtDateDiff - Return Different in Dates
00812  *
00813  * Description:
00814  *      Returns the different between two dates as the number of seconds.
00815  *
00816  * Arguments:
00817  *      const char* date1, const char* date2
00818  *          Dates, given in the form "YYYY-MM-DD HH:MM:SS"
00819  *
00820  *      int* result
00821  *          Seconds between the two dates.
00822  *
00823  * Returns:
00824  *      int
00825  *          Status return.  0 => success, other => some error in the input.
00826 -*/
00827 
00828 int DtDateDiff(const char* date1, const char* date2, int* result)
00829 {
00830     static const char* FORMAT = "%Y-%m-%d %H:%M:%S";
00831     char*   cstatus;        /* Character status return */
00832     int     status;         /* Status return */
00833     struct tm tm1;          /* Converted first time */
00834     struct tm tm2;          /* Converted second time */
00835     time_t    t1;           /* First time as seconds */
00836     time_t    t2;           /* Second time as seconds */
00837 
00838     /* Do sanity check on the argument */
00839     if (result == NULL) {
00840         return 4;
00841     }
00842 
00843     if (date1 && *date1 && date2 && *date2) {
00844 
00845         /* Convert dates to struct tm */
00846 
00847         memset(&tm1, 0, sizeof(tm1));
00848         cstatus = strptime(date1, FORMAT, &tm1);
00849         if (cstatus) {
00850             memset(&tm2, 0, sizeof(tm2));
00851             cstatus = strptime(date2, FORMAT, &tm2);
00852             if (cstatus) {
00853 
00854                 /*
00855                  * tm1 and tm2 contain valid dates.  Convert to seconds since
00856                  * 1 Jan 1970.
00857                  */
00858 
00859                 t1 = mktime(&tm1);
00860                 t2 = mktime(&tm2);
00861                 *result = (int) (t1 - t2);
00862                 status = 0;
00863             }
00864             else {
00865                 status = 2;     /* Second date is invalid */
00866             }
00867         }
00868         else {
00869             status = 1;         /* First date is invalid */
00870         }
00871     }
00872     else {
00873         status = 3;             /* One or both dates are NULL or empty */
00874     }
00875 
00876     return status;
00877 }
00878 
00879 /*+
00880  * DtXMLIntervalSeconds - Parse xsd:durations Interval String
00881  *
00882  * Description:
00883  *      Parses an interval string which is of the form:
00884  *
00885  *          P<number>
00886  *      or  P<number><interval-type>
00887  *      or  PT<number><interval-type> (if the interval-type is H, M or S)
00888  *
00889  *      Without an interval type, the interval is assumed to be in seconds.
00890  *      Otherwise, the following interval types recognised are:
00891  *
00892  *          S       Seconds
00893  *          M       Minutes - multiply number by 60 (no. seconds in a minute)
00894  *          H       Hours - multiply number by 3600 (no. seconds in an hour)
00895  *          D       Day - multiply number by 86400 (no. seconds in a day)
00896  *          W       Week - multiply number by 604,800 (no. seconds in a week)
00897  *          M       Month - multiply number by 2,678,400 (no. seconds in 31 days)
00898  *          Y       Year - multiply number by 31,536,000 (no. seconds in 365 days)
00899  *
00900  *      Lower-case characters are not recognised.
00901  *
00902  *      Example: The string P2D would translate to 172,800
00903  *
00904  * Arguments:
00905  *      const char* text
00906  *          Interval as a string.
00907  *
00908  *      long* interval
00909  *          Returned interval.
00910  *
00911  * Returns:
00912  *      int
00913  *         -1       Success, string translated OK _BUT_ may not be what was expected
00914  *                          (Year or Month used which gives approximate answer).
00915  *          0       Success, string translated OK
00916  *          2       Error - unable to translate string.
00917  *          3       Error - string too long to be a number.
00918  *          4       Error - invalid pointers or text string NULL.
00919  *
00920  * Known issues:
00921  * 
00922  *      1. Years and months are only approximate as it has no concept of "now"
00923  *         We use 30 days = 1 month and 365 days = 1 year.
00924  *      2. The "T" only effects the value of "M" (P1S should be illegal as correctly
00925  *         it would be PT1S)
00926 -*/
00927 
00928 int DtXMLIntervalSeconds(const char* text, int* interval)
00929 {
00930     int     length = 0;         /* Length of the string */
00931     short   is_time = 0;    /* Do we have a Time section or not */
00932     short   is_neg = 0;    /* Do we have a negative number */
00933     short   warning = 0;    /* Do we need a warning code for duration approximation? */
00934     short   got_temp = 0;    /* Have we seen a number? */
00935     long long    temp = 0;       /* Number from this section */
00936     const char  *ptr = text;    /* allow us to read through */
00937 
00938     int status = 0;
00939 
00940     long long temp_interval = 0;
00941 
00942     if (text && interval && *text) {
00943         length = strlen(text);
00944     } else {
00945         return(4);
00946     }
00947 
00948     if (ptr && length && interval) {
00949         const char *end = text + length;
00950         if (*ptr == '-') {
00951             is_neg = 1;
00952             ptr++;
00953         }
00954         if (*ptr == 'P') {
00955             ptr++;
00956         }
00957         do {
00958             switch (*ptr) {
00959                 case 'S':
00960                     if (got_temp) {
00961                         temp_interval += temp;
00962                         temp = 0;
00963                         got_temp = 0;
00964                     } else {
00965                         return(2);
00966                     }
00967                     break;
00968 
00969                 case 'M':
00970                     if (got_temp) {
00971                         if (is_time) {
00972                             temp_interval += 60 * temp;
00973                         } else {
00974                             temp_interval += 31 * 24 * 60 * 60 * temp;
00975                             warning = 1;
00976                         }
00977                         temp = 0;
00978                         got_temp = 0;
00979                     } else {
00980                         return(2);
00981                     }
00982                     break;
00983 
00984                 case 'H':
00985                     if (got_temp) {
00986                         temp_interval += 60 * 60 * temp;
00987                         temp = 0;
00988                         got_temp = 0;
00989                     } else {
00990                         return(2);
00991                     }
00992                     break;
00993 
00994                 case 'D':
00995                     if (got_temp) {
00996                         temp_interval += 24 * 60 * 60 * temp;
00997                         temp = 0;
00998                         got_temp = 0;
00999                     } else {
01000                         return(2);
01001                     }
01002                     break;
01003 
01004                 case 'W':
01005                     if (got_temp) {
01006                         temp_interval += 7 * 24 * 60 * 60 * temp;
01007                         temp = 0;
01008                         got_temp = 0;
01009                     } else {
01010                         return(2);
01011                     }
01012                     break;
01013 
01014                 case 'Y':
01015                     if (got_temp) {
01016                         temp_interval += 365 * 24 * 60 * 60 * temp;
01017                         temp = 0;
01018                         warning = 1;
01019                         got_temp = 0;
01020                     } else {
01021                         return(2);
01022                     }
01023                     break;
01024 
01025                 case 'T':
01026                     is_time = 1;
01027                     break;
01028 
01029                 case '0':
01030                 case '1':
01031                 case '2':
01032                 case '3':
01033                 case '4':
01034                 case '5':
01035                 case '6':
01036                 case '7':
01037                 case '8':
01038                 case '9':
01039                     if (!temp) {
01040                         temp = atoll(ptr);
01041                         got_temp = 1;
01042                         if ((temp_interval <= INT_MIN) || (temp_interval >= INT_MAX)) {
01043                             return(3);
01044                         }
01045                     }
01046                     break;
01047 
01048                 default:
01049                     if (ptr != end) {
01050                         return(2);
01051                     }
01052             }
01053         } while (ptr++ < end);
01054     }
01055     else {
01056         status = 2;     /* Can't translate string/overflow */
01057     }
01058 
01059     /* If we had no trailing letter then it is an implicit "S" */
01060     if (temp) {
01061         temp_interval += temp;
01062         temp = 0;
01063     }
01064 
01065     if (is_neg == 1) {
01066         temp_interval = 0 - temp_interval;
01067     }
01068 
01069     if (warning == 1) {
01070         status = -1;
01071     }
01072 
01073     if ((temp_interval >= INT_MIN) && (temp_interval <= INT_MAX)) {
01074         *interval = (int) temp_interval;
01075     }
01076     else {
01077         status = 3;     /* Integer overflow */
01078     }
01079 
01080     return status;
01081 }

Generated on Mon Oct 31 2011 14:38:30 for OpenDNSSEC-enforcer by  doxygen 1.7.1