A simple .ini file interface.

Dependents:   Smart-WiFly-WebServer SignalGenerator WattEye X10Svr

IniManager.h

Committer:
WiredHome
Date:
2020-06-11
Revision:
28:4e7fc08a0fea
Parent:
24:ba5fa9548f59

File content as of revision 28:4e7fc08a0fea:


#ifndef INIMANAGER_H
#define INIMANAGER_H

#define INTERNAL_BUF_SIZE 250


/** A simple INI file manager - Version 2.
*
* This is a simple ini file manager intended for low duty cycle usage. 
*
* It follows an old "Windows" style of ini file format with section, key, and value.
*
* @note An API change offers DIFFERENT AND INCOMPATIBLE return values from the 
*       WriteString and the ReadString APIs, however it is backward compatible,
*       requiring a new parameter in the constructor or the SetFile API to 
*       access the new return values.
*
* @note Version 1 by default will be deprecated in a future release, probably 
*       around mid to late 2017.
* 
* As a "simple" ini file manager, this version does not cache anything internally.
* This comes at the "cost" that each write transaction will read and replace the
* ini file. Read transactions will open and scan the file.
*
* Also, an internal stack-frame buffer is used to manage the read operations. As
* such, no single record in the file can exceed this buffer size (compile time set
* with a default of 250 bytes). 
*
* @code
* INI ini("/local/settings.ini");
* ...
* char buf[10];
* sprintf_s(buf, 10, "%d", daymask);
* if (INI::INI_SUCCESS == ini.WriteString("Alarm", "Daymask", buf)) {
*     ...
* }
* ...
* uint8_t x = (uint8_t)ReadLongInt("Alarm", "Daymask", 0);
* ...
* @endcode 
*
* A single record for a section is surrounded with '[' and ']' and a new line 
* appended. A single record for an entry within a section for a key, value pair 
* is separated with an '=' and a new line appended.
* @code
* [section name]
* Key name=value for Key name
* Another key=another value
* @endcode
*/
class INI
{
public:

    /** Return values 
    *
    * Functions may return a status code as follows. Where the API supports
    * a default, and on a Fail code, that value will be returned, if it
    * fits in the available buffer.
    *
    * @note Version 1 returned only a success or failure value from the ReadString
    *       and the WriteString APIs. Version 2 returns incompatible and different
    *       values. The selection of version 1 vs. version 2 is made in either
    *       the constructor, or in the SetFile API.
    */
    typedef enum {
        INI_V1_FAIL = 0,        ///< Version 1 return value - Fail
        INI_V1_SUCCESS = 1,     ///< Version 1 return value - Success
        INI_SUCCESS = 0,        ///< Success - operation succeeded
        INI_NO_FILE_SPEC,       ///< Fail - no file was specified
        INI_FILE_NOT_FOUND,     ///< Fail - ini file not found, or failed to open
        INI_SECTION_NOT_FOUND,  ///< Fail - section not found
        INI_KEY_NOT_FOUND,      ///< Fail - key not found
        INI_BUF_TOO_SMALL,      ///< Fail - buffer to small for value
        INI_INTERNAL_ERROR      ///< Fail - internal error - can't alloc buffers
    } INI_Return;

    /** Constructor for an INI file interface.
    *
    * Constructor for an INI file interface.
    *
    * @param[in] file is the filename to manage. Memory is allocated to hold
    *       a private copy of the filename. Be sure that this parameter
    *       has the right path prefix based on what file system you have.
    * @param[in] Version is an optional parameter that defines whether 
    *       the return value of the ReadString and WriteString APIs 
    *       are version 1 or version 2 compatible. The default is version 2.
    */
    INI(const char * file = NULL, int Version = 2);

    /** destructor for the ini manager.
    *
    * releases the memory allocation.
    */
    ~INI(void);

    /** Determine if a file exists
    *
    * This API can be used to determine if a file exists. The file may
    * be specified as a parameter, but if no parameter is supplied it will
    * then check to see if the INI file exists. This is either the file
    * passed to the constructor, or the file passed to the SetFile API.
    *
    * @param[in] file is the optional filename to check for existance.
    * @returns true if the file exists.
    */
    bool Exists(const char * file = NULL);

    /** set the file to use
    *
    * If not set at the time of construction, or if a change is needed, this
    * API can be used.
    *
    * @param[in] file is the filename to manage.
    * @param[in] Version is an optional parameter that defines whether 
    *       the return value of the ReadString and WriteString APIs 
    *       are version 1 or version 2 compatible. The default is version 2.
    * @returns true if success, false if memory could not be allocated.
    */
    bool SetFile(const char * file, int Version = 2);

    /** get the filename in use
    *
    * @returns pointer to the filename
    */
    const char * GetFile(void) { return iniFile; }

