Merge lp:~epics-core/epics-base/dbentrybuf into lp:~epics-core/epics-base/3.16

Proposed by mdavidsaver
Status: Merged
Approved by: Andrew Johnson
Approved revision: 12704
Merged at revision: 12703
Proposed branch: lp:~epics-core/epics-base/dbentrybuf
Merge into: lp:~epics-core/epics-base/3.16
Diff against target: 948 lines (+430/-361)
5 files modified
src/ioc/dbStatic/dbStaticLib.c (+374/-134)
src/ioc/dbStatic/dbStaticRun.c (+1/-219)
src/std/rec/test/asTest.c (+1/-1)
src/std/rec/test/asTest.db (+1/-0)
src/std/rec/test/asTestLib.c (+53/-7)
To merge this branch: bzr merge lp:~epics-core/epics-base/dbentrybuf
Reviewer Review Type Date Requested Status
Andrew Johnson Approve
mdavidsaver Approve
Review via email: mp+281162@code.launchpad.net

Description of the change

Changed to dbGetString() in dbStaticLib.c intended to resolve lp:1462214 for the 3.16 branch.

Introduce local functions dbMsgCpy() and dbMsgPrint() to deal with DBENTRY::message without overflowing.

To post a comment you must log in.
Revision history for this message
mdavidsaver (mdavidsaver) wrote :

The DBF_*LINK parts of this change is covered by dbPutLinkTest (unintentionally verified). No coverage for DBF_STRING though (intentionally verified).

review: Needs Fixing
Revision history for this message
Andrew Johnson (anj) wrote :

On new line 1817 the msstring index should use the local pvlMask variable and not look up the value from the plink structure again.

I suspect you may have been editing this with a tab-width of 4 because your indents don't always seem to line up. I have been replacing tabs with spaces in recent years; the original EPICS sources used a tab-width of 8 for most files, although Jeff sometimes used a tab-width of 4. I have my editor configured so I can tell the difference between spaces and tabs which I find very helpful for understanding the indentation history of files.

With those minor fixes this looks good to me.

lp:~epics-core/epics-base/dbentrybuf updated
12701. By mdavidsaver

Move dbGetStringNum() to dbStaticLib.c

use getpMessage() and keep it private

12702. By mdavidsaver

update asTest

test dbGetString()
and fix cleanup order

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

Added coverage for dbGetString(), and found other usage of DBENTRY::message in dbStaticRun.c.

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

... now fixed

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

forgot to approve

review: Approve
lp:~epics-core/epics-base/dbentrybuf updated
12703. By Andrew Johnson

Fixed some issues with indentation

12704. By Andrew Johnson

More indentation and other trivial cleanup

Revision history for this message
Andrew Johnson (anj) wrote :

