This should be a refactor except in the cases where we use the wrong format specifier [1], in which case this patch is a bug fix.
[1] : e.g. depends: Add libevent compatibility patch for windows #8730
This should be a refactor except in the cases where we use the wrong format specifier [1], in which case this patch is a bug fix.
[1] : e.g. depends: Add libevent compatibility patch for windows #8730
Nice. Concept ACK.
Wasn't aware we had so many uses of fprintf.
We should probably change the linter to prevent it from being used again.
This might do it:
diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh
index 2b6c78c2c841b7cab90ce11b831ea1051118029e..b0c5ce39b1aba1c52b9b23c7451ac46d33cc6c67 100755
--- a/test/lint/lint-locale-dependence.sh
+++ b/test/lint/lint-locale-dependence.sh
@@ -8,7 +8,6 @@ KNOWN_VIOLATIONS=(
"src/dbwrapper.cpp:.*vsnprintf"
"src/httprpc.cpp.*trim"
"src/init.cpp:.*atoi"
- "src/init.cpp:.*fprintf"
"src/qt/rpcconsole.cpp:.*atoi"
"src/rest.cpp:.*strtol"
"src/test/dbwrapper_tests.cpp:.*snprintf"
@@ -189,8 +188,7 @@ GIT_GREP_OUTPUT=$(git grep -E "[^a-zA-Z0-9_\`'\"<>](${REGEXP_LOCALE_DEPENDENT_FU
EXIT_CODE=0
for LOCALE_DEPENDENT_FUNCTION in "${LOCALE_DEPENDENT_FUNCTIONS[@]}"; do
MATCHES=$(grep -E "[^a-zA-Z0-9_\`'\"<>]${LOCALE_DEPENDENT_FUNCTION}(_r|_s)?[^a-zA-Z0-9_\`'\"<>]" <<< "${GIT_GREP_OUTPUT}" | \
- grep -vE "\.(c|cpp|h):\s*(//|\*|/\*|\").*${LOCALE_DEPENDENT_FUNCTION}" | \
- grep -vE 'fprintf\(.*(stdout|stderr)')
+ grep -vE "\.(c|cpp|h):\s*(//|\*|/\*|\").*${LOCALE_DEPENDENT_FUNCTION}")
if [[ ${REGEXP_IGNORE_EXTERNAL_DEPENDENCIES} != "" ]]; then
MATCHES=$(grep -vE "${REGEXP_IGNORE_EXTERNAL_DEPENDENCIES}" <<< "${MATCHES}")
fi
-BEGIN VERIFY SCRIPT-
sed -i --regexp-extended -e 's/fprintf\(std(err|out), /tfm::format(std::c\1, /g' $(git grep -l 'fprintf(' -- ':(exclude)src/crypto' ':(exclude)src/leveldb' ':(exclude)src/univalue' ':(exclude)src/secp256k1')
-END VERIFY SCRIPT-
fixup! scripted-diff: Replace fprintf with tfm::formatConcept ACK
<!--e57a25ab6845829454e8d69fc972939a-->
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
<!--174a7506f384e20aa4161008e828411d-->
Reviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.
Concept ACK, will test in a bit.
ACK fa8f195195945ce6258199af0461e3fbfbc1236d. Ideally this should be rebased before merge.
utACK fa8f195195945ce6258199af0461e3fbfbc1236d
When reviewing please note that tfm::format in contrast to fprintf may throw (tinyformat::format_error). That is not necessarily a problem obviously, but it is worth to have in mind when analysing the change in possible code paths from this change.
103 | @@ -104,10 +104,10 @@ static int AppInitRawTx(int argc, char* argv[]) 104 | "\n"; 105 | strUsage += gArgs.GetHelpMessage(); 106 | 107 | - fprintf(stdout, "%s", strUsage.c_str()); 108 | + tfm::format(std::cout, "%s", strUsage.c_str()); 109 | 110 | if (argc < 2) { 111 | - fprintf(stderr, "Error: too few parameters\n"); 112 | + tfm::format(std::cerr, "Error: too few parameters\n");
nit: a few of these could drop formatting altogether, via <<
I believe tfm uses << under the hood, so it shouldn't matter.
Yeah, the output should be the same, just would remove a layer of indirection.
that's just a matter of style; it seems most of the developers of this code base prefer %X formatting to the various << incantations (hence the use of tinyformat in the first place), so consistently using tfm::format seems good to me
Fair enough. Just a nit.
When reviewing please note that tfm::format in contrast to fprintf may throw (tinyformat::format_error). That is not necessarily a problem obviously, but it is worth to have in mind when analysing the change in possible code paths from this change.
Another thing to be careful of is to not use stderr and std::cerr in a mixed way due to potential buffering issues. So it's essential to do this switch in one go (which is the intent so that's fine).
code review and lightly tested ACK fa8f195195945ce6258199af0461e3fbfbc1236d
56 | @@ -57,7 +57,7 @@ struct CLockLocation { 57 | 58 | std::string ToString() const 59 | { 60 | - return tfm::format( 61 | + return strprintf(
IIUC this change is only required due to the test/lint/lint-format-strings.sh linter change in fa8f195195945ce6258199af0461e3fbfbc1236d of this PR.
E.g. if the above line is not changed then ./test/lint/lint-format-strings.sh will raise
src/sync.cpp: Expected 0 argument(s) after format string but found 4 argument(s): tfm::format( "%s %s:%s%s (in thread %s)", mutexName, sourceFile, itostr(sourceLine), (fTry ? " (TRY)" : ""), m_thread_name)
whereas on master it does not raise.
Perhaps an quick note in the commit and PR description explaining why this changed could be helpful.
Correct, but I didn't rewrite the commits to preserve the acks.
ACK fa8f195195945ce6258199af0461e3fbfbc1236d from light code review, building, and running linter/unit tests/extended functional tests.
Post-merge utACK
Looks like this accidentally fixed multiple test failures with the cross-compiled windows binaries:
feature_config_args:Traceback (most recent call last):
File "C:\Users\travis\build\MarcoFalke\btc_nightly\bitcoin\test\functional\test_framework\test_framework.py", line 193, in main
self.run_test()
File "C:\Users\travis\build\MarcoFalke\btc_nightly\bitcoin\/test/functional/feature_config_args.py", line 67, in run_test
self.test_config_file_parser()
File "C:\Users\travis\build\MarcoFalke\btc_nightly\bitcoin\/test/functional/feature_config_args.py", line 57, in test_config_file_parser
self.nodes[0].stop_node(expected_stderr='Warning: ' + inc_conf_file_path + ':1 Section [testnot] is not recognized.' + os.linesep + 'Warning: ' + inc_conf_file2_path + ':1 Section [testnet] is not recognized.')
File "C:\Users\travis\build\MarcoFalke\btc_nightly\bitcoin\test\functional\test_framework\test_node.py", line 276, in stop_node
raise AssertionError("Unexpected stderr {} != {}".format(stderr, expected_stderr))
AssertionError: Unexpected stderr != Warning: C:\Users\travis\AppData\Local\Temp\test_runner_₿_🏃_20190617_121557\feature_config_args_3\node0\include.conf:1 Section [testnot] is not recognized.
feature_includeconfTraceback (most recent call last):
File "C:\Users\travis\build\MarcoFalke\btc_nightly\bitcoin\test\functional\test_framework\test_framework.py", line 193, in main
self.run_test()
File "C:\Users\travis\build\MarcoFalke\btc_nightly\bitcoin\/test/functional/feature_includeconf.py", line 55, in run_test
self.stop_node(0, expected_stderr="warning: -includeconf cannot be used from included files; ignoring -includeconf=relative2.conf")
File "C:\Users\travis\build\MarcoFalke\btc_nightly\bitcoin\test\functional\test_framework\test_framework.py", line 390, in stop_node
self.nodes[i].stop_node(expected_stderr, wait=wait)
File "C:\Users\travis\build\MarcoFalke\btc_nightly\bitcoin\test\functional\test_framework\test_node.py", line 276, in stop_node
raise AssertionError("Unexpected stderr {} != {}".format(stderr, expected_stderr))
AssertionError: Unexpected stderr != warning: -includeconf cannot be used from included files; ignoring -includeconf=relative2.conf
tool_walletTraceback (most recent call last):
File "C:\Users\travis\build\MarcoFalke\btc_nightly\bitcoin\test\functional\test_framework\test_framework.py", line 193, in main
self.run_test()
File "C:\Users\travis\build\MarcoFalke\btc_nightly\bitcoin\/test/functional/tool_wallet.py", line 61, in run_test
self.assert_tool_output(out, '-wallet=wallet.dat', 'info')
File "C:\Users\travis\build\MarcoFalke\btc_nightly\bitcoin\/test/functional/tool_wallet.py", line 37, in assert_tool_output
assert_equal(stdout, output)
File "C:\Users\travis\build\MarcoFalke\btc_nightly\bitcoin\test\functional\test_framework\util.py", line 39, in assert_equal
raise AssertionError("not(%s)" % " == ".join(str(arg) for arg in (thing1, thing2) + args))
AssertionError: not(Wallet info
===========
Encrypted: no
HD (hd seed available): yes
Keypool Size: 2
Transactions: zu
Address Book: zu
== Wallet info
===========
Encrypted: no
HD (hd seed available): yes
Keypool Size: 2
Transactions: 0
Address Book: 3
)
I am going to backport this, since it turned out to be a bugfix