Chapter 14
Static Database Access

 14.1 Overview
 14.2 Definitions
  14.2.1 DBBASE
  14.2.2 DBENTRY
  14.2.3 Field Types
 14.3 Allocating and Freeing DBBASE
  14.3.1 dbAllocBase
  14.3.2 dbFreeBase
 14.4 DBENTRY Routines
  14.4.1 Alloc/Free DBENTRY
  14.4.2 dbInitEntry dbFinishEntry
  14.4.3 dbCopyEntry
 14.5 Read and Write Database
  14.5.1 Read Database File
  14.5.2 Write Database Definitons
  14.5.3 Write Record Instances
 14.6 Manipulating Record Types
  14.6.1 Get Number of Record Types
  14.6.2 Locate Record Type
  14.6.3 Get Record Type Name
 14.7 Manipulating Field Descriptions
  14.7.1 Get Number of Fields
  14.7.2 Locate Field
  14.7.3 Get Field Type
  14.7.4 Get Field Name
  14.7.5 Get Default Value
  14.7.6 Get Field Prompt
 14.8 Manipulating Record Attributes
  14.8.1 dbPutRecordAttribute
  14.8.2 dbGetRecordAttribute
 14.9 Manipulating Record Instances
  14.9.1 Get Number of Records
  14.9.2 Get Number of Record Aliases
  14.9.3 Locate Record
  14.9.4 Get Record Name
  14.9.5 Distinguishing Record Aliases
  14.9.6 Create/Delete/Free Records and Aliases
  14.9.7 Copy Record
  14.9.8 Rename Record
  14.9.9 Record Visibility
  14.9.10 Find Field
  14.9.11 Get/Put Field Values
 14.10 Manipulating Menu Fields
  14.10.1 Get Number of Menu Choices
  14.10.2 Get Menu Choice
  14.10.3 Get/Put Menu
  14.10.4 Locate Menu
 14.11 Manipulating Link Fields
  14.11.1 Link Types
  14.11.2 All Link Fields
  14.11.3 Constant and Process Variable Links
  14.11.4 Get Related Field
 14.12 Manipulating Information Items
  14.12.1 Locate Item
  14.12.2 Get Item Name
  14.12.3 Get/Set Item String Value
  14.12.4 Get/Set Item Pointer Value
  14.12.5 Create/Delete Item
  14.12.6 Convenience Routine
 14.13 Find Breakpoint Table
 14.14 Dump Routines
 14.15 Examples
  14.15.1 Expand Include
  14.15.2 dbDumpRecords

14.1 Overview

An IOC database is created on a Unix system via a Database Configuration Tool and stored in a Unix file. EPICS provides two sets of database access routines: Static Database Access and Runtime Database Access. Static database access can be used on Unix or IOC database files. Runtime database requires an initialized IOC database. Static database access is described in this chapter, runtime database access in the next chapter.

Static database access provides a simplified interface to a database, i.e. much of the complexity is hidden. DBF_MENU and DBF_DEVICE fields are accessed via a common type called DCT_MENU. A set of routines are provided to simplify access to link fields. All fields can be accessed as character strings. This interface is called static database access because it can be used to access an uninitialized as well as an initialized database.

Before accessing database records, the menus, record types, and devices used to define that IOC database must be read via dbReadDatabase or dbReadDatabaseFP. These routines, which are also used to load record instances, can be called multiple times.

Database Configuration Tools (DCTs) should manipulate an EPICS database only via the static database access interface. An IOC database is created on a host system via a database configuration tool and stored in a host file with a file extension of “.db”. Three routines (dbReadDatabase, dbReadDatabaseFP and dbWriteRecord) access the database file. These routines read/write a database file to/from a memory resident EPICS database. All other access routines manipulate the memory resident database.

An include file dbStaticLib.h contains all the definitions needed to use the static database access library. Two structures (DBBASE and DBENTRY) are used to access a database. The fields in these structures should not be accessed directly. They are used by the static database access library to keep state information for the caller.

