Files
epics-base/modules/database/src/ioc/db/dbTest.c
2020-10-29 17:07:35 -05:00

1336 lines
40 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*************************************************************************\
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* SPDX-License-Identifier: EPICS
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* database access test subroutines */
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include "cvtFast.h"
#include "dbDefs.h"
#include "ellLib.h"
#include "epicsMutex.h"
#include "epicsStdio.h"
#include "epicsStdlib.h"
#include "epicsString.h"
#include "errlog.h"
#define epicsExportSharedSymbols
#include "callback.h"
#include "dbAccessDefs.h"
#include "dbAddr.h"
#include "dbBase.h"
#include "dbCommon.h"
#include "dbEvent.h"
#include "db_field_log.h"
#include "dbFldTypes.h"
#include "dbLock.h"
#include "dbStaticLib.h"
#include "dbTest.h"
#include "devSup.h"
#include "drvSup.h"
#include "link.h"
#include "recGbl.h"
#include "recSup.h"
#include "special.h"
#include "dbConvertJSON.h"
#define MAXLINE 80
#define MAXMESS 128
struct msgBuff { /* line output structure */
char out_buff[MAXLINE + 1];
char *pNext;
char *pLast;
char *pNexTab;
char message[MAXMESS];
};
typedef struct msgBuff TAB_BUFFER;
#ifndef MIN
# define MIN(x,y) (((x) < (y)) ? (x) : (y))
#endif
#ifndef MAX
# define MAX(x,y) (((x) > (y)) ? (x) : (y))
#endif
/* Local Routines */
static long nameToAddr(const char *pname, DBADDR *paddr);
static void printDbAddr(DBADDR *paddr);
static void printBuffer(long status, short dbr_type, void *pbuffer,
long reqOptions, long retOptions, long no_elements,
TAB_BUFFER *pMsgBuff, int tab_size);
static int dbpr_report(const char *pname, DBADDR *paddr, int interest_level,
TAB_BUFFER *pMsgBuff, int tab_size);
static void dbpr_msgOut(TAB_BUFFER *pMsgBuff,int tab_size);
static void dbpr_init_msg(TAB_BUFFER *pMsgBuff,int tab_size);
static void dbpr_insert_msg(TAB_BUFFER *pMsgBuff,size_t len,int tab_size);
static void dbpr_msg_flush(TAB_BUFFER *pMsgBuff,int tab_size);
static char *dbf[DBF_NTYPES] = {
"STRING","CHAR","UCHAR","SHORT","USHORT","LONG","ULONG",
"INT64","UINT64","FLOAT","DOUBLE","ENUM","MENU","DEVICE",
"INLINK","OUTLINK","FWDLINK","NOACCESS"
};
static char *dbr[DBR_ENUM+2] = {
"STRING","CHAR","UCHAR","SHORT","USHORT","LONG","ULONG",
"INT64","UINT64","FLOAT","DOUBLE","ENUM","NOACCESS"
};
long dba(const char*pname)
{
DBADDR addr;
if (!pname || !*pname) {
printf("Usage: dba \"pv name\"\n");
return 1;
}
if (nameToAddr(pname, &addr))
return -1;
printDbAddr(&addr);
return 0;
}
long dbl(const char *precordTypename, const char *fields)
{
DBENTRY dbentry;
DBENTRY *pdbentry=&dbentry;
long status;
int nfields = 0;
int ifield;
char *fieldnames = 0;
char **papfields = 0;
if (!pdbbase) {
printf("No database loaded\n");
return 0;
}
if (precordTypename &&
((*precordTypename == '\0') || !strcmp(precordTypename,"*")))
precordTypename = NULL;
if (fields && (*fields == '\0'))
fields = NULL;
if (fields) {
char *pnext;
fieldnames = epicsStrDup(fields);
nfields = 1;
pnext = fieldnames;
while (*pnext && (pnext = strchr(pnext,' '))) {
nfields++;
while (*pnext == ' ') pnext++;
}
papfields = dbCalloc(nfields,sizeof(char *));
pnext = fieldnames;
for (ifield = 0; ifield < nfields; ifield++) {
papfields[ifield] = pnext;
if (ifield < nfields - 1) {
pnext = strchr(pnext, ' ');
*pnext++ = 0;
while (*pnext == ' ') pnext++;
}
}
}
dbInitEntry(pdbbase, pdbentry);
if (!precordTypename)
status = dbFirstRecordType(pdbentry);
else
status = dbFindRecordType(pdbentry,precordTypename);
if (status) {
printf("No record type\n");
}
while (!status) {
status = dbFirstRecord(pdbentry);
while (!status) {
printf("%s", dbGetRecordName(pdbentry));
for (ifield = 0; ifield < nfields; ifield++) {
char *pvalue;
status = dbFindField(pdbentry, papfields[ifield]);
if (status) {
if (!strcmp(papfields[ifield], "recordType")) {
pvalue = dbGetRecordTypeName(pdbentry);
}
else {
printf(", ");
continue;
}
}
else {
pvalue = dbGetString(pdbentry);
}
printf(", \"%s\"", pvalue ? pvalue : "");
}
printf("\n");
status = dbNextRecord(pdbentry);
}
if (precordTypename)
break;
status = dbNextRecordType(pdbentry);
}
if (nfields > 0) {
free((void *)papfields);
free((void *)fieldnames);
}
dbFinishEntry(pdbentry);
return 0;
}
long dbnr(int verbose)
{
DBENTRY dbentry;
DBENTRY *pdbentry=&dbentry;
long status;
int nrecords;
int naliases;
int trecords = 0;
int taliases = 0;
if (!pdbbase) {
printf("No database loaded\n");
return 0;
}
dbInitEntry(pdbbase, pdbentry);
status = dbFirstRecordType(pdbentry);
if (status) {
printf("No record types loaded\n");
return 0;
}
printf("Records Aliases Record Type\n");
while (!status) {
naliases = dbGetNAliases(pdbentry);
taliases += naliases;
nrecords = dbGetNRecords(pdbentry) - naliases;
trecords += nrecords;
if (verbose || nrecords)
printf(" %5d %5d %s\n",
nrecords, naliases, dbGetRecordTypeName(pdbentry));
status = dbNextRecordType(pdbentry);
}
dbFinishEntry(pdbentry);
printf("Total %d records, %d aliases\n", trecords, taliases);
return 0;
}
long dbla(const char *pmask)
{
DBENTRY dbentry;
DBENTRY *pdbentry = &dbentry;
long status;
if (!pdbbase) {
printf("No database loaded\n");
return 0;
}
dbInitEntry(pdbbase, pdbentry);
status = dbFirstRecordType(pdbentry);
while (!status) {
for (status = dbFirstRecord(pdbentry); !status;
status = dbNextRecord(pdbentry)) {
char *palias;
if (!dbIsAlias(pdbentry))
continue;
palias = dbGetRecordName(pdbentry);
if (pmask && *pmask && !epicsStrGlobMatch(palias, pmask))
continue;
dbFindField(pdbentry, "NAME");
printf("%s -> %s\n", palias, dbGetString(pdbentry));
}
status = dbNextRecordType(pdbentry);
}
dbFinishEntry(pdbentry);
return 0;
}
long dbli(const char *pattern)
{
DBENTRY dbentry;
void* ptr;
if (!pdbbase) {
printf("No database loaded\n");
return 0;
}
dbInitEntry(pdbbase, &dbentry);
while (dbNextMatchingInfo(&dbentry, pattern) == 0)
{
printf("%s info(%s, \"%s\"", dbGetRecordName(&dbentry),
dbGetInfoName(&dbentry), dbGetInfoString(&dbentry));
if ((ptr = dbGetInfoPointer(&dbentry)) != NULL)
printf(", %p", ptr);
printf(")\n");
}
dbFinishEntry(&dbentry);
return 0;
}
long dbgrep(const char *pmask)
{
DBENTRY dbentry;
DBENTRY *pdbentry = &dbentry;
long status;
if (!pmask || !*pmask) {
printf("Usage: dbgrep \"pattern\"\n");
return 1;
}
if (!pdbbase) {
printf("No database loaded\n");
return 0;
}
dbInitEntry(pdbbase, pdbentry);
status = dbFirstRecordType(pdbentry);
while (!status) {
status = dbFirstRecord(pdbentry);
while (!status) {
char *pname = dbGetRecordName(pdbentry);
if (epicsStrGlobMatch(pname, pmask))
puts(pname);
status = dbNextRecord(pdbentry);
}
status = dbNextRecordType(pdbentry);
}
dbFinishEntry(pdbentry);
return 0;
}
long dbgf(const char *pname)
{
/* declare buffer long just to ensure correct alignment */
long buffer[100];
long *pbuffer=&buffer[0];
DBADDR addr;
long options = 0;
long no_elements;
static TAB_BUFFER msg_Buff;
if (!pname || !*pname) {
printf("Usage: dbgf \"pv name\"\n");
return 1;
}
if (nameToAddr(pname, &addr))
return -1;
if (addr.precord->lset == NULL) {
printf("dbgf only works after iocInit\n");
return -1;
}
no_elements = MIN(addr.no_elements, sizeof(buffer)/addr.field_size);
if (addr.dbr_field_type == DBR_ENUM) {
long status = dbGetField(&addr, DBR_STRING, pbuffer,
&options, &no_elements, NULL);
printBuffer(status, DBR_STRING, pbuffer, 0L, 0L,
no_elements, &msg_Buff, 10);
}
else {
long status = dbGetField(&addr, addr.dbr_field_type, pbuffer,
&options, &no_elements, NULL);
printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L,
no_elements, &msg_Buff, 10);
}
msg_Buff.message[0] = '\0';
dbpr_msgOut(&msg_Buff, 10);
return 0;
}
long dbpf(const char *pname,const char *pvalue)
{
DBADDR addr;
long status;
short dbrType = DBR_STRING;
long n = 1;
char *array = NULL;
if (!pname || !*pname || !pvalue) {
printf("Usage: dbpf \"pv name\", \"value\"\n");
return 1;
}
if (nameToAddr(pname, &addr))
return -1;
if (addr.precord->lset == NULL) {
printf("dbpf only works after iocInit\n");
return -1;
}
if (addr.no_elements > 1) {
dbrType = addr.dbr_field_type;
if (addr.dbr_field_type == DBR_CHAR || addr.dbr_field_type == DBR_UCHAR) {
n = (long)strlen(pvalue) + 1;
} else {
n = addr.no_elements;
array = calloc(n, dbValueSize(dbrType));
if (!array) {
printf("Out of memory\n");
return -1;
}
status = dbPutConvertJSON(pvalue, dbrType, array, &n);
if (status)
return status;
pvalue = array;
}
}
status = dbPutField(&addr, dbrType, pvalue, n);
free(array);
dbgf(pname);
return status;
}
long dbpr(const char *pname,int interest_level)
{
static TAB_BUFFER msg_Buff;
TAB_BUFFER *pMsgBuff = &msg_Buff;
DBADDR addr;
char *pmsg;
int tab_size = 20;
if (!pname || !*pname) {
printf("Usage: dbpr \"pv name\", level\n");
return 1;
}
if (nameToAddr(pname, &addr))
return -1;
pmsg = pMsgBuff->message;
if (dbpr_report(pname, &addr, interest_level, pMsgBuff, tab_size))
return 1;
pmsg[0] = '\0';
dbpr_msgOut(pMsgBuff, tab_size);
return 0;
}
long dbtr(const char *pname)
{
DBADDR addr;
long status;
struct dbCommon *precord;
if (!pname || !*pname) {
printf("Usage: dbtr \"pv name\"\n");
return 1;
}
if (nameToAddr(pname, &addr))
return -1;
if (addr.precord->lset == NULL) {
printf("dbtr only works after iocInit\n");
return -1;
}
precord = (struct dbCommon*)addr.precord;
if (precord->pact) {
printf("record active\n");
return 1;
}
dbScanLock(precord);
status = dbProcess(precord);
dbScanUnlock(precord);
if (status)
recGblRecordError(status, precord, "dbtr(dbProcess)");
dbpr(pname, 3);
return 0;
}
long dbtgf(const char *pname)
{
/* declare buffer long just to ensure correct alignment */
long buffer[400];
long *pbuffer = &buffer[0];
DBADDR addr;
long status;
long req_options, ret_options, no_elements;
short dbr_type;
static TAB_BUFFER msg_Buff;
TAB_BUFFER *pMsgBuff = &msg_Buff;
char *pmsg = pMsgBuff->message;
int tab_size = 10;
if (pname==0 || *pname==0) {
printf("Usage: dbtgf \"pv name\"\n");
return 1;
}
if (nameToAddr(pname, &addr))
return -1;
if (addr.precord->lset == NULL) {
printf("dbtgf only works after iocInit\n");
return -1;
}
/* try all options first */
req_options = 0xffffffff;
ret_options = req_options;
no_elements = 0;
status = dbGetField(&addr, addr.dbr_field_type, pbuffer,
&ret_options, &no_elements, NULL);
printBuffer(status, addr.dbr_field_type, pbuffer,
req_options, ret_options, no_elements, pMsgBuff, tab_size);
/* Now try all request types */
ret_options=0;
dbr_type = DBR_STRING;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/MAX_STRING_SIZE));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_CHAR;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt8)));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_UCHAR;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt8)));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_SHORT;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt16)));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_USHORT;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt16)));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_LONG;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt32)));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_ULONG;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt32)));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_INT64;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt64)));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_UINT64;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt64)));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_FLOAT;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat32)));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_DOUBLE;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat64)));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_ENUM;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsEnum16)));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
pmsg[0] = '\0';
dbpr_msgOut(pMsgBuff, tab_size);
return(0);
}
long dbtpf(const char *pname, const char *pvalue)
{
/* declare buffer long just to ensure correct alignment */
long buffer[100];
long *pbuffer = buffer;
DBADDR addr;
int put_type;
static TAB_BUFFER msg_Buff;
TAB_BUFFER *pMsgBuff = &msg_Buff;
char *pmsg = pMsgBuff->message;
int tab_size = 10;
if (!pname || !*pname || !pvalue) {
printf("Usage: dbtpf \"pv name\", \"value\"\n");
return 1;
}
if (nameToAddr(pname, &addr))
return -1;
if (addr.precord->lset == NULL) {
printf("dbtpf only works after iocInit\n");
return -1;
}
for (put_type = DBR_STRING; put_type <= DBF_ENUM; put_type++) {
union {
epicsInt8 i8;
epicsUInt8 u8;
epicsInt16 i16;
epicsUInt16 u16;
epicsInt32 i32;
epicsUInt32 u32;
epicsInt64 i64;
epicsUInt64 u64;
epicsFloat32 f32;
epicsFloat64 f64;
epicsEnum16 e16;
} val;
const void *pval = &val;
int valid = 1;
switch (put_type) {
case DBR_STRING:
pval = pvalue;
break;
case DBR_CHAR:
valid = !epicsParseInt8(pvalue, &val.i8, 10, NULL);
break;
case DBR_UCHAR:
valid = !epicsParseUInt8(pvalue, &val.u8, 10, NULL);
break;
case DBR_SHORT:
valid = !epicsParseInt16(pvalue, &val.i16, 10, NULL);
break;
case DBR_USHORT:
valid = !epicsParseUInt16(pvalue, &val.u16, 10, NULL);
break;
case DBR_LONG:
valid = !epicsParseInt32(pvalue, &val.i32, 10, NULL);
break;
case DBR_ULONG:
valid = !epicsParseUInt32(pvalue, &val.u32, 10, NULL);
break;
case DBR_INT64:
valid = !epicsParseInt64(pvalue, &val.i64, 10, NULL);
break;
case DBR_UINT64:
valid = !epicsParseUInt64(pvalue, &val.u64, 10, NULL);
break;
case DBR_FLOAT:
valid = !epicsParseFloat32(pvalue, &val.f32, NULL);
break;
case DBR_DOUBLE:
valid = !epicsParseFloat64(pvalue, &val.f64, NULL);
break;
case DBR_ENUM:
valid = !epicsParseUInt16(pvalue, &val.e16, 10, NULL);
break;
}
if (valid) {
long status = dbPutField(&addr, put_type, pval, 1);
if (status) {
printf("Put as DBR_%-6s Failed.\n", dbr[put_type]);
}
else {
long options = 0;
long no_elements = MIN(addr.no_elements,
((sizeof(buffer))/addr.field_size));
printf("Put as DBR_%-6s Ok, result as ", dbr[put_type]);
status = dbGetField(&addr, addr.dbr_field_type, pbuffer,
&options, &no_elements, NULL);
printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L,
no_elements, pMsgBuff, tab_size);
}
}
else {
printf("Cvt to DBR_%s failed.\n", dbr[put_type]);
}
}
pmsg[0] = '\0';
dbpr_msgOut(pMsgBuff, tab_size);
return 0;
}
long dbior(const char *pdrvName,int interest_level)
{
drvSup *pdrvSup;
struct drvet *pdrvet;
dbRecordType *pdbRecordType;
if (!pdbbase) {
printf("No database loaded\n");
return 0;
}
if (pdrvName && ((*pdrvName == '\0') || !strcmp(pdrvName,"*")))
pdrvName = NULL;
for (pdrvSup = (drvSup *)ellFirst(&pdbbase->drvList);
pdrvSup;
pdrvSup = (drvSup *)ellNext(&pdrvSup->node)) {
const char *pname = pdrvSup->name;
if (pdrvName!=NULL && *pdrvName!='\0' &&
(strcmp(pdrvName,pname)!=0))
continue;
pdrvet = pdrvSup->pdrvet ;
if (pdrvet == NULL) {
printf("No driver entry table is present for %s\n", pname);
continue;
}
if (pdrvet->report == NULL)
printf("Driver: %s No report available\n", pname);
else {
printf("Driver: %s\n", pname);
pdrvet->report(interest_level);
}
}
/* now check devSup reports */
for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
devSup *pdevSup;
for (pdevSup = (devSup *)ellFirst(&pdbRecordType->devList);
pdevSup;
pdevSup = (devSup *)ellNext(&pdevSup->node)) {
dset *pdset = pdevSup->pdset;
const char *pname = pdevSup->name;
if (!pdset || !pname)
continue;
if (pdrvName != NULL && *pdrvName != '\0' &&
(strcmp(pdrvName, pname) != 0))
continue;
if (pdset->report != NULL) {
printf("Device Support: %s\n", pname);
pdset->report(interest_level);
}
}
}
return 0;
}
int dbhcr(void)
{
if (!pdbbase) {
printf("No database loaded\n");
return 0;
}
dbReportDeviceConfig(pdbbase, stdout);
return 0;
}
static long nameToAddr(const char *pname, DBADDR *paddr)
{
long status = dbNameToAddr(pname, paddr);
if (status) {
printf("PV '%s' not found\n", pname);
}
return status;
}
static void printDbAddr(DBADDR *paddr)
{
dbFldDes *pdbFldDes = paddr->pfldDes;
short field_type = paddr->field_type;
short dbr_field_type = paddr->dbr_field_type;
printf("Record Address: %p", paddr->precord);
printf(" Field Address: %p", paddr->pfield);
printf(" Field Description: %p\n", pdbFldDes);
printf(" No Elements: %ld\n", paddr->no_elements);
printf(" Record Type: %s\n", pdbFldDes->pdbRecordType->name);
printf(" Field Type: %d = DBF_%s\n", field_type,
(field_type < 0 || field_type > DBR_NOACCESS) ? "????" :
dbf[field_type]);
printf(" Field Size: %d\n", paddr->field_size);
printf(" Special: %d\n", paddr->special);
if (dbr_field_type == DBR_NOACCESS)
dbr_field_type = DBR_ENUM + 1;
printf("DBR Field Type: %d = DBR_%s\n", paddr->dbr_field_type,
(dbr_field_type < 0 || dbr_field_type > (DBR_ENUM+1)) ? "????" :
dbr[dbr_field_type]);
}
static void printBuffer(
long status, short dbr_type, void *pbuffer, long reqOptions,
long retOptions, long no_elements, TAB_BUFFER *pMsgBuff, int tab_size)
{
char *pmsg = pMsgBuff->message;
int i;
if (reqOptions & DBR_STATUS) {
if (retOptions & DBR_STATUS) {
struct dbr_status *pdbr_status = (void *)pbuffer;
printf("status = %u, severity = %u\n",
pdbr_status->status,
pdbr_status->severity);
}
else {
printf("status and severity not returned\n");
}
pbuffer = (char *)pbuffer + dbr_status_size;
}
if (reqOptions & DBR_UNITS) {
if (retOptions & DBR_UNITS) {
struct dbr_units *pdbr_units = (void *)pbuffer;
printf("units = \"%s\"\n",
pdbr_units->units);
}
else {
printf("units not returned\n");
}
pbuffer = (char *)pbuffer + dbr_units_size;
}
if (reqOptions & DBR_PRECISION) {
if (retOptions & DBR_PRECISION){
struct dbr_precision *pdbr_precision = (void *)pbuffer;
printf("precision = %ld\n",
pdbr_precision->precision.dp);
}
else {
printf("precision not returned\n");
}
pbuffer = (char *)pbuffer + dbr_precision_size;
}
if (reqOptions & DBR_TIME) {
if (retOptions & DBR_TIME) {
struct dbr_time *pdbr_time = (void *)pbuffer;
char time_buf[40];
epicsTimeToStrftime(time_buf, 40, "%Y-%m-%d %H:%M:%S.%09f",
&pdbr_time->time);
printf("time = %s\n", time_buf);
}
else {
printf("time not returned\n");
}
pbuffer = (char *)pbuffer + dbr_time_size;
}
if (reqOptions & DBR_ENUM_STRS) {
if (retOptions & DBR_ENUM_STRS) {
struct dbr_enumStrs *pdbr_enumStrs = (void *)pbuffer;
printf("no_strs = %u:\n",
pdbr_enumStrs->no_str);
for (i = 0; i < pdbr_enumStrs->no_str; i++)
printf("\t\"%s\"\n", pdbr_enumStrs->strs[i]);
}
else {
printf("enum strings not returned\n");
}
pbuffer = (char *)pbuffer + dbr_enumStrs_size;
}
if (reqOptions & DBR_GR_LONG) {
if (retOptions & DBR_GR_LONG) {
struct dbr_grLong *pdbr_grLong = (void *)pbuffer;
printf("grLong: %d .. %d\n",
pdbr_grLong->lower_disp_limit,
pdbr_grLong->upper_disp_limit);
}
else {
printf("DBRgrLong not returned\n");
}
pbuffer = (char *)pbuffer + dbr_grLong_size;
}
if (reqOptions & DBR_GR_DOUBLE) {
if (retOptions & DBR_GR_DOUBLE) {
struct dbr_grDouble *pdbr_grDouble = (void *)pbuffer;
printf("grDouble: %g .. %g\n",
pdbr_grDouble->lower_disp_limit,
pdbr_grDouble->upper_disp_limit);
}
else {
printf("DBRgrDouble not returned\n");
}
pbuffer = (char *)pbuffer + dbr_grDouble_size;
}
if (reqOptions & DBR_CTRL_LONG) {
if (retOptions & DBR_CTRL_LONG){
struct dbr_ctrlLong *pdbr_ctrlLong = (void *)pbuffer;
printf("ctrlLong: %d .. %d\n",
pdbr_ctrlLong->lower_ctrl_limit,
pdbr_ctrlLong->upper_ctrl_limit);
}
else {
printf("DBRctrlLong not returned\n");
}
pbuffer = (char *)pbuffer + dbr_ctrlLong_size;
}
if (reqOptions & DBR_CTRL_DOUBLE) {
if (retOptions & DBR_CTRL_DOUBLE) {
struct dbr_ctrlDouble *pdbr_ctrlDouble = (void *)pbuffer;
printf("ctrlDouble: %g .. %g\n",
pdbr_ctrlDouble->lower_ctrl_limit,
pdbr_ctrlDouble->upper_ctrl_limit);
}
else {
printf("DBRctrlDouble not returned\n");
}
pbuffer = (char *)pbuffer + dbr_ctrlDouble_size;
}
if (reqOptions & DBR_AL_LONG) {
if (retOptions & DBR_AL_LONG) {
struct dbr_alLong *pdbr_alLong = (void *)pbuffer;
printf("alLong: %d < %d .. %d < %d\n",
pdbr_alLong->lower_alarm_limit,
pdbr_alLong->lower_warning_limit,
pdbr_alLong->upper_warning_limit,
pdbr_alLong->upper_alarm_limit);
}
else {
printf("DBRalLong not returned\n");
}
pbuffer = (char *)pbuffer + dbr_alLong_size;
}
if (reqOptions & DBR_AL_DOUBLE) {
if (retOptions & DBR_AL_DOUBLE) {
struct dbr_alDouble *pdbr_alDouble = (void *)pbuffer;
printf("alDouble: %g < %g .. %g < %g\n",
pdbr_alDouble->lower_alarm_limit,
pdbr_alDouble->lower_warning_limit,
pdbr_alDouble->upper_warning_limit,
pdbr_alDouble->upper_alarm_limit);
}
else {
printf("DBRalDouble not returned\n");
}
pbuffer = (char *)pbuffer + dbr_alDouble_size;
}
/* Now print values */
if (no_elements == 0)
return;
if (no_elements == 1)
sprintf(pmsg, "DBF_%s: ", dbr[dbr_type]);
else
sprintf(pmsg, "DBF_%s[%ld]: ", dbr[dbr_type], no_elements);
dbpr_msgOut(pMsgBuff, tab_size);
if (status != 0) {
strcpy(pmsg, "failed.");
dbpr_msgOut(pMsgBuff, tab_size);
}
else {
switch (dbr_type) {
case DBR_STRING:
for(i=0; i<no_elements; i++) {
size_t len = strlen(pbuffer);
strcpy(pmsg, "\"");
epicsStrnEscapedFromRaw(pmsg+1, MAXLINE - 3,
(char *)pbuffer, len);
strcat(pmsg, "\"");
dbpr_msgOut(pMsgBuff, tab_size);
pbuffer = (char *)pbuffer + MAX_STRING_SIZE;
}
break;
case DBR_CHAR:
if (no_elements == 1) {
epicsInt32 val = *(epicsInt8 *) pbuffer;
if (isprint(val))
sprintf(pmsg, "%d = 0x%x = '%c'", val, val & 0xff, val);
else
sprintf(pmsg, "%d = 0x%x", val, val & 0xff);
dbpr_msgOut(pMsgBuff, tab_size);
} else {
size_t len = epicsStrnLen(pbuffer, no_elements);
i = 0;
while (len > 0) {
int chunk = (len > MAXLINE - 5) ? MAXLINE - 5 : len;
sprintf(pmsg, "\"%.*s\"", chunk, (char *)pbuffer + i);
len -= chunk; i += chunk;
if (len > 0)
strcat(pmsg, " +");
dbpr_msgOut(pMsgBuff, tab_size);
}
}
break;
case DBR_UCHAR:
for (i = 0; i < no_elements; i++) {
epicsUInt32 val = *(epicsUInt8 *) pbuffer;
sprintf(pmsg, "%u = 0x%x", val, val);
dbpr_msgOut(pMsgBuff, tab_size);
pbuffer = (char *)pbuffer + sizeof(epicsUInt8);
}
break;
case DBR_SHORT:
for (i = 0; i < no_elements; i++) {
epicsInt16 val = *(epicsInt16 *) pbuffer;
sprintf(pmsg, "%hd = 0x%hx", val, val);
dbpr_msgOut(pMsgBuff, tab_size);
pbuffer = (char *)pbuffer + sizeof(epicsInt16);
}
break;
case DBR_USHORT:
for (i = 0; i < no_elements; i++) {
epicsUInt16 val = *(epicsUInt16 *) pbuffer;
sprintf(pmsg, "%hu = 0x%hx", val, val);
dbpr_msgOut(pMsgBuff, tab_size);
pbuffer = (char *)pbuffer + sizeof(epicsUInt16);
}
break;
case DBR_LONG:
for (i = 0; i < no_elements; i++) {
epicsInt32 val = *(epicsInt32 *) pbuffer;
sprintf(pmsg, "%d = 0x%x", val, val);
dbpr_msgOut(pMsgBuff, tab_size);
pbuffer = (char *)pbuffer + sizeof(epicsInt32);
}
break;
case DBR_ULONG:
for (i = 0; i < no_elements; i++) {
epicsUInt32 val = *(epicsUInt32 *) pbuffer;
sprintf(pmsg, "%u = 0x%x", val, val);
dbpr_msgOut(pMsgBuff, tab_size);
pbuffer = (char *)pbuffer + sizeof(epicsUInt32);
}
break;
case DBR_INT64:
for (i = 0; i < no_elements; i++) {
epicsInt64 val = *(epicsInt64 *) pbuffer;
pmsg += cvtInt64ToString(val, pmsg);
strcpy(pmsg, " = ");
pmsg += 3;
cvtInt64ToHexString(val, pmsg);
dbpr_msgOut(pMsgBuff, tab_size);
pmsg = pMsgBuff->message;
pbuffer = (char *)pbuffer + sizeof(epicsInt64);
}
break;
case DBR_UINT64:
for (i = 0; i < no_elements; i++) {
epicsUInt64 val = *(epicsUInt64 *) pbuffer;
pmsg += cvtUInt64ToString(val, pmsg);
strcpy(pmsg, " = ");
pmsg += 3;
cvtUInt64ToHexString(val, pmsg);
dbpr_msgOut(pMsgBuff, tab_size);
pmsg = pMsgBuff->message;
pbuffer = (char *)pbuffer + sizeof(epicsUInt64);
}
break;
case DBR_FLOAT:
for (i = 0; i < no_elements; i++) {
sprintf(pmsg, "%.6g", *((epicsFloat32 *) pbuffer));
dbpr_msgOut(pMsgBuff, tab_size);
pbuffer = (char *)pbuffer + sizeof(epicsFloat32);
}
break;
case DBR_DOUBLE:
for (i = 0; i < no_elements; i++) {
sprintf(pmsg, "%.12g", *((epicsFloat64 *) pbuffer));
dbpr_msgOut(pMsgBuff, tab_size);
pbuffer = (char *)pbuffer + sizeof(epicsFloat64);
}
break;
case DBR_ENUM:
for (i = 0; i < no_elements; i++) {
sprintf(pmsg, "%u", *((epicsEnum16 *) pbuffer));
dbpr_msgOut(pMsgBuff, tab_size);
pbuffer = (char *)pbuffer + sizeof(epicsEnum16);
}
break;
default:
sprintf(pmsg, "Bad DBR type %d", dbr_type);
dbpr_msgOut(pMsgBuff, tab_size);
break;
}
}
dbpr_msg_flush(pMsgBuff, tab_size);
}
static int dbpr_report(
const char *pname, DBADDR *paddr, int interest_level,
TAB_BUFFER *pMsgBuff, int tab_size)
{
char *pmsg;
dbFldDes *pdbFldDes = paddr->pfldDes;
dbRecordType *pdbRecordType = pdbFldDes->pdbRecordType;
short n2;
void *pfield;
char *pfield_name;
char *pfield_value;
DBENTRY dbentry;
DBENTRY *pdbentry = &dbentry;
long status;
dbInitEntry(pdbbase,pdbentry);
status = dbFindRecord(pdbentry,pname);
if (status) {
errMessage(status,pname);
return -1;
}
pmsg = pMsgBuff->message;
for (n2 = 0; n2 <= pdbRecordType->no_fields - 1; n2++) {
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->sortFldInd[n2]];
pfield_name = pdbFldDes->name;
pfield = ((char *)paddr->precord) + pdbFldDes->offset;
if (pdbFldDes->interest > interest_level )
continue;
switch (pdbFldDes->field_type) {
case DBF_STRING:
case DBF_USHORT:
case DBF_ENUM:
case DBF_FLOAT:
case DBF_CHAR:
case DBF_UCHAR:
case DBF_SHORT:
case DBF_LONG:
case DBF_ULONG:
case DBF_INT64:
case DBF_UINT64:
case DBF_DOUBLE:
case DBF_MENU:
case DBF_DEVICE:
status = dbFindField(pdbentry,pfield_name);
pfield_value = dbGetString(pdbentry);
sprintf(pmsg, "%-4s: %s", pfield_name,
(pfield_value ? pfield_value : "<nil>"));
dbpr_msgOut(pMsgBuff, tab_size);
break;
case DBF_INLINK:
case DBF_OUTLINK:
case DBF_FWDLINK: {
DBLINK *plink = (DBLINK *)pfield;
int ind;
const char *type = "LINK";
status = dbFindField(pdbentry,pfield_name);
if (!plink->text)
for (ind=0; ind<LINK_NTYPES; ind++) {
if (pamaplinkType[ind].value == plink->type) {
type = pamaplinkType[ind].strvalue;
break;
}
}
epicsSnprintf(pmsg, MAXMESS, "%-4s: %s %s", pfield_name,
type, dbGetString(pdbentry));
dbpr_msgOut(pMsgBuff, tab_size);
}
break;
case DBF_NOACCESS:
if (pfield == (void *)&paddr->precord->time) {
/* Special for the TIME field, make it human-readable */
char time_buf[40];
epicsTimeToStrftime(time_buf, 40, "%Y-%m-%d %H:%M:%S.%09f",
&paddr->precord->time);
sprintf(pmsg, "%-4s: %s", pfield_name, time_buf);
dbpr_msgOut(pMsgBuff, tab_size);
}
else if (pdbFldDes->size == sizeof(void *) &&
strchr(pdbFldDes->extra, '*')) {
/* Special for pointers */
sprintf(pmsg, "%-4s: PTR %p", pfield_name, *(void **)pfield);
dbpr_msgOut(pMsgBuff, tab_size);
}
else if (pdbFldDes->size == sizeof(ELLLIST) &&
!strncmp(pdbFldDes->extra, "ELLLIST", 7)) {
/* Special for linked lists */
ELLLIST *plist = (ELLLIST *)pfield;
sprintf(pmsg, "%-4s: ELL %d [%p .. %p]", pfield_name,
ellCount(plist), ellFirst(plist), ellLast(plist));
dbpr_msgOut(pMsgBuff, tab_size);
}
else { /* just print field as hex bytes */
unsigned char *pchar = (unsigned char *)pfield;
char temp_buf[61];
char *ptemp_buf = &temp_buf[0];
short n = pdbFldDes->size;
short i;
unsigned int value;
if (n > sizeof(temp_buf)/3) n = sizeof(temp_buf)/3;
for (i=0; i<n; i++, ptemp_buf += 3, pchar++) {
value = (unsigned int)*pchar;
sprintf(ptemp_buf, "%02x ", value);
}
sprintf(pmsg, "%-4s: %s", pfield_name,temp_buf);
dbpr_msgOut(pMsgBuff, tab_size);
}
break;
default:
sprintf(pmsg, "%s: dbpr: Unknown field_type", pfield_name);
dbpr_msgOut(pMsgBuff, tab_size);
break;
}
}
pmsg[0] = '\0';
dbpr_msgOut(pMsgBuff, tab_size);
dbFinishEntry(pdbentry);
return (0);
}
static void dbpr_msgOut(TAB_BUFFER *pMsgBuff,int tab_size)
{
size_t len;
int err = 0;
char *pmsg = pMsgBuff->message;
static int last_tabsize;
if (!((tab_size == 10) || (tab_size == 20))) {
printf("tab_size not 10 or 20 - dbpr_msgOut()\n");
return;
}
/* init if first time */
if (!(pMsgBuff->pNext))
dbpr_init_msg(pMsgBuff, tab_size);
if (tab_size != last_tabsize)
pMsgBuff->pNexTab = pMsgBuff->out_buff + tab_size;
last_tabsize = tab_size;
/* flush output if NULL string command */
if (*pmsg == 0) {
dbpr_msg_flush(pMsgBuff, tab_size);
return;
}
/* truncate if too long */
len = strlen(pmsg);
if (len > MAXLINE) {
err = 1;
len = MAXLINE;
}
dbpr_insert_msg(pMsgBuff, len, tab_size);
/* warn if msg gt 80 */
if (err == 1) {
len = strlen(pmsg);
sprintf(pmsg, "dbpr_msgOut: ERROR - msg length=%d limit=%d ",
(int)len, MAXLINE);
dbpr_insert_msg(pMsgBuff, len, tab_size);
}
}
static void dbpr_init_msg(TAB_BUFFER *pMsgBuff,int tab_size)
{
pMsgBuff->pNext = pMsgBuff->out_buff;
pMsgBuff->pLast = pMsgBuff->out_buff + MAXLINE;
pMsgBuff->pNexTab = pMsgBuff->out_buff + tab_size;
}
static void dbpr_insert_msg(TAB_BUFFER *pMsgBuff,size_t len,int tab_size)
{
size_t current_len;
size_t n;
size_t tot_line;
char *pmsg = pMsgBuff->message;
current_len = strlen(pMsgBuff->out_buff);
tot_line = current_len + len;
/* flush buffer if overflow would occor */
if (tot_line > MAXLINE)
dbpr_msg_flush(pMsgBuff, tab_size);
/* append message to buffer */
n = 0;
while ((*pmsg) && (n < len)) {
*pMsgBuff->pNext++ = *pmsg++;
/* position to next tab stop */
if (*(pMsgBuff->pNexTab - 1) != '\0')
pMsgBuff->pNexTab = pMsgBuff->pNexTab + tab_size;
n++;
}
/* fill spaces to next tab stop */
while (*(pMsgBuff->pNexTab - 1) != ' '
&& pMsgBuff->pNext < pMsgBuff->pLast) {
*pMsgBuff->pNext++ = ' ';
}
}
static void dbpr_msg_flush(TAB_BUFFER *pMsgBuff,int tab_size)
{
/* skip print if buffer empty */
if (pMsgBuff->pNext != pMsgBuff->out_buff)
printf("%s\n", pMsgBuff->out_buff);
memset(pMsgBuff->out_buff,'\0', (int) MAXLINE + 1);
pMsgBuff->pNext = pMsgBuff->out_buff;
pMsgBuff->pNexTab = pMsgBuff->out_buff + tab_size;
}