Merge branch '7.0' into PSI-7.0

This commit is contained in:
2025-07-14 10:49:20 +02:00
129 changed files with 7604 additions and 4778 deletions
+2
View File
@@ -1251,7 +1251,9 @@ static void dbCaTask(void *arg)
epicsMutexMustLock(pca->lock);
prec = pca->plink->precord;
epicsMutexUnlock(pca->lock);
dbScanLock(prec);
db_process(prec);
dbScanUnlock(prec);
}
}
SEVCHK(ca_flush_io(), "dbCaTask");
+6 -6
View File
@@ -7,7 +7,7 @@
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head3 Operator Display Parameters
=head2 Operator Display Parameters
The B<NAME> field contains the record name which must be unique within an
EPICS Channel Access name space. The name is supplied by the application
@@ -43,7 +43,7 @@ record's purpose. Maximum length is 40 characters.
size(29)
}
=head3 Scan Fields
=head2 Scan Fields
These fields contain information related to how and when a record processes. A
few records have unique fields that also affect how they process. These
@@ -245,7 +245,7 @@ The B<SPVT> field is for internal use by the scanning system.
interest(3)
}
=head3 Alarm Fields
=head2 Alarm Fields
Alarm fields indicate the status and severity of record alarms, or determine
how and when alarms are triggered. Of course, many records have alarm-related
@@ -392,7 +392,7 @@ initial severity of the record being undefined after the IOC boots.
extra("struct scan_element *spvt")
}
=head3 Device Fields
=head2 Device Fields
The B<RSET> field contains the address of the Record Support Entry Table. See
the Application Developers Guide for details on usage.
@@ -446,7 +446,7 @@ The B<DPVT> field is is for private use of the device support modules.
menu(menuPriority)
}
=head3 Debugging Fields
=head2 Debugging Fields
The B<TPRO> field can be used to trace record processing. When this field is
non-zero and the record is processed, a trace message will be be printed for
@@ -461,7 +461,7 @@ database processing can be supported using this.
=fields TPRO, BKPT
=head3 Miscellaneous Fields
=head2 Miscellaneous Fields
The B<ASG> string field sets the name of the access security group used for this
record. If left empty, the record is placed in group C<DEFAULT>.
@@ -11,7 +11,7 @@ These fields usually have the same meaning whenever they are used.
See also L<Fields Common to All Record Types|dbCommonRecord> and L<Fields Common
to Output Record Types|dbCommonOutput>.
=head3 Input and Value Fields
=head2 Input and Value Fields
The B<INP> field specifies an input link. It is used by the device support
routines to obtain input. For soft analog records it can be a constant, a
@@ -30,7 +30,7 @@ reads values directly into VAL, bypassing this field.
The B<VAL> field contains the record's final value, after any needed
conversions have been performed.
=head3 Device Input
=head2 Device Input
A device input routine normally returns one of the following values to its
associated record support routine:
@@ -65,7 +65,7 @@ to the engineering units value.
=back
=head3 Device Support for Soft Records
=head2 Device Support for Soft Records
In most cases, two soft output device support modules are provided: Soft Channel
and Raw Soft Channel. Both allow INP to be a constant, a database link, or a
@@ -83,7 +83,7 @@ If a value was returned by the link the UDF field is set to FALSE. The device
support read routine normally returns the status from C<dbGetLink()>.
=head3 Input Simulation Fields
=head2 Input Simulation Fields
The B<SIMM> field controls simulation mode.
By setting this field to YES or RAW, the record can be switched into
@@ -121,7 +121,7 @@ The B<SSCN> field specifies the SCAN mechanism to be used in simulation mode.
This is specifically useful for 'I/O Intr' scanned records, which would
otherwise never be scanned in simulation mode.
=head3 Simulation Mode for Input Records
=head2 Simulation Mode for Input Records
An input record can be switched into simulation mode of operation by setting
the value of SIMM to YES or RAW.
@@ -11,7 +11,7 @@ These fields usually have the same meaning whenever they are used.
See also L<Fields Common to All Record Types|dbCommonRecord> and L<Fields Common to
Input Records|dbCommonInput>.
=head3 Output and Value Fields
=head2 Output and Value Fields
The B<OUT> field specifies an output link. It is used by the device support
routines to decide where to send output. For soft records, it can be a
@@ -38,7 +38,7 @@ The B<RBV> field contains - whenever possible - the actual read back value
obtained from the hardware itself or from the associated device driver.
=head3 Device Support for Soft Records
=head2 Device Support for Soft Records
Normally two soft output device support modules are provided, Soft Channel and
and Raw Soft Channel. Both write a value through the output link OUT.
@@ -50,7 +50,7 @@ The device support write routine normally calls C<dbPutLink()> which writes a
value through the OUT link, and returns the status from that call.
=head3 Input and Mode Select Fields
=head2 Input and Mode Select Fields
The B<DOL> field is a link from which the desired output value can be fetched.
DOL can be a constant, a database link, or a channel access link. If DOL is a
@@ -63,7 +63,7 @@ value C<closed_loop>. By setting this field a record can be switched between
supervisory and closed loop mode of operation. While in closed loop mode, the
VAL field cannot be set via dbPuts.
=head3 Output Mode Selection
=head2 Output Mode Selection
The fields DOL and OMSL are used to allow the output record to be part of a
closed loop control algorithm. OMSL is meaningful only if DOL refers to a
@@ -76,7 +76,7 @@ types with an OIF field and OIF is Full, VAL is set equal to the value obtained
from the location referenced by DOL; if OIF is Incremental VAL is incremented by
the value obtained from DOL.
=head3 Invalid Output Action Fields
=head2 Invalid Output Action Fields
The B<IVOA> field specifies the output action for the case that the record is
put into an INVALID alarm severity. IVOA can be one of the following actions:
@@ -102,7 +102,7 @@ in engineering units. If a new severity has been set to INVALID and IVOA is
C<Set output to IVOV>, then VAL is set to IVOV and converted to RVAL before
device support is called.
=head3 Invalid Alarm Output Action
=head2 Invalid Alarm Output Action
Whenever an output record is put into INVALID alarm severity, IVOA specifies
an action to take. The record support process routine for each output record
@@ -142,7 +142,7 @@ If IVOA not one of the above, an error message is generated.
=back
=head3 Output Simulation Fields
=head2 Output Simulation Fields
The B<SIMM> field controls simulation mode. It has either the value YES or NO.
By setting this field to YES, the record can be switched into simulation mode
@@ -171,7 +171,7 @@ The B<SSCN> field specifies the SCAN mechanism to be used in simulation mode.
This is specifically useful for 'I/O Intr' scanned records, which would
otherwise never be scanned in simulation mode.
=head3 Simulation Mode for Output Records
=head2 Simulation Mode for Output Records
An output record can be switched into simulation mode of operation by setting
the value of SIMM to YES. During simulation, the record will be put into alarm
@@ -8,8 +8,8 @@
This section contains a description of the fields that are common to all record
types. These fields are defined in dbCommon.dbd.
See also L<Fields Common to Input Record Types|dbCommonInput> and L<Fields
Common to Output Record Types|dbCommonOutput>.
See also L<Fields Common to Input Record Types|dbCommonInput> and
L<Fields Common to Output Record Types|dbCommonOutput>.
=recordtype dbCommon
+11
View File
@@ -443,6 +443,17 @@ static long processTarget(dbCommon *psrc, dbCommon *pdst)
epicsUInt8 pact = psrc->pact;
epicsThreadId self = epicsThreadGetIdSelf();
#ifdef LOCKSET_DEBUG
{
lockSet *ls = dbLockGetRef(psrc->lset);
assert(ls->owner == self);
dbLockDecRef(ls);
ls = dbLockGetRef(pdst->lset);
assert(ls->owner == self);
dbLockDecRef(ls);
}
#endif
psrc->pact = TRUE;
if (psrc->ppn)
+15 -7
View File
@@ -233,16 +233,23 @@ static const iocshFuncDef dblaFuncDef = {"dbla",1,dblaArgs,
"Example: dbla(\"alia*\")\n"};
static void dblaCallFunc(const iocshArgBuf *args) { iocshSetError(dbla(args[0].sval));}
/* dbgrep */
static const iocshArg dbgrepArg0 = { "pattern",iocshArgStringRecord};
static const iocshArg * const dbgrepArgs[1] = {&dbgrepArg0};
static const iocshFuncDef dbgrepFuncDef = {"dbgrep",1,dbgrepArgs,
"List record names matching pattern.\n"
/* dbglob */
static const iocshArg dbglobArg0 = { "pattern",iocshArgStringRecord};
static const iocshArg dbglobArg1 = { "fields",iocshArgString};
static const iocshArg * const dbglobArgs[2] = {&dbglobArg0,&dbglobArg1};
static const iocshFuncDef dbglobFuncDef = {"dbglob",2,dbglobArgs,
"List record names matching pattern and optionally print field values. \n"
"The pattern can contain any characters that are legal in record names as well as:\n"
" - \"?\", which matches 0 or one characters.\n"
" - \"*\", which matches 0 or more characters.\n\n"
"Example: dbgrep(\"*gpibAi*\")\n"};
static void dbgrepCallFunc(const iocshArgBuf *args) { iocshSetError(dbgrep(args[0].sval));}
"Example: dbglob(\"*gpibAi*\")\n"
" dbglob(\"*gpibAi*\",\"VAL DESC\")\n"};
static void dbglobCallFunc(const iocshArgBuf *args) { iocshSetError(dbglob(args[0].sval,args[1].sval));}
/* dbgrep; alias for dbglob, so it should have the same arguments */
static const iocshFuncDef dbgrepFuncDef = {"dbgrep",2,dbglobArgs,
"See dbglob.\n"};
static void dbgrepCallFunc(const iocshArgBuf *args) { iocshSetError(dbglob(args[0].sval,args[1].sval));}
/* dbgf */
static const iocshArg dbgfArg0 = { "record name",iocshArgStringRecord};
@@ -598,6 +605,7 @@ void dbIocRegister(void)
iocshRegister(&dbnrFuncDef,dbnrCallFunc);
iocshRegister(&dblaFuncDef,dblaCallFunc);
iocshRegister(&dbliFuncDef,dbliCallFunc);
iocshRegister(&dbglobFuncDef,dbglobCallFunc);
iocshRegister(&dbgrepFuncDef,dbgrepCallFunc);
iocshRegister(&dbgfFuncDef,dbgfCallFunc);
iocshRegister(&dbpfFuncDef,dbpfCallFunc);
+1
View File
@@ -12,6 +12,7 @@
#include "dbLock.h"
#include "epicsMutex.h"
#include "epicsSpin.h"
#include "epicsThread.h"
/* Define to enable additional error checking */
#undef LOCKSET_DEBUG
+3 -1
View File
@@ -680,7 +680,9 @@ int scanOnceCallback(struct dbCommon *precord, once_complete cb, void *usr)
pushOK = epicsRingBytesPut(onceQ, (void*)&ent, sizeof(ent));
if (!pushOK) {
if (newOverflow) errlogPrintf("scanOnce: Ring buffer overflow\n");
if (newOverflow)
errlogPrintf("%s : " ERL_WARNING " scanOnce: Ring buffer overflow\n",
precord->name);
newOverflow = FALSE;
epicsAtomicIncrIntT(&onceQOverruns);
} else {
+73 -44
View File
@@ -100,13 +100,59 @@ long dba(const char*pname)
return 0;
}
/* split a space separated list of field names and return the number of
fields with each field an element of papfields. These elements
point to within the fieldnames variable which is modified
by the function. memory is allocated for *ppapfields and needs
to be freed later by the calling routine */
static int splitFieldsList(char *fieldnames, char ***ppapfields)
{
char *pnext = fieldnames;
int nfields = 0, maxfields = 1;
char* saveptr = NULL;
/* this may overcount real fields e.g. " VAL " hence maxfields */
while (*pnext && (pnext = strchr(pnext, ' '))) {
maxfields++;
while (*pnext == ' ') pnext++;
}
*ppapfields = dbCalloc(maxfields, sizeof(char *));
pnext = epicsStrtok_r(fieldnames, " ", &saveptr);
while(pnext != NULL) {
(*ppapfields)[nfields++] = pnext;
pnext = epicsStrtok_r(NULL, " ", &saveptr);
}
return nfields;
}
static void printFieldsList(DBENTRY *pdbentry, char** papfields, int nfields)
{
int ifield;
for (ifield = 0; ifield < nfields; ifield++) {
char *pvalue;
long 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");
}
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;
@@ -121,25 +167,8 @@ long dbl(const char *precordTypename, const char *fields)
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++;
}
}
nfields = splitFieldsList(fieldnames, &papfields);
}
dbInitEntry(pdbbase, pdbentry);
if (!precordTypename)
@@ -154,24 +183,7 @@ long dbl(const char *precordTypename, const char *fields)
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");
printFieldsList(pdbentry, papfields, nfields);
status = dbNextRecord(pdbentry);
}
if (precordTypename)
@@ -283,14 +295,17 @@ long dbli(const char *pattern)
return 0;
}
long dbgrep(const char *pmask)
long dbglob(const char *pmask,const char *fields)
{
DBENTRY dbentry;
DBENTRY *pdbentry = &dbentry;
long status;
int nfields = 0;
char *fieldnames = 0;
char **papfields = 0;
if (!pmask || !*pmask) {
printf("Usage: dbgrep \"pattern\"\n");
printf("Usage: dbglob \"pattern\" \"fields\"\n");
return 1;
}
@@ -298,24 +313,38 @@ long dbgrep(const char *pmask)
printf("No database loaded\n");
return 0;
}
if (fields && (*fields == '\0'))
fields = NULL;
if (fields) {
fieldnames = epicsStrDup(fields);
nfields = splitFieldsList(fieldnames, &papfields);
}
dbInitEntry(pdbbase, pdbentry);
status = dbFirstRecordType(pdbentry);
while (!status) {
status = dbFirstRecord(pdbentry);
while (!status) {
char *pname = dbGetRecordName(pdbentry);
if (epicsStrGlobMatch(pname, pmask))
puts(pname);
if (epicsStrGlobMatch(pname, pmask)) {
printf("%s", pname);
printFieldsList(pdbentry, papfields, nfields);
}
status = dbNextRecord(pdbentry);
}
status = dbNextRecordType(pdbentry);
}
if (nfields > 0) {
free((void *)papfields);
free((void *)fieldnames);
}
dbFinishEntry(pdbentry);
return 0;
}
long dbgrep(const char *pname, const char *fields) {
return dbglob(pname, fields);
}
long dbgf(const char *pname)
{
/* declare buffer long just to ensure correct alignment */
+4 -2
View File
@@ -28,8 +28,10 @@ DBCORE_API long dbnr(int verbose);
DBCORE_API long dbla(const char *pmask);
/* list infos */
DBCORE_API long dbli(const char *patern);
/*list records with mask*/
DBCORE_API long dbgrep(const char *pmask);
/*list records filtered by glob pattern*/
DBCORE_API long dbglob(const char *ppattern,const char *fields);
/*list records filtered by glob pattern; alias for dbglob*/
DBCORE_API long dbgrep(const char *ppatern,const char *fields);
/*get field value*/
DBCORE_API long dbgf(const char *pname);
/*put field value*/
@@ -17,6 +17,7 @@
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "dbDefs.h"
#include "dbmf.h"
@@ -38,7 +39,8 @@
#include "iocInit.h"
/* This file is included from dbYacc.y
* Duplicate some declarations to avoid warnings from analysis tools which don't know about this.
* Duplicate some declarations to avoid warnings
* from analysis tools that don't know about this.
*/
static int yyerror(char *str);
static long pvt_yy_parse(void);
@@ -199,8 +201,9 @@ static void freeInputFileList(void)
while((pinputFileNow=(inputFile *)ellFirst(&inputFileList))) {
if(fclose(pinputFileNow->fp))
errPrintf(0,__FILE__, __LINE__,
"Closing file %s",pinputFileNow->filename);
fprintf(stderr, ERL_WARNING
": Error closing file '%s': %s\n",
pinputFileNow->filename, strerror(errno));
free((void *)pinputFileNow->filename);
ellDelete(&inputFileList,(ELLNODE *)pinputFileNow);
free((void *)pinputFileNow);
@@ -225,7 +228,8 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
char **macPairs;
if (ellCount(&tempList)) {
fprintf(stderr, ERL_WARNING ": dbReadCOM: Parser stack dirty %d\n", ellCount(&tempList));
fprintf(stderr, ERL_WARNING
": dbReadCOM: Parser stack dirty %d\n", ellCount(&tempList));
}
if (getIocState() != iocVoid) {
@@ -274,8 +278,8 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
if (pinputFile->filename)
pinputFile->path = dbOpenFile(savedPdbbase, pinputFile->filename, &fp1);
if (!pinputFile->filename || !fp1) {
errPrintf(0, __FILE__, __LINE__,
"dbRead opening file %s\n",pinputFile->filename);
fprintf(stderr, ERL_ERROR
": Can't open file '%s'\n", pinputFile->filename);
free((char*)pinputFile->filename);
free(pinputFile);
status = -1;
@@ -294,7 +298,9 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
status = pvt_yy_parse();
if (ellCount(&tempList) && !yyAbort)
fprintf(stderr, ERL_WARNING ": dbReadCOM: Parser stack dirty w/o error. %d\n", ellCount(&tempList));
fprintf(stderr, ERL_WARNING
": dbReadCOM: Parser stack dirty w/o error. %d\n",
ellCount(&tempList));
while (ellCount(&tempList))
popFirstTemp(); /* Memory leak on parser failure */
@@ -368,7 +374,8 @@ static int db_yyinput(char *buf, int max_size)
int exp = macExpandString(macHandle,mac_input_buffer,
my_buffer,MY_BUFFER_SIZE);
if (exp < 0) {
fprintf(stderr, "Warning: '%s' line %d has undefined macros\n",
fprintf(stderr, ERL_WARNING
": '%s' line %d has undefined macros\n",
pinputFileNow->filename, pinputFileNow->line_num+1);
}
}
@@ -377,8 +384,9 @@ static int db_yyinput(char *buf, int max_size)
}
if(fgetsRtn) break;
if(fclose(pinputFileNow->fp))
errPrintf(0,__FILE__, __LINE__,
"Closing file %s",pinputFileNow->filename);
fprintf(stderr, ERL_WARNING
": Error closing file '%s': %s\n",
pinputFileNow->filename, strerror(errno));
free((void *)pinputFileNow->filename);
ellDelete(&inputFileList,(ELLNODE *)pinputFileNow);
free((void *)pinputFileNow);
@@ -434,7 +442,7 @@ static void dbIncludeNew(char *filename)
pinputFile->filename = macEnvExpand(filename);
pinputFile->path = dbOpenFile(savedPdbbase, pinputFile->filename, &fp);
if (!fp) {
fprintf(stderr, "Can't open include file \"%s\"\n", filename);
fprintf(stderr, ERL_ERROR ": Can't open include file '%s'\n", filename);
yyerror(NULL);
free((void *)pinputFile->filename);
free((void *)pinputFile);
@@ -557,7 +565,7 @@ static void dbRecordtypeFieldHead(char *name,char *type)
strcmp(pdbFldDes->name, "OUT")==0;
i = dbFindFieldType(type);
if (i < 0)
yyerrorAbort("Illegal Field Type");
yyerrorAbort("Invalid Field Type");
pdbFldDes->field_type = i;
}
@@ -589,7 +597,7 @@ static void dbRecordtypeFieldItem(char *name,char *value)
} else if(strcmp(value,"ASL1")==0) {
pdbFldDes->as_level = ASL1;
} else {
yyerror("Illegal Access Security value: Must be ASL0 or ASL1");
yyerror("Invalid 'asl' value, must be ASL0 or ASL1");
}
return;
}
@@ -616,7 +624,7 @@ static void dbRecordtypeFieldItem(char *name,char *value)
if(sscanf(value,"%hd",&pdbFldDes->special)==1) {
return;
}
yyerror("Illegal 'special' value.");
yyerror("Invalid 'special' value.");
return;
}
if(strcmp(name,"pp")==0) {
@@ -625,13 +633,13 @@ static void dbRecordtypeFieldItem(char *name,char *value)
} else if((strcmp(value,"NO")==0) || (strcmp(value,"FALSE")==0)) {
pdbFldDes->process_passive = FALSE;
} else {
yyerror("Illegal 'pp' value, must be YES/NO/TRUE/FALSE");
yyerror("Invalid 'pp' value, must be YES/NO/TRUE/FALSE");
}
return;
}
if(strcmp(name,"interest")==0) {
if(sscanf(value,"%hd",&pdbFldDes->interest)!=1)
yyerror("Illegal 'interest' value, must be integer");
yyerror("Invalid 'interest' value, must be integer");
return;
}
if(strcmp(name,"base")==0) {
@@ -640,13 +648,13 @@ static void dbRecordtypeFieldItem(char *name,char *value)
} else if(strcmp(value,"HEX")==0) {
pdbFldDes->base = CT_HEX;
} else {
yyerror("Illegal 'base' value, must be DECIMAL/HEX");
yyerror("Invalid 'base' value, must be DECIMAL/HEX");
}
return;
}
if(strcmp(name,"size")==0) {
if(sscanf(value,"%hd",&pdbFldDes->size)!=1)
yyerror("Illegal 'size' value, must be integer");
yyerror("Invalid 'size' value, must be integer");
return;
}
if(strcmp(name,"extra")==0) {
@@ -696,7 +704,8 @@ static void dbRecordtypeEmpty(void)
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbRecordType = ptempListNode->item;
fprintf(stderr, "Declaration of recordtype(%s) preceeded full definition.\n",
fprintf(stderr, ERL_ERROR
": Declaration of recordtype(%s) preceeded full definition.\n",
pdbRecordType->name);
yyerrorAbort(NULL);
}
@@ -737,10 +746,12 @@ static void dbRecordtypeBody(void)
field_type = pdbFldDes->field_type;
if((field_type>=DBF_INLINK) && (field_type<=DBF_FWDLINK))no_links++;
if((field_type==DBF_STRING) && (pdbFldDes->size==0))
fprintf(stderr,"recordtype(%s).%s size not specified\n",
fprintf(stderr, ERL_ERROR
": recordtype(%s).%s size not specified\n",
pdbRecordType->name,pdbFldDes->name);
if((field_type==DBF_NOACCESS) && (pdbFldDes->extra==0))
fprintf(stderr,"recordtype(%s).%s extra not specified\n",
fprintf(stderr, ERL_ERROR
": recordtype(%s).%s extra not specified\n",
pdbRecordType->name,pdbFldDes->name);
}
if (ellCount(&tempList))
@@ -801,8 +812,9 @@ static void dbDevice(char *recordtype,char *linktype,
int i,link_type;
pgphentry = gphFind(savedPdbbase->pgpHash,recordtype,&savedPdbbase->recordTypeList);
if(!pgphentry) {
fprintf(stderr, "Record type \"%s\" not found for device \"%s\"\n",
recordtype, choicestring);
fprintf(stderr, ERL_ERROR
": Record type '%s' not found for device '%s'\n",
recordtype, choicestring);
yyerror(NULL);
return;
}
@@ -814,8 +826,9 @@ static void dbDevice(char *recordtype,char *linktype,
}
}
if(link_type==-1) {
fprintf(stderr, "Bad link type \"%s\" for device \"%s\"\n",
linktype, choicestring);
fprintf(stderr, ERL_ERROR
": Bad link type '%s' for device '%s'\n",
linktype, choicestring);
yyerror(NULL);
return;
}
@@ -1077,16 +1090,20 @@ int dbRecordNameValidate(const char *name)
if(i==0) {
/* first character restrictions */
if(c=='-' || c=='+' || c=='[' || c=='{') {
fprintf(stderr, "Warning: Record/Alias name '%s' should not begin with '%c'\n", name, c);
fprintf(stderr, ERL_WARNING
": Record/Alias name '%s' should not begin with '%c'\n",
name, c);
}
}
/* any character restrictions */
if(c < ' ') {
fprintf(stderr, "Warning: Record/Alias name '%s' should not contain non-printable 0x%02x\n",
name, c);
fprintf(stderr, ERL_WARNING
": Record/Alias name '%s' contains non-printable 0x%02x\n",
name, c);
} else if(c==' ' || c=='\t' || c=='"' || c=='\'' || c=='.' || c=='$') {
fprintf(stderr, ERL_ERROR ": Bad character '%c' in Record/Alias name \"%s\"\n",
fprintf(stderr, ERL_ERROR
": Bad character '%c' in Record/Alias name \"%s\"\n",
c, name);
yyerrorAbort(NULL);
return 1;
@@ -1113,7 +1130,7 @@ static void dbRecordHead(char *recordType, char *name, int visible)
status = dbFindRecord(pdbentry, name);
if (status == 0)
return; /* done */
fprintf(stderr, ERL_ERROR ": Record \"%s\" not found\n", name);
fprintf(stderr, ERL_ERROR ": Record '%s' not found\n", name);
yyerror(NULL);
duplicate = TRUE;
return;
@@ -1124,9 +1141,10 @@ static void dbRecordHead(char *recordType, char *name, int visible)
if (status == 0) {
dbDeleteRecord(pdbentry);
} else {
fprintf(stderr, ERL_WARNING ": Unable to delete record \"%s\". Not found.\n"
" at file %s line %d\n",
name, pinputFileNow->filename, pinputFileNow->line_num);
fprintf(stderr, ERL_WARNING
": Record '%s' not found, can't delete\n"
" at file '%s', line %d\n",
name, pinputFileNow->filename, pinputFileNow->line_num);
}
popFirstTemp();
dbFreeEntry(pdbentry);
@@ -1135,8 +1153,9 @@ static void dbRecordHead(char *recordType, char *name, int visible)
}
status = dbFindRecordType(pdbentry, recordType);
if (status) {
fprintf(stderr, "Record \"%s\" is of unknown type \"%s\"\n",
name, recordType);
fprintf(stderr, ERL_ERROR
": Record type '%s' for record '%s' not found\n",
recordType, name);
yyerrorAbort(NULL);
return;
}
@@ -1146,23 +1165,24 @@ static void dbRecordHead(char *recordType, char *name, int visible)
status = dbCreateRecord(pdbentry,name);
if (status == S_dbLib_recExists) {
if (strcmp(recordType, dbGetRecordTypeName(pdbentry)) != 0) {
fprintf(stderr, ERL_ERROR ": Record \"%s\" of type \"%s\" redefined with new type "
"\"%s\"\n", name, dbGetRecordTypeName(pdbentry), recordType);
fprintf(stderr, ERL_ERROR
": %s record '%s' already exists, can't load %s record\n",
recordType, name, dbGetRecordTypeName(pdbentry));
yyerror(NULL);
duplicate = TRUE;
return;
}
else if (dbRecordsOnceOnly) {
fprintf(stderr, ERL_ERROR ": Record \"%s\" already defined and dbRecordsOnceOnly set.\n"
"Used record type \"*\" to append.\n",
name);
fprintf(stderr, ERL_ERROR
": Record '%s' already defined; dbRecordsOnceOnly is set,\n"
" so can't modify record.\n", name);
yyerror(NULL);
duplicate = TRUE;
}
}
else if (status) {
fprintf(stderr, "Can't create record \"%s\" of type \"%s\"\n",
name, recordType);
fprintf(stderr, ERL_ERROR
": Can't create %s record '%s'\n",
recordType, name);
yyerrorAbort(NULL);
}
@@ -1181,8 +1201,9 @@ static void dbRecordField(char *name,char *value)
pdbentry = ptempListNode->item;
status = dbFindField(pdbentry,name);
if (status) {
fprintf(stderr, "%s Record \"%s\" does not have a field \"%s\"\n",
dbGetRecordTypeName(pdbentry), dbGetRecordName(pdbentry), name);
fprintf(stderr, ERL_ERROR
": %s record '%s' doesn't have a field '%s'\n",
dbGetRecordTypeName(pdbentry), dbGetRecordName(pdbentry), name);
if(dbGetRecordName(pdbentry)) {
DBENTRY temp;
double bestSim = -1.0;
@@ -1207,7 +1228,8 @@ static void dbRecordField(char *name,char *value)
return;
}
if (pdbentry->indfield == 0) {
fprintf(stderr, "Can't set \"NAME\" field of record \"%s\"\n",
fprintf(stderr, ERL_ERROR
": Can't set 'NAME' field of record '%s'\n",
dbGetRecordName(pdbentry));
yyerror(NULL);
return;
@@ -1225,8 +1247,10 @@ static void dbRecordField(char *name,char *value)
char msg[128];
errSymLookup(status, msg, sizeof(msg));
fprintf(stderr, "Can't set \"%s.%s\" to \"%s\" %s : %s\n",
dbGetRecordName(pdbentry), name, value, pdbentry->message ? pdbentry->message : "", msg);
fprintf(stderr, ERL_ERROR
": Can't set '%s.%s' to '%s' %s : %s\n",
dbGetRecordName(pdbentry), name, value,
pdbentry->message ? pdbentry->message : "", msg);
dbPutStringSuggest(pdbentry, value);
yyerror(NULL);
return;
@@ -1256,8 +1280,9 @@ static void dbRecordInfo(char *name, char *value)
status = dbPutInfo(pdbentry,name,value);
if (status) {
fprintf(stderr, "Can't set \"%s\" info \"%s\" to \"%s\"\n",
dbGetRecordName(pdbentry), name, value);
fprintf(stderr, ERL_ERROR
": Can't set '%s' info(\"%s\") to '%s'\n",
dbGetRecordName(pdbentry), name, value);
yyerror(NULL);
return;
}
@@ -1275,15 +1300,18 @@ static long createAlias(DBENTRY *pdbentry, const char *alias)
if (status == 0) {
if (tempEntry.precnode->aliasedRecnode != precnode) {
if (tempEntry.precnode->aliasedRecnode)
fprintf(stderr, ERL_ERROR ": Alias \"%s\" for \"%s\": name already used by an alias for \"%s\"\n",
alias, dbGetRecordName(pdbentry),
tempEntry.precnode->aliasedRecnode->recordname);
fprintf(stderr, ERL_ERROR
": Alias '%s' for record '%s' already aliases '%s'\n",
alias, dbGetRecordName(pdbentry),
tempEntry.precnode->aliasedRecnode->recordname);
else
fprintf(stderr, ERL_ERROR ": Alias \"%s\" for \"%s\": name already used by a record\n",
alias, dbGetRecordName(pdbentry));
fprintf(stderr, ERL_ERROR
": Alias '%s' for record '%s' is already a record name.\n",
alias, dbGetRecordName(pdbentry));
status = S_dbLib_recExists;
} else if (dbRecordsOnceOnly) {
fprintf(stderr, ERL_ERROR ": Alias \"%s\" already defined and dbRecordsOnceOnly set.\n",
fprintf(stderr, ERL_ERROR
": Alias '%s' already defined; dbRecordsOnceOnly is set.\n",
alias);
status = S_dbLib_recExists;
}
@@ -1320,8 +1348,9 @@ static void dbAlias(char *name, char *alias)
dbInitEntry(savedPdbbase, pdbEntry);
if (dbFindRecord(pdbEntry, name)) {
fprintf(stderr, "Alias \"%s\" refers to unknown record \"%s\"\n",
alias, name);
fprintf(stderr, ERL_ERROR
": Alias '%s' names an unknown record '%s'\n",
alias, name);
yyerror(NULL);
}
else if (createAlias(pdbEntry, alias) != 0) {
@@ -2635,7 +2635,9 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
}
}
break;
case DBF_NOACCESS:
dbMsgPrint(pdbentry, "Can't set array field before iocInit()");
/* fall through */
default:
return S_dbLib_badField;
}
@@ -3454,7 +3456,7 @@ void dbDumpDevice(DBBASE *pdbbase,const char *recordTypeName)
" - get_ioint_info()"
};
int i, n = pdevSup->pdset->number;
DEVSUPFUN *pfunc = &pdevSup->pdset->report;
DEVSUPFUN *pfunc = (DEVSUPFUN*) &pdevSup->pdset->report;
printf("\t number: %d\n", n);
for (i = 0; i < n; ++i, ++pfunc) {
@@ -19,7 +19,7 @@ extern "C" {
#endif
DBCORE_API int dbLoadTemplate(
const char *sub_file, const char *cmd_collect);
const char *sub_file, const char *cmd_collect, const char *path);
#ifdef __cplusplus
}
@@ -12,6 +12,7 @@
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include "osiUnistd.h"
#include "macLib.h"
@@ -20,7 +21,10 @@
#include "epicsExport.h"
#include "dbAccess.h"
#include "dbStaticLib.h"
#include "dbStaticPvt.h"
#include "dbLoadTemplate.h"
#include "osiFileName.h"
static int line_num;
static int yyerror(char* str);
@@ -335,7 +339,7 @@ static int yyerror(char* str)
static int is_not_inited = 1;
int dbLoadTemplate(const char *sub_file, const char *cmd_collect)
int dbLoadTemplate(const char *sub_file, const char *cmd_collect, const char *path)
{
FILE *fp;
int i;
@@ -356,8 +360,16 @@ int dbLoadTemplate(const char *sub_file, const char *cmd_collect)
}
fp = fopen(sub_file, "r");
// If the file does not exist locally, and it is not an absolute path...
if (!fp && sub_file[0] != OSI_PATH_SEPARATOR[0]) {
if (!path || !*path) {
path = getenv("EPICS_DB_INCLUDE_PATH");
}
dbPath(pdbbase, path);
dbOpenFile(pdbbase, sub_file, &fp);
}
if (!fp) {
fprintf(stderr, "dbLoadTemplate: error opening sub file %s\n", sub_file);
fprintf(stderr, "dbLoadTemplate: error opening sub file %s: %s\n", sub_file, strerror(errno));
return -1;
}
@@ -15,23 +15,24 @@
/* dbLoadTemplate */
static const iocshArg dbLoadTemplateArg0 = {"filename", iocshArgStringPath};
static const iocshArg dbLoadTemplateArg1 = {"var1=value1,var2=value2", iocshArgString};
static const iocshArg * const dbLoadTemplateArgs[2] = {
&dbLoadTemplateArg0, &dbLoadTemplateArg1
};
static const iocshArg dbLoadTemplateArg2 = {"path1:path2:...", iocshArgString};
static const iocshArg *const dbLoadTemplateArgs[3] = {
&dbLoadTemplateArg0, &dbLoadTemplateArg1, &dbLoadTemplateArg2};
static const iocshFuncDef dbLoadTemplateFuncDef = {
"dbLoadTemplate",
2,
3,
dbLoadTemplateArgs,
"Load the substitution file given as first argument, apply the substitutions\n"
"for each template in the substitution file, and load them using 'dbLoadRecords'.\n\n"
"The second argument provides extra variables to substitute in the\n"
"template files (not the substitution file).\n\n"
"template files (not the substitution file). The third argument provides\n"
"a list of paths to search through for the subsitution and template files.\n\n"
"See 'help dbLoadRecords' for more information.\n\n"
"Example: dbLoadTemplate db/my.substitutions 'user=myself,host=myhost'\n",
"Example: dbLoadTemplate db/my.substitutions 'user=myself,host=myhost' 'path/to/subst:path2/to2/subst2'\n",
};
static void dbLoadTemplateCallFunc(const iocshArgBuf *args)
{
iocshSetError(dbLoadTemplate(args[0].sval, args[1].sval));
iocshSetError(dbLoadTemplate(args[0].sval, args[1].sval, args[2].sval));
}
+91 -77
View File
@@ -1,5 +1,8 @@
# msi: Macro Substitution and Include Tool
``` {program} msi
```
(msitool)=
## Introduction
@@ -18,7 +21,9 @@ substitution files accepted by the EPICS IOC's dbLoadTemplate command.
## Command Syntax
`msi -V -g -o outfile -I dir -M subs -S subfile template`
``` bash
msi -V -g -o outfile -I dir -M subs -S subfile template
```
All parameters are optional. The -o, -I, -M, and -S switches may be
separated from their associated value string by spaces if desired.
@@ -26,80 +31,89 @@ Output will be written to stdout unless the -o option is given.
Switches have the following meanings:
- **-V**
::: {option} -V
Verbose warnings; if this parameter is specified then any undefined
macro discovered in the template file which does not have an
associated default value is considered an error. An error message is
generated, and when msi terminates it will do so with an exit status
of 2.
:::
Verbose warnings; if this parameter is specified then any undefined
macro discovered in the template file which does not have an
associated default value is considered an error. An error message is
generated, and when msi terminates it will do so with an exit status
of 2.
- **-g**
::: {option} -g
When this flag is given all macros defined in a substitution file
will have global scope and thus their values will persist until a
new value is given for this macro. This flag is provided for
backwards compatibility as this was the behavior of previous
versions of msi, but it does not follow common scoping rules and is
discouraged.
:::
When this flag is given all macros defined in a substitution file
will have global scope and thus their values will persist until a
new value is given for this macro. This flag is provided for
backwards compatibility as this was the behavior of previous
versions of msi, but it does not follow common scoping rules and is
discouraged.
- **-o _file_**
::: {option} -o <file>
Output will be written to the specifed \<file\> rather than to the
standard output.
:::
Output will be written to the specifed file rather than to the
standard output.
- **-I _dir_**
::: {option} -I <dir>
This parameter, which may be repeated or contain a colon-separated
(or semi-colon separated on Windows) list of directory paths,
specifies a search path for include commands. For example:
This parameter, which may be repeated or contain a colon-separated
(or semi-colon separated on Windows) list of directory paths,
specifies a search path for include commands. For example:
``` bash
msi -I /home/mrk/examples:. -I.. template
```
msi -I /home/mrk/examples:. -I.. template
specifies that all named files should be searched for in the following locations,
in the order given:
specifies that all named files should be searched for in the following locations,
in the order given:
1. `/home/mrk/examples`
2. `.` (the current directory)
3. `..` (the parent of the current directory)
1. /home/mrk/examples
2. . (the current directory)
3. .. (the parent of the current directory)
Note that relative path searching is handled as
Note that relative path searching is handled as
$ cat foo.substitutions
file rel/path/bar.template {
# contents
}
$ msi -I . -I /some/path foo.substitutions
which will try to find `bar.template` at the path `./rel/path/` followed by
`/some/path/rel/path`.
$ cat foo.substitutions
file rel/path/bar.template {
# contents
}
$ msi -I . -I /some/path foo.substitutions
which will try to find `bar.template` at the path `./rel/path/` followed by
`/some/path/rel/path`.
:::
- **-M _substitutions_**
::: {option} -M <substitutions>
This parameter specifies macro values for the template instance.
Multiple macro values can be specified in one substitution
parameter, or in multiple -M parameters. For example:
This parameter specifies macro values for the template instance.
Multiple macro values can be specified in one substitution
parameter, or in multiple -M parameters. For example:
``` bash
msi -M "a=aval,b=bval" -Mc=cval template
```
msi -M "a=aval,b=bval" -Mc=cval template
specifies that in the template file each occurrence of:
specifies that in the template file each occurrence of:
- `$(a)` or `${a}` is replaced by _aval_
- `$(b)` or `${b}` is replaced by _bval_
- `$(c)` or `${c}` is replaced by _cval_
:::
- `$(a)` or `${a}` is replaced by _aval_
- `$(b)` or `${b}` is replaced by _bval_
- `$(c)` or `${c}` is replaced by _cval_
::: {option} -S <subfile>
The substitution file. See below for format.
:::
- **-S _subfile_**
The substitution file. See below for format.
- **_template_**
The input file. If no file is specified then input is taken from
stdin, i.e. msi can be used as a filter. See below for a description
of commands that can be embedded in the template file.
::: {option} <template>
The input file. If no file is specified then input is taken from
stdin, i.e. msi can be used as a filter. See below for a description
of commands that can be embedded in the template file.
:::
It is not possible to display usage by just typing msi since executing
the command with no arguments is a valid command. To show usage specify
an illegal switch, e.g.
msi -help
``` bash
msi -help
```
## Exit Status
@@ -167,9 +181,9 @@ template file itself. These commands are:
Lines containing commands must be in one of these forms:
- include "_filename_"
- {samp}`include "{filename}"`
- substitute "_name1=value1, name2=value2, ..._"
- {samp}`substitute "{name1=value1, name2=value2, ...}"`
White space is allowed before and after the command verb, and after the
quoted string. If embedded quotes are needed, the backslash character \
@@ -227,11 +241,11 @@ dbTemplate format. We will discuss each separately.
### Regular format
global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
{var1=set1_val1, var2=set1_val2, ...}
{var2=set2_val2, var1=set2_val1, ...}
{var1=set1_val1, var2=set1_val2, ...}
{var2=set2_val2, var1=set2_val1, ...}
global {gbl_var1=gbl_val3, gbl_var2=gbl_val4, ...}
{var1=set3_val1, var2=set3_val2, ...}
{var2=set4_val2, var1=set4_val1, ...}
{var1=set3_val1, var2=set3_val2, ...}
{var2=set4_val2, var1=set4_val1, ...}
The template file is output with macro substitutions performed once for
each set of braces containing macro replacement values.
@@ -241,12 +255,12 @@ each set of braces containing macro replacement values.
global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
pattern {var1, var2, ...}
{set1_val1, set1_val2, ...}
{set2_val1, set2_val2, ...}
{set1_val1, set1_val2, ...}
{set2_val1, set2_val2, ...}
pattern {var2, var1, ...}
global {gbl_var1=gbl_val3, gbl_var2=gbl_val4, ...}
{set3_val2, set3_val1, ...}
{set4_val2, set4_val2, ...}
{set3_val2, set3_val1, ...}
{set4_val2, set4_val2, ...}
This produces the same result as the regular format example above.
@@ -320,8 +334,8 @@ The file template contains
and the file `substitute` is
global {family=Kraimer}
{first=Marty}
{first=Irma}
{first=Marty}
{first=Irma}
The following is the output produced:
@@ -340,8 +354,8 @@ Let the command be:
The file pattern contains
pattern {first,last}
{Marty,Kraimer}
{Irma,Kraimer}
{Marty,Kraimer}
{Irma,Kraimer}
and template is the same as the previous example:
@@ -365,16 +379,16 @@ Let the command be
`xxx.substitutions` is
file template {
pattern {first,last}
{Marty,Kraimer}
{Irma,Kraimer}
pattern {last,first}
{Smith,Bill}
{Smith,Mary}
pattern {first,last}
{Marty,Kraimer}
{Irma,Kraimer}
pattern {last,first}
{Smith,Bill}
{Smith,Mary}
}
file template {
{first=Marty,last=Kraimer}
{first=Irma,last=Kraimer}
{first=Marty,last=Kraimer}
{first=Irma,last=Kraimer}
}
`template` is the same as in the previous example.
+1 -1
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.
#*************************************************************************
# This is a Makefile fragment, see src/ioc/Makefile.
@@ -112,7 +112,7 @@ express that space character as an escaped character C<\x20> or C<\u0020> inside
a quoted string, otherwise the space will mark the end of the channel name to
the link parsing code inside the IOC.
=head4 Example Filters
=head3 Example Filters
Given a record called C<test:channel> the following would all apply a channel
filter C<f> to the VAL field of that record, giving the filter two numeric
@@ -230,7 +230,9 @@ This filter is used for two purposes:
=head4 Parameters
=head4 No parameters (an empty pair of braces)
=over
=item No parameters (an empty pair of braces)
Retrieve the record value as normal, but replace the timestamp with the time the
value was fetched (or an update was sent). This is useful for clients that can't
@@ -239,7 +241,7 @@ indicates when the record last processed, which could have been days or even
weeks ago for some records, or set to the EPICS epoch if the record has never
processed.
=head4 Numeric type C<"num">
=item Numeric type C<"num">
The following values are accepted for this parameter:
@@ -262,7 +264,7 @@ The following values are accepted for this parameter:
Note that C<epicsUInt32> cannot be transferred over Channel Access; in that
case, the value will be converted to C<epicsFloat64>.
=head4 String type C<"str">
=item String type C<"str">
The following values are accepted for this parameter:
@@ -275,7 +277,7 @@ The following values are accepted for this parameter:
=back
=head4 Epoch adjustment C<"epoch">
=item Epoch adjustment C<"epoch">
The following values are accepted for this parameter:
@@ -288,6 +290,8 @@ The following values are accepted for this parameter:
=back
=back
=head4 Examples
Hal$ caget -a 'test:invalid_ts.{"ts":{}}'
+5 -4
View File
@@ -21,6 +21,7 @@
#include "alarm.h"
#include "cantProceed.h"
#include "epicsStdio.h"
#include "dbDefs.h"
#include "dbEvent.h"
#include "dbAccess.h"
@@ -141,8 +142,8 @@ static long init_record(struct dbCommon *pcommon, int pass)
if (pfunc) {
pfunc(prec);
} else {
recGblRecordError(S_db_BadSub, (void *)prec,
"aSubRecord::init_record - INAM subr not found");
fprintf(stderr, "%s.INAM " ERL_ERROR " function '%s' not found\n",
prec->name, prec->inam);
return S_db_BadSub;
}
}
@@ -153,8 +154,8 @@ static long init_record(struct dbCommon *pcommon, int pass)
if (pfunc)
prec->sadr = pfunc;
else {
recGblRecordError(S_db_BadSub, (void *)prec,
"aSubRecord::init_record - SNAM subr not found");
fprintf(stderr, "%s.SNAM " ERL_ERROR " function '%s' not found\n",
prec->name, prec->snam);
return S_db_BadSub;
}
}
+12 -12
View File
@@ -226,7 +226,7 @@ This flag controls value, log (archive) and alarm change events.
The input links from where the values of A,...,U are fetched
during record processing.
=fields INPA, INPB, INPC, INPD, INPE, INPF, INPG, INPH, INPI, INPJ, INPK, INPL, INPM, INPN, INPO, INPP, INPQ, INPR, INPS, INPT, INPU
=fields INPA - INPU
=cut
@@ -341,7 +341,7 @@ during record processing.
Thse fields hold the scalar or array values fetched through the input links
INPA,...,INPU.
=fields A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U
=fields A - U
=cut
@@ -561,7 +561,7 @@ INPA,...,INPU.
Field types of the input value fields.
The choices can be found by following the link to the menuFtype definition.
=fields FTA, FTB, FTC, FTD, FTE, FTF, FTG, FTH, FTI, FTJ, FTK, FTL, FTM, FTN, FTO, FTP, FTQ, FTR, FTS, FTT, FTU
=fields FTA - FTU
=cut
@@ -742,7 +742,7 @@ Note that access to the C<NOT> field from C code must use the field name in
upper case, e.g. C<< prec->NOT >> since the lower-case C<not> is a reserved
word in C++ and cannot be used as an identifier.
=fields NOA, NOB, NOC, NOD, NOE, NOF, NOG, NOH, NOI, NOJ, NOK, NOL, NOM, NON, NOO, NOP, NOQ, NOR, NOS, NOT, NOU
=fields NOA - NOU
=cut
@@ -899,7 +899,7 @@ word in C++ and cannot be used as an identifier.
These fields specify how many array elements the input value fields currently
contain.
=fields NEA, NEB, NEC, NED, NEE, NEF, NEG, NEH, NEI, NEJ, NEK, NEL, NEM, NEN, NEO, NEP, NEQ, NER, NES, NET, NEU
=fields NEA - NEU
=cut
@@ -1035,7 +1035,7 @@ contain.
The output links through which the VALA ... VALU field values are sent
during record processing, provided the subroutine returned 0.
=fields OUTA, OUTB, OUTC, OUTD, OUTE, OUTF, OUTG, OUTH, OUTI, OUTJ, OUTK, OUTL, OUTM, OUTN, OUTO, OUTP, OUTQ, OUTR, OUTS, OUTT, OUTU
=fields OUTA - OUTU
=cut
field(OUTA,DBF_OUTLINK) {
@@ -1149,7 +1149,7 @@ during record processing, provided the subroutine returned 0.
These fields hold scalar or array data generated by the subroutine which will
be sent through the OUTA ... OUTU links during record processing.
=fields VALA, VALB, VALC, VALD, VALE, VALF, VALG, VALH, VALI, VALJ, VALK, VALL, VALM, VALN, VALO, VALP, VALQ, VALR, VALS, VALT, VALU
=fields VALA - VALU
=cut
@@ -1369,7 +1369,7 @@ be sent through the OUTA ... OUTU links during record processing.
The previous values of the output fields.
These are used to determine when to post events if EFLG is set to C<ON CHANGE>.
=fields OVLA, OVLB, OVLC, OVLD, OVLE, OVLF, OVLG, OVLH, OVLI, OVLJ, OVLK, OVLL, OVLM, OVLN, OVLO, OVLP, OVLQ, OVLR, OVLS, OVLT, OVLU
=fields OVLA - OVLU
=cut
@@ -1526,7 +1526,7 @@ These are used to determine when to post events if EFLG is set to C<ON CHANGE>.
Field types of the output value fields.
The choices can be found by following a link to the menuFtype definition.
=fields FTVA, FTVB, FTVC, FTVD, FTVE, FTVF, FTVG, FTVH, FTVI, FTVJ, FTVK, FTVL, FTVM, FTVN, FTVO, FTVP, FTVQ, FTVR, FTVS, FTVT, FTVU
=fields FTVA - FTVU
=cut
@@ -1703,7 +1703,7 @@ The choices can be found by following a link to the menuFtype definition.
These fields specify how many array elements the output value fields may hold.
=fields NOVA, NOVB, NOVC, NOVD, NOVE, NOVF, NOVG, NOVH, NOVI, NOVJ, NOVK, NOVL, NOVM, NOVN, NOVO, NOVP, NOVQ, NOVR, NOVS, NOVT, NOVU
=fields NOVA - NOVU
=cut
@@ -1860,7 +1860,7 @@ These fields specify how many array elements the output value fields may hold.
These fields specify how many array elements the output value fields currently
contain.
=fields NEVA, NEVB, NEVC, NEVD, NEVE, NEVF, NEVG, NEVH, NEVI, NEVJ, NEVK, NEVL, NEVM, NEVN, NEVO, NEVP, NEVQ, NEVR, NEVS, NEVT, NEVU
=fields NEVA - NEVU
=cut
@@ -1996,7 +1996,7 @@ contain.
These fields specify how many array elements the old value fields currently
contain.
=fields ONVA, ONVB, ONVC, ONVD, ONVE, ONVF, ONVG, ONVH, ONVI, ONVJ, ONVK, ONVL, ONVM, ONVN, ONVO, ONVP, ONVQ, ONVR, ONVS, ONVT, ONVU
=fields ONVA - ONVU
=cut
@@ -67,23 +67,29 @@ converted into engineering units and placed in the VAL field as follows:
=over
=item 1.
RVAL is converted to a double and ROFF is added to it.
=item 2.
If ASLO is non-zero the value is multiplied by ASLO.
=item 3.
AOFF is added.
=item 4.
If LINR is C<NO CONVERSION> the units conversion is finished after the above
steps.
=item 5.
If LINR is C<LINEAR> or C<SLOPE>, the value from step 3 above is multiplied by
ESLO and EOFF is added to complete the units conversion process.
=item 6.
Any other value for LINR selects a particular breakpoint table to be used on the
value from step 3 above.
+21 -7
View File
@@ -689,13 +689,17 @@ Routine process implements the following algorithm:
=over
=item 1. Check to see that the appropriate device support module
=item 1.
Check to see that the appropriate device support module
exists. If it doesn't, an error message is issued and processing is
terminated with the PACT field set to TRUE. This ensures that processes
will no longer be called for this record. Thus error storms will not
occur.
=item 2. Check PACT: If PACT is FALSE call fetch_values and convert
=item 2.
Check PACT: If PACT is FALSE call fetch_values and convert
which perform the following steps:
=over
@@ -742,20 +746,28 @@ calculated in, using the formula RVAL = (RVAL -AOFF) / ASLO - ROFF.
=back
=item 3. Check alarms: This routine checks to see if the new VAL causes
=item 3.
Check alarms: This routine checks to see if the new VAL causes
the alarm status and severity to change. If so, NSEV, NSTA and y are
set. It also honors the alarm hysteresis factor (HYST). Thus the value
must change by at least HYST before the alarm status and severity is
reduced.
=item 4. Check severity and write the new value. See Invalid Alarm
=item 4.
Check severity and write the new value. See Invalid Alarm
Output Action for details on how invalid alarms affect output records.
=item 5. If PACT has been changed to TRUE, the device support write
=item 5.
If PACT has been changed to TRUE, the device support write
output routine has started but has not completed writing the new value.
In this case, the processing routine merely returns, leaving PACT TRUE.
=item 6. Check to see if monitors should be invoked:
=item 6.
Check to see if monitors should be invoked:
=over
@@ -772,7 +784,9 @@ monitors are invoked.
=back
=item 7. Scan forward link if necessary, set PACT and INIT FALSE, and
=item 7.
Scan forward link if necessary, set PACT and INIT FALSE, and
return.
=back
@@ -331,23 +331,25 @@ Routine process implements the following algorithm:
=over
=item 1.
Check to see that the appropriate device support module exists. If it
doesn't, an error message is issued and processing is terminated with
the PACT field still set to TRUE. This ensures that processes will no
longer be called for this record. Thus error storms will not occur.
=item 2.
C<readValue()> is called. See L<Input Records> for details.
=item 3.
If PACT has been changed to TRUE, the device support read routine has
started but has not completed reading a new input value. In this case, the
processing routine merely returns, leaving PACT TRUE.
=item 4.
Convert.
=back
Convert.
=over
@@ -368,17 +370,15 @@ if status is 2, set status = 0
=back
=over
=item 5.
Check alarms: This routine checks to see if the new VAL causes the alarm
status and severity to change. If so, NSEV, NSTA and LALM are set. Note
that if VAL is greater than 1, no checking is performed.
=item 6.
Check if monitors should be invoked:
=back
Check if monitors should be invoked:
=over
@@ -396,9 +396,8 @@ NSEV and NSTA are reset to 0.
=back
=over
=item 7.
Scan forward link if necessary, set PACT FALSE, and return.
=back
+47 -33
View File
@@ -21,7 +21,7 @@ the HIGH field is configured.
recordtype(bo) {
=head3 Scan Parameters
=head2 Scan Parameters
The binary output record has the standard fields for specifying under what
circumstances the record will be processed.
@@ -29,7 +29,7 @@ These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
=fields SCAN, PHAS, EVNT, PRIO, PINI
=head3 Desired Output Parameters
=head2 Desired Output Parameters
The binary output record must specify where its desired output originates.
The desired output needs to be in engineering units.
@@ -50,7 +50,7 @@ for information on hardware addresses and links.
=fields DOL, OMSL
=head3 Convert and Write Parameters
=head2 Convert and Write Parameters
These parameters are used to determine where the binary output writes to
and how to convert the engineering units to a raw signal. After VAL is set
@@ -76,7 +76,7 @@ device back to 0 after I<N> number of seconds.
=fields DTYP, OUT, VAL, RVAL, HIGH, ZNAM, ONAM
=head3 Conversion Parameters
=head2 Conversion Parameters
The ZNAM field has the string that corresponds to the 0 state, and the ONAM
field holds the string that corresponds to the 1 state. These fields, other
@@ -98,7 +98,7 @@ the device or link to 1, then changes it back to 0 after I<N> number of seconds.
=fields ZNAM, ONAM, HIGH
=head3 Output Specification
=head2 Output Specification
The OUT field specifies where the binary output record writes its output.
It must specify the address of an I/O card if the record sends its output
@@ -116,7 +116,7 @@ for information on the format of the database and channel access addresses.
Also, see L<Device Support For Soft Records> in this chapter for more on output
to other records.
=head3 Operator Display Parameters
=head2 Operator Display Parameters
These parameters are used to present meaningful data to the operator, The
C<get_enum_str()> record support routine can retrieve the state string
@@ -129,7 +129,7 @@ Parameters> for more on the record name (NAME) and description (DESC) fields.
=fields ZNAM, ONAM, NAME, DESC
=head3 Alarm Parameters
=head2 Alarm Parameters
These parameters are used to determine the binary output's alarm condition
and to determine the severity of that condition. The possible alarm
@@ -147,7 +147,7 @@ common to all record types.
=fields ZSV, OSV, COSV, IVOA, IVOV
=head3 Run-Time Parameters
=head2 Run-Time Parameters
These parameters are used by the run-time code for processiong the binary
output. They are not configurable using a configuration tool. They
@@ -178,7 +178,7 @@ The WPDT field is a private field for honoring seconds to hold HIGH.
=fields ORAW, MASK, RBV, ORBV, LALM, MLST, RPVT, WDPT
=head3 Simulation Mode Parameters
=head2 Simulation Mode Parameters
The following fields are used to operate the record in simulation mode.
@@ -376,11 +376,9 @@ for more information on simulation mode and its fields.
}
=head2 Record Support
=head2 Record Support Routines
=head3 Record Support Routines
=head2 C<init_record>
=head3 C<init_record>
This routine initializes SIMM if SIML is a constant or creates a channel
access link if SIML is PV_LINK. If SIOL is a PV_LINK a channel access link
@@ -398,19 +396,19 @@ or initialzed to 0 if DOL is zero, and UDF is set to FALSE.
If device support includes C<init_record()>, it is called. VAL is set using
RVAL, and UDF is set to FALSE.
=head2 C<process>
=head3 C<process>
See next section.
=head2 C<get_enum_str>
=head3 C<get_enum_str>
Retrieves ASCII string corresponding to VAL.
=head2 C<get_enum_strs>
=head3 C<get_enum_strs>
Retrieves ASCII strings for ZNAM and ONAM.
=head2 C<put_enum_str>
=head3 C<put_enum_str>
Checks if string matches ZNAM or ONAM, and if it does, sets VAL.
@@ -418,96 +416,107 @@ Checks if string matches ZNAM or ONAM, and if it does, sets VAL.
Routine process implements the following algorithm:
=over 1
=over
=item 1.
Check to see that the appropriate device support module exists. If it
doesn't, an error message is issued and processing is terminated with
the PACT field still set to TRUE. This ensures that processes will no
longer be called for this record. Thus error storms will not occur.
=item 2.
If PACT is FALSE
=back
If PACT is FALSE
=over
=item *
If DOL holds a link and OMSL is C<closed_loop>
=over
=item *
get values from DOL
=item *
check for link alarm
=item *
force VAL to be 0 or 1
=item *
if MASK is defined
=over
=item *
if VAL is 0 set RVAL = 0
=back
=item *
else set RVAL = MASK
=back
=back
=over
=item 3.
Check alarms: This routine checks to see if the new VAL causes the alarm
status and severity to change. If so, NSEV, NSTA, and LALM are set.
=item 4.
Check severity and write the new value. See L<Invalid Output Action Fields|dbCommonOutput/Invalid Output Action Fields>
for more information on how INVALID alarms affect output.
=item 5.
If PACT has been changed to TRUE, the device support write output routine
has started but has not completed writing the new value. in this case, the
processing routine merely returns, leaving PACT TRUE.
=item 6.
Check WAIT. If VAL is 1 and WAIT is greater than 0, process again with a
VAL=0 after WAIT seconds.
=item 7.
Check to see if monitors should be invoked.
=back
=over 1
=over
=item *
Alarm monitors are invoked if the alarm status or severity has changed.
=item *
Archive and value change monitors are invoked if MLST is not equal to VAL.
=item *
Monitors for RVAL and for RBV are checked whenever other monitors are
invoked.
=item *
NSEV and NSTA are reset to 0.
=back
=over
=item 8.
=item 8
Scan forward link if necessary, set PACT FALSE, and return
=back
@@ -527,7 +536,7 @@ are primarily interested in the following fields:
Device support consists of the following routines:
=head4 long report(int level)
=head4 C<long report(int level)>
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
@@ -537,7 +546,7 @@ information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=head4 long init(int after)
=head4 C<long init(int after)>
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
@@ -545,41 +554,46 @@ the integer parameter C<after> set to 0.
The second call happens after all of the C<init_record()> calls have been made,
with C<after> set to 1.
=head2 C<init_record(precord)>
=head4 C<init_record(precord)>
This routine is optional. If provided, it is called by record support
This routine is optional. If provided, it is called by the record support's
C<init_record()> routine. It should determine MASK if it is needed.
=over
=item *
0: Success. RVAL modified (VAL will be set accordingly)
=item *
2: Success. VAL modified
=item *
other: Error
=back
=head2 C<get_ioint_info(int cmd, struct dbCommon *precord, IOSCANPVT *ppvt)>
=head4 C<get_ioint_info(int cmd, struct dbCommon *precord, IOSCANPVT *ppvt)>
This routine is called by the ioEventScan system each time the record is
added or deleted from an I/O event scan list. C<cmd> has the value (0,1) if
the record is being (added to, deleted from) an I/O event list. It must be
provided for any device type that can use the ioEvent scanner.
=head2 C<write_bo(precord)>
=head4 C<write_bo(precord)>
This routine must output a new value. It returns the following values:
=over
=item *
0: Success
=item *
other: Error.
=back
@@ -88,7 +88,7 @@ If SELM is C<Mask>, then SELN will be treated as a bit mask. If bit zero
OUTB will be written to, and so on. Thus when SELN==5, both OUTC and OUTA
will be written to.
=fields SELL, SELM, SELN, OUTA, OUTB, OUTC, OUTD, OUTE, OUTF, OUTG, OUTH
=fields SELL, SELM, SELN, OUTA - OUTH
=head3 Operator Display Parameters
@@ -99,7 +99,7 @@ via dbPuts.
The Fanout record also has the standard scanning fields common to all records.
These fields are listed in L<Scan Fields|dbCommonRecord/Scan Fields>.
=fields SELM, SELN, SELL, OFFS, SHFT, LNK0, LNK1, LNK2, LNK3, LNK4, LNK5, LNK6, LNK7, LNK8, LNK9, LNKA, LNKB, LNKC, LNKD, LNKE, LNKF
=fields SELM, SELN, SELL, OFFS, SHFT, LNK0 - LNK9, LNKA - LNKF
=cut
@@ -68,7 +68,7 @@ determine VAL as follows:
Each of the fields, B0-BF and B10-B1F, represents one bit of the word.
=fields VAL, INP, RVAL, SHFT, B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF, B10, B11, B12, B13, B14, B15, B16, B17, B18, B19, B1A, B1B, B1C, B1D, B1E, B1F
=fields VAL, INP, RVAL, SHFT, B0 - B9, BA - BF, B10 - B1F
=head3 Operator Display Parameters
@@ -81,7 +81,7 @@ initialization if the record is still undefined (UDF) after DOL has been read
and the device support initialized but at least one of the B0-B1F fields is
non-zero, the VAL field will be set from those fields and UDF will be cleared.
=fields B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF, B10, B11, B12, B13, B14, B15, B16, B17, B18, B19, B1A, B1B, B1C, B1D, B1E, B1F
=fields B0 - B9, BA - BF, B10 - B1F
=head3 Convert and Write Parameters
@@ -54,7 +54,7 @@ NaN to another value in order to define the link and its field. Note that all
undefined links must be recognized as such if the selection algorithm is to work
as expected.
=fields INPA, INPB, INPC, INPD, INPE, INPF, INPG, INPH, INPI, INPJ, INPK, INPL, A, B, C, D, E, F, G, H, I, J, K, L
=fields INPA - INPL, A - L
=head3 Select Parameters
@@ -156,7 +156,7 @@ The LA-LL fields are used to implement the monitors for each of the value
fields, A-L. They represent previous input values. For example, unless LA is not
equal to A, no monitor is invoked for A.
=fields VAL, LALM, ALST, MLST, LA, LB, LC, LD, LE, LF, LG, LH, LI, LJ, LK, LL
=fields VAL, LALM, ALST, MLST, LA - LL
=head2 Record Support
@@ -58,11 +58,11 @@ constant value, and may subsequently be changed via dbPuts.
=head4 Desired Output Link Fields
=fields DOL0, DOL1, DOL2, DOL3, DOL4, DOL5, DOL6, DOL7, DOL8, DOL9, DOLA, DOLB, DOLC, DOLD, DOLE, DOLF
=fields DOL0 - DOL9, DOLA - DOLF
=head4 Desired Output Value Fields
=fields DO0, DO1, DO2, DO3, DO4, DO5, DO6, DO7, DO8, DO9, DOA, DOB, DOC, DOD, DOE, DOF
=fields DO0 - DO9, DOA - DOF
=head3 Output Parameters
@@ -72,7 +72,7 @@ output link (LNK0-LNKF). These output links can be database links or channel
access links; they cannot be device addresses. There are sixteen output links, one
for each desired output link. Only those that are defined are used.
=fields LNK0, LNK1, LNK2, LNK3, LNK4, LNK5, LNK6, LNK7, LNK8, LNK9, LNKA, LNKB, LNKC, LNKD, LNKE, LNKF
=fields LNK0 - LNK9, LNKA - LNKF
=head3 Selection Algorithm Parameters
@@ -178,7 +178,7 @@ DOL1, DOV1, and LNK1 fields for three seconds. That is, the desired output value
will not be fetched and written to the output link until three seconds have
lapsed.
=fields DLY0, DLY1, DLY2, DLY3, DLY4, DLY5, DLY6, DLY7, DLY8, DLY9, DLYA, DLYB, DLYC, DLYD, DLYE, DLYF
=fields DLY0 - DLY9, DLYA - DLYF
=head3 Operator Display Parameters
@@ -72,7 +72,7 @@ link.
DOL can also be a constant, in which case VAL will be initialized to the
constant value. However to be interpreted as a constant instead of a CA link
the constant can only be numeric, so string output records are best initialized
by dirctly setting the VAL field. Note that if DOL is a constant, OMSL
by directly setting the VAL field. Note that if DOL is a constant, OMSL
cannot be C<<< closed_loop >>>.
=fields VAL, DOL, OMSL
+6 -4
View File
@@ -108,7 +108,8 @@ static long init_record(struct dbCommon *pcommon, int pass)
/* convert the initialization subroutine name */
psubroutine = (SUBFUNCPTR)registryFunctionFind(prec->inam);
if (psubroutine == 0) {
recGblRecordError(S_db_BadSub, (void *)prec, "Init subroutine (INAM)");
fprintf(stderr, "%s.INAM " ERL_ERROR " function '%s' not found\n",
prec->name, prec->inam);
return S_db_BadSub;
}
/* invoke the initialization subroutine */
@@ -122,7 +123,8 @@ static long init_record(struct dbCommon *pcommon, int pass)
}
prec->sadr = (SUBFUNCPTR)registryFunctionFind(prec->snam);
if (prec->sadr == NULL) {
recGblRecordError(S_db_BadSub, (void *)prec, "Proc subroutine (SNAM)");
fprintf(stderr, "%s.SNAM " ERL_ERROR " function '%s' not found\n",
prec->name, prec->snam);
return S_db_BadSub;
}
prec->mlst = prec->val;
@@ -186,8 +188,8 @@ static long special(DBADDR *paddr, int after)
prec->sadr = (SUBFUNCPTR)registryFunctionFind(prec->snam);
if (prec->sadr) return 0;
recGblRecordError(S_db_BadSub, (void *)prec,
"subRecord(special) registryFunctionFind failed");
fprintf(stderr, "%s " ERL_ERROR " subRecord::special - SNAM = '%s' not found\n",
prec->name, prec->snam);
return S_db_BadSub;
}
@@ -40,7 +40,7 @@ the constant value and the field's value can be changed at run-time via dbPuts.
Otherwise, the values for (A-F) are fetched from the input links when the record
is processed.
=fields INPA, INPB, INPC, INPD, INPE, INPF, INPG, INPH, INPI, INPJ, INPK, INPL, A, B, C, D, E, F, G, H, I, J, K, L
=fields INPA - INPL, A - L
=head3 Subroutine Connection
@@ -119,7 +119,7 @@ The rest of these fields--LALM, ALST, MLST, and the LA-LL fields--are used to
implement the monitors. For example, when LA is not equal to A, the value-change
monitors are called for that field.
=fields VAL, SADR, LALM, ALST, MLST, LA, LB, LC, LD, LE, LF, LG, LH, LI, LJ, LK, LL
=fields VAL, SADR, LALM, ALST, MLST, LA - LL
=head2 Record Support
@@ -29,4 +29,3 @@ softIoc_LIBS = $(EPICS_BASE_IOC_LIBS)
DB += softIocExit.db
CLEANS += epicsInstallDir.h
+23 -24
View File
@@ -51,6 +51,14 @@ namespace {
bool verbose = false;
enum coloration {NONE, CMD, REM};
void verbose_out(coloration color, const std::string& message) {
if (!verbose) return;
const char *ansi[] = {ANSI_ESC_RESET, ANSI_ESC_BOLD, ANSI_ESC_BLUE};
std::cout << ansi[color] << message << ansi[NONE] << std::endl;
}
static void exitSubroutine(subRecord *precord) {
epicsExitLater((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE);
}
@@ -109,13 +117,11 @@ void lazy_dbd(const std::string& dbd_file) {
if(lazy_dbd_loaded) return;
lazy_dbd_loaded = true;
if (verbose)
std::cout<<"dbLoadDatabase(\""<<dbd_file<<"\")\n";
verbose_out(CMD, std::string("dbLoadDatabase(\"") + dbd_file + "\")");
errIf(dbLoadDatabase(dbd_file.c_str(), NULL, NULL),
std::string("Failed to load DBD file: ")+dbd_file);
if (verbose)
std::cout<<"softIoc_registerRecordDeviceDriver(pdbbase)\n";
verbose_out(CMD, "softIoc_registerRecordDeviceDriver(pdbbase)");
errIf(softIoc_registerRecordDeviceDriver(pdbbase),
"Failed to initialize database");
registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine);
@@ -166,15 +172,14 @@ int main(int argc, char *argv[])
epicsExit(2);
return 2;
case 'a':
lazy_dbd(dbd_file);
if (!macros.empty()) {
if (verbose)
std::cout<<"asSetSubstitutions(\""<<macros<<"\")\n";
verbose_out(CMD, std::string("asSetSubstitutions(\"")
+ macros + "\")");
if(asSetSubstitutions(macros.c_str()))
throw std::bad_alloc();
}
if (verbose)
std::cout<<"asSetFilename(\""<<optarg<<"\")\n";
verbose_out(CMD, std::string("asSetFilename(\"")
+ optarg + "\")");
if(asSetFilename(optarg))
throw std::bad_alloc();
break;
@@ -186,12 +191,10 @@ int main(int argc, char *argv[])
break;
case 'd':
lazy_dbd(dbd_file);
if (verbose) {
std::cout<<"dbLoadRecords(\""<<optarg<<"\"";
if(!macros.empty())
std::cout<<", \""<<macros<<"\"";
std::cout<<")\n";
}
verbose_out(CMD, std::string("dbLoadRecords(\"")
+ optarg + "\"" + ( !macros.empty() ?
(std::string(", \"") + macros + "\"") : std::string() )
+ ")");
errIf(dbLoadRecords(optarg, macros.c_str()),
std::string("Failed to load: ")+optarg);
loadedDb = true;
@@ -211,9 +214,8 @@ int main(int argc, char *argv[])
lazy_dbd(dbd_file);
xmacro = "IOC=";
xmacro += optarg;
if (verbose) {
std::cout<<"dbLoadRecords(\""<<exit_file<<"\", \""<<xmacro<<"\")\n";
}
verbose_out(CMD, std::string("dbLoadRecords(\"")
+ exit_file + "\", \"" + xmacro + "\")");
errIf(dbLoadRecords(exit_file.c_str(), xmacro.c_str()),
std::string("Failed to load: ")+exit_file);
loadedDb = true;
@@ -227,20 +229,17 @@ int main(int argc, char *argv[])
// run script
// ignore any extra positional args (historical)
if (verbose)
std::cout<<"# Begin "<<argv[optind]<<"\n";
verbose_out(REM, std::string("# Begin ") + argv[optind]);
errIf(iocsh(argv[optind]),
std::string("Error in ")+argv[optind]);
if (verbose)
std::cout<<"# End "<<argv[optind]<<"\n";
verbose_out(REM, std::string("# End ") + argv[optind]);
epicsThreadSleep(0.2);
ranScript = true; /* Assume the script has done any necessary initialization */
}
if (loadedDb) {
if (verbose)
std::cout<<"iocInit()\n";
verbose_out(CMD, "iocInit()");
if(iocInit()) {
std::cerr<<ERL_ERROR " during iocInit()"<<std::endl;
}
+8 -2
View File
@@ -135,7 +135,13 @@ my $pod = join "\n",
}
elsif (m/^ =title \s+ (.*)/x) {
$title = $1;
"=head1 $title";
"=head1 $title\n\n=encoding utf8\n";
}
elsif (m/^ =encoding \s+ (.*)/x) {
my $enc = $1;
die "Encoding '$enc' conflicts with 'utf8' in $infile POD directive\n"
unless $enc =~ m/^ utf-?8 $/ix;
# ignore, we already have =encoding utf8
}
else {
$_;
@@ -196,7 +202,7 @@ sub rtypeToMD {
sub fieldTableRow {
my ($fld, $dbd) = @_;
if ($fld eq '-') {
return "| \x{22EE}".(" " x 83)."||||||||";
return "| \N{VERTICAL ELLIPSIS}".(" " x 82)."||||||||";
}
my @md;
push @md, sprintf("%-5s", $fld->name), sprintf("%-26s", $fld->attribute('prompt'));