14.2 Definitions

14.2.1 DBBASE

Multiple memory resident databases can be accessed simultaneously. The user must provide definitions in the form:

DBBASE pdbbase;

NOTE: On an IOC pdbbase is a global variable, which is accessable if you include dbAccess.h

14.2.2 DBENTRY

A typical declaration for a database entry structure is:

DBENTRY pdbentry; 
pdbentry=dbAllocEntry(pdbbase);

Most static access to a database is via a DBENTRY structure. As many DBENTRYs as desired can be allocated.

The user should NEVER access the fields of DBENTRY directly. They are meant to be used by the static database access library.

Most static access routines accept an argument which contains the address of a DBENTRY. Each routine uses this structure to locate the information it needs and gives values to as many fields in this structure as possible. All other fields are set to NULL.

14.2.3 Field Types

Each database field has a type as defined in the next chapter. For static database access a simpler set of field types are defined. In addition, at runtime, a database field can be an array. With static database access, however, all fields are scalars. Static database access field types are called DCT field types.

The DCT field types are:

A DCT_STRING field contains the address of a NULL terminated string. The field types DCT_INTEGER and DCT_REAL are used for numeric fields. A field that has any of these types can be accessed via the dbGetString, dbPutString, dbVerify, and dbGetRange routines.

The field type DCT_MENU has an associated set of strings defining the choices. Routines are available for accessing menu fields. A menu field can also be accessed via the dbGetString, dbPutString, dbVerify, and dbGetRange routines.

The field type DCT_MENUFORM is like DCT_MENU but in addition the field has an associated link field.

DCT_INLINK (input), DCT_OUTLINK (output), and DCT_FWDLINK (forward) specify that the field is a link, which has an associated set of static access routines described in the next subsection. A field that has any of these types can also be accessed via the dbGetString, dbPutString, dbVerify, and dbGetRange routines.

14.3 Allocating and Freeing DBBASE

14.3.1 dbAllocBase

DBBASE dbAllocBase(void);

This routine allocates and initializes a DBBASE structure. It does not return if it is unable to allocate storage.

Most applications should not need to call this routine directly. The dbReadDatabase and dbReadDatabaseFP routines will call it automatically if pdbbase is null. Thus an application normally only has to contain code like the following:

DBBASE  pdbbase=0; 
... 
status = dbReadDatabase(&pdbbase, dbdfile, search_path, macros);

However the static database access library does allow applications to work with multiple databases simultaneously, each referenced via a different DBBASE pointer. Such applications may need to call dbAllocBase directly.

14.3.2 dbFreeBase

void dbFreeBase(DBBASE pdbbase);

dbFreeBase frees the entire database reference by pdbbase including the DBBASE structure itself.

14.4 DBENTRY Routines

14.4.1 Alloc/Free DBENTRY

DBENTRY dbAllocEntry(DBBASE pdbbase); 
void dbFreeEntry(DBENTRY pdbentry);

These routines allocate, initialize, and free DBENTRY structures. The user can allocate and free DBENTRY structures as necessary. Each DBENTRY is, however, tied to a particular database.

dbAllocEntry and dbFreeEntry act as a pair, i.e. the user calls dbAllocEntry to create a new DBENTRY and calls dbFreeEntry when done.

14.4.2 dbInitEntry dbFinishEntry

void dbInitEntry(DBBASE pdbbase,DBENTRY pdbentry); 
void dbFinishEntry(DBENTRY pdbentry);

The routines dbInitEntry and dbFinishEntry are provided in case the user wants to allocate a DBENTRY structure on the stack. Note that the caller MUST call dbFinishEntry before returning from the routine that calls dbInitEntry. An example of how to use these routines is:

int xxx(DBBASE pdbbase) 
{ 
    DBENTRY dbentry; 
    DBENTRY pdbentry = &dbentry; 
    ... 
    dbInitEntry(pdbbase,pdbentry); 
    ... 
    dbFinishEntry(pdbentry); 
}

