+/** @brief Format an error string
+ * @param ec Error class
+ * @param err Error code (interpretation defined by @p ec)
+ * @param buffer Output buffer
+ * @param bufsize Size of output buffer
+ * @return Pointer to error string
+ *
+ * The return value may or may not be @p buffer.
+ */
+#if !_WIN32
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+const char *format_error(enum error_class ec, int err, char buffer[], size_t bufsize) {
+#if _WIN32
+ size_t n;
+ switch(ec) {
+ default:
+ if(!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ buffer,
+ bufsize,
+ NULL))
+ disorder_fatal(0, "FormatMessage failed");
+ n = strlen(buffer);
+ while(n > 0 && isspace((unsigned char)buffer[n-1]))
+ --n;
+ buffer[n] = 0;
+ return buffer;
+ case ec_errno:
+ strerror_s(buffer, bufsize, err);
+ return buffer;
+ case ec_none:
+ return "(none)";
+ }
+#else
+ switch(ec) {
+ default:
+ return strerror(err);
+ case ec_getaddrinfo:
+ return gai_strerror(err);
+ case ec_none:
+ return "(none)";
+ }
+#endif
+}
+