Files
epics-base/src/ioc/dbStatic/dbLexRoutines.c
Andrew Johnson 8b616ba00a Merged changes from 3.14 branch
Includes everything up to revno 12352 on 2012-07-31
2012-07-31 14:04:38 -05:00

1051 lines
29 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*************************************************************************\
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* $Revision-Id$ */
/* Author: Marty Kraimer Date: 13JUL95*/
/*The routines in this module are serially reusable NOT reentrant*/
#include <epicsStdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "dbmf.h"
#include "dbDefs.h"
#include "epicsPrint.h"
#include "errMdef.h"
#include "ellLib.h"
#include "gpHash.h"
#include "freeList.h"
#include "guigroup.h"
#include "special.h"
#include "macLib.h"
#include "epicsString.h"
#include "epicsExport.h"
#define epicsExportSharedSymbols
#include "dbFldTypes.h"
#include "link.h"
#include "dbStaticLib.h"
#include "dbStaticPvt.h"
/*global declarations*/
epicsShareDef char *makeDbdDepends=0;
epicsShareDef int dbRecordsOnceOnly=0;
epicsExportAddress(int,dbRecordsOnceOnly);
epicsShareDef int dbBptNotMonotonic=0;
epicsExportAddress(int,dbBptNotMonotonic);
/*private routines */
static void yyerrorAbort(char *str);
static void allocTemp(void *pvoid);
static void *popFirstTemp(void);
static void *getLastTemp(void);
static int db_yyinput(char *buf,int max_size);
static void dbIncludePrint(void);
static void dbPathCmd(char *path);
static void dbAddPathCmd(char *path);
static void dbIncludeNew(char *include_file);
static void dbMenuHead(char *name);
static void dbMenuChoice(char *name,char *value);
static void dbMenuBody(void);
static void dbRecordtypeHead(char *name);
static void dbRecordtypeBody(void);
static void dbRecordtypeFieldHead(char *name,char *type);
static void dbRecordtypeFieldItem(char *name,char *value);
static void dbDevice(char *recordtype,char *linktype,
char *dsetname,char *choicestring);
static void dbDriver(char *name);
static void dbRegistrar(char *name);
static void dbFunction(char *name);
static void dbVariable(char *name, char *type);
static void dbBreakHead(char *name);
static void dbBreakItem(char *value);
static void dbBreakBody(void);
static void dbRecordHead(char *recordType,char*name,int visible);
static void dbRecordField(char *name,char *value);
static void dbRecordBody(void);
/*private declarations*/
#define MY_BUFFER_SIZE 1024
static char *my_buffer=NULL;
static char *mac_input_buffer=NULL;
static char *my_buffer_ptr=NULL;
static MAC_HANDLE *macHandle = NULL;
typedef struct inputFile{
ELLNODE node;
char *path;
char *filename;
FILE *fp;
int line_num;
}inputFile;
static ELLLIST inputFileList = ELLLIST_INIT;
static inputFile *pinputFileNow = NULL;
static DBBASE *pdbbase = NULL;
typedef struct tempListNode {
ELLNODE node;
void *item;
}tempListNode;
static ELLLIST tempList = ELLLIST_INIT;
static void *freeListPvt = NULL;
static int duplicate = FALSE;
static void yyerrorAbort(char *str)
{
yyerror(str);
yyAbort = TRUE;
while (ellCount(&tempList))
popFirstTemp();
}
static void allocTemp(void *pvoid)
{
tempListNode *ptempListNode;
ptempListNode = freeListCalloc(freeListPvt);
ptempListNode->item = pvoid;
ellAdd(&tempList,&ptempListNode->node);
}
static void *popFirstTemp(void)
{
tempListNode *ptempListNode;
void *ptemp;
ptempListNode = (tempListNode *)ellFirst(&tempList);
ptemp = ptempListNode->item;
ellDelete(&tempList,(ELLNODE *)ptempListNode);
freeListFree(freeListPvt,ptempListNode);
return(ptemp);
}
static void *getLastTemp(void)
{
tempListNode *ptempListNode;
ptempListNode = (tempListNode *)ellLast(&tempList);
return(ptempListNode->item);
}
static char *dbOpenFile(DBBASE *pdbbase,const char *filename,FILE **fp)
{
ELLLIST *ppathList = (ELLLIST *)pdbbase->pathPvt;
dbPathNode *pdbPathNode;
char *fullfilename;
*fp = 0;
if (!filename) return 0;
if (!ppathList || ellCount(ppathList) == 0 ||
strchr(filename, '/') || strchr(filename, '\\')) {
*fp = fopen(filename, "r");
if (*fp && makeDbdDepends)
fprintf(stdout, "%s:%s \n", makeDbdDepends, filename);
return 0;
}
pdbPathNode = (dbPathNode *)ellFirst(ppathList);
while (pdbPathNode) {
fullfilename = dbMalloc(strlen(pdbPathNode->directory) +
strlen(filename) + 2);
strcpy(fullfilename, pdbPathNode->directory);
strcat(fullfilename, "/");
strcat(fullfilename, filename);
*fp = fopen(fullfilename, "r");
if (*fp && makeDbdDepends)
fprintf(stdout, "%s:%s \n", makeDbdDepends, fullfilename);
free((void *)fullfilename);
if (*fp) return pdbPathNode->directory;
pdbPathNode = (dbPathNode *)ellNext(&pdbPathNode->node);
}
return 0;
}
static void freeInputFileList(void)
{
inputFile *pinputFileNow;
while((pinputFileNow=(inputFile *)ellFirst(&inputFileList))) {
if(fclose(pinputFileNow->fp))
errPrintf(0,__FILE__, __LINE__,
"Closing file %s",pinputFileNow->filename);
free((void *)pinputFileNow->filename);
ellDelete(&inputFileList,(ELLNODE *)pinputFileNow);
free((void *)pinputFileNow);
}
}
static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
const char *path,const char *substitutions)
{
long status;
inputFile *pinputFile = NULL;
char *penv;
char **macPairs;
if(*ppdbbase == 0) *ppdbbase = dbAllocBase();
pdbbase = *ppdbbase;
if(path && strlen(path)>0) {
dbPath(pdbbase,path);
} else {
penv = getenv("EPICS_DB_INCLUDE_PATH");
if(penv) {
dbPath(pdbbase,penv);
} else {
dbPath(pdbbase,".");
}
}
my_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char));
freeListInitPvt(&freeListPvt,sizeof(tempListNode),100);
if(substitutions) {
if(macCreateHandle(&macHandle,NULL)) {
epicsPrintf("macCreateHandle error\n");
status = -1;
goto cleanup;
}
macParseDefns(macHandle,(char *)substitutions,&macPairs);
if(macPairs ==NULL) {
macDeleteHandle(macHandle);
macHandle = NULL;
} else {
macInstallMacros(macHandle,macPairs);
free((void *)macPairs);
mac_input_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char));
}
}
pinputFile = dbCalloc(1,sizeof(inputFile));
if(filename) {
pinputFile->filename = macEnvExpand(filename);
}
if(!fp) {
FILE *fp1;
if(pinputFile->filename) pinputFile->path = dbOpenFile(pdbbase,pinputFile->filename,&fp1);
if(!pinputFile->filename || !fp1) {
errPrintf(0,__FILE__, __LINE__,
"dbRead opening file %s",pinputFile->filename);
free((void *)pinputFile->filename);
free((void *)pinputFile);
status = -1;
goto cleanup;
}
pinputFile->fp = fp1;
} else {
pinputFile->fp = fp;
}
pinputFile->line_num = 0;
pinputFileNow = pinputFile;
my_buffer[0] = '\0';
my_buffer_ptr = my_buffer;
ellAdd(&inputFileList,&pinputFile->node);
status = pvt_yy_parse();
dbFreePath(pdbbase);
if(!status) { /*add RTYP and VERS as an attribute */
DBENTRY dbEntry;
DBENTRY *pdbEntry = &dbEntry;
long localStatus;
dbInitEntry(pdbbase,pdbEntry);
localStatus = dbFirstRecordType(pdbEntry);
while(!localStatus) {
localStatus = dbPutRecordAttribute(pdbEntry,"RTYP",
dbGetRecordTypeName(pdbEntry));
if(!localStatus) {
localStatus = dbPutRecordAttribute(pdbEntry,"VERS",
"none specified");
}
if(localStatus) {
fprintf(stderr,"dbPutRecordAttribute status %ld\n",status);
} else {
localStatus = dbNextRecordType(pdbEntry);
}
}
dbFinishEntry(pdbEntry);
}
cleanup:
if(macHandle) macDeleteHandle(macHandle);
macHandle = NULL;
if(mac_input_buffer) free((void *)mac_input_buffer);
mac_input_buffer = NULL;
if(freeListPvt) freeListCleanup(freeListPvt);
freeListPvt = NULL;
if(my_buffer) free((void *)my_buffer);
my_buffer = NULL;
freeInputFileList();
return(status);
}
long dbReadDatabase(DBBASE **ppdbbase,const char *filename,
const char *path,const char *substitutions)
{return (dbReadCOM(ppdbbase,filename,0,path,substitutions));}
long dbReadDatabaseFP(DBBASE **ppdbbase,FILE *fp,
const char *path,const char *substitutions)
{return (dbReadCOM(ppdbbase,0,fp,path,substitutions));}
static int db_yyinput(char *buf, int max_size)
{
int l,n;
char *fgetsRtn;
if(yyAbort) return(0);
if(*my_buffer_ptr==0) {
while(TRUE) { /*until we get some input*/
if(macHandle) {
fgetsRtn = fgets(mac_input_buffer,MY_BUFFER_SIZE,
pinputFileNow->fp);
if(fgetsRtn) {
n = macExpandString(macHandle,mac_input_buffer,
my_buffer,MY_BUFFER_SIZE);
if(n<0) {
errPrintf(0,__FILE__, __LINE__,
"macExpandString failed for file %s",
pinputFileNow->filename);
}
}
} else {
fgetsRtn = fgets(my_buffer,MY_BUFFER_SIZE,pinputFileNow->fp);
}
if(fgetsRtn) break;
if(fclose(pinputFileNow->fp))
errPrintf(0,__FILE__, __LINE__,
"Closing file %s",pinputFileNow->filename);
free((void *)pinputFileNow->filename);
ellDelete(&inputFileList,(ELLNODE *)pinputFileNow);
free((void *)pinputFileNow);
pinputFileNow = (inputFile *)ellLast(&inputFileList);
if(!pinputFileNow) return(0);
}
if(dbStaticDebug) fprintf(stderr,"%s",my_buffer);
pinputFileNow->line_num++;
my_buffer_ptr = &my_buffer[0];
}
l = strlen(my_buffer_ptr);
n = (l<=max_size ? l : max_size);
memcpy(buf,my_buffer_ptr,n);
my_buffer_ptr += n;
return(n);
}
static void dbIncludePrint(void)
{
inputFile *pinputFile = pinputFileNow;
while (pinputFile) {
epicsPrintf(" in");
if (pinputFile->path)
epicsPrintf(" path \"%s\" ",pinputFile->path);
if (pinputFile->filename) {
epicsPrintf(" file \"%s\"",pinputFile->filename);
} else {
epicsPrintf(" standard input");
}
epicsPrintf(" line %d\n",pinputFile->line_num);
pinputFile = (inputFile *)ellPrevious(&pinputFile->node);
}
return;
}
static void dbPathCmd(char *path)
{
dbPath(pdbbase,path);
}
static void dbAddPathCmd(char *path)
{
dbAddPath(pdbbase,path);
}
static void dbIncludeNew(char *filename)
{
inputFile *pinputFile;
FILE *fp;
pinputFile = dbCalloc(1,sizeof(inputFile));
pinputFile->filename = macEnvExpand(filename);
pinputFile->path = dbOpenFile(pdbbase, pinputFile->filename, &fp);
if (!fp) {
epicsPrintf("Can't open include file \"%s\"\n", filename);
yyerror(NULL);
free((void *)pinputFile->filename);
free((void *)pinputFile);
return;
}
pinputFile->fp = fp;
ellAdd(&inputFileList,&pinputFile->node);
pinputFileNow = pinputFile;
}
static void dbMenuHead(char *name)
{
dbMenu *pdbMenu;
GPHENTRY *pgphentry;
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->menuList);
if(pgphentry) {
duplicate = TRUE;
return;
}
if(ellCount(&tempList)) yyerrorAbort("dbMenuHead: tempList not empty");
pdbMenu = dbCalloc(1,sizeof(dbMenu));
pdbMenu->name = epicsStrDup(name);
allocTemp(pdbMenu);
}
static void dbMenuChoice(char *name,char *value)
{
if(duplicate) return;
allocTemp(epicsStrDup(name));
allocTemp(epicsStrDup(value));
}
static void dbMenuBody(void)
{
dbMenu *pnewMenu;
dbMenu *pMenu;
int nChoice;
int i;
GPHENTRY *pgphentry;
if(duplicate) {
duplicate = FALSE;
return;
}
pnewMenu = (dbMenu *)popFirstTemp();
pnewMenu->nChoice = nChoice = ellCount(&tempList)/2;
pnewMenu->papChoiceName = dbCalloc(pnewMenu->nChoice,sizeof(char *));
pnewMenu->papChoiceValue = dbCalloc(pnewMenu->nChoice,sizeof(char *));
for(i=0; i<nChoice; i++) {
pnewMenu->papChoiceName[i] = (char *)popFirstTemp();
pnewMenu->papChoiceValue[i] = (char *)popFirstTemp();
}
if(ellCount(&tempList)) yyerrorAbort("dbMenuBody: tempList not empty");
/* Add menu in sorted order */
pMenu = (dbMenu *)ellFirst(&pdbbase->menuList);
while(pMenu && strcmp(pMenu->name,pnewMenu->name) >0 )
pMenu = (dbMenu *)ellNext(&pMenu->node);
if(pMenu)
ellInsert(&pdbbase->menuList,ellPrevious(&pMenu->node),&pnewMenu->node);
else
ellAdd(&pdbbase->menuList,&pnewMenu->node);
pgphentry = gphAdd(pdbbase->pgpHash,pnewMenu->name,&pdbbase->menuList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
} else {
pgphentry->userPvt = pnewMenu;
}
}
static void dbRecordtypeHead(char *name)
{
dbRecordType *pdbRecordType;
GPHENTRY *pgphentry;
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->recordTypeList);
if(pgphentry) {
duplicate = TRUE;
return;
}
pdbRecordType = dbCalloc(1,sizeof(dbRecordType));
pdbRecordType->name = epicsStrDup(name);
if (pdbbase->loadCdefs) ellInit(&pdbRecordType->cdefList);
if(ellCount(&tempList))
yyerrorAbort("dbRecordtypeHead tempList not empty");
allocTemp(pdbRecordType);
}
static void dbRecordtypeFieldHead(char *name,char *type)
{
dbFldDes *pdbFldDes;
int i;
if(duplicate) return;
pdbFldDes = dbCalloc(1,sizeof(dbFldDes));
allocTemp(pdbFldDes);
pdbFldDes->name = epicsStrDup(name);
pdbFldDes->as_level = ASL1;
for(i=0; i<DBF_NTYPES; i++) {
if(strcmp(type,pamapdbfType[i].strvalue)==0) {
pdbFldDes->field_type = pamapdbfType[i].value;
return;
}
}
yyerrorAbort("Illegal Field Type");
}
static void dbRecordtypeFieldItem(char *name,char *value)
{
dbFldDes *pdbFldDes;
if(duplicate) return;
pdbFldDes = (dbFldDes *)getLastTemp();
if(strcmp(name,"asl")==0) {
if(strcmp(value,"ASL0")==0) {
pdbFldDes->as_level = ASL0;
} else if(strcmp(value,"ASL1")==0) {
pdbFldDes->as_level = ASL1;
} else {
yyerror("Illegal Access Security value: Must be ASL0 or ASL1");
}
return;
}
if(strcmp(name,"initial")==0) {
pdbFldDes->initial = epicsStrDup(value);
return;
}
if(strcmp(name,"promptgroup")==0) {
int i;
for(i=0; i<GUI_NTYPES; i++) {
if(strcmp(value,pamapguiGroup[i].strvalue)==0) {
pdbFldDes->promptgroup = pamapguiGroup[i].value;
return;
}
}
yyerror("Illegal promptgroup. See guigroup.h for legal values");
return;
}
if(strcmp(name,"prompt")==0) {
pdbFldDes->prompt = epicsStrDup(value);
return;
}
if(strcmp(name,"special")==0) {
int i;
for(i=0; i<SPC_NTYPES; i++) {
if(strcmp(value,pamapspcType[i].strvalue)==0) {
pdbFldDes->special = pamapspcType[i].value;
return;
}
}
if(sscanf(value,"%hd",&pdbFldDes->special)==1) {
return;
}
yyerror("Illegal special value.");
return;
}
if(strcmp(name,"pp")==0) {
if((strcmp(value,"YES")==0) || (strcmp(value,"TRUE")==0)) {
pdbFldDes->process_passive = TRUE;
} else if((strcmp(value,"NO")==0) || (strcmp(value,"FALSE")==0)) {
pdbFldDes->process_passive = FALSE;
} else {
yyerror("Illegal value. Must be NO or YES");
}
return;
}
if(strcmp(name,"interest")==0) {
if(sscanf(value,"%hd",&pdbFldDes->interest)!=1)
yyerror("Illegal value. Must be integer");
return;
}
if(strcmp(name,"base")==0) {
if(strcmp(value,"DECIMAL")==0) {
pdbFldDes->base = CT_DECIMAL;
} else if(strcmp(value,"HEX")==0) {
pdbFldDes->base = CT_HEX;
} else {
yyerror("Illegal value. Must be CT_DECIMAL or CT_HEX");
}
return;
}
if(strcmp(name,"size")==0) {
if(sscanf(value,"%hd",&pdbFldDes->size)!=1)
yyerror("Illegal value. Must be integer");
return;
}
if(strcmp(name,"extra")==0) {
pdbFldDes->extra = epicsStrDup(value);
return;
}
if(strcmp(name,"menu")==0) {
pdbFldDes->ftPvt = (dbMenu *)dbFindMenu(pdbbase,value);
if(!pdbbase->ignoreMissingMenus && !pdbFldDes->ftPvt)
yyerrorAbort("menu not found");
return;
}
}
static void dbRecordtypeCdef(char *text) {
dbText *pdbCdef;
tempListNode *ptempListNode;
dbRecordType *pdbRecordType;
if (!pdbbase->loadCdefs || duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbRecordType = ptempListNode->item;
pdbCdef = dbCalloc(1,sizeof(dbText));
if (text[0] == ' ') text++; /* strip leading space if present */
pdbCdef->text = epicsStrDup(text);
ellAdd(&pdbRecordType->cdefList, &pdbCdef->node);
return;
}
static void dbRecordtypeBody(void)
{
dbRecordType *pdbRecordType;
dbFldDes *pdbFldDes;
int i,j,ilink;
GPHENTRY *pgphentry;
int no_fields,no_prompt,no_links;
dbfType field_type;
char *psortFldNameTemp;
short psortFldIndTemp;
char **papsortFldName;
short *sortFldInd;
if(duplicate) {
duplicate = FALSE;
return;
}
pdbRecordType= (dbRecordType *)popFirstTemp();
pdbRecordType->no_fields = no_fields = ellCount(&tempList);
pdbRecordType->papFldDes = dbCalloc(no_fields,sizeof(dbFldDes *));
pdbRecordType->papsortFldName = dbCalloc(no_fields,sizeof(char *));
pdbRecordType->sortFldInd = dbCalloc(no_fields,sizeof(short));
no_prompt = no_links = 0;
for(i=0; i<no_fields; i++) {
pdbFldDes = (dbFldDes *)popFirstTemp();
pdbFldDes->pdbRecordType = pdbRecordType;
pdbFldDes->indRecordType = i;
pdbRecordType->papFldDes[i] = pdbFldDes;
if(pdbFldDes->promptgroup) no_prompt++;
field_type = pdbFldDes->field_type;
if((field_type>=DBF_INLINK) && (field_type<=DBF_FWDLINK))no_links++;
if((field_type==DBF_STRING) && (pdbFldDes->size==0))
fprintf(stderr,"recordtype(%s).%s size not specified\n",
pdbRecordType->name,pdbFldDes->name);
if((field_type==DBF_NOACCESS) && (pdbFldDes->extra==0))
fprintf(stderr,"recordtype(%s).%s extra not specified\n",
pdbRecordType->name,pdbFldDes->name);
}
if(ellCount(&tempList)) yyerrorAbort("dbMenuBody: tempList not empty");
pdbRecordType->no_prompt = no_prompt;
pdbRecordType->no_links = no_links;
pdbRecordType->link_ind = dbCalloc(no_links,sizeof(short));
ilink = 0;
for(i=0; i<no_fields; i++) {
pdbFldDes = pdbRecordType->papFldDes[i];
/* if prompt is null make it a null string */
if(!pdbFldDes->prompt) pdbFldDes->prompt = dbCalloc(1,sizeof(char));
field_type = pdbFldDes->field_type;
if((field_type>=DBF_INLINK) && (field_type<=DBF_FWDLINK))
pdbRecordType->link_ind[ilink++] = i;
if(strcmp(pdbFldDes->name,"VAL")==0) {
pdbRecordType->pvalFldDes = pdbRecordType->papFldDes[i];
pdbRecordType->indvalFlddes = i;
}
pdbRecordType->papsortFldName[i] = pdbFldDes->name;
pdbRecordType->sortFldInd[i] = i;
}
/*Now sort fields. Sorry dumb sort algorithm */
papsortFldName = pdbRecordType->papsortFldName;
sortFldInd = pdbRecordType->sortFldInd;
for(i=0; i<no_fields; i++) {
for(j=i+1; j<no_fields; j++) {
if(strcmp(papsortFldName[j],papsortFldName[i])<0 ) {
psortFldNameTemp = papsortFldName[j];
psortFldIndTemp = sortFldInd[j];
papsortFldName[j] = papsortFldName[i];
sortFldInd[j] = sortFldInd[i];
papsortFldName[i] = psortFldNameTemp;
sortFldInd[i] = psortFldIndTemp;
}
}
}
/*Initialize lists*/
ellInit(&pdbRecordType->attributeList);
ellInit(&pdbRecordType->recList);
ellInit(&pdbRecordType->devList);
pgphentry = gphAdd(pdbbase->pgpHash,pdbRecordType->name,
&pdbbase->recordTypeList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
} else {
pgphentry->userPvt = pdbRecordType;
}
ellAdd(&pdbbase->recordTypeList,&pdbRecordType->node);
}
static void dbDevice(char *recordtype,char *linktype,
char *dsetname,char *choicestring)
{
devSup *pdevSup;
dbRecordType *pdbRecordType;
GPHENTRY *pgphentry;
int i,link_type;
pgphentry = gphFind(pdbbase->pgpHash,recordtype,&pdbbase->recordTypeList);
if(!pgphentry) {
epicsPrintf("Record type \"%s\" not found for device \"%s\"\n",
recordtype, choicestring);
yyerror(NULL);
return;
}
link_type=-1;
for(i=0; i<LINK_NTYPES; i++) {
if(strcmp(pamaplinkType[i].strvalue,linktype)==0) {
link_type = pamaplinkType[i].value;
break;
}
}
if(link_type==-1) {
epicsPrintf("Bad link type \"%s\" for device \"%s\"\n",
linktype, choicestring);
yyerror(NULL);
return;
}
pdbRecordType = (dbRecordType *)pgphentry->userPvt;
pgphentry = gphFind(pdbbase->pgpHash,choicestring,&pdbRecordType->devList);
if(pgphentry) {
return;
}
pdevSup = dbCalloc(1,sizeof(devSup));
pdevSup->name = epicsStrDup(dsetname);
pdevSup->choice = epicsStrDup(choicestring);
pdevSup->link_type = link_type;
pgphentry = gphAdd(pdbbase->pgpHash,pdevSup->choice,&pdbRecordType->devList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
} else {
pgphentry->userPvt = pdevSup;
}
ellAdd(&pdbRecordType->devList,&pdevSup->node);
}
static void dbDriver(char *name)
{
drvSup *pdrvSup;
GPHENTRY *pgphentry;
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->drvList);
if(pgphentry) {
return;
}
pdrvSup = dbCalloc(1,sizeof(drvSup));
pdrvSup->name = epicsStrDup(name);
pgphentry = gphAdd(pdbbase->pgpHash,pdrvSup->name,&pdbbase->drvList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = pdrvSup;
ellAdd(&pdbbase->drvList,&pdrvSup->node);
}
static void dbRegistrar(char *name)
{
dbText *ptext;
GPHENTRY *pgphentry;
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->registrarList);
if(pgphentry) {
return;
}
ptext = dbCalloc(1,sizeof(dbText));
ptext->text = epicsStrDup(name);
pgphentry = gphAdd(pdbbase->pgpHash,ptext->text,&pdbbase->registrarList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = ptext;
ellAdd(&pdbbase->registrarList,&ptext->node);
}
static void dbFunction(char *name)
{
dbText *ptext;
GPHENTRY *pgphentry;
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->functionList);
if(pgphentry) {
return;
}
ptext = dbCalloc(1,sizeof(dbText));
ptext->text = epicsStrDup(name);
pgphentry = gphAdd(pdbbase->pgpHash,ptext->text,&pdbbase->functionList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = ptext;
ellAdd(&pdbbase->functionList,&ptext->node);
}
static void dbVariable(char *name, char *type)
{
dbVariableDef *pvar;
GPHENTRY *pgphentry;
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->variableList);
if(pgphentry) {
return;
}
pvar = dbCalloc(1,sizeof(dbVariableDef));
pvar->name = epicsStrDup(name);
pvar->type = epicsStrDup(type);
pgphentry = gphAdd(pdbbase->pgpHash,pvar->name,&pdbbase->variableList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = pvar;
ellAdd(&pdbbase->variableList,&pvar->node);
}
static void dbBreakHead(char *name)
{
brkTable *pbrkTable;
GPHENTRY *pgphentry;
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->bptList);
if(pgphentry) {
duplicate = TRUE;
return;
}
pbrkTable = dbCalloc(1,sizeof(brkTable));
pbrkTable->name = epicsStrDup(name);
if(ellCount(&tempList)) yyerrorAbort("dbBreakHead:tempList not empty");
allocTemp(pbrkTable);
}
static void dbBreakItem(char *value)
{
double dummy;
if (duplicate) return;
if (epicsScanDouble(value, &dummy) != 1) {
yyerrorAbort("Non-numeric value in breaktable");
}
allocTemp(epicsStrDup(value));
}
static void dbBreakBody(void)
{
brkTable *pnewbrkTable;
brkInt *paBrkInt;
brkTable *pbrkTable;
int number, down=0;
int i;
GPHENTRY *pgphentry;
if (duplicate) {
duplicate = FALSE;
return;
}
pnewbrkTable = (brkTable *)popFirstTemp();
number = ellCount(&tempList);
if (number % 2) {
yyerrorAbort("breaktable: Raw value missing");
return;
}
number /= 2;
if (number < 2) {
yyerrorAbort("breaktable: Must have at least two points!");
return;
}
pnewbrkTable->number = number;
pnewbrkTable->paBrkInt = paBrkInt = dbCalloc(number, sizeof(brkInt));
for (i=0; i<number; i++) {
char *str;
str = (char *)popFirstTemp();
(void) epicsScanDouble(str, &paBrkInt[i].raw);
free(str);
str = (char *)popFirstTemp();
(void) epicsScanDouble(str, &paBrkInt[i].eng);
free(str);
}
/* Compute slopes */
for (i=0; i<number-1; i++) {
double slope =
(paBrkInt[i+1].eng - paBrkInt[i].eng)/
(paBrkInt[i+1].raw - paBrkInt[i].raw);
if (!dbBptNotMonotonic && slope == 0) {
yyerrorAbort("breaktable slope is zero");
return;
}
if (i == 0) {
down = (slope < 0);
} else if (!dbBptNotMonotonic && down != (slope < 0)) {
yyerrorAbort("breaktable slope changes sign");
return;
}
paBrkInt[i].slope = slope;
}
/* Continue with last slope beyond the final point */
paBrkInt[number-1].slope = paBrkInt[number-2].slope;
/* Add brkTable in sorted order */
pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList);
while (pbrkTable) {
if (strcmp(pbrkTable->name, pnewbrkTable->name) > 0) {
ellInsert(&pdbbase->bptList, ellPrevious((ELLNODE *)pbrkTable),
(ELLNODE *)pnewbrkTable);
break;
}
pbrkTable = (brkTable *)ellNext(&pbrkTable->node);
}
if (!pbrkTable) ellAdd(&pdbbase->bptList, &pnewbrkTable->node);
pgphentry = gphAdd(pdbbase->pgpHash,pnewbrkTable->name,&pdbbase->bptList);
if (!pgphentry) {
yyerrorAbort("dbBreakBody: gphAdd failed");
return;
}
pgphentry->userPvt = pnewbrkTable;
}
static void dbRecordHead(char *recordType, char *name, int visible)
{
char *badch;
DBENTRY *pdbentry;
long status;
badch = strpbrk(name, " \"'.$");
if (badch) {
epicsPrintf("Bad character '%c' in record name \"%s\"\n",
*badch, name);
}
pdbentry = dbAllocEntry(pdbbase);
if (ellCount(&tempList))
yyerrorAbort("dbRecordHead: tempList not empty");
allocTemp(pdbentry);
status = dbFindRecordType(pdbentry, recordType);
if (status) {
epicsPrintf("Record \"%s\" is of unknown type \"%s\" - ",
name, recordType);
yyerrorAbort(NULL);
return;
}
/*Duplicate records ok if the same type */
status = dbCreateRecord(pdbentry,name);
if (status==S_dbLib_recExists) {
if (strcmp(recordType, dbGetRecordTypeName(pdbentry))!=0) {
epicsPrintf("Record \"%s\" already defined with different type "
"\"%s\"\n", name, dbGetRecordTypeName(pdbentry));
yyerror(NULL);
duplicate = TRUE;
return;
}
else if (dbRecordsOnceOnly) {
epicsPrintf("Record \"%s\" already defined (dbRecordsOnceOnly is "
"set)\n", name);
yyerror(NULL);
duplicate = TRUE;
}
}
else if (status) {
epicsPrintf("Can't create record \"%s\" of type \"%s\"\n",
name, recordType);
yyerrorAbort(NULL);
}
if (visible)
dbVisibleRecord(pdbentry);
}
static void dbRecordField(char *name,char *value)
{
DBENTRY *pdbentry;
tempListNode *ptempListNode;
long status;
if(duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbentry = ptempListNode->item;
status = dbFindField(pdbentry,name);
if(status) {
epicsPrintf("Record \"%s\" does not have a field \"%s\"\n",
dbGetRecordName(pdbentry), name);
yyerror(NULL);
return;
}
dbTranslateEscape(value, value); /* yuck: in-place, but safe */
status = dbPutString(pdbentry,value);
if(status) {
epicsPrintf("Can't set \"%s.%s\" to \"%s\"\n",
dbGetRecordName(pdbentry), name, value);
yyerror(NULL);
return;
}
}
static void dbRecordInfo(char *name, char *value)
{
DBENTRY *pdbentry;
tempListNode *ptempListNode;
long status;
if(duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbentry = ptempListNode->item;
status = dbPutInfo(pdbentry,name,value);
if(status) {
epicsPrintf("Can't set \"%s\" info \"%s\" to \"%s\"\n",
dbGetRecordName(pdbentry), name, value);
yyerror(NULL);
return;
}
}
static void dbRecordAlias(char *name)
{
DBENTRY *pdbentry;
tempListNode *ptempListNode;
long status;
if(duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbentry = ptempListNode->item;
status = dbCreateAlias(pdbentry, name);
if(status) {
epicsPrintf("Can't create alias \"%s\" for \"%s\"\n",
name, dbGetRecordName(pdbentry));
yyerror(NULL);
return;
}
}
static void dbAlias(char *name, char *alias)
{
DBENTRY dbEntry;
DBENTRY *pdbEntry = &dbEntry;
dbInitEntry(pdbbase, pdbEntry);
if (dbFindRecord(pdbEntry, name)) {
epicsPrintf("Alias \"%s\" refers to unknown record \"%s\"\n",
alias, name);
yyerror(NULL);
} else if (dbCreateAlias(pdbEntry, alias)) {
epicsPrintf("Can't create alias \"%s\" referring to \"%s\"\n",
alias, name);
yyerror(NULL);
}
dbFinishEntry(pdbEntry);
}
static void dbRecordBody(void)
{
DBENTRY *pdbentry;
if(duplicate) {
duplicate = FALSE;
return;
}
pdbentry = (DBENTRY *)popFirstTemp();
if(ellCount(&tempList))
yyerrorAbort("dbRecordBody: tempList not empty");
dbFreeEntry(pdbentry);
}