Timezone, DSTmaybe));
}
+/*
+ * Parses and consumes an unsigned number.
+ * Returns 1 if any number is parsed. Otherwise, *value is unchanged.
+ */
+static char
+consume_unsigned_number(const char **in, time_t *value)
+{
+ char c;
+ if (isdigit((unsigned char)(c = **in))) {
+ for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); )
+ *value = 10 * *value + c - '0';
+ (*in)--;
+ return 1;
+ }
+ return 0;
+}
+
/*
* Tokenizer.
*/
* Because '-' and '+' have other special meanings, I
* don't deal with signed numbers here.
*/
- if (isdigit((unsigned char)(c = **in))) {
- for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); )
- *value = 10 * *value + c - '0';
- (*in)--;
+ if (consume_unsigned_number(in, value)) {
return (tUNUMBER);
}
+ (a->tm_sec - b->tm_sec));
}
+/*
+ * Parses a Unix epoch timestamp (seconds).
+ * This supports a subset of what GNU tar accepts from black box testing,
+ * but covers common use cases.
+ */
+static time_t
+parse_unix_epoch(const char *p)
+{
+ time_t epoch;
+
+ /* may begin with + */
+ if (*p == '+') {
+ p++;
+ }
+
+ /* followed by some number */
+ if (!consume_unsigned_number(&p, &epoch))
+ return (time_t)-1;
+
+ /* ...and nothing else */
+ if (*p != '\0')
+ return (time_t)-1;
+
+ return epoch;
+}
+
/*
*
* The public function.
time_t tod;
long tzone;
+ /*
+ * @-prefixed Unix epoch timestamps (seconds)
+ * Skip the complex tokenizer - We do not want to accept strings like "@tenth"
+ */
+ if (*p == '@')
+ return parse_unix_epoch(p + 1);
+
/* Clear out the parsed token array. */
memset(tokens, 0, sizeof(tokens));
/* Initialize the parser state. */
/* "last tuesday" is one week before "tuesday" */
assertEqualInt(get_date(now, "last tuesday UTC"),
now - 6 * 24 * 60 * 60);
+
+ /* Unix epoch timestamps */
+ assertEqualInt(get_date(now, "@0"), 0);
+ assertEqualInt(get_date(now, "@100"), 100);
+ assertEqualInt(get_date(now, "@+100"), 100);
+
+ assertEqualInt(get_date(now, "@"), -1);
+ assertEqualInt(get_date(now, "@-"), -1);
+ assertEqualInt(get_date(now, "@+"), -1);
+ assertEqualInt(get_date(now, "@tenth"), -1);
+ assertEqualInt(get_date(now, "@100 tomorrow"), -1);
+
/* TODO: Lots more tests here. */
}