14.4.3 dbCopyEntry

dbCopyEntry

Contents

DBENTRY dbCopyEntry(DBENTRY pdbentry); 
void dbCopyEntryContents(DBENTRY pfrom,DBENTRY pto);

The routine dbCopyEntry allocates a new entry, via a call to dbAllocEntry, copies the information from the original entry, and returns the result. The caller must free the entry, via dbFreeEntry when finished with the DBENTRY.

The routine dbCopyEntryContents copies the contents of pfrom to pto. Code should never perform structure copies.

14.5 Read and Write Database

14.5.1 Read Database File

long dbReadDatabase(DBBASE ⋆⋆ppdbbase,const char filename, 
    char path, char substitutions); 
long dbReadDatabaseFP(DBBASE ⋆⋆ppdbbase,FILE fp, 
    char path, char substitutions); 
long dbPath(DBBASE pdbbase,const char path); 
long dbAddPath(DBBASE pdbbase,const char path);

dbReadDatabase and dbReadDatabaseFP both read a file containing database definitions as described in chapter ”Database Definitions”. If ⋆ppdbbase is NULL, dbAllocBase is automatically invoked and the return address assigned to ⋆pdbbase. The only difference between the two routines is that one accepts a file name and the other a ”FILE *”. Any combination of these routines can be called multiple times. Each adds definitions with the rules described in chapter “Database Definitions”.

The routines dbPath and dbAddPath specify paths for use by include statements in database definition files. These are not normally called by user code.

14.5.2 Write Database Definitons

long dbWriteMenu(DBBASE pdbbase,char filename,char menuName); 
long dbWriteMenuFP(DBBASE pdbbase,FILE fp,char menuName); 
long dbWriteRecordType(DBBASE pdbbase,char filename,char recordTypeName); 
long dbWriteRecordTypeFP(DBBASE pdbbase,FILE fp,char recordTypeName); 
long dbWriteDevice(DBBASE pdbbase,char filename); 
long dbWriteDeviceFP(DBBASE pdbbase,FILE fp); 
long dbWriteDriver(DBBASE pdbbase,char filename); 
long dbWriteDriverFP(DBBASE pdbbase,FILE fp); 
long dbWriteRegistrarFP(DBBASE pdbbase,FILE fp); 
long dbWriteFunctionFP(DBBASE pdbbase,FILE fp); 
long dbWriteVariableFP(DBBASE pdbbase,FILE fp); 
long dbWriteBreaktable(DBBASE pdbbase,const char filename); 
long dbWriteBreaktableFP(DBBASE pdbbase,FILE fp);

Each of these routines writes files in the same format accepted by dbReadDatabase and dbReadDatabaseFP. Two versions of each type are provided. The only difference is that one accepts a filename string and the other a FILE ⋆ pointer. Thus only one of each type will be described.

dbWriteMenu writes the description of the specified menu or, if menuName is NULL, the descriptions of all menus.

dbWriteRecordType writes the description of the specified record type or, if recordTypeName is NULL, the descriptions of all record types to the named file.

dbWriteDevice writes the description of all devices to the named file.

dbWriteDriver writes the description of all drivers to the named file.

dbWriteRegistrarFP writes the list of all registrars to the given open file (no filename version is provided).

dbWriteFunctionFP writes the list of all functions to the given open file (no filename version is provided).

dbWriteVariableFP writes the list of all variables to the given open file (no filename version is provided).

dbWriteBreaktable writes the definitions of all breakpoint tables to the named file.

14.5.3 Write Record Instances

long dbWriteRecord(DBBASE pdbbase,char  file, 
 
char precordTypeName,int level); 
long dbWriteRecordFP(DBBASE pdbbase,FILE fp, 
 
char precordTypeName,int level);

These routines write record instance data. If precordTypeName is NULL, then the record instances for all record types are written, otherwise only the records for the specified type are written. level has the following meaning:

14.6 Manipulating Record Types

14.6.1 Get Number of Record Types

