Documentation: The FOX Registry

| Documentation: The FOX Registry [Remove Frame]

Many applications have a need to read settings and configuration parameters from configuration files. For example, it is common for applications to remember which documents have been used recently with an application, or what color a user has changed his/her window background to.

Historically, each application has implemented its configuration files in its own way, resulting in a plethora of file formats, each with their own syntax and semantics. Moreover, many applications can only read, and not write these configuration files; they rely on the user to fire up an editor and edit them by hand.

The FOX Registry class provides a simple method to keep track of configuration parameters for FOX-based applications. Entries can be both read as well as written, and settings will persist across invocations because the system will write changed settings back to disk.

Because the format is the same for all FOX applications, users will have to learn only one [very simple] syntax in case they want to edit these files by hand (although in most cases, registry files will probably be manipulated by FOX programs only).

Design Features of the FOX Registry

A registry mechanism should allow applications from many vendors or organizations to coexist peacefully. Also, certain settings or configuration parameters should be applied system wide, others ``suite-wide'' i.e. for all applications produced by some organization. Yet other settings apply only to one application. Tallying it all up, I've come up with the following list of requirements for a registry system:

- System-wide Desktop settings. Configuration parameters which apply to all users on a certain system, and apply to all applications. For example, parameters specific to a certain FOX installation, such as the location of icon files, images, and other such parameters.
- System-wide Vendor settings. These settings are determined during installation of some vendor's application suite. They apply to all applications which belong to the suite, and to all users on the system.
- System-wide Application settings. These parameters apply to a specific application, and to all users on the system.
- Per-user Desktop settings. Personal preferences that a specific user has changed from the system-wide settings, and which apply to all applications run by this user.
- Per-user Vendor settings. Similarly, a user of some application-suite from a certain vendor may have changed a few things to suit his/her personal preferences.
- Per-user Application settings. These are specific configurations that a user may have changed while running an application.

All settings can be ``shadowed'' or overridden. The general rule is that more specific settings override more general ones. FOX implements this by first loading system-wide settings, then per-user settings; within each category, Desktop settings are shadowed by Vendor settings, and those are overruled by Application settings.

Registry settings are not shadowed when they've been changed, i.e. a setting which was changed by an application is not replaced by a settings entry loaded later.

Finally, when settings are being written back to disk, they will automatically become per-application, per-user settings. For instance, suppose the default system-wide background color is ``gray.'' If the user changes this, it will become a per-user default background color. In other words, the system-wide settings are never written, except perhaps when the application is being installed.

The FOX settings database is comprised tyically of a number of files which are placed in a certain directory structure. The organization is as follows:

<DIR>/Desktop | The settings database for all FOX applications. This contains things such as double-click speed, default application fonts, and so on.
<DIR>/<VENDOR>/<VENDOR> | This contains all settings for all applications produced by organization <VENDOR>.
<DIR>/<VENDOR>/<APP> | This contains all settings for application <APP> produced by organization <VENDOR>.

The same directory structure applies for both system-wide settings and per-user settings. The system-wide settings are found in directories:

    /etc/foxrc
    /usr/lib/FOX/foxrc
    /usr/local/lib/FOX/foxrc

Per-user settings are found in:

    $HOME/.foxrc

Which is a hidden directory directly under the users regular HOME directory.

Format of a Registry File

The format for a FOX registry file is very similar to that of the SAMBA configuration files. It consists of a number of sections, and each section contains a number of registry entries. Each entry is a key/value pair, where the key is the name of the particular entry, and the value is a human-readable string representing the value of that key. For example:

    # A section
    [SETTINGS]

    # An entry
    clickspeed = 400
    scrollspeed = 400

    # Strings may have to be quoted if they contain special characters
    tiger = "Tyger tyger burning bright\nIn the forest of the night"

    ! Comment may also start with a bang
    tippause = 500
    tiptime = 300

The section names should consist of alphanumeric characters [A-Z,a-z,0-9], and may contain underscores ``_'' also. Key names should consist of alphanumeric characters [A-Z,a-z,0-9], underscores, dash ``-'' or periods ``.''. Value strings may consist of any non-blank character, except ``#'' or ``!'' which are used for comments. To incorporate these and other non-printable characters, you may quote the string as shown above. Special characters can be embedded into a quotable string using the regular C-style backslash mechanism, i.e. ``\n'' is replaced by a newline; control characters can be embedded using hex-notation: for instance, ``\FF'' represents the byte 0xff.

Under the MS-Windows Implementation of FOX, you can use either the ASCII, human-readable implementation, or the binary version which uses the built-in System Registry.

Using the Registry

The FOX FXApp object contains an embedded FXRegistry object, which is automatically read in when you start up using FXApp::init(). Likewise, this registry is also automatically written back out when you terminate the application using FXApp::exit().

