From 82adda06846b7525efc96fabdff0b264edf05753 Mon Sep 17 00:00:00 2001 From: Eduardo Rodrigues Seifert Date: Sat, 16 Nov 2024 17:35:30 -0300 Subject: [PATCH 1/9] Add function --- parser/mpFuncCommon.cpp | 57 ++++++++++++++++++++++++++++++++++---- parser/mpFuncCommon.h | 13 +++++++++ parser/mpPackageCommon.cpp | 1 + 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/parser/mpFuncCommon.cpp b/parser/mpFuncCommon.cpp index e342f12..f72dd9d 100644 --- a/parser/mpFuncCommon.cpp +++ b/parser/mpFuncCommon.cpp @@ -703,11 +703,6 @@ MUP_NAMESPACE_START return new FunAddDays(*this); } - //------------------------------------------------------------------------------ - // - // class FunTimeDiff - // - //------------------------------------------------------------------------------ //FunTimeDiff::FunTimeDiff() // :ICallback(cmFUNC, _T("timediff"), -1) @@ -808,6 +803,25 @@ MUP_NAMESPACE_START // | //------------------------------------------------------------------------------ + //------------------------------------------------------------------------------ + // | + // Time auxiliar functions! | + // | + //------------------------------------------------------------------------------ + + string_type format_time (struct tm time) { + char buffer[9]; + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d", time.tm_hour, time.tm_min, time.tm_sec); + + return std::string(buffer); + } + + //------------------------------------------------------------------------------ + // + // class FunTimeDiff + // + //------------------------------------------------------------------------------ + FunTimeDiff::FunTimeDiff() :ICallback(cmFUNC, _T("timediff"), -1) {} @@ -856,6 +870,39 @@ MUP_NAMESPACE_START return new FunTimeDiff(*this); } + //------------------------------------------------------------------------------ + // + // class FunCurrentTime + // + //------------------------------------------------------------------------------ + + FunCurrentTime::FunCurrentTime() + :ICallback(cmFUNC, _T("current_time"), -1) + {} + + void FunCurrentTime::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) + { + if (a_iArgc != 0) + throw ParserError(ErrorContext(ecTOO_MANY_PARAMS, GetExprPos(), GetIdent())); + + std::time_t t = std::time(0); + std::tm now = *std::localtime(&t); + + *ret = format_time(now); + } + + ////------------------------------------------------------------------------------ + const char_type* FunCurrentTime::GetDesc() const + { + return _T("current_time() - Returns the current time in the HH:MM:SS format."); + } + + ////------------------------------------------------------------------------------ + IToken* FunCurrentTime::Clone() const + { + return new FunCurrentTime(*this); + } + //------------------------------------------------------------------------------ // | // Functions for regex matching | diff --git a/parser/mpFuncCommon.h b/parser/mpFuncCommon.h index 7f8406a..e2c4226 100644 --- a/parser/mpFuncCommon.h +++ b/parser/mpFuncCommon.h @@ -198,6 +198,19 @@ MUP_NAMESPACE_START virtual IToken* Clone() const override; }; // class FunTimeDiff + //------------------------------------------------------------------------------ + /** \brief Returns the current time in the HH:MM:SS format. + \ingroup functions + */ + class FunCurrentTime : public ICallback + { + public: + FunCurrentTime(); + virtual void Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) override; + virtual const char_type* GetDesc() const override; + virtual IToken* Clone() const override; + }; // class FunCurrentTime + //------------------------------------------------------------------------------ /** \brief Return the capture group of a regular expression. \ingroup functions diff --git a/parser/mpPackageCommon.cpp b/parser/mpPackageCommon.cpp index d3cb474..1add84c 100644 --- a/parser/mpPackageCommon.cpp +++ b/parser/mpPackageCommon.cpp @@ -107,6 +107,7 @@ void PackageCommon::AddToParser(ParserXBase *pParser) // Time functions pParser->DefineFun(new FunTimeDiff()); + pParser->DefineFun(new FunCurrentTime()); // misc pParser->DefineFun(new FunParserID); From 0f3a329473a3d2f44643173dcddc931e05532ff2 Mon Sep 17 00:00:00 2001 From: Eduardo Rodrigues Seifert Date: Sat, 16 Nov 2024 17:35:46 -0300 Subject: [PATCH 2/9] Add tests --- tests.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests.sh b/tests.sh index c7c03f0..c2f4d76 100755 --- a/tests.sh +++ b/tests.sh @@ -184,6 +184,9 @@ test_eval 'timediff("02:00:00", "03:30:00")' '1.5' test_eval 'timediff("03:30:00", "02:00:00")' '22.5' test_eval 'timediff("02:00:00", "02:00:30")' '0.01' +current_time=$(echo `date +"%H:%M:%S"`) +test_eval 'current_time()' "\"$current_time\"" + # Mask tests test_eval 'mask("000-000", 123456)' '"123-456"' test_eval 'mask("00000", 14)' '"00014"' From 06f4528e6fe3a164023574930c9be2027ac657db Mon Sep 17 00:00:00 2001 From: Eduardo Rodrigues Seifert Date: Fri, 22 Nov 2024 14:26:27 -0300 Subject: [PATCH 3/9] Add hour offset calculation --- parser/mpFuncCommon.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/parser/mpFuncCommon.cpp b/parser/mpFuncCommon.cpp index f72dd9d..e87e257 100644 --- a/parser/mpFuncCommon.cpp +++ b/parser/mpFuncCommon.cpp @@ -809,9 +809,14 @@ MUP_NAMESPACE_START // | //------------------------------------------------------------------------------ - string_type format_time (struct tm time) { + int calculate_hour_offset(int original_hour, int gmt_offset) { + return ((original_hour + gmt_offset) % 24 + 24) % 24; + } + + string_type format_time (struct tm time, int gmt_offset) { char buffer[9]; - snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d", time.tm_hour, time.tm_min, time.tm_sec); + int hours = calculate_hour_offset(time.tm_hour, gmt_offset); + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d", hours, time.tm_min, time.tm_sec); return std::string(buffer); } @@ -882,13 +887,29 @@ MUP_NAMESPACE_START void FunCurrentTime::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) { - if (a_iArgc != 0) + int gmt_offset = 0; + if (a_iArgc > 1) { throw ParserError(ErrorContext(ecTOO_MANY_PARAMS, GetExprPos(), GetIdent())); + } else if (a_iArgc == 1) { + switch(a_pArg[0]->GetType()) + { + case 'i': gmt_offset = a_pArg[0]->GetInteger(); break; + default: + { + ErrorContext err; + err.Errc = ecTYPE_CONFLICT_FUN; + err.Arg = 1; + err.Type1 = a_pArg[0]->GetType(); + err.Type2 = 'i'; + throw ParserError(err); + } + } + } std::time_t t = std::time(0); std::tm now = *std::localtime(&t); - *ret = format_time(now); + *ret = format_time(now, gmt_offset); } ////------------------------------------------------------------------------------ From d132882b009036a7bec606308dd3e5cbc809fe1d Mon Sep 17 00:00:00 2001 From: Eduardo Rodrigues Seifert Date: Fri, 22 Nov 2024 15:37:40 -0300 Subject: [PATCH 4/9] Add tests for matching regex --- tests.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests.sh b/tests.sh index c2f4d76..7d9319c 100755 --- a/tests.sh +++ b/tests.sh @@ -32,6 +32,21 @@ exit" | ./example | grep -E "(ans =|Can't evaluate function/operator \".*\":)") esac } +function match_regex() { + input="$1" + regex="$2" + + output=$(echo "$input +exit" | ./example | grep -E "(ans =|Can't evaluate function/operator \".*\":)") + + if echo "$output" | egrep -q "$regex"; then + printf "\e[32mTest passed for input $input\e[0m\n" + else + printf "\e[31mTest failed for input $input: regex did not match\e[0m\n" + exit 1 + fi +} + # Arithmetic tests test_eval "2 + 2" "4" test_eval "55 * 33" "1815" @@ -329,5 +344,8 @@ test_eval 'weekday("2019-03-21", "invalidlocale")' 'The chosen locale is not sup test_eval 'weekday("2024-32-21")' 'Invalid format on the parameter(s). Please use two "yyyy-mm-dd" for dates OR two "yyyy-mm-ddTHH:MM" for date_times.' test_eval 'weekday("2024-09-17", "en", "one too many params")' 'Too many parameters passed to function "weekday".' +# Regex match test +match_regex 'current_time(5)' '\b([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\b' + echo "All tests passed!" From e222b0f447cfb01019083e580d6f32b713d01db0 Mon Sep 17 00:00:00 2001 From: Eduardo Rodrigues Seifert Date: Fri, 22 Nov 2024 15:54:59 -0300 Subject: [PATCH 5/9] Add failing case for bad offset --- parser/mpFuncCommon.cpp | 1 + tests.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/parser/mpFuncCommon.cpp b/parser/mpFuncCommon.cpp index e87e257..275833c 100644 --- a/parser/mpFuncCommon.cpp +++ b/parser/mpFuncCommon.cpp @@ -901,6 +901,7 @@ MUP_NAMESPACE_START err.Arg = 1; err.Type1 = a_pArg[0]->GetType(); err.Type2 = 'i'; + err.Ident = GetIdent(); throw ParserError(err); } } diff --git a/tests.sh b/tests.sh index 7d9319c..c21fcdb 100755 --- a/tests.sh +++ b/tests.sh @@ -201,6 +201,7 @@ test_eval 'timediff("02:00:00", "02:00:30")' '0.01' current_time=$(echo `date +"%H:%M:%S"`) test_eval 'current_time()' "\"$current_time\"" +test_eval 'current_time("2")' "Argument 1 of function/operator \"current_time\" is of type 's' whereas type 'i' was expected." # Mask tests test_eval 'mask("000-000", 123456)' '"123-456"' From bf59f54d81d6d3e9c6098c0e2694c18808092f41 Mon Sep 17 00:00:00 2001 From: Eduardo Rodrigues Seifert Date: Fri, 22 Nov 2024 16:02:26 -0300 Subject: [PATCH 6/9] improve description --- parser/mpFuncCommon.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/parser/mpFuncCommon.cpp b/parser/mpFuncCommon.cpp index 275833c..c29be20 100644 --- a/parser/mpFuncCommon.cpp +++ b/parser/mpFuncCommon.cpp @@ -876,9 +876,11 @@ MUP_NAMESPACE_START } //------------------------------------------------------------------------------ - // - // class FunCurrentTime - // + // | + // class FunCurrentTime | + // Usage: current_time() | + // Optional offset: current_time(-2) | + // | //------------------------------------------------------------------------------ FunCurrentTime::FunCurrentTime() @@ -913,13 +915,13 @@ MUP_NAMESPACE_START *ret = format_time(now, gmt_offset); } - ////------------------------------------------------------------------------------ + ////--------------------------------------------------------------------------------------------------------- const char_type* FunCurrentTime::GetDesc() const { - return _T("current_time() - Returns the current time in the HH:MM:SS format."); + return _T("current_time(offset) - Returns the current time in the HH:MM:SS format, applying the offset."); } - ////------------------------------------------------------------------------------ + ////--------------------------------------------------------------------------------------------------------- IToken* FunCurrentTime::Clone() const { return new FunCurrentTime(*this); From 280a45e8c710943911cbd9df8caf86fc1bc47ea0 Mon Sep 17 00:00:00 2001 From: Eduardo Rodrigues Seifert Date: Fri, 22 Nov 2024 16:05:35 -0300 Subject: [PATCH 7/9] Use gmtime instead of localtime and remove test --- parser/mpFuncCommon.cpp | 2 +- tests.sh | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/parser/mpFuncCommon.cpp b/parser/mpFuncCommon.cpp index c29be20..2f28f58 100644 --- a/parser/mpFuncCommon.cpp +++ b/parser/mpFuncCommon.cpp @@ -910,7 +910,7 @@ MUP_NAMESPACE_START } std::time_t t = std::time(0); - std::tm now = *std::localtime(&t); + std::tm now = *std::gmtime(&t); *ret = format_time(now, gmt_offset); } diff --git a/tests.sh b/tests.sh index c21fcdb..815d1c3 100755 --- a/tests.sh +++ b/tests.sh @@ -199,8 +199,6 @@ test_eval 'timediff("02:00:00", "03:30:00")' '1.5' test_eval 'timediff("03:30:00", "02:00:00")' '22.5' test_eval 'timediff("02:00:00", "02:00:30")' '0.01' -current_time=$(echo `date +"%H:%M:%S"`) -test_eval 'current_time()' "\"$current_time\"" test_eval 'current_time("2")' "Argument 1 of function/operator \"current_time\" is of type 's' whereas type 'i' was expected." # Mask tests From 7b6c6b454ac53c7ef44cee85707676736fcc80f6 Mon Sep 17 00:00:00 2001 From: Eduardo Rodrigues Seifert Date: Fri, 22 Nov 2024 16:07:06 -0300 Subject: [PATCH 8/9] add tests for no offset and negative offset --- tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests.sh b/tests.sh index 815d1c3..b34a03a 100755 --- a/tests.sh +++ b/tests.sh @@ -345,6 +345,8 @@ test_eval 'weekday("2024-09-17", "en", "one too many params")' 'Too many paramet # Regex match test match_regex 'current_time(5)' '\b([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\b' +match_regex 'current_time()' '\b([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\b' +match_regex 'current_time(-3)' '\b([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\b' echo "All tests passed!" From e785d822196891f280c47182968d3387b88b5ab2 Mon Sep 17 00:00:00 2001 From: Eduardo Rodrigues Seifert Date: Fri, 22 Nov 2024 16:08:10 -0300 Subject: [PATCH 9/9] Should work even for big offset(what will be the current time 6 days from now?) --- tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests.sh b/tests.sh index b34a03a..8fdf8e3 100755 --- a/tests.sh +++ b/tests.sh @@ -347,6 +347,8 @@ test_eval 'weekday("2024-09-17", "en", "one too many params")' 'Too many paramet match_regex 'current_time(5)' '\b([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\b' match_regex 'current_time()' '\b([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\b' match_regex 'current_time(-3)' '\b([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\b' +match_regex 'current_time(-200)' '\b([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\b' + echo "All tests passed!"