Repository: ledger/ledger (language: cpp)

Issue:
Build fails with boost 1.86
With Boost 1.86.0-2, I get the following error during build:
```
In file included from src/exprbase.h:56,
                 from src/draft.h:44,
                 from src/stats.cc:34
src/utils.h: In function ‘ledger::string ledger::sha1sum(const string&)’:
src/utils.h:602:18: error: cannot convert ‘unsigned int [5]’ to ‘unsigned char (&)[20]’
  602 |   sha.get_digest(message_digest);
      |                  ^~~~~~~~~~~~~~
      |                  |
      |                  unsigned int [5]
In file included from src/utils.h:46:
/usr/include/boost/uuid/detail/sha1.hpp:179:43: note:   initializing argument 1 of ‘void boost::uuids::detail::sha1::get_digest(unsigned char (&)[20])’
  179 | inline void sha1::get_digest(digest_type& digest)
      |                              ~~~~~~~~~~~~~^~~~~~
```
Build fails with boost 1.86
With Boost 1.86.0-2, I get the following error during build:
```
In file included from src/exprbase.h:56,
                 from src/draft.h:44,
                 from src/stats.cc:34
src/utils.h: In function ‘ledger::string ledger::sha1sum(const string&)’:
src/utils.h:602:18: error: cannot convert ‘unsigned int [5]’ to ‘unsigned char (&)[20]’
  602 |   sha.get_digest(message_digest);
      |                  ^~~~~~~~~~~~~~
      |                  |
      |                  unsigned int [5]
In file included from src/utils.h:46:
/usr/include/boost/uuid/detail/sha1.hpp:179:43: note:   initializing argument 1 of ‘void boost::uuids::detail::sha1::get_digest(unsigned char (&)[20])’
  179 | inline void sha1::get_digest(digest_type& digest)
      |                              ~~~~~~~~~~~~~^~~~~~
```


Discussion / hints:

Fix patch:
diff --git a/src/filters.cc b/src/filters.cc
index b5b7fb19f..523fa7959 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -237,8 +237,6 @@ void anonymize_posts::render_commodity(amount_t& amt)
 
 void anonymize_posts::operator()(post_t& post)
 {
-	boost::uuids::detail::sha1  sha;
-  unsigned int message_digest[5];
   bool         copy_xact_details = false;
 
   if (last_xact != post.xact) {
@@ -255,12 +253,7 @@ void anonymize_posts::operator()(post_t& post)
     std::ostringstream buf;
     buf << reinterpret_cast<boost::uintmax_t>(post.xact->payee.c_str())
         << integer_gen() << post.xact->payee.c_str();
-
-		sha.reset();
-    sha.process_bytes(buf.str().c_str(), buf.str().length());
-    sha.get_digest(message_digest);
-
-    xact.payee = to_hex(message_digest);
+    xact.payee = sha1sum(buf.str(), 8);
     xact.note  = none;
   } else {
     xact.journal = post.xact->journal;
@@ -273,12 +266,7 @@ void anonymize_posts::operator()(post_t& post)
        acct = acct->parent) {
     std::ostringstream buf;
     buf << integer_gen() << acct << acct->fullname();
-
-    sha.reset();
-    sha.process_bytes(buf.str().c_str(), buf.str().length());
-    sha.get_digest(message_digest);
-
-    account_names.push_front(to_hex(message_digest));
+    account_names.push_front(sha1sum(buf.str(), 8));
   }
 
   account_t * new_account =
@@ -1269,7 +1257,7 @@ void budget_posts::report_budget_items(const date_t& date)
     foreach (pending_posts_list::iterator& i, posts_to_erase)
       pending_posts.erase(i);
   }
-  
+
   if (pending_posts.size() == 0)
     return;
 
diff --git a/src/utils.h b/src/utils.h
index bc05ff4f9..13cf26f63 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -578,29 +578,39 @@ inline int peek_next_nonws(std::istream& in) {
     *_p = '\0';                                         \
   }
 
-inline string to_hex(unsigned int * message_digest, const int len = 1)
-{
+inline string digest_to_hex(
+  const boost::uuids::detail::sha1::digest_type& message_digest,
+  size_t len = sizeof(boost::uuids::detail::sha1::digest_type) * 2
+) {
   std::ostringstream buf;
-
-  for(int i = 0; i < 5 ; i++) {
-    buf.width(8);
-    buf.fill('0');
-    buf << std::hex << message_digest[i];
-    if (i + 1 >= len)
-      break;                    // only output the first LEN dwords
+  buf.setf(std::ios_base::hex, std::ios_base::basefield);
+  buf.fill('0');
+
+  // sha1::digest_type is an array type and may change between Boost versions
+  const size_t count = std::min(
+    sizeof(message_digest) / sizeof(message_digest[0]),
+    (len - 1) / (sizeof(message_digest[0]) * 2) + 1
+  );
+  for(size_t i = 0; i < count; i++) {
+    buf.width(sizeof(message_digest[i]) * 2);
+    buf << (unsigned int)message_digest[i];
   }
-  return buf.str();
+  string hex = buf.str();
+  hex.resize(len, '0'); // in case a partial element is requested
+  return hex;
 }
 
-inline string sha1sum(const string& str)
-{
-	boost::uuids::detail::sha1 sha;
+inline string sha1sum(
+  const string& str,
+  size_t len = sizeof(boost::uuids::detail::sha1::digest_type) * 2
+) {
+	static boost::uuids::detail::sha1 sha;
+  boost::uuids::detail::sha1::digest_type message_digest;
 
+	sha.reset();
   sha.process_bytes(str.c_str(), str.length());
-
-  unsigned int message_digest[5];
   sha.get_digest(message_digest);
-  return to_hex(message_digest, 5);
+  return digest_to_hex(message_digest, len);
 }
 
 extern const string version;


Test patch: