*************** *** 121,126 **** exit_cleanup(RERR_MALLOC); } int set_modtime(char *fname, time_t modtime, mode_t mode) { #if !defined HAVE_LUTIMES || !defined HAVE_UTIMES --- 121,253 ---- exit_cleanup(RERR_MALLOC); } + /* Allow the user to specify a time in the format yyyy-mm-ddThh:mm while + * also allowing abbreviated data. For instance, if the time is omitted, + * it defaults to midnight. If the date is omitted, it defaults to the + * next possible date in the future with the specified time. Even the + * year or year-month can be omitted, again defaulting to the next date + * in the future that matches the specified information. A 2-digit year + * is also OK, as is using '/' instead of '-'. */ + time_t parse_time(const char *arg) + { + const char *cp; + time_t val, now = time(NULL); + struct tm t, *today = localtime(&now); + int in_date, n; + + memset(&t, 0, sizeof t); + t.tm_year = t.tm_mon = t.tm_mday = -1; + t.tm_hour = t.tm_min = t.tm_isdst = -1; + cp = arg; + if (*cp == 'T' || *cp == 't' || *cp == ':') { + cp++; + in_date = 0; + } else + in_date = 1; + for ( ; ; cp++) { + if (!isdigit(*cp)) + return -1; + + n = 0; + do { + n = n * 10 + *cp++ - '0'; + } while (isdigit(*cp)); + + if (*cp == ':') + in_date = 0; + if (in_date) { + if (t.tm_year != -1) + return -1; + t.tm_year = t.tm_mon; + t.tm_mon = t.tm_mday; + t.tm_mday = n; + if (!*cp) + break; + if (*cp == 'T' || *cp == 't') { + if (!cp[1]) + break; + in_date = 0; + } else if (*cp != '-' && *cp != '/') + return -1; + continue; + } + if (t.tm_hour != -1) + return -1; + t.tm_hour = t.tm_min; + t.tm_min = n; + if (!*cp) + break; + if (*cp != ':') + return -1; + } + + in_date = 0; + if (t.tm_year < 0) { + t.tm_year = today->tm_year; + in_date = 1; + } else if (t.tm_year < 100) { + while (t.tm_year < today->tm_year) + t.tm_year += 100; + } else + t.tm_year -= 1900; + if (t.tm_mon < 0) { + t.tm_mon = today->tm_mon; + in_date = 2; + } else + t.tm_mon--; + if (t.tm_mday < 0) { + t.tm_mday = today->tm_mday; + in_date = 3; + } + + n = 0; + if (t.tm_min < 0) { + t.tm_hour = t.tm_min = 0; + } else if (t.tm_hour < 0) { + if (in_date != 3) + return -1; + in_date = 0; + t.tm_hour = today->tm_hour; + n = 60*60; + } + + if (t.tm_hour > 23 || t.tm_min > 59 + || t.tm_mon < 0 || t.tm_mon >= 12 + || t.tm_mday < 1 || t.tm_mday > 31 + || (val = mktime(&t)) == (time_t)-1) + return -1; + + if (val <= now && in_date) { + tweak_date: + switch (in_date) { + case 3: + t.tm_mday++; + break; + case 2: + if (++t.tm_mon == 12) + t.tm_mon = 0; + else + break; + case 1: + t.tm_year++; + break; + } + if ((val = mktime(&t)) == (time_t)-1) { + if (in_date == 3 && t.tm_mday > 28) { + t.tm_mday = 1; + in_date = 2; + goto tweak_date; + } + return -1; + } + } + if (n) { + while (val <= now) + val += n; + } + return val; + } + int set_modtime(char *fname, time_t modtime, mode_t mode) { #if !defined HAVE_LUTIMES || !defined HAVE_UTIMES