int  dbGetNRecordTypes(DBENTRY pdbentry);

This routine returns the number of record types in the database.

14.6.2 Locate Record Type

long dbFindRecordType(DBENTRY pdbentry, 
char recordTypeName); 
long dbFirstRecordType(DBENTRY pdbentry); 
long dbNextRecordType(DBENTRY pdbentry);

dbFindRecordType locates a particular record type. dbFirstRecordType locates the first, in alphabetical order, record type. Given that DBENTRY points to a particular record type, dbNextRecordType locates the next record type. Each routine returns 0 for success and a non zero status value for failure. A typical code segment using these routines is:

status = dbFirstRecordType(pdbentry); 
while(!status) { 
    /⋆Do something⋆/ 
    status = dbNextRecordType(pdbentry) 
}

14.6.3 Get Record Type Name

char dbGetRecordTypeName(DBENTRY pdbentry);

This routine returns the name of the record type that DBENTRY currently references. This routine should only be called after a successful call to dbFindRecordType, dbFirstRecordType, or dbNextRecordType. It returns NULL if DBENTRY does not point to a record description.

14.7 Manipulating Field Descriptions

The routines described here all assume that DBENTRY references a record type, i.e. that dbFindRecordType, dbFirstRecordType or dbNextRecordType have returned success or that a record instance has been successfully located.

14.7.1 Get Number of Fields

int  dbGetNFields(DBENTRY pdbentry,int dctonly);

Returns the number of fields for the record instance that DBENTRY currently references.

14.7.2 Locate Field

long dbFirstField(DBENTRY pdbentry,int dctonly); 
long dbNextField(DBENTRY pdbentry,int dctonly);

These routines are used to locate fields. If any of these routines returns success, then DBENTRY references that field description.

14.7.3 Get Field Type

int  dbGetFieldType(DBENTRY pdbentry);

This routine returns the integer value for a DCT field type. See Section 14.2.3 for a description of the field types.

14.7.4 Get Field Name

char dbGetFieldName(DBENTRY pdbentry);

This routine returns the name of the field that DBENTRY currently references. It returns NULL if DBENTRY does not point to a field.

14.7.5 Get Default Value

char dbGetDefault(DBENTRY pdbentry);

This routine returns the default value for the field that DBENTRY currently references. It returns NULL if DBENTRY does not point to a field or if the default value is NULL.

14.7.6 Get Field Prompt

char dbGetPrompt(DBENTRY pdbentry); 
int   dbGetPromptGroup(DBENTRY pdbentry); 
char dbGetPromptGroupNameFromKey(DBBASE pdbbase, const short key); 
short dbGetPromptGroupKeyFromName(DBBASE pdbbase, const char name);

The dbGetPrompt routine returns the character string prompt value, which provides a short description of the field. dbGetPromptGroup returns the field’s group key.

Conversion between the group key and the group name as a string is provided by two functions: dbGetPromptGroupNameFromKey returns a pointer to a static string containing the name of the group, NULL for an invalid key. dbGetPromptGroupKeyFromName returns the numerical key related to the specified group name string, 0 if the string does not match an existing group name.

14.8 Manipulating Record Attributes

A record attribute is a psuedo-field definition attached to a record type. If a attribute value is assigned to a psuedo field name then all record instances of that record type appear to have that field with the defined value. All attribute fields are DCT_STRING fields.

Two field attributes are automatically created: RTYP and VERS. RTYP is set equal to ,the record type name. VERS is initialized to the value “none specified” but can be changed by record support.

14.8.1 dbPutRecordAttribute

long dbPutRecordAttribute(DBENTRY pdbentry, const char name, 
    const char value);

This creates or modifies the attribute name of the record type referenced by pdbentry to value. Attribute names should be valid C identifiers, starting with a letter or underscore followed by any number of alphanumeric or underscore characters.

14.8.2 dbGetRecordAttribute

long dbGetRecordAttribute(DBENTRY pdbentry, const char name);