Merging.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/ioc/dbStatic/dbStaticLib.c'
2--- src/ioc/dbStatic/dbStaticLib.c 2015-08-20 16:24:07 +0000
3+++ src/ioc/dbStatic/dbStaticLib.c 2016-02-10 20:04:08 +0000
4@@ -52,8 +52,11 @@
5 #define messagesize 276
6 #define RPCL_LEN INFIX_TO_POSTFIX_SIZE(80)
7
8-static char *ppstring[5]={"NPP","PP","CA","CP","CPP"};
9-static char *msstring[4]={"NMS","MS","MSI","MSS"};
10+/* must be long enough to hold 32-bit signed integer in base 10 */
11+STATIC_ASSERT(messagesize>=11);
12+
13+static char *ppstring[5]={" NPP"," PP"," CA"," CP"," CPP"};
14+static char *msstring[4]={" NMS"," MS"," MSI"," MSS"};
15
16 epicsShareDef maplinkType pamaplinkType[LINK_NTYPES] = {
17 {"CONSTANT",CONSTANT},
18@@ -83,13 +86,9 @@
19 DCT_INLINK,DCT_OUTLINK,DCT_FWDLINK,
20 DCT_NOACCESS};
21
22-
23 /*forward references for private routines*/
24-static FILE *openOutstream(const char *filename);
25-static void finishOutstream(FILE *stream);
26-static void entryErrMessage(DBENTRY *pdbentry,long status,char *mess);
27-static void zeroDbentry(DBENTRY *pdbentry);
28-static char *getpMessage(DBENTRY *pdbentry);
29+static void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...)
30+ EPICS_PRINTF_STYLE(2,3);
31 static long dbAddOnePath (DBBASE *pdbbase, const char *path, unsigned length);
32
33 /* internal routines*/
34@@ -207,10 +206,152 @@
35 msg = dbCalloc(1, messagesize);
36 pdbentry->message = msg;
37 }
38- *msg = 0;
39+ *msg = '\0';
40 return msg;
41 }
42
43+static
44+void dbMsgCpy(DBENTRY *pdbentry, const char *msg)
45+{
46+ getpMessage(pdbentry);
47+ strncpy(pdbentry->message, msg, messagesize-1);
48+ pdbentry->message[messagesize-1] = '\0';
49+}
50+
51+static
52+void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...)
53+{
54+ va_list args;
55+ getpMessage(pdbentry);
56+ va_start(args, fmt);
57+ epicsVsnprintf(pdbentry->message, messagesize, fmt, args);
58+ va_end(args);
59+}
60+
61+static void ulongToHexString(epicsUInt32 source,char *pdest)
62+{
63+ static const char hex_digit_to_ascii[16] = "0123456789abcdef";
64+ epicsUInt32 val,temp;
65+ char digit[10];
66+ int i,j;
67+
68+ if (source==0) {
69+ strcpy(pdest,"0x0");
70+ return;
71+ }
72+ *pdest++ = '0'; *pdest++ = 'x';
73+ val = source;
74+ for (i=0; val!=0; i++) {
75+ temp = val/16;
76+ digit[i] = hex_digit_to_ascii[val - temp*16];
77+ val = temp;
78+ }
79+ for (j=i-1; j>=0; j--) {
80+ *pdest++ = digit[j];
81+ }
82+ *pdest = 0;
83+ return;
84+}
85+
86+static void realToString(double value, char *preturn, int isdouble)
87+{
88+ static const double delta[2] = {1e-6, 1e-15};
89+ static const int precision[2] = {6, 14};
90+ double absvalue;
91+ int logval,prec;
92+ size_t end;
93+ char tstr[30];
94+ char *ptstr = &tstr[0];
95+ int round;
96+ int ise = FALSE;
97+ char *loce = NULL;
98+
99+ if (value == 0) {
100+ strcpy(preturn, "0");
101+ return;
102+ }
103+
104+ absvalue = value < 0 ? -value : value;
105+ if (absvalue < (double)INT_MAX) {
106+ epicsInt32 intval = (epicsInt32) value;
107+ double diff = value - intval;
108+
109+ if (diff < 0) diff = -diff;
110+ if (diff < absvalue * delta[isdouble]) {
111+ cvtLongToString(intval, preturn);
112+ return;
113+ }
114+ }
115+
116+ /*Now starts the hard cases*/
117+ if (value < 0) {
118+ *preturn++ = '-';
119+ value = -value;
120+ }
121+
122+ logval = (int)log10(value);
123+ if (logval > 6 || logval < -2) {
124+ int nout;
125+
126+ ise = TRUE;
127+ prec = precision[isdouble];
128+ nout = sprintf(ptstr, "%.*e", prec, value);
129+ loce = strchr(ptstr, 'e');
130+
131+ if (!loce) {
132+ ptstr[nout] = 0;
133+ strcpy(preturn, ptstr);
134+ return;
135+ }
136+
137+ *loce++ = 0;
138+ } else {
139+ prec = precision[isdouble] - logval;
140+ if ( prec < 0) prec = 0;
141+ sprintf(ptstr, "%.*f", prec, value);
142+ }
143+
144+ if (prec > 0) {
145+ end = strlen(ptstr) - 1;
146+ round = FALSE;
147+ while (end > 0) {
148+ if (tstr[end] == '.') {end--; break;}
149+ if (tstr[end] == '0') {end--; continue;}
150+ if (!round && end < precision[isdouble]) break;
151+ if (!round && tstr[end] < '8') break;
152+ if (tstr[end-1] == '.') {
153+ if (round) end = end-2;
154+ break;
155+ }
156+ if (tstr[end-1] != '9') break;
157+ round = TRUE;
158+ end--;
159+ }
160+ tstr[end+1] = 0;
161+ while (round) {
162+ if (tstr[end] < '9') {tstr[end]++; break;}
163+ if (end == 0) { *preturn++ = '1'; tstr[end] = '0'; break;}
164+ tstr[end--] = '0';
165+ }
166+ }
167+ strcpy(preturn, &tstr[0]);
168+ if (ise) {
169+ if (!(strchr(preturn, '.'))) strcat(preturn, ".0");
170+ strcat(preturn, "e");
171+ strcat(preturn, loce);
172+ }
173+}
174+
175+static void floatToString(float value, char *preturn)
176+{
177+ realToString((double)value, preturn, 0);
178+}
179+
180+static void doubleToString(double value, char *preturn)
181+{
182+ realToString(value, preturn, 1);
183+}
184+
185 /*Public only for dbStaticNoRun*/
186 dbDeviceMenu *dbGetDeviceMenu(DBENTRY *pdbentry)
187 {
188@@ -1718,16 +1859,30 @@
189 {
190 dbFldDes *pflddes = pdbentry->pflddes;
191 void *pfield = pdbentry->pfield;
192- char *message;
193 DBLINK *plink;
194
195- message = getpMessage(pdbentry);
196- if(!pflddes) {strcpy(message,"fldDes not found"); return(message);}
197- switch (pflddes->field_type) {
198- case DBF_STRING:
199- if(!pfield) {strcpy(message,"Field not found"); return(message);}
200- strcpy(message, (char *)pfield);
201- break;
202+ if (!pflddes) {
203+ dbMsgCpy(pdbentry, "fldDes not found");
204+ return pdbentry->message;
205+ }
206+ switch (pflddes->field_type) {
207+ case DBF_STRING:
208+ case DBF_INLINK:
209+ case DBF_OUTLINK:
210+ case DBF_FWDLINK:
211+ if (!pfield) {
212+ dbMsgCpy(pdbentry, "Field not allocated (NULL)");
213+ return pdbentry->message;
214+ }
215+ break;
216+ default:
217+ break;
218+ }
219+
220+ switch (pflddes->field_type) {
221+ case DBF_STRING:
222+ dbMsgCpy(pdbentry, (char *)pfield);
223+ break;
224 case DBF_CHAR:
225 case DBF_UCHAR:
226 case DBF_SHORT:
227@@ -1742,125 +1897,115 @@
228 return(dbGetStringNum(pdbentry));
229 case DBF_INLINK:
230 case DBF_OUTLINK:
231- if(!pfield) {strcpy(message,"Field not found"); return(message);}
232 plink = (DBLINK *)pfield;
233 switch(plink->type) {
234- case CONSTANT:
235- if(plink->value.constantStr) {
236- strcpy(message,plink->value.constantStr);
237- } else {
238- strcpy(message,"");
239- }
240- break;
241- case MACRO_LINK:
242- if(plink->value.macro_link.macroStr) {
243- strcpy(message,plink->value.macro_link.macroStr);
244- } else {
245- strcpy(message,"");
246- }
247- break;
248- case PN_LINK:
249- if(plink->value.pv_link.pvname)
250- strcpy(message,plink->value.pv_link.pvname);
251- else
252- strcpy(message,"");
253- strcat(message," ");
254- strcat(message,msstring[plink->value.pv_link.pvlMask&pvlOptMsMode]);
255- break;
256- case PV_LINK:
257- case CA_LINK:
258- case DB_LINK: {
259- int ppind;
260- short pvlMask;
261+ case CONSTANT:
262+ if (plink->value.constantStr) {
263+ dbMsgCpy(pdbentry, plink->value.constantStr);
264+ } else {
265+ dbMsgCpy(pdbentry, "");
266+ }
267+ break;
268+ case MACRO_LINK:
269+ if (plink->value.macro_link.macroStr) {
270+ dbMsgCpy(pdbentry, plink->value.macro_link.macroStr);
271+ } else {
272+ dbMsgCpy(pdbentry, "");
273+ }
274+ break;
275+ case PN_LINK:
276+ dbMsgPrint(pdbentry, "%s%s",
277+ plink->value.pv_link.pvname ? plink->value.pv_link.pvname : "",
278+ msstring[plink->value.pv_link.pvlMask&pvlOptMsMode]);
279+ break;
280+ case PV_LINK:
281+ case CA_LINK:
282+ case DB_LINK: {
283+ int ppind;
284+ short pvlMask;
285
286- pvlMask = plink->value.pv_link.pvlMask;
287- if(pvlMask&pvlOptPP) ppind=1;
288- else if(pvlMask&pvlOptCA) ppind=2;
289- else if(pvlMask&pvlOptCP) ppind=3;
290- else if(pvlMask&pvlOptCPP) ppind=4;
291- else ppind=0;
292- if (plink->value.pv_link.pvname) {
293- strcpy(message, plink->value.pv_link.pvname);
294- if (pvlMask & pvlOptTSELisTime)
295- strcat(message, ".TIME");
296- } else
297- strcpy(message,"");
298- strcat(message," ");
299- strcat(message,ppstring[ppind]);
300- strcat(message," ");
301- strcat(message,msstring[pvlMask&pvlOptMsMode]);
302- break;
303- }
304- case VME_IO:
305- sprintf(message,"#C%d S%d @%s",
306- plink->value.vmeio.card,plink->value.vmeio.signal,
307- plink->value.vmeio.parm);
308- break;
309- case CAMAC_IO:
310- sprintf(message,"#B%d C%d N%d A%d F%d @%s",
311- plink->value.camacio.b,plink->value.camacio.c,
312- plink->value.camacio.n,plink->value.camacio.a,
313- plink->value.camacio.f,plink->value.camacio.parm);
314- break;
315- case RF_IO:
316- sprintf(message,"#R%d M%d D%d E%d",
317- plink->value.rfio.cryo,
318- plink->value.rfio.micro,
319- plink->value.rfio.dataset,
320- plink->value.rfio.element);
321- break;
322- case AB_IO:
323- sprintf(message,"#L%d A%d C%d S%d @%s",
324- plink->value.abio.link,plink->value.abio.adapter,
325- plink->value.abio.card,plink->value.abio.signal,
326- plink->value.abio.parm);
327- break;
328- case GPIB_IO:
329- sprintf(message,"#L%d A%d @%s",
330- plink->value.gpibio.link,plink->value.gpibio.addr,
331- plink->value.gpibio.parm);
332- break;
333- case BITBUS_IO:
334- sprintf(message,"#L%u N%u P%u S%u @%s",
335- plink->value.bitbusio.link,plink->value.bitbusio.node,
336- plink->value.bitbusio.port,plink->value.bitbusio.signal,
337- plink->value.bitbusio.parm);
338- break;
339- case BBGPIB_IO:
340- sprintf(message,"#L%u B%u G%u @%s",
341- plink->value.bbgpibio.link,plink->value.bbgpibio.bbaddr,
342- plink->value.bbgpibio.gpibaddr,plink->value.bbgpibio.parm);
343- break;
344- case INST_IO:
345- sprintf(message,"@%s", plink->value.instio.string);
346- break;
347- case VXI_IO :
348- if (plink->value.vxiio.flag == VXIDYNAMIC)
349- sprintf(message,"#V%d C%d S%d @%s",
350- plink->value.vxiio.frame,plink->value.vxiio.slot,
351- plink->value.vxiio.signal,plink->value.vxiio.parm);
352- else
353- sprintf(message,"#V%d S%d @%s",
354- plink->value.vxiio.la,plink->value.vxiio.signal,
355- plink->value.vxiio.parm);
356- break;
357- default :
358- return(NULL);
359+ pvlMask = plink->value.pv_link.pvlMask;
360+ if (pvlMask&pvlOptPP) ppind=1;
361+ else if(pvlMask&pvlOptCA) ppind=2;
362+ else if(pvlMask&pvlOptCP) ppind=3;
363+ else if(pvlMask&pvlOptCPP) ppind=4;
364+ else ppind=0;
365+ dbMsgPrint(pdbentry, "%s%s%s%s",
366+ plink->value.pv_link.pvname ? plink->value.pv_link.pvname : "",
367+ (pvlMask & pvlOptTSELisTime) ? ".TIME" : "",
368+ ppstring[ppind],
369+ msstring[plink->value.pv_link.pvlMask&pvlOptMsMode]);
370+ break;
371+ }
372+ case VME_IO:
373+ dbMsgPrint(pdbentry, "#C%d S%d @%s",
374+ plink->value.vmeio.card,plink->value.vmeio.signal,
375+ plink->value.vmeio.parm);
376+ break;
377+ case CAMAC_IO:
378+ dbMsgPrint(pdbentry, "#B%d C%d N%d A%d F%d @%s",
379+ plink->value.camacio.b,plink->value.camacio.c,
380+ plink->value.camacio.n,plink->value.camacio.a,
381+ plink->value.camacio.f,plink->value.camacio.parm);
382+ break;
383+ case RF_IO:
384+ dbMsgPrint(pdbentry, "#R%d M%d D%d E%d",
385+ plink->value.rfio.cryo,
386+ plink->value.rfio.micro,
387+ plink->value.rfio.dataset,
388+ plink->value.rfio.element);
389+ break;
390+ case AB_IO:
391+ dbMsgPrint(pdbentry, "#L%d A%d C%d S%d @%s",
392+ plink->value.abio.link,plink->value.abio.adapter,
393+ plink->value.abio.card,plink->value.abio.signal,
394+ plink->value.abio.parm);
395+ break;
396+ case GPIB_IO:
397+ dbMsgPrint(pdbentry, "#L%d A%d @%s",
398+ plink->value.gpibio.link,plink->value.gpibio.addr,
399+ plink->value.gpibio.parm);
400+ break;
401+ case BITBUS_IO:
402+ dbMsgPrint(pdbentry, "#L%u N%u P%u S%u @%s",
403+ plink->value.bitbusio.link,plink->value.bitbusio.node,
404+ plink->value.bitbusio.port,plink->value.bitbusio.signal,
405+ plink->value.bitbusio.parm);
406+ break;
407+ case BBGPIB_IO:
408+ dbMsgPrint(pdbentry, "#L%u B%u G%u @%s",
409+ plink->value.bbgpibio.link,plink->value.bbgpibio.bbaddr,
410+ plink->value.bbgpibio.gpibaddr,plink->value.bbgpibio.parm);
411+ break;
412+ case INST_IO:
413+ dbMsgPrint(pdbentry, "@%s", plink->value.instio.string);
414+ break;
415+ case VXI_IO :
416+ if (plink->value.vxiio.flag == VXIDYNAMIC)
417+ dbMsgPrint(pdbentry, "#V%d C%d S%d @%s",
418+ plink->value.vxiio.frame,plink->value.vxiio.slot,
419+ plink->value.vxiio.signal,plink->value.vxiio.parm);
420+ else
421+ dbMsgPrint(pdbentry, "#V%d S%d @%s",
422+ plink->value.vxiio.la,plink->value.vxiio.signal,
423+ plink->value.vxiio.parm);
424+ break;
425+ default :
426+ return(NULL);
427 }
428 break;
429 case DBF_FWDLINK: {
430 DBLINK *plink=(DBLINK *)pfield;
431
432- if(!pfield) {strcpy(message,"Field not found"); return(message);}
433 switch(plink->type) {
434 case CONSTANT:
435- strcpy(message,"0");
436+ dbMsgCpy(pdbentry, "0");
437 break;
438 case MACRO_LINK:
439- if(plink->value.macro_link.macroStr) {
440- strcpy(message,plink->value.macro_link.macroStr);
441+ if (plink->value.macro_link.macroStr) {
442+ dbMsgCpy(pdbentry, plink->value.macro_link.macroStr);
443 } else {
444- strcpy(message,"");
445+ dbMsgCpy(pdbentry, "");
446 }
447 break;
448 case PV_LINK:
449@@ -1870,16 +2015,11 @@
450 short pvlMask;
451
452 pvlMask = plink->value.pv_link.pvlMask;
453- if(pvlMask&pvlOptCA) ppind=2;
454+ if (pvlMask&pvlOptCA) ppind=2;
455 else ppind=0;
456- if(plink->value.pv_link.pvname)
457- strcpy(message,plink->value.pv_link.pvname);
458- else
459- strcpy(message,"");
460- if(ppind) {
461- strcat(message," ");
462- strcat(message,ppstring[ppind]);
463- }
464+ dbMsgPrint(pdbentry, "%s%s",
465+ plink->value.pv_link.pvname ? plink->value.pv_link.pvname : "",
466+ ppind ? ppstring[ppind] : "");
467 break;
468 }
469 default :
470@@ -1890,7 +2030,106 @@
471 default:
472 return(NULL);
473 }
474- return (message);
475+ return pdbentry->message;
476+}
477+
478+char *dbGetStringNum(DBENTRY *pdbentry)
479+{
480+ dbFldDes *pflddes = pdbentry->pflddes;
481+ void *pfield = pdbentry->pfield;
482+ char *message;
483+ unsigned char cvttype;
484+
485+ /* the following assumes that messagesize is large enough
486+ * to hold the base 10 encoded value of a 32-bit integer.
487+ */
488+ message = getpMessage(pdbentry);
489+ cvttype = pflddes->base;
490+ switch (pflddes->field_type) {
491+ case DBF_CHAR:
492+ if (cvttype==CT_DECIMAL)
493+ cvtCharToString(*(char*)pfield, message);
494+ else
495+ ulongToHexString((epicsUInt32)(*(char*)pfield),message);
496+ break;
497+ case DBF_UCHAR:
498+ if (cvttype==CT_DECIMAL)
499+ cvtUcharToString(*(unsigned char*)pfield, message);
500+ else
501+ ulongToHexString((epicsUInt32)(*(unsigned char*)pfield),message);
502+ break;
503+ case DBF_SHORT:
504+ if (cvttype==CT_DECIMAL)
505+ cvtShortToString(*(short*)pfield, message);
506+ else
507+ ulongToHexString((epicsUInt32)(*(short*)pfield),message);
508+ break;
509+ case DBF_USHORT:
510+ case DBF_ENUM:
511+ if (cvttype==CT_DECIMAL)
512+ cvtUshortToString(*(unsigned short*)pfield, message);
513+ else
514+ ulongToHexString((epicsUInt32)(*(unsigned short*)pfield),message);
515+ break;
516+ case DBF_LONG:
517+ if (cvttype==CT_DECIMAL)
518+ cvtLongToString(*(epicsInt32*)pfield, message);
519+ else
520+ ulongToHexString((epicsUInt32)(*(epicsInt32*)pfield), message);
521+ break;
522+ case DBF_ULONG:
523+ if (cvttype==CT_DECIMAL)
524+ cvtUlongToString(*(epicsUInt32 *)pfield, message);
525+ else
526+ ulongToHexString(*(epicsUInt32*)pfield, message);
527+ break;
528+ case DBF_FLOAT:
529+ floatToString(*(float *)pfield,message);
530+ break;
531+ case DBF_DOUBLE:
532+ doubleToString(*(double *)pfield,message);
533+ break;
534+ case DBF_MENU:
535+ {
536+ dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt;
537+ short choice_ind;
538+ char *pchoice;
539+
540+ if (!pfield) {
541+ dbMsgCpy(pdbentry, "Field not found");
542+ return message;
543+ }
544+ choice_ind = *((short *) pdbentry->pfield);
545+ if (!pdbMenu || choice_ind<0 || choice_ind>=pdbMenu->nChoice)
546+ return NULL;
547+ pchoice = pdbMenu->papChoiceValue[choice_ind];
548+ dbMsgCpy(pdbentry, pchoice);
549+ }
550+ break;
551+ case DBF_DEVICE:
552+ {
553+ dbDeviceMenu *pdbDeviceMenu;
554+ char *pchoice;
555+ short choice_ind;
556+
557+ if (!pfield) {
558+ dbMsgCpy(pdbentry, "Field not found");
559+ return message;
560+ }
561+ pdbDeviceMenu = dbGetDeviceMenu(pdbentry);
562+ if (!pdbDeviceMenu)
563+ return NULL;
564+ choice_ind = *((short *) pdbentry->pfield);
565+ if (choice_ind<0 || choice_ind>=pdbDeviceMenu->nChoice)
566+ return NULL;
567+ pchoice = pdbDeviceMenu->papChoice[choice_ind];
568+ dbMsgCpy(pdbentry, pchoice);
569+ }
570+ break;
571+ default:
572+ return NULL;
573+ }
574+ return message;
575 }
576
577 long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
578@@ -3265,7 +3504,8 @@
579 plink = pdbentry->pfield;
580 linkType = plink->type;
581 if(bus[linkType][0]==0) continue;
582- strcpy(linkValue,dbGetString(pdbentry));
583+ strncpy(linkValue, dbGetString(pdbentry), NELEMENTS(linkValue)-1);
584+ linkValue[NELEMENTS(linkValue)-1] = '\0';
585 status = dbFindField(pdbentry,"DTYP");
586 if(status) break;
587 strcpy(dtypValue,dbGetString(pdbentry));
588
589=== modified file 'src/ioc/dbStatic/dbStaticRun.c'
590--- src/ioc/dbStatic/dbStaticRun.c 2015-09-10 14:56:50 +0000
591+++ src/ioc/dbStatic/dbStaticRun.c 2016-02-10 20:04:08 +0000
592@@ -31,136 +31,6 @@
593 #include "devSup.h"
594 #include "special.h"
595
596-
597
598-static char hex_digit_to_ascii[16]={'0','1','2','3','4','5','6','7','8','9',
599- 'a','b','c','d','e','f'};
600-
601-static void ulongToHexString(epicsUInt32 source,char *pdest)
602-{
603- epicsUInt32 val,temp;
604- char digit[10];
605- int i,j;
606-
607- if(source==0) {
608- strcpy(pdest,"0x0");
609- return;
610- }
611- *pdest++ = '0'; *pdest++ = 'x';
612- val = source;
613- for(i=0; val!=0; i++) {
614- temp = val/16;
615- digit[i] = hex_digit_to_ascii[val - temp*16];
616- val = temp;
617- }
618- for(j=i-1; j>=0; j--) {
619- *pdest++ = digit[j];
620- }
621- *pdest = 0;
622- return;
623-}
624-
625
626-static double delta[2] = {1e-6, 1e-15};
627-static int precision[2] = {6, 14};
628-static void realToString(double value, char *preturn, int isdouble)
629-{
630- double absvalue;
631- int logval,prec;
632- size_t end;
633- char tstr[30];
634- char *ptstr = &tstr[0];
635- int round;
636- int ise = FALSE;
637- char *loce = NULL;
638-
639- if (value == 0) {
640- strcpy(preturn, "0");
641- return;
642- }
643-
644- absvalue = value < 0 ? -value : value;
645- if (absvalue < (double)INT_MAX) {
646- epicsInt32 intval = (epicsInt32) value;
647- double diff = value - intval;
648-
649- if (diff < 0) diff = -diff;
650- if (diff < absvalue * delta[isdouble]) {
651- cvtLongToString(intval, preturn);
652- return;
653- }
654- }
655-
656- /*Now starts the hard cases*/
657- if (value < 0) {
658- *preturn++ = '-';
659- value = -value;
660- }
661-
662- logval = (int)log10(value);
663- if (logval > 6 || logval < -2) {
664- int nout;
665-
666- ise = TRUE;
667- prec = precision[isdouble];
668- nout = sprintf(ptstr, "%.*e", prec, value);
669- loce = strchr(ptstr, 'e');
670-
671- if (!loce) {
672- ptstr[nout] = 0;
673- strcpy(preturn, ptstr);
674- return;
675- }
676-
677- *loce++ = 0;
678- } else {
679- prec = precision[isdouble] - logval;
680- if ( prec < 0) prec = 0;
681- sprintf(ptstr, "%.*f", prec, value);
682- }
683-
684- if (prec > 0) {
685- end = strlen(ptstr) - 1;
686- round = FALSE;
687- while (end > 0) {
688- if (tstr[end] == '.') {end--; break;}
689- if (tstr[end] == '0') {end--; continue;}
690- if (!round && end < precision[isdouble]) break;
691- if (!round && tstr[end] < '8') break;
692- if (tstr[end-1] == '.') {
693- if (round) end = end-2;
694- break;
695- }
696- if (tstr[end-1] != '9') break;
697- round = TRUE;
698- end--;
699- }
700- tstr[end+1] = 0;
701- while (round) {
702- if (tstr[end] < '9') {tstr[end]++; break;}
703- if (end == 0) { *preturn++ = '1'; tstr[end] = '0'; break;}
704- tstr[end--] = '0';
705- }
706- }
707- strcpy(preturn, &tstr[0]);
708- if (ise) {
709- if (!(strchr(preturn, '.'))) strcat(preturn, ".0");
710- strcat(preturn, "e");
711- strcat(preturn, loce);
712- }
713-}
714-
715-static void floatToString(float value,char *preturn)
716-{
717- realToString((double)value,preturn,0);
718- return;
719-}
720-
721-static void doubleToString(double value,char *preturn)
722-{
723- realToString(value,preturn,1);
724- return;
725-}
726-
727-
728
729 static long do_nothing(struct dbCommon *precord) { return 0; }
730
731 /* Dummy DSXT used for soft device supports */
732@@ -480,95 +350,7 @@
733 }
734 return(FALSE);
735 }
736-
737
738-char *dbGetStringNum(DBENTRY *pdbentry)
739-{
740- dbFldDes *pflddes = pdbentry->pflddes;
741- void *pfield = pdbentry->pfield;
742- char *message;
743- unsigned char cvttype;
744-
745- if(!pdbentry->message) pdbentry->message = dbCalloc(1,50);
746- message = pdbentry->message;
747- cvttype = pflddes->base;
748- switch (pflddes->field_type) {
749- case DBF_CHAR:
750- if(cvttype==CT_DECIMAL)
751- cvtCharToString(*(char*)pfield, message);
752- else
753- ulongToHexString((epicsUInt32)(*(char*)pfield),message);
754- break;
755- case DBF_UCHAR:
756- if(cvttype==CT_DECIMAL)
757- cvtUcharToString(*(unsigned char*)pfield, message);
758- else
759- ulongToHexString((epicsUInt32)(*(unsigned char*)pfield),message);
760- break;
761- case DBF_SHORT:
762- if(cvttype==CT_DECIMAL)
763- cvtShortToString(*(short*)pfield, message);
764- else
765- ulongToHexString((epicsUInt32)(*(short*)pfield),message);
766- break;
767- case DBF_USHORT:
768- case DBF_ENUM:
769- if(cvttype==CT_DECIMAL)
770- cvtUshortToString(*(unsigned short*)pfield, message);
771- else
772- ulongToHexString((epicsUInt32)(*(unsigned short*)pfield),message);
773- break;
774- case DBF_LONG:
775- if(cvttype==CT_DECIMAL)
776- cvtLongToString(*(epicsInt32*)pfield, message);
777- else
778- ulongToHexString((epicsUInt32)(*(epicsInt32*)pfield), message);
779- break;
780- case DBF_ULONG:
781- if(cvttype==CT_DECIMAL)
782- cvtUlongToString(*(epicsUInt32 *)pfield, message);
783- else
784- ulongToHexString(*(epicsUInt32*)pfield, message);
785- break;
786- case DBF_FLOAT:
787- floatToString(*(float *)pfield,message);
788- break;
789- case DBF_DOUBLE:
790- doubleToString(*(double *)pfield,message);
791- break;
792- case DBF_MENU: {
793- dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt;
794- short choice_ind;
795- char *pchoice;
796-
797- if(!pfield) {strcpy(message,"Field not found"); return(message);}
798- choice_ind = *((short *) pdbentry->pfield);
799- if(!pdbMenu || choice_ind<0 || choice_ind>=pdbMenu->nChoice)
800- return(NULL);
801- pchoice = pdbMenu->papChoiceValue[choice_ind];
802- strcpy(message, pchoice);
803- }
804- break;
805- case DBF_DEVICE: {
806- dbDeviceMenu *pdbDeviceMenu;
807- char *pchoice;
808- short choice_ind;
809-
810- if(!pfield) {strcpy(message,"Field not found"); return(message);}
811- pdbDeviceMenu = dbGetDeviceMenu(pdbentry);
812- if(!pdbDeviceMenu) return(NULL);
813- choice_ind = *((short *) pdbentry->pfield);
814- if(choice_ind<0 || choice_ind>=pdbDeviceMenu->nChoice)
815- return(NULL);
816- pchoice = pdbDeviceMenu->papChoice[choice_ind];
817- strcpy(message, pchoice);
818- }
819- break;
820- default:
821- return(NULL);
822- }
823- return (message);
824-}
825-
826
827+
828 long dbPutStringNum(DBENTRY *pdbentry,const char *pstring)
829 {
830 dbFldDes *pflddes = pdbentry->pflddes;
831
832=== modified file 'src/std/rec/test/asTest.c'
833--- src/std/rec/test/asTest.c 2015-09-07 19:06:02 +0000
834+++ src/std/rec/test/asTest.c 2016-02-10 20:04:08 +0000
835@@ -42,7 +42,7 @@
836
837 MAIN(asTest)
838 {
839- testPlan(29);
840+ testPlan(42);
841 testRestore();
842 return testDone();
843 }
844
845=== modified file 'src/std/rec/test/asTest.db'
846--- src/std/rec/test/asTest.db 2015-03-16 22:47:58 +0000
847+++ src/std/rec/test/asTest.db 2016-02-10 20:04:08 +0000
848@@ -1,4 +1,5 @@
849 record(ao, "rec0") {
850+ field(DESC, "foobar")
851 field(DTYP, "asTest")
852 field(VAL, "1")
853 field(OUT, "rec0.DISV")
854
855=== modified file 'src/std/rec/test/asTestLib.c'
856--- src/std/rec/test/asTestLib.c 2015-09-07 19:37:46 +0000
857+++ src/std/rec/test/asTestLib.c 2016-02-10 20:04:08 +0000
858@@ -39,6 +39,17 @@
859
860 static unsigned iran;
861
862+static
863+int checkGetString(DBENTRY *pent, const char *expect)
864+{
865+ dbCommon *prec = pent->precnode->precord;
866+ const char *actual = dbGetString(pent);
867+ int ret = strcmp(actual, expect);
868+ testOk(ret==0, "dbGetString(\"%s.%s\") -> '%s' == '%s'", prec->name,
869+ pent->pflddes->name, actual, expect);
870+ return ret;
871+}
872+
873 static void hookPass0(initHookState state)
874 {
875 DBENTRY entry;
876@@ -48,17 +59,46 @@
877
878 dbInitEntry(pdbbase, &entry);
879
880+ testDiag("restore integer pass0");
881 /* rec0.VAL is initially 1, set it to 2 */
882 if(dbFindRecord(&entry, "rec0.VAL")==0) {
883 aoRecord *prec = entry.precnode->precord;
884 testOk(prec->val==1, "VAL %d==1 (initial value from .db)", (int)prec->val);
885+ checkGetString(&entry, "1");
886 testOk1(dbPutString(&entry, "2")==0);
887 testOk(prec->val==2, "VAL %d==2", (int)prec->val);
888- } else {
889- testFail("Missing rec0");
890- testSkip(1, "missing record");
891- }
892-
893+ checkGetString(&entry, "2");
894+ } else {
895+ testFail("Missing rec0");
896+ testSkip(4, "missing record");
897+ }
898+
899+ testDiag("restore string pass0");
900+ if(dbFindRecord(&entry, "rec0.DESC")==0) {
901+ aoRecord *prec = entry.precnode->precord;
902+ testOk1(strcmp(prec->desc, "foobar")==0);
903+ checkGetString(&entry, "foobar");
904+ testOk1(dbPutString(&entry, "hello")==0);
905+ testOk1(strcmp(prec->desc, "hello")==0);
906+ checkGetString(&entry, "hello");
907+ } else {
908+ testFail("Missing rec0");
909+ testSkip(4, "missing record");
910+ }
911+
912+ if(dbFindRecord(&entry, "rec1.DESC")==0) {
913+ aoRecord *prec = entry.precnode->precord;
914+ testOk1(strcmp(prec->desc, "")==0);
915+ checkGetString(&entry, "");
916+ testOk1(dbPutString(&entry, "world")==0);
917+ testOk1(strcmp(prec->desc, "world")==0);
918+ checkGetString(&entry, "world");
919+ } else {
920+ testFail("Missing rec1");
921+ testSkip(4, "missing record");
922+ }
923+
924+ testDiag("restore link pass0");
925 /* rec0.OUT is initially "rec0.DISV", set it to "rec0.SEVR" */
926 if(dbFindRecord(&entry, "rec0.OUT")==0) {
927 aoRecord *prec = entry.precnode->precord;
928@@ -69,6 +109,12 @@
929 else
930 testFail("Wrong link type: %d", (int)prec->out.type);
931
932+ /* note that dbGetString() reads an empty string before links are initialized
933+ * should probably be considered a bug, but has been the case for so long
934+ * we call it a 'feature'.
935+ */
936+ checkGetString(&entry, "");
937+
938 testOk1(dbPutString(&entry, "rec0.SEVR")==0);
939 } else{
940 testFail("Missing rec0");
941@@ -213,10 +259,10 @@
942
943 testIocShutdownOk();
944
945- testdbCleanup();
946-
947 /* recSup doesn't cleanup after itself */
948 free(rec1->bptr);
949+
950+ testdbCleanup();
951 }
952
953 struct dset6 {

Subscribers

People subscribed via source and target branches