diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index ec0a3b76..540fe19b 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -1262,6 +1262,27 @@ jobs: fi echo "[type-tests] iscon, isstr, isnum, isfloat, ispn and isarray" + - name: "-DATUM sets G($datum) (NLPPlus #1) (Non-20.04)" + if: matrix.id != 'docker-ubuntu-20.04' + shell: bash + run: | + set -eo pipefail + # NLP_ENGINE::setDatum and nlp -DATUM pass a string the analyzer + # reads as G("$datum"), eg the output format a caller wants. The + # engine API always passed none before. + FIX=.github/workflows/tests/datum + OUT="$FIX/input/text.txt_log/output.txt" + for v in json xml; do + rm -rf "$FIX/logs" "$FIX/input/text.txt_log" "$FIX/output" + mkdir -p "$FIX/logs" + ./bin/nlp -ANA "$FIX" -WORK ./ -DATUM "$v" "$FIX/input/text.txt" + got=$(tr -d '\r' < "$OUT") + if [ "$got" != "datum=[$v]" ]; then + echo "FAIL(datum): wanted datum=[$v], got: $got"; exit 1 + fi + done + echo "[datum] -DATUM reaches G(\$datum)" + - name: factorial() up to 20! (Non-20.04) if: matrix.id != 'docker-ubuntu-20.04' shell: bash diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 02e58ddd..280fdc7d 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -1153,6 +1153,26 @@ jobs: fi echo "[type-tests] iscon, isstr, isnum, isfloat, ispn and isarray" + - name: "-DATUM sets G($datum) (NLPPlus #1)" + shell: bash + run: | + set -eo pipefail + # NLP_ENGINE::setDatum and nlp -DATUM pass a string the analyzer + # reads as G("$datum"), eg the output format a caller wants. The + # engine API always passed none before. + FIX=.github/workflows/tests/datum + OUT="$FIX/input/text.txt_log/output.txt" + for v in json xml; do + rm -rf "$FIX/logs" "$FIX/input/text.txt_log" "$FIX/output" + mkdir -p "$FIX/logs" + ./bin/Release/nlp.exe -ANA "$FIX" -WORK ./ -DATUM "$v" "$FIX/input/text.txt" + got=$(tr -d '\r' < "$OUT") + if [ "$got" != "datum=[$v]" ]; then + echo "FAIL(datum): wanted datum=[$v], got: $got"; exit 1 + fi + done + echo "[datum] -DATUM reaches G(\$datum)" + - name: factorial() up to 20! shell: bash run: | diff --git a/.github/workflows/tests/datum/input/text.txt b/.github/workflows/tests/datum/input/text.txt new file mode 100644 index 00000000..587be6b4 --- /dev/null +++ b/.github/workflows/tests/datum/input/text.txt @@ -0,0 +1 @@ +x diff --git a/.github/workflows/tests/datum/spec/analyzer.seq b/.github/workflows/tests/datum/spec/analyzer.seq new file mode 100644 index 00000000..74aa7849 --- /dev/null +++ b/.github/workflows/tests/datum/spec/analyzer.seq @@ -0,0 +1,2 @@ +tokenize nil # +nlp show # diff --git a/.github/workflows/tests/datum/spec/show.nlp b/.github/workflows/tests/datum/spec/show.nlp new file mode 100644 index 00000000..7c53a559 --- /dev/null +++ b/.github/workflows/tests/datum/spec/show.nlp @@ -0,0 +1,9 @@ +############################################### +# FILE: show.nlp +# SUBJ: Print G("$datum"), set by nlp -DATUM or NLP_ENGINE::setDatum. +# NOTE: Part of the datum regression; expected output is in the CI step. +############################################### + +@CODE +"output.txt" << "datum=[" << G("$datum") << "]\n"; +@@CODE diff --git a/include/Api/lite/nlp_engine.h b/include/Api/lite/nlp_engine.h index 2c910ca3..6a705649 100644 --- a/include/Api/lite/nlp_engine.h +++ b/include/Api/lite/nlp_engine.h @@ -166,6 +166,11 @@ class LITE_API NLP_ENGINE int close(); int close(_TCHAR *analyzer); + // A string every later analysis sees as G("$datum"), eg the output + // format the caller wants. Empty (the default) means none. + void setDatum(const _TCHAR *datum); + const _TCHAR *getDatum(); + private: void analyzeFile(const std::string &file, _TCHAR *outdir, std::_t_ofstream *fp); int createDir(_TCHAR *dirPath); @@ -175,4 +180,8 @@ class LITE_API NLP_ENGINE // close() must key the VTRun analyzer registry on this so the same analyzer // passed as different path-forms maps to one entry -- see #658 / #380. void anaRegName(const _TCHAR *path, _TCHAR *out); + _TCHAR *datumArg(); + + // At the end of the class, so its layout is unchanged before it. + std::basic_string<_TCHAR> m_datum; // G("$datum") for analyses. }; \ No newline at end of file diff --git a/lite/nlp_engine.cpp b/lite/nlp_engine.cpp index 4ad7029b..6272d224 100644 --- a/lite/nlp_engine.cpp +++ b/lite/nlp_engine.cpp @@ -632,7 +632,8 @@ void NLP_ENGINE::analyzeFile( m_compiled, // If running compiled analyzer. &std::_t_cout, // Stream for cout() in NLP++ obuf, // 05/11/02 AM. - MAXSTR // 05/11/02 AM. + MAXSTR, // 05/11/02 AM. + datumArg() // G("$datum"). ); // A caller reading a stream's cout() output needs each input's share now, @@ -686,7 +687,8 @@ int NLP_ENGINE::analyze( m_compiled, // If running compiled analyzer. &std::_t_cout, // Stream for cout() in NLP++ outbuf, // 05/11/02 AM. - outlen // 05/11/02 AM. + outlen, // 05/11/02 AM. + datumArg() // G("$datum"). ); //std::_t_cout << _T("AFTER ANALYSIS: ") << std::endl; // 09/27/20 AM. @@ -735,7 +737,7 @@ int NLP_ENGINE::analyze( m_outdir, m_compiled, // If running compiled analyzer. &std::_t_cout, // Stream for cout() in NLP++ - NULL // datum + datumArg() // G("$datum"); was always NULL. ); @@ -816,6 +818,19 @@ void NLP_ENGINE::setDictSource(bool on) { CG::setDictSource(on); // #432. } +void NLP_ENGINE::setDatum(const _TCHAR *datum) { + m_datum = datum ? datum : _T(""); +} + +const _TCHAR *NLP_ENGINE::getDatum() { + return m_datum.c_str(); +} + +// The datum to pass to an analysis: 0 when unset, as before. +_TCHAR *NLP_ENGINE::datumArg() { + return m_datum.empty() ? 0 : (_TCHAR *) m_datum.c_str(); +} + int NLP_ENGINE::createDir(_TCHAR *dirPath) { std::error_code ec; // #323. if (!std::filesystem::exists(std::filesystem::path(dirPath), ec)) { diff --git a/nlp/main.cpp b/nlp/main.cpp index 0954ac2b..aba38fa3 100644 --- a/nlp/main.cpp +++ b/nlp/main.cpp @@ -15,9 +15,9 @@ All rights reserved. #include "lite/nlp_engine.h" #include "version.h" -#define NLP_ENGINE_VERSION "4.2.35" +#define NLP_ENGINE_VERSION "4.2.36" -bool cmdReadArgs(int, _TCHAR *argv[], _TCHAR *&, _TCHAR *&, _TCHAR *&, _TCHAR *&, bool &, bool &, bool &, bool &, bool &, bool &, int &, bool &, bool &); +bool cmdReadArgs(int, _TCHAR *argv[], _TCHAR *&, _TCHAR *&, _TCHAR *&, _TCHAR *&, bool &, bool &, bool &, bool &, bool &, bool &, int &, bool &, bool &, _TCHAR *&); void cmdHelpargs(_TCHAR *); #include "lite/nlpdebug.h" @@ -47,13 +47,14 @@ int _tmain( int debugPort = 0; // -debug : rule-level debug server. 0 = off. bool stream = false; // -STDIN: read input file paths from stdin. bool dictSource = false; // -DICTSOURCE: nodes record their .dict file and line. + _TCHAR *datum = 0; // -DATUM value: G("$datum") in the analyzer. ///////////////////////////////////////////////// // GET APP INFORMATION ///////////////////////////////////////////////// // Get analyzer name, input and output filenames from command line. - if (!cmdReadArgs(argc, argv, analyzerpath, input, output, workdir, develop, compile, compiled, silent, compileKB, compileAna, debugPort, stream, dictSource)) + if (!cmdReadArgs(argc, argv, analyzerpath, input, output, workdir, develop, compile, compiled, silent, compileKB, compileAna, debugPort, stream, dictSource, datum)) exit(1); if (dictSource) NLP_ENGINE::setDictSource(true); // #432. @@ -70,6 +71,8 @@ int _tmain( // No -WORK means the current folder. Passing the null pointer on to the // std::string parameter was undefined behavior and crashed (#347). // 10/13/26 DD. NLP_ENGINE *nlpEngine = new NLP_ENGINE(workdir ? workdir : _T("")); + if (datum) + nlpEngine->setDatum(datum); if (compile) { // Compile mode: generate C++ code for the analyzer and KB. @@ -133,7 +136,8 @@ bool cmdReadArgs( bool &compileAna, // true - compile only the analyzer to C++. int &debugPort, // -debug : rule-level debug server. 0 = off. bool &stream, // -STDIN: read input file paths from stdin. - bool &dictSource // -DICTSOURCE: nodes record their .dict file and line. + bool &dictSource, // -DICTSOURCE: nodes record their .dict file and line. + _TCHAR *&datum // -DATUM value: G("$datum") in the analyzer. ) { _TCHAR *ptr; @@ -144,6 +148,7 @@ bool cmdReadArgs( bool f_out = false; bool f_work = false; bool f_debug = false; + bool f_datum = false; bool flag = false; bool compiledck = false; // If compiled/interp arg seen. bool doubledash = false; @@ -226,6 +231,8 @@ bool cmdReadArgs( f_work = flag = true; // Expecting output file. else if (!strcmp_i(ptr, _T("debug"))) f_debug = flag = true; // Expecting a TCP port. + else if (!strcmp_i(ptr, _T("datum"))) + f_datum = flag = true; // Expecting G("$datum"). else if (!strcmp_i(ptr, _T("dev"))) // 12/25/98 AM. { if (silent) @@ -345,6 +352,11 @@ bool cmdReadArgs( workdir = ptr; f_work = flag = false; } + else if (f_datum) + { + datum = ptr; + f_datum = flag = false; + } else if (f_debug) { debugPort = _ttoi(ptr); @@ -377,7 +389,7 @@ bool cmdReadArgs( { // The last argument was an option that takes a value, eg "-ANA". std::_t_cerr << _T("[") << argv[0] << _T(": ") - << (f_ana ? _T("-ANA") : f_in ? _T("-IN") : f_out ? _T("-OUT") : f_work ? _T("-WORK") : _T("-DEBUG")) + << (f_ana ? _T("-ANA") : f_in ? _T("-IN") : f_out ? _T("-OUT") : f_work ? _T("-WORK") : f_datum ? _T("-DATUM") : _T("-DEBUG")) << _T(" needs a value.]") << std::endl; cmdHelpargs(argv[0]); return false; @@ -425,6 +437,7 @@ void cmdHelpargs(_TCHAR *name) << _T(" [-STDIN] load once, then analyze one input file path per stdin line;") << std::endl << _T(" a blank line or EOF ends the run. Each input is analyzed") << std::endl << _T(" when the next line arrives, so $islastfile can be set.") << std::endl + << _T(" [-DATUM value] pass a string the analyzer reads as G(\"$datum\")") << std::endl << _T(" [-DICTSOURCE] nodes built from .dict entries get dictfile and dictline") << std::endl << _T(" attributes naming the entry's file and line") << std::endl << std::endl