diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index e4ba47e2f..2240e1bc3 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -52,8 +52,11 @@ static char *pNullString = ""; #define messagesize 276 #define RPCL_LEN INFIX_TO_POSTFIX_SIZE(80) -static char *ppstring[5]={"NPP","PP","CA","CP","CPP"}; -static char *msstring[4]={"NMS","MS","MSI","MSS"}; +/* must be long enough to hold 32-bit signed integer in base 10 */ +STATIC_ASSERT(messagesize>=11); + +static char *ppstring[5]={" NPP"," PP"," CA"," CP"," CPP"}; +static char *msstring[4]={" NMS"," MS"," MSI"," MSS"}; epicsShareDef maplinkType pamaplinkType[LINK_NTYPES] = { {"CONSTANT",CONSTANT}, @@ -83,13 +86,9 @@ static int mapDBFtoDCT[DBF_NOACCESS+1] = { DCT_INLINK,DCT_OUTLINK,DCT_FWDLINK, DCT_NOACCESS}; - /*forward references for private routines*/ -static FILE *openOutstream(const char *filename); -static void finishOutstream(FILE *stream); -static void entryErrMessage(DBENTRY *pdbentry,long status,char *mess); -static void zeroDbentry(DBENTRY *pdbentry); -static char *getpMessage(DBENTRY *pdbentry); +static void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...) + EPICS_PRINTF_STYLE(2,3); static long dbAddOnePath (DBBASE *pdbbase, const char *path, unsigned length); /* internal routines*/ @@ -207,10 +206,152 @@ static char *getpMessage(DBENTRY *pdbentry) msg = dbCalloc(1, messagesize); pdbentry->message = msg; } - *msg = 0; + *msg = '\0'; return msg; } +static +void dbMsgCpy(DBENTRY *pdbentry, const char *msg) +{ + getpMessage(pdbentry); + strncpy(pdbentry->message, msg, messagesize-1); + pdbentry->message[messagesize-1] = '\0'; +} + +static +void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...) +{ + va_list args; + getpMessage(pdbentry); + va_start(args, fmt); + epicsVsnprintf(pdbentry->message, messagesize, fmt, args); + va_end(args); +} + +static void ulongToHexString(epicsUInt32 source,char *pdest) +{ + static const char hex_digit_to_ascii[16] = "0123456789abcdef"; + epicsUInt32 val,temp; + char digit[10]; + int i,j; + + if (source==0) { + strcpy(pdest,"0x0"); + return; + } + *pdest++ = '0'; *pdest++ = 'x'; + val = source; + for (i=0; val!=0; i++) { + temp = val/16; + digit[i] = hex_digit_to_ascii[val - temp*16]; + val = temp; + } + for (j=i-1; j>=0; j--) { + *pdest++ = digit[j]; + } + *pdest = 0; + return; +} + +static void realToString(double value, char *preturn, int isdouble) +{ + static const double delta[2] = {1e-6, 1e-15}; + static const int precision[2] = {6, 14}; + double absvalue; + int logval,prec; + size_t end; + char tstr[30]; + char *ptstr = &tstr[0]; + int round; + int ise = FALSE; + char *loce = NULL; + + if (value == 0) { + strcpy(preturn, "0"); + return; + } + + absvalue = value < 0 ? -value : value; + if (absvalue < (double)INT_MAX) { + epicsInt32 intval = (epicsInt32) value; + double diff = value - intval; + + if (diff < 0) diff = -diff; + if (diff < absvalue * delta[isdouble]) { + cvtLongToString(intval, preturn); + return; + } + } + + /*Now starts the hard cases*/ + if (value < 0) { + *preturn++ = '-'; + value = -value; + } + + logval = (int)log10(value); + if (logval > 6 || logval < -2) { + int nout; + + ise = TRUE; + prec = precision[isdouble]; + nout = sprintf(ptstr, "%.*e", prec, value); + loce = strchr(ptstr, 'e'); + + if (!loce) { + ptstr[nout] = 0; + strcpy(preturn, ptstr); + return; + } + + *loce++ = 0; + } else { + prec = precision[isdouble] - logval; + if ( prec < 0) prec = 0; + sprintf(ptstr, "%.*f", prec, value); + } + + if (prec > 0) { + end = strlen(ptstr) - 1; + round = FALSE; + while (end > 0) { + if (tstr[end] == '.') {end--; break;} + if (tstr[end] == '0') {end--; continue;} + if (!round && end < precision[isdouble]) break; + if (!round && tstr[end] < '8') break; + if (tstr[end-1] == '.') { + if (round) end = end-2; + break; + } + if (tstr[end-1] != '9') break; + round = TRUE; + end--; + } + tstr[end+1] = 0; + while (round) { + if (tstr[end] < '9') {tstr[end]++; break;} + if (end == 0) { *preturn++ = '1'; tstr[end] = '0'; break;} + tstr[end--] = '0'; + } + } + strcpy(preturn, &tstr[0]); + if (ise) { + if (!(strchr(preturn, '.'))) strcat(preturn, ".0"); + strcat(preturn, "e"); + strcat(preturn, loce); + } +} + +static void floatToString(float value, char *preturn) +{ + realToString((double)value, preturn, 0); +} + +static void doubleToString(double value, char *preturn) +{ + realToString(value, preturn, 1); +} + /*Public only for dbStaticNoRun*/ dbDeviceMenu *dbGetDeviceMenu(DBENTRY *pdbentry) { @@ -1718,16 +1859,30 @@ char * dbGetString(DBENTRY *pdbentry) { dbFldDes *pflddes = pdbentry->pflddes; void *pfield = pdbentry->pfield; - char *message; DBLINK *plink; - message = getpMessage(pdbentry); - if(!pflddes) {strcpy(message,"fldDes not found"); return(message);} + if (!pflddes) { + dbMsgCpy(pdbentry, "fldDes not found"); + return pdbentry->message; + } switch (pflddes->field_type) { case DBF_STRING: - if(!pfield) {strcpy(message,"Field not found"); return(message);} - strcpy(message, (char *)pfield); - break; + case DBF_INLINK: + case DBF_OUTLINK: + case DBF_FWDLINK: + if (!pfield) { + dbMsgCpy(pdbentry, "Field not allocated (NULL)"); + return pdbentry->message; + } + break; + default: + break; + } + + switch (pflddes->field_type) { + case DBF_STRING: + dbMsgCpy(pdbentry, (char *)pfield); + break; case DBF_CHAR: case DBF_UCHAR: case DBF_SHORT: @@ -1742,125 +1897,115 @@ char * dbGetString(DBENTRY *pdbentry) return(dbGetStringNum(pdbentry)); case DBF_INLINK: case DBF_OUTLINK: - if(!pfield) {strcpy(message,"Field not found"); return(message);} plink = (DBLINK *)pfield; switch(plink->type) { - case CONSTANT: - if(plink->value.constantStr) { - strcpy(message,plink->value.constantStr); - } else { - strcpy(message,""); - } - break; - case MACRO_LINK: - if(plink->value.macro_link.macroStr) { - strcpy(message,plink->value.macro_link.macroStr); - } else { - strcpy(message,""); - } - break; - case PN_LINK: - if(plink->value.pv_link.pvname) - strcpy(message,plink->value.pv_link.pvname); - else - strcpy(message,""); - strcat(message," "); - strcat(message,msstring[plink->value.pv_link.pvlMask&pvlOptMsMode]); - break; - case PV_LINK: - case CA_LINK: - case DB_LINK: { - int ppind; - short pvlMask; - - pvlMask = plink->value.pv_link.pvlMask; - if(pvlMask&pvlOptPP) ppind=1; - else if(pvlMask&pvlOptCA) ppind=2; - else if(pvlMask&pvlOptCP) ppind=3; - else if(pvlMask&pvlOptCPP) ppind=4; - else ppind=0; - if (plink->value.pv_link.pvname) { - strcpy(message, plink->value.pv_link.pvname); - if (pvlMask & pvlOptTSELisTime) - strcat(message, ".TIME"); - } else - strcpy(message,""); - strcat(message," "); - strcat(message,ppstring[ppind]); - strcat(message," "); - strcat(message,msstring[pvlMask&pvlOptMsMode]); - break; + case CONSTANT: + if (plink->value.constantStr) { + dbMsgCpy(pdbentry, plink->value.constantStr); + } else { + dbMsgCpy(pdbentry, ""); } - case VME_IO: - sprintf(message,"#C%d S%d @%s", - plink->value.vmeio.card,plink->value.vmeio.signal, - plink->value.vmeio.parm); - break; - case CAMAC_IO: - sprintf(message,"#B%d C%d N%d A%d F%d @%s", - plink->value.camacio.b,plink->value.camacio.c, - plink->value.camacio.n,plink->value.camacio.a, - plink->value.camacio.f,plink->value.camacio.parm); - break; - case RF_IO: - sprintf(message,"#R%d M%d D%d E%d", - plink->value.rfio.cryo, - plink->value.rfio.micro, - plink->value.rfio.dataset, - plink->value.rfio.element); - break; - case AB_IO: - sprintf(message,"#L%d A%d C%d S%d @%s", - plink->value.abio.link,plink->value.abio.adapter, - plink->value.abio.card,plink->value.abio.signal, - plink->value.abio.parm); - break; - case GPIB_IO: - sprintf(message,"#L%d A%d @%s", - plink->value.gpibio.link,plink->value.gpibio.addr, - plink->value.gpibio.parm); - break; - case BITBUS_IO: - sprintf(message,"#L%u N%u P%u S%u @%s", - plink->value.bitbusio.link,plink->value.bitbusio.node, - plink->value.bitbusio.port,plink->value.bitbusio.signal, - plink->value.bitbusio.parm); - break; - case BBGPIB_IO: - sprintf(message,"#L%u B%u G%u @%s", - plink->value.bbgpibio.link,plink->value.bbgpibio.bbaddr, - plink->value.bbgpibio.gpibaddr,plink->value.bbgpibio.parm); - break; - case INST_IO: - sprintf(message,"@%s", plink->value.instio.string); - break; - case VXI_IO : - if (plink->value.vxiio.flag == VXIDYNAMIC) - sprintf(message,"#V%d C%d S%d @%s", - plink->value.vxiio.frame,plink->value.vxiio.slot, - plink->value.vxiio.signal,plink->value.vxiio.parm); - else - sprintf(message,"#V%d S%d @%s", - plink->value.vxiio.la,plink->value.vxiio.signal, - plink->value.vxiio.parm); - break; - default : - return(NULL); + break; + case MACRO_LINK: + if (plink->value.macro_link.macroStr) { + dbMsgCpy(pdbentry, plink->value.macro_link.macroStr); + } else { + dbMsgCpy(pdbentry, ""); + } + break; + case PN_LINK: + dbMsgPrint(pdbentry, "%s%s", + plink->value.pv_link.pvname ? plink->value.pv_link.pvname : "", + msstring[plink->value.pv_link.pvlMask&pvlOptMsMode]); + break; + case PV_LINK: + case CA_LINK: + case DB_LINK: { + int ppind; + short pvlMask; + + pvlMask = plink->value.pv_link.pvlMask; + if (pvlMask&pvlOptPP) ppind=1; + else if(pvlMask&pvlOptCA) ppind=2; + else if(pvlMask&pvlOptCP) ppind=3; + else if(pvlMask&pvlOptCPP) ppind=4; + else ppind=0; + dbMsgPrint(pdbentry, "%s%s%s%s", + plink->value.pv_link.pvname ? plink->value.pv_link.pvname : "", + (pvlMask & pvlOptTSELisTime) ? ".TIME" : "", + ppstring[ppind], + msstring[plink->value.pv_link.pvlMask&pvlOptMsMode]); + break; + } + case VME_IO: + dbMsgPrint(pdbentry, "#C%d S%d @%s", + plink->value.vmeio.card,plink->value.vmeio.signal, + plink->value.vmeio.parm); + break; + case CAMAC_IO: + dbMsgPrint(pdbentry, "#B%d C%d N%d A%d F%d @%s", + plink->value.camacio.b,plink->value.camacio.c, + plink->value.camacio.n,plink->value.camacio.a, + plink->value.camacio.f,plink->value.camacio.parm); + break; + case RF_IO: + dbMsgPrint(pdbentry, "#R%d M%d D%d E%d", + plink->value.rfio.cryo, + plink->value.rfio.micro, + plink->value.rfio.dataset, + plink->value.rfio.element); + break; + case AB_IO: + dbMsgPrint(pdbentry, "#L%d A%d C%d S%d @%s", + plink->value.abio.link,plink->value.abio.adapter, + plink->value.abio.card,plink->value.abio.signal, + plink->value.abio.parm); + break; + case GPIB_IO: + dbMsgPrint(pdbentry, "#L%d A%d @%s", + plink->value.gpibio.link,plink->value.gpibio.addr, + plink->value.gpibio.parm); + break; + case BITBUS_IO: + dbMsgPrint(pdbentry, "#L%u N%u P%u S%u @%s", + plink->value.bitbusio.link,plink->value.bitbusio.node, + plink->value.bitbusio.port,plink->value.bitbusio.signal, + plink->value.bitbusio.parm); + break; + case BBGPIB_IO: + dbMsgPrint(pdbentry, "#L%u B%u G%u @%s", + plink->value.bbgpibio.link,plink->value.bbgpibio.bbaddr, + plink->value.bbgpibio.gpibaddr,plink->value.bbgpibio.parm); + break; + case INST_IO: + dbMsgPrint(pdbentry, "@%s", plink->value.instio.string); + break; + case VXI_IO : + if (plink->value.vxiio.flag == VXIDYNAMIC) + dbMsgPrint(pdbentry, "#V%d C%d S%d @%s", + plink->value.vxiio.frame,plink->value.vxiio.slot, + plink->value.vxiio.signal,plink->value.vxiio.parm); + else + dbMsgPrint(pdbentry, "#V%d S%d @%s", + plink->value.vxiio.la,plink->value.vxiio.signal, + plink->value.vxiio.parm); + break; + default : + return(NULL); } break; case DBF_FWDLINK: { DBLINK *plink=(DBLINK *)pfield; - if(!pfield) {strcpy(message,"Field not found"); return(message);} switch(plink->type) { case CONSTANT: - strcpy(message,"0"); + dbMsgCpy(pdbentry, "0"); break; case MACRO_LINK: - if(plink->value.macro_link.macroStr) { - strcpy(message,plink->value.macro_link.macroStr); + if (plink->value.macro_link.macroStr) { + dbMsgCpy(pdbentry, plink->value.macro_link.macroStr); } else { - strcpy(message,""); + dbMsgCpy(pdbentry, ""); } break; case PV_LINK: @@ -1870,16 +2015,11 @@ char * dbGetString(DBENTRY *pdbentry) short pvlMask; pvlMask = plink->value.pv_link.pvlMask; - if(pvlMask&pvlOptCA) ppind=2; + if (pvlMask&pvlOptCA) ppind=2; else ppind=0; - if(plink->value.pv_link.pvname) - strcpy(message,plink->value.pv_link.pvname); - else - strcpy(message,""); - if(ppind) { - strcat(message," "); - strcat(message,ppstring[ppind]); - } + dbMsgPrint(pdbentry, "%s%s", + plink->value.pv_link.pvname ? plink->value.pv_link.pvname : "", + ppind ? ppstring[ppind] : ""); break; } default : @@ -1890,7 +2030,106 @@ char * dbGetString(DBENTRY *pdbentry) default: return(NULL); } - return (message); + return pdbentry->message; +} + +char *dbGetStringNum(DBENTRY *pdbentry) +{ + dbFldDes *pflddes = pdbentry->pflddes; + void *pfield = pdbentry->pfield; + char *message; + unsigned char cvttype; + + /* the following assumes that messagesize is large enough + * to hold the base 10 encoded value of a 32-bit integer. + */ + message = getpMessage(pdbentry); + cvttype = pflddes->base; + switch (pflddes->field_type) { + case DBF_CHAR: + if (cvttype==CT_DECIMAL) + cvtCharToString(*(char*)pfield, message); + else + ulongToHexString((epicsUInt32)(*(char*)pfield),message); + break; + case DBF_UCHAR: + if (cvttype==CT_DECIMAL) + cvtUcharToString(*(unsigned char*)pfield, message); + else + ulongToHexString((epicsUInt32)(*(unsigned char*)pfield),message); + break; + case DBF_SHORT: + if (cvttype==CT_DECIMAL) + cvtShortToString(*(short*)pfield, message); + else + ulongToHexString((epicsUInt32)(*(short*)pfield),message); + break; + case DBF_USHORT: + case DBF_ENUM: + if (cvttype==CT_DECIMAL) + cvtUshortToString(*(unsigned short*)pfield, message); + else + ulongToHexString((epicsUInt32)(*(unsigned short*)pfield),message); + break; + case DBF_LONG: + if (cvttype==CT_DECIMAL) + cvtLongToString(*(epicsInt32*)pfield, message); + else + ulongToHexString((epicsUInt32)(*(epicsInt32*)pfield), message); + break; + case DBF_ULONG: + if (cvttype==CT_DECIMAL) + cvtUlongToString(*(epicsUInt32 *)pfield, message); + else + ulongToHexString(*(epicsUInt32*)pfield, message); + break; + case DBF_FLOAT: + floatToString(*(float *)pfield,message); + break; + case DBF_DOUBLE: + doubleToString(*(double *)pfield,message); + break; + case DBF_MENU: + { + dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt; + short choice_ind; + char *pchoice; + + if (!pfield) { + dbMsgCpy(pdbentry, "Field not found"); + return message; + } + choice_ind = *((short *) pdbentry->pfield); + if (!pdbMenu || choice_ind<0 || choice_ind>=pdbMenu->nChoice) + return NULL; + pchoice = pdbMenu->papChoiceValue[choice_ind]; + dbMsgCpy(pdbentry, pchoice); + } + break; + case DBF_DEVICE: + { + dbDeviceMenu *pdbDeviceMenu; + char *pchoice; + short choice_ind; + + if (!pfield) { + dbMsgCpy(pdbentry, "Field not found"); + return message; + } + pdbDeviceMenu = dbGetDeviceMenu(pdbentry); + if (!pdbDeviceMenu) + return NULL; + choice_ind = *((short *) pdbentry->pfield); + if (choice_ind<0 || choice_ind>=pdbDeviceMenu->nChoice) + return NULL; + pchoice = pdbDeviceMenu->papChoice[choice_ind]; + dbMsgCpy(pdbentry, pchoice); + } + break; + default: + return NULL; + } + return message; } long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec) @@ -3265,7 +3504,8 @@ void dbReportDeviceConfig(dbBase *pdbbase,FILE *report) plink = pdbentry->pfield; linkType = plink->type; if(bus[linkType][0]==0) continue; - strcpy(linkValue,dbGetString(pdbentry)); + strncpy(linkValue, dbGetString(pdbentry), NELEMENTS(linkValue)-1); + linkValue[NELEMENTS(linkValue)-1] = '\0'; status = dbFindField(pdbentry,"DTYP"); if(status) break; strcpy(dtypValue,dbGetString(pdbentry)); diff --git a/src/ioc/dbStatic/dbStaticRun.c b/src/ioc/dbStatic/dbStaticRun.c index f7fcbd5c5..886fa3501 100644 --- a/src/ioc/dbStatic/dbStaticRun.c +++ b/src/ioc/dbStatic/dbStaticRun.c @@ -31,136 +31,6 @@ #include "devSup.h" #include "special.h" - -static char hex_digit_to_ascii[16]={'0','1','2','3','4','5','6','7','8','9', - 'a','b','c','d','e','f'}; - -static void ulongToHexString(epicsUInt32 source,char *pdest) -{ - epicsUInt32 val,temp; - char digit[10]; - int i,j; - - if(source==0) { - strcpy(pdest,"0x0"); - return; - } - *pdest++ = '0'; *pdest++ = 'x'; - val = source; - for(i=0; val!=0; i++) { - temp = val/16; - digit[i] = hex_digit_to_ascii[val - temp*16]; - val = temp; - } - for(j=i-1; j>=0; j--) { - *pdest++ = digit[j]; - } - *pdest = 0; - return; -} - -static double delta[2] = {1e-6, 1e-15}; -static int precision[2] = {6, 14}; -static void realToString(double value, char *preturn, int isdouble) -{ - double absvalue; - int logval,prec; - size_t end; - char tstr[30]; - char *ptstr = &tstr[0]; - int round; - int ise = FALSE; - char *loce = NULL; - - if (value == 0) { - strcpy(preturn, "0"); - return; - } - - absvalue = value < 0 ? -value : value; - if (absvalue < (double)INT_MAX) { - epicsInt32 intval = (epicsInt32) value; - double diff = value - intval; - - if (diff < 0) diff = -diff; - if (diff < absvalue * delta[isdouble]) { - cvtLongToString(intval, preturn); - return; - } - } - - /*Now starts the hard cases*/ - if (value < 0) { - *preturn++ = '-'; - value = -value; - } - - logval = (int)log10(value); - if (logval > 6 || logval < -2) { - int nout; - - ise = TRUE; - prec = precision[isdouble]; - nout = sprintf(ptstr, "%.*e", prec, value); - loce = strchr(ptstr, 'e'); - - if (!loce) { - ptstr[nout] = 0; - strcpy(preturn, ptstr); - return; - } - - *loce++ = 0; - } else { - prec = precision[isdouble] - logval; - if ( prec < 0) prec = 0; - sprintf(ptstr, "%.*f", prec, value); - } - - if (prec > 0) { - end = strlen(ptstr) - 1; - round = FALSE; - while (end > 0) { - if (tstr[end] == '.') {end--; break;} - if (tstr[end] == '0') {end--; continue;} - if (!round && end < precision[isdouble]) break; - if (!round && tstr[end] < '8') break; - if (tstr[end-1] == '.') { - if (round) end = end-2; - break; - } - if (tstr[end-1] != '9') break; - round = TRUE; - end--; - } - tstr[end+1] = 0; - while (round) { - if (tstr[end] < '9') {tstr[end]++; break;} - if (end == 0) { *preturn++ = '1'; tstr[end] = '0'; break;} - tstr[end--] = '0'; - } - } - strcpy(preturn, &tstr[0]); - if (ise) { - if (!(strchr(preturn, '.'))) strcat(preturn, ".0"); - strcat(preturn, "e"); - strcat(preturn, loce); - } -} - -static void floatToString(float value,char *preturn) -{ - realToString((double)value,preturn,0); - return; -} - -static void doubleToString(double value,char *preturn) -{ - realToString(value,preturn,1); - return; -} - - static long do_nothing(struct dbCommon *precord) { return 0; } /* Dummy DSXT used for soft device supports */ @@ -480,95 +350,7 @@ epicsShareFunc int dbIsDefaultValue(DBENTRY *pdbentry) } return(FALSE); } - -char *dbGetStringNum(DBENTRY *pdbentry) -{ - dbFldDes *pflddes = pdbentry->pflddes; - void *pfield = pdbentry->pfield; - char *message; - unsigned char cvttype; - if(!pdbentry->message) pdbentry->message = dbCalloc(1,50); - message = pdbentry->message; - cvttype = pflddes->base; - switch (pflddes->field_type) { - case DBF_CHAR: - if(cvttype==CT_DECIMAL) - cvtCharToString(*(char*)pfield, message); - else - ulongToHexString((epicsUInt32)(*(char*)pfield),message); - break; - case DBF_UCHAR: - if(cvttype==CT_DECIMAL) - cvtUcharToString(*(unsigned char*)pfield, message); - else - ulongToHexString((epicsUInt32)(*(unsigned char*)pfield),message); - break; - case DBF_SHORT: - if(cvttype==CT_DECIMAL) - cvtShortToString(*(short*)pfield, message); - else - ulongToHexString((epicsUInt32)(*(short*)pfield),message); - break; - case DBF_USHORT: - case DBF_ENUM: - if(cvttype==CT_DECIMAL) - cvtUshortToString(*(unsigned short*)pfield, message); - else - ulongToHexString((epicsUInt32)(*(unsigned short*)pfield),message); - break; - case DBF_LONG: - if(cvttype==CT_DECIMAL) - cvtLongToString(*(epicsInt32*)pfield, message); - else - ulongToHexString((epicsUInt32)(*(epicsInt32*)pfield), message); - break; - case DBF_ULONG: - if(cvttype==CT_DECIMAL) - cvtUlongToString(*(epicsUInt32 *)pfield, message); - else - ulongToHexString(*(epicsUInt32*)pfield, message); - break; - case DBF_FLOAT: - floatToString(*(float *)pfield,message); - break; - case DBF_DOUBLE: - doubleToString(*(double *)pfield,message); - break; - case DBF_MENU: { - dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt; - short choice_ind; - char *pchoice; - - if(!pfield) {strcpy(message,"Field not found"); return(message);} - choice_ind = *((short *) pdbentry->pfield); - if(!pdbMenu || choice_ind<0 || choice_ind>=pdbMenu->nChoice) - return(NULL); - pchoice = pdbMenu->papChoiceValue[choice_ind]; - strcpy(message, pchoice); - } - break; - case DBF_DEVICE: { - dbDeviceMenu *pdbDeviceMenu; - char *pchoice; - short choice_ind; - - if(!pfield) {strcpy(message,"Field not found"); return(message);} - pdbDeviceMenu = dbGetDeviceMenu(pdbentry); - if(!pdbDeviceMenu) return(NULL); - choice_ind = *((short *) pdbentry->pfield); - if(choice_ind<0 || choice_ind>=pdbDeviceMenu->nChoice) - return(NULL); - pchoice = pdbDeviceMenu->papChoice[choice_ind]; - strcpy(message, pchoice); - } - break; - default: - return(NULL); - } - return (message); -} - long dbPutStringNum(DBENTRY *pdbentry,const char *pstring) { dbFldDes *pflddes = pdbentry->pflddes; diff --git a/src/std/rec/test/asTest.c b/src/std/rec/test/asTest.c index 412e9ca33..44ef66fd2 100644 --- a/src/std/rec/test/asTest.c +++ b/src/std/rec/test/asTest.c @@ -42,7 +42,7 @@ epicsShareFunc void testRestore(void); MAIN(asTest) { - testPlan(29); + testPlan(42); testRestore(); return testDone(); } diff --git a/src/std/rec/test/asTest.db b/src/std/rec/test/asTest.db index a50d1998b..6a4eea4bd 100644 --- a/src/std/rec/test/asTest.db +++ b/src/std/rec/test/asTest.db @@ -1,4 +1,5 @@ record(ao, "rec0") { + field(DESC, "foobar") field(DTYP, "asTest") field(VAL, "1") field(OUT, "rec0.DISV") diff --git a/src/std/rec/test/asTestLib.c b/src/std/rec/test/asTestLib.c index 17a1ac702..2eca72775 100644 --- a/src/std/rec/test/asTestLib.c +++ b/src/std/rec/test/asTestLib.c @@ -39,6 +39,17 @@ static unsigned iran; +static +int checkGetString(DBENTRY *pent, const char *expect) +{ + dbCommon *prec = pent->precnode->precord; + const char *actual = dbGetString(pent); + int ret = strcmp(actual, expect); + testOk(ret==0, "dbGetString(\"%s.%s\") -> '%s' == '%s'", prec->name, + pent->pflddes->name, actual, expect); + return ret; +} + static void hookPass0(initHookState state) { DBENTRY entry; @@ -48,17 +59,46 @@ static void hookPass0(initHookState state) dbInitEntry(pdbbase, &entry); + testDiag("restore integer pass0"); /* rec0.VAL is initially 1, set it to 2 */ if(dbFindRecord(&entry, "rec0.VAL")==0) { aoRecord *prec = entry.precnode->precord; testOk(prec->val==1, "VAL %d==1 (initial value from .db)", (int)prec->val); + checkGetString(&entry, "1"); testOk1(dbPutString(&entry, "2")==0); testOk(prec->val==2, "VAL %d==2", (int)prec->val); + checkGetString(&entry, "2"); } else { testFail("Missing rec0"); - testSkip(1, "missing record"); + testSkip(4, "missing record"); } + testDiag("restore string pass0"); + if(dbFindRecord(&entry, "rec0.DESC")==0) { + aoRecord *prec = entry.precnode->precord; + testOk1(strcmp(prec->desc, "foobar")==0); + checkGetString(&entry, "foobar"); + testOk1(dbPutString(&entry, "hello")==0); + testOk1(strcmp(prec->desc, "hello")==0); + checkGetString(&entry, "hello"); + } else { + testFail("Missing rec0"); + testSkip(4, "missing record"); + } + + if(dbFindRecord(&entry, "rec1.DESC")==0) { + aoRecord *prec = entry.precnode->precord; + testOk1(strcmp(prec->desc, "")==0); + checkGetString(&entry, ""); + testOk1(dbPutString(&entry, "world")==0); + testOk1(strcmp(prec->desc, "world")==0); + checkGetString(&entry, "world"); + } else { + testFail("Missing rec1"); + testSkip(4, "missing record"); + } + + testDiag("restore link pass0"); /* rec0.OUT is initially "rec0.DISV", set it to "rec0.SEVR" */ if(dbFindRecord(&entry, "rec0.OUT")==0) { aoRecord *prec = entry.precnode->precord; @@ -69,6 +109,12 @@ static void hookPass0(initHookState state) else testFail("Wrong link type: %d", (int)prec->out.type); + /* note that dbGetString() reads an empty string before links are initialized + * should probably be considered a bug, but has been the case for so long + * we call it a 'feature'. + */ + checkGetString(&entry, ""); + testOk1(dbPutString(&entry, "rec0.SEVR")==0); } else{ testFail("Missing rec0"); @@ -213,10 +259,10 @@ void testRestore(void) testIocShutdownOk(); - testdbCleanup(); - /* recSup doesn't cleanup after itself */ free(rec1->bptr); + + testdbCleanup(); } struct dset6 {