    /** Read a string from the ini file - if it exists.
    *
    * This searches the ini file for the named section and key and if found it will
    * return the string associated with that entry into a user supplied buffer.
    * 
    * @param[in] section is the name of the section to search.
    * @param[in] key is the name of the key to search.
    * @param[out] buffer is the caller provided buffer for this method to put the string into.
    * @param[in] bufferSize is the caller provided declaration of the available space.
    * @param[in] defaultString is an optional parameter that sets the buffer if the section/key is not found.
    *           if defaultString is NULL (or omitted), and if the item cannot be found, 
    *           it will return INI_KEY_NOT_FOUND.
    * 
    * @return INI_SUCCESS if the file, section, key, and value are found, and it fits into the specified buffer.
    * @return INI_NO_FILE_SPEC if the ini file was never set.
    * @return INI_FILE_NOT_FOUND if the ini file was specified, but cannot be found as specified.
    * @return INI_SECTION_NOT_FOUND if the section was not found.
    * @return INI_KEY_NOT_FOUND if the key was not found.
    * @return INI_BUF_TOO_SMALL if everything was found, but it could not fit into the specified buffer.
    */
    INI_Return ReadString(const char * section, const char * key, char * buffer, size_t bufferSize, const char * defaultString = NULL);

    /** Read a long integer from the ini file - if it exists.
    *
    * This searches the ini file for the named section and key and if found it will 
    * return the long integer value from that entry.
    *
    * @param[in] section is the name of the section to search.
    * @param[in] key is the name of the key to search.
    * @param[in] defaultValue is the default value to return if the entry is not found.
    *
    * @return the value read, or the defaultVaule; no failure code is returned.
    */
    long int ReadLongInt(const char * section, const char * key, long int defaultValue);

    /** Writes a string into the ini file
    *
    * This writes a given string into an ini file in the named section and key.
    * 
    * @param[in] section is the name of the section to search.
    * @param[in] key is the name of the key to search.
    * @param[in] buffer is the caller provided buffer containing the string to write. If
    *       buffer is NULL, then any existing entry is removed.
    * @param[in] len is the number of characters to write, if specified. If not specified,
    *       the length of the buffer defines the length to write.
    *
    * @return INI_SUCCESS if the file, section, key, and value are written.
    * @return INI_NO_FILE_SPEC if the ini file was never set.
    * @return INI_FILE_NOT_FOUND if the ini file was specified, but cannot be found as specified.
    * @return INI_SECTION_NOT_FOUND if the section was not found.
    * @return INI_KEY_NOT_FOUND if the key was not found.
    * @return INI_BUF_TOO_SMALL if everything was found, but it could not fit into the specified buffer.
    */
    INI_Return WriteString(const char * section, const char * key, const char * buffer, int len = -1);


    /** Writes a long integer into the ini file
    *
    * This writes a given long integer into an ini file in the named section and key.
    * 
    * @param[in] section is the name of the section to search.
    * @param[in] key is the name of the key to search.
    * @param[in] value is the long integer.
    *
    * @return INI_SUCCESS if the file, section, key, and value are written.
    * @return INI_NO_FILE_SPEC if the ini file was never set.
    * @return INI_FILE_NOT_FOUND if the ini file was specified, but cannot be found as specified.
    * @return INI_SECTION_NOT_FOUND if the section was not found.
    * @return INI_KEY_NOT_FOUND if the key was not found.
    * @return INI_BUF_TOO_SMALL if everything was found, but it could not fit into the specified buffer.
    */
    INI_Return WriteLongInt(const char * section, const char * key, long int value);

    /** Get Section, or Next Section name
    *
    * This can be used to walk the list of section names in a file.
    *
    * @param[in] After is the name of the section to search after. When NULL, it
    *           is a "find-first" method.
    * @param[out] buffer is the caller provided buffer for this method to put the string into.
    * @param[in] bufferSize is the caller provided declaration of the available space.
    * @returns true if a new section was found, false otherwise.
    */
    bool GetNextSection(const char * after, char * buffer, size_t bufferSize);
    

    /** Get the first Key, or the next Key, within a section
    *
    * This can be used to walk the list of keys in a file.
    *
    * @param[in] Section is the name of the section to search.
    * @param[in] After is the name of the key to search after. When NULL, it
    *           is a "find-first" method.
    * @param[out] buffer is the caller provided buffer for this method to put the string into.
    * @param[in] bufferSize is the caller provided declaration of the available space.
    * @returns true if a new key was found, false otherwise.
    */
    bool GetNextKey(const char * Section, const char * after, char * buffer, size_t bufferSize);
    

    /** Get the text message for an error return value from ReadString and WriteString.
    *
    * @param[in] retVal is the return value from either the ReadString or the WriteString
    *           APIs.
    * @returns a pointer to a string which describes the return value.
    */
    const char * GetReturnMessage(INI_Return retVal);

private:
    char * iniFile;

    /** Version of the return values
    */
    int version;
    
    /** Cleanup temporary files.
    *
    * This will attempt to clean up any temporary files. This can happen
    * while writing a new file, if something went wrong and the program 
    * crashed or otherwise could not complete the process.
    * This will look for the temp files, try to finish processing them
    * and remove the extraneous.
    *
    * @return true, always until I find a reason not to.
    */
    bool CleanUp();
    
    /** Rename a file
    *
    * This version also works on the local file system.
    *
    * @param[in] oldfname is the old file name
    * @param[in] newfname is the new file name
    * @returns 0 on success, -1 on error
    */
    int Rename(const char *oldfname, const char *newfname);
    
    /** Copy a file
    *
    * This version also works on the local file system.
    *
    * @param[in] src is the source file
    * @param[in] dst is the destination file
    * @returns 0 on success, -1 on error
    */
    int Copy(const char *src, const char *dst);
};

#endif // INIMANAGER_H