diff --git a/src/ioc/db/dbChannel.c b/src/ioc/db/dbChannel.c index d58df92a0..313ecea72 100644 --- a/src/ioc/db/dbChannel.c +++ b/src/ioc/db/dbChannel.c @@ -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; } diff --git a/src/ioc/db/dbChannel.h b/src/ioc/db/dbChannel.h index 1508d5c1a..aa43325b0 100644 --- a/src/ioc/db/dbChannel.h +++ b/src/ioc/db/dbChannel.h @@ -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); diff --git a/src/ioc/db/test/dbChannelTest.c b/src/ioc/db/test/dbChannelTest.c index 31ca3180d..221a6b3d5 100644 --- a/src/ioc/db/test/dbChannelTest.c +++ b/src/ioc/db/test/dbChannelTest.c @@ -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(); } diff --git a/src/ioc/db/test/dbChannelTest.dbx b/src/ioc/db/test/dbChannelTest.dbx new file mode 100644 index 000000000..b743359c1 --- /dev/null +++ b/src/ioc/db/test/dbChannelTest.dbx @@ -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) {} diff --git a/src/ioc/dbStatic/dbBase.h b/src/ioc/dbStatic/dbBase.h index 55268ea3a..6be2465d5 100644 --- a/src/ioc/dbStatic/dbBase.h +++ b/src/ioc/dbStatic/dbBase.h @@ -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; diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index 7b42704f5..bcd630c6c 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -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; indfieldno_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)