This is Unofficial EPICS BASE Doxygen Site
lnkConst.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
3 * National Laboratory.
4 * EPICS BASE is distributed subject to a Software License Agreement found
5 * in file LICENSE that is included with this distribution.
6 \*************************************************************************/
7 /* lnkConst.c */
8 
9 #include <string.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 
13 #include "dbDefs.h"
14 #include "errlog.h"
15 #include "epicsAssert.h"
16 #include "epicsString.h"
17 #include "epicsTypes.h"
18 #include "dbAccessDefs.h"
19 #include "dbConvertFast.h"
20 #include "dbLink.h"
21 #include "dbJLink.h"
22 #include "epicsExport.h"
23 
24 
25 typedef long (*FASTCONVERT)();
26 
27 typedef struct const_link {
28  jlink jlink; /* embedded object */
29  int nElems;
30  enum {s0, si64, sf64, sc40, a0, ai64, af64, ac40} type;
31  union {
34  char *scalar_string; /* sc40 */
35  void *pmem;
36  epicsInt64 *pintegers; /* ai64 */
37  epicsFloat64 *pdoubles; /* af64 */
38  char **pstrings; /* ac40 */
39  } value;
40 } const_link;
41 
42 static lset lnkConst_lset;
43 
44 
45 /*************************** jlif Routines **************************/
46 
47 static jlink* lnkConst_alloc(short dbfType)
48 {
49  const_link *clink;
50 
51  if (dbfType != DBF_INLINK) {
52  errlogPrintf("lnkConst: Only works with input links\n");
53  return NULL;
54  }
55 
56  clink = calloc(1, sizeof(*clink));
57  if (!clink) {
58  errlogPrintf("lnkConst: calloc() failed.\n");
59  return NULL;
60  }
61 
62  clink->type = s0;
63  clink->nElems = 0;
64  clink->value.pmem = NULL;
65 
66  return &clink->jlink;
67 }
68 
69 static void lnkConst_free(jlink *pjlink)
70 {
71  const_link *clink = CONTAINER(pjlink, const_link, jlink);
72 
73  switch (clink->type) {
74  int i;
75  case ac40:
76  for (i=0; i<clink->nElems; i++)
77  free(clink->value.pstrings[i]);
78  /* fall through */
79  case sc40:
80  case ai64:
81  case af64:
82  free(clink->value.pmem);
83  break;
84  case s0:
85  case a0:
86  case si64:
87  case sf64:
88  break;
89  }
90  free(clink);
91 }
92 
93 static jlif_result lnkConst_integer(jlink *pjlink, long long num)
94 {
95  const_link *clink = CONTAINER(pjlink, const_link, jlink);
96  int newElems = clink->nElems + 1;
97 
98  switch (clink->type) {
99  void *buf;
100 
101  case s0:
102  clink->type = si64;
103  clink->value.scalar_integer = num;
104  if (pjlink->debug)
105  printf(" si64 := %lld\n", num);
106  break;
107 
108  case a0:
109  clink->type = ai64;
110  /* fall through */
111  case ai64:
112  buf = realloc(clink->value.pmem, newElems * sizeof(epicsInt64));
113  if (!buf)
114  return jlif_stop;
115 
116  clink->value.pmem = buf;
117  clink->value.pintegers[clink->nElems] = num;
118  if (pjlink->debug)
119  printf(" ai64 += %lld\n", num);
120  break;
121 
122  case af64:
123  buf = realloc(clink->value.pmem, newElems * sizeof(epicsFloat64));
124  if (!buf)
125  return jlif_stop;
126 
127  clink->value.pmem = buf;
128  clink->value.pdoubles[clink->nElems] = num;
129  if (pjlink->debug)
130  printf(" af64 += %lld\n", num);
131  break;
132 
133  case ac40:
134  errlogPrintf("lnkConst: Mixed data types in array\n");
135  /* fall through */
136  default:
137  return jlif_stop;
138  }
139 
140  clink->nElems = newElems;
141  return jlif_continue;
142 }
143 
144 static jlif_result lnkConst_boolean(jlink *pjlink, int val)
145 {
146  return lnkConst_integer(pjlink, val);
147 }
148 
149 static jlif_result lnkConst_double(jlink *pjlink, double num)
150 {
151  const_link *clink = CONTAINER(pjlink, const_link, jlink);
152  int newElems = clink->nElems + 1;
153 
154  switch (clink->type) {
155  epicsFloat64 *f64buf;
156  int i;
157 
158  case s0:
159  clink->type = sf64;
160  clink->value.scalar_double = num;
161  break;
162 
163  case a0:
164  clink->type = af64;
165  /* fall through */
166  case af64:
167  f64buf = realloc(clink->value.pmem, newElems * sizeof(epicsFloat64));
168  if (!f64buf)
169  return jlif_stop;
170 
171  f64buf[clink->nElems] = num;
172  clink->value.pdoubles = f64buf;
173  break;
174 
175  case ai64: /* promote earlier ai64 values to af64 */
176  f64buf = calloc(newElems, sizeof(epicsFloat64));
177  if (!f64buf)
178  return jlif_stop;
179 
180  for (i = 0; i < clink->nElems; i++) {
181  f64buf[i] = clink->value.pintegers[i];
182  }
183  free(clink->value.pmem);
184  f64buf[clink->nElems] = num;
185  clink->type = af64;
186  clink->value.pdoubles = f64buf;
187  break;
188 
189  case ac40:
190  errlogPrintf("lnkConst: Mixed data types in array\n");
191  /* fall through */
192  default:
193  return jlif_stop;
194  }
195 
196  clink->nElems = newElems;
197  return jlif_continue;
198 }
199 
200 static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
201 {
202  const_link *clink = CONTAINER(pjlink, const_link, jlink);
203  int newElems = clink->nElems + 1;
204 
205  switch (clink->type) {
206  char **vec, *str;
207 
208  case s0:
209  str = malloc(len+1);
210  if (!str)
211  return jlif_stop;
212 
213  strncpy(str, val, len);
214  str[len] = '\0';
215  clink->type = sc40;
216  clink->value.scalar_string = str;
217  break;
218 
219  case a0:
220  clink->type = ac40;
221  /* fall thorough */
222  case ac40:
223  vec = realloc(clink->value.pmem, newElems * sizeof(char *));
224  if (!vec)
225  return jlif_stop;
226  str = malloc(len+1);
227  if (!str)
228  return jlif_stop;
229 
230  strncpy(str, val, len);
231  str[len] = '\0';
232  vec[clink->nElems] = str;
233  clink->value.pstrings = vec;
234  break;
235 
236  case af64:
237  case ai64:
238  errlogPrintf("lnkConst: Mixed data types in array\n");
239  /* fall thorough */
240  default:
241  return jlif_stop;
242  }
243 
244  clink->nElems = newElems;
245  return jlif_continue;
246 }
247 
248 static jlif_result lnkConst_start_array(jlink *pjlink)
249 {
250  const_link *clink = CONTAINER(pjlink, const_link, jlink);
251 
252  if (clink->type != s0) {
253  errlogPrintf("lnkConst: Embedded array value\n");
254  return jlif_stop;
255  }
256 
257  clink->type = a0;
258  return jlif_continue;
259 }
260 
261 static jlif_result lnkConst_end_array(jlink *pjlink)
262 {
263  return jlif_continue;
264 }
265 
266 static struct lset* lnkConst_get_lset(const jlink *pjlink)
267 {
268  return &lnkConst_lset;
269 }
270 
271 
272 /* Report outputs:
273  * 'const': integer 21
274  * 'const': double 5.23
275  * 'const': string "something"
276  * 'const': array of 999 integers
277  * [1, 2, 3]
278  * 'const': array of 1 double
279  * [1.2345]
280  * 'const': array of 2 strings
281  * ["hello", "world"]
282  *
283  * Array values are only printed at level 2
284  * because there might be quite a few of them.
285  */
286 
287 static void lnkConst_report(const jlink *pjlink, int level, int indent)
288 {
289  const_link *clink = CONTAINER(pjlink, const_link, jlink);
290  const char * const type_names[4] = {
291  "bug", "integer", "double", "string"
292  };
293  const char * const dtype = type_names[clink->type & 3];
294 
295  if (clink->type > a0) {
296  const char * const plural = clink->nElems > 1 ? "s" : "";
297 
298  printf("%*s'const': array of %d %s%s", indent, "",
299  clink->nElems, dtype, plural);
300 
301  if (level < 2) {
302  putchar('\n');
303  }
304  else {
305  int i;
306 
307  switch (clink->type) {
308  case ai64:
309  printf("\n%*s[%lld", indent+2, "", clink->value.pintegers[0]);
310  for (i = 1; i < clink->nElems; i++) {
311  printf(", %lld", clink->value.pintegers[i]);
312  }
313  break;
314  case af64:
315  printf("\n%*s[%g", indent+2, "", clink->value.pdoubles[0]);
316  for (i = 1; i < clink->nElems; i++) {
317  printf(", %g", clink->value.pdoubles[i]);
318  }
319  break;
320  case ac40:
321  printf("\n%*s[\"%s\"", indent+2, "", clink->value.pstrings[0]);
322  for (i = 1; i < clink->nElems; i++) {
323  printf(", \"%s\"", clink->value.pstrings[i]);
324  }
325  break;
326  default:
327  break;
328  }
329  printf("]\n");
330  }
331  return;
332  }
333 
334  printf("%*s'const': %s", indent, "", dtype);
335 
336  switch (clink->type) {
337  case si64:
338  printf(" %lld\n", clink->value.scalar_integer);
339  return;
340  case sf64:
341  printf(" %g\n", clink->value.scalar_double);
342  return;
343  case sc40:
344  printf(" \"%s\"\n", clink->value.scalar_string);
345  return;
346  default:
347  printf(" -- type=%d\n", clink->type);
348  return;
349  }
350 }
351 
352 /*************************** lset Routines **************************/
353 
354 static void lnkConst_remove(struct dbLocker *locker, struct link *plink)
355 {
356  lnkConst_free(plink->value.json.jlink);
357 }
358 
359 static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer)
360 {
361  const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
362  long status;
363 
364  if(INVALID_DB_REQ(dbrType))
365  return S_db_badDbrtype;
366 
367  switch (clink->type) {
368  case si64:
369  if (clink->jlink.debug)
370  printf(" si64 %lld\n", clink->value.scalar_integer);
371  status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
372  (&clink->value.scalar_integer, pbuffer, NULL);
373  break;
374 
375  case sf64:
376  if (clink->jlink.debug)
377  printf(" sf64 %g\n", clink->value.scalar_double);
378  status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
379  (&clink->value.scalar_double, pbuffer, NULL);
380  break;
381 
382  case sc40:
383  if (clink->jlink.debug)
384  printf(" sc40 '%s'\n", clink->value.scalar_string);
385  status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
386  (clink->value.scalar_string, pbuffer, NULL);
387  break;
388 
389  case ai64:
390  if (clink->jlink.debug)
391  printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]);
392  status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
393  (clink->value.pintegers, pbuffer, NULL);
394  break;
395 
396  case af64:
397  if (clink->jlink.debug)
398  printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]);
399  status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
400  (clink->value.pdoubles, pbuffer, NULL);
401  break;
402 
403  case ac40:
404  if (clink->jlink.debug)
405  printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
406  status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
407  (clink->value.pstrings[0], pbuffer, NULL);
408  break;
409 
410  default:
411  if (clink->jlink.debug)
412  printf(" Bad type %d\n", clink->type);
413  status = S_db_badField;
414  break;
415  }
416 
417  return status;
418 }
419 
420 static long lnkConst_loadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
421  epicsUInt32 *plen)
422 {
423  const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
424  const char *pstr;
425 
426  if(!size) return 0;
427 
428  switch (clink->type) {
429  case sc40:
430  if (clink->jlink.debug)
431  printf(" sc40 '%s'\n", clink->value.scalar_string);
432  pstr = clink->value.scalar_string;
433  break;
434 
435  case ac40:
436  if (clink->jlink.debug)
437  printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
438  pstr = clink->value.pstrings[0];
439  break;
440 
441  default:
442  if (clink->jlink.debug)
443  printf(" Bad type %d\n", clink->type);
444  return S_db_badField;
445  }
446 
447  strncpy(pbuffer, pstr, --size);
448  pbuffer[size] = 0;
449  *plen = (epicsUInt32) strlen(pbuffer) + 1;
450  return 0;
451 }
452 
453 static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
454  long *pnReq)
455 {
456  const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
457  short dbrSize;
458  char *pdest = pbuffer;
459  int nElems = clink->nElems;
460  FASTCONVERT conv;
461  long status;
462 
463  if(INVALID_DB_REQ(dbrType))
464  return S_db_badDbrtype;
465 
466  dbrSize = dbValueSize(dbrType);
467 
468  if (nElems > *pnReq)
469  nElems = *pnReq;
470 
471  switch (clink->type) {
472  int i;
473 
474  case si64:
475  if (clink->jlink.debug)
476  printf(" si64 %lld\n", clink->value.scalar_integer);
477  status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
478  (&clink->value.scalar_integer, pdest, NULL);
479  break;
480 
481  case sf64:
482  if (clink->jlink.debug)
483  printf(" sf64 %g\n", clink->value.scalar_double);
484  status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
485  (&clink->value.scalar_double, pdest, NULL);
486  break;
487 
488  case sc40:
489  if (clink->jlink.debug)
490  printf(" sc40 '%s'\n", clink->value.scalar_string);
491  status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
492  (clink->value.scalar_string, pbuffer, NULL);
493  break;
494 
495  case ai64:
496  if (clink->jlink.debug)
497  printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]);
498  conv = dbFastPutConvertRoutine[DBF_INT64][dbrType];
499  for (i = 0; i < nElems; i++) {
500  conv(&clink->value.pintegers[i], pdest, NULL);
501  pdest += dbrSize;
502  }
503  status = 0;
504  break;
505 
506  case af64:
507  if (clink->jlink.debug)
508  printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]);
509  conv = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType];
510  for (i = 0; i < nElems; i++) {
511  conv(&clink->value.pdoubles[i], pdest, NULL);
512  pdest += dbrSize;
513  }
514  status = 0;
515  break;
516 
517  case ac40:
518  if (clink->jlink.debug)
519  printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
520  conv = dbFastPutConvertRoutine[DBF_STRING][dbrType];
521  for (i = 0; i < nElems; i++) {
522  conv(clink->value.pstrings[i], pdest, NULL);
523  pdest += dbrSize;
524  }
525  status = 0;
526  break;
527 
528  default:
529  if (clink->jlink.debug)
530  printf(" Bad type %d\n", clink->type);
531  status = S_db_badField;
532  }
533  *pnReq = nElems;
534  return status;
535 }
536 
537 static long lnkConst_getNelements(const struct link *plink, long *nelements)
538 {
539  *nelements = 0;
540  return 0;
541 }
542 
543 static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer,
544  long *pnRequest)
545 {
546  if (pnRequest)
547  *pnRequest = 0;
548  return 0;
549 }
550 
551 static long lnkConst_putValue(struct link *plink, short dbrType,
552  const void *pbuffer, long nRequest)
553 {
554  return 0;
555 }
556 
557 
558 /************************* Interface Tables *************************/
559 
560 static lset lnkConst_lset = {
561  1, 0, /* Constant, not Volatile */
562  NULL, lnkConst_remove,
563  lnkConst_loadScalar, lnkConst_loadLS, lnkConst_loadArray, NULL,
564  NULL, lnkConst_getNelements, lnkConst_getValue,
565  NULL, NULL, NULL,
566  NULL, NULL,
567  NULL, NULL,
568  lnkConst_putValue, NULL,
569  NULL, NULL
570 };
571 
572 static jlif lnkConstIf = {
573  "const", lnkConst_alloc, lnkConst_free,
574  NULL, lnkConst_boolean, lnkConst_integer, lnkConst_double, lnkConst_string,
575  NULL, NULL, NULL,
576  lnkConst_start_array, lnkConst_end_array,
577  NULL, lnkConst_get_lset,
578  lnkConst_report, NULL, NULL
579 };
580 epicsExportAddress(jlif, lnkConstIf);
struct const_link const_link
double epicsFloat64
Definition: epicsTypes.h:49
pvd::Status status
An EPICS-specific replacement for ANSI C&#39;s assert.
#define CONTAINER(ptr, structure, member)
Find parent object from a member pointer.
Definition: dbDefs.h:66
int i
Definition: scan.c:967
#define printf
Definition: epicsStdio.h:41
#define INVALID_DB_REQ(x)
Definition: db_access.h:115
#define NULL
Definition: catime.c:38
#define str(v)
unsigned int epicsUInt32
Definition: epicsTypes.h:43
dbfType
Definition: dbFldTypes.h:24
Miscellaneous macro definitions.
#define putchar
Definition: epicsStdio.h:51
epicsExportAddress(jlif, lnkConstIf)
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
long(* FASTCONVERT)()
Definition: lnkConst.c:25
char * pbuffer
Definition: errlog.c:85
struct json_link json
Definition: link.h:177
long long epicsInt64
Definition: epicsTypes.h:44
Exporting IOC objects.