1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21#include "common/config.h"
22#include "deprecation.h"
23#include "thread/threads.h"
24
25#include <atomic>
26#include <map>
27
28namespace love
29{
30
31static std::map<std::string, DeprecationInfo> *deprecated = nullptr;
32static std::vector<const DeprecationInfo *> *deprecatedList = nullptr;
33
34static std::atomic<int> initCount;
35
36static thread::Mutex *mutex = nullptr;
37static bool outputEnabled = false;
38
39void initDeprecation()
40{
41 if (initCount.fetch_add(1) == 0)
42 {
43 mutex = thread::newMutex();
44
45 // These are heap-allocated because we want to clear them on deinit,
46 // and deinit may be called when the program is shutting down in the
47 // middle of static variable cleanup (eg in the Math module destructor).
48 // Calling std::map::clear() in that case was causing segfaults.
49 deprecated = new std::map<std::string, DeprecationInfo>();
50 deprecatedList = new std::vector<const DeprecationInfo *>();
51 }
52}
53
54void deinitDeprecation()
55{
56 if (initCount.fetch_sub(1) == 1)
57 {
58 delete deprecated;
59 delete deprecatedList;
60 delete mutex;
61
62 deprecated = nullptr;
63 deprecatedList = nullptr;
64 mutex = nullptr;
65 }
66}
67
68static void printDeprecationNotice(const DeprecationInfo &info)
69{
70 std::string notice = getDeprecationNotice(info, true);
71 printf("LOVE - Warning: %s\n", notice.c_str());
72}
73
74void setDeprecationOutputEnabled(bool enable)
75{
76 if (enable == outputEnabled)
77 return;
78
79 outputEnabled = enable;
80
81 if (enable)
82 {
83 GetDeprecated deprecated;
84
85 for (const DeprecationInfo *info : deprecated.all)
86 {
87 if (info->uses == 1)
88 printDeprecationNotice(*info);
89 }
90 }
91}
92
93bool isDeprecationOutputEnabled()
94{
95 return outputEnabled;
96}
97
98std::string getDeprecationNotice(const DeprecationInfo &info, bool usewhere)
99{
100 std::string notice;
101
102 if (usewhere)
103 notice += info.where;
104
105 notice += "Using deprecated ";
106
107 if (info.apiType == API_FUNCTION)
108 notice += "function ";
109 else if (info.apiType == API_METHOD)
110 notice += "method ";
111 else if (info.apiType == API_FIELD)
112 notice += "field ";
113 else if (info.apiType == API_CONSTANT)
114 notice += "constant ";
115 else
116 notice += "API ";
117
118 notice += info.name;
119
120 if (info.type == DEPRECATED_REPLACED && !info.replacement.empty())
121 notice += " (replaced by " + info.replacement + ")";
122 else if (info.type == DEPRECATED_RENAMED && !info.replacement.empty())
123 notice += " (renamed to " + info.replacement + ")";
124
125 return notice;
126}
127
128GetDeprecated::GetDeprecated()
129 : all(*deprecatedList)
130{
131 if (mutex != nullptr)
132 mutex->lock();
133}
134
135GetDeprecated::~GetDeprecated()
136{
137 if (mutex != nullptr)
138 mutex->unlock();
139}
140
141MarkDeprecated::MarkDeprecated(const char *name, APIType api)
142 : MarkDeprecated(name, api, DEPRECATED_NO_REPLACEMENT, nullptr)
143{
144}
145
146MarkDeprecated::MarkDeprecated(const char *name, APIType api, DeprecationType type, const char *replacement)
147 : info(nullptr)
148{
149 if (mutex != nullptr)
150 mutex->lock();
151
152 auto it = deprecated->find(name);
153
154 if (it != deprecated->end())
155 {
156 it->second.uses++;
157 info = &it->second;
158 }
159 else
160 {
161 DeprecationInfo newinfo = {};
162
163 newinfo.type = type;
164 newinfo.apiType = api;
165 newinfo.uses = 1;
166 newinfo.name = name;
167
168 if (replacement != nullptr)
169 newinfo.replacement = replacement;
170
171 auto inserted = deprecated->insert(std::make_pair(newinfo.name, newinfo));
172
173 info = &inserted.first->second;
174 deprecatedList->push_back(info);
175 }
176}
177
178MarkDeprecated::~MarkDeprecated()
179{
180 if (outputEnabled && info != nullptr && info->uses == 1)
181 printDeprecationNotice(*info);
182
183 if (mutex != nullptr)
184 mutex->unlock();
185}
186
187} // love
188