Integrated dbChannel more and extended its functionality:

* Register filters in pdbbase, using a list and gphash
 * Do record and field search first
 * Test loads a DBD/DB file to provide a record to find
This commit is contained in:
Michael Davidsaver
2012-04-27 13:21:39 -04:00
parent 8baf3b1362
commit eee5a28983
6 changed files with 433 additions and 206 deletions
+242 -48
View File
@@ -13,8 +13,12 @@
#include "dbBase.h"
#include "link.h"
#include "dbAccessDefs.h"
#include "dbStaticLib.h"
#include "epicsAssert.h"
#include "errlog.h"
#include "gpHash.h"
#include "recSup.h"
#include "special.h"
#include "yajl_parse.h"
@@ -24,10 +28,16 @@ typedef struct parseContext {
int depth;
} parseContext;
typedef struct filterPlugin {
ELLNODE node;
const char *name;
const chFilterIf *fif;
} filterPlugin;
#define CALLIF(rtn) rtn && rtn
static void chp_value(parseContext *parser, int result)
static void chf_value(parseContext *parser, int result)
{
chFilter *filter = parser->filter;
@@ -40,7 +50,7 @@ static void chp_value(parseContext *parser, int result)
}
static int chp_null(void * ctx)
static int chf_null(void * ctx)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
@@ -48,11 +58,11 @@ static int chp_null(void * ctx)
assert(filter);
result = CALLIF(filter->fif->parse_null) (filter );
chp_value(parser, result);
chf_value(parser, result);
return result;
}
static int chp_boolean(void * ctx, int boolVal)
static int chf_boolean(void * ctx, int boolVal)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
@@ -60,11 +70,11 @@ static int chp_boolean(void * ctx, int boolVal)
assert(filter);
result = CALLIF(filter->fif->parse_boolean) (filter , boolVal);
chp_value(parser, result);
chf_value(parser, result);
return result;
}
static int chp_integer(void * ctx, long integerVal)
static int chf_integer(void * ctx, long integerVal)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
@@ -72,11 +82,11 @@ static int chp_integer(void * ctx, long integerVal)
assert(filter);
result = CALLIF(filter->fif->parse_integer) (filter , integerVal);
chp_value(parser, result);
chf_value(parser, result);
return result;
}
static int chp_double(void * ctx, double doubleVal)
static int chf_double(void * ctx, double doubleVal)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
@@ -84,11 +94,11 @@ static int chp_double(void * ctx, double doubleVal)
assert(filter);
result = CALLIF(filter->fif->parse_double) (filter , doubleVal);
chp_value(parser, result);
chf_value(parser, result);
return result;
}
static int chp_string(void * ctx, const unsigned char * stringVal,
static int chf_string(void * ctx, const unsigned char * stringVal,
unsigned int stringLen)
{
parseContext *parser = (parseContext *) ctx;
@@ -97,11 +107,11 @@ static int chp_string(void * ctx, const unsigned char * stringVal,
assert(filter);
result = CALLIF(filter->fif->parse_string) (filter , (const char *) stringVal, stringLen);
chp_value(parser, result);
chf_value(parser, result);
return result;
}
static int chp_start_map(void * ctx)
static int chf_start_map(void * ctx)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
@@ -115,7 +125,7 @@ static int chp_start_map(void * ctx)
return CALLIF(filter->fif->parse_start_map) (filter );
}
static int chp_map_key(void * ctx, const unsigned char * key,
static int chf_map_key(void * ctx, const unsigned char * key,
unsigned int stringLen)
{
parseContext *parser = (parseContext *) ctx;
@@ -148,7 +158,7 @@ static int chp_map_key(void * ctx, const unsigned char * key,
return result;
}
static int chp_end_map(void * ctx)
static int chf_end_map(void * ctx)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
@@ -156,14 +166,14 @@ static int chp_end_map(void * ctx)
if (filter) {
int result = CALLIF(filter->fif->parse_end_map) (filter );
if (--parser->depth == 0) chp_value(parser, result);
if (--parser->depth == 0) chf_value(parser, result);
return result;
}
assert(parser->depth == 0);
return parse_continue; /* Final closing '}' */
}
static int chp_start_array(void * ctx)
static int chf_start_array(void * ctx)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
@@ -173,7 +183,7 @@ static int chp_start_array(void * ctx)
return CALLIF(filter->fif->parse_start_array) (filter );
}
static int chp_end_array(void * ctx)
static int chf_end_array(void * ctx)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
@@ -181,66 +191,250 @@ static int chp_end_array(void * ctx)
assert(filter);
result = CALLIF(filter->fif->parse_end_array) (filter );
if (--parser->depth == 0) chp_value(parser, result);
if (--parser->depth == 0) chf_value(parser, result);
return result;
}
static const yajl_callbacks chp_callbacks =
{ chp_null, chp_boolean, chp_integer, chp_double, NULL, chp_string,
chp_start_map, chp_map_key, chp_end_map, chp_start_array, chp_end_array };
static const yajl_callbacks chf_callbacks =
{ chf_null, chf_boolean, chf_integer, chf_double, NULL, chf_string,
chf_start_map, chf_map_key, chf_end_map, chf_start_array, chf_end_array };
static const yajl_parser_config chp_config =
static const yajl_parser_config chf_config =
{ 0, 1 }; /* allowComments = NO , checkUTF8 = YES */
void dbChannelInit(dbChannel *chan)
{
ellInit(&chan->filters);
}
// Move ellInit into ChannelFind, rename it again?
long dbChannelFind(dbChannel *chan, const char *name)
static long chf_parse(dbChannel *chan, const char *json)
{
parseContext parser =
{ chan, NULL, 0};
yajl_handle yh = yajl_alloc(&chp_callbacks, &chp_config, NULL, &parser);
size_t len = strlen(name);
yajl_status status;
yajl_handle yh = yajl_alloc(&chf_callbacks, &chf_config, NULL, &parser);
size_t jlen = strlen(json);
yajl_status ys;
long status;
status = yajl_parse(yh, (const unsigned char *) name, len);
if (status != yajl_status_ok && parser.filter) {
if (!yh) return S_db_noMemory;
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
if (ys == yajl_status_insufficient_data)
ys = yajl_parse_complete(yh);
switch(ys) {
case yajl_status_ok:
status = 0;
break;
case yajl_status_error: {
unsigned char *err;
err = yajl_get_error(yh, 1, (const unsigned char *) json, jlen);
printf("dbChannelFind: %s\n", err);
yajl_free_error(yh, err);
} /* fall through */
default:
status = S_db_notFound;
}
if (parser.filter) {
assert(status);
parser.filter->fif->parse_abort(parser.filter);
free(parser.filter);
}
yajl_free(yh);
return status == yajl_status_ok;
return status;
}
/* Stolen from dbAccess.c: */
static short mapDBFToDBR[DBF_NTYPES] = {
/* DBF_STRING => */ DBR_STRING,
/* DBF_CHAR => */ DBR_CHAR,
/* DBF_UCHAR => */ DBR_UCHAR,
/* DBF_SHORT => */ DBR_SHORT,
/* DBF_USHORT => */ DBR_USHORT,
/* DBF_LONG => */ DBR_LONG,
/* DBF_ULONG => */ DBR_ULONG,
/* DBF_FLOAT => */ DBR_FLOAT,
/* DBF_DOUBLE => */ DBR_DOUBLE,
/* DBF_ENUM, => */ DBR_ENUM,
/* DBF_MENU, => */ DBR_ENUM,
/* DBF_DEVICE => */ DBR_ENUM,
/* DBF_INLINK => */ DBR_STRING,
/* DBF_OUTLINK => */ DBR_STRING,
/* DBF_FWDLINK => */ DBR_STRING,
/* DBF_NOACCESS => */ DBR_NOACCESS
};
long dbChannelFind(dbChannel *chan, const char *pname)
{
DBADDR *paddr;
DBENTRY dbEntry;
dbFldDes *pflddes;
long status;
short dbfType;
if (!chan || !pname || !*pname || !pdbbase)
return S_db_notFound;
if (chan->magic == DBCHANNEL_MAGIC) {
chFilter *filter;
while ((filter = (chFilter *) ellGet(&chan->filters))) {
filter->fif->channel_close(filter);
free(filter);
}
} else {
ellInit(&chan->filters);
chan->magic = DBCHANNEL_MAGIC;
}
dbInitEntry(pdbbase, &dbEntry);
status = dbFindRecordPart(&dbEntry, &pname);
if (status) goto finish;
if (*pname == '.') ++pname;
status = dbFindFieldPart(&dbEntry, &pname);
if (status == S_dbLib_fieldNotFound)
status = dbGetAttributePart(&dbEntry, &pname);
if (status) goto finish;
paddr = &chan->addr;
pflddes = dbEntry.pflddes;
dbfType = pflddes->field_type;
paddr->precord = dbEntry.precnode->precord;
paddr->pfield = dbEntry.pfield;
paddr->pfldDes = pflddes;
paddr->no_elements = 1;
paddr->field_type = dbfType;
paddr->field_size = pflddes->size;
paddr->special = pflddes->special;
paddr->dbr_field_type = mapDBFToDBR[dbfType];
/* Handle field modifiers */
while (*pname) {
switch (*pname) {
case '$':
/* Some field types can be accessed as char arrays */
if (dbfType == DBF_STRING) {
paddr->no_elements = pflddes->size;
paddr->field_type = DBF_CHAR;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
/* Clients see a char array, but keep original dbfType */
paddr->no_elements = PVNAME_STRINGSZ + 12;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else {
status = S_dbLib_fieldNotFound;
goto finish;
}
break;
case '{':
status = chf_parse(chan, pname);
goto finish;
default:
status = S_dbLib_fieldNotFound;
goto finish;
}
pname++;
}
finish:
dbFinishEntry(&dbEntry);
return status;
}
long dbChannelOpen(dbChannel *chan)
{
return S_db_notFound;
DBADDR *paddr;
chFilter *filter;
long status = 0;
if (chan->magic != DBCHANNEL_MAGIC) return S_db_notInit;
paddr = &chan->addr;
if (paddr->special == SPC_DBADDR) {
struct rset *prset = dbGetRset(paddr);
/* Let record type modify the dbAddr */
if (prset && prset->cvt_dbaddr) {
status = prset->cvt_dbaddr(paddr);
if (status) return status;
}
}
filter = (chFilter *) ellFirst(&chan->filters);
while (filter) {
status = filter->fif->channel_open(filter);
if (status) break;
filter = (chFilter *) ellNext(&filter->node);
}
return status;
}
void dbChannelReport(dbChannel *chan, int level)
{
chFilter *filter;
if (chan->magic != DBCHANNEL_MAGIC) return;
filter = (chFilter *) ellFirst(&chan->filters);
while (filter) {
filter->fif->channel_report(filter, level);
filter = (chFilter *) ellNext(&filter->node);
}
}
long dbChannelClose(dbChannel *chan)
{
chFilter *filter;
if (chan->magic != DBCHANNEL_MAGIC) return S_db_notInit;
while ((filter = (chFilter *) ellGet(&chan->filters))) {
filter->fif->channel_close(filter);
free(filter);
}
chan->magic = 0;
return 0;
}
/* FIXME: Do these belong in a different file? */
const chFilterIf * filt = NULL;
const char *fname = NULL;
void dbRegisterFilter(const char *key, const chFilterIf *fif)
void dbRegisterFilter(const char *name, const chFilterIf *fif)
{
/* FIXME: Add filter to a list and hash in pdbbase */
filt = fif;
fname = key;
fif->plugin_init();
GPHENTRY *pgph;
filterPlugin *pfilt;
if (!pdbbase) {
printf("dbRegisterFilter: pdbbase not set!\n");
return;
}
pgph = gphFind(pdbbase->pgpHash, name, &pdbbase->filterList);
if (pgph) return;
pfilt = dbCalloc(1, sizeof(filterPlugin));
pfilt->name = strdup(name);
pfilt->fif = fif;
ellAdd(&pdbbase->filterList, &pfilt->node);
pgph = gphAdd(pdbbase->pgpHash, pfilt->name, &pdbbase->filterList);
if (!pgph) {
free((void *)pfilt->name);
free(pfilt);
printf("dbRegisterFilter: gphAdd failed\n");
return;
}
pgph->userPvt = pfilt;
}
const chFilterIf * dbFindFilter(const char *key, size_t len)
const chFilterIf * dbFindFilter(const char *name, size_t len)
{
/* FIXME: gpHash lookup */
if (strncmp(fname, key, len) == 0)
return filt;
return NULL;
GPHENTRY *pgph = gphFindParse(pdbbase->pgpHash, name, len, &pdbbase->filterList);
filterPlugin *pfilt;
if (!pgph) return NULL;
pfilt = (filterPlugin *)pgph->userPvt;
return pfilt->fif;
}
+13 -8
View File
@@ -11,28 +11,33 @@
#include "dbDefs.h"
#include "dbAddr.h"
#include "ellLib.h"
#include "epicsTypes.h"
#include "errMdef.h"
#include "shareLib.h"
enum {parse_stop, parse_continue};
#ifdef __cplusplus
// extern "C" {
#endif
#define DBCHANNEL_MAGIC 0xdbc4a9e1
#define S_db_notInit (M_dbAccess|21) /*dbChannel not initialized*/
/* A dbChannel points to a record field, and can have multiple filters */
typedef struct dbChannel {
epicsUInt32 magic;
dbAddr addr;
ELLLIST filters;
} dbChannel;
typedef struct chFilter chFilter;
/* Return values from chFilterIf->parse_* routines: */
enum {parse_stop, parse_continue};
/* These routines must be implemented by each filter plug-in */
typedef struct chFilterIf {
/* Plug-in management */
void (* plugin_init)(void);
void (* plugin_exit)(void);
/* Parsing event handlers */
int (* parse_start)(chFilter *filter);
void (* parse_abort)(chFilter *filter);
@@ -68,9 +73,9 @@ struct chFilter {
void *puser;
};
epicsShareFunc void dbChannelInit(dbChannel *chan);
epicsShareFunc long dbChannelFind(dbChannel *chan, const char *name);
epicsShareFunc long dbChannelFind(dbChannel *chan, const char *pname);
epicsShareFunc long dbChannelOpen(dbChannel *chan);
epicsShareFunc void dbChannelReport(dbChannel *chan, int level);
epicsShareFunc long dbChannelClose(dbChannel *chan);
epicsShareFunc void dbRegisterFilter(const char *key, const chFilterIf *fif);
+80 -67
View File
@@ -6,165 +6,178 @@
\*************************************************************************/
#include "dbChannel.h"
#include "dbStaticLib.h"
#include "dbAccessDefs.h"
#include "epicsUnitTest.h"
#include "testMain.h"
/* Expected call bit definitions */
#define e_init 0x00000001
#define e_exit 0x00000002
#define e_start 0x00000004
#define e_abort 0x00000008
#define e_end 0x00000010
#define e_null 0x00000020
#define e_boolean 0x00000040
#define e_integer 0x00000080
#define e_double 0x00000100
#define e_string 0x00000200
#define e_start_map 0x00000400
#define e_map_key 0x00000800
#define e_end_map 0x00001000
#define e_start_array 0x00002000
#define e_end_array 0x00004000
#define e_open 0x00008000
#define e_report 0x00010000
#define e_close 0x00020000
#define e_start 0x00000001
#define e_abort 0x00000002
#define e_end 0x00000004
#define e_null 0x00000008
#define e_boolean 0x00000010
#define e_integer 0x00000020
#define e_double 0x00000040
#define e_string 0x00000080
#define e_start_map 0x00000100
#define e_map_key 0x00000200
#define e_end_map 0x00000400
#define e_start_array 0x00000800
#define e_end_array 0x00001000
#define e_open 0x00002000
#define e_report 0x00004000
#define e_close 0x00008000
unsigned int e;
void f_init(void)
{
testOk(e & e_init, "plugin_init expected");
}
void f_exit(void)
{
testOk(e & e_exit, "plugin_exit expected");
}
int p_start(chFilter *filter)
{
testOk(e & e_start, "parse_start expected");
testOk(e & e_start, "parse_start called");
return parse_continue;
}
void p_abort(chFilter *filter)
{
testOk(e & e_abort, "parse_abort expected");
testOk(e & e_abort, "parse_abort called");
}
int p_end(chFilter *filter)
{
testOk(e & e_end, "parse_end expected");
testOk(e & e_end, "parse_end called");
return parse_continue;
}
int p_null(chFilter *filter)
{
testOk(e & e_null, "parse_null expected");
testOk(e & e_null, "parse_null called");
return parse_continue;
}
int p_boolean(chFilter *filter, int boolVal)
{
testOk(e & e_boolean, "parse_boolean expected, val = %d", boolVal);
testOk(e & e_boolean, "parse_boolean called, val = %d", boolVal);
return parse_continue;
}
int p_integer(chFilter *filter, long integerVal)
{
testOk(e & e_integer, "parse_integer expected, val = %ld", integerVal);
testOk(e & e_integer, "parse_integer called, val = %ld", integerVal);
return parse_continue;
}
int p_double(chFilter *filter, double doubleVal)
{
testOk(e & e_double, "parse_double expected, val = %g", doubleVal);
testOk(e & e_double, "parse_double called, val = %g", doubleVal);
return parse_continue;
}
int p_string(chFilter *filter, const char *stringVal, size_t stringLen)
{
testOk(e & e_string, "parse_string expected, val = '%.*s'", stringLen, stringVal);
testOk(e & e_string, "parse_string called, val = '%.*s'", stringLen,
stringVal);
return parse_continue;
}
int p_start_map(chFilter *filter)
{
testOk(e & e_start_map, "parse_start_map expected");
testOk(e & e_start_map, "parse_start_map called");
return parse_continue;
}
int p_map_key(chFilter *filter, const char *key, size_t stringLen)
{
testOk(e & e_map_key, "parse_map_key expected, key = '%.*s'", stringLen, key);
testOk(e & e_map_key, "parse_map_key called, key = '%.*s'", stringLen, key);
return parse_continue;
}
int p_end_map(chFilter *filter)
{
testOk(e & e_end_map, "parse_end_map expected");
testOk(e & e_end_map, "parse_end_map called");
return parse_continue;
}
int p_start_array(chFilter *filter)
{
testOk(e & e_start_array, "parse_start_array expected");
testOk(e & e_start_array, "parse_start_array called");
return parse_continue;
}
int p_end_array(chFilter *filter)
{
testOk(e & e_end_array, "parse_end_array expected");
testOk(e & e_end_array, "parse_end_array called");
return parse_continue;
}
long c_open(chFilter *filter)
{
testOk(e & e_open, "channel_open expected");
testOk(e & e_open, "channel_open called");
return 0;
}
void c_report(chFilter *filter, int level)
{
testOk(e & e_report, "channel_report expected, level = %d", level);
testOk(e & e_report, "channel_report called, level = %d", level);
}
void c_close(chFilter *filter)
{
testOk(e & e_close, "channel_close expected");
testOk(e & e_close, "channel_close called");
}
chFilterIf testIf =
{ f_init, f_exit, p_start, p_abort, p_end, p_null, p_boolean,
p_integer, p_double, p_string, p_start_map, p_map_key, p_end_map,
p_start_array, p_end_array, c_open, c_report, c_close };
chFilterIf anyIf =
{ p_start, p_abort, p_end, p_null, p_boolean, p_integer, p_double,
p_string, p_start_map, p_map_key, p_end_map, p_start_array, p_end_array,
c_open, c_report, c_close };
chFilterIf scalarIf =
{ f_init, f_exit, p_start, p_abort, p_end, p_null, p_boolean,
p_integer, p_double, p_string, NULL, NULL, NULL, NULL, NULL, c_open,
c_report, c_close };
{ p_start, p_abort, p_end, p_null, p_boolean, p_integer, p_double,
p_string, NULL, NULL, NULL, NULL, NULL, c_open,
c_report, c_close};
MAIN(dbChannelTest)
{
dbChannel ch;
testPlan(33);
dbChannelInit(&ch);
testPlan(45);
testOk1(!dbReadDatabase(&pdbbase, "dbChannelTest.dbx", ".:..", NULL));
testOk(!!pdbbase, "pdbbase was set");
e = 0;
testOk1(dbChannelFind(&ch, "{}"));
testOk1(!dbChannelFind(&ch, "x.NAME$"));
testOk1(ch.addr.no_elements > 1);
e = e_init;
dbRegisterFilter("test", &testIf);
testOk1(!dbChannelFind(&ch, "x.{}"));
dbRegisterFilter("any", &anyIf);
e = e_start | e_null | e_end;
testOk1(dbChannelFind(&ch, "{\"test\":null}"));
testOk1(!dbChannelFind(&ch, "x.{\"any\":null}"));
e = e_close;
testOk1(!dbChannelClose(&ch));
e = e_start | e_start_array | e_boolean | e_integer | e_end_array | e_end;
testOk1(dbChannelFind(&ch, "{\"test\":[true,1]}"));
e = e_start | e_start_map | e_map_key | e_double | e_string | e_end_map | e_end;
testOk1(dbChannelFind(&ch, "{\"test\":{\"a\":2.7183,\"b\":\"c\"}}"));
e = e_init;
dbRegisterFilter("scalar", &scalarIf);
e = e_start | e_null | e_end;
testOk1(dbChannelFind(&ch, "{\"scalar\":null}"));
testOk1(!dbChannelFind(&ch, "x.{\"scalar\":null}"));
e = e_report;
dbChannelReport(&ch, 0);
e = e_close;
testOk1(!dbChannelClose(&ch));
e = e_start | e_start_array | e_boolean | e_integer | e_end_array | e_end;
testOk1(!dbChannelFind(&ch, "x.{\"any\":[true,1]}"));
e = e_close;
testOk1(!dbChannelClose(&ch));
e = e_start | e_start_map | e_map_key | e_double | e_string | e_end_map
| e_end;
testOk1(!dbChannelFind(&ch, "x.{\"any\":{\"a\":2.7183,\"b\":\"c\"}}"));
e = e_close | e_start | e_abort;
testOk1(dbChannelFind(&ch, "x.{\"scalar\":[null]}"));
e = 0;
testOk1(!dbChannelClose(&ch));
e = e_start | e_abort;
testOk1(!dbChannelFind(&ch, "{\"scalar\":[null]}"));
testOk1(!dbChannelFind(&ch, "{\"scalar\":{}}"));
testOk1(dbChannelFind(&ch, "x.{\"scalar\":{}}"));
e = 0;
testOk1(!dbChannelClose(&ch));
dbFreeBase(pdbbase);
return testDone();
}
+13
View File
@@ -0,0 +1,13 @@
# This is a combined minimal DBD and DB file
recordtype(x) {
field(NAME, DBF_STRING) {
prompt("Record Name")
special(SPC_NOMOD)
size(61)
}
field(VAL, DBF_LONG) {
prompt("Value")
}
}
record(x, x) {}
+5 -4
View File
@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* $Revision-Id$
*
@@ -19,7 +19,7 @@
#include "dbFldTypes.h"
#include "ellLib.h"
#include "dbDefs.h"
typedef struct dbMenu {
ELLNODE node;
char *name;
@@ -67,7 +67,7 @@ typedef struct brkTable { /* breakpoint table */
long number; /*number of brkInt in this table*/
struct brkInt *paBrkInt; /* ptr to array of brkInts */
}brkTable;
typedef struct dbFldDes{ /* field description */
char *prompt; /*Prompt string for DCT*/
char *name; /*Field name*/
@@ -128,7 +128,7 @@ typedef struct dbVariableDef {
ELLNODE node;
char *name;
char *type;
}dbVariableDef;
typedef struct dbRecordType {
@@ -164,6 +164,7 @@ typedef struct dbBase {
ELLLIST functionList;
ELLLIST variableList;
ELLLIST bptList;
ELLLIST filterList;
void *pathPvt;
struct dbPvd *ppvd;
struct gphPvt *pgpHash;
+80 -79
View File
@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* $Revision-Id$ */
@@ -41,7 +41,7 @@
#include "guigroup.h"
#include "dbStaticLib.h"
#include "dbStaticPvt.h"
int dbStaticDebug = 0;
static char *pNullString = "";
#define messagesize 100
@@ -191,7 +191,7 @@ sizeof(promptINST_IO)/sizeof(char *),
sizeof(promptBBGPIB_IO)/sizeof(char *),
sizeof(promptRF_IO)/sizeof(char *),
sizeof(promptVXI_IO)/sizeof(char *)};
/*forward references for private routines*/
static FILE *openOutstream(const char *filename);
static void finishOutstream(FILE *stream);
@@ -203,7 +203,7 @@ static void zeroDbentry(DBENTRY *pdbentry);
static char *getpMessage(DBENTRY *pdbentry);
static long putPvLink(DBENTRY *pdbentry,short pvlMask,const char *pvname);
static long epicsShareAPI dbAddOnePath (DBBASE *pdbbase, const char *path, unsigned length);
/* internal routines*/
static FILE *openOutstream(const char *filename)
{
@@ -347,7 +347,7 @@ void dbFreeLinkContents(struct link *plink)
if(plink->text) free(plink->text);
memset((char *)plink,0,sizeof(struct link));
}
void dbFreePath(DBBASE *pdbbase)
{
ELLLIST *ppathList;
@@ -366,7 +366,7 @@ void dbFreePath(DBBASE *pdbbase)
return;
}
static long mapLINKTtoFORMT(DBLINK *plink,dbFldDes *pflddes,int *ind)
{
switch(plink->type) {
@@ -407,7 +407,7 @@ static long mapLINKTtoFORMT(DBLINK *plink,dbFldDes *pflddes,int *ind)
}
return(S_dbLib_badLink);
}
static void entryErrMessage(DBENTRY *pdbentry,long status,char *mess)
{
char message[200];
@@ -439,7 +439,7 @@ static void entryErrMessage(DBENTRY *pdbentry,long status,char *mess)
strcat(pmessage,mess);
errMessage(status,pmessage);
}
static void zeroDbentry(DBENTRY *pdbentry)
{
/*NOTE that pdbbase, message, and formpvt MUST NOT be set to NULL*/
@@ -466,7 +466,7 @@ static long putPvLink(DBENTRY *pdbentry,short pvlMask,const char *pvname)
dbFldDes *pflddes;
DBLINK *plink;
char *pname;
dbGetFieldAddress(pdbentry);
pflddes = pdbentry->pflddes;
if(!pflddes) return(-1);
@@ -489,7 +489,7 @@ static long putPvLink(DBENTRY *pdbentry,short pvlMask,const char *pvname)
}
return(S_dbLib_badLink);
}
/*Public only for dbStaticNoRun*/
dbDeviceMenu *dbGetDeviceMenu(DBENTRY *pdbentry)
{
@@ -526,7 +526,7 @@ dbDeviceMenu *dbGetDeviceMenu(DBENTRY *pdbentry)
pflddes->ftPvt = pdbDeviceMenu;
return(pdbDeviceMenu);
}
/* Beginning of Public Routines */
#define INC_SIZE 256
@@ -555,7 +555,7 @@ void epicsShareAPI dbCatString(char **string,int *stringLength,char *src,char *s
strcat(*string,src);
*stringLength += strlen(src);
}
dbBase * epicsShareAPI dbAllocBase(void)
{
dbBase *pdbbase;
@@ -568,6 +568,7 @@ dbBase * epicsShareAPI dbAllocBase(void)
ellInit(&pdbbase->functionList);
ellInit(&pdbbase->variableList);
ellInit(&pdbbase->bptList);
ellInit(&pdbbase->filterList);
gphInitPvt(&pdbbase->pgpHash,256);
dbPvdInitPvt(pdbbase);
return (pdbbase);
@@ -595,7 +596,7 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase)
brkTable *pbrkTableNext;
int i;
DBENTRY dbentry;
dbInitEntry(pdbbase,&dbentry);
pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
@@ -620,7 +621,7 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase)
free((void *)pdbFldDes->initial);
if(pdbFldDes->field_type==DBF_DEVICE && pdbFldDes->ftPvt) {
dbDeviceMenu *pdbDeviceMenu;
pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt;
free((void *)pdbDeviceMenu->papChoice);
free((void *)pdbDeviceMenu);
@@ -729,12 +730,12 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase)
free((void *)pdbbase);
return;
}
DBENTRY * epicsShareAPI dbAllocEntry(dbBase *pdbbase)
{
DBENTRY *pdbentry;
pdbentry = dbmfMalloc(sizeof(DBENTRY));
pdbentry = dbmfMalloc(sizeof(DBENTRY));
memset(pdbentry,'\0',sizeof(DBENTRY));
pdbentry->pdbbase = pdbbase;
return(pdbentry);
@@ -780,7 +781,7 @@ void epicsShareAPI dbCopyEntryContents(DBENTRY *pfrom,DBENTRY *pto)
pto->formpvt = NULL;
}
long epicsShareAPI dbPath(DBBASE *pdbbase,const char *path)
{
if(!pdbbase) return(-1);
@@ -796,7 +797,7 @@ long epicsShareAPI dbAddPath(DBBASE *pdbbase,const char *path)
const char *plast;
unsigned expectingPath;
unsigned sawMissingPath;
if(!pdbbase) return(-1);
ppathList = (ELLLIST *)pdbbase->pathPvt;
if(!ppathList) {
@@ -865,7 +866,7 @@ static long epicsShareAPI dbAddOnePath (DBBASE *pdbbase, const char *path, unsig
{
ELLLIST *ppathList;
dbPathNode *pdbPathNode;
if(!pdbbase) return(-1);
ppathList = (ELLLIST *)pdbbase->pathPvt;
@@ -877,7 +878,7 @@ static long epicsShareAPI dbAddOnePath (DBBASE *pdbbase, const char *path, unsig
return 0;
}
long epicsShareAPI dbWriteRecord(DBBASE *ppdbbase,const char *filename,
const char *precordTypename,int level)
{
@@ -974,7 +975,7 @@ long epicsShareAPI dbWriteRecordFP(
dbFinishEntry(pdbentry);
return(0);
}
long epicsShareAPI dbWriteMenu(
DBBASE *ppdbbase,const char *filename,const char *menuName)
{
@@ -1017,7 +1018,7 @@ long epicsShareAPI dbWriteMenuFP(DBBASE *pdbbase,FILE *fp,const char *menuName)
}
return(0);
}
long epicsShareAPI dbWriteRecordType(
DBBASE *pdbbase,const char *filename,const char *recordTypeName)
{
@@ -1114,7 +1115,7 @@ long epicsShareAPI dbWriteRecordTypeFP(
}
return(0);
}
long epicsShareAPI dbWriteDevice(DBBASE *pdbbase,const char *filename)
{
FILE *stream;
@@ -1156,7 +1157,7 @@ long epicsShareAPI dbWriteDeviceFP(DBBASE *pdbbase,FILE *fp)
}
return(0);
}
long epicsShareAPI dbWriteDriver(DBBASE *pdbbase,const char *filename)
{
FILE *stream;
@@ -1227,7 +1228,7 @@ long epicsShareAPI dbWriteVariableFP(DBBASE *pdbbase,FILE *fp)
}
return(0);
}
long epicsShareAPI dbWriteBreaktable(DBBASE *pdbbase,const char *filename)
{
FILE *stream;
@@ -1262,7 +1263,7 @@ long epicsShareAPI dbWriteBreaktableFP(DBBASE *pdbbase,FILE *fp)
}
return(0);
}
long epicsShareAPI dbFindRecordType(DBENTRY *pdbentry,const char *recordType)
{
dbBase *pdbbase = pdbentry->pdbbase;
@@ -1306,7 +1307,7 @@ int epicsShareAPI dbGetNRecordTypes(DBENTRY *pdbentry)
{
return(ellCount(&pdbentry->pdbbase->recordTypeList));
}
long epicsShareAPI dbPutRecordAttribute(
DBENTRY *pdbentry, const char *name, const char*value)
{
@@ -1382,7 +1383,7 @@ long epicsShareAPI dbGetRecordAttribute(DBENTRY *pdbentry, const char *pname)
{
return dbGetAttributePart(pdbentry, &pname);
}
long epicsShareAPI dbFirstField(DBENTRY *pdbentry,int dctonly)
{
@@ -1426,7 +1427,7 @@ long epicsShareAPI dbNextField(DBENTRY *pdbentry,int dctonly)
indfield++;
}
}
int epicsShareAPI dbGetFieldType(DBENTRY *pdbentry)
{
dbFldDes *pflddes = pdbentry->pflddes;
@@ -1450,7 +1451,7 @@ int epicsShareAPI dbGetNFields(DBENTRY *pdbentry,int dctonly)
n = 0;
for(indfield=0; indfield<precordType->no_fields; indfield++) {
pflddes = precordType->papFldDes[indfield];
if(dctonly && (pflddes->field_type==DBF_DEVICE)
if(dctonly && (pflddes->field_type==DBF_DEVICE)
&& (ellCount(&precordType->devList)==0) ) continue;
if(!dctonly || pflddes->promptgroup) n++;
}
@@ -1488,7 +1489,7 @@ int epicsShareAPI dbGetPromptGroup(DBENTRY *pdbentry)
if(!pflddes) return(0);
return(pflddes->promptgroup);
}
long epicsShareAPI dbCreateRecord(DBENTRY *pdbentry,const char *precordName)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -1535,7 +1536,7 @@ long epicsShareAPI dbCreateRecord(DBENTRY *pdbentry,const char *precordName)
if(!ppvd) {errMessage(-1,"Logic Err: Could not add to PVD");return(-1);}
return(0);
}
long epicsShareAPI dbDeleteAliases(DBENTRY *pdbentry)
{
dbBase *pdbbase = pdbentry->pdbbase;
@@ -1653,7 +1654,7 @@ long epicsShareAPI dbFindRecord(DBENTRY *pdbentry, const char *pname)
return dbFindField(pdbentry, ++pname);
return 0;
}
long epicsShareAPI dbFirstRecord(DBENTRY *pdbentry)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -1706,7 +1707,7 @@ char * epicsShareAPI dbGetRecordName(DBENTRY *pdbentry)
if(!precnode) return NULL;
return precnode->recordname;
}
long epicsShareAPI dbRenameRecord(DBENTRY *pdbentry,const char *newName)
{
dbBase *pdbbase = pdbentry->pdbbase;
@@ -1752,7 +1753,7 @@ long epicsShareAPI dbRenameRecord(DBENTRY *pdbentry,const char *newName)
/*Leave pdbentry pointing to newly renamed record*/
return(dbFindRecord(pdbentry,newName));
}
long epicsShareAPI dbVisibleRecord(DBENTRY *pdbentry)
{
dbRecordNode *precnode = pdbentry->precnode;
@@ -1778,7 +1779,7 @@ int epicsShareAPI dbIsVisibleRecord(DBENTRY *pdbentry)
if(!precnode) return 0;
return precnode->flags & DBRN_FLAGS_VISIBLE ? 1 : 0;
}
long epicsShareAPI dbCreateAlias(DBENTRY *pdbentry, const char *alias)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -1828,7 +1829,7 @@ int epicsShareAPI dbIsAlias(DBENTRY *pdbentry)
if(!precnode) return 0;
return precnode->flags & DBRN_FLAGS_ISALIAS ? 1 : 0;
}
long epicsShareAPI dbCopyRecord(DBENTRY *pdbentry,const char *newRecordName,int overWriteOK)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -1882,7 +1883,7 @@ long epicsShareAPI dbCopyRecord(DBENTRY *pdbentry,const char *newRecordName,int
/*Leave pdbentry pointing to newRecordName*/
return(dbFindRecord(pdbentry,newRecordName));
}
long epicsShareAPI dbFindFieldPart(DBENTRY *pdbentry,const char **ppname)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -1967,7 +1968,7 @@ long epicsShareAPI dbFindField(DBENTRY *pdbentry,const char *pname)
int epicsShareAPI dbFoundField(DBENTRY *pdbentry)
{ return((pdbentry->pfield) ? TRUE : FALSE); }
char * epicsShareAPI dbGetString(DBENTRY *pdbentry)
{
dbFldDes *pflddes = pdbentry->pflddes;
@@ -1997,7 +1998,7 @@ char * epicsShareAPI dbGetString(DBENTRY *pdbentry)
case DBF_DEVICE:
return(dbGetStringNum(pdbentry));
case DBF_INLINK:
case DBF_OUTLINK:
case DBF_OUTLINK:
if(!pfield) {strcpy(message,"Field not found"); return(message);}
plink = (DBLINK *)pfield;
switch(plink->type) {
@@ -2138,7 +2139,7 @@ char * epicsShareAPI dbGetString(DBENTRY *pdbentry)
}
return (message);
}
static void cvtDecimalOrHexToShort(char *from,short *value)
{
if(strspn(from,"0x")==2 || strspn(from,"0X")==2) {
@@ -2264,7 +2265,7 @@ long epicsShareAPI dbPutString(DBENTRY *pdbentry,const char *pstring)
goto done;
}
switch (plink->type) {
case CONSTANT:
case CONSTANT:
case PV_LINK: {
short ppOpt = 0;
short msOpt = 0;
@@ -2428,7 +2429,7 @@ long epicsShareAPI dbPutString(DBENTRY *pdbentry,const char *pstring)
}
break;
case GPIB_IO: {
char *end;
char *end;
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
pstr = end + 1;
@@ -2545,7 +2546,7 @@ done:
}
return(status);
}
char * epicsShareAPI dbVerify(DBENTRY *pdbentry,const char *pstring)
{
dbFldDes *pflddes = pdbentry->pflddes;
@@ -2591,13 +2592,13 @@ char * epicsShareAPI dbVerify(DBENTRY *pdbentry,const char *pstring)
return(message);
}
switch (pflddes->field_type) {
case DBF_CHAR :
case DBF_CHAR :
if(value<-128 || value>127) {
strcpy(message,"must have -128<=value<=127");
return(message);
}
return(NULL);
case DBF_SHORT :
case DBF_SHORT :
if(value<-32768 || value>32767) {
strcpy(message,"must have -32768<=value<=32767");
return(message);
@@ -2626,14 +2627,14 @@ char * epicsShareAPI dbVerify(DBENTRY *pdbentry,const char *pstring)
return(message);
}
switch (pflddes->field_type) {
case DBF_UCHAR :
case DBF_UCHAR :
if(value>255) {
strcpy(message,"must have 0<=value<=255");
return(message);
}
return(NULL);
case DBF_ENUM:
case DBF_USHORT :
case DBF_USHORT :
if(value>65535) {
strcpy(message,"must have 0<=value<=65535");
return(message);
@@ -2646,7 +2647,7 @@ char * epicsShareAPI dbVerify(DBENTRY *pdbentry,const char *pstring)
}
}
case DBF_FLOAT:
case DBF_DOUBLE: {
case DBF_DOUBLE: {
double value;
char *endp;
@@ -2661,7 +2662,7 @@ char * epicsShareAPI dbVerify(DBENTRY *pdbentry,const char *pstring)
dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt;
char *pchoice;
int i;
if(!pdbMenu) return(NULL);
for (i = 0; i < pdbMenu->nChoice; i++) {
if(!(pchoice = pdbMenu->papChoiceValue[i])) continue;
@@ -2699,7 +2700,7 @@ char * epicsShareAPI dbVerify(DBENTRY *pdbentry,const char *pstring)
strcpy(message,"Not a valid field type");
return (message);
}
char *epicsShareAPI dbGetRange(DBENTRY *pdbentry)
{
dbFldDes *pflddes = pdbentry->pflddes;
@@ -2729,14 +2730,14 @@ char *epicsShareAPI dbGetRange(DBENTRY *pdbentry)
strcpy(message,"Not a valid field type");
return (message);
}
long epicsShareAPI dbFirstInfo(DBENTRY *pdbentry)
{
dbRecordNode *precnode = pdbentry->precnode;
pdbentry->pinfonode = NULL;
if (!precnode) return (S_dbLib_recNotFound);
pdbentry->pinfonode = (dbInfoNode *)ellFirst(&precnode->infoList);
return (pdbentry->pinfonode ? 0 : S_dbLib_infoNotFound);
}
@@ -2745,11 +2746,11 @@ long epicsShareAPI dbNextInfo(DBENTRY *pdbentry)
{
dbRecordNode *precnode = pdbentry->precnode;
dbInfoNode *pinfo;
if (!precnode) return (S_dbLib_recNotFound);
pinfo = pdbentry->pinfonode;
if (!pinfo) return (S_dbLib_infoNotFound);
pinfo = (dbInfoNode *)ellNext(&pinfo->node);
pdbentry->pinfonode = pinfo;
return (pinfo ? 0 : S_dbLib_infoNotFound);
@@ -2759,10 +2760,10 @@ long epicsShareAPI dbFindInfo(DBENTRY *pdbentry,const char *name)
{
dbRecordNode *precnode = pdbentry->precnode;
dbInfoNode *pinfo;
pdbentry->pinfonode = NULL;
if (!precnode) return(S_dbLib_recNotFound);
pinfo = (dbInfoNode *)ellFirst(&precnode->infoList);
while (pinfo) {
if (!strcmp(pinfo->name, name)) {
@@ -2778,7 +2779,7 @@ long epicsShareAPI dbDeleteInfo(DBENTRY *pdbentry)
{
dbRecordNode *precnode = pdbentry->precnode;
dbInfoNode *pinfo = pdbentry->pinfonode;
if (!precnode) return (S_dbLib_recNotFound);
if (!pinfo) return (S_dbLib_infoNotFound);
ellDelete(&precnode->infoList,&pinfo->node);
@@ -2841,11 +2842,11 @@ long epicsShareAPI dbPutInfo(DBENTRY *pdbentry,const char *name,const char *stri
dbInfoNode *pinfo;
dbRecordNode *precnode = pdbentry->precnode;
if (!precnode) return (S_dbLib_recNotFound);
dbFindInfo(pdbentry, name);
pinfo = pdbentry->pinfonode;
if (pinfo) return (dbPutInfoString(pdbentry, string));
/*Create new info node*/
pinfo = calloc(1,sizeof(dbInfoNode));
if (!pinfo) return (S_dbLib_outMem);
@@ -2875,7 +2876,7 @@ brkTable * epicsShareAPI dbFindBrkTable(dbBase *pdbbase,const char *name)
if(!pgph) return(NULL);
return((brkTable *)pgph->userPvt);
}
dbMenu * epicsShareAPI dbFindMenu(dbBase *pdbbase,const char *name)
{
GPHENTRY *pgph;
@@ -2933,7 +2934,7 @@ int epicsShareAPI dbGetNMenuChoices(DBENTRY *pdbentry)
}
return (-1);
}
char * epicsShareAPI dbGetMenuStringFromIndex(DBENTRY *pdbentry, int index)
{
dbFldDes *pflddes = pdbentry->pflddes;
@@ -2996,13 +2997,13 @@ int epicsShareAPI dbGetMenuIndexFromString(DBENTRY *pdbentry, const char *choice
}
return (-1);
}
drvSup * epicsShareAPI dbFindDriver(dbBase *pdbbase, const char *name) {
GPHENTRY *pgph = gphFind(pdbbase->pgpHash,name,&pdbbase->drvList);
if (!pgph) return NULL;
return (drvSup *) pgph->userPvt;
}
int epicsShareAPI dbAllocForm(DBENTRY *psave)
{
DBENTRY dbEntry;
@@ -3076,7 +3077,7 @@ done:
dbFinishEntry(pdbentry);
return(nlines);
}
long epicsShareAPI dbFreeForm(DBENTRY *pdbentry)
{
if(pdbentry->formpvt) {
@@ -3093,7 +3094,7 @@ char ** epicsShareAPI dbGetFormPrompt(DBENTRY *pdbentry)
if(!pform) return(NULL);
return(pform->prompt);
}
char ** epicsShareAPI dbGetFormValue(DBENTRY *pdbentry)
{
struct form *pform = pdbentry->formpvt;
@@ -3105,7 +3106,7 @@ char ** epicsShareAPI dbGetFormValue(DBENTRY *pdbentry)
if(!plink) return(NULL);
value = pform->value;
switch(pform->linkType) {
case FORM_CONSTANT:
case FORM_CONSTANT:
if(plink->value.constantStr) {
strcpy(*value,plink->value.constantStr);
} else {
@@ -3263,7 +3264,7 @@ char ** epicsShareAPI dbGetFormValue(DBENTRY *pdbentry)
}
return(pform->value);
}
long epicsShareAPI dbPutForm(DBENTRY *pdbentry,char **value)
{
struct form *pform = pdbentry->formpvt;
@@ -3279,7 +3280,7 @@ long epicsShareAPI dbPutForm(DBENTRY *pdbentry,char **value)
if(!plink) return(S_dbLib_badLink);
verify = pform->verify;
switch(pform->linkType) {
case FORM_CONSTANT:
case FORM_CONSTANT:
**verify = 0; /*Initialize to no error*/
if(**value == '\0') break;
dvalue = epicsStrtod(*value,&endp);
@@ -3580,7 +3581,7 @@ long epicsShareAPI dbPutForm(DBENTRY *pdbentry,char **value)
**verify = 0;
break;
case FORM_VXI_IO:
plink->value.vxiio.flag =
plink->value.vxiio.flag =
((strchr(*value,'Y')||strchr(*value,'y') ? VXIDYNAMIC : VXISTATIC));
value++; verify++;
lvalue = strtol(*value,&endp,0);
@@ -3619,7 +3620,7 @@ long epicsShareAPI dbPutForm(DBENTRY *pdbentry,char **value)
}
return(status);
}
char ** epicsShareAPI dbVerifyForm(DBENTRY *pdbentry,char **value)
{
struct form *pform = pdbentry->formpvt;
@@ -3664,7 +3665,7 @@ char * epicsShareAPI dbGetRelatedField(DBENTRY *psave)
dbFinishEntry(pdbentry);
return(rtnval);
}
int epicsShareAPI dbGetNLinks(DBENTRY *pdbentry)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -3715,7 +3716,7 @@ int epicsShareAPI dbGetLinkType(DBENTRY *pdbentry)
}
return(-1);
}
long epicsShareAPI dbCvtLinkToConstant(DBENTRY *pdbentry)
{
dbFldDes *pflddes;
@@ -3779,7 +3780,7 @@ long epicsShareAPI dbCvtLinkToPvlink(DBENTRY *pdbentry)
}
return(S_dbLib_badLink);
}
void epicsShareAPI dbDumpPath(DBBASE *pdbbase)
{
ELLLIST *ppathList;
@@ -3821,7 +3822,7 @@ void epicsShareAPI dbDumpMenu(dbBase *pdbbase,const char *menuName)
}
dbWriteMenuFP(pdbbase,stdout,menuName);
}
void epicsShareAPI dbDumpRecordType(DBBASE *pdbbase,const char *recordTypeName)
{
dbRecordType *pdbRecordType;
@@ -3863,7 +3864,7 @@ void epicsShareAPI dbDumpRecordType(DBBASE *pdbbase,const char *recordTypeName)
if(recordTypeName) break;
}
}
void epicsShareAPI dbDumpField(
DBBASE *pdbbase,const char *recordTypeName,const char *fname)
{
@@ -3955,7 +3956,7 @@ void epicsShareAPI dbDumpField(
if(recordTypeName) break;
}
}
void epicsShareAPI dbDumpDevice(DBBASE *pdbbase,const char *recordTypeName)
{
dbRecordType *pdbRecordType;
@@ -4051,7 +4052,7 @@ void epicsShareAPI dbDumpBreaktable(DBBASE *pdbbase,const char *name)
}
return;
}
static char *bus[VXI_IO+1] = {"","","VME","CAMAC","AB",
"GPIB","BITBUS","","","","","","INST","BBGPIB","VXI"};
void epicsShareAPI dbReportDeviceConfig(dbBase *pdbbase,FILE *report)