++/* 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(const char *fname, time_t modtime, mode_t mode)
+ {
+ #if !defined HAVE_LUTIMES || !defined HAVE_UTIMES