OpenDNSSEC-enforcer 1.3.0
|
00001 /* 00002 * $Id: datetime.c 5320 2011-07-12 10:42:26Z jakob $ 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, ©[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 }