The application name and vendor name parameters passed in when you construct the FXApp object are directly used as the application name and vendor name for the registry system.

To make use of the registry in your application's code, you can obtain a reference to the embedded registry object using FXApp::reg(). FXRegistry provides the following API:

FXbool read()

> This function causes the system-wide registry database to be read first, followed by the per-user database. In each category, it reads the Desktop, Vendor, and Application settings in order, overwriting unmodified settings as it goes.
> Note that upon startup, a FOX application automatically calls the registry's read() function already. You will usually not call this function, unless perhaps to re-read the registry.

FXbool write()

> If any settings have been changed, this will write out the changed values into the per-user, per-application files of the registry database.
> Note that a FOX application automatically calls the registry's write() function when the application terminates normally (i.e. by calling FXApp::exit()). You will not call this function under normal conditions, except perhaps to force changed registry entries to disk, e.g. so that other instances of the same application will encounter the changed entries, even before the current one quits.

const FXchar *readStringEntry(const FXchar *section,const FXchar *key,const FXchar *def)

> This function attempts to localize the entry key in the section of the registry database, and returns the value of this key if it is found; otherwise, it returns the specified def value.

FXint readIntEntry(const FXchar *section,const FXchar *key,FXint def)

> Similar to the function above, only it assumes the entry's value is an integer number.

FXint readUnsignedEntry(const FXchar *section,const FXchar *key,FXint def)

> Similar to the function above, only it assumes the entry's value is an unsigned integer number.

FXdouble readRealEntry(const FXchar *section,const FXchar *key,FXdouble def)

> Assumes that the entry's value is a real number.

FXColor readColorEntry(const FXchar *section,const FXchar *key,FXColor def)

> Assumes that the entry's value is a color, which may be specified by a color name, like "red", or in hex notation, as in "#ff0000".

FXbool writeStringEntry(const FXchar *section,const FXchar *key,const FXchar *val)

> Sets or changes the value of key in the given section to the value val. If this key or section does not yet exist, it is created.

FXbool writeIntEntry(const FXchar *section,const FXchar *key,FXint val)

> Similar, but assumes the key's value is an integer number.

FXbool writeUnsignedEntry(const FXchar *section,const FXchar *key,FXint val)

> Similar, but assumes the key's value is an unsigned integer number.

FXbool writeRealEntry(const FXchar *section,const FXchar *key,FXdouble val)

> Assumes the entry's value is a real number.

FXbool writeColorEntry(const FXchar *section,const FXchar *key,FXColor val)

> Assumes the entry's value is a color; it is translated into a colorname, or as in hex notation if no name is found for the color.

FXbool deleteEntry(const FXchar *section,const FXchar *key)

> Removes the entry from the database. It will be removed from the per-user, per-application file, but not from the system-wide or per-user Desktop or Vendor files.

FXbool existingEntry(const FXchar *section,const FXchar *key)

> Returns true if the given section and key exists.

FXbool deleteSection(const FXchar *section)

> Removes the named section from the database. The section will be removed only from the per-user, per-application file.

FXbool existingSection(const FXchar *section)

> Returns true if the given section exists.

FXbool clear()

> Clears the entire database.

void setModified(FXbool mdfy=TRUE)

> Mark the registry as having been modified or non-modified. One would typically call this to prevent modified entries from being written.

FXbool isModified()

> Returns TRUE if the database has been modified.

void setAsciiMode(FXbool asciiMode)

> On MS-Windows, this switches the registry to ASCII based, human-readable format or, if asciiMode is FALSE, to the binary system.

The Standard Registry in FOX Application Object

Note that the FOX FXApp object provides a registry already. The standard application registry is defined in terms of the application name and vendor name that were passed into the FXApp's constructor.
When an application is started, the standard registry is automatically loaded when `FXApp::init()` is called. Likewise, modified registry settings are automatically written when `FXApp::exit()` is called. You should take care that these functions are called when writing your own programs so that settings needed in your program are available when you expect them, and are properly written back to disk after the application exits
Only changed settings are written back; if no changes have been made to any settings while running the application, no writing would take place at all.

You can access the built-in registry object by the `FXApp::reg()` member function. For example:

    FXColor canvasbackground = myapp->reg().readColorEntry("SETTINGS","background",FXRGB(255,255,255));

To read a background color from the settings database, and default to white if no entry exists.

When writing the registry, FOX first writes to a temp file, then renames the temp file to the regular registry file. Since rename() is an atomic system call, either it works and the new registry is in place, or it doesn't and the old registry is still in place; at no time would a partially complete registry file be left behind; therefore, the registry mechanism should be quite safe even in the presence of multiple applications simultaneously trying to access the same registry.

Copyright © 1997-2005 Jeroen van der Zijp