Looks up the attribute name of the record type referenced by pdbentry and sets the the field pointer in pdbentry to refer to this string if it exists. The routine dbGetString can be used subsequently to read the current attribute value.

14.9 Manipulating Record Instances

With the exception of dbFindRecord, each of the routines described in this section need DBENTRY to reference a valid record type, i.e. that dbFindRecordType, dbFirstRecordType, or dbNextRecordType have been called and returned success.

14.9.1 Get Number of Records

int  dbGetNRecords(DBENTRY pdbentry);

Returns the total number of record instances and aliases for the record type that DBENTRY currently references.

14.9.2 Get Number of Record Aliases

int dbGetNAliases(DBENTRY pdbentry)

Returns the number of record aliases for the record type that DBENTRY currently references.

14.9.3 Locate Record

long dbFindRecord(DBENTRY pdbentry,char precordName); 
long dbFirstRecord(DBENTRY pdbentry); 
long dbNextRecord(DBENTRY pdbentry);

These routines are used to locate record instances and aliases. If any of these routines returns success, then DBENTRY references a record or a record alias (use dbIsAlias to distinguish the two). dbFindRecord may be called without DBENTRY referencing a valid record type. dbFirstRecord only works if DBENTRY references a record type. The dbDumpRecords example given at the end of this chapter shows how these routines can be used.

dbFindRecord also calls dbFindField if the record name includes a field name, i.e. it ends in “.XXX”. The routine dbFoundField indicates whether the field was found or not. If it was not found, then dbFindField must be called before individual fields can be accessed.

14.9.4 Get Record Name

char dbGetRecordName(DBENTRY pdbentry);

This routine only works properly if called after dbFindRecord, dbFirstRecord, or dbNextRecord has returned success. If DBENTRY refers to an alias, the name returned is that of the alias, not of the record it refers to.

14.9.5 Distinguishing Record Aliases

int dbIsAlias(DBENTRY pdbentry)

This routine only works properly if called after dbFindRecord, dbFirstRecord, or dbNextRecord has returned success. If DBENTRY refers to an alias it returns a non-zero value, otherwise it returns zero.

14.9.6 Create/Delete/Free Records and Aliases

long dbCreateRecord(DBENTRY pdbentry,char precordName); 
long dbCreateAlias(DBENTRY pdbentry, const char paliasName); 
long dbDeleteRecord(DBENTRY pdbentry); 
long dbDeleteAliases(DBENTRY pdbentry); 
long dbFreeRecords(DBBASE pdbbase);

dbCreateRecord, which assumes that DBENTRY references a valid record type, creates a new record instance and initializes it as specified by the record description. If it returns success, then DBENTRY references the record just created. dbCreateAlias assumes that DBENTRY references a particular record instance and creates an alias for that record. If it returns success, then DBENTRY references the alias just created. dbDeleteRecord deletes either a single alias, or a single record instance and all the aliases that refer to it. dbDeleteAliases finds and deletes all aliases that refer to the current record. dbFreeRecords deletes all record instances.

14.9.7 Copy Record

long dbCopyRecord(DBENTRY pdbentry, char newRecordName 
    int overWriteOK)

This routine copies the record instance currently referenced by DBENTRY (it fails if DBENTRY references an alias). Thus it creates a new record with the name newRecordName that is of the same type as the original record and copies the original records field values to the new record. If newRecordName already exists and overWriteOK is true, then the original newRecordName is deleted and recreated. If dbCopyRecord completes successfully, DBENTRY references the new record.

14.9.8 Rename Record

long dbRenameRecord(DBENTRY pdbentry, char newname)

This routine renames the record instance currently referenced by DBENTRY (it fails if DBENTRY references an alias). If dbRenameRecord completes successfully, DBENTRY references the renamed record.

14.9.9 Record Visibility

These routines are intended for use by graphical configuration tools.

long dbVisibleRecord(DBENTRY pdbentry); 
long dbInvisibleRecord(DBENTRY pdbentry); 
int dbIsVisibleRecord(DBENTRY pdbentry);

