|
| 1 | +# minIni |
| 2 | +minIni is a portable and configurable library for reading and writing ".INI" files. At 830 lines of commented source |
| 3 | +code |
| 4 | +(version 1.2), minIni truly is a "mini" INI file parser, especially considering its features. |
| 5 | + |
| 6 | +The library does not require the file I/O functions from the standard C/C++ library, but instead lets you configure |
| 7 | +the file I/O interface to use via macros. minIni uses limited stack space and does not use dynamic memory (malloc and |
| 8 | +friends) at all. |
| 9 | + |
| 10 | +Some minor variations on standard INI files are supported too, notably minIni supports INI files that lack sections. |
| 11 | + |
| 12 | + |
| 13 | +# Acknowledgement |
| 14 | + |
| 15 | +minIni is derived from an earlier INI file parser (which I wrote) for desktop systems. |
| 16 | + |
| 17 | +In turn, that earlier parser was a re-write of the code from the article "Multiplatform .INI Files" by Joseph J. Graf |
| 18 | +in the March 1994 issue of Dr. Dobb's Journal. In other words, minIni has its roots in the work of Joseph Graf (even |
| 19 | +though the code has been almost completely re-written). |
| 20 | + |
| 21 | + |
| 22 | +# Features |
| 23 | + |
| 24 | +minIni is a programmer's library to read and write "INI" files in embedded systems. minIni takes little resources, |
| 25 | +can be configured for various kinds of file I/O libraries and provides functionality for reading, writing and |
| 26 | +deleting keys from an INI file. |
| 27 | + |
| 28 | +Although the main feature of minIni is that it is small and minimal, it has a few other features: |
| 29 | + |
| 30 | + * minIni supports reading keys that are outside a section, and it thereby supports configuration files that do not use sections (but that are otherwise compatible with INI files). |
| 31 | + * You may use a colon to separate key and value; the colon is equivalent to the equal sign. That is, the strings "Name: Value" and "Name=Value" have the same meaning. |
| 32 | + * The hash character ("#") is an alternative for the semicolon to start a comment. Trailing comments (i.e. behind a key/value pair on a line) are allowed. |
| 33 | + * Leading and trailing white space around key names and values is ignored. |
| 34 | + * When writing a value that contains a comment character (";" or "#"), that value will automatically be put between double quotes; when reading the value, these quotes are removed. When a double-quote itself appears in the setting, these characters are escaped. |
| 35 | + * Section and key enumeration are supported. |
| 36 | + * You can optionally set the line termination (for text files) that minIni will use. (This is a compile-time setting, not a run-time setting.) |
| 37 | + * Since writing speed is much lower than reading speed in Flash memory (SD/MMC cards, USB memory sticks), minIni minimizes "file writes" at the expense of double "file reads". |
| 38 | + * The memory footprint is deterministic. There is no dynamic memory allocation. |
| 39 | + |
| 40 | +## INI file reading paradigms |
| 41 | + |
| 42 | +There are two approaches to reading settings from an INI file. One way is to call a function, such as |
| 43 | +GetProfileString() for every section and key that you need. This is especially convenient if there is a large |
| 44 | +INI file, but you only need a few settings from that file at any time —especially if the INI file can also |
| 45 | +change while your program runs. This is the approach that the Microsoft Windows API uses. |
| 46 | + |
| 47 | +The above procedure is quite inefficient, however, when you need to retrieve quite a few settings in a row from |
| 48 | +the INI file —especially if the INI file is not cached in memory (which it isn't, in minIni). A different approach |
| 49 | +to getting settings from an INI file is to call a "parsing" function and let that function call the application |
| 50 | +back with the section and key names plus the associated data. XML parsing libraries often use this approach; see |
| 51 | +for example the Expat library. |
| 52 | + |
| 53 | +minIni supports both approaches. For reading a single setting, use functions like ini_gets(). For the callback |
| 54 | +approach, implement a callback and call ini_browse(). See the minIni manual for details. |
| 55 | + |
| 56 | + |
| 57 | +# INI file syntax |
| 58 | + |
| 59 | +INI files are best known from Microsoft Windows, but they are also used with applications that run on other |
| 60 | +platforms (although their file extension is sometimes ".cfg" instead of ".ini"). |
| 61 | + |
| 62 | +INI files have a simple syntax with name/value pairs in a plain text file. The name must be unique (per section) |
| 63 | +and the value must fit on a single line. INI files are commonly separated into sections —in minIni, this is |
| 64 | +optional. A section is a name between square brackets, like "[Network]" in the example below. |
| 65 | + |
| 66 | +``` |
| 67 | +[Network] |
| 68 | +hostname=My Computer |
| 69 | +address=dhcp |
| 70 | +dns = 192.168.1.1 |
| 71 | +``` |
| 72 | + |
| 73 | +In the API and in this documentation, the "name" for a setting is denoted as the key for the setting. The key |
| 74 | +and the value are separated by an equal sign ("="). minIni supports the colon (":") as an alternative to the |
| 75 | +equal sign for the key/value delimiter. |
| 76 | + |
| 77 | +Leading a trailing spaces around values or key names are removed. If you need to include leading and/or trailing |
| 78 | +spaces in a value, put the value between double quotes. The ini_gets() function (from the minIni library, see the |
| 79 | +minIni manual) strips off the double quotes from the returned value. Function ini_puts() adds double quotes if |
| 80 | +the value to write contains trailing white space (or special characters). |
| 81 | + |
| 82 | +minIni ignores spaces around the "=" or ":" delimiters, but it does not ignore spaces between the brackets in a |
| 83 | +section name. In other words, it is best not to put spaces behind the opening bracket "[" or before the closing |
| 84 | +bracket "]" of a section name. |
| 85 | + |
| 86 | +Comments in the INI must start with a semicolon (";") or a hash character ("#"), and run to the end of the line. |
| 87 | +A comment can be a line of its own, or it may follow a key/value pair (the "#" character and trailing comments |
| 88 | +are extensions of minIni). |
| 89 | + |
| 90 | +For more details on the format, please see http://en.wikipedia.org/wiki/INI_file. |
| 91 | + |
| 92 | + |
| 93 | +# Adapting minIni to a file system |
| 94 | + |
| 95 | +The minIni library must be configured for a platform with the help of a so- called "glue file". This glue file |
| 96 | +contains macros (and possibly functions) that map file reading and writing functions used by the minIni library |
| 97 | +to those provided by the operating system. The glue file must be called "minGlue.h". |
| 98 | + |
| 99 | +To get you started, the minIni distribution comes with the following example glue files: |
| 100 | + |
| 101 | + * a glue file that maps to the standard C/C++ library (specifically the file I/O functions from the "stdio" package), |
| 102 | + * a glue file for Microchip's "Memory Disk Drive File System Library" (see http://www.microchip.com/), |
| 103 | + * a glue file for the FAT library provided with the CCS PIC compiler (see http://www.ccsinfo.com/) |
| 104 | + * a glue file for the EFS Library (EFSL, http://www.efsl.be/), |
| 105 | + * and a glue file for the FatFs and Petit-FatFs libraries (http://elm-chan.org/fsw/ff/00index_e.html). |
| 106 | + |
| 107 | +The minIni library does not rely on the availability of a standard C library, because embedded operating systems |
| 108 | +may have limited support for file I/O. Even on full operating systems, separating the file I/O from the INI format |
| 109 | +parsing carries advantages, because it allows you to cache the INI file and thereby enhance performance. |
| 110 | + |
| 111 | +The glue file must specify the type that identifies a file, whether it is a handle or a pointer. For the standard |
| 112 | +C/C++ file I/O library, this would be: |
| 113 | + |
| 114 | +```C |
| 115 | +#define INI_FILETYPE FILE* |
| 116 | +``` |
| 117 | + |
| 118 | +If you are not using the standard C/C++ file I/O library, chances are that you need a different handle or |
| 119 | +"structure" to identify the storage than the ubiquitous "FILE*" type. For example, the glue file for the FatFs |
| 120 | +library uses the following declaration: |
| 121 | + |
| 122 | +```C |
| 123 | +#define INI_FILETYPE FIL |
| 124 | +``` |
| 125 | + |
| 126 | +The minIni functions declare variables of this INI_FILETYPE type and pass these variables to sub-functions |
| 127 | +(including the glue interface functions) by reference. |
| 128 | + |
| 129 | +For "write support", another type that must be defined is for variables that hold the "current position" in a |
| 130 | +file. For the standard C/C++ I/O library, this is "fpos_t". |
| 131 | + |
| 132 | +Another item that needs to be configured is the buffer size. The functions in the minIni library allocate this |
| 133 | +buffer on the stack, so the buffer size is directly related to the stack usage. In addition, the buffer size |
| 134 | +determines the maximum line length that is supported in the INI file and the maximum path name length for the |
| 135 | +temporary file. For example, minGlue.h could contain the definition: |
| 136 | + |
| 137 | +```C |
| 138 | +#define INI_BUFFERSIZE 512 |
| 139 | +``` |
| 140 | + |
| 141 | +The above macro limits the line length of the INI files supported by minIni to 512 characters. |
| 142 | + |
| 143 | +The temporary file is only used when writing to INI files. The minIni routines copy/change the INI file to a |
| 144 | +temporary file and then rename that temporary file to the original file. This approach uses the least amount of |
| 145 | +memory. The path name of the temporary file is the same as the input file, but with the last character set to a |
| 146 | +tilde ("~"). |
| 147 | + |
| 148 | +Below is an example of a glue file (this is the one that maps to the C/C++ "stdio" library). |
| 149 | + |
| 150 | +```C |
| 151 | +#include <stdio.h> |
| 152 | + |
| 153 | +#define INI_FILETYPE FILE* |
| 154 | +#define ini_openread(filename,file) ((*(file) = fopen((filename),"r")) != NULL) |
| 155 | +#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"w")) != NULL) |
| 156 | +#define ini_close(file) (fclose(*(file)) == 0) |
| 157 | +#define ini_read(buffer,size,file) (fgets((buffer),(size),*(file)) != NULL) |
| 158 | +#define ini_write(buffer,file) (fputs((buffer),*(file)) >= 0) |
| 159 | +#define ini_rename(source,dest) (rename((source), (dest)) == 0) |
| 160 | +#define ini_remove(filename) (remove(filename) == 0) |
| 161 | + |
| 162 | +#define INI_FILEPOS fpos_t |
| 163 | +#define ini_tell(file,pos) (fgetpos(*(file), (pos)) == 0) |
| 164 | +#define ini_seek(file,pos) (fsetpos(*(file), (pos)) == 0) |
| 165 | +``` |
| 166 | + |
| 167 | +As you can see, a glue file is mostly a set of macros that wraps one function definition around another. |
| 168 | + |
| 169 | +The glue file may contain more settings, for support of rational numbers, to explicitly set the line termination |
| 170 | +character(s), or to disable write support (for example). See the manual that comes with the archive for the details. |
0 commit comments