From e350f28e26a99785a8fdbf8ec3976f9f08c06d7c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 17 Jan 2025 18:06:31 -0500 Subject: [PATCH] refactor how error output is created and only print input and parsed line if they differ in text --- src/error.cpp | 29 +++------------- src/fix_ave_time.cpp | 2 +- src/input.h | 1 + src/utils.cpp | 82 +++++++++++++++++++++++++++++--------------- src/utils.h | 4 +-- 5 files changed, 63 insertions(+), 55 deletions(-) diff --git a/src/error.cpp b/src/error.cpp index d03e5453e9..6dbd0a20b3 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -121,16 +121,9 @@ void Error::all(const std::string &file, int line, int failed, const std::string std::string lastcmd = "(unknown)"; std::string mesg = "ERROR: " + str + fmt::format(" ({}:{})\n", truncpath(file), line); - if (input && input->line) lastcmd = input->line; + // add text about the input following the error message - if (failed > NOLASTLINE) { - try { - mesg += fmt::format("Last input line: {}\n", lastcmd); - if (failed > NOPOINTER) mesg += utils::point_to_error(input, failed); - } catch (fmt::format_error &) { - ; // do nothing - } - } + if (failed > NOLASTLINE) mesg += utils::point_to_error(input, failed); if (comm->me == 0) utils::logmesg(lmp,mesg); // allow commands if an exception was caught in a run @@ -153,23 +146,11 @@ void Error::all(const std::string &file, int line, int failed, const std::string void Error::one(const std::string &file, int line, int failed, const std::string &str) { - int me; std::string lastcmd = "(unknown)"; - MPI_Comm_rank(world,&me); - if (input && input->line) lastcmd = input->line; - std::string mesg; - try { - if (failed == NOLASTLINE) { - mesg = fmt::format("ERROR on proc {}: {} ({}:{})\n", me, str, truncpath(file), line); - } else { - mesg = fmt::format("ERROR on proc {}: {} ({}:{})\nLast input line: {}\n", - me, str, truncpath(file), line, lastcmd); - } - if (failed > NOPOINTER) mesg += utils::point_to_error(input, failed); - } catch (fmt::format_error &) { - ; // do nothing - } + std::string mesg = fmt::format("ERROR on proc {}: {} ({}:{})\n", comm->me, str, + truncpath(file), line); + if (failed > NOPOINTER) mesg += utils::point_to_error(input, failed); utils::logmesg(lmp,mesg); if (universe->nworlds > 1) diff --git a/src/fix_ave_time.cpp b/src/fix_ave_time.cpp index 8c7d902b86..7efb8cc8a6 100644 --- a/src/fix_ave_time.cpp +++ b/src/fix_ave_time.cpp @@ -1075,7 +1075,7 @@ void FixAveTime::options(int iarg, int narg, char **arg) if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix ave/time mode", error); if (strcmp(arg[iarg+1],"scalar") == 0) mode = SCALAR; else if (strcmp(arg[iarg+1],"vector") == 0) mode = VECTOR; - else error->all(FLERR,"Unknown fix ave/time mode {}", arg[iarg+1]); + else error->all(FLERR,iarg+1,"Unknown fix ave/time mode {}", arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"off") == 0) { if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "fix ave/time off", error); diff --git a/src/input.h b/src/input.h index e71ee22174..728c224835 100644 --- a/src/input.h +++ b/src/input.h @@ -26,6 +26,7 @@ class Input : protected Pointers { friend class Error; friend class Deprecated; friend class SimpleCommandsTest_Echo_Test; + friend std::string utils::point_to_error(Input *input, int failed); public: char *command; // ptr to current command diff --git a/src/utils.cpp b/src/utils.cpp index b72a9f1be3..4f1a0cb3fa 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -158,39 +158,65 @@ void utils::missing_cmd_args(const std::string &file, int line, const std::strin std::string utils::point_to_error(Input *input, int failed) { if (input) { - std::string cmdline = "--> parsed line: "; - int indicator = cmdline.size(); // error indicator points to command by default - cmdline += input->command; - cmdline += ' '; + std::string lastline = input->line; + std::string lastargs = input->command; + std::string cmdline = "Last input line: "; - // assemble pre-processed command line and update error indicator position, if needed. - for (int i = 0; i < input->narg; ++i) { - std::string inputarg = input->arg[i]; - if (i == failed) indicator = cmdline.size(); + // extended output + if (failed > Error::NOPOINTER) { - // argument contains whitespace. add quotes. check which type of quotes, too - if (inputarg.find_first_of(" \t\n") != std::string::npos) { - if (inputarg.find_first_of('"') != std::string::npos) { - cmdline += "'"; - cmdline += inputarg; - cmdline += "'"; - } else { - cmdline += '"'; - cmdline += inputarg; - cmdline += '"'; - } - } else - cmdline += inputarg; - cmdline += ' '; + // indicator points to command by default + int indicator = 0; + int quoted = 0; + lastargs += ' '; + + // assemble pre-processed command line and update error indicator position, if needed. + for (int i = 0; i < input->narg; ++i) { + std::string inputarg = input->arg[i]; + if (i == failed) indicator = lastargs.size(); + + // argument contains whitespace. add quotes. check which type of quotes, too + if (inputarg.find_first_of(" \t\n") != std::string::npos) { + if (i == failed) quoted = 2; + if (inputarg.find_first_of('"') != std::string::npos) { + lastargs += "'"; + lastargs += inputarg; + lastargs += "'"; + } else { + lastargs += '"'; + lastargs += inputarg; + lastargs += '"'; + } + } else + lastargs += inputarg; + lastargs += ' '; + } + + indicator += cmdline.size(); + // the string is unchanged by substitution (ignoring whitespace), print output only once + if (utils::strsame(lastline, lastargs)) { + cmdline += lastargs; + } else { + cmdline += lastline; + cmdline += '\n'; + // must have the same number of chars as "Last input line: " used in the previous line + cmdline += "--> parsed line: "; + cmdline += lastargs; + } + + // construct and append error indicator line + cmdline += '\n'; + cmdline += std::string(indicator, ' '); + cmdline += std::string(strlen(input->arg[failed]) + quoted, '^'); + cmdline += '\n'; + + } else { + cmdline += input->line; + cmdline += '\n'; } - // construct and append error indicator line - cmdline += '\n'; - cmdline += std::string(indicator, ' '); - cmdline += std::string(strlen(input->arg[failed]), '^'); - cmdline += '\n'; return cmdline; } else - return std::string("(Failed command line text not available)"); + return std::string("(Failed input line text not available)"); } /* specialization for the case of just a single string argument */ diff --git a/src/utils.h b/src/utils.h index 1d1ce27de5..598ff56eb3 100644 --- a/src/utils.h +++ b/src/utils.h @@ -68,7 +68,7 @@ namespace utils { void missing_cmd_args(const std::string &file, int line, const std::string &cmd, Error *error); - /*! Create string with last command after pre-processing and pointing to arg with error + /*! Create string with last command and optionally pointing to arg with error * * This function is a helper function for error messages. It creates * @@ -349,7 +349,7 @@ namespace utils { template void bounds(const char *file, int line, const std::string &str, bigint nmin, bigint nmax, - TYPE &nlo, TYPE &nhi, Error *error, int failed = -2); // -2 = Error::NOPOINTER + TYPE &nlo, TYPE &nhi, Error *error, int failed = -2); // -2 = Error::NOPOINTER /*! Same as utils::bounds(), but string may be a typelabel *