Calling dbVisibleRecord makes the record referenced by DBENTRY visible. dbInvisibleRecord makes the record invisible. dbIsVisibleRecord returns TRUE if the record is visible, FALSE otherwise.

14.9.10 Find Field

long dbFindField(DBENTRY pdbentry,char pfieldName); 
int dbFoundField(DBENTRY pdbentry);

Given that a record instance has been located, dbFindField finds the specified field. If it returns success, then DBENTRY references that field. dbFoundField returns FALSE if no field with the given name could be found, TRUE if the field was located.

14.9.11 Get/Put Field Values

char dbGetString(DBENTRY pdbentry); 
long dbPutString(DBENTRY pdbentry,char pstring); 
char dbVerify(DBENTRY pdbentry,char pstring); 
char dbGetRange(DBENTRY pdbentry); 
int   dbIsDefaultValue(DBENTRY pdbentry);

These routines are used to get or change field values. They work on any database field type except DCT_NOACCESS. dbVerify returns NULL if the string contains a valid value for this field or an error message if not. Note that the strings returned are owned by the DBENTRY, so the next call passing that DBENTRY object that returns a string will overwrite the value returned by a previous call. It is the caller’s responsibility to copy the strings if the value must be kept.

DCT_MENU, DCT_MENUFORM and DCT_LINK_xxx fields can be manipulated via routines described in the following sections. If, however dbGetString and dbPutString are used, they do work correctly. For these field types dbGetString and dbPutString are intended to be used only for creating and restoring versions of a database.

14.10 Manipulating Menu Fields

These routines should only be used for DCT_MENU and DCT_MENUFORM fields. Thus they should only be called if dbFindField, dbFirstField, or dbNextField has returned success and the field type is DCT_MENU or DCT_MENUFORM.

14.10.1 Get Number of Menu Choices

int  dbGetNMenuChoices(DBENTRY pdbentry);

This routine returns the number of menu choices for menu.

14.10.2 Get Menu Choice

char ⋆⋆dbGetMenuChoices(DBENTRY pdbentry);

This routine returns the address of an array of pointers to strings which contain the menu choices.

14.10.3 Get/Put Menu

int  dbGetMenuIndex(DBENTRY pdbentry); 
long dbPutMenuIndex(DBENTRY pdbentry,int index); 
char dbGetMenuStringFromIndex(DBENTRY pdbentry,int index); 
int dbGetMenuIndexFromString(DBENTRY pdbentry, 
 
char choice);

NOTE: These routines do not work if the current field value contains a macro definition.

dbGetMenuIndex returns the index of the menu choice for the current field, i.e. it specifies which choice to which the field is currently set. dbPutMenuIndex sets the field to the choice specified by the index.

dbGetMenuStringFromIndex returns the string value for a menu index. If the index value is invalid NULL is returned. dbGetMenuIndexFromString returns the index for the given string. If the string is not a valid choice -1 is returned.

14.10.4 Locate Menu

dbMenu dbFindMenu(DBBASE pdbbase,char name);

dbFindMenu is most useful for runtime use but is a static database access routine. This routine just finds a menu with the given name.

14.11 Manipulating Link Fields

14.11.1 Link Types

Links are the most complicated types of fields. A link can be a constant, reference a field in another record, or can refer to a hardware device. Two additional complications arise for hardware links. The first is that field DTYP, which is a menu field, determines if the INP or OUT field is a device link. The second is that the information that must be specified for a device link is bus dependent. In order to shelter database configuration tools from these complications the following is done for static database access.

Each link is one of the following types:

Database configuration tools can change any link between being a constant and a process variable link. Routines are provided to accomplish these tasks.

The routines dbGetString, dbPutString, and dbVerify can be used for link fields but the form routines can be used to provide a friendlier user interface.

14.11.2 All Link Fields

int  dbGetNLinks(DBENTRY pdbentry); 
long dbGetLinkField(DBENTRY pdbentry,int index) 
int  dbGetLinkType(DBENTRY pdbentry);

