Merge lp:~epics-core/epics-base/dbentrybuf into lp:~epics-core/epics-base/3.16
- dbentrybuf
- Merge into 3.16
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrew Johnson | Approve | ||
mdavidsaver | Approve | ||
Review via email: mp+281162@code.launchpad.net |
Commit message
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.
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.
- 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
mdavidsaver (mdavidsaver) wrote : | # |
Added coverage for dbGetString(), and found other usage of DBENTRY::message in dbStaticRun.c.
mdavidsaver (mdavidsaver) wrote : | # |
... now fixed
mdavidsaver (mdavidsaver) wrote : | # |
forgot to approve
- 12703. By Andrew Johnson
-
Fixed some issues with indentation
- 12704. By Andrew Johnson
-
More indentation and other trivial cleanup
Preview Diff
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 { |
The DBF_*LINK parts of this change is covered by dbPutLinkTest (unintentionally verified). No coverage for DBF_STRING though (intentionally verified).