FlightGear next
NasalAddons.cxx
Go to the documentation of this file.
1// -*- coding: utf-8 -*-
2//
3// NasalAddons.cxx --- Expose add-on classes to Nasal
4// Copyright (C) 2017, 2018 Florent Rougon
5//
6// This program is free software; you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation; either version 2 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License along
17// with this program; if not, write to the Free Software Foundation, Inc.,
18// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20#include <memory>
21#include <string>
22
23#include <cassert>
24
25#include <simgear/nasal/cppbind/Ghost.hxx>
26#include <simgear/nasal/cppbind/NasalCallContext.hxx>
27#include <simgear/nasal/cppbind/NasalHash.hxx>
28#include <simgear/nasal/nasal.h>
29#include <simgear/structure/exception.hxx>
30
31#include <Add-ons/addon_fwd.hxx>
32#include <Add-ons/Addon.hxx>
35#include <Add-ons/contacts.hxx>
36
37namespace flightgear
38{
39
40namespace addons
41{
42
43// ***************************************************************************
44// * AddonManager *
45// ***************************************************************************
46
47static const std::unique_ptr<AddonManager>& getAddonMgrWithCheck()
48{
49 const auto& addonMgr = AddonManager::instance();
50
51 if (!addonMgr) {
52 throw sg_exception("trying to access the AddonManager from Nasal, "
53 "however it is not initialized");
54 }
55
56 return addonMgr;
57}
58
59static naRef f_registeredAddons(const nasal::CallContext& ctx)
60{
61 const auto& addonMgr = getAddonMgrWithCheck();
62 return ctx.to_nasal(addonMgr->registeredAddons());
63}
64
65static naRef f_isAddonRegistered(const nasal::CallContext& ctx)
66{
67 const auto& addonMgr = getAddonMgrWithCheck();
68 std::string addonId = ctx.requireArg<std::string>(0);
69 return ctx.to_nasal(addonMgr->isAddonRegistered(addonId));
70}
71
72static naRef f_loadedAddons(const nasal::CallContext& ctx)
73{
74 const auto& addonMgr = getAddonMgrWithCheck();
75 return ctx.to_nasal(addonMgr->loadedAddons());
76}
77
78static naRef f_isAddonLoaded(const nasal::CallContext& ctx)
79{
80 const auto& addonMgr = getAddonMgrWithCheck();
81 std::string addonId = ctx.requireArg<std::string>(0);
82 return ctx.to_nasal(addonMgr->isAddonLoaded(addonId));
83}
84
85static naRef f_getAddon(const nasal::CallContext& ctx)
86{
87 const auto& addonMgr = getAddonMgrWithCheck();
88 return ctx.to_nasal(addonMgr->getAddon(ctx.requireArg<std::string>(0)));
89}
90
91static void wrapAddonManagerMethods(nasal::Hash& addonsModule)
92{
93 addonsModule.set("registeredAddons", &f_registeredAddons);
94 addonsModule.set("isAddonRegistered", &f_isAddonRegistered);
95 addonsModule.set("loadedAddons", &f_loadedAddons);
96 addonsModule.set("isAddonLoaded", &f_isAddonLoaded);
97 addonsModule.set("getAddon", &f_getAddon);
98}
99
100// ***************************************************************************
101// * AddonVersion *
102// ***************************************************************************
103
104// Create a new AddonVersion instance.
105//
106// addons.AddonVersion.new(versionString)
107// addons.AddonVersion.new(major[, minor[, patchLevel[, suffix]]])
108//
109// where:
110// - 'major', 'minor' and 'patchLevel' are integers;
111// - 'suffix' is a string such as "", "a3", "b12" or "rc4" (resp. meaning:
112// release, alpha 3, beta 12, release candidate 4) Suffixes for
113// development releases are also allowed, such as ".dev4" (sorts before
114// the release as well as any alphas, betas and rcs for the release) and
115// "a3.dev10" (sorts before "a3.dev11", "a3.dev12", "a3", etc.).
116//
117// For details, see <https://www.python.org/dev/peps/pep-0440/> which is a
118// proper superset of what is allowed here.
119naRef f_createAddonVersion(const nasal::CallContext& ctx)
120{
121 int major = 0, minor = 0, patchLevel = 0;
122 std::string suffix;
123
124 if (ctx.argc == 0 || ctx.argc > 4) {
125 ctx.runtimeError(
126 "AddonVersion.new(versionString) or "
127 "AddonVersion.new(major[, minor[, patchLevel[, suffix]]])"
128 );
129 }
130
131 if (ctx.argc == 1) {
132 naRef arg1 = ctx.args[0];
133
134 if (naIsString(arg1)) {
135 return ctx.to_nasal(AddonVersionRef(new AddonVersion(naStr_data(arg1))));
136 } else if (naIsNum(arg1)) {
137 AddonVersionRef ref{new AddonVersion(arg1.num, minor, patchLevel,
138 AddonVersionSuffix(suffix))};
139 return ctx.to_nasal(std::move(ref));
140 } else {
141 ctx.runtimeError(
142 "AddonVersion.new(versionString) or "
143 "AddonVersion.new(major[, minor[, patchLevel[, suffix]]])"
144 );
145 }
146 }
147
148 assert(ctx.argc > 0);
149 if (!ctx.isNumeric(0)) {
150 ctx.runtimeError(
151 "addons.AddonVersion.new() requires major number as an integer"
152 );
153 }
154
155 major = ctx.requireArg<int>(0);
156
157 if (ctx.argc > 1) {
158 if (!ctx.isNumeric(1)) {
159 ctx.runtimeError(
160 "addons.AddonVersion.new() requires minor number as an integer"
161 );
162 }
163
164 minor = ctx.requireArg<int>(1);
165 }
166
167 if (ctx.argc > 2) {
168 if (!ctx.isNumeric(2)) {
169 ctx.runtimeError(
170 "addons.AddonVersion.new() requires patch level as an integer"
171 );
172 }
173
174 patchLevel = ctx.requireArg<int>(2);
175 }
176
177 if (ctx.argc > 3) {
178 if (!ctx.isString(3)) {
179 ctx.runtimeError(
180 "addons.AddonVersion.new() requires suffix as a string"
181 );
182 }
183
184 suffix = ctx.requireArg<std::string>(3);
185 }
186
187 assert(ctx.argc <= 4);
188
189 return ctx.to_nasal(
190 AddonVersionRef(new AddonVersion(major, minor, patchLevel,
191 AddonVersionSuffix(suffix))));
192}
193
194void initAddonClassesForNasal(naRef globals, naContext c)
195{
196 nasal::Hash globalsModule(globals, c);
197 nasal::Hash addonsModule = globalsModule.createHash("addons");
198
199 wrapAddonManagerMethods(addonsModule);
200
201 Addon::setupGhost(addonsModule);
202 Contact::setupGhost(addonsModule);
203 Author::setupGhost(addonsModule);
204 Maintainer::setupGhost(addonsModule);
205
206 AddonVersion::setupGhost(addonsModule);
207 addonsModule.createHash("AddonVersion").set("new", &f_createAddonVersion);
208}
209
210} // of namespace addons
211
212} // of namespace flightgear
static const std::unique_ptr< AddonManager > & instance()
static void setupGhost(nasal::Hash &addonsModule)
static void setupGhost(nasal::Hash &addonsModule)
Definition Addon.cxx:480
static void setupGhost(nasal::Hash &addonsModule)
Definition contacts.cxx:104
static void setupGhost(nasal::Hash &addonsModule)
Definition contacts.cxx:87
static void setupGhost(nasal::Hash &addonsModule)
Definition contacts.cxx:119
FGGlobals * globals
Definition globals.cxx:142
void initAddonClassesForNasal(naRef globals, naContext c)
static const std::unique_ptr< AddonManager > & getAddonMgrWithCheck()
static void wrapAddonManagerMethods(nasal::Hash &addonsModule)
static naRef f_loadedAddons(const nasal::CallContext &ctx)
naRef f_createAddonVersion(const nasal::CallContext &ctx)
static naRef f_getAddon(const nasal::CallContext &ctx)
static naRef f_isAddonRegistered(const nasal::CallContext &ctx)
static naRef f_registeredAddons(const nasal::CallContext &ctx)
SGSharedPtr< AddonVersion > AddonVersionRef
Definition addon_fwd.hxx:47
static naRef f_isAddonLoaded(const nasal::CallContext &ctx)
FlightPlan.hxx - defines a full flight-plan object, including departure, cruise, arrival information ...
Definition Addon.cxx:53