These are routines for manipulating DCT_xxxLINK fields. dbGetNLinks and dbGetLinkField are used to walk through all the link fields of a record. dbGetLinkType returns one of the values: DCT_LINK_CONSTANT, DCT_LINK_PV, DCT_LINK_FORM, or the value -1 if it is called for an illegal field.

14.11.3 Constant and Process Variable Links

long dbCvtLinkToConstant(DBENTRY pdbentry); 
long dbCvtLinkToPvlink(DBENTRY pdbentry);

These routines should be used for modifying DCT_LINK_CONSTANT or DCT_LINK_PV links. They should not be used for DCT_LINK_FORM links, which should be processed via the associated DCT_MENUFORM field described above.

14.11.4 Get Related Field

char dbGetRelatedField(DBENTRY pdbentry)

This routine returns the field name of the related field for a DCT_MENUFORM field. If it is called for any other type of field it returns NULL.

14.12 Manipulating Information Items

Information items are stored as a list attached to each individual record instance. All routines listed in this section require that the DBENTRY argument refer to a valid record instance.

14.12.1 Locate Item

long dbFirstInfo(DBENTRY pdbentry); 
long dbNextInfo(DBENTRY pdbentry); 
long dbFindInfo(DBENTRY pdbentry,const char name);

There are two ways to locate info items, by scanning through the list using first/next, or by asking for the item by name. These routines set pdbentry to refer to the info item and return 0, or return an error code if no info item is found.

14.12.2 Get Item Name

const char  dbGetInfoName(DBENTRY pdbentry);

Returns the name of the info item referred to by pdbentry, or a NULL pointer if no item is referred to.

14.12.3 Get/Set Item String Value

const char  dbGetInfoString(DBENTRY pdbentry); 
long dbPutInfoString(DBENTRY pdbentry,const char string);

These routines provide access to the currently selected item’s string value. When changing the string value using dbPutInfoSting, the character string provided will be copied, with additional memory being allocated as necessary. Developers are advised not to make continuously repeated calls to dbPutInfoString at IOC runtime as this could fragment the free memory heap. The Put routine returns 0 if Ok or an error code; the Get routine returns NULL on error.

14.12.4 Get/Set Item Pointer Value

void  dbGetInfoPointer(DBENTRY pdbentry); 
long dbPutInfoPointer(DBENTRY pdbentry, void pointer);

Each info item includes space to store a single void⋆ pointer as well as the value string. Applications using the info item may set this as often as they wish. The Put routine returns 0 if Ok or an error code; the Get routine returns NULL on error.

14.12.5 Create/Delete Item

long dbPutInfo(DBENTRY pdbentry,const char name,const char string); 
long dbDeleteInfo(DBENTRY pdbentry);

A new info item can be created by calling dbPutInfo. If an item by that name already exists its value will be replaced with the new string, otherwise storage is allocated and the name and value strings copied into it. The function returns 0 on success, or an error code.

When calling dbDeleteInfo, pdbentry must refer to the item to be removed (using dbFirstInfo, dbNextInfo or dbFindInfo). The function returns 0 on success, or an error code.

14.12.6 Convenience Routine

const char  dbGetInfo(DBENTRY pdbentry,const char name);

It is common to want to look up the value of a named info item in one call, and dbGetInfo is provided for this purpose. It returns a NULL pointer if no info item exists with the given name.

14.13 Find Breakpoint Table

brkTable dbFindBrkTable(DBBASE pdbbase,char name)

This routine returns the address of the specified breakpoint table. It is normally used by the runtime breakpoint conversion routines so will not be discussed further.

14.14 Dump Routines

