aboutsummaryrefslogtreecommitdiffstats
path: root/src/expire.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/expire.c')
-rw-r--r--src/expire.c114
1 files changed, 90 insertions, 24 deletions
diff --git a/src/expire.c b/src/expire.c
index 23ce6ae..2207d3c 100644
--- a/src/expire.c
+++ b/src/expire.c
@@ -20,9 +20,11 @@
/******************************************************************************/
/******************************************************************************/
+#include <stdbool.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
+#include <limits.h>
#include "expire.h"
@@ -31,52 +33,116 @@ static const int MIN = 60;
static const int HOUR = 60*60;
static const int DAY = 24*60*60;
static const int WEEK = 7*24*60*60;
-static const int YEAR = 365*24*60*60 + 24*60*60/4;
+static const int YEAR = 365*24*60*60 + 24*60*60/4; /* average includes leap */
+static const time_t TMIN = (time_t)1 << ((CHAR_BIT * sizeof(time_t)) - 1);
+static const time_t TMAX = ~TMIN;
-/* see expire.h */
-time_t txt2exp(const char *txt)
+/** add positives x and y with saturation */
+static time_t pt_add(time_t x, time_t y)
{
- time_t r, x;
+ time_t r = x + y;
+ return r < 0 ? TMAX : r;
+}
- /* infinite time */
- if (!strcmp(txt, "always") || !strcmp(txt, "forever") || !strcmp(txt, "*"))
- return 0;
+/** multiply positive x by m with saturation */
+static time_t pt_mul(time_t x, int m)
+{
+ time_t r;
+
+ if (m <= 1)
+ r = 0;
+ else {
+ r = pt_mul(x, m >> 1) << 1;
+ if (r < 0)
+ r = TMAX;
+ }
+ return (m & 1) ? pt_add(r, x) : r;
+}
+
+/** multiply positive x by m and then add y with saturation */
+static time_t pt_muladd(time_t x, int m, time_t y)
+{
+ return pt_add(pt_mul(x, m), y);
+}
+
+/** multiply positive x by 10 and then add d with saturation */
+static time_t pt_tm10a(time_t x, int d)
+{
+ return pt_muladd(x, 10, (time_t)d);
+}
+
+/** translate the string 'txt' to its time representation */
+static bool parse_time_spec(const char *txt, time_t *time_out)
+{
+ time_t r, x;
/* parse */
- r = time(NULL);
+ r = 0;
while(*txt) {
x = 0;
while('0' <= *txt && *txt <= '9')
- x = (x << 3) + (x << 1) + (time_t)(*txt++ - '0');
+ x = pt_tm10a(x, *txt++ - '0');
switch(*txt) {
- case 'y': r += x * YEAR; txt++; break;
- case 'w': r += x * WEEK; txt++; break;
- case 'd': r += x * DAY; txt++; break;
- case 'h': r += x * HOUR; txt++; break;
- case 'm': r += x * MIN; txt++; break;
+ case 'y': r = pt_muladd(x, YEAR, r); txt++; break;
+ case 'w': r = pt_muladd(x, WEEK, r); txt++; break;
+ case 'd': r = pt_muladd(x, DAY, r); txt++; break;
+ case 'h': r = pt_muladd(x, HOUR, r); txt++; break;
+ case 'm': r = pt_muladd(x, MIN, r); txt++; break;
case 's': txt++; /*@fallthrough@*/
- case 0: r += x * SEC; break;
- default: return -1;
+ case 0: r = pt_muladd(x, SEC, r); break;
+ default: return false;
}
}
- return r;
+ *time_out = r;
+ return true;
+}
+
+
+/* see expire.h */
+bool txt2exp(const char *txt, time_t *time_out)
+{
+ bool nocache;
+ time_t r;
+
+ /* no cache */
+ nocache = txt[0] == '-';
+ txt += nocache;
+
+ /* infinite time */
+ if (!txt[0] || !strcmp(txt, "always") || !strcmp(txt, "forever") || !strcmp(txt, "*")) {
+ r = 0;
+ } else {
+ /* parse */
+ if (!parse_time_spec(txt, &r))
+ return false;
+ /* relative time */
+ r = pt_add(r, time(NULL));
+ }
+
+ *time_out = nocache ? -(r + 1) : r;
+ return true;
}
/* see expire.h */
size_t exp2txt(time_t expire, char *buffer, size_t buflen)
{
char b[100];
- size_t l;
- int n;
+ size_t l, n;
- if (!expire)
- strncpy(b, "forever", sizeof b);
- else {
+ n = 0;
+ if (expire < 0) {
+ b[n++] = '-';
+ b[n] = 0;
+ expire = -(expire + 1);
+ }
+ if (!expire) {
+ if (!n)
+ strncpy(b, "forever", sizeof b);
+ } else {
expire -= time(NULL);
- n = 0;
#define ADD(C,U) \
if (expire >= U) { \
- n += snprintf(&b[n], sizeof b - (size_t)n, "%lld" #C, (long long)(expire / U)); \
+ n += (size_t)snprintf(&b[n], sizeof b - (size_t)n, "%lld" #C, (long long)(expire / U)); \
expire %= U; \
}
ADD(y,YEAR)