ptimes.c (398faf12050b17c407eb9db71cb67166cdb43aff) | ptimes.c (2f8d7c56da1ce2c5069fab78876cc6a90b343cfa) |
---|---|
1/*- 2 * ------+---------+---------+---------+---------+---------+---------+---------* 3 * Initial version of parse8601 was originally added to newsyslog.c in 4 * FreeBSD on Jan 22, 1999 by Garrett Wollman <wollman@FreeBSD.org>. 5 * Initial version of parseDWM was originally added to newsyslog.c in 6 * FreeBSD on Apr 4, 2000 by Hellmuth Michaelis <hm@FreeBSD.org>. 7 * 8 * Copyright (c) 2003 - Garance Alistair Drosehn <gad@FreeBSD.org>. --- 20 unchanged lines hidden (view full) --- 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * The views and conclusions contained in the software and documentation 33 * are those of the authors and should not be interpreted as representing 34 * official policies, either expressed or implied, of the FreeBSD Project. 35 * 36 * ------+---------+---------+---------+---------+---------+---------+---------* | 1/*- 2 * ------+---------+---------+---------+---------+---------+---------+---------* 3 * Initial version of parse8601 was originally added to newsyslog.c in 4 * FreeBSD on Jan 22, 1999 by Garrett Wollman <wollman@FreeBSD.org>. 5 * Initial version of parseDWM was originally added to newsyslog.c in 6 * FreeBSD on Apr 4, 2000 by Hellmuth Michaelis <hm@FreeBSD.org>. 7 * 8 * Copyright (c) 2003 - Garance Alistair Drosehn <gad@FreeBSD.org>. --- 20 unchanged lines hidden (view full) --- 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * The views and conclusions contained in the software and documentation 33 * are those of the authors and should not be interpreted as representing 34 * official policies, either expressed or implied, of the FreeBSD Project. 35 * 36 * ------+---------+---------+---------+---------+---------+---------+---------* |
37 * This is intended to be a set of general-purpose routines to process times. 38 * Right now it probably still has a number of assumptions in it, such that 39 * it works fine for newsyslog but might not work for other uses. 40 * ------+---------+---------+---------+---------+---------+---------+---------* | |
41 */ 42 43#include <sys/cdefs.h> 44__FBSDID("$FreeBSD$"); 45 46#include <ctype.h> 47#include <limits.h> 48#include <stdio.h> | 37 */ 38 39#include <sys/cdefs.h> 40__FBSDID("$FreeBSD$"); 41 42#include <ctype.h> 43#include <limits.h> 44#include <stdio.h> |
45#include <stdint.h> |
|
49#include <stdlib.h> | 46#include <stdlib.h> |
50#include <string.h> | |
51#include <time.h> 52 53#include "extern.h" 54 | 47#include <time.h> 48 49#include "extern.h" 50 |
55#define SECS_PER_HOUR 3600 56 57/* 58 * Bit-values which indicate which components of time were specified 59 * by the string given to parse8601 or parseDWM. These are needed to 60 * calculate what time-in-the-future will match that string. 61 */ 62#define TSPEC_YEAR 0x0001 63#define TSPEC_MONTHOFYEAR 0x0002 64#define TSPEC_LDAYOFMONTH 0x0004 65#define TSPEC_DAYOFMONTH 0x0008 66#define TSPEC_DAYOFWEEK 0x0010 67#define TSPEC_HOUROFDAY 0x0020 68 69#define TNYET_ADJ4DST -10 /* DST has "not yet" been adjusted */ 70 71struct ptime_data { 72 time_t basesecs; /* Base point for relative times */ 73 time_t tsecs; /* Time in seconds */ 74 struct tm basetm; /* Base Time expanded into fields */ 75 struct tm tm; /* Time expanded into fields */ 76 int did_adj4dst; /* Track calls to ptime_adjust4dst */ 77 int parseopts; /* Options given for parsing */ 78 int tmspec; /* Indicates which time fields had 79 * been specified by the user */ 80}; 81 82static int days_pmonth(int month, int year); 83static int parse8601(struct ptime_data *ptime, const char *str); 84static int parseDWM(struct ptime_data *ptime, const char *str); 85 86/* 87 * Simple routine to calculate the number of days in a given month. 88 */ 89static int 90days_pmonth(int month, int year) 91{ 92 static const int mtab[] = {31, 28, 31, 30, 31, 30, 31, 31, 93 30, 31, 30, 31}; 94 int ndays; 95 96 ndays = mtab[month]; 97 98 if (month == 1) { 99 /* 100 * We are usually called with a 'tm-year' value 101 * (ie, the value = the number of years past 1900). 102 */ 103 if (year < 1900) 104 year += 1900; 105 if (year % 4 == 0) { 106 /* 107 * This is a leap year, as long as it is not a 108 * multiple of 100, or if it is a multiple of 109 * both 100 and 400. 110 */ 111 if (year % 100 != 0) 112 ndays++; /* not multiple of 100 */ 113 else if (year % 400 == 0) 114 ndays++; /* is multiple of 100 and 400 */ 115 } 116 } 117 return (ndays); 118} 119 | |
120/*- 121 * Parse a limited subset of ISO 8601. The specific format is as follows: 122 * 123 * [CC[YY[MM[DD]]]][THH[MM[SS]]] (where `T' is the literal letter) 124 * 125 * We don't accept a timezone specification; missing fields (including timezone) 126 * are defaulted to the current date but time zero. 127 */ | 51/*- 52 * Parse a limited subset of ISO 8601. The specific format is as follows: 53 * 54 * [CC[YY[MM[DD]]]][THH[MM[SS]]] (where `T' is the literal letter) 55 * 56 * We don't accept a timezone specification; missing fields (including timezone) 57 * are defaulted to the current date but time zero. 58 */ |
128static int 129parse8601(struct ptime_data *ptime, const char *s) | 59time_t 60parse8601(const char *s, time_t *next_time) |
130{ 131 char *t; | 61{ 62 char *t; |
63 time_t tsecs; 64 struct tm tm, *tmp; |
|
132 long l; | 65 long l; |
133 struct tm tm; | |
134 | 66 |
67 tmp = localtime(&timenow); 68 tm = *tmp; 69 if (next_time != NULL) 70 *next_time = (time_t)-1; 71 72 tm.tm_hour = tm.tm_min = tm.tm_sec = 0; 73 |
|
135 l = strtol(s, &t, 10); 136 if (l < 0 || l >= INT_MAX || (*t != '\0' && *t != 'T')) 137 return (-1); 138 139 /* 140 * Now t points either to the end of the string (if no time was 141 * provided) or to the letter `T' which separates date and time in 142 * ISO 8601. The pointer arithmetic is the same for either case. 143 */ | 74 l = strtol(s, &t, 10); 75 if (l < 0 || l >= INT_MAX || (*t != '\0' && *t != 'T')) 76 return (-1); 77 78 /* 79 * Now t points either to the end of the string (if no time was 80 * provided) or to the letter `T' which separates date and time in 81 * ISO 8601. The pointer arithmetic is the same for either case. 82 */ |
144 tm = ptime->tm; 145 ptime->tmspec = TSPEC_HOUROFDAY; | |
146 switch (t - s) { 147 case 8: 148 tm.tm_year = ((l / 1000000) - 19) * 100; 149 l = l % 1000000; 150 case 6: | 83 switch (t - s) { 84 case 8: 85 tm.tm_year = ((l / 1000000) - 19) * 100; 86 l = l % 1000000; 87 case 6: |
151 ptime->tmspec |= TSPEC_YEAR; | |
152 tm.tm_year -= tm.tm_year % 100; 153 tm.tm_year += l / 10000; 154 l = l % 10000; 155 case 4: | 88 tm.tm_year -= tm.tm_year % 100; 89 tm.tm_year += l / 10000; 90 l = l % 10000; 91 case 4: |
156 ptime->tmspec |= TSPEC_MONTHOFYEAR; | |
157 tm.tm_mon = (l / 100) - 1; 158 l = l % 100; 159 case 2: | 92 tm.tm_mon = (l / 100) - 1; 93 l = l % 100; 94 case 2: |
160 ptime->tmspec |= TSPEC_DAYOFMONTH; | |
161 tm.tm_mday = l; 162 case 0: 163 break; 164 default: 165 return (-1); 166 } 167 168 /* sanity check */ --- 10 unchanged lines hidden (view full) --- 179 switch (t - s) { 180 case 6: 181 tm.tm_sec = l % 100; 182 l /= 100; 183 case 4: 184 tm.tm_min = l % 100; 185 l /= 100; 186 case 2: | 95 tm.tm_mday = l; 96 case 0: 97 break; 98 default: 99 return (-1); 100 } 101 102 /* sanity check */ --- 10 unchanged lines hidden (view full) --- 113 switch (t - s) { 114 case 6: 115 tm.tm_sec = l % 100; 116 l /= 100; 117 case 4: 118 tm.tm_min = l % 100; 119 l /= 100; 120 case 2: |
187 ptime->tmspec |= TSPEC_HOUROFDAY; | |
188 tm.tm_hour = l; 189 case 0: 190 break; 191 default: 192 return (-1); 193 } 194 195 /* sanity check */ 196 if (tm.tm_sec < 0 || tm.tm_sec > 60 || tm.tm_min < 0 197 || tm.tm_min > 59 || tm.tm_hour < 0 || tm.tm_hour > 23) 198 return (-1); 199 } 200 | 121 tm.tm_hour = l; 122 case 0: 123 break; 124 default: 125 return (-1); 126 } 127 128 /* sanity check */ 129 if (tm.tm_sec < 0 || tm.tm_sec > 60 || tm.tm_min < 0 130 || tm.tm_min > 59 || tm.tm_hour < 0 || tm.tm_hour > 23) 131 return (-1); 132 } 133 |
201 ptime->tm = tm; 202 return (0); | 134 tsecs = mktime(&tm); 135 /* 136 * Check for invalid times, including things like the missing 137 * hour when switching from "standard time" to "daylight saving". 138 */ 139 if (tsecs == (time_t)-1) 140 tsecs = (time_t)-2; 141 return (tsecs); |
203} 204 205/*- 206 * Parse a cyclic time specification, the format is as follows: 207 * 208 * [Dhh] or [Wd[Dhh]] or [Mdd[Dhh]] 209 * 210 * to rotate a logfile cyclic at 211 * 212 * - every day (D) within a specific hour (hh) (hh = 0...23) 213 * - once a week (W) at a specific day (d) OR (d = 0..6, 0 = Sunday) 214 * - once a month (M) at a specific day (d) (d = 1..31,l|L) 215 * 216 * We don't accept a timezone specification; missing fields 217 * are defaulted to the current date but time zero. 218 */ | 142} 143 144/*- 145 * Parse a cyclic time specification, the format is as follows: 146 * 147 * [Dhh] or [Wd[Dhh]] or [Mdd[Dhh]] 148 * 149 * to rotate a logfile cyclic at 150 * 151 * - every day (D) within a specific hour (hh) (hh = 0...23) 152 * - once a week (W) at a specific day (d) OR (d = 0..6, 0 = Sunday) 153 * - once a month (M) at a specific day (d) (d = 1..31,l|L) 154 * 155 * We don't accept a timezone specification; missing fields 156 * are defaulted to the current date but time zero. 157 */ |
219static int 220parseDWM(struct ptime_data *ptime, const char *s) | 158time_t 159parseDWM(char *s, time_t *next_time) |
221{ | 160{ |
222 int daysmon, Dseen, WMseen; 223 const char *endval; 224 char *tmp; | 161 char *t; 162 time_t tsecs; 163 struct tm tm, *tmp; |
225 long l; | 164 long l; |
226 struct tm tm; | 165 int nd; 166 static int mtab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 167 int WMseen = 0; 168 int Dseen = 0; |
227 | 169 |
228 /* Save away the number of days in this month */ 229 tm = ptime->tm; 230 daysmon = days_pmonth(tm.tm_mon, tm.tm_year); | 170 tmp = localtime(&timenow); 171 tm = *tmp; 172 if (next_time != NULL) 173 *next_time = (time_t)-1; |
231 | 174 |
232 WMseen = Dseen = 0; 233 ptime->tmspec = TSPEC_HOUROFDAY; | 175 /* set no. of days per month */ 176 177 nd = mtab[tm.tm_mon]; 178 179 if (tm.tm_mon == 1) { 180 if (((tm.tm_year + 1900) % 4 == 0) && 181 ((tm.tm_year + 1900) % 100 != 0) && 182 ((tm.tm_year + 1900) % 400 == 0)) { 183 nd++; /* leap year, 29 days in february */ 184 } 185 } 186 tm.tm_hour = tm.tm_min = tm.tm_sec = 0; 187 |
234 for (;;) { | 188 for (;;) { |
235 endval = NULL; | |
236 switch (*s) { 237 case 'D': 238 if (Dseen) 239 return (-1); 240 Dseen++; | 189 switch (*s) { 190 case 'D': 191 if (Dseen) 192 return (-1); 193 Dseen++; |
241 ptime->tmspec |= TSPEC_HOUROFDAY; | |
242 s++; | 194 s++; |
243 l = strtol(s, &tmp, 10); | 195 l = strtol(s, &t, 10); |
244 if (l < 0 || l > 23) 245 return (-1); | 196 if (l < 0 || l > 23) 197 return (-1); |
246 endval = tmp; | |
247 tm.tm_hour = l; 248 break; 249 250 case 'W': 251 if (WMseen) 252 return (-1); 253 WMseen++; | 198 tm.tm_hour = l; 199 break; 200 201 case 'W': 202 if (WMseen) 203 return (-1); 204 WMseen++; |
254 ptime->tmspec |= TSPEC_DAYOFWEEK; | |
255 s++; | 205 s++; |
256 l = strtol(s, &tmp, 10); | 206 l = strtol(s, &t, 10); |
257 if (l < 0 || l > 6) 258 return (-1); | 207 if (l < 0 || l > 6) 208 return (-1); |
259 endval = tmp; | |
260 if (l != tm.tm_wday) { 261 int save; 262 263 if (l < tm.tm_wday) { 264 save = 6 - tm.tm_wday; 265 save += (l + 1); 266 } else { 267 save = l - tm.tm_wday; 268 } 269 270 tm.tm_mday += save; 271 | 209 if (l != tm.tm_wday) { 210 int save; 211 212 if (l < tm.tm_wday) { 213 save = 6 - tm.tm_wday; 214 save += (l + 1); 215 } else { 216 save = l - tm.tm_wday; 217 } 218 219 tm.tm_mday += save; 220 |
272 if (tm.tm_mday > daysmon) { | 221 if (tm.tm_mday > nd) { |
273 tm.tm_mon++; | 222 tm.tm_mon++; |
274 tm.tm_mday = tm.tm_mday - daysmon; | 223 tm.tm_mday = tm.tm_mday - nd; |
275 } 276 } 277 break; 278 279 case 'M': 280 if (WMseen) 281 return (-1); 282 WMseen++; | 224 } 225 } 226 break; 227 228 case 'M': 229 if (WMseen) 230 return (-1); 231 WMseen++; |
283 ptime->tmspec |= TSPEC_DAYOFMONTH; | |
284 s++; 285 if (tolower(*s) == 'l') { | 232 s++; 233 if (tolower(*s) == 'l') { |
286 /* User wants the last day of the month. */ 287 ptime->tmspec |= TSPEC_LDAYOFMONTH; 288 tm.tm_mday = daysmon; 289 endval = s + 1; | 234 tm.tm_mday = nd; 235 s++; 236 t = s; |
290 } else { | 237 } else { |
291 l = strtol(s, &tmp, 10); | 238 l = strtol(s, &t, 10); |
292 if (l < 1 || l > 31) 293 return (-1); 294 | 239 if (l < 1 || l > 31) 240 return (-1); 241 |
295 if (l > daysmon) | 242 if (l > nd) |
296 return (-1); | 243 return (-1); |
297 endval = tmp; | |
298 tm.tm_mday = l; 299 } 300 break; 301 302 default: 303 return (-1); 304 break; 305 } 306 | 244 tm.tm_mday = l; 245 } 246 break; 247 248 default: 249 return (-1); 250 break; 251 } 252 |
307 if (endval == NULL) 308 return (-1); 309 else if (*endval == '\0' || isspace(*endval)) | 253 if (*t == '\0' || isspace(*t)) |
310 break; 311 else | 254 break; 255 else |
312 s = endval; | 256 s = t; |
313 } 314 | 257 } 258 |
315 ptime->tm = tm; 316 return (0); 317} 318 319/* 320 * Initialize a new ptime-related data area. 321 */ 322struct ptime_data * 323ptime_init(const struct ptime_data *optsrc) 324{ 325 struct ptime_data *newdata; 326 327 newdata = malloc(sizeof(struct ptime_data)); 328 if (optsrc != NULL) { 329 memcpy(newdata, optsrc, sizeof(struct ptime_data)); 330 } else { 331 memset(newdata, '\0', sizeof(struct ptime_data)); 332 newdata->did_adj4dst = TNYET_ADJ4DST; 333 } 334 335 return (newdata); 336} 337 338/* 339 * Adjust a given time if that time is in a different timezone than 340 * some other time. 341 */ 342int 343ptime_adjust4dst(struct ptime_data *ptime, const struct ptime_data *dstsrc) 344{ 345 struct ptime_data adjtime; 346 347 if (ptime == NULL) 348 return (-1); 349 | 259 tsecs = mktime(&tm); |
350 /* | 260 /* |
351 * Changes are not made to the given time until after all 352 * of the calculations have been successful. | 261 * Check for invalid times, including things like the missing 262 * hour when switching from "standard time" to "daylight saving". |
353 */ | 263 */ |
354 adjtime = *ptime; 355 356 /* Check to see if this adjustment was already made */ 357 if ((adjtime.did_adj4dst != TNYET_ADJ4DST) && 358 (adjtime.did_adj4dst == dstsrc->tm.tm_isdst)) 359 return (0); /* yes, so don't make it twice */ 360 361 /* See if daylight-saving has changed between the two times. */ 362 if (dstsrc->tm.tm_isdst != adjtime.tm.tm_isdst) { 363 if (adjtime.tm.tm_isdst == 1) 364 adjtime.tsecs -= SECS_PER_HOUR; 365 else if (adjtime.tm.tm_isdst == 0) 366 adjtime.tsecs += SECS_PER_HOUR; 367 adjtime.tm = *(localtime(&adjtime.tsecs)); 368 /* Remember that this adjustment has been made */ 369 adjtime.did_adj4dst = dstsrc->tm.tm_isdst; 370 /* 371 * XXX - Should probably check to see if changing the 372 * hour also changed the value of is_dst. What 373 * should we do in that case? 374 */ 375 } 376 377 *ptime = adjtime; 378 return (0); | 264 if (tsecs == (time_t)-1) 265 tsecs = (time_t)-2; 266 return (tsecs); |
379} | 267} |
380 381int 382ptime_relparse(struct ptime_data *ptime, int parseopts, time_t basetime, 383 const char *str) 384{ 385 int dpm, pres; 386 struct tm temp_tm; 387 388 ptime->parseopts = parseopts; 389 ptime->basesecs = basetime; 390 ptime->basetm = *(localtime(&ptime->basesecs)); 391 ptime->tm = ptime->basetm; 392 ptime->tm.tm_hour = ptime->tm.tm_min = ptime->tm.tm_sec = 0; 393 394 /* 395 * Call a routine which sets ptime.tm and ptime.tspecs based 396 * on the given string and parsing-options. Note that the 397 * routine should not call mktime to set ptime.tsecs. 398 */ 399 if (parseopts & PTM_PARSE_DWM) 400 pres = parseDWM(ptime, str); 401 else 402 pres = parse8601(ptime, str); 403 if (pres < 0) { 404 ptime->tsecs = (time_t)pres; 405 return (pres); 406 } 407 408 /* 409 * Before calling mktime, check to see if we ended up with a 410 * "day-of-month" that does not exist in the selected month. 411 * If we did call mktime with that info, then mktime will 412 * make it look like the user specifically requested a day 413 * in the following month (eg: Feb 31 turns into Mar 3rd). 414 */ 415 dpm = days_pmonth(ptime->tm.tm_mon, ptime->tm.tm_year); 416 if ((parseopts & PTM_PARSE_MATCHDOM) && 417 (ptime->tmspec & TSPEC_DAYOFMONTH) && 418 (ptime->tm.tm_mday> dpm)) { 419 /* 420 * ptime_nxtime() will want a ptime->tsecs value, 421 * but we need to avoid mktime resetting all the 422 * ptime->tm values. 423 */ 424 if (verbose && dbg_at_times > 1) 425 fprintf(stderr, 426 "\t-- dom fixed: %4d/%02d/%02d %02d:%02d (%02d)", 427 ptime->tm.tm_year, ptime->tm.tm_mon, 428 ptime->tm.tm_mday, ptime->tm.tm_hour, 429 ptime->tm.tm_min, dpm); 430 temp_tm = ptime->tm; 431 ptime->tsecs = mktime(&temp_tm); 432 if (ptime->tsecs > (time_t)-1) 433 ptimeset_nxtime(ptime); 434 if (verbose && dbg_at_times > 1) 435 fprintf(stderr, 436 " to: %4d/%02d/%02d %02d:%02d\n", 437 ptime->tm.tm_year, ptime->tm.tm_mon, 438 ptime->tm.tm_mday, ptime->tm.tm_hour, 439 ptime->tm.tm_min); 440 } 441 442 /* 443 * Convert the ptime.tm into standard time_t seconds. Check 444 * for invalid times, which includes things like the hour lost 445 * when switching from "standard time" to "daylight saving". 446 */ 447 ptime->tsecs = mktime(&ptime->tm); 448 if (ptime->tsecs == (time_t)-1) { 449 ptime->tsecs = (time_t)-2; 450 return (-2); 451 } 452 453 return (0); 454} 455 456int 457ptime_free(struct ptime_data *ptime) 458{ 459 460 if (ptime == NULL) 461 return (-1); 462 463 free(ptime); 464 return (0); 465} 466 467/* 468 * Some trivial routines so ptime_data can remain a completely 469 * opaque type. 470 */ 471const char * 472ptimeget_ctime(const struct ptime_data *ptime) 473{ 474 475 if (ptime == NULL) 476 return ("Null time in ptimeget_ctime()\n"); 477 478 return (ctime(&ptime->tsecs)); 479} 480 481double 482ptimeget_diff(const struct ptime_data *minuend, const struct 483 ptime_data *subtrahend) 484{ 485 486 /* Just like difftime(), we have no good error-return */ 487 if (minuend == NULL || subtrahend == NULL) 488 return (0.0); 489 490 return (difftime(minuend->tsecs, subtrahend->tsecs)); 491} 492 493time_t 494ptimeget_secs(const struct ptime_data *ptime) 495{ 496 497 if (ptime == NULL) 498 return (-1); 499 500 return (ptime->tsecs); 501} 502 503/* 504 * Generate an approximate timestamp for the next event, based on 505 * what parts of time were specified by the original parameter to 506 * ptime_relparse(). The result may be -1 if there is no obvious 507 * "next time" which will work. 508 */ 509int 510ptimeset_nxtime(struct ptime_data *ptime) 511{ 512 int moredays, tdpm, tmon, tyear; 513 struct ptime_data nextmatch; 514 515 if (ptime == NULL) 516 return (-1); 517 518 /* 519 * Changes are not made to the given time until after all 520 * of the calculations have been successful. 521 */ 522 nextmatch = *ptime; 523 /* 524 * If the user specified a year and we're already past that 525 * time, then there will never be another one! 526 */ 527 if (ptime->tmspec & TSPEC_YEAR) 528 return (-1); 529 530 /* 531 * The caller gave us a time in the past. Calculate how much 532 * time is needed to go from that valid rotate time to the 533 * next valid rotate time. We only need to get to the nearest 534 * hour, because newsyslog is only run once per hour. 535 */ 536 moredays = 0; 537 if (ptime->tmspec & TSPEC_MONTHOFYEAR) { 538 /* Special case: Feb 29th does not happen every year. */ 539 if (ptime->tm.tm_mon == 1 && ptime->tm.tm_mday == 29) { 540 nextmatch.tm.tm_year += 4; 541 if (days_pmonth(1, nextmatch.tm.tm_year) < 29) 542 nextmatch.tm.tm_year += 4; 543 } else { 544 nextmatch.tm.tm_year += 1; 545 } 546 nextmatch.tm.tm_isdst = -1; 547 nextmatch.tsecs = mktime(&nextmatch.tm); 548 549 } else if (ptime->tmspec & TSPEC_LDAYOFMONTH) { 550 /* 551 * Need to get to the last day of next month. Origtm is 552 * already at the last day of this month, so just add to 553 * it number of days in the next month. 554 */ 555 if (ptime->tm.tm_mon < 11) 556 moredays = days_pmonth(ptime->tm.tm_mon + 1, 557 ptime->tm.tm_year); 558 else 559 moredays = days_pmonth(0, ptime->tm.tm_year + 1); 560 561 } else if (ptime->tmspec & TSPEC_DAYOFMONTH) { 562 /* Jump to the same day in the next month */ 563 moredays = days_pmonth(ptime->tm.tm_mon, ptime->tm.tm_year); 564 /* 565 * In some cases, the next month may not *have* the 566 * desired day-of-the-month. If that happens, then 567 * move to the next month that does have enough days. 568 */ 569 tmon = ptime->tm.tm_mon; 570 tyear = ptime->tm.tm_year; 571 for (;;) { 572 if (tmon < 11) 573 tmon += 1; 574 else { 575 tmon = 0; 576 tyear += 1; 577 } 578 tdpm = days_pmonth(tmon, tyear); 579 if (tdpm >= ptime->tm.tm_mday) 580 break; 581 moredays += tdpm; 582 } 583 584 } else if (ptime->tmspec & TSPEC_DAYOFWEEK) { 585 moredays = 7; 586 } else if (ptime->tmspec & TSPEC_HOUROFDAY) { 587 moredays = 1; 588 } 589 590 if (moredays != 0) { 591 nextmatch.tsecs += SECS_PER_HOUR * 24 * moredays; 592 nextmatch.tm = *(localtime(&nextmatch.tsecs)); 593 } 594 595 /* 596 * The new time will need to be adjusted if the setting of 597 * daylight-saving has changed between the two times. 598 */ 599 ptime_adjust4dst(&nextmatch, ptime); 600 601 /* Everything worked. Update the given time and return. */ 602 *ptime = nextmatch; 603 return (0); 604} 605 606int 607ptimeset_time(struct ptime_data *ptime, time_t secs) 608{ 609 610 if (ptime == NULL) 611 return (-1); 612 613 ptime->tsecs = secs; 614 ptime->tm = *(localtime(&ptime->tsecs)); 615 ptime->parseopts = 0; 616 /* ptime->tmspec = ? */ 617 return (0); 618} | |