Files
epics-base/modules/database/src/ioc/misc/registerAllRecordDeviceDrivers.cpp
Michael Davidsaver 0502fe25e4 print ANSI escapes to stderr
unconditionally print ANSI some escapes (to colorize errors)
to the stderr stream.
2023-12-01 16:47:18 +01:00

256 lines
7.9 KiB
C++

/*************************************************************************\
* Copyright (c) 2020 Michael Davidsaver
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <exception>
#include <string>
#include <set>
#include <map>
#include <string.h>
#define EPICS_PRIVATE_API
#include <iocsh.h>
#include <epicsStdio.h>
#include <epicsFindSymbol.h>
#include <errlog.h>
#include <registryRecordType.h>
#include <registryDeviceSupport.h>
#include <registryDriverSupport.h>
#include <iocshRegisterCommon.h>
#include <registryCommon.h>
#include <dbAccess.h>
#include <dbBase.h>
#include <dbStaticLib.h>
namespace {
struct compareLoc {
bool operator()(const recordTypeLocation& lhs, const recordTypeLocation& rhs) const
{
if(lhs.prset<rhs.prset)
return true;
else if(lhs.prset>rhs.prset)
return false;
return lhs.sizeOffset<rhs.sizeOffset;
}
};
// storage which will be referenced by pdbbase. Must never be free'd
std::set<std::string> names;
std::set<recordTypeLocation, compareLoc> reclocs;
template<typename T, typename Y>
const T& intern(std::set<T,Y>& coll, const T& val)
{
return *coll.insert(val).first;
}
std::set<void*> registrarsRun;
// gcc circa 4.4 doesn't like iocshVarDef[2] as mapped_type
struct varDef {
iocshVarDef def[2];
};
typedef std::map<std::string, varDef> vardefs_t;
vardefs_t vardefs;
template<typename T>
T lookupAs(const char* a, const char* b =0, const char* c =0, const char* d =0)
{
std::string name(a);
if(b)
name += b;
if(c)
name += c;
if(d)
name += d;
T ret = (T)epicsFindSymbol(name.c_str());
if(!ret) {
fprintf(stderr, "Unable to find symbol '%s' : %s\n", name.c_str(), epicsLoadError());
// all pvar_* are pointers to the exported object
} else if(ret && !*ret) {
fprintf(stderr, "symbol '%s' holds NULL\n", name.c_str());
}
return ret;
}
} // namespace
void runRegistrarOnce(void (*reg_func)(void))
{
if(registrarsRun.find((void*)reg_func)!=registrarsRun.end())
return;
registrarsRun.insert((void*)reg_func);
reg_func();
}
void clearRegistrarOnce()
{
registrarsRun.clear();
}
long
registerAllRecordDeviceDrivers(DBBASE *pdbbase)
{
DBENTRY entry;
if(!pdbbase) {
fprintf(stderr, "Must call dbLoadRecords() before registerAllRecordDeviceDrivers(pdbbase)\n");
return 1;
}
dbInitEntry(pdbbase, &entry);
try {
// for each recordType
for(long status=dbFirstRecordType(&entry); !status; status=dbNextRecordType(&entry)) {
dbRecordType *rtype = entry.precordType;
if(!registryRecordTypeFind(rtype->name)) {
rset** prset = lookupAs<rset**>("pvar_rset_", rtype->name, "RSET");
computeSizeOffset* sizeOffset = lookupAs<computeSizeOffset*>("pvar_func_", rtype->name, "RecordSizeOffset");
if(!prset || !*prset || !sizeOffset || !*sizeOffset) {
fprintf(stderr, "Unable to find support for record type '%s' : %s\n",
rtype->name, epicsLoadError());
return 1;
}
recordTypeLocation sup;
sup.prset = *prset;
sup.sizeOffset = *sizeOffset;
const char *cname = intern<std::string>(names, rtype->name).c_str();
const recordTypeLocation* csup = &intern<recordTypeLocation>(reclocs, sup);
registerRecordTypes(pdbbase, 1, &cname, csup);
}
// for each device support for this recordType
for(ELLNODE *cur = ellFirst(&rtype->devList); cur; cur = ellNext(cur)) {
devSup& devsup = *CONTAINER(cur, devSup, node);
if(registryDeviceSupportFind(devsup.name))
continue;
dset** ptr = lookupAs<dset**>("pvar_dset_", devsup.name);
if(!ptr || !*ptr) {
fprintf(stderr, "Unable to find dset for record type '%s' support '%s' : %s\n",
rtype->name, devsup.name, epicsLoadError());
return 1;
}
const char *cname = intern<std::string>(names, devsup.name).c_str();
registerDevices(pdbbase, 1, &cname, ptr);
}
}
// for each driver
for(ELLNODE *cur = ellFirst(&pdbbase->drvList); cur; cur = ellNext(cur)) {
drvSup& drv = *CONTAINER(cur, drvSup, node);
if(registryDriverSupportFind(drv.name))
continue;
drvet** ptr = lookupAs<drvet**>("pvar_drvet_", drv.name);
if(!ptr || !*ptr) {
fprintf(stderr, "Unable to find drvet '%s' : %s\n", drv.name, epicsLoadError());
return 1;
}
const char *cname = intern<std::string>(names, drv.name).c_str();
registerDrivers(pdbbase, 1, &cname, ptr);
}
// for each link support
for(ELLNODE *cur = ellFirst(&pdbbase->linkList); cur; cur = ellNext(cur)) {
linkSup& lnk = *CONTAINER(cur, linkSup, node);
jlif** ptr = lookupAs<jlif**>("pvar_jlif_", lnk.jlif_name);
if(!ptr || !*ptr) {
fprintf(stderr, "Unable to find link support '%s' : %s\n", lnk.jlif_name, epicsLoadError());
return 1;
}
registerJLinks(pdbbase, 1, ptr);
}
// for each function()
for(ELLNODE *cur = ellFirst(&pdbbase->functionList); cur; cur = ellNext(cur)) {
dbText& reg = *CONTAINER(cur, dbText, node);
typedef void(*registrar)(void);
registrar* ptr = lookupAs<registrar*>("pvar_func_register_func_", reg.text);
if(!ptr || !*ptr) {
fprintf(stderr, "Unable to find function '%s' : %s\n", reg.text, epicsLoadError());
return 1;
}
runRegistrarOnce(*ptr);
}
// for each registrar()
for(ELLNODE *cur = ellFirst(&pdbbase->registrarList); cur; cur = ellNext(cur)) {
dbText& reg = *CONTAINER(cur, dbText, node);
typedef void(*registrar)(void);
registrar* ptr = lookupAs<registrar*>("pvar_func_", reg.text);
if(!ptr || !*ptr) {
fprintf(stderr, "Unable to find registrar '%s' : %s\n", reg.text, epicsLoadError());
return 1;
}
runRegistrarOnce(*ptr);
}
// for each iocsh variable
for(ELLNODE *cur = ellFirst(&pdbbase->variableList); cur; cur = ellNext(cur)) {
dbVariableDef& var = *CONTAINER(cur, dbVariableDef, node);
if(iocshFindVariable(var.name))
continue;
void** ptr = lookupAs<void**>("pvar_", var.type, "_", var.name);
if(!ptr || !*ptr) {
fprintf(stderr, "Unable to find variable '%s' : %s\n", var.name, epicsLoadError());
return 1;
}
vardefs_t::mapped_type& vdef = vardefs[var.name];
vdef.def[0].name = intern<std::string>(names, var.name).c_str();
vdef.def[0].pval = *ptr;
if(strcmp(var.type, "double")==0) {
vdef.def[0].type = iocshArgDouble;
} else if(strcmp(var.type, "int")==0) {
vdef.def[0].type = iocshArgInt;
} else {
fprintf(stderr, "Unsupported type %s of variable '%s' : %s\n", var.type, var.name, epicsLoadError());
return 1;
}
vdef.def[1].name = 0;
iocshRegisterVariable(vdef.def);
}
dbFinishEntry(&entry);
return 0;
} catch(std::exception& e) {
dbFinishEntry(&entry);
fprintf(stderr, ERL_ERROR ": %s\n", e.what());
return 2;
}
}