Changeset 95

Show
Ignore:
Timestamp:
02/05/07 06:33:05 (2 years ago)
Author:
KirkMcDonald
Message:

Added configparse docs.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • misc/configparse.d

    r94 r95  
    2626 
    2727import std.stream : Stream, BufferedFile, FileMode; 
    28 import std.string : find, strip, toString, tolower
     28import std.string : find, strip, toString, tolower, split
    2929import std.file : exists; 
    3030import std.conv : toInt, toReal, ConvError; 
     31import std.path : getBaseName, getDirName, join, pathsep; 
     32import std.c.stdlib : getenv; 
    3133 
    3234import std.stdio : writefln; 
    3335 
    34 // Thrown when configparse is unable to parse a file. 
     36/// Thrown when configparse is unable to parse a file. 
    3537class ConfigParseError : Exception { 
    3638    this(char[] msg) { super(msg); } 
    3739} 
    38 // Thrown when configparse is unable to coerce a value to a requested type. 
     40/// Thrown when configparse is unable to coerce a value to a requested type. 
    3941class ConfigConvertError : Exception { 
    4042    this(char[] msg) { super(msg); } 
    4143} 
    42 // Thrown when user adds already-existing section to parser. 
     44/// Thrown when user adds already-existing section to parser. 
    4345class DuplicateSectionError : Exception { 
    4446    this(char[] msg) { super(msg); } 
    4547} 
    46 // Thrown when a section is not found. 
     48/// Thrown when a section is not found. 
    4749class SectionNotFoundError : Exception { 
    4850    this(char[] msg) { super(msg); } 
    4951} 
    50 // Thrown when an option is not found. 
     52/// Thrown when an option is not found. 
    5153class OptionNotFoundError : Exception { 
    5254    this(char[] msg) { super(msg); } 
    5355} 
    5456 
     57/// The name of the global section. This is currently "General". 
    5558const char[] GLOBAL_SECTION = "General"; 
    5659 
     60// Returns the name of the executable, minus directories or extensions. 
     61char[] get_program_name(char[] path) { 
     62    version(Windows) { 
     63        // (Unicode note: ".exe" only contains 4 code units, so this slice 
     64        // should Just Work.) (Although it remains to be seen how robust 
     65        // this code actually is.) 
     66        assert(path[$-4 .. $] == ".exe"); 
     67        path = path[0 .. $-4]; 
     68    } 
     69    return getBaseName(path); 
     70} 
     71char[] env(char* var) { 
     72    return toString(getenv(var)); 
     73} 
     74/++ 
     75Returns the path of a config file (filename) in the same directory as the 
     76executable (arg0). 
     77+/ 
     78char[] same_dir(char[] arg0, char[] filename) { 
     79    version (Windows) { 
     80        return join(getDirName(arg0), filename); 
     81    } else { 
     82        char[] dir = getDirName(arg0); 
     83        if (dir == "") { 
     84            char[][] paths = split(env("PATH"), pathsep); 
     85            foreach (path; paths) { 
     86                if (exists(join(path, getBaseName(arg0)))) 
     87                    return join(path, filename); 
     88            } 
     89            return ""; 
     90        } else { 
     91            return join(dir, filename); 
     92        } 
     93    } 
     94} 
     95/++ 
     96Returns a nice "default" list of config files. arg0 should be the first element 
     97of the args array passed to main(). The optional name parameter should be the _name of the config file, 
     98minus any extension. It defaults to the executable's _name, minus any directory 
     99or extension. 
     100 
     101On Windows, the returned filenames are: 
     102$(UL 
     103    $(LI name.ini alongside the .exe) 
     104    $(LI %HOMEDRIVE%%HOMEPATH%\name.ini) 
     105    $(LI .\name.ini) 
     106) 
     107 
     108On all other platforms (e.g. Linux), the returned filenames are: 
     109$(UL 
     110    $(LI /etc/name.conf) 
     111    $(LI name.ini alongside the binary) 
     112    $(LI ~/.namerc) 
     113    $(LI ./name.conf) 
     114) 
     115+/ 
     116char[][] config_files(char[] arg0, char[] name=null) { 
     117    if (name is null) name = get_program_name(arg0); 
     118    version (Windows) { 
     119        name ~= ".ini"; 
     120        return [ 
     121            same_dir(arg0, name), 
     122            join(env("HOMEDRIVE")~env("HOMEPATH"), name), 
     123            name 
     124        ]; 
     125    } else { 
     126        return [ 
     127            "/etc/"~name~".conf", 
     128            same_dir(arg0, name~".ini"), 
     129            "~/."~name~"rc", 
     130            name~".conf" 
     131        ]; 
     132    } 
     133} 
     134 
     135/++ 
     136The ConfigParser class represents a config file. 
     137+/ 
    57138class ConfigParser { 
    58139    char[][char[]][char[]] config; 
     
    61142    } 
    62143 
     144    /++ 
     145    Returns a list of the _sections in the parser, including the global 
     146    section. ("General" by default.) 
     147    +/ 
    63148    char[][] sections() { 
    64149        return this.config.keys; 
    65150    } 
     151    /++ 
     152    Adds a section named name to the parser. 
     153     
     154    Throws: DuplicateSectionError if the section already exists. 
     155    +/ 
    66156    void add_section(char[] name) { 
    67157        auto section = name in config; 
     
    72162        } 
    73163    } 
     164    /// Requests if a section exists in the parser. 
    74165    bool has_section(char[] name) { 
    75166        return name in config !is null; 
    76167    } 
    77168    private void no_section(char[] section) { 
    78         throw new SectionNotFoundError("Section '"~section~"' not found."); 
    79     } 
    80     private void no_option(char[] option) { 
    81         throw new OptionNotFoundError("Option '"~option~"' not found."); 
    82     } 
     169        throw new SectionNotFoundError("Configuration section '"~section~"' not found."); 
     170    } 
     171    private void no_option(char[] section, char[] option) { 
     172        throw new OptionNotFoundError("Configuration option '"~option~"' in section '"~section~"' not found."); 
     173    } 
     174    /++ 
     175    Returns a list of _options in the given section. 
     176 
     177    Throws: SectionNotFoundError 
     178    +/ 
    83179    char[][] options(char[] section=GLOBAL_SECTION) { 
    84180        auto s = section in config; 
     
    86182        return s.keys; 
    87183    } 
     184    /++ 
     185    Returns a list of _values in the given section. 
     186 
     187    Throws: SectionNotFoundError 
     188    +/ 
    88189    char[][] values(char[] section=GLOBAL_SECTION) { 
    89190        auto s = section in config; 
     
    91192        return s.values; 
    92193    } 
     194    /++ 
     195    Returns whether the given option exists in the given section. This method 
     196    (and all of the others in this form) will set option to section, and 
     197    section to the global _section, when only one argument is provided. (In 
     198    other words, providing only one argument will check for options in the 
     199    global _section.) This will silently return false if the section does not 
     200    exist. 
     201    +/ 
    93202    bool has_option(char[] section, char[] option=null) { 
    94203        if (option is null) { 
     
    102211        else return true; 
    103212    } 
     213    /++ 
     214    Reads a series of files into the parser, in the order provided. Files that 
     215    don't exist will be silently skipped. Options specified in later files will 
     216    override those specified in earlier files. 
     217 
     218    Returns: A list of files _read in. 
     219    Throws: ConfigParseError if a file contains errors. 
     220    +/ 
    104221    char[][] read(char[][] filenames...) { 
    105222        char[][] files_read; 
     
    107224            if (!exists(filename)) continue; 
    108225            files_read ~= filename; 
    109             this.read(new BufferedFile(filename), filename); 
     226            Stream s = new BufferedFile(filename); 
     227            this.read(s, filename); 
     228            delete s; 
    110229        } 
    111230        return files_read; 
    112231    } 
     232    /++ 
     233    Reads in any Stream as a config _file. 
     234 
     235    Params: 
     236        filename = An optional argument for clarifying error output. 
     237    Throws: ConfigParseError if the stream contains errors. 
     238    +/ 
    113239    void read(Stream file, char[] filename="") { 
    114240        if (filename.length != 0) filename ~= " "; 
     
    139265        } 
    140266    } 
     267    /++ 
     268    Retrieves the value of an option in the given section. If only one argument 
     269    is supplied, it is treated as an _option in the global _section. 
     270 
     271    Throws: 
     272        SectionNotFoundError if the section doesn't exist. 
     273        OptionNotFoundError if the option doesn't exist. 
     274    +/ 
    141275    char[] opIndex(char[] section, char[] option=null) { 
    142276        if (option is null) { 
     
    147281        if (s is null) no_section(section); 
    148282        auto o = option in (*s); 
    149         if (o is null) no_option(option); 
     283        if (o is null) no_option(section, option); 
    150284        return *o; 
    151285    } 
     286    /// An alias of opIndex. 
    152287    alias opIndex get; 
     288    /++ 
     289    Retrieves the value of an option in the given section in a manner identical 
     290    to opIndex, and attempts to convert it to an integer. 
     291 
     292    Throws: ConfigConvertError if the value cannot be converted. 
     293    +/ 
    153294    int getint(char[] section, char[] option=null) { 
    154295        char[] o = this[section, option]; 
     
    156297            return toInt(o); 
    157298        } catch(ConvError e) { 
    158             throw new ConfigConvertError("Could not convert '"~o~"' to an integer."); 
    159         } 
    160     } 
     299            throw new ConfigConvertError("Could not convert '"~o~"' to an integer in option "~section~"."~option~"."); 
     300        } 
     301    } 
     302    /++ 
     303    Retrieves the value of an option in the given section in a manner identical 
     304    to opIndex, and attempts to convert it to a real. 
     305 
     306    Throws: ConfigConvertError if the value cannot be converted. 
     307    +/ 
    161308    real getreal(char[] section, char[] option=null) { 
    162309        char[] o = this[section, option]; 
     
    167314        } 
    168315    } 
     316    /++ 
     317    Retrieves the value of an option in the given section in a manner identical 
     318    to opIndex, and attempts to convert it to a boolean. The value is first 
     319    converted to lower-case. The accepted values for true are "yes," "_true," 
     320    "on," and "1." The accepted values for false are "no," "_false," "off," and 
     321    "0." 
     322 
     323    Throws: ConfigConvertError if the value cannot be converted. 
     324    +/ 
    169325    bool getbool(char[] section, char[] option=null) { 
    170326        char[] o = tolower(this[section, option]); 
     
    178334        } 
    179335    } 
     336    /++ 
     337    Stores value to option in section. If option is not supplied, section is 
     338    treated like an _option in the global _section. 
     339 
     340    Throws: SectionNotFoundError if section does not exist. 
     341    +/ 
    180342    void opIndexAssign(char[] value, char[] section, char[] option=null) { 
    181343        if (option is null) { 
     
    187349        (*s)[option] = value; 
    188350    } 
     351    /++ 
     352    Calls opIndexAssign after converting value to a string. 
     353    +/ 
    189354    void opIndexAssign(int value, char[] section, char[] option=null) { 
    190355        this.opIndexAssign(.toString(value), section, option); 
    191356    } 
     357    /++ 
     358    Calls opIndexAssign after converting value to a string. 
     359    +/ 
     360    void opIndexAssign(real value, char[] section, char[] option=null) { 
     361        this.opIndexAssign(.toString(value), section, option); 
     362    } 
     363    /++ 
     364    Calls opIndexAssign after converting value to a string. 
     365    +/ 
    192366    void opIndexAssign(bool value, char[] section, char[] option=null) { 
    193367        this.opIndexAssign(.toString(value), section, option); 
    194368    } 
     369    /++ 
     370    Removes the specified option in section. Silently does nothing if option 
     371    does not exist. 
     372 
     373    Throws: SectionNotFoundError if the section does not exist. 
     374    +/ 
    195375    void remove_option(char[] section, char[] option=null) { 
    196376        if (option is null) { 
     
    202382        (*s).remove(option); 
    203383    } 
     384    /++ 
     385    Removes section. Silently does nothing if section does not exist. 
     386    +/ 
    204387    void remove_section(char[] section) { 
    205388        this.config.remove(section); 
    206389    } 
     390    /++ 
     391    Writes the config _file to file. Note that ConfigParser does not preserve 
     392    the ordering of options or sections, although it will always write the 
     393    global section first. 
     394    +/ 
    207395    void write(Stream file) { 
    208396        auto global = config[GLOBAL_SECTION]; 
     
    223411        file.flush(); 
    224412    } 
     413    /++ 
     414    Writes the config file to the file specified by filename. If the file 
     415    already exists, it is erased and written over. If it does not exist, it is 
     416    created. 
     417    +/ 
    225418    void write(char[] filename) { 
    226         this.write(new BufferedFile(filename, FileMode.OutNew)); 
    227     } 
    228 
    229  
     419        Stream s = new BufferedFile(filename, FileMode.OutNew); 
     420        this.write(s); 
     421        s.close(); 
     422        delete s; 
     423    } 
     424
     425 
  • misc/configtest.d

    r94 r95  
    44import configparse; 
    55 
    6 void main() { 
     6void main(char[][] args) { 
    77    auto config = new ConfigParser; 
    88    config.read("test.ini"); 
     
    1717    } 
    1818    config.write("test2.ini"); 
     19    writefln(config_files(args[0], "foo")); 
    1920} 
    2021