void dbDumpPath(DBBASE pdbbase) 
void dbDumpRecord(DBBASE pdbbase,char precordTypeName,int level); 
void dbDumpMenu(DBBASE pdbbase,char menuName); 
void dbDumpRecordType(DBBASE pdbbase,char recordTypeName); 
void dbDumpField(DBBASE pdbbase,char recordTypeName,char fname); 
void dbDumpDevice(DBBASE pdbbase,char recordTypeName); 
void dbDumpDriver(DBBASE pdbbase); 
void dbDumpRegistrar(DBBASE pdbbase); 
void dbDumpFunction(DBBASE pdbbase); 
void dbDumpVariable(DBBASE pdbbase); 
void dbDumpBreaktable(DBBASE pdbbase,char name); 
void dbPvdDump(DBBASE pdbbase,int verbose); 
void dbReportDeviceConfig(DBBASE pdbbase,FILE report);

These routines are used to dump information about the database. The routines dbDumpRecord, dbDumpMenu, dbDumpDriver, dbDumpRegistrar and dbDumpVariable just call their corresponding dbWriteXxxFP routine, specifying stdout for the file to write to. dbDumpRecordType, dbDumpField, and dbDumpDevice give internal information useful on an ioc. These commands can be executed via iocsh, specifying pdbbase as the first argument.

14.15 Examples

14.15.1 Expand Include

This example is like the dbExpand utility, except that it doesn’t allow path or macro substitution options. It reads a set of database definition files and writes all definitions to stdout. All include statements appearing in the input files are expanded.

/⋆ dbExpand.c ⋆/ 
#include <stdlib.h> 
#include <stddef.h> 
#include <stdio.h> 
#include <epicsPrint.h> 
#include <dbStaticLib.h> 
 
DBBASE pdbbase = NULL; 
 
int main(int argc, char ⋆⋆argv) 
{ 
    long status; 
    int i; 
    int arg; 
 
    if (argc < 2) { 
        printf("usage:expandIncludefile1.dbfile2.db...\n"); 
        exit 0; 
    } 
 
    for (i = 1; i < argc; i++) { 
        status = dbReadDatabase(&pdbbase, argv[i], NULL, NULL); 
        if (!status) continue; 
        fprintf(stderr, "Forinputfile%s", argv[i]); 
        errMessage(status, "fromdbReadDatabase"); 
    } 
    dbWriteMenuFP(pdbbase,stdout,0); 
    dbWriteRecordTypeFP(pdbbase,stdout,0); 
    dbWriteDeviceFP(pdbbase.stdout); 
    dbWriteDriverFP(pdbbase.stdout); 
    dbWriteRecordFP(pdbbase,stdout,0,0); 
    return(0); 
}

14.15.2 dbDumpRecords

NOTE: This example is similar but not identical to the actual dbDumpRecords routine.

The following example demonstrates how to use the database access routines. The code shows how to iterate through the record types and instances and display field values.

void dbDumpRecords(DBBASE pdbbase) 
{ 
    DBENTRY  pdbentry; 
    long  status; 
 
    pdbentry = dbAllocEntry(pdbbase); 
    status = dbFirstRecordType(pdbentry); 
    if (status) { 
        printf("Norecordtypes\n"); 
        return; 
    } 
    while (!status) { 
        printf("Recordtype:%s\n", dbGetRecordTypeName(pdbentry)); 
        status = dbFirstRecord(pdbentry); 
        if (status) 
            printf("Norecordinstances\n"); 
        else while (!status) { 
            if (dbIsAlias(pdbentry)) 
                printf("Alias:%s\n", dbGetRecordName(pdbentry)); 
            else { 
                printf("Record:%s\n", dbGetRecordName(pdbentry)); 
                status = dbFirstField(pdbentry, TRUE); 
                if (status) 
                    printf("Nofields\n"); 
                else while(!status) { 
                    printf("%s:%s\n", dbGetFieldName(pdbentry), 
                        dbGetString(pdbentry)); 
                    status = dbNextField(pdbentry, TRUE); 
                } 
            } 
            status = dbNextRecord(pdbentry); 
        } 
        status = dbNextRecordType(pdbentry); 
    } 
    printf("Endofrecordtypes\n"); 
    dbFreeEntry(pdbentry); 
}