This is Unofficial EPICS BASE Doxygen Site
dbStaticLib.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 
10 #include <stdio.h>
11 #include <stddef.h>
12 #include <errno.h>
13 #include <limits.h>
14 #include <string.h>
15 #include <math.h>
16 #include <ctype.h>
17 
18 #include "cantProceed.h"
19 #include "cvtFast.h"
20 #include "epicsAssert.h"
21 #include "dbDefs.h"
22 #include "dbmf.h"
23 #include "ellLib.h"
24 #include "epicsPrint.h"
25 #include "epicsStdio.h"
26 #include "epicsStdlib.h"
27 #include "epicsString.h"
28 #include "errlog.h"
29 #include "gpHash.h"
30 #include "osiFileName.h"
31 #include "postfix.h"
32 
33 #define DBFLDTYPES_GBLSOURCE
34 #define SPECIAL_GBLSOURCE
35 
36 #define epicsExportSharedSymbols
37 #include "dbChannel.h"
38 #include "dbFldTypes.h"
39 #include "dbStaticLib.h"
40 #include "dbStaticPvt.h"
41 #include "devSup.h"
42 #include "drvSup.h"
43 #include "link.h"
44 #include "special.h"
45 
46 #include "dbCommon.h"
47 #include "dbJLink.h"
48 
49 int dbStaticDebug = 0;
50 static char *pNullString = "";
51 #define messagesize 276
52 #define RPCL_LEN INFIX_TO_POSTFIX_SIZE(80)
53 
54 /* Must be big enough to hold a 64-bit integer in base 10, but in
55  * the future when fields hold large JSON objects this fixed size
56  * allocation will probably have to become variable sized.
57  */
59 
60 static char *ppstring[5]={" NPP"," PP"," CA"," CP"," CPP"};
61 static char *msstring[4]={" NMS"," MS"," MSI"," MSS"};
62 
64  {"CONSTANT",CONSTANT},
65  {"PV_LINK",PV_LINK},
66  {"VME_IO",VME_IO},
67  {"CAMAC_IO",CAMAC_IO},
68  {"AB_IO",AB_IO},
69  {"GPIB_IO",GPIB_IO},
70  {"BITBUS_IO",BITBUS_IO},
71  {"MACRO_LINK",MACRO_LINK},
72  {"JSON_LINK",JSON_LINK},
73  {"PN_LINK",PN_LINK},
74  {"DB_LINK",DB_LINK},
75  {"CA_LINK",CA_LINK},
76  {"INST_IO",INST_IO},
77  {"BBGPIB_IO",BBGPIB_IO},
78  {"RF_IO",RF_IO},
79  {"VXI_IO",VXI_IO}
80 };
81 
82 /*forward references for private routines*/
83 static void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...)
84  EPICS_PRINTF_STYLE(2,3);
85 static long dbAddOnePath (DBBASE *pdbbase, const char *path, unsigned length);
86 
87 /* internal routines*/
88 static FILE *openOutstream(const char *filename)
89 {
90  FILE *stream;
91  errno = 0;
92  stream = fopen(filename,"w");
93  if(!stream) {
94  fprintf(stderr,"error opening %s %s\n",filename,strerror(errno));
95  return 0;
96  }
97  return stream;
98 }
99 
100 static void finishOutstream(FILE *stream)
101 {
102  if(stream==stdout) {
103  fflush(stdout);
104  } else {
105  if(fclose(stream)) fprintf(stderr,"fclose error %s\n",strerror(errno));
106  }
107 }
108 
109 void dbFreeLinkContents(struct link *plink)
110 {
111  char *parm = NULL;
112 
113  switch(plink->type) {
114  case CONSTANT: free((void *)plink->value.constantStr); break;
115  case MACRO_LINK: free((void *)plink->value.macro_link.macroStr); break;
116  case PV_LINK: free((void *)plink->value.pv_link.pvname); break;
117  case JSON_LINK:
118  dbJLinkFree(plink->value.json.jlink);
119  parm = plink->value.json.string;
120  break;
121  case VME_IO: parm = plink->value.vmeio.parm; break;
122  case CAMAC_IO: parm = plink->value.camacio.parm; break;
123  case AB_IO: parm = plink->value.abio.parm; break;
124  case GPIB_IO: parm = plink->value.gpibio.parm; break;
125  case BITBUS_IO: parm = plink->value.bitbusio.parm;break;
126  case INST_IO: parm = plink->value.instio.string; break;
127  case BBGPIB_IO: parm = plink->value.bbgpibio.parm;break;
128  case RF_IO: break;
129  case VXI_IO: parm = plink->value.vxiio.parm; break;
130  default:
131  epicsPrintf("dbFreeLink called but link type %d unknown\n", plink->type);
132  }
133  if(parm && (parm != pNullString)) free((void *)parm);
134  if(plink->text) free(plink->text);
135  plink->lset = NULL;
136  plink->text = NULL;
137  memset(&plink->value, 0, sizeof(union value));
138 }
139 
140 void dbFreePath(DBBASE *pdbbase)
141 {
142  ELLLIST *ppathList;
143  dbPathNode *pdbPathNode;
144 
145  if(!pdbbase) return;
146  ppathList = (ELLLIST *)pdbbase->pathPvt;
147  if(!ppathList) return;
148  while((pdbPathNode = (dbPathNode *)ellFirst(ppathList))) {
149  ellDelete(ppathList,&pdbPathNode->node);
150  free((void *)pdbPathNode->directory);
151  free((void *)pdbPathNode);
152  }
153  free((void *)ppathList);
154  pdbbase->pathPvt = 0;
155  return;
156 }
157 
158 
159 static void zeroDbentry(DBENTRY *pdbentry)
160 {
161  /*NOTE that pdbbase and message MUST NOT be set to NULL*/
162  pdbentry->precordType=NULL;
163  pdbentry->pflddes=NULL;
164  pdbentry->precnode=NULL;
165  pdbentry->pfield=NULL;
166  pdbentry->indfield=0;
167 }
168 
169 static char *getpMessage(DBENTRY *pdbentry)
170 {
171  char *msg = pdbentry->message;
172 
173  if (!msg) {
174  msg = dbCalloc(1, messagesize);
175  pdbentry->message = msg;
176  }
177  else
178  *msg = '\0';
179  return msg;
180 }
181 
182 static
183 void dbMsgCpy(DBENTRY *pdbentry, const char *msg)
184 {
185  getpMessage(pdbentry);
186  strncpy(pdbentry->message, msg, messagesize-1);
187  pdbentry->message[messagesize-1] = '\0';
188 }
189 
190 static
191 void dbMsgNCpy(DBENTRY *pdbentry, const char *msg, size_t len)
192 {
193  getpMessage(pdbentry);
194  if (len >= messagesize)
195  len = messagesize-1; /* FIXME: Quietly truncates */
196 
197  strncpy(pdbentry->message, msg, len);
198  pdbentry->message[len] = '\0';
199 }
200 
201 static
202 void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...)
203 {
204  va_list args;
205  getpMessage(pdbentry);
206  va_start(args, fmt);
207  epicsVsnprintf(pdbentry->message, messagesize, fmt, args);
208  va_end(args);
209 }
210 
211 static void ulongToHexString(epicsUInt32 source, char *pdest)
212 {
213  static const char hex_digit_to_ascii[16] = "0123456789abcdef";
214  epicsUInt32 val,temp;
215  char digit[10];
216  int i,j;
217 
218  if (source==0) {
219  strcpy(pdest,"0x0");
220  return;
221  }
222  *pdest++ = '0'; *pdest++ = 'x';
223  val = source;
224  for (i=0; val!=0; i++) {
225  temp = val/16;
226  digit[i] = hex_digit_to_ascii[val - temp*16];
227  val = temp;
228  }
229  for (j=i-1; j>=0; j--) {
230  *pdest++ = digit[j];
231  }
232  *pdest = 0;
233  return;
234 }
235 
236 static void realToString(double value, char *preturn, int isdouble)
237 {
238  static const double delta[2] = {1e-6, 1e-15};
239  static const int precision[2] = {6, 14};
240  double absvalue;
241  int logval,prec;
242  size_t end;
243  char tstr[30];
244  char *ptstr = &tstr[0];
245  int round;
246  int ise = FALSE;
247  char *loce = NULL;
248 
249  if (value == 0) {
250  strcpy(preturn, "0");
251  return;
252  }
253 
254  absvalue = value < 0 ? -value : value;
255  if (absvalue < (double)INT_MAX) {
256  epicsInt32 intval = (epicsInt32) value;
257  double diff = value - intval;
258 
259  if (diff < 0) diff = -diff;
260  if (diff < absvalue * delta[isdouble]) {
261  cvtLongToString(intval, preturn);
262  return;
263  }
264  }
265 
266  /*Now starts the hard cases*/
267  if (value < 0) {
268  *preturn++ = '-';
269  value = -value;
270  }
271 
272  logval = (int)log10(value);
273  if (logval > 6 || logval < -2) {
274  int nout;
275 
276  ise = TRUE;
277  prec = precision[isdouble];
278  nout = sprintf(ptstr, "%.*e", prec, value);
279  loce = strchr(ptstr, 'e');
280 
281  if (!loce) {
282  ptstr[nout] = 0;
283  strcpy(preturn, ptstr);
284  return;
285  }
286 
287  *loce++ = 0;
288  } else {
289  prec = precision[isdouble] - logval;
290  if ( prec < 0) prec = 0;
291  sprintf(ptstr, "%.*f", prec, value);
292  }
293 
294  if (prec > 0) {
295  end = strlen(ptstr) - 1;
296  round = FALSE;
297  while (end > 0) {
298  if (tstr[end] == '.') {end--; break;}
299  if (tstr[end] == '0') {end--; continue;}
300  if (!round && end < precision[isdouble]) break;
301  if (!round && tstr[end] < '8') break;
302  if (tstr[end-1] == '.') {
303  if (round) end = end-2;
304  break;
305  }
306  if (tstr[end-1] != '9') break;
307  round = TRUE;
308  end--;
309  }
310  tstr[end+1] = 0;
311  while (round) {
312  if (tstr[end] < '9') {tstr[end]++; break;}
313  if (end == 0) { *preturn++ = '1'; tstr[end] = '0'; break;}
314  tstr[end--] = '0';
315  }
316  }
317  strcpy(preturn, &tstr[0]);
318  if (ise) {
319  if (!(strchr(preturn, '.'))) strcat(preturn, ".0");
320  strcat(preturn, "e");
321  strcat(preturn, loce);
322  }
323 }
324 
325 static void floatToString(float value, char *preturn)
326 {
327  realToString((double)value, preturn, 0);
328 }
329 
330 static void doubleToString(double value, char *preturn)
331 {
332  realToString(value, preturn, 1);
333 }
334 
335 /*Public only for dbStaticNoRun*/
337 {
338  dbRecordType *precordType = pdbentry->precordType;
339  dbFldDes *pflddes = pdbentry->pflddes;
340  dbDeviceMenu *pdbDeviceMenu;
341  devSup *pdevSup;
342  int ind;
343  int nChoice;
344 
345  if(!precordType) return(NULL);
346  if(!pflddes) return(NULL);
347  if(pflddes->field_type!=DBF_DEVICE) return(NULL);
348  if(pflddes->ftPvt){
349  pdbDeviceMenu = (dbDeviceMenu *)pflddes->ftPvt;
350  if(pdbDeviceMenu->nChoice == ellCount(&precordType->devList))
351  return(pdbDeviceMenu);
352  free((void *)pdbDeviceMenu->papChoice);
353  free((void *)pdbDeviceMenu);
354  pflddes->ftPvt = NULL;
355  }
356  nChoice = ellCount(&precordType->devList);
357  if(nChoice <= 0) return(NULL);
358  pdbDeviceMenu = dbCalloc(1,sizeof(dbDeviceMenu));
359  pdbDeviceMenu->nChoice = nChoice;
360  pdbDeviceMenu->papChoice = dbCalloc(pdbDeviceMenu->nChoice,sizeof(char *));
361  pdevSup = (devSup *)ellFirst(&precordType->devList);
362  ind = 0;
363  while(pdevSup) {
364  pdbDeviceMenu->papChoice[ind] = pdevSup->choice;
365  ind++;
366  pdevSup = (devSup *)ellNext(&pdevSup->node);
367  }
368  pflddes->ftPvt = pdbDeviceMenu;
369  return(pdbDeviceMenu);
370 }
371 
372 /* Beginning of Public Routines */
373 
374 #define INC_SIZE 256
375 void dbCatString(char **string,int *stringLength,char *src,char *separator)
376 {
377  if((*string==NULL)
378  || ((strlen(*string)+strlen(src)+2) > (size_t)*stringLength)) {
379  char *newString;
380  size_t size;
381 
382  size = strlen(src);
383  if(*string) size += strlen(*string);
384  /*Make size multiple of INC_SIZE*/
385  size = ((size + 2 + INC_SIZE)/INC_SIZE) * INC_SIZE;
386  newString = dbCalloc(size,sizeof(char));
387  if(*string) {
388  strcpy(newString,*string);
389  free((void *)(*string));
390  }
391  *string = newString;
392  }
393  if(*stringLength>0) {
394  strcat(*string,separator);
395  *stringLength += (int) strlen(separator);
396  }
397  strcat(*string,src);
398  *stringLength += (int) strlen(src);
399 }
400 
402 {
403  dbBase *pdbbase;
404 
405  pdbbase = dbCalloc(1,sizeof(dbBase));
406  ellInit(&pdbbase->menuList);
407  ellInit(&pdbbase->recordTypeList);
408  ellInit(&pdbbase->drvList);
409  ellInit(&pdbbase->registrarList);
410  ellInit(&pdbbase->functionList);
411  ellInit(&pdbbase->variableList);
412  ellInit(&pdbbase->bptList);
413  ellInit(&pdbbase->filterList);
414  ellInit(&pdbbase->guiGroupList);
415  gphInitPvt(&pdbbase->pgpHash,256);
416  dbPvdInitPvt(pdbbase);
417  return (pdbbase);
418 }
419 void dbFreeBase(dbBase *pdbbase)
420 {
421  dbMenu *pdbMenu;
422  dbMenu *pdbMenuNext;
423  dbRecordType *pdbRecordType;
424  dbRecordType *pdbRecordTypeNext;
425  dbFldDes *pdbFldDes;
426  dbRecordAttribute *pAttribute;
427  dbRecordAttribute *pAttributeNext;
428  devSup *pdevSup;
429  devSup *pdevSupNext;
430  dbText *ptext;
431  dbText *ptextNext;
432  dbVariableDef *pvar;
433  dbVariableDef *pvarNext;
434  drvSup *pdrvSup;
435  drvSup *pdrvSupNext;
436  linkSup *plinkSup;
437  brkTable *pbrkTable;
438  brkTable *pbrkTableNext;
439  chFilterPlugin *pfilt;
440  chFilterPlugin *pfiltNext;
441  dbGuiGroup *pguiGroup;
442  dbGuiGroup *pguiGroupNext;
443  int i;
444  DBENTRY dbentry;
445  long status;
446 
447  dbInitEntry(pdbbase,&dbentry);
448  status = dbFirstRecordType(&dbentry);
449  while(!status) {
450  /* dbDeleteRecord() will remove alias or real record node.
451  * For real record nodes, also removes the nodes of all aliases.
452  * This complicates safe traversal, so we re-start iteration
453  * from the first record after each call.
454  */
455  while((status = dbFirstRecord(&dbentry))==0) {
456  dbDeleteRecord(&dbentry);
457  }
458  assert(status==S_dbLib_recNotFound);
459  status = dbNextRecordType(&dbentry);
460  }
461  dbFinishEntry(&dbentry);
462  pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
463  while(pdbRecordType) {
464  for(i=0; i<pdbRecordType->no_fields; i++) {
465  pdbFldDes = pdbRecordType->papFldDes[i];
466  free((void *)pdbFldDes->prompt);
467  free((void *)pdbFldDes->name);
468  free((void *)pdbFldDes->extra);
469  free((void *)pdbFldDes->initial);
470  if(pdbFldDes->field_type==DBF_DEVICE && pdbFldDes->ftPvt) {
471  dbDeviceMenu *pdbDeviceMenu;
472 
473  pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt;
474  free((void *)pdbDeviceMenu->papChoice);
475  free((void *)pdbDeviceMenu);
476  pdbFldDes->ftPvt=0;
477  }
478  free((void *)pdbFldDes);
479  }
480  pdevSup = (devSup *)ellFirst(&pdbRecordType->devList);
481  while(pdevSup) {
482  pdevSupNext = (devSup *)ellNext(&pdevSup->node);
483  ellDelete(&pdbRecordType->devList,&pdevSup->node);
484  free((void *)pdevSup->name);
485  free((void *)pdevSup->choice);
486  free((void *)pdevSup);
487  pdevSup = pdevSupNext;
488  }
489  ptext = (dbText *)ellFirst(&pdbRecordType->cdefList);
490  while(ptext) {
491  ptextNext = (dbText *)ellNext(&ptext->node);
492  ellDelete(&pdbRecordType->cdefList,&ptext->node);
493  free((void *)ptext->text);
494  free((void *)ptext);
495  ptext = ptextNext;
496  }
497  pAttribute =
498  (dbRecordAttribute *)ellFirst(&pdbRecordType->attributeList);
499  while(pAttribute) {
500  pAttributeNext = (dbRecordAttribute *)ellNext(&pAttribute->node);
501  ellDelete(&pdbRecordType->attributeList,&pAttribute->node);
502  free((void *)pAttribute->name);
503  free((void *)pAttribute->pdbFldDes);
504  free(pAttribute);
505  pAttribute = pAttributeNext;
506  }
507  pdbRecordTypeNext = (dbRecordType *)ellNext(&pdbRecordType->node);
508  gphDelete(pdbbase->pgpHash,pdbRecordType->name,&pdbbase->recordTypeList);
509  ellDelete(&pdbbase->recordTypeList,&pdbRecordType->node);
510  free((void *)pdbRecordType->name);
511  free((void *)pdbRecordType->link_ind);
512  free((void *)pdbRecordType->papsortFldName);
513  free((void *)pdbRecordType->sortFldInd);
514  free((void *)pdbRecordType->papFldDes);
515  free((void *)pdbRecordType);
516  pdbRecordType = pdbRecordTypeNext;
517  }
518  pdbMenu = (dbMenu *)ellFirst(&pdbbase->menuList);
519  while(pdbMenu) {
520  pdbMenuNext = (dbMenu *)ellNext(&pdbMenu->node);
521  gphDelete(pdbbase->pgpHash,pdbMenu->name,&pdbbase->menuList);
522  ellDelete(&pdbbase->menuList,&pdbMenu->node);
523  for(i=0; i< pdbMenu->nChoice; i++) {
524  free((void *)pdbMenu->papChoiceName[i]);
525  free((void *)pdbMenu->papChoiceValue[i]);
526  }
527  free((void *)pdbMenu->papChoiceName);
528  free((void *)pdbMenu->papChoiceValue);
529  free((void *)pdbMenu ->name);
530  free((void *)pdbMenu);
531  pdbMenu = pdbMenuNext;
532  }
533  pdrvSup = (drvSup *)ellFirst(&pdbbase->drvList);
534  while(pdrvSup) {
535  pdrvSupNext = (drvSup *)ellNext(&pdrvSup->node);
536  ellDelete(&pdbbase->drvList,&pdrvSup->node);
537  free((void *)pdrvSup->name);
538  free((void *)pdrvSup);
539  pdrvSup = pdrvSupNext;
540  }
541  while ((plinkSup = (linkSup *) ellGet(&pdbbase->linkList))) {
542  free(plinkSup->jlif_name);
543  free(plinkSup->name);
544  free(plinkSup);
545  }
546  ptext = (dbText *)ellFirst(&pdbbase->registrarList);
547  while(ptext) {
548  ptextNext = (dbText *)ellNext(&ptext->node);
549  ellDelete(&pdbbase->registrarList,&ptext->node);
550  free((void *)ptext->text);
551  free((void *)ptext);
552  ptext = ptextNext;
553  }
554  ptext = (dbText *)ellFirst(&pdbbase->functionList);
555  while(ptext) {
556  ptextNext = (dbText *)ellNext(&ptext->node);
557  ellDelete(&pdbbase->functionList,&ptext->node);
558  free((void *)ptext->text);
559  free((void *)ptext);
560  ptext = ptextNext;
561  }
562  pvar = (dbVariableDef *)ellFirst(&pdbbase->variableList);
563  while(pvar) {
564  pvarNext = (dbVariableDef *)ellNext(&pvar->node);
565  ellDelete(&pdbbase->variableList,&pvar->node);
566  free((void *)pvar->name);
567  free((void *)pvar->type);
568  free((void *)pvar);
569  pvar = pvarNext;
570  }
571  pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList);
572  while(pbrkTable) {
573  pbrkTableNext = (brkTable *)ellNext(&pbrkTable->node);
574  gphDelete(pdbbase->pgpHash,pbrkTable->name,&pdbbase->bptList);
575  ellDelete(&pdbbase->bptList,&pbrkTable->node);
576  free(pbrkTable->name);
577  free((void *)pbrkTable->paBrkInt);
578  free((void *)pbrkTable);
579  pbrkTable = pbrkTableNext;
580  }
581  pfilt = (chFilterPlugin *)ellFirst(&pdbbase->filterList);
582  while(pfilt) {
583  pfiltNext = (chFilterPlugin *)ellNext(&pfilt->node);
584  free((char*)pfilt->name);
585  if(pfilt->fif->priv_free)
586  (*pfilt->fif->priv_free)(pfilt->puser);
587  free(pfilt);
588  pfilt = pfiltNext;
589  }
590  pguiGroup = (dbGuiGroup *)ellFirst(&pdbbase->guiGroupList);
591  while (pguiGroup) {
592  pguiGroupNext = (dbGuiGroup *)ellNext(&pguiGroup->node);
593  gphDelete(pdbbase->pgpHash, pguiGroup->name, &pdbbase->guiGroupList);
594  ellDelete(&pdbbase->guiGroupList, &pguiGroup->node);
595  free(pguiGroup->name);
596  free((void *)pguiGroup);
597  pguiGroup = pguiGroupNext;
598  }
599  gphFreeMem(pdbbase->pgpHash);
600  dbPvdFreeMem(pdbbase);
601  dbFreePath(pdbbase);
602  free((void *)pdbbase);
603  pdbbase = NULL;
604  return;
605 }
606 
608 {
609  DBENTRY *pdbentry;
610 
611  pdbentry = dbmfMalloc(sizeof(DBENTRY));
612  memset(pdbentry,'\0',sizeof(DBENTRY));
613  pdbentry->pdbbase = pdbbase;
614  return(pdbentry);
615 }
616 
617 void dbFreeEntry(DBENTRY *pdbentry)
618 {
619  if (!pdbentry)
620  return;
621  if (pdbentry->message)
622  free((void *)pdbentry->message);
623  dbmfFree(pdbentry);
624 }
625 
626 void dbInitEntry(dbBase *pdbbase,DBENTRY *pdbentry)
627 {
628  memset((char *)pdbentry,'\0',sizeof(DBENTRY));
629  pdbentry->pdbbase = pdbbase;
630 }
631 
632 void dbFinishEntry(DBENTRY *pdbentry)
633 {
634  if(pdbentry->message) {
635  free((void *)pdbentry->message);
636  pdbentry->message = NULL;
637  }
638 }
639 
641 {
642  DBENTRY *pnew;
643 
644  pnew = dbAllocEntry(pdbentry->pdbbase);
645  *pnew = *pdbentry;
646  pnew->message = NULL;
647  return(pnew);
648 }
649 
651 {
652  *pto = *pfrom;
653  pto->message = NULL;
654 }
655 
656 
657 long dbPath(DBBASE *pdbbase,const char *path)
658 {
659  if(!pdbbase) return(-1);
660  dbFreePath(pdbbase);
661  if(!path || strlen(path)==0) return(dbAddPath(pdbbase,"."));
662  return(dbAddPath(pdbbase,path));
663 }
664 
665 long dbAddPath(DBBASE *pdbbase,const char *path)
666 {
667  ELLLIST *ppathList;
668  const char *pcolon;
669  const char *plast;
670  unsigned expectingPath;
671  unsigned sawMissingPath;
672 
673  if(!pdbbase) return(-1);
674  ppathList = (ELLLIST *)pdbbase->pathPvt;
675  if(!ppathList) {
676  ppathList = dbCalloc(1,sizeof(ELLLIST));
677  ellInit(ppathList);
678  pdbbase->pathPvt = (void *)ppathList;
679  }
680  if (!path) return(0); /* Empty path strings are ignored */
681  /* care is taken to properly deal with white space
682  * 1) preceding and trailing white space is removed from paths
683  * 2) white space inbetween path separator counts as an empty name
684  * (see below)
685  */
686  expectingPath = FALSE;
687  sawMissingPath = FALSE;
688  while (*path) {
689  size_t len;
690 
691  /* preceding white space is removed */
692  if (isspace((int)*path)) {
693  path++;
694  continue;
695  }
696  pcolon = strstr (path, OSI_PATH_LIST_SEPARATOR);
697  if (pcolon==path) {
698  sawMissingPath = TRUE;
699  path += strlen (OSI_PATH_LIST_SEPARATOR);
700  continue;
701  }
702  if (pcolon) {
703  plast = pcolon - 1;
704  expectingPath = TRUE;
705  } else {
706  plast = strlen (path) + path - 1;
707  expectingPath = FALSE;
708  }
709  /* trailing white space is removed */
710  while (isspace((int)*plast)) {
711  plast--;
712  }
713 
714  /*
715  * len is always nonzero because we found something that
716  * 1) isnt white space
717  * 2) isnt a path separator
718  */
719  len = (plast - path) + 1;
720  if (dbAddOnePath (pdbbase, path, (unsigned) len)) return (-1);
721  path += len;
722  if (pcolon) {
723  path += strlen(OSI_PATH_LIST_SEPARATOR);
724  }
725  }
726 
727  /*
728  * an empty name at beginning, middle, or end of a path string that isnt
729  * empty means current directory
730  */
731  if (expectingPath||sawMissingPath) {
732  return dbAddOnePath (pdbbase, ".", 1);
733  }
734  return(0);
735 }
736 
737 static long dbAddOnePath (DBBASE *pdbbase, const char *path, unsigned length)
738 {
739  ELLLIST *ppathList;
740  dbPathNode *pdbPathNode;
741 
742  if(!pdbbase) return(-1);
743  ppathList = (ELLLIST *)pdbbase->pathPvt;
744 
745  pdbPathNode = (dbPathNode *)dbCalloc(1, sizeof(dbPathNode));
746  pdbPathNode->directory = (char *)dbCalloc(length+1, sizeof(char));
747  strncpy(pdbPathNode->directory, path, length);
748  pdbPathNode->directory[length] = '\0';
749  ellAdd(ppathList, &pdbPathNode->node);
750  return 0;
751 }
752 
753 char *dbGetPromptGroupNameFromKey(DBBASE *pdbbase, const short key)
754 {
755  dbGuiGroup *pdbGuiGroup;
756 
757  if (!pdbbase) return NULL;
758  for (pdbGuiGroup = (dbGuiGroup *)ellFirst(&pdbbase->guiGroupList);
759  pdbGuiGroup; pdbGuiGroup = (dbGuiGroup *)ellNext(&pdbGuiGroup->node)) {
760  if (pdbGuiGroup->key == key) return pdbGuiGroup->name;
761  }
762  return NULL;
763 }
764 
765 short dbGetPromptGroupKeyFromName(DBBASE *pdbbase, const char *name)
766 {
767  GPHENTRY *pgphentry;
768 
769  if (!pdbbase) return 0;
770  pgphentry = gphFind(pdbbase->pgpHash, name, &pdbbase->guiGroupList);
771  if (!pgphentry) {
772  return 0;
773  } else {
774  return ((dbGuiGroup*)pgphentry->userPvt)->key;
775  }
776 }
777 
778 
779 long dbWriteRecord(DBBASE *ppdbbase,const char *filename,
780  const char *precordTypename,int level)
781 {
782  FILE *stream;
783  long status;
784 
785  stream = openOutstream(filename);
786  if(!stream) return -1;
787  status = dbWriteRecordFP(ppdbbase,stream,precordTypename,level);
788  finishOutstream(stream);
789  return status;
790 }
791 
793  DBBASE *pdbbase,FILE *fp,const char *precordTypename,int level)
794 {
795  DBENTRY dbentry;
796  DBENTRY *pdbentry=&dbentry;
797  long status;
798  int dctonly;
799 
800  dctonly = ((level>1) ? FALSE : TRUE);
801  dbInitEntry(pdbbase,pdbentry);
802  if (precordTypename) {
803  if (*precordTypename == 0 || *precordTypename == '*')
804  precordTypename = 0;
805  }
806 
807  if(!precordTypename) {
808  status = dbFirstRecordType(pdbentry);
809  if(status) {
810  /* No record descriptions, so no record instances */
811  dbFinishEntry(pdbentry);
812  return(0);
813  }
814  } else {
815  status = dbFindRecordType(pdbentry,precordTypename);
816  if(status) {
817  fprintf(stderr,"dbWriteRecordFP: No record description for %s\n",
818  precordTypename);
819  dbFinishEntry(pdbentry);
820  return(status);
821  }
822  }
823  while(!status) {
824  status = dbFirstRecord(pdbentry);
825  while(!status) {
826  if (dbIsAlias(pdbentry)) {
827  status = dbNextRecord(pdbentry);
828  continue;
829  }
830  if(dbIsVisibleRecord(pdbentry))
831  fprintf(fp,"grecord(%s,\"%s\") {\n",
832  dbGetRecordTypeName(pdbentry),dbGetRecordName(pdbentry));
833  else
834  fprintf(fp,"record(%s,\"%s\") {\n",
835  dbGetRecordTypeName(pdbentry),dbGetRecordName(pdbentry));
836  status = dbFirstField(pdbentry,dctonly);
837  while(!status) {
838  if (!dbIsDefaultValue(pdbentry) || level>0) {
839  char *pvalstring = dbGetString(pdbentry);
840 
841  if (!pvalstring) {
842  fprintf(fp,"\tfield(%s,\"\")\n",
843  dbGetFieldName(pdbentry));
844  } else {
845  fprintf(fp,"\tfield(%s,\"",
846  dbGetFieldName(pdbentry));
847  epicsStrPrintEscaped(fp,pvalstring,strlen(pvalstring));
848  fprintf(fp,"\")\n");
849  }
850  } else if(level>0) { /*generate 0 length string*/
851  fprintf(fp,"\tfield(%s,\"\")\n",dbGetFieldName(pdbentry));
852  }
853  status=dbNextField(pdbentry,dctonly);
854  }
855  status = dbFirstInfo(pdbentry);
856  while (!status) {
857  const char *pinfostr = dbGetInfoString(pdbentry);
858 
859  fprintf(fp, "\tinfo(\"%s\",\"",
860  dbGetInfoName(pdbentry));
861  epicsStrPrintEscaped(fp, pinfostr, strlen(pinfostr));
862  fprintf(fp, "\")\n");
863  status = dbNextInfo(pdbentry);
864  }
865  fprintf(fp,"}\n");
866  status = dbNextRecord(pdbentry);
867  }
868  status = dbFirstRecord(pdbentry);
869  while (!status) {
870  if (!dbIsAlias(pdbentry)) {
871  status = dbNextRecord(pdbentry);
872  continue;
873  }
874  fprintf(fp, "alias(\"%s\",\"%s\")\n",
875  dbRecordName(pdbentry), dbGetRecordName(pdbentry));
876  status = dbNextRecord(pdbentry);
877  }
878  if(precordTypename) break;
879  status = dbNextRecordType(pdbentry);
880  }
881  dbFinishEntry(pdbentry);
882  return(0);
883 }
884 
886  DBBASE *ppdbbase,const char *filename,const char *menuName)
887 {
888  FILE *stream;
889  long status;
890 
891  stream = openOutstream(filename);
892  status = dbWriteMenuFP(ppdbbase,stream,menuName);
893  finishOutstream(stream);
894  return status;
895 }
896 
897 long dbWriteMenuFP(DBBASE *pdbbase,FILE *fp,const char *menuName)
898 {
899  dbMenu *pdbMenu;
900  int gotMatch;
901  int i;
902 
903  if(!pdbbase) {
904  fprintf(stderr,"pdbbase not specified\n");
905  return(-1);
906  }
907  if (menuName) {
908  if (*menuName == 0 || *menuName == '*')
909  menuName = 0;
910  }
911  pdbMenu = (dbMenu *)ellFirst(&pdbbase->menuList);
912  while(pdbMenu) {
913  if(menuName) {
914  gotMatch = (strcmp(menuName,pdbMenu->name)==0) ? TRUE : FALSE;
915  }else {
916  gotMatch=TRUE;
917  }
918  if(gotMatch) {
919  fprintf(fp,"menu(%s) {\n",pdbMenu->name);
920  for(i=0; i<pdbMenu->nChoice; i++) {
921  fprintf(fp,"\tchoice(%s,\"%s\")\n",pdbMenu->papChoiceName[i],
922  pdbMenu->papChoiceValue[i]);
923  }
924  fprintf(fp,"}\n");
925  if(menuName) break;
926  }
927  pdbMenu = (dbMenu *)ellNext(&pdbMenu->node);
928  }
929  return(0);
930 }
931 
933  DBBASE *pdbbase,const char *filename,const char *recordTypeName)
934 {
935  FILE *stream;
936  long status;
937 
938  stream = openOutstream(filename);
939  status = dbWriteRecordTypeFP(pdbbase,stream,recordTypeName);
940  finishOutstream(stream);
941  return status;
942 }
943 
945  DBBASE *pdbbase,FILE *fp,const char *recordTypeName)
946 {
947  dbRecordType *pdbRecordType;
948  dbFldDes *pdbFldDes;
949  int gotMatch;
950  int i;
951 
952  if(!pdbbase) {
953  fprintf(stderr,"pdbbase not specified\n");
954  return(-1);
955  }
956  if (recordTypeName) {
957  if (*recordTypeName == 0 || *recordTypeName == '*')
958  recordTypeName = 0;
959  }
960 
961  for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
962  pdbRecordType; pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
963  if(recordTypeName) {
964  gotMatch = (strcmp(recordTypeName,pdbRecordType->name)==0)
965  ? TRUE : FALSE;
966  }else {
967  gotMatch=TRUE;
968  }
969  if(!gotMatch) continue;
970  fprintf(fp,"recordtype(%s) {\n",pdbRecordType->name);
971  for(i=0; i<pdbRecordType->no_fields; i++) {
972  int j;
973 
974  pdbFldDes = pdbRecordType->papFldDes[i];
975  fprintf(fp,"\tfield(%s,%s) {\n",pdbFldDes->name,
976  dbGetFieldTypeString(pdbFldDes->field_type));
977  if(pdbFldDes->prompt)
978  fprintf(fp,"\t\tprompt(\"%s\")\n",pdbFldDes->prompt);
979  if(pdbFldDes->initial)
980  fprintf(fp,"\t\tinitial(\"%s\")\n",pdbFldDes->initial);
981  if (pdbFldDes->promptgroup) {
982  fprintf(fp,"\t\tpromptgroup(\"%s\")\n",
983  dbGetPromptGroupNameFromKey(pdbbase, pdbFldDes->promptgroup));
984  }
985  if(pdbFldDes->special) {
986  if(pdbFldDes->special >= SPC_NTYPES) {
987  fprintf(fp,"\t\tspecial(%d)\n",pdbFldDes->special);
988  } else for(j=0; j<SPC_NTYPES; j++) {
989  if(pamapspcType[j].value == pdbFldDes->special) {
990  fprintf(fp,"\t\tspecial(%s)\n",
991  pamapspcType[j].strvalue);
992  break;
993  }
994  }
995  }
996  if(pdbFldDes->extra)
997  fprintf(fp,"\t\textra(\"%s\")\n",pdbFldDes->extra);
998  if(pdbFldDes->field_type==DBF_MENU) {
999  if(pdbFldDes->ftPvt)
1000  fprintf(fp,"\t\tmenu(%s)\n",
1001  ((dbMenu *)pdbFldDes->ftPvt)->name);
1002  else
1003  fprintf(stderr,"\t\t menu: NOT FOUND\n");
1004  }
1005  if(pdbFldDes->field_type==DBF_STRING) {
1006  fprintf(fp,"\t\tsize(%d)\n",
1007  pdbFldDes->size);
1008  }
1009  if(pdbFldDes->process_passive) fprintf(fp,"\t\tpp(TRUE)\n");
1010  if(pdbFldDes->prop) fprintf(fp,"\t\tprop(YES)\n");
1011  if(pdbFldDes->base) fprintf(fp,"\t\tbase(HEX)\n");
1012  if(pdbFldDes->interest)
1013  fprintf(fp,"\t\tinterest(%d)\n",pdbFldDes->interest);
1014  if(!pdbFldDes->as_level) fprintf(fp,"\t\tasl(ASL0)\n");
1015  fprintf(fp,"\t}\n");
1016  }
1017  fprintf(fp,"}\n");
1018  if(recordTypeName) break;
1019  }
1020  return(0);
1021 }
1022 
1023 long dbWriteDevice(DBBASE *pdbbase,const char *filename)
1024 {
1025  FILE *stream;
1026  long status;
1027 
1028  stream = openOutstream(filename);
1029  status = dbWriteDeviceFP(pdbbase,stream);
1030  finishOutstream(stream);
1031  return status;
1032 }
1033 
1034 long dbWriteDeviceFP(DBBASE *pdbbase,FILE *fp)
1035 {
1036  dbRecordType *pdbRecordType;
1037  devSup *pdevSup;
1038 
1039  if(!pdbbase) {
1040  fprintf(stderr,"dbWriteDeviceFP: pdbbase not specified\n");
1041  return(-1);
1042  }
1043  for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
1044  pdbRecordType; pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
1045  for(pdevSup = (devSup *)ellFirst(&pdbRecordType->devList);
1046  pdevSup; pdevSup = (devSup *)ellNext(&pdevSup->node)) {
1047  int j;
1048 
1049  for(j=0; j< LINK_NTYPES; j++) {
1050  if(pamaplinkType[j].value==pdevSup->link_type) break;
1051  }
1052  if(j>=LINK_NTYPES) {
1053  fprintf(fp,"link_type not valid\n");
1054  continue;
1055  }
1056  fprintf(fp,"device(%s,%s,%s,\"%s\")\n",
1057  pdbRecordType->name,
1058  pamaplinkType[j].strvalue,
1059  pdevSup->name,pdevSup->choice);
1060  }
1061  }
1062  return(0);
1063 }
1064 
1065 long dbWriteDriver(DBBASE *pdbbase,const char *filename)
1066 {
1067  FILE *stream;
1068  long status;
1069 
1070  stream = openOutstream(filename);
1071  status = dbWriteDriverFP(pdbbase,stream);
1072  finishOutstream(stream);
1073  return status;
1074 }
1075 
1076 long dbWriteDriverFP(DBBASE *pdbbase,FILE *fp)
1077 {
1078  drvSup *pdrvSup;
1079 
1080  if(!pdbbase) {
1081  fprintf(stderr,"pdbbase not specified\n");
1082  return(-1);
1083  }
1084  for(pdrvSup = (drvSup *)ellFirst(&pdbbase->drvList);
1085  pdrvSup; pdrvSup = (drvSup *)ellNext(&pdrvSup->node)) {
1086  fprintf(fp,"driver(%s)\n",pdrvSup->name);
1087  }
1088  return(0);
1089 }
1090 
1091 long dbWriteLinkFP(DBBASE *pdbbase, FILE *fp)
1092 {
1093  linkSup *plinkSup;
1094 
1095  if (!pdbbase) {
1096  fprintf(stderr, "pdbbase not specified\n");
1097  return -1;
1098  }
1099  for (plinkSup = (linkSup *) ellFirst(&pdbbase->linkList);
1100  plinkSup; plinkSup = (linkSup *) ellNext(&plinkSup->node)) {
1101  fprintf(fp, "link(%s,%s)\n", plinkSup->name, plinkSup->jlif_name);
1102  }
1103  return 0;
1104 }
1105 
1106 long dbWriteRegistrarFP(DBBASE *pdbbase,FILE *fp)
1107 {
1108  dbText *ptext;
1109 
1110  if(!pdbbase) {
1111  fprintf(stderr,"pdbbase not specified\n");
1112  return(-1);
1113  }
1114  for(ptext = (dbText *)ellFirst(&pdbbase->registrarList);
1115  ptext; ptext = (dbText *)ellNext(&ptext->node)) {
1116  fprintf(fp,"registrar(%s)\n",ptext->text);
1117  }
1118  return(0);
1119 }
1120 
1121 long dbWriteFunctionFP(DBBASE *pdbbase,FILE *fp)
1122 {
1123  dbText *ptext;
1124 
1125  if(!pdbbase) {
1126  fprintf(stderr,"pdbbase not specified\n");
1127  return(-1);
1128  }
1129  for(ptext = (dbText *)ellFirst(&pdbbase->functionList);
1130  ptext; ptext = (dbText *)ellNext(&ptext->node)) {
1131  fprintf(fp,"function(%s)\n",ptext->text);
1132  }
1133  return(0);
1134 }
1135 
1136 long dbWriteVariableFP(DBBASE *pdbbase,FILE *fp)
1137 {
1138  dbVariableDef *pvar;
1139 
1140  if(!pdbbase) {
1141  fprintf(stderr,"pdbbase not specified\n");
1142  return(-1);
1143  }
1144  for(pvar = (dbVariableDef *)ellFirst(&pdbbase->variableList);
1145  pvar; pvar = (dbVariableDef *)ellNext(&pvar->node)) {
1146  fprintf(fp,"variable(%s,%s)\n",pvar->name,pvar->type);
1147  }
1148  return(0);
1149 }
1150 
1151 long dbWriteBreaktable(DBBASE *pdbbase,const char *filename)
1152 {
1153  FILE *stream;
1154  long status;
1155 
1156  stream = openOutstream(filename);
1157  status = dbWriteBreaktableFP(pdbbase,stream);
1158  finishOutstream(stream);
1159  return status;
1160 }
1161 
1162 long dbWriteBreaktableFP(DBBASE *pdbbase,FILE *fp)
1163 {
1164  brkTable *pbrkTable;
1165  brkInt *pbrkInt;
1166  int i;
1167 
1168  if (!pdbbase) {
1169  fprintf(stderr,"pdbbase not specified\n");
1170  return(-1);
1171  }
1172  for (pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList);
1173  pbrkTable;
1174  pbrkTable = (brkTable *)ellNext(&pbrkTable->node)) {
1175  fprintf(fp,"breaktable(%s) {\n",pbrkTable->name);
1176  pbrkInt = pbrkTable->paBrkInt;
1177  for(i=0; i < pbrkTable->number; i++) {
1178  fprintf(fp,"\t%e, %e\n",pbrkInt->raw,pbrkInt->eng);
1179  pbrkInt++;
1180  }
1181  fprintf(fp,"}\n");
1182  }
1183  return(0);
1184 }
1185 
1186 long dbFindRecordType(DBENTRY *pdbentry,const char *recordType)
1187 {
1188  dbBase *pdbbase = pdbentry->pdbbase;
1189  GPHENTRY *phash;
1190 
1191  zeroDbentry(pdbentry);
1192  phash = gphFind(pdbbase->pgpHash,recordType,&pdbbase->recordTypeList);
1193  if(!phash) return(S_dbLib_recordTypeNotFound);
1194  pdbentry->precordType = phash->userPvt;
1195  return(0);
1196 }
1197 
1199 {
1200  dbRecordType *precordType;
1201 
1202  zeroDbentry(pdbentry);
1203  precordType = (dbRecordType *)ellFirst(&pdbentry->pdbbase->recordTypeList);
1204  if(!precordType) return(S_dbLib_recordTypeNotFound);
1205  pdbentry->precordType = precordType;
1206  return(0);
1207 }
1208 
1209 long dbNextRecordType(DBENTRY *pdbentry)
1210 {
1211  dbRecordType *precordType = pdbentry->precordType;
1212 
1213  zeroDbentry(pdbentry);
1214  precordType = (dbRecordType *)ellNext(&precordType->node);
1215  if(!precordType) return(S_dbLib_recordTypeNotFound);
1216  pdbentry->precordType = precordType;
1217  return(0);
1218 }
1219 
1220 char * dbGetRecordTypeName(DBENTRY *pdbentry)
1221 {
1222  return(pdbentry->precordType->name);
1223 }
1224 
1226 {
1227  return(ellCount(&pdbentry->pdbbase->recordTypeList));
1228 }
1229 
1231  DBENTRY *pdbentry, const char *name, const char*value)
1232 {
1233  dbRecordType *precordType = pdbentry->precordType;
1234  int createNew = TRUE;
1235  int compare;
1236  dbRecordAttribute *pattribute;
1237 
1238  if(!precordType) return(S_dbLib_recordTypeNotFound);
1239  pattribute = (dbRecordAttribute *)ellFirst(&precordType->attributeList);
1240  /*put new attribute name in sort order*/
1241  while(pattribute) {
1242  compare = strcmp(pattribute->name,name);
1243  if(compare==0) {
1244  createNew = FALSE;
1245  }
1246  if(compare>=0) break;
1247  pattribute = (dbRecordAttribute *)ellNext(&pattribute->node);
1248  }
1249  if(createNew) {
1250  dbRecordAttribute *pnew;
1251  dbFldDes *pdbFldDes;
1252 
1253  pnew = dbCalloc(1,sizeof(dbRecordAttribute));
1254  if(pattribute) {
1255  ellInsert(&precordType->attributeList,pattribute->node.previous,
1256  &pnew->node);
1257  } else {
1258  ellAdd(&precordType->attributeList,&pnew->node);
1259  }
1260  pattribute = pnew;
1261  pattribute->name = dbCalloc(strlen(name)+1,sizeof(char));
1262  strcpy(pattribute->name,name);
1263  pdbFldDes = dbCalloc(1,sizeof(dbFldDes));
1264  pdbFldDes->name = pattribute->name;
1265  pdbFldDes->pdbRecordType = precordType;
1266  pdbFldDes->special = SPC_ATTRIBUTE;
1267  pdbFldDes->field_type = DBF_STRING;
1268  pdbFldDes->as_level = ASL1;
1269  pdbFldDes->size = MAX_STRING_SIZE;
1270  pattribute->pdbFldDes = pdbFldDes;
1271  }
1272  strncpy(pattribute->value,value,MAX_STRING_SIZE);
1273  pattribute->value[MAX_STRING_SIZE-1] = 0;
1274  return(0);
1275 }
1276 
1277 long dbGetAttributePart(DBENTRY *pdbentry, const char **ppname)
1278 {
1279  dbRecordType *precordType = pdbentry->precordType;
1280  const char *pname = *ppname;
1281  dbRecordAttribute *pattribute;
1282 
1283  if (!precordType)
1285 
1286  pattribute = (dbRecordAttribute *)ellFirst(&precordType->attributeList);
1287  while (pattribute) {
1288  size_t nameLen = strlen(pattribute->name);
1289  int compare = strncmp(pattribute->name, pname, nameLen);
1290 
1291  if (compare == 0) {
1292  int ch = pname[nameLen];
1293 
1294  if (ch != '_' && !isalnum(ch)) {
1295  /* Any other character can't be in the attribute name */
1296  pdbentry->pflddes = pattribute->pdbFldDes;
1297  pdbentry->pfield = pattribute->value;
1298  *ppname = &pname[nameLen];
1299  return 0;
1300  }
1301  if (strlen(pname) > nameLen) {
1302  compare = -1;
1303  }
1304  }
1305  if (compare >= 0) break;
1306  pattribute = (dbRecordAttribute *)ellNext(&pattribute->node);
1307  }
1308  return S_dbLib_fieldNotFound;
1309 }
1310 
1311 long dbGetRecordAttribute(DBENTRY *pdbentry, const char *pname)
1312 {
1313  return dbGetAttributePart(pdbentry, &pname);
1314 }
1315 
1316 long dbFirstField(DBENTRY *pdbentry,int dctonly)
1317 {
1318 
1319  pdbentry->indfield = -1;
1320  return(dbNextField(pdbentry,dctonly));
1321 }
1322 
1323 long dbNextField(DBENTRY *pdbentry,int dctonly)
1324 {
1325  dbRecordType *precordType = pdbentry->precordType;
1326  dbRecordNode *precnode = pdbentry->precnode;
1327  dbFldDes *pflddes;
1328  short indfield = pdbentry->indfield;
1329 
1330  if(!precordType) return(S_dbLib_recordTypeNotFound);
1331  indfield++;
1332  while(TRUE) {
1333  if(indfield>=precordType->no_fields) {
1334  pdbentry->indfield = 0;
1335  pdbentry->pflddes = NULL;
1336  pdbentry->pfield = NULL;
1337  return(S_dbLib_fieldNotFound);
1338  }
1339  pflddes = precordType->papFldDes[indfield];
1340  if(!dctonly || pflddes->promptgroup) {
1341  /*Skip field if dctonly and no device support*/
1342  if(!dctonly || (pflddes->field_type!=DBF_DEVICE)
1343  || (ellCount(&precordType->devList)>0)) {
1344  pdbentry->indfield = indfield;
1345  pdbentry->pflddes = pflddes;
1346  pdbentry->indfield = indfield;
1347  if(precnode) {
1348  dbGetFieldAddress(pdbentry);
1349  }else {
1350  pdbentry->pfield = NULL;
1351  }
1352  return(0);
1353  }
1354  }
1355  indfield++;
1356  }
1357 }
1358 
1359 int dbGetNFields(DBENTRY *pdbentry,int dctonly)
1360 {
1361  dbRecordType *precordType = pdbentry->precordType;
1362  dbFldDes *pflddes;
1363  int indfield,n;
1364 
1365  if(!precordType) return(S_dbLib_recordTypeNotFound);
1366  n = 0;
1367  for(indfield=0; indfield<precordType->no_fields; indfield++) {
1368  pflddes = precordType->papFldDes[indfield];
1369  if(dctonly && (pflddes->field_type==DBF_DEVICE)
1370  && (ellCount(&precordType->devList)==0) ) continue;
1371  if(!dctonly || pflddes->promptgroup) n++;
1372  }
1373  return(n);
1374 }
1375 
1376 char * dbGetFieldName(DBENTRY *pdbentry)
1377 {
1378  dbFldDes *pflddes = pdbentry->pflddes;
1379 
1380  if(!pflddes) return(NULL);
1381  return(pflddes->name);
1382 }
1383 
1385 {
1386  dbFldDes *pflddes = pdbentry->pflddes;
1387 
1388  if(!pflddes) return(-1);
1389  return(pflddes->field_type);
1390 }
1391 
1392 char * dbGetDefault(DBENTRY *pdbentry)
1393 {
1394  dbFldDes *pflddes = pdbentry->pflddes;
1395 
1396  if(!pflddes) return(NULL);
1397  return(pflddes->initial);
1398 }
1399 
1400 char * dbGetPrompt(DBENTRY *pdbentry)
1401 {
1402  dbFldDes *pflddes = pdbentry->pflddes;
1403 
1404  if(!pflddes) return(NULL);
1405  return(&pflddes->prompt[0]);
1406 }
1407 
1409 {
1410  dbFldDes *pflddes = pdbentry->pflddes;
1411 
1412  if(!pflddes) return(0);
1413  return(pflddes->promptgroup);
1414 }
1415 
1416 long dbCreateRecord(DBENTRY *pdbentry,const char *precordName)
1417 {
1418  dbRecordType *precordType = pdbentry->precordType;
1419  dbFldDes *pdbFldDes;
1420  PVDENTRY *ppvd;
1421  ELLLIST *preclist = NULL;
1422  dbRecordNode *pNewRecNode = NULL;
1423  long status = 0;
1424 
1425  if(!precordType) return(S_dbLib_recordTypeNotFound);
1426  /*Get size of NAME field*/
1427  pdbFldDes = precordType->papFldDes[0];
1428  if(!pdbFldDes || (strcmp(pdbFldDes->name,"NAME")!=0))
1429  return(S_dbLib_nameLength);
1430  if((int)strlen(precordName)>=pdbFldDes->size) return(S_dbLib_nameLength);
1431  /* clear callers entry */
1432  zeroDbentry(pdbentry);
1433  if(!dbFindRecord(pdbentry,precordName)) return (S_dbLib_recExists);
1434  zeroDbentry(pdbentry);
1435  pdbentry->precordType = precordType;
1436  preclist = &precordType->recList;
1437  /* create a recNode */
1438  pNewRecNode = dbCalloc(1,sizeof(dbRecordNode));
1439  /* create a new record of this record type */
1440  pdbentry->precnode = pNewRecNode;
1441  if((status = dbAllocRecord(pdbentry,precordName))) return(status);
1442  pNewRecNode->recordname = dbRecordName(pdbentry);
1443  ellInit(&pNewRecNode->infoList);
1444  ellAdd(preclist, &pNewRecNode->node);
1445  pdbentry->precnode = pNewRecNode;
1446  ppvd = dbPvdAdd(pdbentry->pdbbase,precordType,pNewRecNode);
1447  if(!ppvd) {errMessage(-1,"Logic Err: Could not add to PVD");return(-1);}
1448  return(0);
1449 }
1450 
1451 long dbDeleteAliases(DBENTRY *pdbentry)
1452 {
1453  dbBase *pdbbase = pdbentry->pdbbase;
1454  dbRecordType *precordType = pdbentry->precordType;
1455  dbRecordNode *precnode = pdbentry->precnode;
1456  ELLLIST *preclist = &precordType->recList;
1457  dbRecordNode *pAliasNode, *pAliasNodeNext;
1458  DBENTRY dbentry;
1459  void *precord;
1460 
1461  if (!precnode) return S_dbLib_recNotFound;
1462  if (precnode->flags & DBRN_FLAGS_ISALIAS) return S_dbLib_recExists;
1463  precord = precnode->precord;
1464 
1465  dbInitEntry(pdbbase, &dbentry);
1466  pAliasNode = (dbRecordNode *)ellFirst(preclist);
1467  while (pAliasNode) {
1468  pAliasNodeNext = (dbRecordNode *)ellNext(&pAliasNode->node);
1469  if (pAliasNode->flags & DBRN_FLAGS_ISALIAS &&
1470  pAliasNode->precord == precord &&
1471  !dbFindRecord(&dbentry, pAliasNode->recordname)) {
1472  dbDeleteRecord(&dbentry);
1473  }
1474  pAliasNode = pAliasNodeNext;
1475  }
1476  precnode->flags &= ~DBRN_FLAGS_HASALIAS;
1477  return 0;
1478 }
1479 
1480 long dbDeleteRecord(DBENTRY *pdbentry)
1481 {
1482  dbBase *pdbbase = pdbentry->pdbbase;
1483  dbRecordType *precordType = pdbentry->precordType;
1484  dbRecordNode *precnode = pdbentry->precnode;
1485  ELLLIST *preclist;
1486  long status;
1487 
1488  if (!precnode) return S_dbLib_recNotFound;
1489  if (precnode->flags & DBRN_FLAGS_HASALIAS)
1490  dbDeleteAliases(pdbentry);
1491 
1492  preclist = &precordType->recList;
1493  ellDelete(preclist, &precnode->node);
1494  dbPvdDelete(pdbbase, precnode);
1495  while (!dbFirstInfo(pdbentry)) {
1496  dbDeleteInfo(pdbentry);
1497  }
1498  if (precnode->flags & DBRN_FLAGS_ISALIAS) {
1499  free(precnode->recordname);
1500  precordType->no_aliases--;
1501  } else {
1502  status = dbFreeRecord(pdbentry);
1503  if (status) return status;
1504  }
1505  free(precnode);
1506  pdbentry->precnode = NULL;
1507  return 0;
1508 }
1509 
1510 long dbFreeRecords(DBBASE *pdbbase)
1511 {
1512  DBENTRY dbentry;
1513  dbRecordType *pdbRecordType;
1514  dbRecordNode *pdbRecordNode;
1515  dbRecordNode *pdbRecordNodeNext;
1516 
1517  dbInitEntry(pdbbase,&dbentry);
1518  pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
1519  while(pdbRecordType) {
1520  pdbRecordNode = (dbRecordNode *)ellFirst(&pdbRecordType->recList);
1521  while(pdbRecordNode) {
1522  pdbRecordNodeNext = (dbRecordNode *)ellNext(&pdbRecordNode->node);
1523  if(!dbFindRecord(&dbentry,pdbRecordNode->recordname))
1524  dbDeleteRecord(&dbentry);
1525  pdbRecordNode = pdbRecordNodeNext;
1526  }
1527  pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node);
1528  }
1529  dbFinishEntry(&dbentry);
1530  return(0);
1531 }
1532 
1533 long dbFindRecordPart(DBENTRY *pdbentry, const char **ppname)
1534 {
1535  dbBase *pdbbase = pdbentry->pdbbase;
1536  const char *pname = *ppname;
1537  const char *pfn;
1538  size_t lenName;
1539  PVDENTRY *ppvdNode;
1540 
1541  zeroDbentry(pdbentry);
1542  pfn = strchr(pname, '.');
1543  if (pfn) {
1544  lenName = (size_t) (pfn - pname);
1545  } else {
1546  lenName = strlen(pname);
1547  }
1548 
1549  ppvdNode = dbPvdFind(pdbbase, pname, lenName);
1550  if (!ppvdNode)
1551  return S_dbLib_recNotFound;
1552 
1553  pdbentry->precnode = ppvdNode->precnode;
1554  pdbentry->precordType = ppvdNode->precordType;
1555  *ppname = pname + lenName;
1556  return 0;
1557 }
1558 
1559 long dbFindRecord(DBENTRY *pdbentry, const char *pname)
1560 {
1561  long status = dbFindRecordPart(pdbentry, &pname);
1562 
1563  if (status) return status;
1564  if (*pname == '.')
1565  return dbFindField(pdbentry, ++pname);
1566  return 0;
1567 }
1568 
1569 long dbFirstRecord(DBENTRY *pdbentry)
1570 {
1571  dbRecordType *precordType = pdbentry->precordType;
1572  dbRecordNode *precnode;
1573 
1574  zeroDbentry(pdbentry);
1575  if(!precordType) return(S_dbLib_recordTypeNotFound);
1576  pdbentry->precordType = precordType;
1577  precnode = (dbRecordNode *)ellFirst(&precordType->recList);
1578  if(!precnode) return(S_dbLib_recNotFound);
1579  pdbentry->precnode = precnode;
1580  return(0);
1581 }
1582 
1583 long dbNextRecord(DBENTRY *pdbentry)
1584 {
1585  dbRecordNode *precnode=pdbentry->precnode;
1586  long status=0;
1587 
1588  if(!precnode) return(S_dbLib_recNotFound);
1589  precnode = (dbRecordNode *)ellNext(&precnode->node);
1590  if(!precnode) status = S_dbLib_recNotFound;
1591  pdbentry->precnode = precnode;
1592  pdbentry->pfield = NULL;
1593  return(status);
1594 }
1595 
1596 int dbGetNRecords(DBENTRY *pdbentry)
1597 {
1598  dbRecordType *precordType = pdbentry->precordType;
1599 
1600  if(!precordType) return(0);
1601  return(ellCount(&precordType->recList));
1602 }
1603 
1604 int dbGetNAliases(DBENTRY *pdbentry)
1605 {
1606  dbRecordType *precordType = pdbentry->precordType;
1607 
1608  if(!precordType) return(0);
1609  return(precordType->no_aliases);
1610 }
1611 
1612 char * dbGetRecordName(DBENTRY *pdbentry)
1613 {
1614  dbRecordType *pdbRecordType = pdbentry->precordType;
1615  dbRecordNode *precnode = pdbentry->precnode;
1616 
1617  if(!pdbRecordType) return NULL;
1618  if(!precnode) return NULL;
1619  return precnode->recordname;
1620 }
1621 
1622 long dbVisibleRecord(DBENTRY *pdbentry)
1623 {
1624  dbRecordNode *precnode = pdbentry->precnode;
1625 
1626  if(!precnode) return(S_dbLib_recNotFound);
1627  precnode->flags |= DBRN_FLAGS_VISIBLE;
1628  return 0;
1629 }
1630 
1632 {
1633  dbRecordNode *precnode = pdbentry->precnode;
1634 
1635  if(!precnode) return(S_dbLib_recNotFound);
1636  precnode->flags &= ~DBRN_FLAGS_VISIBLE;
1637  return 0;
1638 }
1639 
1641 {
1642  dbRecordNode *precnode = pdbentry->precnode;
1643 
1644  if(!precnode) return 0;
1645  return precnode->flags & DBRN_FLAGS_VISIBLE ? 1 : 0;
1646 }
1647 
1648 long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
1649 {
1650  dbRecordType *precordType = pdbentry->precordType;
1651  dbRecordNode *precnode = pdbentry->precnode;
1652  dbRecordNode *pnewnode;
1653  DBENTRY tempEntry;
1654  PVDENTRY *ppvd;
1655 
1656  if (!precordType)
1658 
1659  /* alias of alias still references actual record */
1660  while (precnode && (precnode->flags & DBRN_FLAGS_ISALIAS))
1661  precnode = precnode->aliasedRecnode;
1662 
1663  if (!precnode)
1664  return S_dbLib_recNotFound;
1665 
1666  dbInitEntry(pdbentry->pdbbase, &tempEntry);
1667  if (!dbFindRecord(&tempEntry, alias))
1668  return S_dbLib_recExists;
1669  dbFinishEntry(&tempEntry);
1670 
1671  pnewnode = dbCalloc(1, sizeof(dbRecordNode));
1672  pnewnode->recordname = epicsStrDup(alias);
1673  pnewnode->precord = precnode->precord;
1674  pnewnode->aliasedRecnode = precnode;
1675  pnewnode->flags = DBRN_FLAGS_ISALIAS;
1676  precnode->flags |= DBRN_FLAGS_HASALIAS;
1677  ellInit(&pnewnode->infoList);
1678 
1679  ellAdd(&precordType->recList, &pnewnode->node);
1680  precordType->no_aliases++;
1681 
1682  ppvd = dbPvdAdd(pdbentry->pdbbase, precordType, pnewnode);
1683  if (!ppvd) {
1684  errMessage(-1, "dbCreateAlias: Add to PVD failed");
1685  return -1;
1686  }
1687 
1688  return 0;
1689 }
1690 
1691 int dbFollowAlias(DBENTRY *pdbentry)
1692 {
1693  if(!pdbentry->precnode)
1694  return S_dbLib_recNotFound;
1695  if(pdbentry->precnode->aliasedRecnode)
1696  pdbentry->precnode = pdbentry->precnode->aliasedRecnode;
1697  return 0;
1698 }
1699 
1700 int dbIsAlias(DBENTRY *pdbentry)
1701 {
1702  dbRecordNode *precnode = pdbentry->precnode;
1703 
1704  if(!precnode) return 0;
1705  return precnode->flags & DBRN_FLAGS_ISALIAS ? 1 : 0;
1706 }
1707 
1708 long dbCopyRecord(DBENTRY *pdbentry,const char *newRecordName,int overWriteOK)
1709 {
1710  dbRecordType *precordType = pdbentry->precordType;
1711  dbFldDes *pdbFldDes;
1712  dbRecordNode *precnode = pdbentry->precnode;
1713  long status;
1714  DBENTRY dbentry;
1715  char *pvalue;
1716 
1717  if(!precordType) return(S_dbLib_recordTypeNotFound);
1718  /*Get size of NAME field*/
1719  pdbFldDes = precordType->papFldDes[0];
1720  if(!pdbFldDes || (strcmp(pdbFldDes->name,"NAME")!=0))
1721  return(S_dbLib_nameLength);
1722  if((int)strlen(newRecordName)>=pdbFldDes->size) return(S_dbLib_nameLength);
1723  if (!precnode || dbIsAlias(pdbentry)) return S_dbLib_recNotFound;
1724  dbInitEntry(pdbentry->pdbbase,&dbentry);
1725  status = dbFindRecord(&dbentry,newRecordName);
1726  if(!status) {
1727  if(!overWriteOK) {
1728  dbFinishEntry(&dbentry);
1729  return(S_dbLib_recExists);
1730  }
1731  status = dbDeleteRecord(&dbentry);
1732  if(status) return(status);
1733  }
1734  dbFinishEntry(&dbentry);
1735  if((status = dbFindRecordType(&dbentry,precordType->name))) return(status);
1736  if((status = dbCreateRecord(&dbentry,newRecordName))) return(status);
1737  if((status = dbFirstField(pdbentry,TRUE))) return(status);
1738  if((status = dbFirstField(&dbentry,TRUE))) return(status);
1739  while(!status) {
1740  if(!dbIsDefaultValue(pdbentry)) {
1741  pvalue = dbGetString(pdbentry);
1742  if((status = dbPutString(&dbentry,pvalue))) return(status);
1743  }
1744  status = dbNextField(pdbentry,TRUE);
1745  if(!status) status = dbNextField(&dbentry,TRUE);
1746  if(!status && (pdbentry->pflddes!=dbentry.pflddes)) {
1747  epicsPrintf("dbCopyRecord: Logic Error\n");
1748  return(-1);
1749  }
1750  }
1751  /*Copy the info strings too*/
1752  status = dbFirstInfo(pdbentry);
1753  while (!status) {
1754  status = dbPutInfo(&dbentry, dbGetInfoName(pdbentry), dbGetInfoString(pdbentry));
1755  if (status) return (status);
1756  status = dbNextInfo(pdbentry);
1757  }
1758  /*Leave pdbentry pointing to newRecordName*/
1759  return(dbFindRecord(pdbentry,newRecordName));
1760 }
1761 
1762 long dbFindFieldPart(DBENTRY *pdbentry,const char **ppname)
1763 {
1764  dbRecordType *precordType = pdbentry->precordType;
1765  dbRecordNode *precnode = pdbentry->precnode;
1766  const char *pname = *ppname;
1767  short top, bottom, test;
1768  char **papsortFldName;
1769  short *sortFldInd;
1770  int ch;
1771  size_t nameLen;
1772 
1773  if (!precordType) return S_dbLib_recordTypeNotFound;
1774  if (!precnode) return S_dbLib_recNotFound;
1775  papsortFldName = precordType->papsortFldName;
1776  sortFldInd = precordType->sortFldInd;
1777 
1778  /* Measure field name length; name is a valid C identifier */
1779  nameLen = 0;
1780  if ((ch = *pname) &&
1781  (ch == '_' || isalpha(ch))) {
1782  while ((ch = pname[++nameLen]))
1783  if (!(ch == '_' || isalnum(ch))) break;
1784  }
1785 
1786  /* Handle absent field name */
1787  if (nameLen == 0) {
1788  dbFldDes *pflddes = precordType->pvalFldDes;
1789 
1790  if (!pflddes)
1792  pdbentry->pflddes = pflddes;
1793  pdbentry->indfield = precordType->indvalFlddes;
1794  *ppname = &pname[nameLen];
1795  return dbGetFieldAddress(pdbentry);
1796  }
1797 
1798  /* binary search through ordered field names */
1799  top = precordType->no_fields - 1;
1800  bottom = 0;
1801  test = (top + bottom) / 2;
1802  while (1) {
1803  int compare = strncmp(papsortFldName[test], pname, nameLen);
1804  if (compare == 0)
1805  compare = (int) (strlen(papsortFldName[test]) - nameLen);
1806  if (compare == 0) {
1807  dbFldDes *pflddes = precordType->papFldDes[sortFldInd[test]];
1808 
1809  if (!pflddes)
1811  pdbentry->pflddes = pflddes;
1812  pdbentry->indfield = sortFldInd[test];
1813  *ppname = &pname[nameLen];
1814  return dbGetFieldAddress(pdbentry);
1815  } else if (compare > 0) {
1816  top = test - 1;
1817  if (top < bottom) break;
1818  test = (top + bottom) / 2;
1819  } else {
1820  bottom = test + 1;
1821  if (top < bottom) break;
1822  test = (top + bottom) / 2;
1823  }
1824  }
1825  return S_dbLib_fieldNotFound;
1826 }
1827 
1828 long dbFindField(DBENTRY *pdbentry,const char *pname)
1829 {
1830  long status = dbFindFieldPart(pdbentry, &pname);
1831  int ch;
1832 
1833  if (status == S_dbLib_fieldNotFound)
1834  return dbGetRecordAttribute(pdbentry, pname);
1835  if (status) return status;
1836 
1837  ch = *pname;
1838  if (ch == 0 || isspace(ch)) return 0;
1839  return S_dbLib_recNotFound;
1840 }
1841 
1842 int dbFoundField(DBENTRY *pdbentry)
1843 { return((pdbentry->pfield) ? TRUE : FALSE); }
1844 
1845 char * dbGetString(DBENTRY *pdbentry)
1846 {
1847  dbFldDes *pflddes = pdbentry->pflddes;
1848  void *pfield = pdbentry->pfield;
1849  DBLINK *plink;
1850 
1851  if (!pflddes) {
1852  dbMsgCpy(pdbentry, "fldDes not found");
1853  return pdbentry->message;
1854  }
1855  switch (pflddes->field_type) {
1856  case DBF_STRING:
1857  case DBF_INLINK:
1858  case DBF_OUTLINK:
1859  case DBF_FWDLINK:
1860  if (!pfield) {
1861  dbMsgCpy(pdbentry, "Field not allocated (NULL)");
1862  return pdbentry->message;
1863  }
1864  break;
1865  default:
1866  break;
1867  }
1868 
1869  switch (pflddes->field_type) {
1870  case DBF_STRING:
1871  /* Protect against a missing nil-terminator */
1872  dbMsgNCpy(pdbentry, (char *)pfield, pflddes->size);
1873  break;
1874  case DBF_CHAR:
1875  case DBF_UCHAR:
1876  case DBF_SHORT:
1877  case DBF_USHORT:
1878  case DBF_ENUM:
1879  case DBF_LONG:
1880  case DBF_ULONG:
1881  case DBF_INT64:
1882  case DBF_UINT64:
1883  case DBF_FLOAT:
1884  case DBF_DOUBLE:
1885  case DBF_MENU:
1886  case DBF_DEVICE:
1887  return(dbGetStringNum(pdbentry));
1888  case DBF_INLINK:
1889  case DBF_OUTLINK:
1890  plink = (DBLINK *)pfield;
1891  switch(plink->type) {
1892  case CONSTANT:
1893  if (plink->value.constantStr) {
1894  dbMsgCpy(pdbentry, plink->value.constantStr);
1895  } else if (plink->text) {
1896  dbMsgCpy(pdbentry, plink->text);
1897  } else {
1898  dbMsgCpy(pdbentry, "");
1899  }
1900  break;
1901  case MACRO_LINK:
1902  if (plink->value.macro_link.macroStr) {
1903  dbMsgCpy(pdbentry, plink->value.macro_link.macroStr);
1904  } else {
1905  dbMsgCpy(pdbentry, "");
1906  }
1907  break;
1908  case JSON_LINK:
1909  dbMsgCpy(pdbentry, plink->value.json.string);
1910  break;
1911  case PN_LINK:
1912  dbMsgPrint(pdbentry, "%s%s",
1913  plink->value.pv_link.pvname ? plink->value.pv_link.pvname : "",
1914  msstring[plink->value.pv_link.pvlMask&pvlOptMsMode]);
1915  break;
1916  case PV_LINK:
1917  case CA_LINK:
1918  case DB_LINK: {
1919  int ppind;
1920  short pvlMask;
1921 
1922  pvlMask = plink->value.pv_link.pvlMask;
1923  if (pvlMask&pvlOptPP) ppind=1;
1924  else if(pvlMask&pvlOptCA) ppind=2;
1925  else if(pvlMask&pvlOptCP) ppind=3;
1926  else if(pvlMask&pvlOptCPP) ppind=4;
1927  else ppind=0;
1928  dbMsgPrint(pdbentry, "%s%s%s%s",
1929  plink->value.pv_link.pvname ? plink->value.pv_link.pvname : "",
1930  (plink->flags & DBLINK_FLAG_TSELisTIME) ? ".TIME" : "",
1931  ppstring[ppind],
1932  msstring[plink->value.pv_link.pvlMask&pvlOptMsMode]);
1933  break;
1934  }
1935  case VME_IO:
1936  dbMsgPrint(pdbentry, "#C%d S%d @%s",
1937  plink->value.vmeio.card,plink->value.vmeio.signal,
1938  plink->value.vmeio.parm);
1939  break;
1940  case CAMAC_IO:
1941  dbMsgPrint(pdbentry, "#B%d C%d N%d A%d F%d @%s",
1942  plink->value.camacio.b,plink->value.camacio.c,
1943  plink->value.camacio.n,plink->value.camacio.a,
1944  plink->value.camacio.f,plink->value.camacio.parm);
1945  break;
1946  case RF_IO:
1947  dbMsgPrint(pdbentry, "#R%d M%d D%d E%d",
1948  plink->value.rfio.cryo,
1949  plink->value.rfio.micro,
1950  plink->value.rfio.dataset,
1951  plink->value.rfio.element);
1952  break;
1953  case AB_IO:
1954  dbMsgPrint(pdbentry, "#L%d A%d C%d S%d @%s",
1955  plink->value.abio.link,plink->value.abio.adapter,
1956  plink->value.abio.card,plink->value.abio.signal,
1957  plink->value.abio.parm);
1958  break;
1959  case GPIB_IO:
1960  dbMsgPrint(pdbentry, "#L%d A%d @%s",
1961  plink->value.gpibio.link,plink->value.gpibio.addr,
1962  plink->value.gpibio.parm);
1963  break;
1964  case BITBUS_IO:
1965  dbMsgPrint(pdbentry, "#L%u N%u P%u S%u @%s",
1966  plink->value.bitbusio.link,plink->value.bitbusio.node,
1967  plink->value.bitbusio.port,plink->value.bitbusio.signal,
1968  plink->value.bitbusio.parm);
1969  break;
1970  case BBGPIB_IO:
1971  dbMsgPrint(pdbentry, "#L%u B%u G%u @%s",
1972  plink->value.bbgpibio.link,plink->value.bbgpibio.bbaddr,
1973  plink->value.bbgpibio.gpibaddr,plink->value.bbgpibio.parm);
1974  break;
1975  case INST_IO:
1976  dbMsgPrint(pdbentry, "@%s", plink->value.instio.string);
1977  break;
1978  case VXI_IO :
1979  if (plink->value.vxiio.flag == VXIDYNAMIC)
1980  dbMsgPrint(pdbentry, "#V%d C%d S%d @%s",
1981  plink->value.vxiio.frame,plink->value.vxiio.slot,
1982  plink->value.vxiio.signal,plink->value.vxiio.parm);
1983  else
1984  dbMsgPrint(pdbentry, "#V%d S%d @%s",
1985  plink->value.vxiio.la,plink->value.vxiio.signal,
1986  plink->value.vxiio.parm);
1987  break;
1988  default :
1989  return(NULL);
1990  }
1991  break;
1992  case DBF_FWDLINK: {
1993  DBLINK *plink=(DBLINK *)pfield;
1994 
1995  switch(plink->type) {
1996  case CONSTANT:
1997  if (plink->value.constantStr) {
1998  dbMsgCpy(pdbentry, plink->value.constantStr);
1999  } else if (plink->text) {
2000  dbMsgCpy(pdbentry, plink->text);
2001  } else {
2002  dbMsgCpy(pdbentry, "");
2003  }
2004  break;
2005  case MACRO_LINK:
2006  if (plink->value.macro_link.macroStr) {
2007  dbMsgCpy(pdbentry, plink->value.macro_link.macroStr);
2008  } else {
2009  dbMsgCpy(pdbentry, "");
2010  }
2011  break;
2012  case JSON_LINK:
2013  dbMsgCpy(pdbentry, plink->value.json.string);
2014  break;
2015  case PV_LINK:
2016  case CA_LINK:
2017  case DB_LINK: {
2018  int ppind;
2019  short pvlMask;
2020 
2021  pvlMask = plink->value.pv_link.pvlMask;
2022  if (pvlMask&pvlOptCA) ppind=2;
2023  else ppind=0;
2024  dbMsgPrint(pdbentry, "%s%s",
2025  plink->value.pv_link.pvname ? plink->value.pv_link.pvname : "",
2026  ppind ? ppstring[ppind] : "");
2027  break;
2028  }
2029  default :
2030  return(NULL);
2031  }
2032  }
2033  break;
2034  default:
2035  return(NULL);
2036  }
2037  return pdbentry->message;
2038 }
2039 
2040 char *dbGetStringNum(DBENTRY *pdbentry)
2041 {
2042  dbFldDes *pflddes = pdbentry->pflddes;
2043  void *pfield = pdbentry->pfield;
2044  char *message;
2045  unsigned char cvttype;
2046 
2047  /* the following assumes that messagesize is large enough
2048  * to hold the base 10 encoded value of a 32-bit integer.
2049  */
2050  message = getpMessage(pdbentry);
2051  cvttype = pflddes->base;
2052  switch (pflddes->field_type) {
2053  case DBF_CHAR:
2054  if (cvttype == CT_DECIMAL)
2055  cvtCharToString(*(char *) pfield, message);
2056  else
2057  ulongToHexString(*(char *) pfield, message);
2058  break;
2059  case DBF_UCHAR:
2060  if (cvttype==CT_DECIMAL)
2061  cvtUcharToString(*(epicsUInt8 *) pfield, message);
2062  else
2063  ulongToHexString(*(epicsUInt8 *) pfield, message);
2064  break;
2065  case DBF_SHORT:
2066  if (cvttype==CT_DECIMAL)
2067  cvtShortToString(*(epicsInt16 *) pfield, message);
2068  else
2069  ulongToHexString(*(epicsInt16 *) pfield, message);
2070  break;
2071  case DBF_USHORT:
2072  case DBF_ENUM:
2073  if (cvttype==CT_DECIMAL)
2074  cvtUshortToString(*(epicsUInt16 *) pfield, message);
2075  else
2076  ulongToHexString(*(epicsUInt16 *) pfield, message);
2077  break;
2078  case DBF_LONG:
2079  if (cvttype==CT_DECIMAL)
2080  cvtLongToString(*(epicsInt32 *) pfield, message);
2081  else
2082  ulongToHexString(*(epicsInt32 *) pfield, message);
2083  break;
2084  case DBF_ULONG:
2085  if (cvttype==CT_DECIMAL)
2086  cvtUlongToString(*(epicsUInt32 *) pfield, message);
2087  else
2088  ulongToHexString(*(epicsUInt32 *) pfield, message);
2089  break;
2090  case DBF_INT64:
2091  if (cvttype==CT_DECIMAL)
2092  cvtInt64ToString(*(epicsInt64 *) pfield, message);
2093  else
2094  cvtInt64ToHexString(*(epicsInt64 *) pfield, message);
2095  break;
2096  case DBF_UINT64:
2097  if (cvttype==CT_DECIMAL)
2098  cvtUInt64ToString(*(epicsUInt32 *) pfield, message);
2099  else
2100  cvtUInt64ToHexString(*(epicsUInt32 *) pfield, message);
2101  break;
2102  case DBF_FLOAT:
2103  floatToString(*(epicsFloat32 *) pfield, message);
2104  break;
2105  case DBF_DOUBLE:
2106  doubleToString(*(epicsFloat64 *) pfield, message);
2107  break;
2108  case DBF_MENU:
2109  {
2110  dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt;
2111  epicsEnum16 choice_ind;
2112  char *pchoice;
2113 
2114  if (!pfield) {
2115  dbMsgCpy(pdbentry, "Field not found");
2116  return message;
2117  }
2118  choice_ind = *((epicsEnum16 *) pdbentry->pfield);
2119  if (!pdbMenu || choice_ind < 0 || choice_ind >= pdbMenu->nChoice)
2120  return NULL;
2121  pchoice = pdbMenu->papChoiceValue[choice_ind];
2122  dbMsgCpy(pdbentry, pchoice);
2123  }
2124  break;
2125  case DBF_DEVICE:
2126  {
2127  dbDeviceMenu *pdbDeviceMenu;
2128  epicsEnum16 choice_ind;
2129  char *pchoice;
2130 
2131  if (!pfield) {
2132  dbMsgCpy(pdbentry, "Field not found");
2133  return message;
2134  }
2135  pdbDeviceMenu = dbGetDeviceMenu(pdbentry);
2136  if (!pdbDeviceMenu)
2137  return NULL;
2138  choice_ind = *((epicsEnum16 *) pdbentry->pfield);
2139  if (choice_ind<0 || choice_ind>=pdbDeviceMenu->nChoice)
2140  return NULL;
2141  pchoice = pdbDeviceMenu->papChoice[choice_ind];
2142  dbMsgCpy(pdbentry, pchoice);
2143  }
2144  break;
2145  default:
2146  return NULL;
2147  }
2148  return message;
2149 }
2150 
2151 long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
2152 {
2153  short i;
2154 
2155  for (i=0; i<rtyp->no_links; i++) {
2156  dbLinkInfo link_info;
2157  dbFldDes *pflddes = rtyp->papFldDes[rtyp->link_ind[i]];
2158  DBLINK *plink = (DBLINK *)(((char *)prec) + pflddes->offset);
2159  devSup *devsup = NULL;
2160 
2161  plink->precord = prec;
2162 
2163  /* link fields are zero'd on allocation.
2164  * so are effectively CONSTANT, but with constantStr==NULL.
2165  * Here we initialize them to have the correct link type,
2166  * with zero values and empty (but non-NULL) strings.
2167  */
2168 
2169  if(pflddes->isDevLink) {
2170  devsup = (devSup *)ellNth(&rtyp->devList, prec->dtyp+1);
2171  }
2172  if(devsup)
2173  plink->type = devsup->link_type;
2174  else
2175  plink->type = CONSTANT;
2176 
2177  switch (plink->type) {
2178  /* constantStr is allowed to remain NULL if plink->text==NULL
2179  * constantStr==NULL has special meaning in recGblInitConstantLink()
2180  */
2181  case CONSTANT: plink->value.constantStr = NULL; break;
2182  case PV_LINK: plink->value.pv_link.pvname = callocMustSucceed(1, 1, "init PV_LINK"); break;
2183  case JSON_LINK: plink->value.json.string = pNullString; break;
2184  case VME_IO: plink->value.vmeio.parm = pNullString; break;
2185  case CAMAC_IO: plink->value.camacio.parm = pNullString; break;
2186  case AB_IO: plink->value.abio.parm = pNullString; break;
2187  case GPIB_IO: plink->value.gpibio.parm = pNullString; break;
2188  case BITBUS_IO: plink->value.bitbusio.parm = pNullString; break;
2189  case INST_IO: plink->value.instio.string = pNullString; break;
2190  case BBGPIB_IO: plink->value.bbgpibio.parm = pNullString; break;
2191  case VXI_IO: plink->value.vxiio.parm = pNullString; break;
2192  }
2193 
2194  if(!plink->text)
2195  continue;
2196 
2197  if(dbParseLink(plink->text, pflddes->field_type, &link_info)!=0) {
2198  /* This was already parsed once when ->text was set.
2199  * Any syntax error messages were printed at that time.
2200  */
2201 
2202  } else if(dbCanSetLink(plink, &link_info, devsup)!=0) {
2203  errlogPrintf("Error: %s.%s: can't initialize link type %d with \"%s\" (type %d)\n",
2204  prec->name, pflddes->name, plink->type, plink->text, link_info.ltype);
2205 
2206  } else if(dbSetLink(plink, &link_info, devsup)) {
2207  errlogPrintf("Error: %s.%s: failed to initialize link type %d with \"%s\" (type %d)\n",
2208  prec->name, pflddes->name, plink->type, plink->text, link_info.ltype);
2209  }
2210  free(plink->text);
2211  plink->text = NULL;
2212  }
2213  return 0;
2214 }
2215 
2217 {
2218  if (pinfo->ltype == JSON_LINK) {
2219  dbJLinkFree(pinfo->jlink);
2220  pinfo->jlink = NULL;
2221  }
2222  free(pinfo->target);
2223  pinfo->target = NULL;
2224 }
2225 
2226 long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
2227 {
2228  char *pstr;
2229  size_t len;
2230  double value;
2231 
2232  memset(pinfo, 0, sizeof(*pinfo));
2233 
2234  /* Strip leading white space */
2235  while (*str && isspace((int)*str)) str++;
2236 
2237  len = strlen(str);
2238  /* Strip trailing white space */
2239  while (len > 0 && isspace((int)str[len-1])) len--;
2240 
2241  pstr = malloc(len + 1);
2242  if (!pstr)
2243  return S_dbLib_outMem;
2244  pinfo->target = pstr;
2245 
2246  /* Check for Instrument I/O links */
2247  if (*str == '@') {
2248  pinfo->ltype = INST_IO;
2249 
2250  /* Store everything after the '@' */
2251  memcpy(pstr, str+1, --len);
2252  pstr[len] = '\0';
2253  return 0;
2254  }
2255 
2256  /* Store the stripped string */
2257  memcpy(pstr, str, len);
2258  pstr[len] = '\0';
2259 
2260  /* Check for braces => JSON */
2261  if (*str == '{' && str[len-1] == '}') {
2262  if (dbJLinkParse(str, len, ftype, &pinfo->jlink))
2263  goto fail;
2264 
2265  pinfo->ltype = JSON_LINK;
2266  return 0;
2267  }
2268 
2269  /* Check for other HW link types */
2270  if (*pstr == '#') {
2271  int ret;
2272  char junk = 0;
2273  char *parm = strchr(pstr, '@'); /* find start of parm string */
2274 
2275  if (parm) {
2276  *parm++ = '\0'; /* isolate the parm string for later */
2277  len -= (parm - pstr);
2278  }
2279 
2280  /* generalized extraction of ID charactor and integer pairs (eg. "#C15 S14") */
2281  ret = sscanf(pinfo->target, "# %c%d %c%d %c%d %c%d %c%d %c",
2282  &pinfo->hwid[0], &pinfo->hwnums[0],
2283  &pinfo->hwid[1], &pinfo->hwnums[1],
2284  &pinfo->hwid[2], &pinfo->hwnums[2],
2285  &pinfo->hwid[3], &pinfo->hwnums[3],
2286  &pinfo->hwid[4], &pinfo->hwnums[4],
2287  &junk);
2288 
2289  /* ret<0 when pattern not matched
2290  * ret==11 when extra non-space before '@'.
2291  * ret is odd when a number is missing
2292  */
2293  if (ret<0 || ret>10 || ret%2==1) goto fail;
2294 
2295  if (strcmp(pinfo->hwid, "CS")==0) pinfo->ltype = VME_IO;
2296  else if (strcmp(pinfo->hwid, "BCN")==0) pinfo->ltype = CAMAC_IO;
2297  else if (strcmp(pinfo->hwid, "BCNA")==0) pinfo->ltype = CAMAC_IO;
2298  else if (strcmp(pinfo->hwid, "BCNF")==0) pinfo->ltype = CAMAC_IO;
2299  else if (strcmp(pinfo->hwid, "BCNAF")==0) pinfo->ltype = CAMAC_IO;
2300  else if (strcmp(pinfo->hwid, "RMDE")==0) pinfo->ltype = RF_IO;
2301  else if (strcmp(pinfo->hwid, "LACS")==0) pinfo->ltype = AB_IO;
2302  else if (strcmp(pinfo->hwid, "LA")==0) pinfo->ltype = GPIB_IO;
2303  else if (strcmp(pinfo->hwid, "LNPS")==0) pinfo->ltype = BITBUS_IO;
2304  else if (strcmp(pinfo->hwid, "LBG")==0) pinfo->ltype = BBGPIB_IO;
2305  else if (strcmp(pinfo->hwid, "VCS")==0) pinfo->ltype = VXI_IO;
2306  else if (strcmp(pinfo->hwid, "VS")==0) pinfo->ltype = VXI_IO;
2307  else goto fail;
2308 
2309  if (pinfo->ltype != RF_IO) {
2310  if (!parm) {
2311  pinfo->target[0] = '\0';
2312  } else {
2313  /* move parm string to beginning of buffer */
2314  memmove(pinfo->target, parm, len + 1);
2315  }
2316  } else if (!parm && pinfo->ltype == RF_IO) {
2317  /* RF_IO, the string isn't needed at all */
2318  free(pinfo->target);
2319  pinfo->target = NULL;
2320  }
2321  else goto fail;
2322 
2323  return 0;
2324  }
2325 
2326  /* Link is a constant if empty or it holds just a number */
2327  if (len == 0 || epicsParseDouble(pstr, &value, NULL) == 0) {
2328  pinfo->ltype = CONSTANT;
2329  return 0;
2330  }
2331 
2332  /* Link may be an array constant */
2333  if (pstr[0] == '[' && pstr[len-1] == ']' &&
2334  (strchr(pstr, ',') || strchr(pstr, '"'))) {
2335  pinfo->ltype = CONSTANT;
2336  return 0;
2337  }
2338 
2339  pinfo->ltype = PV_LINK;
2340  pstr = strchr(pstr, ' '); /* find start of link modifiers (can't be seperated by tabs) */
2341  if (pstr) {
2342  *pstr++ = '\0'; /* isolate modifiers. pinfo->target is PV name only for re-use in struct pv_link */
2343 
2344  /* Space seperation of modifiers isn't required, and other chars are ignored.
2345  * Order of comparisons resolves ambiguity by checking for
2346  * longer matches first.
2347  * eg. "QQCPPXMSITT" is pvlOptCPP|pvlOptMSI
2348  */
2349 
2350  if (strstr(pstr, "NPP")) pinfo->modifiers = 0;
2351  else if (strstr(pstr, "CPP")) pinfo->modifiers = pvlOptCPP;
2352  else if (strstr(pstr, "PP")) pinfo->modifiers = pvlOptPP;
2353  else if (strstr(pstr, "CA")) pinfo->modifiers = pvlOptCA;
2354  else if (strstr(pstr, "CP")) pinfo->modifiers = pvlOptCP;
2355 
2356  if (strstr(pstr, "NMS")) pinfo->modifiers |= pvlOptNMS;
2357  else if (strstr(pstr, "MSI")) pinfo->modifiers |= pvlOptMSI;
2358  else if (strstr(pstr, "MSS")) pinfo->modifiers |= pvlOptMSS;
2359  else if (strstr(pstr, "MS")) pinfo->modifiers |= pvlOptMS;
2360 
2361  /* filter modifiers based on link type */
2362  switch(ftype) {
2363  case DBF_INLINK: /* accept all */ break;
2364  case DBF_OUTLINK: pinfo->modifiers &= ~pvlOptCPP; break;
2365  case DBF_FWDLINK: pinfo->modifiers &= pvlOptCA; break;
2366  }
2367  }
2368 
2369  return 0;
2370 fail:
2371  dbFreeLinkInfo(pinfo);
2372  return S_dbLib_badField;
2373 }
2374 
2375 long dbCanSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
2376 {
2377  /* Release pinfo resources on failure */
2378  int expected_type = devsup ? devsup->link_type : CONSTANT;
2379 
2380  if (pinfo->ltype == expected_type)
2381  return 0;
2382 
2383  switch (pinfo->ltype) {
2384  case CONSTANT:
2385  case JSON_LINK:
2386  case PV_LINK:
2387  if (expected_type == CONSTANT ||
2388  expected_type == JSON_LINK ||
2389  expected_type == PV_LINK)
2390  return 0;
2391  default:
2392  dbFreeLinkInfo(pinfo);
2393  return 1;
2394  }
2395 }
2396 
2397 static
2398 void dbSetLinkConst(DBLINK *plink, dbLinkInfo *pinfo)
2399 {
2400  plink->type = CONSTANT;
2401  plink->value.constantStr = pinfo->target;
2402 
2403  pinfo->target = NULL;
2404 }
2405 
2406 static
2407 void dbSetLinkPV(DBLINK *plink, dbLinkInfo *pinfo)
2408 {
2409  plink->type = PV_LINK;
2410  plink->value.pv_link.pvname = pinfo->target;
2411  plink->value.pv_link.pvlMask = pinfo->modifiers;
2412 
2413  pinfo->target = NULL;
2414 }
2415 
2416 static
2417 void dbSetLinkJSON(DBLINK *plink, dbLinkInfo *pinfo)
2418 {
2419  plink->type = JSON_LINK;
2420  plink->value.json.string = pinfo->target;
2421  plink->value.json.jlink = pinfo->jlink;
2422 
2423  pinfo->target = NULL;
2424  pinfo->jlink = NULL;
2425 }
2426 
2427 static
2428 void dbSetLinkHW(DBLINK *plink, dbLinkInfo *pinfo)
2429 {
2430  switch(pinfo->ltype) {
2431  case JSON_LINK:
2432  plink->value.json.string = pinfo->target;
2433  break;
2434  case INST_IO:
2435  plink->value.instio.string = pinfo->target;
2436  break;
2437  case VME_IO:
2438  plink->value.vmeio.card = pinfo->hwnums[0];
2439  plink->value.vmeio.signal = pinfo->hwnums[1];
2440  plink->value.vmeio.parm = pinfo->target;
2441  break;
2442  case CAMAC_IO:
2443  plink->value.camacio.b = pinfo->hwnums[0];
2444  plink->value.camacio.c = pinfo->hwnums[1];
2445  plink->value.camacio.n = pinfo->hwnums[2];
2446  plink->value.camacio.a = pinfo->hwnums[3];
2447  plink->value.camacio.f = pinfo->hwnums[4];
2448  plink->value.camacio.parm = pinfo->target;
2449  break;
2450  case RF_IO:
2451  plink->value.rfio.cryo = pinfo->hwnums[0];
2452  plink->value.rfio.micro = pinfo->hwnums[1];
2453  plink->value.rfio.dataset = pinfo->hwnums[2];
2454  plink->value.rfio.element = pinfo->hwnums[3];
2455  break;
2456  case AB_IO:
2457  plink->value.abio.link = pinfo->hwnums[0];
2458  plink->value.abio.adapter = pinfo->hwnums[1];
2459  plink->value.abio.card = pinfo->hwnums[2];
2460  plink->value.abio.signal = pinfo->hwnums[3];
2461  plink->value.abio.parm = pinfo->target;
2462  break;
2463  case GPIB_IO:
2464  plink->value.gpibio.link = pinfo->hwnums[0];
2465  plink->value.gpibio.addr = pinfo->hwnums[1];
2466  plink->value.gpibio.parm = pinfo->target;
2467  break;
2468  case BITBUS_IO:
2469  plink->value.bitbusio.link = pinfo->hwnums[0];
2470  plink->value.bitbusio.node = pinfo->hwnums[1];
2471  plink->value.bitbusio.port = pinfo->hwnums[2];
2472  plink->value.bitbusio.signal = pinfo->hwnums[3];
2473  plink->value.bitbusio.parm = pinfo->target;
2474  break;
2475  case BBGPIB_IO:
2476  plink->value.bbgpibio.link = pinfo->hwnums[0];
2477  plink->value.bbgpibio.bbaddr = pinfo->hwnums[1];
2478  plink->value.bbgpibio.gpibaddr = pinfo->hwnums[2];
2479  plink->value.bbgpibio.parm = pinfo->target;
2480  break;
2481  case VXI_IO:
2482  if(strcmp(pinfo->hwid, "VCS")==0) {
2483  plink->value.vxiio.flag=VXIDYNAMIC;
2484  plink->value.vxiio.frame = pinfo->hwnums[0];
2485  plink->value.vxiio.slot = pinfo->hwnums[1];
2486  plink->value.vxiio.signal = pinfo->hwnums[2];
2487  } else if(strcmp(pinfo->hwid, "VS")==0) {
2488  plink->value.vxiio.flag=VXISTATIC;
2489  plink->value.vxiio.la = pinfo->hwnums[0];
2490  plink->value.vxiio.signal = pinfo->hwnums[1];
2491  } else {
2492  cantProceed("dbSetLinkHW: logic error, unknown VXI_IO variant");
2493  }
2494  plink->value.vxiio.parm = pinfo->target;
2495  break;
2496 
2497  default:
2498  cantProceed("dbSetLinkHW: logic error, unhandled link type");
2499  return;
2500  }
2501 
2502  plink->type = pinfo->ltype;
2503 
2504  pinfo->target = NULL; /* now owned by link field */
2505 }
2506 
2507 long dbSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
2508 {
2509  int expected_type = devsup ? devsup->link_type : CONSTANT;
2510 
2511  if (expected_type == CONSTANT ||
2512  expected_type == JSON_LINK ||
2513  expected_type == PV_LINK) {
2514  switch (pinfo->ltype) {
2515  case CONSTANT:
2516  dbFreeLinkContents(plink);
2517  dbSetLinkConst(plink, pinfo);
2518  break;
2519  case PV_LINK:
2520  dbFreeLinkContents(plink);
2521  dbSetLinkPV(plink, pinfo);
2522  break;
2523  case JSON_LINK:
2524  dbFreeLinkContents(plink);
2525  dbSetLinkJSON(plink, pinfo);
2526  break;
2527  default:
2528  errlogMessage("Warning: dbSetLink: forgot to test with dbCanSetLink() or logic error");
2529  goto fail; /* can't assign HW link */
2530  }
2531  }
2532  else if (expected_type == pinfo->ltype) {
2533  dbFreeLinkContents(plink);
2534  dbSetLinkHW(plink, pinfo);
2535  }
2536  else
2537  goto fail;
2538 
2539  return 0;
2540 fail:
2541  dbFreeLinkInfo(pinfo);
2542  return S_dbLib_badField;
2543 }
2544 
2545 long dbPutString(DBENTRY *pdbentry,const char *pstring)
2546 {
2547  dbFldDes *pflddes = pdbentry->pflddes;
2548  void *pfield = pdbentry->pfield;
2549  long status=0;
2550  int macroIsOk;
2551  int stringHasMacro=FALSE;
2552 
2553  if(!pflddes) return(S_dbLib_flddesNotFound);
2554  macroIsOk = dbIsMacroOk(pdbentry);
2555  stringHasMacro = strstr(pstring,"$(") || strstr(pstring,"${");
2556  if(!macroIsOk && stringHasMacro) {
2557  epicsPrintf("%s.%s Has unexpanded macro\n",
2558  dbGetRecordName(pdbentry),dbGetFieldName(pdbentry));
2559  return(S_dbLib_badField);
2560  }
2561  switch (pflddes->field_type) {
2562  case DBF_STRING:
2563  if(!pfield) return(S_dbLib_fieldNotFound);
2564  if(strlen(pstring) >= (size_t)pflddes->size) return S_dbLib_strLen;
2565  strncpy((char *)pfield, pstring, pflddes->size-1);
2566  ((char *)pfield)[pflddes->size-1] = 0;
2567 
2568  if((pflddes->special == SPC_CALC) && !stringHasMacro) {
2569  char rpcl[RPCL_LEN];
2570  short err;
2571 
2572  if (postfix(pstring,rpcl,&err)) {
2573  status = S_dbLib_badField;
2574  errlogPrintf("%s in CALC expression '%s'\n",
2575  calcErrorStr(err), pstring);
2576  }
2577  }
2578  break;
2579 
2580  case DBF_CHAR:
2581  case DBF_SHORT:
2582  case DBF_LONG:
2583  case DBF_INT64:
2584  case DBF_UCHAR:
2585  case DBF_USHORT:
2586  case DBF_ULONG:
2587  case DBF_UINT64:
2588  case DBF_ENUM:
2589  case DBF_FLOAT:
2590  case DBF_DOUBLE:
2591  case DBF_MENU:
2592  case DBF_DEVICE:
2593  status = dbPutStringNum(pdbentry,pstring);
2594  break;
2595 
2596  case DBF_INLINK:
2597  case DBF_OUTLINK:
2598  case DBF_FWDLINK: {
2599  dbLinkInfo link_info;
2600  DBLINK *plink = (DBLINK *)pfield;
2601 
2602  status = dbParseLink(pstring, pflddes->field_type, &link_info);
2603  if (status) break;
2604 
2605  if (plink->type==CONSTANT && plink->value.constantStr==NULL) {
2606  /* links not yet initialized by dbInitRecordLinks() */
2607  free(plink->text);
2608  plink->text = epicsStrDup(pstring);
2609  dbFreeLinkInfo(&link_info);
2610  } else {
2611  /* assignment after init (eg. autosave restore) */
2612  struct dbCommon *prec = pdbentry->precnode->precord;
2613  devSup *devsup = (devSup *)ellNth(&pdbentry->precordType->devList, prec->dtyp+1);
2614 
2615  status = dbCanSetLink(plink, &link_info, devsup);
2616  if (status == 0)
2617  status = dbSetLink(plink, &link_info, devsup);
2618  }
2619  }
2620  break;
2621 
2622  default:
2623  return S_dbLib_badField;
2624  }
2625 
2626  if (!status && strcmp(pflddes->name, "VAL") == 0) {
2627  DBENTRY dbentry;
2628 
2629  dbCopyEntryContents(pdbentry, &dbentry);
2630  if (!dbFindField(&dbentry, "UDF")) {
2631  dbPutString(&dbentry, "0");
2632  }
2633  dbFinishEntry(&dbentry);
2634  }
2635  return(status);
2636 }
2637 
2638 char * dbVerify(DBENTRY *pdbentry, const char *pstring)
2639 {
2640  dbFldDes *pflddes = pdbentry->pflddes;
2641  char *message = getpMessage(pdbentry);
2642  long status;
2643  union {
2644  epicsInt8 i8;
2645  epicsUInt8 u8;
2646  epicsInt16 i16;
2647  epicsUInt16 u16;
2648  epicsInt32 i32;
2649  epicsUInt32 u32;
2650  epicsInt64 i64;
2651  epicsUInt64 u64;
2652  epicsFloat32 f32;
2653  epicsFloat64 f64;
2654  } val;
2655 
2656  if (!pflddes) {
2657  strcpy(message, "fldDes not found");
2658  return message;
2659  }
2660 
2661  if (strstr(pstring,"$(") || strstr(pstring,"${"))
2662  return NULL;
2663 
2664  switch (pflddes->field_type) {
2665  case DBF_STRING:
2666  {
2667  size_t length = strlen(pstring);
2668 
2669  if (length >= pflddes->size) {
2670  sprintf(message, "String too long, max %d characters",
2671  pflddes->size - 1);
2672  return message;
2673  }
2674 
2675  if (pflddes->special == SPC_CALC) {
2676  char rpcl[RPCL_LEN];
2677  short err;
2678 
2679  status = postfix(pstring, rpcl, &err);
2680  if (status) {
2681  sprintf(message,"%s in CALC expression '%s'",
2682  calcErrorStr(err), pstring);
2683  return message;
2684  }
2685  }
2686 
2687  return NULL;
2688  }
2689 
2690  case DBF_CHAR:
2691  status = epicsParseInt8(pstring, &val.i8, 0, NULL);
2692  break;
2693 
2694  case DBF_UCHAR:
2695  status = epicsParseUInt8(pstring, &val.u8, 0, NULL);
2696  break;
2697 
2698  case DBF_SHORT:
2699  status = epicsParseInt16(pstring, &val.i16, 0, NULL);
2700  break;
2701 
2702  case DBF_ENUM:
2703  case DBF_USHORT:
2704  status = epicsParseUInt16(pstring, &val.u16, 0, NULL);
2705  break;
2706 
2707  case DBF_LONG:
2708  status = epicsParseInt32(pstring, &val.i32, 0, NULL);
2709  break;
2710 
2711  case DBF_ULONG:
2712  status = epicsParseUInt32(pstring, &val.u32, 0, NULL);
2713  break;
2714 
2715  case DBF_INT64:
2716  status = epicsParseInt64(pstring, &val.i64, 0, NULL);
2717  break;
2718 
2719  case DBF_UINT64:
2720  status = epicsParseUInt64(pstring, &val.u64, 0, NULL);
2721  break;
2722 
2723  case DBF_FLOAT:
2724  status = epicsParseFloat32(pstring, &val.f32, NULL);
2725  break;
2726 
2727  case DBF_DOUBLE:
2728  status = epicsParseFloat64(pstring, &val.f64, NULL);
2729  break;
2730 
2731  case DBF_MENU:
2732  {
2733  dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt;
2734  int i;
2735 
2736  if (!pdbMenu)
2737  return NULL;
2738 
2739  for (i = 0; i < pdbMenu->nChoice; i++) {
2740  const char *pchoice = pdbMenu->papChoiceValue[i];
2741 
2742  if (!pchoice)
2743  continue;
2744 
2745  if (strcmp(pchoice, pstring) == 0) {
2746  return NULL;
2747  }
2748  }
2749  }
2750  strcpy(message, "Not a valid menu choice");
2751  return message;
2752 
2753  case DBF_DEVICE:
2754  {
2755  dbDeviceMenu *pdbDeviceMenu = dbGetDeviceMenu(pdbentry);
2756  int i;
2757 
2758  if (!pdbDeviceMenu || pdbDeviceMenu->nChoice == 0)
2759  return NULL;
2760 
2761  for (i = 0; i < pdbDeviceMenu->nChoice; i++) {
2762  const char *pchoice = pdbDeviceMenu->papChoice[i];
2763 
2764  if (!pchoice)
2765  continue;
2766 
2767  if (strcmp(pchoice, pstring) == 0) {
2768  return NULL;
2769  }
2770  }
2771  }
2772  strcpy(message, "Not a valid device type");
2773  return message;
2774 
2775  case DBF_INLINK:
2776  case DBF_OUTLINK:
2777  case DBF_FWDLINK:
2778  return NULL;
2779 
2780  default:
2781  strcpy(message, "Not a valid field type");
2782  return message;
2783  }
2784 
2785  switch (status) {
2786  case 0:
2787  message = NULL;
2788  break;
2789 
2790  case S_stdlib_noConversion:
2791  strcpy(message, "Not a valid integer");
2792  break;
2793 
2794  case S_stdlib_badBase:
2795  strcpy(message, "Internal error (badBase)");
2796  break;
2797 
2798  case S_stdlib_overflow:
2799  strcpy(message, "Number too large for field type");
2800  break;
2801 
2802  case S_stdlib_underflow:
2803  strcpy(message, "Number too small for field type");
2804  break;
2805 
2806  case S_stdlib_extraneous:
2807  strcpy(message, "Extraneous characters after number");
2808  break;
2809 
2810  default:
2811  strcpy(message, "Unknown numeric conversion error");
2812  }
2813  return message;
2814 }
2815 
2816 long dbFirstInfo(DBENTRY *pdbentry)
2817 {
2818  dbRecordNode *precnode = pdbentry->precnode;
2819 
2820  pdbentry->pinfonode = NULL;
2821  if (!precnode) return (S_dbLib_recNotFound);
2822 
2823  pdbentry->pinfonode = (dbInfoNode *)ellFirst(&precnode->infoList);
2824  return (pdbentry->pinfonode ? 0 : S_dbLib_infoNotFound);
2825 }
2826 
2827 long dbNextInfo(DBENTRY *pdbentry)
2828 {
2829  dbRecordNode *precnode = pdbentry->precnode;
2830  dbInfoNode *pinfo;
2831 
2832  if (!precnode) return (S_dbLib_recNotFound);
2833  pinfo = pdbentry->pinfonode;
2834  if (!pinfo) return (S_dbLib_infoNotFound);
2835 
2836  pinfo = (dbInfoNode *)ellNext(&pinfo->node);
2837  pdbentry->pinfonode = pinfo;
2838  return (pinfo ? 0 : S_dbLib_infoNotFound);
2839 }
2840 
2841 long dbNextMatchingInfo(DBENTRY *pdbentry, const char *pattern)
2842 {
2843  long status;
2844 
2845  if (!pdbentry->precordType)
2846  {
2847  status = dbFirstRecordType(pdbentry);
2848  goto first;
2849  }
2850  while(1) {
2851  status = dbNextInfo(pdbentry);
2852  while (status) {
2853  status = dbNextRecord(pdbentry);
2854  while (status) {
2855  status = dbNextRecordType(pdbentry);
2856 first:
2857  if (status) return status;
2858  status = dbFirstRecord(pdbentry);
2859  }
2860  status = dbFirstInfo(pdbentry);
2861  }
2862  if (!pattern || !*pattern) return 0;
2863  if (epicsStrGlobMatch(dbGetInfoName(pdbentry), pattern)) return 0;
2864  }
2865 }
2866 
2867 long dbFindInfo(DBENTRY *pdbentry,const char *name)
2868 {
2869  dbRecordNode *precnode = pdbentry->precnode;
2870  dbInfoNode *pinfo;
2871 
2872  pdbentry->pinfonode = NULL;
2873  if (!precnode) return(S_dbLib_recNotFound);
2874 
2875  pinfo = (dbInfoNode *)ellFirst(&precnode->infoList);
2876  while (pinfo) {
2877  if (!strcmp(pinfo->name, name)) {
2878  pdbentry->pinfonode = pinfo;
2879  return (0);
2880  }
2881  pinfo = (dbInfoNode *)ellNext(&pinfo->node);
2882  }
2883  return (S_dbLib_infoNotFound);
2884 }
2885 
2886 long dbDeleteInfo(DBENTRY *pdbentry)
2887 {
2888  dbRecordNode *precnode = pdbentry->precnode;
2889  dbInfoNode *pinfo = pdbentry->pinfonode;
2890 
2891  if (!precnode) return (S_dbLib_recNotFound);
2892  if (!pinfo) return (S_dbLib_infoNotFound);
2893  ellDelete(&precnode->infoList,&pinfo->node);
2894  free(pinfo->name);
2895  free(pinfo->string);
2896  free(pinfo);
2897  pdbentry->pinfonode = NULL;
2898  return (0);
2899 }
2900 
2901 const char * dbGetInfoName(DBENTRY *pdbentry)
2902 {
2903  dbInfoNode *pinfo = pdbentry->pinfonode;
2904  if (!pinfo) return (NULL);
2905  return (pinfo->name);
2906 }
2907 
2908 const char * dbGetInfoString(DBENTRY *pdbentry)
2909 {
2910  dbInfoNode *pinfo = pdbentry->pinfonode;
2911  if (!pinfo) return (NULL);
2912  return (pinfo->string);
2913 }
2914 
2915 long dbPutInfoString(DBENTRY *pdbentry,const char *string)
2916 {
2917  dbInfoNode *pinfo = pdbentry->pinfonode;
2918  char *newstring;
2919  if (!pinfo) return (S_dbLib_infoNotFound);
2920  newstring = realloc(pinfo->string,1+strlen(string));
2921  if (!newstring) return (S_dbLib_outMem);
2922  strcpy(newstring, string);
2923  pinfo->string = newstring;
2924  return (0);
2925 }
2926 
2927 long dbPutInfoPointer(DBENTRY *pdbentry, void *pointer)
2928 {
2929  dbInfoNode *pinfo = pdbentry->pinfonode;
2930  if (!pinfo) return (S_dbLib_infoNotFound);
2931  pinfo->pointer = pointer;
2932  return (0);
2933 }
2934 
2935 void * dbGetInfoPointer(DBENTRY *pdbentry)
2936 {
2937  dbInfoNode *pinfo = pdbentry->pinfonode;
2938  if (!pinfo) return (NULL);
2939  return (pinfo->pointer);
2940 }
2941 
2942 const char * dbGetInfo(DBENTRY *pdbentry,const char *name)
2943 {
2944  if (dbFindInfo(pdbentry, name)) return NULL;
2945  return dbGetInfoString(pdbentry);
2946 }
2947 
2948 long dbPutInfo(DBENTRY *pdbentry,const char *name,const char *string)
2949 {
2950  dbInfoNode *pinfo;
2951  dbRecordNode *precnode = pdbentry->precnode;
2952  if (!precnode) return (S_dbLib_recNotFound);
2953 
2954  dbFindInfo(pdbentry, name);
2955  pinfo = pdbentry->pinfonode;
2956  if (pinfo) return (dbPutInfoString(pdbentry, string));
2957 
2958  /*Create new info node*/
2959  pinfo = calloc(1,sizeof(dbInfoNode));
2960  if (!pinfo) return (S_dbLib_outMem);
2961  pinfo->name = calloc(1,1+strlen(name));
2962  if (!pinfo->name) {
2963  free(pinfo);
2964  return (S_dbLib_outMem);
2965  }
2966  strcpy(pinfo->name, name);
2967  pinfo->string = calloc(1,1+strlen(string));
2968  if (!pinfo->string) {
2969  free(pinfo->name);
2970  free(pinfo);
2971  return (S_dbLib_outMem);
2972  }
2973  strcpy(pinfo->string, string);
2974  ellAdd(&precnode->infoList,&pinfo->node);
2975  pdbentry->pinfonode = pinfo;
2976  return (0);
2977 }
2978 
2979 brkTable * dbFindBrkTable(dbBase *pdbbase,const char *name)
2980 {
2981  GPHENTRY *pgph;
2982 
2983  pgph = gphFind(pdbbase->pgpHash,name,(void *)&pdbbase->bptList);
2984  if(!pgph) return(NULL);
2985  return((brkTable *)pgph->userPvt);
2986 }
2987 
2989 {
2990  int i;
2991 
2992  for (i=0; i < DBF_NTYPES; i++) {
2993  if (pamapdbfType[i].value == dbfType) {
2994  return pamapdbfType[i].strvalue;
2995  }
2996  }
2997  return "BAD_DBF_TYPE";
2998 }
2999 
3000 int dbFindFieldType(const char *type)
3001 {
3002  int i;
3003 
3004  for (i = 0; i < DBF_NTYPES; i++) {
3005  if (strcmp(type, pamapdbfType[i].strvalue) == 0) {
3006  return pamapdbfType[i].value;
3007  }
3008  }
3009  return -1;
3010 }
3011 
3012 dbMenu * dbFindMenu(dbBase *pdbbase,const char *name)
3013 {
3014  GPHENTRY *pgph;
3015 
3016  pgph = gphFind(pdbbase->pgpHash,name,(void *)&pdbbase->menuList);
3017  if(!pgph) return(NULL);
3018  return((dbMenu *)pgph->userPvt);
3019 }
3020 
3021 char ** dbGetMenuChoices(DBENTRY *pdbentry)
3022 {
3023  dbFldDes *pflddes = pdbentry->pflddes;
3024 
3025  if(!pflddes) return(NULL);
3026  switch (pflddes->field_type) {
3027  case DBF_MENU: {
3028  dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt;
3029 
3030  if(!pdbMenu) return(NULL);
3031  return(pdbMenu->papChoiceValue);
3032  }
3033  case DBF_DEVICE: {
3034  dbDeviceMenu *pdbDeviceMenu;
3035 
3036  pdbDeviceMenu = dbGetDeviceMenu(pdbentry);
3037  if(!pdbDeviceMenu) return(NULL);
3038  return(pdbDeviceMenu->papChoice);
3039  }
3040  default:
3041  return(NULL);
3042  }
3043 }
3044 
3046 {
3047  dbFldDes *pflddes = pdbentry->pflddes;
3048 
3049  if(!pflddes) return(-1);
3050  switch (pflddes->field_type) {
3051  case DBF_MENU: {
3052  dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt;
3053 
3054  if(!pdbMenu) return(0);
3055  return(pdbMenu->nChoice);
3056  }
3057  case DBF_DEVICE: {
3058  dbDeviceMenu *pdbDeviceMenu;
3059 
3060  pdbDeviceMenu = dbGetDeviceMenu(pdbentry);
3061  if(!pdbDeviceMenu) return(0);
3062  return(pdbDeviceMenu->nChoice);
3063  }
3064  default:
3065  break;
3066  }
3067  return (-1);
3068 }
3069 
3070 char * dbGetMenuStringFromIndex(DBENTRY *pdbentry, int index)
3071 {
3072  dbFldDes *pflddes = pdbentry->pflddes;
3073 
3074  if(!pflddes) return(NULL);
3075  switch (pflddes->field_type) {
3076  case DBF_MENU: {
3077  dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt;
3078 
3079  if(!pdbMenu) return(NULL);
3080  if(index<0 || index>=pdbMenu->nChoice) return(NULL);
3081  return(pdbMenu->papChoiceValue[index]);
3082  }
3083  case DBF_DEVICE: {
3084  dbDeviceMenu *pdbDeviceMenu;
3085 
3086  pdbDeviceMenu = dbGetDeviceMenu(pdbentry);
3087  if(!pdbDeviceMenu) return(NULL);
3088  if(index<0 || index>=pdbDeviceMenu->nChoice) return(NULL);
3089  return(pdbDeviceMenu->papChoice[index]);
3090  }
3091  default:
3092  break;
3093  }
3094  return (NULL);
3095 }
3096 
3097 int dbGetMenuIndexFromString(DBENTRY *pdbentry, const char *choice)
3098 {
3099  dbFldDes *pflddes = pdbentry->pflddes;
3100  int ind;
3101  int nChoice = 0;
3102  char **papChoice = NULL;
3103 
3104  if(!pflddes) return(-1);
3105  switch (pflddes->field_type) {
3106  case DBF_MENU: {
3107  dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt;
3108 
3109  if(!pdbMenu) return(-1);
3110  papChoice = pdbMenu->papChoiceValue;
3111  nChoice = pdbMenu->nChoice;
3112  break;
3113  }
3114  case DBF_DEVICE: {
3115  dbDeviceMenu *pdbDeviceMenu;
3116 
3117  pdbDeviceMenu = dbGetDeviceMenu(pdbentry);
3118  if(!pdbDeviceMenu) return(-1);
3119  papChoice = pdbDeviceMenu->papChoice;
3120  nChoice = pdbDeviceMenu->nChoice;
3121  break;
3122  }
3123  default:
3124  return(-1);
3125  }
3126  if(nChoice<=0 || !papChoice) return(-1);
3127  for(ind=0; ind<nChoice; ind++) {
3128  if(strcmp(choice,papChoice[ind])==0) return(ind);
3129  }
3130  return (-1);
3131 }
3132 
3133 drvSup * dbFindDriver(dbBase *pdbbase, const char *name) {
3134  GPHENTRY *pgph = gphFind(pdbbase->pgpHash,name,&pdbbase->drvList);
3135  if (!pgph) return NULL;
3136  return (drvSup *) pgph->userPvt;
3137 }
3138 
3140 {
3141  DBENTRY dbEntry;
3142  DBENTRY *pdbentry= &dbEntry;
3143  dbFldDes *pflddes;
3144  char *rtnval = NULL;
3145  long status;
3146 
3147  pflddes = psave->pflddes;
3148  if(pflddes->field_type !=DBF_DEVICE) return(NULL);
3149  dbCopyEntryContents(psave,pdbentry);
3150  pflddes = pdbentry->pflddes;
3151  status = dbFindField(pdbentry,"INP");
3152  if(status) status = dbFindField(pdbentry,"OUT");
3153  if(!status) rtnval = pdbentry->pflddes->name;
3154  dbFinishEntry(pdbentry);
3155  return(rtnval);
3156 }
3157 
3158 linkSup* dbFindLinkSup(dbBase *pdbbase, const char *name) {
3159  GPHENTRY *pgph = gphFind(pdbbase->pgpHash,name,&pdbbase->linkList);
3160  if (!pgph) return NULL;
3161  return (linkSup *) pgph->userPvt;
3162 }
3163 
3164 int dbGetNLinks(DBENTRY *pdbentry)
3165 {
3166  dbRecordType *precordType = pdbentry->precordType;
3167 
3168  if(!precordType) return(S_dbLib_recordTypeNotFound);
3169  return((int)precordType->no_links);
3170 }
3171 
3172 long dbGetLinkField(DBENTRY *pdbentry, int index)
3173 {
3174  dbRecordType *precordType = pdbentry->precordType;
3175  dbFldDes *pflddes;
3176 
3177  if (!precordType)
3179 
3180  if (index < 0 || index >= precordType->no_links)
3181  return S_dbLib_badLink;
3182 
3183  pdbentry->indfield = precordType->link_ind[index];
3184  pdbentry->pflddes = pflddes = precordType->papFldDes[pdbentry->indfield];
3185  dbGetFieldAddress(pdbentry);
3186  return 0;
3187 }
3188 
3189 void dbDumpPath(DBBASE *pdbbase)
3190 {
3191  ELLLIST *ppathList;
3192  dbPathNode *pdbPathNode;
3193 
3194  if(!pdbbase) {
3195  fprintf(stderr,"pdbbase not specified\n");
3196  return;
3197  }
3198  ppathList = (ELLLIST *)pdbbase->pathPvt;
3199  if(!ppathList || !(pdbPathNode = (dbPathNode *)ellFirst(ppathList))) {
3200  printf("no path defined\n");
3201  return;
3202  }
3203  while(pdbPathNode) {
3204  printf("%s",pdbPathNode->directory);
3205  pdbPathNode = (dbPathNode *)ellNext(&pdbPathNode->node);
3206  if(pdbPathNode) printf("%s", OSI_PATH_LIST_SEPARATOR);
3207  }
3208  printf("\n");
3209  return;
3210 }
3211 
3213  dbBase *pdbbase,const char *precordTypename,int level)
3214 {
3215  if(!pdbbase) {
3216  fprintf(stderr,"pdbbase not specified\n");
3217  return;
3218  }
3219  dbWriteRecordFP(pdbbase,stdout,precordTypename,level);
3220 }
3221 
3222 void dbDumpMenu(dbBase *pdbbase,const char *menuName)
3223 {
3224  if(!pdbbase) {
3225  fprintf(stderr,"pdbbase not specified\n");
3226  return;
3227  }
3228  dbWriteMenuFP(pdbbase,stdout,menuName);
3229 }
3230 
3231 void dbDumpRecordType(DBBASE *pdbbase,const char *recordTypeName)
3232 {
3233  dbRecordType *pdbRecordType;
3234  dbFldDes *pdbFldDes;
3235  int gotMatch;
3236  int i;
3237 
3238  if(!pdbbase) {
3239  fprintf(stderr,"pdbbase not specified\n");
3240  return;
3241  }
3242  for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
3243  pdbRecordType; pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
3244  if(recordTypeName) {
3245  gotMatch = (strcmp(recordTypeName,pdbRecordType->name)==0)
3246  ? TRUE : FALSE;
3247  }else {
3248  gotMatch=TRUE;
3249  }
3250  if(!gotMatch) continue;
3251  printf("name(%s) no_fields(%hd) no_prompt(%hd) no_links(%hd)\n",
3252  pdbRecordType->name,pdbRecordType->no_fields,
3253  pdbRecordType->no_prompt,pdbRecordType->no_links);
3254  printf("index name\tsortind sortname\n");
3255  for(i=0; i<pdbRecordType->no_fields; i++) {
3256  pdbFldDes = pdbRecordType->papFldDes[i];
3257  printf("%5d %s\t%7d %s\n",
3258  i,pdbFldDes->name,
3259  pdbRecordType->sortFldInd[i],pdbRecordType->papsortFldName[i]);
3260  }
3261  printf("link_ind ");
3262  for(i=0; i<pdbRecordType->no_links; i++)
3263  printf(" %hd",pdbRecordType->link_ind[i]);
3264  printf("\n");
3265  printf("indvalFlddes %d name %s\n",pdbRecordType->indvalFlddes,
3266  pdbRecordType->pvalFldDes->name);
3267  printf("rset * %p rec_size %d\n",
3268  (void *)pdbRecordType->prset,pdbRecordType->rec_size);
3269  if(recordTypeName) break;
3270  }
3271 }
3272 
3274  DBBASE *pdbbase,const char *recordTypeName,const char *fname)
3275 {
3276  dbRecordType *pdbRecordType;
3277  dbFldDes *pdbFldDes;
3278  int gotMatch;
3279  int i;
3280  dbRecordAttribute *pAttribute;
3281 
3282  if(!pdbbase) {
3283  fprintf(stderr,"pdbbase not specified\n");
3284  return;
3285  }
3286  for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
3287  pdbRecordType; pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
3288  if(recordTypeName) {
3289  gotMatch = (strcmp(recordTypeName,pdbRecordType->name)==0)
3290  ? TRUE : FALSE;
3291  }else {
3292  gotMatch=TRUE;
3293  }
3294  if(!gotMatch) continue;
3295  printf("recordtype(%s) \n",pdbRecordType->name);
3296  for(i=0; i<pdbRecordType->no_fields; i++) {
3297  int j;
3298 
3299  pdbFldDes = pdbRecordType->papFldDes[i];
3300  if(fname && strcmp(fname,pdbFldDes->name)!=0) continue;
3301  printf(" %s\n", pdbFldDes->name);
3302  printf("\t prompt: %s\n",
3303  (pdbFldDes->prompt ? pdbFldDes->prompt : ""));
3304  printf("\t extra: %s\n",
3305  (pdbFldDes->extra ? pdbFldDes->extra: ""));
3306  printf("\t indRecordType: %hd\n",pdbFldDes->indRecordType);
3307  printf("\t special: %hd ",pdbFldDes->special);
3308  if(pdbFldDes->special) {
3309  for(j=0; j<SPC_NTYPES; j++) {
3310  if(pamapspcType[j].value == pdbFldDes->special) {
3311  printf("%s",pamapspcType[j].strvalue);
3312  break;
3313  }
3314  }
3315  }
3316  printf("\n");
3317  printf("\t field_type: %s\n",
3318  dbGetFieldTypeString(pdbFldDes->field_type));
3319  printf("\tprocess_passive: %u\n",pdbFldDes->process_passive);
3320  printf("\t property: %u\n",pdbFldDes->prop);
3321  printf("\t base: %d\n",pdbFldDes->base);
3322  if(!pdbFldDes->promptgroup) {
3323  printf("\t promptgroup: %d\n",pdbFldDes->promptgroup);
3324  } else {
3325  printf("\t promptgroup: %s\n",
3326  dbGetPromptGroupNameFromKey(pdbbase, pdbFldDes->promptgroup));
3327  }
3328  printf("\t interest: %hd\n", pdbFldDes->interest);
3329  printf("\t as_level: %d\n",pdbFldDes->as_level);
3330  printf("\t initial: %s\n",
3331  (pdbFldDes->initial ? pdbFldDes->initial : ""));
3332  if(pdbFldDes->field_type==DBF_MENU) {
3333  if(pdbFldDes->ftPvt)
3334  printf("\t\t menu: %s\n",
3335  ((dbMenu *)pdbFldDes->ftPvt)->name);
3336  else
3337  printf("\t\t menu: NOT FOUND\n");
3338  }
3339  if(pdbFldDes->field_type==DBF_DEVICE) {
3340  printf("\t ftPvt: %p\n",pdbFldDes->ftPvt);
3341  }
3342  printf("\t size: %hd\n",pdbFldDes->size);
3343  printf("\t offset: %hd\n",pdbFldDes->offset);
3344  }
3345  pAttribute =
3346  (dbRecordAttribute *)ellFirst(&pdbRecordType->attributeList);
3347  while(pAttribute) {
3348  printf("Attribute: name %s value %s\n",
3349  pAttribute->name,pAttribute->value);
3350  pAttribute = (dbRecordAttribute *)ellNext(&pAttribute->node);
3351  }
3352  if(recordTypeName) break;
3353  }
3354 }
3355 
3356 void dbDumpDevice(DBBASE *pdbbase,const char *recordTypeName)
3357 {
3358  dbRecordType *pdbRecordType;
3359  devSup *pdevSup;
3360  int gotMatch;
3361 
3362  if (recordTypeName) {
3363  if (*recordTypeName == 0 || *recordTypeName == '*')
3364  recordTypeName = 0;
3365  }
3366  if(!pdbbase) {
3367  fprintf(stderr,"pdbbase not specified\n");
3368  return;
3369  }
3370  for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
3371  pdbRecordType; pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
3372  if(recordTypeName) {
3373  gotMatch = (strcmp(recordTypeName,pdbRecordType->name)==0)
3374  ? TRUE : FALSE;
3375  }else {
3376  gotMatch=TRUE;
3377  }
3378  if(!gotMatch) continue;
3379  printf("recordtype(%s)\n",pdbRecordType->name);
3380  for(pdevSup = (devSup *)ellFirst(&pdbRecordType->devList);
3381  pdevSup; pdevSup = (devSup *)ellNext(&pdevSup->node)) {
3382  printf(" device name: %s\n",pdevSup->name);
3383  printf("\tchoice: %s\n",pdevSup->choice);
3384  printf("\tlink_type: %d\n",pdevSup->link_type);
3385  printf("\tpdset: %p\n",(void *)pdevSup->pdset);
3386  if (pdevSup->pdset) {
3387  static const char *names[] = {
3388  " - report()",
3389  " - init()",
3390  " - init_record()",
3391  " - get_ioint_info()"
3392  };
3393  int i, n = pdevSup->pdset->number;
3394  DEVSUPFUN *pfunc = &pdevSup->pdset->report;
3395 
3396  printf("\t number: %d\n", n);
3397  for (i = 0; i < n; ++i, ++pfunc) {
3398  const char *name = (i < NELEMENTS(names)) ? names[i] : "";
3399 
3400  printf("\t func %d: %p%s\n", i, (void *)*pfunc, name);
3401  }
3402  }
3403  printf("\tpdsxt: %p\n",(void *)pdevSup->pdsxt);
3404  if (pdevSup->pdsxt) {
3405  printf("\t add_record: %p\n",
3406  (void *)pdevSup->pdsxt->add_record);
3407  printf("\t del_record: %p\n",
3408  (void *)pdevSup->pdsxt->del_record);
3409  }
3410  }
3411  if(recordTypeName) break;
3412  }
3413 }
3414 
3415 void dbDumpDriver(DBBASE *pdbbase)
3416 {
3417  if(!pdbbase) {
3418  fprintf(stderr,"pdbbase not specified\n");
3419  return;
3420  }
3421  dbWriteDriverFP(pdbbase,stdout);
3422 }
3423 
3424 void dbDumpLink(DBBASE *pdbbase)
3425 {
3426  if(!pdbbase) {
3427  fprintf(stderr,"pdbbase not specified\n");
3428  return;
3429  }
3430  dbWriteLinkFP(pdbbase,stdout);
3431 }
3432 
3433 void dbDumpRegistrar(DBBASE *pdbbase)
3434 {
3435  if(!pdbbase) {
3436  fprintf(stderr,"pdbbase not specified\n");
3437  return;
3438  }
3439  dbWriteRegistrarFP(pdbbase,stdout);
3440 }
3441 
3442 void dbDumpFunction(DBBASE *pdbbase)
3443 {
3444  if(!pdbbase) {
3445  fprintf(stderr,"pdbbase not specified\n");
3446  return;
3447  }
3448  dbWriteFunctionFP(pdbbase,stdout);
3449 }
3450 
3451 void dbDumpVariable(DBBASE *pdbbase)
3452 {
3453  if(!pdbbase) {
3454  fprintf(stderr,"pdbbase not specified\n");
3455  return;
3456  }
3457  dbWriteVariableFP(pdbbase,stdout);
3458 }
3459 
3460 void dbDumpBreaktable(DBBASE *pdbbase,const char *name)
3461 {
3462  brkTable *pbrkTable;
3463  brkInt *pbrkInt;
3464  int ind;
3465 
3466  if(!pdbbase) {
3467  fprintf(stderr,"pdbbase not specified\n");
3468  return;
3469  }
3470  for(pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList);
3471  pbrkTable; pbrkTable = (brkTable *)ellNext(&pbrkTable->node)) {
3472  if (name && strcmp(name,pbrkTable->name)!=0) continue;
3473  printf("breaktable(%s) {\n",pbrkTable->name);
3474  pbrkInt = pbrkTable->paBrkInt;
3475  for(ind=0; ind < pbrkTable->number; ind++) {
3476  printf("\traw=%f slope=%e eng=%f\n",
3477  pbrkInt->raw, pbrkInt->slope, pbrkInt->eng);
3478  pbrkInt++;
3479  }
3480  printf("}\n");
3481  }
3482  return;
3483 }
3484 
3485 static char *bus[LINK_NTYPES] = {
3486  "", /* CONSTANT */
3487  NULL, /* PV_LINK */
3488  "VME",
3489  "CAMAC",
3490  "AB",
3491  "GPIB",
3492  "BITBUS",
3493  NULL, /* MACRO_LINK */
3494  NULL, /* JSON_LINK */
3495  NULL, /* PN_LINK */
3496  NULL, /* DB_LINK */
3497  NULL, /* CA_LINK */
3498  "INST",
3499  "BBGPIB",
3500  "VXI"
3501 };
3502 void dbReportDeviceConfig(dbBase *pdbbase, FILE *report)
3503 {
3504  DBENTRY dbentry, *pdbentry = &dbentry;
3505  long status;
3506  FILE *stream = report ? report : stdout;
3507 
3508  if (!pdbbase) {
3509  fprintf(stderr, "dbReportDeviceConfig: pdbbase not specified\n");
3510  return;
3511  }
3512 
3513  dbInitEntry(pdbbase,pdbentry);
3514  status = dbFirstRecordType(pdbentry);
3515  while (!status) {
3516  const int nlinks = dbGetNLinks(pdbentry);
3517 
3518  status = dbFirstRecord(pdbentry);
3519  while (!status) {
3520  int ilink;
3521 
3522  for (ilink=0; ilink<nlinks; ilink++) {
3523  char linkValue[messagesize];
3524  char dtypValue[50];
3525  char cvtValue[40];
3526  struct link *plink;
3527  int linkType;
3528 
3529  status = dbGetLinkField(pdbentry, ilink);
3530  if (status)
3531  continue;
3532 
3533  plink = pdbentry->pfield;
3534  linkType = plink->type;
3535  if (plink->text) { /* Not yet parsed */
3536  dbLinkInfo linfo;
3537 
3538  if (dbParseLink(plink->text, pdbentry->pflddes->field_type, &linfo))
3539  continue;
3540 
3541  linkType = linfo.ltype;
3542  if (linkType && bus[linkType])
3543  strncpy(linkValue, plink->text, messagesize-1);
3544 
3545  dbFreeLinkInfo(&linfo);
3546  }
3547  else {
3548  strncpy(linkValue, dbGetString(pdbentry), messagesize-1);
3549  }
3550 
3551  if (!linkType || !bus[linkType])
3552  continue;
3553  linkValue[messagesize-1] = '\0';
3554 
3555  status = dbFindField(pdbentry, "DTYP");
3556  if (status)
3557  break; /* Next record type */
3558 
3559  strcpy(dtypValue, dbGetString(pdbentry));
3560  status = dbFindField(pdbentry, "LINR");
3561  if (status) {
3562  cvtValue[0] = 0;
3563  }
3564  else {
3565  if (strcmp(dbGetString(pdbentry), "LINEAR") != 0) {
3566  cvtValue[0] = 0;
3567  }
3568  else {
3569  strcpy(cvtValue,"cvt(");
3570  status = dbFindField(pdbentry, "EGUL");
3571  if (!status)
3572  strcat(cvtValue, dbGetString(pdbentry));
3573  status = dbFindField(pdbentry, "EGUF");
3574  if (!status) {
3575  strcat(cvtValue, ",");
3576  strcat(cvtValue, dbGetString(pdbentry));
3577  }
3578  strcat(cvtValue, ")");
3579  }
3580  }
3581  fprintf(stream,"%-8s %-20s %-20s %-20s %-s\n",
3582  bus[linkType], linkValue, dtypValue,
3583  dbGetRecordName(pdbentry), cvtValue);
3584  break;
3585  }
3586  status = dbNextRecord(pdbentry);
3587  }
3588  status = dbNextRecordType(pdbentry);
3589  }
3590  dbFinishEntry(pdbentry);
3591  finishOutstream(stream);
3592  return;
3593 }
char * parm
Definition: link.h:101
struct abio abio
Definition: link.h:182
ELLNODE node
Definition: dbStaticPvt.h:82
char * dbGetStringNum(DBENTRY *pdbentry)
Definition: dbStaticLib.c:2040
long dbWriteDriver(DBBASE *pdbbase, const char *filename)
Definition: dbStaticLib.c:1065
dbDeviceMenu * dbGetDeviceMenu(DBENTRY *pdbentry)
Definition: dbStaticLib.c:336
struct gpibio gpibio
Definition: link.h:183
ELLLIST cdefList
Definition: dbBase.h:150
long dbFirstField(DBENTRY *pdbentry, int dctonly)
Definition: dbStaticLib.c:1316
long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
Definition: dbStaticLib.c:1648
long dbPath(DBBASE *pdbbase, const char *path)
Definition: dbStaticLib.c:657
char ** papChoiceName
Definition: dbBase.h:28
void dbDumpLink(DBBASE *pdbbase)
Definition: dbStaticLib.c:3424
char * dbVerify(DBENTRY *pdbentry, const char *pstring)
Definition: dbStaticLib.c:2638
void dbInitEntry(dbBase *pdbbase, DBENTRY *pdbentry)
Definition: dbStaticLib.c:626
#define SPC_NTYPES
Definition: special.h:42
char ** papChoice
Definition: dbBase.h:57
char * name
Definition: dbBase.h:140
ELLNODE node
Definition: dbBase.h:134
Definition: link.h:174
short promptgroup
Definition: dbBase.h:91
const char * dbGetInfoName(DBENTRY *pdbentry)
Definition: dbStaticLib.c:2901
char * parm
Definition: link.h:155
long dbFirstRecordType(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1198
ELLLIST drvList
Definition: dbBase.h:173
long dbWriteBreaktable(DBBASE *pdbbase, const char *filename)
Definition: dbStaticLib.c:1151
LIBCOM_API const char * calcErrorStr(short error)
Convert an error code to a string.
Definition: postfix.c:493
#define S_dbLib_badField
Definition: dbStaticLib.h:241
#define S_dbLib_recNotFound
Definition: dbStaticLib.h:238
long dbNextInfo(DBENTRY *pdbentry)
Definition: dbStaticLib.c:2827
long dbNextMatchingInfo(DBENTRY *pdbentry, const char *pattern)
Definition: dbStaticLib.c:2841
rset * prset
Definition: dbBase.h:163
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
char * choice
Definition: dbBase.h:41
void * pathPvt
Definition: dbBase.h:181
#define FALSE
Definition: dbDefs.h:32
int dbGetNRecords(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1596
char * jlif_name
Definition: dbBase.h:51
short frame
Definition: link.h:166
#define ellCount(PLIST)
Report the number of nodes in a list.
Definition: ellLib.h:84
PVDENTRY * dbPvdAdd(dbBase *pdbbase, dbRecordType *precordType, dbRecordNode *precnode)
Definition: dbPvdLib.c:105
Definition: dbBase.h:32
short special
Definition: dbBase.h:85
long dbPutRecordAttribute(DBENTRY *pdbentry, const char *name, const char *value)
Definition: dbStaticLib.c:1230
DBENTRY * dbCopyEntry(DBENTRY *pdbentry)
Definition: dbStaticLib.c:640
ELLLIST linkList
Definition: dbBase.h:174
double epicsFloat64
Definition: epicsTypes.h:49
struct jlink * jlink
Definition: dbStaticPvt.h:57
pvd::Status status
int dbFindFieldType(const char *type)
Definition: dbStaticLib.c:3000
An EPICS-specific replacement for ANSI C&#39;s assert.
long dbPutInfoString(DBENTRY *pdbentry, const char *string)
Definition: dbStaticLib.c:2915
struct bitbusio bitbusio
Definition: link.h:184
dbRecordType * precordType
Definition: dbStaticLib.h:35
int i
Definition: scan.c:967
#define S_stdlib_underflow
Definition: epicsStdlib.h:29
STATIC_ASSERT(messagesize >=21)
#define OSI_PATH_LIST_SEPARATOR
Definition: unixFileName.h:23
LIBCOM_API int epicsParseInt64(const char *str, epicsInt64 *to, int base, char **units)
Definition: epicsStdlib.c:281
LIBCOM_API int epicsStdCall LIBCOM_API int epicsStdCall epicsVsnprintf(char *str, size_t size, const char *format, va_list ap)
Definition: osdStdio.c:26
short key
Definition: dbStaticPvt.h:89
int dbIsVisibleRecord(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1640
short adapter
Definition: link.h:127
void * precord
Definition: dbBase.h:116
char * parm
Definition: link.h:111
ELLNODE * ellNth(ELLLIST *pList, int nodeNum)
Find the Nth node in a list.
Definition: ellLib.c:205
void dbFreeEntry(DBENTRY *pdbentry)
Definition: dbStaticLib.c:617
int dbStaticDebug
Definition: dbStaticLib.c:49
long dbFindFieldPart(DBENTRY *pdbentry, const char **ppname)
Definition: dbStaticLib.c:1762
short c
Definition: link.h:107
ELLLIST infoList
Definition: dbBase.h:118
#define S_stdlib_badBase
Definition: epicsStdlib.h:31
#define cvtShortToString(val, str)
Definition: cvtFast.h:70
dbFldDes * pflddes
Definition: dbStaticLib.h:36
long dbWriteLinkFP(DBBASE *pdbbase, FILE *fp)
Definition: dbStaticLib.c:1091
unsigned short epicsUInt16
Definition: epicsTypes.h:41
Driver support routines.
linkSup * dbFindLinkSup(dbBase *pdbbase, const char *name)
Definition: dbStaticLib.c:3158
short link
Definition: link.h:126
The API for the EPICS Calculation Engine.
DBENTRY * dbAllocEntry(dbBase *pdbbase)
Definition: dbStaticLib.c:607
int epicsStrGlobMatch(const char *str, const char *pattern)
Definition: epicsString.c:279
long dbGetLinkField(DBENTRY *pdbentry, int index)
Definition: dbStaticLib.c:3172
long dbFindRecordType(DBENTRY *pdbentry, const char *recordType)
Definition: dbStaticLib.c:1186
ELLLIST recordTypeList
Definition: dbBase.h:172
#define SPC_CALC
Definition: special.h:39
char value[MAX_STRING_SIZE]
Definition: dbBase.h:130
#define S_dbLib_flddesNotFound
Definition: dbStaticLib.h:239
LIBCOM_API int epicsParseInt8(const char *str, epicsInt8 *to, int base, char **units)
Definition: epicsStdlib.c:181
#define S_stdlib_noConversion
Definition: epicsStdlib.h:27
void dbDumpPath(DBBASE *pdbbase)
Definition: dbStaticLib.c:3189
const char * dbGetInfo(DBENTRY *pdbentry, const char *name)
Definition: dbStaticLib.c:2942
DBBASE * pdbbase
Definition: dbStaticLib.h:34
#define printf
Definition: epicsStdio.h:41
short la
Definition: link.h:168
void dbFinishEntry(DBENTRY *pdbentry)
Definition: dbStaticLib.c:632
pvd::StructureConstPtr type
int dbGetMenuIndexFromString(DBENTRY *pdbentry, const char *choice)
Definition: dbStaticLib.c:3097
ELLNODE * ellGet(ELLLIST *pList)
Deletes and returns the first node from a list.
Definition: ellLib.c:147
short * link_ind
Definition: dbBase.h:156
ELLNODE node
Definition: dbBase.h:104
#define S_dbLib_recExists
Definition: dbStaticLib.h:237
void dbPvdFreeMem(dbBase *pdbbase)
Definition: dbPvdLib.c:166
short signal
Definition: link.h:169
unsigned char epicsUInt8
Definition: epicsTypes.h:39
void dbCatString(char **string, int *stringLength, char *src, char *separator)
Definition: dbStaticLib.c:375
struct vxiio vxiio
Definition: link.h:187
void dbFreePath(DBBASE *pdbbase)
Definition: dbStaticLib.c:140
ELLNODE node
Definition: dbStaticPvt.h:88
#define NULL
Definition: catime.c:38
long number
Definition: dbBase.h:75
#define errMessage(S, PM)
Definition: errlog.h:48
dbFldDes * pdbFldDes
Definition: dbBase.h:129
long dbWriteDriverFP(DBBASE *pdbbase, FILE *fp)
Definition: dbStaticLib.c:1076
ELLLIST functionList
Definition: dbBase.h:176
char * parm
Definition: link.h:130
unsigned char port
Definition: link.h:144
long dbWriteFunctionFP(DBBASE *pdbbase, FILE *fp)
Definition: dbStaticLib.c:1121
brkTable * dbFindBrkTable(dbBase *pdbbase, const char *name)
Definition: dbStaticLib.c:2979
long dbInvisibleRecord(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1631
void dbDumpRecord(dbBase *pdbbase, const char *precordTypename, int level)
Definition: dbStaticLib.c:3212
#define str(v)
void dbPvdDelete(dbBase *pdbbase, dbRecordNode *precnode)
Definition: dbPvdLib.c:140
unsigned int epicsUInt32
Definition: epicsTypes.h:43
long dbNextRecordType(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1209
dbfType
Definition: dbFldTypes.h:24
#define S_dbLib_badLink
Definition: dbStaticLib.h:243
#define S_dbLib_strLen
Definition: dbStaticLib.h:246
void * dbGetInfoPointer(DBENTRY *pdbentry)
Definition: dbStaticLib.c:2935
ELLNODE node
Definition: dbBase.h:127
ELLLIST bptList
Definition: dbBase.h:178
void dbDumpBreaktable(DBBASE *pdbbase, const char *name)
Definition: dbStaticLib.c:3460
char * name
Definition: dbBase.h:26
long dbFindRecord(DBENTRY *pdbentry, const char *pname)
Definition: dbStaticLib.c:1559
long number
Definition: devSup.h:141
unsigned char node
Definition: link.h:143
Miscellaneous macro definitions.
void dbDumpDevice(DBBASE *pdbbase, const char *recordTypeName)
Definition: dbStaticLib.c:3356
char * name
Definition: dbBase.h:40
A library to manage storage that is allocated and quickly freed.
short no_aliases
Definition: dbBase.h:155
ELLNODE node
Definition: dbBase.h:146
size_t cvtUInt64ToHexString(epicsUInt64 val, char *pdest)
Definition: cvtFast.c:509
ELLNODE node
Definition: dbBase.h:39
long dbNextRecord(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1583
LIBCOM_API int epicsParseUInt8(const char *str, epicsUInt8 *to, int base, char **units)
Definition: epicsStdlib.c:197
#define DBF_NTYPES
Definition: dbFldTypes.h:44
short f
Definition: link.h:110
dbfType value
Definition: dbFldTypes.h:48
#define S_stdlib_extraneous
Definition: epicsStdlib.h:28
long dbWriteBreaktableFP(DBBASE *pdbbase, FILE *fp)
Definition: dbStaticLib.c:1162
unsigned long long epicsUInt64
Definition: epicsTypes.h:45
void * pfield
Definition: dbStaticLib.h:39
long dbFindRecordPart(DBENTRY *pdbentry, const char **ppname)
Definition: dbStaticLib.c:1533
struct bbgpibio bbgpibio
Definition: link.h:186
long dbPutInfoPointer(DBENTRY *pdbentry, void *pointer)
Definition: dbStaticLib.c:2927
struct instio instio
Definition: link.h:185
LIBCOM_API void epicsStdCall gphDelete(struct gphPvt *pvt, const char *name, void *pvtid)
Definition: gpHashLib.c:142
void dbFreeLinkInfo(dbLinkInfo *pinfo)
Definition: dbStaticLib.c:2216
struct dsxt * pdsxt
Definition: dbBase.h:45
LIBCOM_API void epicsStdCall gphInitPvt(struct gphPvt **ppvt, int tableSize)
Definition: gpHashLib.c:37
dbBase * dbAllocBase(void)
Definition: dbStaticLib.c:401
int dbGetNRecordTypes(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1225
char * dbRecordName(DBENTRY *pdbentry)
Definition: dbStaticRun.c:201
void * userPvt
Definition: gpHash.h:25
short signal
Definition: link.h:129
void dbDumpField(DBBASE *pdbbase, const char *recordTypeName, const char *fname)
Definition: dbStaticLib.c:3273
long dbWriteRecordType(DBBASE *pdbbase, const char *filename, const char *recordTypeName)
Definition: dbStaticLib.c:932
long dbCopyRecord(DBENTRY *pdbentry, const char *newRecordName, int overWriteOK)
Definition: dbStaticLib.c:1708
A doubly-linked list library.
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
Definition: ellLib.c:24
LIBCOM_API GPHENTRY *epicsStdCall gphFind(struct gphPvt *pvt, const char *name, void *pvtid)
Definition: gpHashLib.c:92
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
short interest
Definition: dbBase.h:92
struct dbRecordType * pdbRecordType
Definition: dbBase.h:83
ELLNODE node
Definition: dbBase.h:73
ELLNODE node
Definition: dbBase.h:139
#define EPICS_PRINTF_STYLE(f, a)
size_t cvtInt64ToHexString(epicsInt64 val, char *pdest)
Definition: cvtFast.c:483
#define RPCL_LEN
Definition: dbStaticLib.c:52
#define cvtUshortToString(val, str)
Definition: cvtFast.h:71
short slot
Definition: link.h:167
long dbWriteRecord(DBBASE *ppdbbase, const char *filename, const char *precordTypename, int level)
Definition: dbStaticLib.c:779
maplinkType pamaplinkType[LINK_NTYPES]
Definition: dbStaticLib.c:63
Device support routines.
#define cvtLongToString(val, str)
Definition: cvtFast.h:72
int dbGetNMenuChoices(DBENTRY *pdbentry)
Definition: dbStaticLib.c:3045
#define INC_SIZE
Definition: dbStaticLib.c:374
short card
Definition: link.h:128
float epicsFloat32
Definition: epicsTypes.h:48
short indfield
Definition: dbStaticLib.h:41
struct macro_link macro_link
Definition: link.h:176
short size
Definition: dbBase.h:98
long dbGetAttributePart(DBENTRY *pdbentry, const char **ppname)
Definition: dbStaticLib.c:1277
unsigned int process_passive
Definition: dbBase.h:87
struct dbRecordNode * aliasedRecnode
Definition: dbBase.h:120
long(* add_record)(struct dbCommon *precord)
Definition: devSup.h:122
int flags
Definition: dbBase.h:119
short indvalFlddes
Definition: dbBase.h:160
size_t cvtInt64ToString(epicsInt64 val, char *pdest)
Definition: cvtFast.c:396
void * pointer
Definition: dbBase.h:107
dbRecordNode * precnode
Definition: dbStaticLib.h:37
unsigned char gpibaddr
Definition: link.h:153
short signal
Definition: link.h:100
const char * dbGetInfoString(DBENTRY *pdbentry)
Definition: dbStaticLib.c:2908
long dbNextField(DBENTRY *pdbentry, int dctonly)
Definition: dbStaticLib.c:1323
char ** papsortFldName
Definition: dbBase.h:157
char * dbGetMenuStringFromIndex(DBENTRY *pdbentry, int index)
Definition: dbStaticLib.c:3070
long dbFindInfo(DBENTRY *pdbentry, const char *name)
Definition: dbStaticLib.c:2867
int dbIsAlias(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1700
#define cvtUcharToString(val, str)
Definition: cvtFast.h:69
void dbmfFree(void *mem)
Free the memory allocated by dbmfMalloc.
Definition: dbmf.c:175
short modifiers
Definition: dbStaticPvt.h:50
ctType base
Definition: dbBase.h:90
short dataset
Definition: link.h:119
#define epicsPrintf
Definition: errlog.h:51
LIBCOM_API int epicsParseUInt64(const char *str, epicsUInt64 *to, int base, char **units)
Definition: epicsStdlib.c:299
#define report
Definition: aaiRecord.c:53
LIBCOM_API int epicsParseDouble(const char *str, double *to, char **units)
Definition: epicsStdlib.c:149
short b
Definition: link.h:106
char * text
Definition: dbBase.h:135
void dbDumpMenu(dbBase *pdbbase, const char *menuName)
Definition: dbStaticLib.c:3222
Definition: dbBase.h:48
dbInfoNode * pinfonode
Definition: dbStaticLib.h:38
char ** dbGetMenuChoices(DBENTRY *pdbentry)
Definition: dbStaticLib.c:3021
int dbFollowAlias(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1691
char ** papChoiceValue
Definition: dbBase.h:29
int epicsStrPrintEscaped(FILE *fp, const char *s, size_t len)
Definition: epicsString.c:238
PVDENTRY * dbPvdFind(dbBase *pdbbase, const char *name, size_t lenName)
Definition: dbPvdLib.c:82
struct camacio camacio
Definition: link.h:180
ELLNODE node
Definition: dbBase.h:49
char epicsInt8
Definition: epicsTypes.h:38
long dbDeleteRecord(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1480
ELLLIST devList
Definition: dbBase.h:149
char * directory
Definition: dbStaticPvt.h:83
short addr
Definition: link.h:136
int dbFoundField(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1842
char * dbGetFieldName(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1376
long dbCreateRecord(DBENTRY *pdbentry, const char *precordName)
Definition: dbStaticLib.c:1416
short no_fields
Definition: dbBase.h:152
Definition: dbBase.h:38
char * dbGetRecordName(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1612
ELLLIST guiGroupList
Definition: dbBase.h:180
long dbPutStringNum(DBENTRY *pdbentry, const char *pstring)
Definition: dbStaticRun.c:383
LIBCOM_API void * callocMustSucceed(size_t count, size_t size, const char *msg)
A calloc() that never returns NULL.
Definition: cantProceed.c:22
#define NELEMENTS(A)
Definition: aToIPAddr.c:21
#define S_stdlib_overflow
Definition: epicsStdlib.h:30
#define S_dbLib_outMem
Definition: dbStaticLib.h:248
ELLNODE node
Definition: dbBase.h:115
LIBCOM_API void epicsStdCall gphFreeMem(struct gphPvt *pvt)
Definition: gpHashLib.c:176
char * dbGetPromptGroupNameFromKey(DBBASE *pdbbase, const short key)
Definition: dbStaticLib.c:753
short micro
Definition: link.h:118
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
#define S_dbLib_infoNotFound
Definition: dbStaticLib.h:249
double eng
Definition: makeBpt.c:46
#define stdout
Definition: epicsStdio.h:30
void dbFreeBase(dbBase *pdbbase)
Definition: dbStaticLib.c:419
char * name
Definition: dbStaticPvt.h:90
char * name
Definition: dbBase.h:151
long dbWriteVariableFP(DBBASE *pdbbase, FILE *fp)
Definition: dbStaticLib.c:1136
size_t cvtUInt64ToString(epicsUInt64 val, char *pdest)
Definition: cvtFast.c:384
char * string
Definition: dbBase.h:106
#define epicsParseFloat32(str, to, units)
Definition: epicsStdlib.h:67
void dbDumpVariable(DBBASE *pdbbase)
Definition: dbStaticLib.c:3451
char * message
Definition: dbStaticLib.h:40
short * sortFldInd
Definition: dbBase.h:158
long dbFirstInfo(DBENTRY *pdbentry)
Definition: dbStaticLib.c:2816
#define cvtCharToString(val, str)
Definition: cvtFast.h:68
char * epicsStrDup(const char *s)
Definition: epicsString.c:233
int dbGetNFields(DBENTRY *pdbentry, int dctonly)
Definition: dbStaticLib.c:1359
int dbGetNLinks(DBENTRY *pdbentry)
Definition: dbStaticLib.c:3164
void dbDumpRegistrar(DBBASE *pdbbase)
Definition: dbStaticLib.c:3433
long dbFreeRecord(DBENTRY *pdbentry)
Definition: dbStaticRun.c:174
char * dbGetPrompt(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1400
unsigned char signal
Definition: link.h:145
mapspcType pamapspcType[]
void dbCopyEntryContents(DBENTRY *pfrom, DBENTRY *pto)
Definition: dbStaticLib.c:650
epicsShareExtern mapdbfType pamapdbfType[]
Definition: dbFldTypes.h:51
epicsUInt16 epicsEnum16
Definition: epicsTypes.h:47
unsigned char link
Definition: link.h:151
DEVSUPFUN report
Definition: devSup.h:142
dbRecordNode * precnode
Definition: dbStaticPvt.h:98
ELLLIST menuList
Definition: dbBase.h:171
Definition: dbBase.h:24
int hwnums[5]
Definition: dbStaticPvt.h:54
int errlogMessage(const char *message)
Definition: errlog.c:180
asLevel as_level
Definition: dbBase.h:93
short cryo
Definition: link.h:117
char * parm
Definition: link.h:146
LIBCOM_API int epicsParseInt32(const char *str, epicsInt32 *to, int base, char **units)
Definition: epicsStdlib.c:245
short no_links
Definition: dbBase.h:154
Definition: makeBpt.c:43
long dbAllocRecord(DBENTRY *pdbentry, const char *precordName)
Definition: dbStaticRun.c:69
long(* del_record)(struct dbCommon *precord)
Definition: devSup.h:127
long dbWriteMenu(DBBASE *ppdbbase, const char *filename, const char *menuName)
Definition: dbStaticLib.c:885
short ltype
Definition: dbStaticPvt.h:42
struct ELLNODE * previous
Pointer to previous node in list.
Definition: ellLib.h:47
unsigned int prop
Definition: dbBase.h:88
char * name
Definition: dbBase.h:105
Definition: dbBase.h:63
short no_prompt
Definition: dbBase.h:153
long dbDeleteAliases(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1451
char * dbGetDefault(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1392
short dbGetPromptGroupKeyFromName(DBBASE *pdbbase, const char *name)
Definition: dbStaticLib.c:765
#define MAX_STRING_SIZE
Definition: epicsTypes.h:65
ELLNODE node
Definition: dbBase.h:33
#define messagesize
Definition: dbStaticLib.c:51
void dbReportDeviceConfig(dbBase *pdbbase, FILE *report)
Definition: dbStaticLib.c:3502
long dbGetFieldAddress(DBENTRY *pdbentry)
Definition: dbStaticRun.c:187
int nChoice
Definition: dbBase.h:27
ELLLIST recList
Definition: dbBase.h:148
char * dbGetString(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1845
#define TRUE
Definition: dbDefs.h:27
#define dbCalloc(nobj, size)
Definition: dbStaticLib.h:228
LIBCOM_API int epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units)
Definition: epicsStdlib.c:263
char * strvalue
Definition: dbFldTypes.h:47
long dbWriteRegistrarFP(DBBASE *pdbbase, FILE *fp)
Definition: dbStaticLib.c:1106
LIBCOM_API int epicsParseInt16(const char *str, epicsInt16 *to, int base, char **units)
Definition: epicsStdlib.c:213
long dbWriteRecordFP(DBBASE *pdbbase, FILE *fp, const char *precordTypename, int level)
Definition: dbStaticLib.c:792
#define ellInit(PLIST)
Initialize a list type.
Definition: ellLib.h:76
long(* DEVSUPFUN)()
Definition: devSup.h:135
void dbDumpDriver(DBBASE *pdbbase)
Definition: dbStaticLib.c:3415
void dbFreeLinkContents(struct link *plink)
Definition: dbStaticLib.c:109
char * constantStr
Definition: link.h:175
unsigned int isDevLink
Definition: dbBase.h:89
void ellInsert(ELLLIST *plist, ELLNODE *pPrev, ELLNODE *pNode)
Inserts a node into a list immediately after a specific node.
Definition: ellLib.c:178
void * ftPvt
Definition: dbBase.h:96
LIBCOM_API void cantProceed(const char *msg,...)
Definition: cantProceed.c:54
Definition: dbBase.h:170
short n
Definition: link.h:108
dbFldDes * pvalFldDes
Definition: dbBase.h:159
dbFldDes ** papFldDes
Definition: dbBase.h:161
dbRecordType * precordType
Definition: dbStaticPvt.h:97
long dbFirstRecord(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1569
#define SPC_ATTRIBUTE
Definition: special.h:31
int dbGetPromptGroup(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1408
long dbFreeRecords(DBBASE *pdbbase)
Definition: dbStaticLib.c:1510
short link
Definition: link.h:135
if(yy_init)
Definition: scan.c:972
const char * dbGetFieldTypeString(int dbfType)
Definition: dbStaticLib.c:2988
drvSup * dbFindDriver(dbBase *pdbbase, const char *name)
Definition: dbStaticLib.c:3133
unsigned char link
Definition: link.h:142
#define DBRN_FLAGS_HASALIAS
Definition: dbBase.h:112
long dbFindField(DBENTRY *pdbentry, const char *pname)
Definition: dbStaticLib.c:1828
struct rfio rfio
Definition: link.h:181
short card
Definition: link.h:99
char * extra
Definition: dbBase.h:82
ELLLIST filterList
Definition: dbBase.h:179
struct brkInt * paBrkInt
Definition: dbBase.h:76
char * dbGetRelatedField(DBENTRY *psave)
Definition: dbStaticLib.c:3139
long dbWriteDevice(DBBASE *pdbbase, const char *filename)
Definition: dbStaticLib.c:1023
char * recordname
Definition: dbBase.h:117
short flag
Definition: link.h:165
char * initial
Definition: dbBase.h:94
long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
Definition: dbStaticLib.c:2151
void dbPvdInitPvt(dbBase *pdbbase)
Definition: dbPvdLib.c:63
Routines for code that can&#39;t continue or return after an error.
#define stderr
Definition: epicsStdio.h:32
unsigned char bbaddr
Definition: link.h:152
char * prompt
Definition: dbBase.h:80
char * name
Definition: dbBase.h:81
short epicsInt16
Definition: epicsTypes.h:40
char * strvalue
Definition: link.h:45
LIBCOM_API int epicsParseUInt16(const char *str, epicsUInt16 *to, int base, char **units)
Definition: epicsStdlib.c:229
long dbPutString(DBENTRY *pdbentry, const char *pstring)
Definition: dbStaticLib.c:2545
long dbVisibleRecord(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1622
long dbAddPath(DBBASE *pdbbase, const char *path)
Definition: dbStaticLib.c:665
char * type
Definition: dbBase.h:141
const std::string pname
LIBCOM_API long postfix(const char *psrc, char *pout, short *perror)
Compile an infix expression into postfix byte-code.
Definition: postfix.c:209
dbMenu * dbFindMenu(dbBase *pdbbase, const char *name)
Definition: dbStaticLib.c:3012
int dbIsMacroOk(DBENTRY *pdbentry)
Definition: dbStaticRun.c:217
#define S_dbLib_fieldNotFound
Definition: dbStaticLib.h:240
int dbGetFieldDbfType(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1384
List header type.
Definition: ellLib.h:56
ELLLIST registrarList
Definition: dbBase.h:175
long dbDeleteInfo(DBENTRY *pdbentry)
Definition: dbStaticLib.c:2886
#define S_dbLib_nameLength
Definition: dbStaticLib.h:244
char * target
Definition: dbStaticPvt.h:47
int prec
Definition: reader.c:29
long dbWriteRecordTypeFP(DBBASE *pdbbase, FILE *fp, const char *recordTypeName)
Definition: dbStaticLib.c:944
int nChoice
Definition: dbBase.h:56
struct pv_link pv_link
Definition: link.h:178
ELLNODE node
Definition: dbBase.h:25
char * parm
Definition: link.h:170
struct json_link json
Definition: link.h:177
ELLLIST attributeList
Definition: dbBase.h:147
long dbWriteMenuFP(DBBASE *pdbbase, FILE *fp, const char *menuName)
Definition: dbStaticLib.c:897
char * string
Definition: link.h:160
void ellDelete(ELLLIST *pList, ELLNODE *pNode)
Deletes a node from a list.
Definition: ellLib.c:75
Definition: dbBase.h:133
unsigned short offset
Definition: dbBase.h:100
short a
Definition: link.h:109
long dbWriteDeviceFP(DBBASE *pdbbase, FILE *fp)
Definition: dbStaticLib.c:1034
struct vmeio vmeio
Definition: link.h:179
#define DBRN_FLAGS_VISIBLE
Definition: dbBase.h:110
long dbPutInfo(DBENTRY *pdbentry, const char *name, const char *string)
Definition: dbStaticLib.c:2948
struct gphPvt * pgpHash
Definition: dbBase.h:183
void * dbmfMalloc(size_t size)
Allocate memory.
Definition: dbmf.c:97
short element
Definition: link.h:120
long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
Definition: dbStaticLib.c:2226
dbfType field_type
Definition: dbBase.h:86
void dbDumpFunction(DBBASE *pdbbase)
Definition: dbStaticLib.c:3442
char * name
Definition: dbBase.h:34
#define cvtUlongToString(val, str)
Definition: cvtFast.h:73
int epicsInt32
Definition: epicsTypes.h:42
void dbDumpRecordType(DBBASE *pdbbase, const char *recordTypeName)
Definition: dbStaticLib.c:3231
char * parm
Definition: link.h:137
#define S_dbLib_recordTypeNotFound
Definition: dbStaticLib.h:236
char hwid[6]
Definition: dbStaticPvt.h:53
#define epicsParseFloat64(str, to, units)
Definition: epicsStdlib.h:68
char * dbGetRecordTypeName(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1220
char * name
Definition: dbBase.h:50
long dbGetRecordAttribute(DBENTRY *pdbentry, const char *pname)
Definition: dbStaticLib.c:1311
long long epicsInt64
Definition: epicsTypes.h:44
#define DBRN_FLAGS_ISALIAS
Definition: dbBase.h:111
int rec_size
Definition: dbBase.h:164
ELLLIST variableList
Definition: dbBase.h:177
long dbCanSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
Definition: dbStaticLib.c:2375
double raw
Definition: makeBpt.c:44
char * name
Definition: dbBase.h:74
long dbSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
Definition: dbStaticLib.c:2507
short indRecordType
Definition: dbBase.h:84
int dbGetNAliases(DBENTRY *pdbentry)
Definition: dbStaticLib.c:1604
double slope
Definition: makeBpt.c:45
int link_type
Definition: dbBase.h:42
epicsShareFunc int dbIsDefaultValue(DBENTRY *pdbentry)
Definition: dbStaticRun.c:219
dset * pdset
Definition: dbBase.h:44
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89