aboutsummaryrefslogtreecommitdiff
path: root/openssl/diagnostics.hxx
blob: 49111e73ecf6d5f5e356b7d1fa64022151a527fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// file      : openssl/diagnostics.hxx -*- C++ -*-
// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#ifndef OPENSSL_DIAGNOSTICS_HXX
#define OPENSSL_DIAGNOSTICS_HXX

#include <libbutl/diagnostics.mxx>

#include <openssl/types.hxx> // Note: not <openssl/utility.hxx>.

namespace openssl
{
  using butl::diag_record;

  // Throw this exception to terminate the process. The handler should
  // assume that the diagnostics has already been issued.
  //
  class failed: public std::exception {};

  // Diagnostic facility, base infrastructure.
  //
  using butl::diag_stream;
  using butl::diag_epilogue;

  // Diagnostic facility, project specifics.
  //
  struct simple_prologue_base
  {
    explicit
    simple_prologue_base (const char* type, const char* name, const char* data)
        : type_ (type), name_ (name), data_ (data) {}

    void
    operator() (const diag_record& r) const;

  private:
    const char* type_;
    const char* name_;
    const char* data_;
  };

  struct basic_mark_base
  {
    using simple_prologue = butl::diag_prologue<simple_prologue_base>;

    // If data if not NULL, then we print it as (data) after name. For
    // example:
    //
    // error: main(foo): bar
    //
    explicit
    basic_mark_base (const char* type,
                     const char* name = nullptr,
                     const char* data = nullptr,
                     diag_epilogue* epilogue = nullptr)
        : type_ (type), name_ (name), data_ (data), epilogue_ (epilogue) {}

    simple_prologue
    operator() () const
    {
      return simple_prologue (epilogue_, type_, name_, data_);
    }

  public:
    const char* type_;
    const char* name_;
    const char* data_;

    diag_epilogue* const epilogue_;
  };
  using basic_mark = butl::diag_mark<basic_mark_base>;

  extern basic_mark error;
  extern basic_mark warn;
  extern basic_mark info;
  extern basic_mark text;

  // fail
  //
  struct fail_mark_base: basic_mark_base
  {
    explicit
    fail_mark_base (const char* type, const char* data = nullptr)
        : basic_mark_base (type,
                           nullptr,
                           data,
                           [](const diag_record& r)
                           {
                             r.flush ();
                             throw failed ();
                           }) {}
  };

  using fail_mark = butl::diag_mark<fail_mark_base>;

  struct fail_end_base
  {
    [[noreturn]] void
    operator() (const diag_record& r) const
    {
      // If we just throw then the record's destructor will see an active
      // exception and will not flush the record.
      //
      r.flush ();
      throw failed ();
    }
  };
  using fail_end = butl::diag_noreturn_end<fail_end_base>;

  extern fail_mark fail;
  extern const fail_end endf;
}

#endif // OPENSSL_DIAGNOSTICS_HXX