This is an automated email from the ASF dual-hosted git repository.

zwoop pushed a commit to branch 8.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 05a6883ccdc6963f6cdb2438e2d86a7f847684fe
Author: Alan M. Carroll <a...@apache.org>
AuthorDate: Wed Jun 6 14:59:28 2018 -0500

    BWF: Add errno support.
    
    (cherry picked from commit 3d8ad11af446cffbc4ceb58a80b5604bdf391edb)
---
 .../internal-libraries/buffer-writer.en.rst        |  24 ++++
 lib/ts/BufferWriterFormat.cc                       | 160 +++++++++++++++++++++
 lib/ts/bwf_std_format.h                            |  14 ++
 lib/ts/unit-tests/test_BufferWriterFormat.cc       |  10 ++
 4 files changed, 208 insertions(+)

diff --git a/doc/developer-guide/internal-libraries/buffer-writer.en.rst 
b/doc/developer-guide/internal-libraries/buffer-writer.en.rst
index f8f19df..ced90d4 100644
--- a/doc/developer-guide/internal-libraries/buffer-writer.en.rst
+++ b/doc/developer-guide/internal-libraries/buffer-writer.en.rst
@@ -704,6 +704,30 @@ These are types for which there exists a type specific BWF 
formatter.
         bw.print("{:>20: =a}",addr); // -> "     172. 19.  3.105"
       }
 
+Format Classes
+++++++++++++++
+
+Although the extension for a format can be overloaded to provide additional 
features, this can become
+too confusing and complex to use if it is used for fundamentally different 
semantics on the same
+based type. In that case it is better to provide a format wrapper class that 
holds the base type
+but can be overloaded to produce different (wrapper class based) output. The 
classic example is
+:code:`errno` which is an integral type but frequently should be formatted 
with additional information
+such as the descriptive string for the value. To do this the format wrapper 
class :code:`ts::bwf::Errno`
+is provided. Using it is simple::
+
+    w.print("File not open - {}", ts::bwf::Errno(errno));
+
+which will produce output that looks like
+
+    "File not open - EACCES: Permission denied [13]"
+
+For :code:`errno` this is handy in another way as :code:`ts::bwf::Errno` will 
preserve the value of
+:code:`errno` across other calls that might change it. E.g.::
+
+    ts::bwf::Errno last_err(errno);
+    // some other code generating diagnostics that might tweak errno.
+    w.print("File not open - {}", last_err);
+
 Global Names
 ++++++++++++
 
diff --git a/lib/ts/BufferWriterFormat.cc b/lib/ts/BufferWriterFormat.cc
index 4bdd507..18384c9 100644
--- a/lib/ts/BufferWriterFormat.cc
+++ b/lib/ts/BufferWriterFormat.cc
@@ -22,6 +22,7 @@
  */
 
 #include <ts/BufferWriter.h>
+#include <ts/bwf_std_format.h>
 #include <unistd.h>
 #include <sys/param.h>
 #include <cctype>
@@ -755,6 +756,164 @@ bwf_register_global(std::string_view name, 
BWGlobalNameSignature formatter)
   return ts::bw_fmt::BWF_GLOBAL_TABLE.emplace(name, formatter).second;
 }
 
