diff --git a/attributes/schema_type_parse.c b/attributes/schema_type_parse.c index 9de255da6fc5986bb28a4565adb4a9709f05f74a..7b1d221d438ac47603d26b95a8772b142e091f36 100644 --- a/attributes/schema_type_parse.c +++ b/attributes/schema_type_parse.c @@ -144,10 +144,11 @@ mstro_stp_val_alloc(enum mstro_stp_val_kind kind) case MSTRO_STP_FLOATVAL: case MSTRO_STP_DOUBLEVAL: case MSTRO_STP_BOOLVAL: + case MSTRO_STP_TIMESTAMP: break; default: - DEBUG("No default restrictions set for type %d\n", kind); + ERR("No default restrictions set for type %d\n", kind); } } return res; @@ -1213,6 +1214,20 @@ static void pcc_action_builtin_type_name_7(mstro_stp_context_t *__pcc_ctx, pcc_t #undef auxil } +static void pcc_action_builtin_type_name_8(mstro_stp_context_t *__pcc_ctx, pcc_thunk_t *__pcc_in, pcc_value_t *__pcc_out) { +#define auxil (__pcc_ctx->auxil) +#define __ (*__pcc_out) +#define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0) +#define _0s ((const)__pcc_in->data.leaf.capt0.range.start) +#define _0e ((const)__pcc_in->data.leaf.capt0.range.end) + __ = mstro_stp_val_alloc(MSTRO_STP_TIMESTAMP); DEBUG("found timestamp\n"); +#undef _0e +#undef _0s +#undef _0 +#undef __ +#undef auxil +} + static void pcc_action_user_type_name_0(mstro_stp_context_t *__pcc_ctx, pcc_thunk_t *__pcc_in, pcc_value_t *__pcc_out) { #define auxil (__pcc_ctx->auxil) #define __ (*__pcc_out) @@ -2169,6 +2184,31 @@ static pcc_thunk_chunk_t *pcc_evaluate_rule_builtin_type_name(mstro_stp_context_ } goto L0001; L0009:; + ctx->pos = p; + pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); + { + if ( + pcc_refill_buffer(ctx, 9) < 9 || + (ctx->buffer.buf + ctx->pos)[0] != 't' || + (ctx->buffer.buf + ctx->pos)[1] != 'i' || + (ctx->buffer.buf + ctx->pos)[2] != 'm' || + (ctx->buffer.buf + ctx->pos)[3] != 'e' || + (ctx->buffer.buf + ctx->pos)[4] != 's' || + (ctx->buffer.buf + ctx->pos)[5] != 't' || + (ctx->buffer.buf + ctx->pos)[6] != 'a' || + (ctx->buffer.buf + ctx->pos)[7] != 'm' || + (ctx->buffer.buf + ctx->pos)[8] != 'p' + ) goto L0010; + ctx->pos += 9; + } + { + pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_builtin_type_name_8, 0, 0); + thunk->data.leaf.capt0.range.start = chunk->pos; + thunk->data.leaf.capt0.range.end = ctx->pos; + pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk); + } + goto L0001; + L0010:; ctx->pos = p; pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); goto L0000; @@ -3578,7 +3618,7 @@ void mstro_stp_destroy(mstro_stp_context_t *ctx) { #define MIN(x,y) ((x)<(y) ? (x) : (y)) -#line 561 "schema_type_parse.peg" +#line 576 "schema_type_parse.peg" mstro_status mstro_schema_type_parse(const char *string, struct mstro_stp_val **res) { @@ -3587,7 +3627,7 @@ mstro_schema_type_parse(const char *string, struct mstro_stp_val **res) if(ctx==NULL) return MSTRO_NOMEM; int i = mstro_stp_parse(ctx, res); - DEBUG("parser result code: %d\n"); + DEBUG("parser result code: %d\n", i); if(in.got_error) { *res = NULL; /* FIXME: we need to figure out if we leak partial parse results here */ @@ -3631,7 +3671,7 @@ mstro_stp_val_dispose(struct mstro_stp_val *v) break; case MSTRO_STP_NAME: if(v->nameval) - free(v->nameval); + free(v->nameval); break; default: break; @@ -3689,6 +3729,7 @@ mstro_stp_val__describe(const struct mstro_stp_val *v) case MSTRO_STP_EXCLSTR: case MSTRO_STP_ICASE: case MSTRO_STP_NAME: + case MSTRO_STP_TIMESTAMP: DEBUG("v kind %d, describe unimplemented\n", v->kind); break; @@ -3751,23 +3792,28 @@ mstro_stp_val__build_restricted_type( struct mstro_stp_val *tmp = args; args = args->list_tail; tmp->list_tail = NULL; - + switch(tmp->list_entry->kind) { case MSTRO_STP_MININT: - result->int_min = tmp->list_entry->minintval; break; + result->int_min = tmp->list_entry->minintval; + break; case MSTRO_STP_MINUINT: if(tmp->list_entry->minuintval>(uint64_t)INT64_MAX) { ERR("signed int min %" PRIu64 "exceeds INT64_MAX\n", tmp->list_entry->minuintval); } - result->int_min = MIN((uint64_t)INT64_MAX,tmp->list_entry->minuintval); + result->int_min = (tmp->list_entry->minuintval < INT64_MAX) + ? (int64_t)tmp->list_entry->minuintval : INT64_MAX; break; case MSTRO_STP_MAXINT: - result->int_max = tmp->list_entry->maxintval; break; + result->int_max = tmp->list_entry->maxintval; + break; case MSTRO_STP_MAXUINT: + DEBUG("int, encountered maxuint arg of %" PRIu64 "\n", tmp->list_entry->maxuintval); if(tmp->list_entry->maxuintval>(uint64_t)INT64_MAX) { ERR("signed int max %" PRIu64 "exceeds INT64_MAX\n", tmp->list_entry->maxuintval); } - result->int_min = MIN((uint64_t)INT64_MAX,tmp->list_entry->maxuintval); + result->int_max = (tmp->list_entry->maxuintval < INT64_MAX) + ? (int64_t)tmp->list_entry->maxuintval : INT64_MAX ; break; default: ERR("Illegal type restriction for signed integer: %d\n", tmp->list_entry->kind); @@ -3978,6 +4024,22 @@ mstro_stp_val__build_restricted_type( break; } + case MSTRO_STP_TIMESTAMP: { + leftovers = args; /* no args supported */ + /* construct the regexp */ + result->kind = MSTRO_STP_REGEX; + result->regex_ignorecase = false; + result->regex_name = strdup("RFC3339 timestamp"); + result->regex_numpatterns = 1; + result->regex_patterns = malloc(sizeof(char*)); + char *tmp = strdup(RFC3339_PATTERN); + if(result->regex_patterns==NULL || tmp==NULL || result->regex_name==NULL) { + ERR("Cannot allocate timestamp regex\n"); + abort(); + } + result->regex_patterns[0] = tmp; + break; + } default: ERR("type parse intermediate kind %d should not be returned\n", typename->kind); diff --git a/attributes/schema_type_parse.h b/attributes/schema_type_parse.h index ce7f22e3449416de2c03b84eddd9dcec359b454c..e9f5803a3d34817be26f664afadbf446d5066588 100644 --- a/attributes/schema_type_parse.h +++ b/attributes/schema_type_parse.h @@ -33,6 +33,7 @@ enum mstro_stp_val_kind { MSTRO_STP_ICASE, MSTRO_STP_NAME, MSTRO_STP_LIST, + MSTRO_STP_TIMESTAMP, /* externally will be converted to RFC3339 regex */ /** user-facing node types */ MSTRO_STP_BOOL = 64, @@ -132,6 +133,10 @@ mstro_schema_type_parse(const char *string, struct mstro_stp_val **res); mstro_status mstro_stp_val_dispose(struct mstro_stp_val *v); +/** User-facing: pattern for RFC3339-timestamp */ +#define RFC3339_PATTERN ("^([0-9]{4})-([0-9]{2})-([0-9]{2})" \ + "([Tt]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?" \ + "(([Zz]|([+-])([0-9]{2}):([0-9]{2})))?") diff --git a/attributes/schema_type_parse.peg b/attributes/schema_type_parse.peg index 620a0a594bdade6ebe6f60293281e3ea4da241cc..d7e8a25870692ba8e853d5957d4d4eb4cedec7e7 100644 --- a/attributes/schema_type_parse.peg +++ b/attributes/schema_type_parse.peg @@ -130,10 +130,11 @@ mstro_stp_val_alloc(enum mstro_stp_val_kind kind) case MSTRO_STP_FLOATVAL: case MSTRO_STP_DOUBLEVAL: case MSTRO_STP_BOOLVAL: + case MSTRO_STP_TIMESTAMP: break; default: - DEBUG("No default restrictions set for type %d\n", kind); + ERR("No default restrictions set for type %d\n", kind); } } return res; @@ -194,6 +195,7 @@ enum mstro_stp_val_kind { MSTRO_STP_ICASE, MSTRO_STP_NAME, MSTRO_STP_LIST, + MSTRO_STP_TIMESTAMP, /* externally will be converted to RFC3339 regex */ /** user-facing node types */ MSTRO_STP_BOOL = 64, @@ -293,6 +295,10 @@ mstro_schema_type_parse(const char *string, struct mstro_stp_val **res); mstro_status mstro_stp_val_dispose(struct mstro_stp_val *v); +/** User-facing: pattern for RFC3339-timestamp */ +#define RFC3339_PATTERN ("^([0-9]{4})-([0-9]{2})-([0-9]{2})" \ + "([Tt]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?" \ + "(([Zz]|([+-])([0-9]{2}):([0-9]{2})))?") } @@ -324,6 +330,7 @@ builtin_type_name <- / "regex" { $$ = mstro_stp_val_alloc(MSTRO_STP_REGEX); DEBUG("found regex\n"); } / "str" { $$ = mstro_stp_val_alloc(MSTRO_STP_STR); DEBUG("found str\n"); } / "blob" { $$ = mstro_stp_val_alloc(MSTRO_STP_BLOB); DEBUG("found blob\n"); } + / "timestamp" { $$ = mstro_stp_val_alloc(MSTRO_STP_TIMESTAMP); DEBUG("found timestamp\n"); } ## user-defined types are a name suitable for a maestro schema yaml ## attribute key, possibly including (parts of) a namespace prefix @@ -566,7 +573,7 @@ EOF <- !. #define MIN(x,y) ((x)<(y) ? (x) : (y)) -#line 561 "schema_type_parse.peg" +#line 576 "schema_type_parse.peg" mstro_status mstro_schema_type_parse(const char *string, struct mstro_stp_val **res) { @@ -575,7 +582,7 @@ mstro_schema_type_parse(const char *string, struct mstro_stp_val **res) if(ctx==NULL) return MSTRO_NOMEM; int i = mstro_stp_parse(ctx, res); - DEBUG("parser result code: %d\n"); + DEBUG("parser result code: %d\n", i); if(in.got_error) { *res = NULL; /* FIXME: we need to figure out if we leak partial parse results here */ @@ -619,7 +626,7 @@ mstro_stp_val_dispose(struct mstro_stp_val *v) break; case MSTRO_STP_NAME: if(v->nameval) - free(v->nameval); + free(v->nameval); break; default: break; @@ -677,6 +684,7 @@ mstro_stp_val__describe(const struct mstro_stp_val *v) case MSTRO_STP_EXCLSTR: case MSTRO_STP_ICASE: case MSTRO_STP_NAME: + case MSTRO_STP_TIMESTAMP: DEBUG("v kind %d, describe unimplemented\n", v->kind); break; @@ -739,23 +747,28 @@ mstro_stp_val__build_restricted_type( struct mstro_stp_val *tmp = args; args = args->list_tail; tmp->list_tail = NULL; - + switch(tmp->list_entry->kind) { case MSTRO_STP_MININT: - result->int_min = tmp->list_entry->minintval; break; + result->int_min = tmp->list_entry->minintval; + break; case MSTRO_STP_MINUINT: if(tmp->list_entry->minuintval>(uint64_t)INT64_MAX) { ERR("signed int min %" PRIu64 "exceeds INT64_MAX\n", tmp->list_entry->minuintval); } - result->int_min = MIN((uint64_t)INT64_MAX,tmp->list_entry->minuintval); + result->int_min = (tmp->list_entry->minuintval < INT64_MAX) + ? (int64_t)tmp->list_entry->minuintval : INT64_MAX; break; case MSTRO_STP_MAXINT: - result->int_max = tmp->list_entry->maxintval; break; + result->int_max = tmp->list_entry->maxintval; + break; case MSTRO_STP_MAXUINT: + DEBUG("int, encountered maxuint arg of %" PRIu64 "\n", tmp->list_entry->maxuintval); if(tmp->list_entry->maxuintval>(uint64_t)INT64_MAX) { ERR("signed int max %" PRIu64 "exceeds INT64_MAX\n", tmp->list_entry->maxuintval); } - result->int_min = MIN((uint64_t)INT64_MAX,tmp->list_entry->maxuintval); + result->int_max = (tmp->list_entry->maxuintval < INT64_MAX) + ? (int64_t)tmp->list_entry->maxuintval : INT64_MAX ; break; default: ERR("Illegal type restriction for signed integer: %d\n", tmp->list_entry->kind); @@ -966,6 +979,22 @@ mstro_stp_val__build_restricted_type( break; } + case MSTRO_STP_TIMESTAMP: { + leftovers = args; /* no args supported */ + /* construct the regexp */ + result->kind = MSTRO_STP_REGEX; + result->regex_ignorecase = false; + result->regex_name = strdup("RFC3339 timestamp"); + result->regex_numpatterns = 1; + result->regex_patterns = malloc(sizeof(char*)); + char *tmp = strdup(RFC3339_PATTERN); + if(result->regex_patterns==NULL || tmp==NULL || result->regex_name==NULL) { + ERR("Cannot allocate timestamp regex\n"); + abort(); + } + result->regex_patterns[0] = tmp; + break; + } default: ERR("type parse intermediate kind %d should not be returned\n", typename->kind); diff --git a/tests/check_type_parser.c b/tests/check_type_parser.c index ffe91b09601d68269355ab95a5f9462d86b5eeeb..fb4c898e2d251ea53ec0959cff3863a2262cd14b 100644 --- a/tests/check_type_parser.c +++ b/tests/check_type_parser.c @@ -55,6 +55,7 @@ CHEAT_DECLARE( /* built-in types, no restrictions */ "bool()", "uint()", "int()", "float()", "double()", "str()", "blob()", + "timestamp()", /* regex is also built-in but can't be used without args; * see below */