summaryrefslogtreecommitdiffstats
path: root/xbmc/commons/Exception.h
blob: ea2c9bc7c52e63254286a44cc8ebae825dadbf4a (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
/*
 *  Copyright (C) 2005-2018 Team Kodi
 *  This file is part of Kodi - https://kodi.tv
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 *  See LICENSES/README.md for more information.
 */

#pragma once

//---------------------------------------------------------
// This include should be moved to commons but even as it is,
// it wont cause a linker circular dependency since it's just
// a header.
#include "utils/StringUtils.h"
//---------------------------------------------------------
#include <stdarg.h>


#ifdef __GNUC__
// The 'this' pointer counts as a parameter on member methods.
#define XBMCCOMMONS_ATTRIB_EXCEPTION_FORMAT __attribute__((format(printf,2,3)))
#else
#define XBMCCOMMONS_ATTRIB_EXCEPTION_FORMAT
#endif

#define XBMCCOMMONS_COPYVARARGS(fmt) va_list argList; va_start(argList, fmt); Set(fmt, argList); va_end(argList)
#define XBMCCOMMONS_STANDARD_EXCEPTION(E) \
  class E : public XbmcCommons::Exception \
  { \
  public: \
    inline E(const char* message,...) XBMCCOMMONS_ATTRIB_EXCEPTION_FORMAT : Exception(#E) { XBMCCOMMONS_COPYVARARGS(message); } \
    \
    inline E(const E& other) : Exception(other) {} \
  }

namespace XbmcCommons
{
  /**
   * This class a superclass for exceptions that want to utilize some
   * utility functionality including autologging with the specific
   * exception name.
   */
  class Exception
  {
  private:

    std::string classname;
    std::string message;

  protected:

    inline explicit Exception(const char* classname_) : classname(classname_) { }
    inline Exception(const char* classname_, const char* message_) : classname(classname_), message(message_) { }
    inline Exception(const Exception& other) = default;

    /**
     * This method is called from the constructor of subclasses. It
     * will set the message from varargs as well as call log message
     */
    inline void Set(const char* fmt, va_list& argList)
    {
      message = StringUtils::FormatV(fmt, argList);
    }

    /**
     * This message can be called from the constructor of subclasses.
     * It will set the message and log the throwing.
     */
    inline void SetMessage(const char* fmt, ...) XBMCCOMMONS_ATTRIB_EXCEPTION_FORMAT
    {
      // calls 'set'
      XBMCCOMMONS_COPYVARARGS(fmt);
    }

    inline void setClassname(const char* cn) { classname = cn; }

  public:
    virtual ~Exception();

    virtual void LogThrowMessage(const char* prefix = NULL) const;

    inline virtual const char* GetExMessage() const { return message.c_str(); }
  };

  /**
   * This class forms the base class for unchecked exceptions. Unchecked exceptions
   * are those that really shouldn't be handled explicitly. For example, on windows
   * when a access violation is converted to a win32_exception, there's nothing
   * that can be done in most code. The outer most stack frame might try to
   * do some error logging prior to shutting down, but that's really it.
   */
  XBMCCOMMONS_STANDARD_EXCEPTION(UncheckedException);

/**
 * In cases where you catch(...){} you will (may) inadvertently be
 * catching UncheckedException's. Therefore this macro will allow
 * you to do something equivalent to:
 *    catch (anything except UncheckedException) {}
 *
 * In order to avoid catching UncheckedException, use the macro as follows:
 *
 *    try { ... }
 *    XBMCCOMMONS_HANDLE_UNCHECKED
 *    catch(...){ ... }
 */
// Yes. I recognize that the name of this macro is an oxymoron.
#define  XBMCCOMMONS_HANDLE_UNCHECKED \
  catch (const XbmcCommons::UncheckedException& ) { throw; } \
  catch (const XbmcCommons::UncheckedException* ) { throw; }

}