+BufferWriter &
+bwformat(BufferWriter &w, BWFSpec const &spec, bwf::Errno const &e)
+{
+  // Hand rolled, might not be totally compliant everywhere, but probably 
close enough.
+  // The long string will be locally accurate.
+  // Clang requires the double braces. Why, Turing only knows.
+  static const std::array<std::string_view, 134> SHORT_NAME = {{
+    "SUCCESS: ",
+    "EPERM: ",
+    "ENOENT: ",
+    "ESRCH: ",
+    "EINTR: ",
+    "EIO: ",
+    "ENXIO: ",
+    "E2BIG ",
+    "ENOEXEC: ",
+    "EBADF: ",
+    "ECHILD: ",
+    "EAGAIN: ",
+    "ENOMEM: ",
+    "EACCES: ",
+    "EFAULT: ",
+    "ENOTBLK: ",
+    "EBUSY: ",
+    "EEXIST: ",
+    "EXDEV: ",
+    "ENODEV: ",
+    "ENOTDIR: ",
+    "EISDIR: ",
+    "EINVAL: ",
+    "ENFILE: ",
+    "EMFILE: ",
+    "ENOTTY: ",
+    "ETXTBSY: ",
+    "EFBIG: ",
+    "ENOSPC: ",
+    "ESPIPE: ",
+    "EROFS: ",
+    "EMLINK: ",
+    "EPIPE: ",
+    "EDOM: ",
+    "ERANGE: ",
+    "EDEADLK: ",
+    "ENAMETOOLONG: ",
+    "ENOLCK: ",
+    "ENOSYS: ",
+    "ENOTEMPTY: ",
+    "ELOOP: ",
+    "EWOULDBLOCK: ",
+    "ENOMSG: ",
+    "EIDRM: ",
+    "ECHRNG: ",
+    "EL2NSYNC: ",
+    "EL3HLT: ",
+    "EL3RST: ",
+    "ELNRNG: ",
+    "EUNATCH: ",
+    "ENOCSI: ",
+    "EL2HTL: ",
+    "EBADE: ",
+    "EBADR: ",
+    "EXFULL: ",
+    "ENOANO: ",
+    "EBADRQC: ",
+    "EBADSLT: ",
+    "EDEADLOCK: ",
+    "EBFONT: ",
+    "ENOSTR: ",
+    "ENODATA: ",
+    "ETIME: ",
+    "ENOSR: ",
+    "ENONET: ",
+    "ENOPKG: ",
+    "EREMOTE: ",
+    "ENOLINK: ",
+    "EADV: ",
+    "ESRMNT: ",
+    "ECOMM: ",
+    "EPROTO: ",
+    "EMULTIHOP: ",
+    "EDOTDOT: ",
+    "EBADMSG: ",
+    "EOVERFLOW: ",
+    "ENOTUNIQ: ",
+    "EBADFD: ",
+    "EREMCHG: ",
+    "ELIBACC: ",
+    "ELIBBAD: ",
+    "ELIBSCN: ",
+    "ELIBMAX: ",
+    "ELIBEXEC: ",
+    "EILSEQ: ",
+    "ERESTART: ",
+    "ESTRPIPE: ",
+    "EUSERS: ",
+    "ENOTSOCK: ",
+    "EDESTADDRREQ: ",
+    "EMSGSIZE: ",
+    "EPROTOTYPE: ",
+    "ENOPROTOOPT: ",
+    "EPROTONOSUPPORT: ",
+    "ESOCKTNOSUPPORT: ",
+    "EOPNOTSUPP: ",
+    "EPFNOSUPPORT: ",
+    "EAFNOSUPPORT: ",
+    "EADDRINUSE: ",
+    "EADDRNOTAVAIL: ",
+    "ENETDOWN: ",
+    "ENETUNREACH: ",
+    "ENETRESET: ",
+    "ECONNABORTED: ",
+    "ECONNRESET: ",
+    "ENOBUFS: ",
+    "EISCONN: ",
+    "ENOTCONN: ",
+    "ESHUTDOWN: ",
+    "ETOOMANYREFS: ",
+    "ETIMEDOUT: ",
+    "ECONNREFUSED: ",
+    "EHOSTDOWN: ",
+    "EHOSTUNREACH: ",
+    "EALREADY: ",
+    "EINPROGRESS: ",
+    "ESTALE: ",
+    "EUCLEAN: ",
+    "ENOTNAM: ",
+    "ENAVAIL: ",
+    "EISNAM: ",
+    "EREMOTEIO: ",
+    "EDQUOT: ",
+    "ENOMEDIUM: ",
+    "EMEDIUMTYPE: ",
+    "ECANCELED: ",
+    "ENOKEY: ",
+    "EKEYEXPIRED: ",
+    "EKEYREVOKED: ",
+    "EKEYREJECTED: ",
+    "EOWNERDEAD: ",
+    "ENOTRECOVERABLE: ",
+    "ERFKILL: ",
+    "EHWPOISON: ",
+  }};
+  // This provides convenient safe access to the errno short name array.
+  auto short_name = [](int n) { return n < static_cast<int>(SHORT_NAME.size()) 
? SHORT_NAME[n] : "Unknown: "sv; };
+  static const BWFormat number_fmt{"[{}]"sv}; // numeric value format.
+  if (spec.has_numeric_type()) {              // if numeric type, print just 
the numeric part.
+    w.print(number_fmt, e._e);
+  } else {
+    w.write(short_name(e._e));
+    w.write(strerror(e._e));
+    if (spec._type != 's' && spec._type != 'S') {
+      w.write(' ');
+      w.print(number_fmt, e._e);
+    }
+  }
+  return w;
+}
+
 } // namespace ts
 
 namespace
@@ -808,6 +967,7 @@ static bool BW_INITIALIZED __attribute__((unused)) = []() 
-> bool {
   ts::bw_fmt::BWF_GLOBAL_TABLE.emplace("thread-name", &BWF_ThreadName);
   return true;
 }();
+
 } // namespace
 
 namespace std
diff --git a/lib/ts/bwf_std_format.h b/lib/ts/bwf_std_format.h
index 9ea50a5..fdc998f 100644
--- a/lib/ts/bwf_std_format.h
+++ b/lib/ts/bwf_std_format.h
@@ -34,3 +34,17 @@ bwformat(ts::BufferWriter &w, ts::BWFSpec const &spec, 
std::atomic<T> const &v)
   return ts::bwformat(w, spec, v.load());
 }
 } // end namespace std
+
+namespace ts
+{
+namespace bwf
+{
+  struct Errno {
+    int _e;
+    explicit Errno(int e) : _e(e) {}
+  };
+} // namespace bwf
+
+BufferWriter &bwformat(BufferWriter &w, BWFSpec const &spec, bwf::Errno const 
&e);
+
+} // namespace ts
diff --git a/lib/ts/unit-tests/test_BufferWriterFormat.cc 
b/lib/ts/unit-tests/test_BufferWriterFormat.cc
index 14986f8..f1f5f3a 100644
--- a/lib/ts/unit-tests/test_BufferWriterFormat.cc
+++ b/lib/ts/unit-tests/test_BufferWriterFormat.cc
@@ -481,6 +481,16 @@ TEST_CASE("BWFormat floating", "[bwprint][bwformat]")
   bw.reduce(0);
 }
 
+TEST_CASE("bwstring std formats", "[libts][bwprint]")
+{
+  ts::LocalBufferWriter<120> w;
+
+  w.print("{}", ts::bwf::Errno(13));
+  REQUIRE(w.view() == "EACCES: Permission denied [13]"sv);
+  w.reset().print("{}", ts::bwf::Errno(134));
+  REQUIRE(w.view().substr(0, 22) == "Unknown: Unknown error"sv);
+}
+
 // Normally there's no point in running the performance tests, but it's worth 
keeping the code
 // for when additional testing needs to be done.
 #if 0

Reply via email to