summaryrefslogtreecommitdiffstats
path: root/src/datatype.c
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2014-01-20 13:38:40 +0000
committerPatrick McHardy <kaber@trash.net>2014-01-20 13:38:40 +0000
commita085d80754af0be8e650724329187aa69e23630d (patch)
tree16775e6b7e402f89be5a1849f9dbae1c9f39153a /src/datatype.c
parent807b936bb3d9bb2c924c742a0548337089494968 (diff)
parent6d0a165e402e6477203111ca9c7ce49f0a3fd758 (diff)
Merge remote-tracking branch 'origin/master' into next-3.14
Diffstat (limited to 'src/datatype.c')
-rw-r--r--src/datatype.c134
1 files changed, 118 insertions, 16 deletions
diff --git a/src/datatype.c b/src/datatype.c
index 5e4aacdf..7c287bdf 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -11,6 +11,7 @@
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
+#include <ctype.h> /* isdigit */
#include <errno.h>
#include <netdb.h>
#include <arpa/inet.h>
@@ -688,7 +689,6 @@ const struct datatype mark_type = {
static void time_type_print(const struct expr *expr)
{
uint64_t days, hours, minutes, seconds;
- const char *delim = "";
seconds = mpz_get_uint64(expr->value);
@@ -701,22 +701,123 @@ static void time_type_print(const struct expr *expr)
minutes = seconds / 60;
seconds %= 60;
- if (days > 0) {
- printf("%s%" PRIu64 " d", delim, days);
- delim = " ";
- }
- if (hours > 0) {
- printf("%s%" PRIu64 " h", delim, hours);
- delim = " ";
- }
- if (minutes > 0) {
- printf("%s%" PRIu64 " min", delim, minutes);
- delim = " ";
- }
- if (seconds > 0) {
- printf("%s%" PRIu64 " s", delim, seconds);
- delim = " ";
+ printf("\"");
+
+ if (days > 0)
+ printf("%"PRIu64"d", days);
+ if (hours > 0)
+ printf("%"PRIu64"h", hours);
+ if (minutes > 0)
+ printf("%"PRIu64"m", minutes);
+ if (seconds > 0)
+ printf("%"PRIu64"s", seconds);
+
+ printf("\"");
+}
+
+enum {
+ DAY = (1 << 0),
+ HOUR = (1 << 1),
+ MIN = (1 << 2),
+ SECS = (1 << 3),
+};
+
+static uint32_t str2int(char *tmp, const char *c, int k)
+{
+ if (k == 0)
+ return 0;
+
+ strncpy(tmp, c-k, k+1);
+ return atoi(tmp);
+}
+
+static struct error_record *time_type_parse(const struct expr *sym,
+ struct expr **res)
+{
+ int i, len;
+ unsigned int k = 0;
+ char tmp[8];
+ const char *c;
+ uint64_t d = 0, h = 0, m = 0, s = 0;
+ uint32_t mask = 0;
+
+ c = sym->identifier;
+ len = strlen(c);
+ for (i = 0; i < len; i++, c++) {
+ switch (*c) {
+ case 'd':
+ if (mask & DAY) {
+ return error(&sym->location,
+ "Day has been specified twice");
+ }
+ d = str2int(tmp, c, k);
+ k = 0;
+ mask |= DAY;
+ break;
+ case 'h':
+ if (mask & HOUR) {
+ return error(&sym->location,
+ "Hour has been specified twice");
+ }
+ h = str2int(tmp, c, k);
+ k = 0;
+ if (h > 23) {
+ return error(&sym->location,
+ "Hour needs to be 0-23");
+ }
+ mask |= HOUR;
+ break;
+ case 'm':
+ if (mask & MIN) {
+ return error(&sym->location,
+ "Minute has been specified twice");
+ }
+ m = str2int(tmp, c, k);
+ k = 0;
+ if (m > 59) {
+ return error(&sym->location,
+ "Minute needs to be 0-59");
+ }
+ mask |= MIN;
+ break;
+ case 's':
+ if (mask & SECS) {
+ return error(&sym->location,
+ "Second has been specified twice");
+ }
+ s = str2int(tmp, c, k);
+ k = 0;
+ if (s > 59) {
+ return error(&sym->location,
+ "second needs to be 0-59");
+ }
+ mask |= SECS;
+ break;
+ default:
+ if (!isdigit(*c))
+ return error(&sym->location, "wrong format");
+
+ if (k++ >= array_size(tmp)) {
+ return error(&sym->location,
+ "value too large");
+ }
+ break;
+ }
}
+
+ /* default to seconds if no unit was specified */
+ if (!mask)
+ s = atoi(sym->identifier);
+ else
+ s = 24*60*60*d+60*60*h+60*m+s;
+
+ if (s > UINT32_MAX)
+ return error(&sym->location, "value too large");
+
+ *res = constant_expr_alloc(&sym->location, &time_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(uint32_t) * BITS_PER_BYTE, &s);
+ return NULL;
}
const struct datatype time_type = {
@@ -727,6 +828,7 @@ const struct datatype time_type = {
.size = 8 * BITS_PER_BYTE,
.basetype = &integer_type,
.print = time_type_print,
+ .parse = time_type_parse,
};
static struct error_record *concat_type_parse(const struct expr *sym,