# PAL - Quickreference: Cfg

## Configuration file routines

The functions in this module allow easy retrieval, addition, deletion and storage of information from user-editable plain-text config files, much like the Windows WIN.INI files.

Available functions:

ReadConfig : Read config file given full name.
ReadMyconfig : Read config, given program name.
GetConfigString : Retrieve a string from config data.
GetConfigInt : Retrieve an integer from config data.
GetFirstEntry : Used to scan sections: init scan.
GetNextEntry : Used to scan sections: continue scan.
GetCfgLine : Retrieve line number info during scan.
GetFirstSection : Scan file for sections: init scan
GetNextSection : Scan file for sections: continue scan
AddConfigString : Add entries to a config file
ReplaceConfigString : Replace a keys value in a config file
DeleteConfigString : Delete a config entry
WriteConfig : Write a config file back to disk

## CFG Introduction

Here's an example of what a config file looks like: ; ------------------------------------------- ; Configuration file for MYAPP ; ------------------------------------------- ; ; Comments are introduced with a semicolon ; [Printer] Port = LPT1 Driver = LaserJet [User] Name = 'John Doe' Serial = 123456 The name in angular brackets is called a section, the left side of an assignment name is called a key, and the right side is called a value. The routines in the CFG allow easy reading in and retrieval of the data in such a file. (In general, after loading the config file you provide a section and a key and get the corresponding value, or a default that you can specify). Once the config file has been read into memory, there are routine that allow you to add new sections, and new key=value pairs to an existing section, replace the value of an existing key, delete any key, keys or even a complete section, and finally a routine to write to file the results. Use ReadConfig(), or ReadMyConfig() to load the config file, and GetConfigString() or GetConfigInt() to retrieve data. That's all you usually need for retrieval. You can also use the function NewConfig() to initialize a new "memory" image of a config file that can later be saved. GetFirstEntry() and GetNextEntry() can be used to scan entire sections. GetFirstSection( and GetNextSection() can be used to enumerate all the sections in the config file. GetCfgLine retrieves the line number (for error messages) during such a scan. Once the file is in memory use AddConfigString() and AddConfigInt() to add new sections and key=value pairs. Use ReplaceConfigString() and ReplaceConfigInt() to replace the value for an existing key. Use DeleteConfigString() to delete a key=value pair, or all keys that match a given string, or all entries for a complete section. Use WriteConfig() to write the file back to either the same, or a different filename. Finally, call DiscardConfig() to free up the memory used by the config database.

## ReadConfig

NAME

            ReadConfig

DESCRIPTION

            Reads a config file and stores the settings in an internal
            database for later retrieval.

SYNOPSIS

            #include "pal.h"
            void  ReadConfig(char *CfgName);

INPUTS

            CfgName - the name of the config file - including the
                      extension.

NOTE

            ReadConfig has no return value - if the file is not found,
            that is not considered an error, since your program may
            still use the default value system supported by the
            GetConfigXXX functions. If you need a mandatory entry in
            the config file, you can detect its absence - see
            GetConfigString for a tip how this can be done.

            An extra section is created in memory when the file is read.
            This section is called the "Prolog" section. The actual section
            name is the fully qualified file specification of the config
            file. This section header is NOT written back to the file. It
            is used solely to keep track of and maintain comments in the
            config file, prior to the first real section.

SAMPLE

            void main(void)
            {
               ReadConfig("MYAPP.CFG"); /* Load config data for future use */
               /* ... */

SEE ALSO
  GetConfigString ReadMyConfig DiscardConfig WriteConfig

## ReadMyConfig

NAME

            ReadMyConfig

DESCRIPTION

            This function is very similar to ReadConfig, but is able to infer the
            name of the config file from the full pathname of your application.
            This is available as the argv[0] argument to C programs. Whatever
            your program is called and wherever it is stored, using this
            device will find the config file located in the same directory under
            the same name.

SYNOPSIS

            #include "pal.h"
            void  ReadMyConfig(char *MyName);

INPUTS

            MyName - the name of your application, including the '.EXE' extension.

NOTE

            ReadMyConfig has no return value - if the file is not found,
            that is not considered an error, since your program may
            still use the default value system supported by the
            GetConfigXXX functions. If you need a mandatory entry in
            the config file, you can detect its absence - see
            GetConfigString for a tip how this can be done.

            An extra section is created in memory when the file is read.
            This section is called the "Prolog" section. The actual section
            name is the fully qualified file specification of the config
            file. This section header is NOT written back to the file. It
            is used solely to keep track of and maintain comments in the
            config file, prior to the first real section.

SAMPLE

            int main(int argc, char *argv[])
            {
               /* read config file, whatever program is called and
                  wherever it is stored. */
               ReadMyConfig(argv[0]);
               /* ... */
            }

SEE ALSO
  GetConfigString ReadConfig DiscardConfig WriteConfig

## NewConfig

NAME

            NewConfig

DESCRIPTION

            Creates a new config file in memory. Once created you can add to
            it as usual.

SYNOPSIS

            #include "pal.h"
            void  NewConfig(char *CfgName);

INPUTS

            CfgName - the name of the config file - this does NOT have to be
                      a real file name. It is used only for the Prolog
                      section.

NOTE

            NewConfig has no return value

            An extra section is created in memory when the file is read. This
            section is called the "Prolog" section. The actual section name
            is what you passed in in CfgName This section header is NOT
            written back to the file. It is used solely to keep track of and
            maintain comments in the config file, prior to the first real
            section.

SAMPLE

            void main(void)
            {
               NewConfig("MYAPP.CFG"); /* Create config file for future use */
               /* ... */

SEE ALSO
  GetConfigString ReadMyConfig DiscardConfig WriteConfig

## GetConfigString

NAME

            GetConfigString

DESCRIPTION

            GetConfigString will retrieve a string value from the config file,
            given a section name and a key. If the section and/or the key does
            not exist, it will return a default value that you provide.

SYNOPSIS

            #include "pal.h"
            char *GetConfigString(char *Section, char *Key, char *Default);

INPUTS

            Section - The name of the section (in angular brackets in the CFG)
                      where you want your value retrieved from.
            Key     - The key, i.e. the left hand side of the assignment in the
                      CFG file.
            Default - what should be returned if the section/key pair cannot be
                      found.

RETURN VALUE

            A pointer to the value, or the default. Note that you should not
            write to this pointer since its storage belongs to the config
            routines. Copy the string to a local buffer if you need to modify
            it.

NOTE

            You can also pass NULL as default string. This is useful to detect
            the absence of a certain section/key pair in the config file. (Or
            the absence of the config file altogether) If you pass NULL as
            default value and get NULL as return value, you can be certain that
            the section/key was not present - GetConfigString will never return
            NULL otherwise.

SAMPLE

            char *SerialCode;

            SerialCode = GetConfigString("User", "Serial", NULL);
            if(SerialCode == NULL) {
               FatalExit("No 'Serial =' in [User] section of CFG file);
            }

SEE ALSO
  GetConfigInt

## GetConfigInt

NAME

            GetConfigInt

DESCRIPTION

            GetConfigInt will retrieve a integer value from the config file,
            given a section name and a key. If the section and/or the key does
            not exist or is not valid, it will return a default value that you
            provide.

SYNOPSIS

            #include "pal.h"
            int GetConfigInt(char *Section, char *Key, int Default);

INPUTS

            Section - The name of the section (in angular brackets in the CFG)
                      where you want your value retrieved from.
            Key     - The key, i.e. the left hand side of the assignment in the
                      CFG file.
            Default - what should be returned if the section/key pair cannot be
                      found. Note that 'Default' is an int here. There is no error
                      condition, the default is returned if the entry does not
                      exist or is not valid.

RETURN VALUE

            The integer value, or the default. (If the section/key pair does
            not exist or if the value is syntactically wrong)

NOTE

            GetConfigInt can also handle hexadecimal and octal values. It assumes
            hex when a value starts with 0x or 0X. Octal is assumed for values
            starting with a zero.

SAMPLE

            int ComBase;

            /* Get COM base address */
            ComBase = GetConfigInt("SerialPort", "Address", 0x3f8);

SEE ALSO
  GetConfigString

## GetFirstEntry

NAME

            GetFirstEntry

DESCRIPTION

            Used to scan all entries of a given section - initiates scan. Returns
            a pointer to the first value string if the section exists, or NULL if
            it does not. Can also return a pointer to the key.

SYNOPSIS

            #include "pal.h"
            char *GetFirstEntry(char *Section, char **pKey);

INPUTS

            Section - The name of the section you want to scan.
            pKey    - a pointer to a string pointer - if not NULL, will be
                      set to point to the first key string if found.

RETURN VALUE

            Will return a pointer to the first value in the section, or NULL if
            the specified section/key pair does not exist.

NOTE

            GetFirstEntry and GetNextEntry use internal static variables to
            store state information. You can only have one active
            GetFirst/NextEntry loop at a time. (That is, in such a loop, you
            can't call a function that itself uses these routines)

SAMPLE

            See the GetNextEntry description for a complete example.

SEE ALSO
  GetNextEntry GetCfgLine

## GetNextEntry

NAME

            GetNextEntry

DESCRIPTION

            Returns the next entry in a section scan. If char **pKey is not NULL,
            the pointer *pKey will be set to point to the key string too.

SYNOPSIS

            #include "pal.h"
            char *GetNextEntry(char **pKey);

INPUTS

            pKey    - a pointer to a string pointer - if not NULL, will be
                      set to point to the next key string if found.

RETURN VALUE

            Will return a pointer to the next value in the section, or NULL if
            there is no next value. (i.e. you have retrieved the last one)

NOTE

            GetFirstEntry and GetNextEntry use internal static variables to
            store state information. You can only have one active
            GetFirst/NextEntry loop at a time. (That is, in such a loop, you
            can't call a function that itself uses these routines)

SAMPLE

            This program will scan and print all key/name pairs of the 'Printer'
            section in 'SETUP.CFG'. It also illustrates a typical GetFirst/Next
            loop.

            #include <stdio.h>
            #include <stdlib.h>

            #include "pal.h"

            void main(void)
            {
               char *Key;
               char *Value;

               ReadConfig("SETUP.CFG");

               if(Value = GetFirstEntry("Printer", &Key)) do {
                  printf("The key %s has the value '%s'", Key, Value);
               } while(Value = GetNextEntry(&Key);
               else printf("Section 'Printer' not found or empty\n");

               DiscardConfig();
            }

SEE ALSO
  GetFirstEntry GetCfgLine

## GetFirstSection

NAME

            GetFirstSection

DESCRIPTION

            Used to scan all sections  of a given file - initiates scan. Returns
            a pointer to the first section string if a section exists, or NULL if
            it does not.

SYNOPSIS

            #include "pal.h"
            char *GetFirstSection( void );

RETURN VALUE

            Will return a pointer to the first section in the file, or NULL if
            no sections exist.

NOTE

            GetFirstSection and GetNextSection use internal static variables to
            store state information. You can only have one active
            GetFirst/NextSection loop at a time. (That is, in such a loop, you
            can't call a function that itself uses these routines)

            An extra section is created in memory when the file is read.
            This section is called the "Prolog" section. The actual section
            name is the fully qualified file specification of the config
            file. This section header is NOT written back to the file. It
            is used solely to keep track of and maintain comments in the
            config file, prior to the first real section.

SAMPLE

            See the GetNextSection description for a complete example.

SEE ALSO
  GetNextSection

## GetNextSection

NAME

            GetNextSection

DESCRIPTION

            Returns the next section in a config file scan.

SYNOPSIS

            #include "pal.h"
            char *GetNextSection( void );

RETURN VALUE

            Will return a pointer to the next section in the config file, or NULL if
            there is no next section. (i.e. you have retrieved the last one)

NOTE

            GetFirstSection and GetNextSection use internal static variables to
            store state information. You can only have one active
            GetFirst/NextSection loop at a time. (That is, in such a loop, you
            can't call a function that itself uses these routines)

            An extra section is created in memory when the file is read.
            This section is called the "Prolog" section. The actual section
            name is the fully qualified file specification of the config
            file. This section header is NOT written back to the file. It
            is used solely to keep track of and maintain comments in the
            config file, prior to the first real section.

SAMPLE

            This program will scan and print sections in the config file 'SETUP.CFG'.
            It also illustrates a typical GetFirst/Next loop.

            #include <stdio.h>
            #include <stdlib.h>

            #include "pal.h"

            void main(void)
            {
               char *Section;

               ReadConfig("SETUP.CFG");

               if(Section = GetFirstSection()) do {
                  printf("The section is %s\n", Section);
               } while(Section = GetNextSection();
               else printf("No Sections found\n");

               DiscardConfig();
            }

SEE ALSO
  GetFirstSection

## GetCfgLine

NAME

            GetCfgLine

DESCRIPTION

            Returns, for the last entry retrieved via GetFirstEntry/GetNextEntry,
            the line number of the config file this entry was defined on - useful
            if you need to output line number information in an error message.

SYNOPSIS

            #include "pal.h"
            int GetCfgLine(void);

SAMPLE

            printf("The last line was %d\n", GetCfgLine());

SEE ALSO
  GetNextEntry GetCfgLine

## AddConfigString

NAME

            AddConfigString

DESCRIPTION

            This function will add a new key=value pair to the currently opened
            config file. It will search for the Section provided and if found add
            the new pair as the last entry in that section. If the Section dows
            not exist, it will be created and the entry added to it.
            AddConfigString does not check to see if there is another key of the
            same name already there. This allows multiple values with the same
            key. If you need to just replace the value for a key use
            ReplaceConfigString.

SYNOPSIS

            #include "pal.h"
            void  AddConfigString(char *Section, char *Key, char *Value );

INPUTS

            char *Section  - Section header in config file. Do not include the
                             surrounding [].

            char *Key      - Key of the key=value pair. If this is a NULL string
                             ("") then the value takes on a special meaning.

            char *Value    - Value of the key=value pair. If Key is a NULL string
                             ("") then if value starts with a ; a comment is
                             inserted in the config file. If value is also a NULL
                             string then a blank line is inserted in the config
                             file.

RETURN VALUE

            None

SAMPLE

            This sample reads in the config file "Setup.Cfg", adds the
            printer=lpt1: pair to the DEVICES section, writes the file to disk,
            and cleans up the storage that was allocated for the file.

            #include "pal.h"

            void main(void)
            {
               ReadConfig("SETUP.CFG");
               AddConfigString("DEVICES","printer","lpt1:");
               WriteConfig("SETUP.CFG")
               DiscardConfig();
            }

SEE ALSO
  ReplaceConfigString

## ReplaceConfigString

NAME

            ReplaceConfigString

DESCRIPTION

            This function will replace the value from an existing key=value pair
            if it exists in a config file. If the key does not exist it will be
            added similr to AddConfigString().

SYNOPSIS

            #include "pal.h"
            void  ReplaceConfigString(char *Section, char *Key, char *Value );

            char *Section  - Section header in config file. Do not include the
                             surrounding [].

            char *Key      - Key of the key=value pair. This is the value
                             searched for in the given Section.

            char *Value    - Value of the key=value pair.

RETURN VALUE

            None

SAMPLE

            This sample reads in the config file "Setup.Cfg", replaces the
            printer keys value with the value lpt2: in the DEVICES section,
            writes the file to disk, and cleans up the storage that was allocated
            for the file.

            #include "pal.h"

            void main(void)
            {
               ReadConfig("SETUP.CFG");
               ReplaceConfigString("DEVICES","printer","lpt2:");
               WriteConfig("SETUP.CFG")
               DiscardConfig();
            }

SEE ALSO
  AddConfigString

## AddConfigInt

NAME

            AddConfigInt

DESCRIPTION

            This function will add a new key=value pair to the currently opened
            config file. It will search for the Section provided and if found add
            the new pair as the last entry in that section. If the Section dows
            not exist, it will be created and the entry added to it.
            AddConfigInt does not check to see if there is another key of the
            same name already there. This allows multiple values with the same
            key. If you need to just replace the value for a key use
            ReplaceConfigInt.

SYNOPSIS

            #include "pal.h"
            void  AddConfigInt(char *Section, char *Key, int Value );

INPUTS

            char *Section  - Section header in config file. Do not include the
                             surrounding [].

            char *Key      - Key of the key=value pair.

            int   Value    - Value of the key=value pair.

RETURN VALUE

            None

SAMPLE

            This sample reads in the config file "Setup.Cfg", adds the
            printers=1 pair to the DEVICES section, writes the file to disk,
            and cleans up the storage that was allocated for the file.

            #include "pal.h"

            void main(void)
            {
               ReadConfig("SETUP.CFG");
               AddConfigInt("DEVICES","printers=,1);
               WriteConfig("SETUP.CFG")
               DiscardConfig();
            }

SEE ALSO
  ReplaceConfigInt

## ReplaceConfigInt

NAME

            ReplaceConfigInt

DESCRIPTION

            This function will replace the value from an existing key=value pair
            if it exists in a config file. If the key does not exist it will be
            added similr to AddConfigString().

SYNOPSIS

            #include "pal.h"
            void  ReplaceConfigInt(char *Section, char *Key, int Value );

INPUTS

            char *Section  - Section header in config file. Do not include the
                             surrounding [].

            char *Key      - Key of the key=value pair. This is the value
                             searched for in the given Section.

            int   Value    - Value of the key=value pair.

RETURN VALUE

            None

SAMPLE

            This sample reads in the config file "Setup.Cfg", replaces the
            printers keys value with the value 2 in the DEVICES section,
            writes the file to disk, and cleans up the storage that was allocated
            for the file.

            #include "pal.h"

            void main(void)
            {
               ReadConfig("SETUP.CFG");
               ReplaceConfigString("DEVICES","printers",2);
               WriteConfig("SETUP.CFG")
               DiscardConfig();
            }

SEE ALSO
  AddConfigInt

## DeleteConfigString

NAME

           DeleteConfigString

DESCRIPTION

           Deletes a ConfigEntry. If Section is found then the action depends on
            Key. If Key is NULL then the complete section is removed. If Key is
            provided and is not found nothing is done. If Key is found then the
            action depends on Value. If Value is NULL then all Matching keys are
            deleted. If Value is provided and it is not found then nothing is
            done. If Value is provided and found it is deleted.

SYNOPSIS

            #include "pal.h"
            int   DeleteConfigString(char *Section, char *Key, char *Value);

INPUTS

            parm    - parm description

RETURN VALUE

            Number of lines/entries deleted.

NOTE

            Section must be provided and found or nothing is done.

SAMPLE

            This sample reads in the config file "Setup.Cfg", deletes the printer
            key that has a value of lpt2: in the DEVICES section, writes the file
            to disk, and cleans up the storage that was allocated for the file.

            #include "pal.h"

            void main(void)
            {
               ReadConfig("SETUP.CFG");
               DeleteConfigString("DEVICES","printer","lpt2:");
               WriteConfig("SETUP.CFG")
               DiscardConfig();
            }

SEE ALSO
  AddConfigString ReplaceConfigString

## WriteConfig

NAME

            WriteConfig

DESCRIPTION

            Write the current Config file data from memory to a file.

SYNOPSIS

            #include "pal.h"
            int   WriteConfig(char *CfgName);

INPUTS

            CfgName - the name of the config file - including the
                      extension.

RETURN VALUE

            1 = Success, 0 = Failure

NOTE

            All comments and blank lines from the original config file are
            preserved.

SAMPLE

            This sample reads in the config file "Setup.Cfg", replaces the
            printer keys value with the value lpt2: in the DEVICES section,
            writes the file to disk, and cleans up the storage that was allocated
            for the file.

            #include "pal.h"

            void main(void)
            {
               ReadConfig("SETUP.CFG");
               ReplaceConfigString("DEVICES","printer","lpt2:");
               WriteConfig("SETUP.CFG")
               DiscardConfig();
            }

SEE ALSO
  ReadConfig ReadMyConfig

## DiscardConfig

NAME

            DiscardConfig

DESCRIPTION

            Call this function when you don't need access to the config data
            any more. You must again load a config file before you may
            retrieve data again.

SYNOPSIS

            #include "pal.h"
            void DiscardConfig(void);

SAMPLE

            See the GetNextEntry description for a sample call to DiscardConfig.

SEE ALSO
  ReadConfig ReadMyConfig GetNextEntry