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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
/*$Id: c_attach.cc $ -*- C++ -*-
* Copyright (C) 2007 Albert Davis
* Author: Albert Davis <aldavis@gnu.org>
*
* This file is part of "Gnucap", the Gnu Circuit Analysis Package
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*------------------------------------------------------------------
*/
//testing=script 2017.06.22
#include "e_cardlist.h"
#include "c_comand.h"
#include "globals.h"
/*--------------------------------------------------------------------------*/
namespace {
/*--------------------------------------------------------------------------*/
std::map<std::string, void*> attach_list;
/*--------------------------------------------------------------------------*/
std::string plug_path()
{
return OS::getenv("GNUCAP_PLUGPATH");
}
/*--------------------------------------------------------------------------*/
void list()
{
for (std::map<std::string, void*>::iterator
ii = attach_list.begin(); ii != attach_list.end(); ++ii) {
if (ii->second) {
IO::mstdout << ii->first << '\n';
}else{itested();
error(bTRACE, ii->first + " (unloaded)\n");
}
}
}
/*--------------------------------------------------------------------------*/
class CMD_ATTACH : public CMD {
public:
void do_it(CS& cmd, CARD_LIST* Scope)override {
assert(Scope);
if (Scope == &CARD_LIST::card_list) {
}else{untested();
}
size_t here = cmd.cursor();
int dl_scope = RTLD_LOCAL;
int check = RTLD_NOW;
// RTLD_NOW means to resolve symbols on loading
// RTLD_LOCAL means symbols defined in a plugin are local
do {
if (cmd.umatch("public ")) {itested();
dl_scope = RTLD_GLOBAL;
// RTLD_GLOBAL means symbols defined in a plugin are global
// Use this when a plugin depends on another.
}else if (cmd.umatch("lazy ")) {untested();
check = RTLD_LAZY;
// RTLD_LAZY means to defer resolving symbols until needed
// Use when a plugin will not load because of unresolved symbols,
// but it may work without it.
}else{
}
} while (cmd.more() && !cmd.stuck(&here));
std::string short_file_name;
cmd >> short_file_name;
if (short_file_name == "") {
// nothing, list what we have
list();
}else{
// a name to look for
// check if already loaded
if (void* handle = attach_list[short_file_name]) {itested();
if (Scope->is_empty()) {itested();
cmd.warn(bDANGER, here, "\"" + short_file_name + "\": already loaded, replacing");
dlclose(handle);
attach_list[short_file_name] = NULL;
}else{itested();
cmd.reset(here);
throw Exception_CS("already loaded, cannot replace when there is a circuit", cmd);
}
}else{
}
std::string full_file_name;
if (short_file_name[0]=='/' || short_file_name[0]=='.'){itested();
if (OS::access_ok(short_file_name, R_OK)) {itested();
// found it, local or root
full_file_name = short_file_name;
}else{untested();
cmd.reset(here);
throw Exception_CS(std::string("plugin not found in ") + short_file_name[0], cmd);
}
}else{
std::string path = plug_path();
full_file_name = findfile(short_file_name, path, R_OK);
if (full_file_name != "") {
// found it, with search
}else{itested();
cmd.reset(here);
throw Exception_CS("plugin not found in " + path, cmd);
}
}
assert(OS::access_ok(full_file_name, R_OK));
if (void* handle = dlopen(full_file_name.c_str(), check | dl_scope)) {
attach_list[short_file_name] = handle;
}else{untested();
cmd.reset(here);
throw Exception_CS(dlerror(), cmd);
}
}
}
std::string help_text()const override {
return
"load command\n"
"Loads plugins\n"
"Syntax: load plugin\n"
"Plugin search path is: " + plug_path() + " \n"
"Path is set by GNUCAP_PLUGPATH environment variable\n"
"With no arg, it lists plugins already loaded\n\n";
}
} p1;
DISPATCHER<CMD>::INSTALL d1(&command_dispatcher, "attach|load", &p1);
/*--------------------------------------------------------------------------*/
class CMD_DETACH : public CMD {
public:
void do_it(CS& cmd, CARD_LIST* Scope) override {
assert(Scope);
if (Scope == &CARD_LIST::card_list) {
}else{untested();
}
size_t here = cmd.cursor(); //BUG// due to the way dlopen and dlclose work
std::string file_name; // it doesn't really work.
cmd >> file_name; // the dispatcher's active instance blocks unload
if (file_name == "") {
// nothing, list what we have
list();
}else{itested();
if (Scope->is_empty()) {itested();
void* handle = attach_list[file_name];
if (handle) {itested();
dlclose(handle);
attach_list[file_name] = NULL;
}else{untested();
cmd.reset(here);
throw Exception_CS("plugin not attached", cmd);
}
}else{untested();
throw Exception_CS("detach prohibited when there is a circuit", cmd);
}
}
}
std::string help_text()const override {
return
"unload command\n"
"Unloads plugins\n"
"Syntax: unload plugin\n"
"The name must match the name you loaded it with.\n"
"Prohibited when there is a circuit\n"
"With no arg, it lists plugins already loaded\n\n";
}
} p2;
DISPATCHER<CMD>::INSTALL d2(&command_dispatcher, "detach|unload", &p2);
/*--------------------------------------------------------------------------*/
class CMD_DETACH_ALL : public CMD {
public:
void do_it(CS& cmd, CARD_LIST* Scope)override {
assert(Scope);
if (Scope == &CARD_LIST::card_list) {
}else{untested();
}
if (Scope->is_empty()) {
for (std::map<std::string, void*>::iterator
ii = attach_list.begin(); ii != attach_list.end(); ++ii) {
void* handle = ii->second;
if (handle) {
dlclose(handle);
ii->second = NULL;
}else{itested();
// name still in list, but has been detached already
}
}
}else{untested();
throw Exception_CS("detach prohibited when there is a circuit", cmd);
}
}
} p3;
DISPATCHER<CMD>::INSTALL d3(&command_dispatcher, "detach_all", &p3);
/*--------------------------------------------------------------------------*/
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
// vim:ts=8:sw=2:noet:
|