From b180a97acc6a5b49f103fda5a18ce566ed56320f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20B=C3=B6sz=C3=B6rm=C3=A9nyi?= Date: Sun, 8 May 2022 19:03:38 +0200 Subject: [PATCH] Add printf() formatting function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It accepts arbitrary number of arguments, the first argument is the format string just like in C. The rest are data that must be the same type as described in the format string. Fixed printing datetime in new style formats with brackets. Adapted the unit test ocrpt_expr_format_test to exercise printf() and show the datetime fix. Signed-off-by: Zoltán Böszörményi --- libsrc/formatting.c | 194 ++++++++++--------- libsrc/formatting.h | 2 +- libsrc/functions.c | 37 +++- tests/expected/ocrpt_expr_format_test.stdout | 103 +++++----- tests/ocrpt_expr_format_test.c | 4 + 5 files changed, 201 insertions(+), 139 deletions(-) diff --git a/libsrc/formatting.c b/libsrc/formatting.c index 5723a9ac..74f809de 100644 --- a/libsrc/formatting.c +++ b/libsrc/formatting.c @@ -223,12 +223,12 @@ static void ocrpt_formatstring_money_length_prec(const char *fmt, int32_t *lengt if (fmt[i] != '}') \ FORMAT_ERROR; -#define COPY_FORMAT(start, end) \ +#define COPY_FORMAT(start, end, extra) \ do { \ ocrpt_mem_string_append_len(str, fmt + start, end - start); \ ocrpt_mem_string_append_c(str, '\0'); \ *out_type = type; \ - *advance = end - start + 4; \ + *advance = end - start + extra; \ } while (0) #define SWITCH_TO_LITERAL(x) \ @@ -449,7 +449,7 @@ static ocrpt_string *ocrpt_get_next_format_string(opencreport *o, const char *fm type = OCRPT_FORMAT_DATETIME; if (fmt[adv + 2] == '{') { BRACKETED_FORMAT; - COPY_FORMAT(adv + 3, i); + COPY_FORMAT(adv + 3, i - 6, 4); return str; } else RETURN_END_LITERAL(type, 2); @@ -522,7 +522,7 @@ static ocrpt_string *ocrpt_get_next_format_string(opencreport *o, const char *fm type = OCRPT_FORMAT_NUMBER; if (fmt[adv + 2] == '{') { BRACKETED_FORMAT; - COPY_FORMAT(adv + 3, i); + COPY_FORMAT(adv + 3, i, 4); ocrpt_string *str1; enum ocrpt_formatstring_type type1; @@ -576,7 +576,7 @@ static ocrpt_string *ocrpt_get_next_format_string(opencreport *o, const char *fm type = OCRPT_FORMAT_STRING; if (fmt[adv + 2] == '{') { BRACKETED_FORMAT; - COPY_FORMAT(adv + 3, i); + COPY_FORMAT(adv + 3, i, 4); ocrpt_string *str1; enum ocrpt_formatstring_type type1; @@ -697,31 +697,14 @@ void ocrpt_utf8backward(const char *s, int l, int *l2, int blen, int *blen2) { *blen2 = i; } -void ocrpt_format_string(opencreport *o, ocrpt_expr *e, const char *formatstring, int32_t formatlen, ocrpt_result *data) { - enum ocrpt_formatstring_type types[2] = { OCRPT_FORMAT_NONE, OCRPT_FORMAT_LITERAL }; - int32_t advance, type_idx; +void ocrpt_format_string(opencreport *o, ocrpt_expr *e, const char *formatstring, int32_t formatlen, ocrpt_expr **expr, int32_t n_expr) { + int32_t i, advance; locale_t locale; /* Use the specified locale, so that thousand separators, etc. work. */ locale = uselocale(o->locale); - switch (data->type) { - case OCRPT_RESULT_STRING: - types[0] = OCRPT_FORMAT_STRING; - break; - case OCRPT_RESULT_NUMBER: - types[0] = OCRPT_FORMAT_NUMBER; - break; - case OCRPT_RESULT_DATETIME: - types[0] = OCRPT_FORMAT_DATETIME; - break; - case OCRPT_RESULT_ERROR: - ocrpt_expr_make_error_result(o, e, data->string->str); - return; - } - - size_t len = (data->type == OCRPT_RESULT_STRING ? data->string->len : 16); - ocrpt_string *string = ocrpt_mem_string_resize(e->result[o->residx]->string, len); + ocrpt_string *string = ocrpt_mem_string_resize(e->result[o->residx]->string, 16); if (string) { if (!e->result[o->residx]->string) { e->result[o->residx]->string = string; @@ -731,85 +714,120 @@ void ocrpt_format_string(opencreport *o, ocrpt_expr *e, const char *formatstring } advance = 0; - type_idx = 0; - while (advance < formatlen && formatstring[advance]) { - ocrpt_string *tmp; - char *result; - enum ocrpt_formatstring_type type; - int32_t adv, length; - ssize_t len; - bool error, lpadded; - - length = -1; - lpadded = 0; - tmp = ocrpt_get_next_format_string(o, formatstring + advance, types[type_idx], &type, &adv, &error, &length, &lpadded); - - if (error) { - ocrpt_expr_make_error_result(o, e, tmp->str); - ocrpt_mem_string_free(tmp, true); + for (i = 0; i < n_expr; i++) { + ocrpt_result *data = expr[i]->result[o->residx]; + enum ocrpt_formatstring_type types[2] = { OCRPT_FORMAT_NONE, OCRPT_FORMAT_LITERAL }; + int32_t type_idx; + bool data_handled = false; + + switch (data->type) { + case OCRPT_RESULT_STRING: + types[0] = OCRPT_FORMAT_STRING; + break; + case OCRPT_RESULT_NUMBER: + types[0] = OCRPT_FORMAT_NUMBER; + break; + case OCRPT_RESULT_DATETIME: + types[0] = OCRPT_FORMAT_DATETIME; + break; + case OCRPT_RESULT_ERROR: + ocrpt_expr_make_error_result(o, e, data->string->str); return; } - if (types[type_idx] == type || (types[type_idx] == OCRPT_FORMAT_NUMBER && type == OCRPT_FORMAT_MONEY)) - type_idx++; - - switch (type) { - case OCRPT_FORMAT_LITERAL: - ocrpt_mem_string_append(string, tmp->str); - break; - case OCRPT_FORMAT_NUMBER: - if (mpfr_asprintf(&result, tmp->str, data->number) >= 0) { - ocrpt_mem_string_append(string, result); - mpfr_free_str(result); + type_idx = 0; + while (advance < formatlen && formatstring[advance]) { + ocrpt_string *tmp; + char *result; + enum ocrpt_formatstring_type type; + int32_t adv, length; + ssize_t len; + bool error, lpadded; + + length = -1; + lpadded = 0; + tmp = ocrpt_get_next_format_string(o, formatstring + advance, types[type_idx], &type, &adv, &error, &length, &lpadded); + + if (error) { + ocrpt_expr_make_error_result(o, e, tmp->str); + ocrpt_mem_string_free(tmp, true); + return; } - break; - case OCRPT_FORMAT_MONEY: - len = ocrpt_mpfr_strfmon(o, NULL, 0, tmp->str, data->number); - if (len >= 0) { - result = ocrpt_mem_malloc(len + 1); - ocrpt_mpfr_strfmon(o, result, len, tmp->str, data->number); - result[len] = 0; - ocrpt_mem_string_append(string, result); - ocrpt_mem_free(result); + + if (types[type_idx] == type || (types[type_idx] == OCRPT_FORMAT_NUMBER && type == OCRPT_FORMAT_MONEY)) { + type_idx++; + data_handled = true; } - break; - case OCRPT_FORMAT_DATETIME: - char dt[256]; - strftime_l(dt, sizeof(dt), tmp->str, &data->datetime, o->locale); - ocrpt_mem_string_append(string, dt); - break; - case OCRPT_FORMAT_STRING: - int32_t blen = data->string->len; + switch (type) { + case OCRPT_FORMAT_LITERAL: + if (!data_handled || i == (n_expr - 1)) + ocrpt_mem_string_append(string, tmp->str); + else + goto end_inner_loop; + break; + case OCRPT_FORMAT_NUMBER: + if (mpfr_asprintf(&result, tmp->str, data->number) >= 0) { + ocrpt_mem_string_append(string, result); + mpfr_free_str(result); + } + data_handled = true; + break; + case OCRPT_FORMAT_MONEY: + len = ocrpt_mpfr_strfmon(o, NULL, 0, tmp->str, data->number); + if (len >= 0) { + result = ocrpt_mem_malloc(len + 1); + ocrpt_mpfr_strfmon(o, result, len, tmp->str, data->number); + result[len] = 0; + ocrpt_mem_string_append(string, result); + ocrpt_mem_free(result); + } + data_handled = true; + break; + case OCRPT_FORMAT_DATETIME: + char dt[256]; + + strftime_l(dt, sizeof(dt), tmp->str, &data->datetime, o->locale); + ocrpt_mem_string_append(string, dt); + data_handled = true; + break; + case OCRPT_FORMAT_STRING: + int32_t blen = data->string->len; - if (length > 0) { - int32_t slen; - ocrpt_utf8forward(data->string->str, length, &slen, data->string->len, &blen); + if (length > 0) { + int32_t slen; + ocrpt_utf8forward(data->string->str, length, &slen, data->string->len, &blen); - if (lpadded) { - char *padstr; - int32_t padlen; + if (lpadded) { + char *padstr; + int32_t padlen; - padlen = length - slen; - padstr = ocrpt_mem_malloc(padlen + 1); - memset(padstr, ' ', padlen); - padstr[padlen] = 0; + padlen = length - slen; + padstr = ocrpt_mem_malloc(padlen + 1); + memset(padstr, ' ', padlen); + padstr[padlen] = 0; - ocrpt_mem_string_append(string, padstr); + ocrpt_mem_string_append(string, padstr); - ocrpt_mem_free(padstr); + ocrpt_mem_free(padstr); + } } + + ocrpt_mem_string_append_len(string, data->string->str, blen); + data_handled = true; + break; + case OCRPT_FORMAT_NONE: + break; } - ocrpt_mem_string_append_len(string, data->string->str, blen); - break; - case OCRPT_FORMAT_NONE: - break; - } + end_inner_loop: + ocrpt_mem_string_free(tmp, true); - advance += adv; + advance += adv; - ocrpt_mem_string_free(tmp, true); + if (data_handled && i != (n_expr - 1)) + break; + } } uselocale(locale); diff --git a/libsrc/formatting.h b/libsrc/formatting.h index 9e8605f2..80b3012f 100644 --- a/libsrc/formatting.h +++ b/libsrc/formatting.h @@ -47,6 +47,6 @@ struct ocrpt_format_string_element_t { void ocrpt_utf8forward(const char *s, int l, int *l2, int blen, int *blen2); void ocrpt_utf8backward(const char *s, int l, int *l2, int blen, int *blen2); -void ocrpt_format_string(opencreport *o, ocrpt_expr *e, const char *formatstring, int32_t formatlen, ocrpt_result *data); +void ocrpt_format_string(opencreport *o, ocrpt_expr *e, const char *formatstring, int32_t formatlen, ocrpt_expr **data, int32_t n_expr); #endif diff --git a/libsrc/functions.c b/libsrc/functions.c index ceb431fe..e0d77336 100644 --- a/libsrc/functions.c +++ b/libsrc/functions.c @@ -3645,7 +3645,7 @@ OCRPT_STATIC_FUNCTION(ocrpt_format) { } else formatlen = strlen(formatstring); - ocrpt_format_string(o, e, formatstring, formatlen, e->ops[0]->result[o->residx]); + ocrpt_format_string(o, e, formatstring, formatlen, e->ops, 1); } OCRPT_STATIC_FUNCTION(ocrpt_dtosf) { @@ -3711,7 +3711,39 @@ OCRPT_STATIC_FUNCTION(ocrpt_dtosf) { } else formatlen = strlen(formatstring); - ocrpt_format_string(o, e, formatstring, formatlen, e->ops[0]->result[o->residx]); + ocrpt_format_string(o, e, formatstring, formatlen, e->ops, 1); +} + +OCRPT_STATIC_FUNCTION(ocrpt_printf) { + int32_t i; + + if (e->n_ops < 2) { + ocrpt_expr_make_error_result(o, e, "invalid operand(s)"); + return; + } + + for (i = 0; i < e->n_ops; i++) { + if (!e->ops[i]->result[o->residx]) { + ocrpt_expr_make_error_result(o, e, "invalid operand(s)"); + return; + } + } + + for (i = 0; i < e->n_ops; i++) { + if (e->ops[i]->result[o->residx]->type == OCRPT_RESULT_ERROR) { + ocrpt_expr_make_error_result(o, e, e->ops[i]->result[o->residx]->string->str); + return; + } + } + + if (e->ops[0]->result[o->residx]->type != OCRPT_RESULT_STRING) { + ocrpt_expr_make_error_result(o, e, "invalid operand(s)"); + return; + } + + ocrpt_expr_init_result(o, e, OCRPT_RESULT_STRING); + + ocrpt_format_string(o, e, e->ops[0]->result[o->residx]->string->str, e->ops[0]->result[o->residx]->string->len, &e->ops[1], e->n_ops - 1); } /* @@ -3782,6 +3814,7 @@ static const ocrpt_function ocrpt_functions[] = { { "nulls", ocrpt_nulls, 0, false, false, false, false }, { "or", ocrpt_or, -1, true, true, false, false }, { "pow", ocrpt_pow, 2, false, false, false, false }, + { "printf", ocrpt_printf, -1, false, false, false, false }, { "proper", ocrpt_proper, 1, false, false, false, false }, { "random", ocrpt_random, 0, false, false, false, true }, { "remainder", ocrpt_remainder, 2, false, false, false, false }, diff --git a/tests/expected/ocrpt_expr_format_test.stdout b/tests/expected/ocrpt_expr_format_test.stdout index 5af13685..ae3ccb06 100644 --- a/tests/expected/ocrpt_expr_format_test.stdout +++ b/tests/expected/ocrpt_expr_format_test.stdout @@ -243,6 +243,13 @@ expr optimized: (string)You have 6 oranges expr nodes: 1 (string)You have 6 oranges +string: printf('You had %d %s on !@{%Y-%m-%d} and %d %s on !@{%Y-%m-%d} in your pocket.', 6, 'apples', stodt('2022-05-01'), 2, 'oranges', stodt('2022-05-02')) +expr reprinted: printf((string)You had %d %s on !@{%Y-%m-%d} and %d %s on !@{%Y-%m-%d} in your pocket.,6.000000,(string)apples,stodt((string)2022-05-01),2.000000,(string)oranges,stodt((string)2022-05-02)) +expr nodes: 10 +expr optimized: (string)You had 6 apples on 2022-05-01 and 2 oranges on 2022-05-02 in your pocket. +expr nodes: 1 +(string)You had 6 apples on 2022-05-01 and 2 oranges on 2022-05-02 in your pocket. + string: format('apples and oranges', '%6.3d') expr reprinted: format((string)apples and oranges,(string)%6.3d) expr nodes: 3 @@ -389,16 +396,16 @@ expr nodes: 1 string: format(stodt('2022-05-08'), '!@{%Y-%m-%d}') expr reprinted: format(stodt((string)2022-05-08),(string)!@{%Y-%m-%d}) expr nodes: 4 -expr optimized: (string)2022-05-08} +expr optimized: (string)2022-05-08 expr nodes: 1 -(string)2022-05-08} +(string)2022-05-08 string: format(stodt('2022-05-08'), '!@{%A}') expr reprinted: format(stodt((string)2022-05-08),(string)!@{%A}) expr nodes: 4 -expr optimized: (string)Sunday} +expr optimized: (string)Sunday expr nodes: 1 -(string)Sunday} +(string)Sunday string: dtosf(stodt('2022-05-08'), '!@%Y-%m-%d') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@%Y-%m-%d) @@ -417,16 +424,16 @@ expr nodes: 1 string: dtosf(stodt('2022-05-08'), '!@{%Y-%m-%d}') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@{%Y-%m-%d}) expr nodes: 4 -expr optimized: (string)2022-05-08} +expr optimized: (string)2022-05-08 expr nodes: 1 -(string)2022-05-08} +(string)2022-05-08 string: dtosf(stodt('2022-05-08'), '!@{%A}') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@{%A}) expr nodes: 4 -expr optimized: (string)Sunday} +expr optimized: (string)Sunday expr nodes: 1 -(string)Sunday} +(string)Sunday Print formats in en_US.UTF-8 @@ -560,16 +567,16 @@ expr nodes: 1 string: format(stodt('2022-05-08'), '!@{%Y-%m-%d}') expr reprinted: format(stodt((string)2022-05-08),(string)!@{%Y-%m-%d}) expr nodes: 4 -expr optimized: (string)2022-05-08} +expr optimized: (string)2022-05-08 expr nodes: 1 -(string)2022-05-08} +(string)2022-05-08 string: format(stodt('2022-05-08'), '!@{%A}') expr reprinted: format(stodt((string)2022-05-08),(string)!@{%A}) expr nodes: 4 -expr optimized: (string)Sunday} +expr optimized: (string)Sunday expr nodes: 1 -(string)Sunday} +(string)Sunday string: dtosf(stodt('2022-05-08'), '!@%Y-%m-%d') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@%Y-%m-%d) @@ -588,16 +595,16 @@ expr nodes: 1 string: dtosf(stodt('2022-05-08'), '!@{%Y-%m-%d}') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@{%Y-%m-%d}) expr nodes: 4 -expr optimized: (string)2022-05-08} +expr optimized: (string)2022-05-08 expr nodes: 1 -(string)2022-05-08} +(string)2022-05-08 string: dtosf(stodt('2022-05-08'), '!@{%A}') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@{%A}) expr nodes: 4 -expr optimized: (string)Sunday} +expr optimized: (string)Sunday expr nodes: 1 -(string)Sunday} +(string)Sunday Print formats in en_GB.UTF-8 @@ -731,16 +738,16 @@ expr nodes: 1 string: format(stodt('2022-05-08'), '!@{%Y-%m-%d}') expr reprinted: format(stodt((string)2022-05-08),(string)!@{%Y-%m-%d}) expr nodes: 4 -expr optimized: (string)2022-05-08} +expr optimized: (string)2022-05-08 expr nodes: 1 -(string)2022-05-08} +(string)2022-05-08 string: format(stodt('2022-05-08'), '!@{%A}') expr reprinted: format(stodt((string)2022-05-08),(string)!@{%A}) expr nodes: 4 -expr optimized: (string)Sunday} +expr optimized: (string)Sunday expr nodes: 1 -(string)Sunday} +(string)Sunday string: dtosf(stodt('2022-05-08'), '!@%Y-%m-%d') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@%Y-%m-%d) @@ -759,16 +766,16 @@ expr nodes: 1 string: dtosf(stodt('2022-05-08'), '!@{%Y-%m-%d}') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@{%Y-%m-%d}) expr nodes: 4 -expr optimized: (string)2022-05-08} +expr optimized: (string)2022-05-08 expr nodes: 1 -(string)2022-05-08} +(string)2022-05-08 string: dtosf(stodt('2022-05-08'), '!@{%A}') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@{%A}) expr nodes: 4 -expr optimized: (string)Sunday} +expr optimized: (string)Sunday expr nodes: 1 -(string)Sunday} +(string)Sunday Print formats in fr_FR.UTF-8 @@ -902,16 +909,16 @@ expr nodes: 1 string: format(stodt('2022-05-08'), '!@{%Y-%m-%d}') expr reprinted: format(stodt((string)2022-05-08),(string)!@{%Y-%m-%d}) expr nodes: 4 -expr optimized: (string)2022-05-08} +expr optimized: (string)2022-05-08 expr nodes: 1 -(string)2022-05-08} +(string)2022-05-08 string: format(stodt('2022-05-08'), '!@{%A}') expr reprinted: format(stodt((string)2022-05-08),(string)!@{%A}) expr nodes: 4 -expr optimized: (string)dimanche} +expr optimized: (string)dimanche expr nodes: 1 -(string)dimanche} +(string)dimanche string: dtosf(stodt('2022-05-08'), '!@%Y-%m-%d') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@%Y-%m-%d) @@ -930,16 +937,16 @@ expr nodes: 1 string: dtosf(stodt('2022-05-08'), '!@{%Y-%m-%d}') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@{%Y-%m-%d}) expr nodes: 4 -expr optimized: (string)2022-05-08} +expr optimized: (string)2022-05-08 expr nodes: 1 -(string)2022-05-08} +(string)2022-05-08 string: dtosf(stodt('2022-05-08'), '!@{%A}') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@{%A}) expr nodes: 4 -expr optimized: (string)dimanche} +expr optimized: (string)dimanche expr nodes: 1 -(string)dimanche} +(string)dimanche Print formats in de_DE.UTF-8 @@ -1073,16 +1080,16 @@ expr nodes: 1 string: format(stodt('2022-05-08'), '!@{%Y-%m-%d}') expr reprinted: format(stodt((string)2022-05-08),(string)!@{%Y-%m-%d}) expr nodes: 4 -expr optimized: (string)2022-05-08} +expr optimized: (string)2022-05-08 expr nodes: 1 -(string)2022-05-08} +(string)2022-05-08 string: format(stodt('2022-05-08'), '!@{%A}') expr reprinted: format(stodt((string)2022-05-08),(string)!@{%A}) expr nodes: 4 -expr optimized: (string)Sonntag} +expr optimized: (string)Sonntag expr nodes: 1 -(string)Sonntag} +(string)Sonntag string: dtosf(stodt('2022-05-08'), '!@%Y-%m-%d') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@%Y-%m-%d) @@ -1101,16 +1108,16 @@ expr nodes: 1 string: dtosf(stodt('2022-05-08'), '!@{%Y-%m-%d}') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@{%Y-%m-%d}) expr nodes: 4 -expr optimized: (string)2022-05-08} +expr optimized: (string)2022-05-08 expr nodes: 1 -(string)2022-05-08} +(string)2022-05-08 string: dtosf(stodt('2022-05-08'), '!@{%A}') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@{%A}) expr nodes: 4 -expr optimized: (string)Sonntag} +expr optimized: (string)Sonntag expr nodes: 1 -(string)Sonntag} +(string)Sonntag Print formats in hu_HU.UTF-8 @@ -1244,16 +1251,16 @@ expr nodes: 1 string: format(stodt('2022-05-08'), '!@{%Y-%m-%d}') expr reprinted: format(stodt((string)2022-05-08),(string)!@{%Y-%m-%d}) expr nodes: 4 -expr optimized: (string)2022-05-08} +expr optimized: (string)2022-05-08 expr nodes: 1 -(string)2022-05-08} +(string)2022-05-08 string: format(stodt('2022-05-08'), '!@{%A}') expr reprinted: format(stodt((string)2022-05-08),(string)!@{%A}) expr nodes: 4 -expr optimized: (string)vasárnap} +expr optimized: (string)vasárnap expr nodes: 1 -(string)vasárnap} +(string)vasárnap string: dtosf(stodt('2022-05-08'), '!@%Y-%m-%d') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@%Y-%m-%d) @@ -1272,14 +1279,14 @@ expr nodes: 1 string: dtosf(stodt('2022-05-08'), '!@{%Y-%m-%d}') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@{%Y-%m-%d}) expr nodes: 4 -expr optimized: (string)2022-05-08} +expr optimized: (string)2022-05-08 expr nodes: 1 -(string)2022-05-08} +(string)2022-05-08 string: dtosf(stodt('2022-05-08'), '!@{%A}') expr reprinted: dtosf(stodt((string)2022-05-08),(string)!@{%A}) expr nodes: 4 -expr optimized: (string)vasárnap} +expr optimized: (string)vasárnap expr nodes: 1 -(string)vasárnap} +(string)vasárnap diff --git a/tests/ocrpt_expr_format_test.c b/tests/ocrpt_expr_format_test.c index cd4f1d6b..0034029a 100644 --- a/tests/ocrpt_expr_format_test.c +++ b/tests/ocrpt_expr_format_test.c @@ -72,6 +72,10 @@ int main(void) { "format(6, 'You have !#% 10d oranges')", "format(6, 'You have !#{% 10d} oranges')", + /* printf(), yay!!! */ + + "printf('You had %d %s on !@{%Y-%m-%d} and %d %s on !@{%Y-%m-%d} in your pocket.', 6, 'apples', stodt('2022-05-01'), 2, 'oranges', stodt('2022-05-02'))", + /* Invalid formats */ /* Numeric format for a string */