1
0
mirror of https://github.com/twiglet/cs2j.git synced 2025-01-18 13:15:17 +01:00

add support for configuration file. rename options

This commit is contained in:
Kevin Glynn 2011-09-13 18:08:59 +02:00
parent 1bee5bb9ac
commit 20cb333fa6
29 changed files with 5519 additions and 122 deletions

View File

@ -1,3 +1,37 @@
2011-09-13
* revamped option names (sorry!). See user guide.
added:
-config=<ini file>
renamed:
-dumpxmls --> -dump-xmls
-xmldir --> -out-xml-dir
-odir --> -out-java-dir
-netdir --> -net-templates-dir
-exnetdir --> -ex-net-templates-dir
-appdir --> -app-dir
-exappdir --> -ex-app-dir
-csdir --> -cs-dir
-excsdir --> -ex-cs-dir
-showcsharp --> -show-csharp
-showjavasyntax --> -show-javasyntax
-showjava --> -show-java
-showtokens --> -show-tokens
-dumpenums --> -dump-enums
-enumdir --> -out-enum-dir
-cheatdir --> -cheat-dir
-translator-keep-parens --> -keep-parens
-translator-timestamp-files --> -timestamp-files
-translator-blanket-throw --> -blanket-throw
-translator-exception-is-throwable --> -exception-is-throwable
-translator-make-javadoc-comments --> -make-javadoc-comments
-translator-make-java-naming-conventions --> -make-java-naming-conventions
-experimental-enums-numericconsts --> -experimental-enums-to-numeric-consts
2011-09-07 2011.2.4
* add option -experimental-unsigned-to-bigger-signed=true/false (default: false).

View File

@ -0,0 +1,65 @@
;; This Configuration file shows all user-settable configuration options for CS2J with their default values.
[General]
; Debug / Verbosity flags
verbose = 0
debug = 1
debug-template-extraction = true
; Control warnings
warnings = true
warnings-resolve-failures = false
; Dump internal structures during translation
show-csharp = false
show-javasyntax = false
show-java = false
show-tokens = false
; Preprocessor tokens
define =
; Output enum list, parsed translation files
dump-enums = false
out-enum-dir =
dump-xmls = false
out-xml-dir = tmpXMLs
; Source and output for translation files and templates
cheat-dir =
net-templates-dir =
ex-net-templates-dir =
app-dir =
ex-app-dir =
cs-dir =
ex-cs-dir =
out-java-dir =
; Enable Alternate Translation Templates
alt-translations =
; Boolean flags
keep-parens = true
timestamp-files = true
blanket-throw = true
exception-is-throwable = false
make-javadoc-comments = true
make-java-naming-conventions = true
; These are experimental settings.
; They may change (or disappear, or move to General section, or ....) in future releases
[Experimental]
enums-to-numeric-consts = false
unsigned-to-signed = false
unsigned-to-bigger-signed = false
transforms = false
; These are internal settings used for development.
; You should not need (or want) to touch them.
[Internal]
isjavaish = false

View File

@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CS2JTemplateSigner", "CS2JT
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CS2JKeyGenerator", "CS2JKeyGenerator\CS2JKeyGenerator.csproj", "{F294E768-56C3-438A-A3E5-8FA39825262E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nini", "Nini\Nini.csproj", "{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -46,6 +48,18 @@ Global
{B72D065B-862A-469B-87F1-2E521AC7CA08}.Release|Mixed Platforms.Build.0 = Release|x86
{B72D065B-862A-469B-87F1-2E521AC7CA08}.Release|x86.ActiveCfg = Release|x86
{B72D065B-862A-469B-87F1-2E521AC7CA08}.Release|x86.Build.0 = Release|x86
{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}.Debug|x86.ActiveCfg = Debug|Any CPU
{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}.Debug|x86.Build.0 = Debug|Any CPU
{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}.Release|Any CPU.Build.0 = Release|Any CPU
{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}.Release|x86.ActiveCfg = Release|Any CPU
{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}.Release|x86.Build.0 = Release|Any CPU
{CF15D0D5-BE72-4F98-B70F-229ABA1DF0E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF15D0D5-BE72-4F98-B70F-229ABA1DF0E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF15D0D5-BE72-4F98-B70F-229ABA1DF0E8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU

View File

@ -27,6 +27,7 @@ using Twiglet.CS2J.Translator.TypeRep;
using CS2JConstants = Twiglet.CS2J.Translator.Utils.Constants;
using Twiglet.CS2J.Translator.Extract;
using Nini.Config;
namespace Twiglet.CS2J.Translator
{
@ -36,6 +37,7 @@ namespace Twiglet.CS2J.Translator
private static DirectoryHT<TypeRepTemplate> AppEnv { get; set; }
private static CS2JSettings cfg = new CS2JSettings();
private static StringTemplateGroup templates = null;
private static bool doEarlyExit = false;
private static RSACryptoServiceProvider RsaKey = null;
private static int badXmlTxCountTrigger = 3 + 4 - 2;
@ -78,35 +80,143 @@ namespace Twiglet.CS2J.Translator
Console.Out.WriteLine(" [-translator-keep-parens <true/false>] (keep parens from source, default true)");
Console.Out.WriteLine(" <directory or file name to be translated>");
}
private static IList<string> mkDirectories(string rawStr) {
private static IList<string> mkDirectories(string rawStr)
{
IList<string> strs = new List<string>();
char splitChar = rawStr.IndexOf(';') >= 0 ? ';' : '|';
string[] argDirs = rawStr.Split(splitChar);
for (int i = 0; i < argDirs.Length; i++)
if (!String.IsNullOrEmpty(rawStr))
{
string dir = Path.GetFullPath(argDirs[i]).TrimEnd(Path.DirectorySeparatorChar);
strs.Add(dir);
char splitChar = rawStr.IndexOf(';') >= 0 ? ';' : '|';
string[] argDirs = rawStr.Split(splitChar);
for (int i = 0; i < argDirs.Length; i++)
{
string dir = Path.GetFullPath(argDirs[i]).TrimEnd(Path.DirectorySeparatorChar);
strs.Add(dir);
}
}
return strs;
}
private static IList<string> mkStrings(string rawStr) {
private static IList<string> mkStrings(string rawStr)
{
IList<string> strs = new List<string>();
char splitChar = rawStr.IndexOf(';') >= 0 ? ';' : '|';
string[] strDirs = rawStr.Split(splitChar);
for (int i = 0; i < strDirs.Length; i++)
strs.Add(strDirs[i]);
if (!String.IsNullOrEmpty(rawStr))
{
char splitChar = rawStr.IndexOf(';') >= 0 ? ';' : '|';
string[] strDirs = rawStr.Split(splitChar);
for (int i = 0; i < strDirs.Length; i++)
strs.Add(strDirs[i]);
}
return strs;
}
private static bool parseBoolOption(String opt)
{
bool ret = true;
// counter intuitive, but captures plain -opt as opt is true
if (!String.IsNullOrEmpty(opt))
{
try
{
ret = Convert.ToBoolean(opt);
}
catch
{
// Not true/false. try as int
try
{
ret = Convert.ToBoolean(Int32.Parse(opt));
}
catch
{
// ok give in
}
}
}
return ret;
}
private static void updateFromConfigFile(string inifile, CS2JSettings cfg)
{
try
{
IConfigSource source = new IniConfigSource(Path.GetFullPath(inifile));
IConfig general = source.Configs["General"];
// Debug / Verbosity
cfg.OptVerbosity.SetIfDefault(general.GetInt("verbose", cfg.Verbosity));
cfg.OptDebugLevel.SetIfDefault(general.GetInt("debug", cfg.DebugLevel));
cfg.OptDebugTemplateExtraction.SetIfDefault(general.GetBoolean("debug-template-extraction", cfg.DebugTemplateExtraction));
// Control warnings
cfg.OptWarnings.SetIfDefault(general.GetBoolean("warnings", cfg.Warnings));
cfg.OptWarningsFailedResolves.SetIfDefault(general.GetBoolean("warnings-resolve-failures", cfg.WarningsFailedResolves));
// Dump internal structures
cfg.OptDumpCSharp.SetIfDefault(general.GetBoolean("show-csharp", cfg.DumpCSharp));
cfg.OptDumpJavaSyntax.SetIfDefault(general.GetBoolean("show-javasyntax", cfg.DumpJavaSyntax));
cfg.OptDumpJava.SetIfDefault(general.GetBoolean("show-java", cfg.DumpJava));
cfg.OptDisplayTokens.SetIfDefault(general.GetBoolean("show-tokens", cfg.DisplayTokens));
// Preprocessor tokens
cfg.OptMacroDefines.SetIfDefault(mkStrings(general.Get("define", "")));
// Output enum list, parsed translation files
cfg.OptDumpEnums.SetIfDefault(general.GetBoolean("dump-enums", cfg.DumpEnums));
cfg.OptEnumDir.SetIfDefault(Path.Combine(Directory.GetCurrentDirectory(), general.Get("out-enum-dir", cfg.EnumDir)));
cfg.OptDumpXmls.SetIfDefault(general.GetBoolean("dump-xmls", cfg.DumpXmls));
cfg.OptXmlDir.SetIfDefault(Path.Combine(Directory.GetCurrentDirectory(), general.Get("out-xml-dir", cfg.XmlDir)));
// Source and output for translation files and templates
cfg.OptCheatDir.SetIfDefault(Path.Combine(Directory.GetCurrentDirectory(), general.Get("cheat-dir", cfg.CheatDir)));
cfg.OptNetRoot.SetIfDefault(mkDirectories(general.Get("net-templates-dir", "")));
cfg.OptExNetRoot.SetIfDefault(mkDirectories(general.Get("ex-net-templates-dir", "")));
cfg.OptNetSchemaDir.SetIfDefault(mkDirectories(general.Get("net-schema-dir", "")));
cfg.OptAppRoot.SetIfDefault(mkDirectories(general.Get("app-dir", "")));
cfg.OptExAppRoot.SetIfDefault(mkDirectories(general.Get("ex-app-dir", "")));
cfg.OptCsDir.SetIfDefault(mkDirectories(general.Get("cs-dir", "")));
cfg.OptExCsDir.SetIfDefault(mkDirectories(general.Get("ex-cs-dir", "")));
cfg.OptOutDir.SetIfDefault(Path.Combine(Directory.GetCurrentDirectory(), general.Get("out-java-dir", cfg.OutDir)));
// Enable Alternate Translation Templates
cfg.OptAltTranslations.SetIfDefault(mkStrings(general.Get("alt-translations", "")));
// Boolean flags
cfg.OptTranslatorKeepParens.SetIfDefault(general.GetBoolean("keep-parens", cfg.TranslatorKeepParens));
cfg.OptTranslatorAddTimeStamp.SetIfDefault(general.GetBoolean("timestamp-files", cfg.TranslatorAddTimeStamp));
cfg.OptTranslatorBlanketThrow.SetIfDefault(general.GetBoolean("blanket-throw", cfg.TranslatorBlanketThrow));
cfg.OptTranslatorExceptionIsThrowable.SetIfDefault(general.GetBoolean("exception-is-throwable", cfg.TranslatorExceptionIsThrowable));
cfg.OptTranslatorMakeJavadocComments.SetIfDefault(general.GetBoolean("make-javadoc-comments", cfg.TranslatorMakeJavadocComments));
cfg.OptTranslatorMakeJavaNamingConventions.SetIfDefault(general.GetBoolean("make-java-naming-conventions", cfg.TranslatorMakeJavaNamingConventions));
IConfig experimental = source.Configs["Experimental"];
cfg.OptEnumsAsNumericConsts.SetIfDefault(general.GetBoolean("enums-to-numeric-consts", cfg.EnumsAsNumericConsts));
cfg.OptUnsignedNumbersToSigned.SetIfDefault(general.GetBoolean("unsigned-to-signed", cfg.UnsignedNumbersToSigned));
cfg.OptUnsignedNumbersToBiggerSignedNumbers.SetIfDefault(general.GetBoolean("unsigned-to-bigger-signed", cfg.UnsignedNumbersToBiggerSignedNumbers));
cfg.OptExperimentalTransforms.SetIfDefault(general.GetBoolean("transforms", cfg.ExperimentalTransforms));
IConfig internl = source.Configs["Internal"];
cfg.OptInternalIsJavaish.SetIfDefault(internl.GetBoolean("isjavaish", cfg.InternalIsJavaish));
}
catch (IOException)
{
Console.WriteLine("ERROR: Could not read configuration file " + Path.GetFullPath(inifile));
doEarlyExit = true;
}
}
public static void CS2JMain(string[] args)
{
long startTime = DateTime.Now.Ticks;
IList<string> csDir = new List<string>();
XmlTextWriter enumXmlWriter = null;
bool doHelp = false;
bool doEarlyExit = false;
// Use a try/catch block for parser exceptions
try
@ -118,43 +228,44 @@ namespace Twiglet.CS2J.Translator
if (cfg.Verbosity >= 2) Console.Error.WriteLine("Parsing Command Line Arguments...");
OptionSet p = new OptionSet ()
.Add ("v", v => cfg.Verbosity++)
.Add ("config=", f => updateFromConfigFile(f, cfg))
.Add ("v", v => cfg.Verbosity = cfg.OptVerbosity.IsDefault ? 1 : cfg.Verbosity + 1)
.Add ("debug=", v => cfg.DebugLevel = Int32.Parse(v))
.Add ("debug-template-extraction=", v => cfg.DebugTemplateExtraction = Boolean.Parse(v))
.Add ("warnings=", v => cfg.Warnings = Boolean.Parse(v))
.Add ("warnings-resolve-failures=", v => cfg.WarningsFailedResolves = Boolean.Parse(v))
.Add ("version", v => showVersion())
.Add ("debug-template-extraction:", v => cfg.DebugTemplateExtraction = parseBoolOption(v))
.Add ("warnings:", v => cfg.Warnings = parseBoolOption(v))
.Add ("warnings-resolve-failures:", v => cfg.WarningsFailedResolves = parseBoolOption(v))
.Add ("version:", v => { if (parseBoolOption(v)) showVersion(); })
.Add ("help|h|?", v => {doHelp = true; doEarlyExit = true; })
.Add ("showcsharp", v => cfg.DumpCSharp = true)
.Add ("showjava", v => cfg.DumpJava = true)
.Add ("showjavasyntax", v => cfg.DumpJavaSyntax = true)
.Add ("showtokens", v => cfg.DisplayTokens = true)
.Add ("D=", def => cfg.MacroDefines.Add(def))
.Add ("dumpenums", v => cfg.DumpEnums = true)
.Add ("enumdir=", dir => cfg.EnumDir = Path.Combine(Directory.GetCurrentDirectory(), dir))
.Add ("dumpxmls", v => cfg.DumpXmls = true)
.Add ("xmldir=", dir => cfg.XmlDir = Path.Combine(Directory.GetCurrentDirectory(), dir))
.Add ("odir=", dir => cfg.OutDir = dir)
.Add ("cheatdir=", dir => cfg.CheatDir = dir)
.Add("netdir=", dirs => cfg.NetRoot = mkDirectories(dirs))
.Add("exnetdir=", dirs => cfg.ExNetRoot = mkDirectories(dirs))
.Add("netschemadir=", dirs => cfg.NetSchemaDir = mkDirectories(dirs))
.Add("appdir=", dirs => cfg.AppRoot = mkDirectories(dirs))
.Add("exappdir=", dirs => cfg.ExAppRoot = mkDirectories(dirs))
.Add("csdir=", dirs => csDir = mkDirectories(dirs))
.Add("excsdir=", dirs => cfg.Exclude = mkDirectories(dirs))
.Add("alt-translations=", alts => cfg.AltTranslations = mkStrings(alts))
.Add ("translator-keep-parens=", v => cfg.TranslatorKeepParens = Boolean.Parse(v))
.Add ("translator-timestamp-files=", v => cfg.TranslatorAddTimeStamp = Boolean.Parse(v))
.Add ("translator-blanket-throw=", v => cfg.TranslatorBlanketThrow = Boolean.Parse(v))
.Add ("translator-exception-is-throwable=", v => cfg.TranslatorExceptionIsThrowable = Boolean.Parse(v))
.Add ("translator-make-javadoc-comments=", v => cfg.TranslatorMakeJavadocComments = Boolean.Parse(v))
.Add ("translator-make-java-naming-conventions=", v => cfg.TranslatorMakeJavaNamingConventions = Boolean.Parse(v))
.Add ("experimental-enums-numericconsts=", v => cfg.EnumsAsNumericConsts = Boolean.Parse(v))
.Add ("experimental-unsigned-to-signed=", v => cfg.UnsignedNumbersToSigned = Boolean.Parse(v))
.Add ("experimental-unsigned-to-bigger-signed=", v => cfg.UnsignedNumbersToBiggerSignedNumbers = Boolean.Parse(v))
.Add ("experimental-transforms=", v => cfg.ExperimentalTransforms = Boolean.Parse(v))
.Add ("internal-isjavaish", v => cfg.InternalIsJavaish = true)
.Add ("show-csharp:", v => cfg.DumpCSharp = parseBoolOption(v))
.Add ("show-java:", v => cfg.DumpJava = parseBoolOption(v))
.Add ("show-javasyntax:", v => cfg.DumpJavaSyntax = parseBoolOption(v))
.Add ("show-tokens:", v => cfg.DisplayTokens = parseBoolOption(v))
.Add ("D=", def => cfg.OptMacroDefines.Add(mkStrings(def)))
.Add ("dump-enums:", v => cfg.DumpEnums = parseBoolOption(v))
.Add ("out-enum-dir=", dir => cfg.EnumDir = Path.Combine(Directory.GetCurrentDirectory(), dir))
.Add ("dump-xmls:", v => cfg.DumpXmls = parseBoolOption(v))
.Add ("out-xml-dir=", dir => cfg.XmlDir = Path.Combine(Directory.GetCurrentDirectory(), dir))
.Add ("out-java-dir=", dir => cfg.OutDir = dir)
.Add ("cheat-dir=", dir => cfg.CheatDir = dir)
.Add ("net-templates-dir=", dirs => cfg.OptNetRoot.Add(mkDirectories(dirs)))
.Add ("ex-net-templates-dir=", dirs => cfg.OptExNetRoot.Add(mkDirectories(dirs)))
.Add ("net-schema-dir=", dirs => cfg.OptNetSchemaDir.Add(mkDirectories(dirs)))
.Add ("app-dir=", dirs => cfg.OptAppRoot.Add(mkDirectories(dirs)))
.Add ("ex-app-dir=", dirs => cfg.OptExAppRoot.Add(mkDirectories(dirs)))
.Add ("cs-dir=", dirs => cfg.OptCsDir.Add(mkDirectories(dirs)))
.Add ("ex-cs-dir=", dirs => cfg.OptExCsDir.Add(mkDirectories(dirs)))
.Add ("alt-translations=", alts => cfg.OptAltTranslations.Add(mkStrings(alts)))
.Add ("keep-parens:", v => cfg.TranslatorKeepParens = parseBoolOption(v))
.Add ("timestamp-files:", v => cfg.TranslatorAddTimeStamp = parseBoolOption(v))
.Add ("blanket-throw:", v => cfg.TranslatorBlanketThrow = parseBoolOption(v))
.Add ("exception-is-throwable:", v => cfg.TranslatorExceptionIsThrowable = parseBoolOption(v))
.Add ("make-javadoc-comments:", v => cfg.TranslatorMakeJavadocComments = parseBoolOption(v))
.Add ("make-java-naming-conventions:", v => cfg.TranslatorMakeJavaNamingConventions = parseBoolOption(v))
.Add ("experimental-enums-to-numeric-consts:", v => cfg.EnumsAsNumericConsts = parseBoolOption(v))
.Add ("experimental-unsigned-to-signed:", v => cfg.UnsignedNumbersToSigned = parseBoolOption(v))
.Add ("experimental-unsigned-to-bigger-signed:", v => cfg.UnsignedNumbersToBiggerSignedNumbers = parseBoolOption(v))
.Add ("experimental-transforms:", v => cfg.ExperimentalTransforms = parseBoolOption(v))
.Add ("internal-isjavaish:", v => cfg.InternalIsJavaish = parseBoolOption(v))
;
//TODO: fix enum dump
@ -163,21 +274,21 @@ namespace Twiglet.CS2J.Translator
{
if (s.StartsWith("-") || s.StartsWith("/"))
{
Console.WriteLine("Unrecognized Option: " + s);
Console.WriteLine("ERROR: Unrecognized Option: " + s);
doEarlyExit = true;
}
else
{
csDir = mkDirectories(s);
cfg.OptCsDir.Add(mkDirectories(s));
}
}
if (cfg.Verbosity > 0) showVersion();
if (doHelp) showUsage();
if (csDir == null || csDir.Count == 0) {
if (cfg.CsDir == null || cfg.CsDir.Count == 0) {
// No work
Console.WriteLine("Please specify files to translate with -csdir option");
Console.WriteLine("Please specify files to translate with -cs-dir option");
doEarlyExit = true;
}
@ -228,7 +339,7 @@ namespace Twiglet.CS2J.Translator
if (cfg.AppRoot.Count == 0)
{
// By default translation target is application root
foreach (string s in csDir)
foreach (string s in cfg.CsDir)
{
cfg.AppRoot.Add(s);
}
@ -268,8 +379,8 @@ namespace Twiglet.CS2J.Translator
templates = new StringTemplateGroup(new StringReader(Templates.JavaTemplateGroup));
}
foreach (string r in csDir)
doFile(r, ".cs", translateFile, cfg.Exclude); // translate it
foreach (string r in cfg.CsDir)
doFile(r, ".cs", translateFile, cfg.ExCsDir); // translate it
if (cfg.DebugLevel >= 1 && partialTypes.Count > 0) Console.Out.WriteLine("Writing out collected partial types");
foreach (KeyValuePair<string, ClassDescriptorSerialized> entry in partialTypes)

View File

@ -32,17 +32,36 @@ namespace Twiglet.CS2J.Translator
isDefault = false;
}
}
public void setIfDefault(T newVal)
public void SetIfDefault(T newVal)
{
if (IsDefault)
{
optValue = newVal;
}
}
public void SetDefault(T newVal)
{
optValue = newVal;
}
}
public class CS2JOptionStrings : CS2JOption<IList<string>>
{
public void Add(IList<string> newVal)
{
if (IsDefault)
{
Value = newVal;
}
}
public void setDefault(T newVal)
{
optValue = newVal;
else
{
foreach (string s in newVal)
{
Value.Add(s);
}
}
}
}
@ -202,8 +221,8 @@ namespace Twiglet.CS2J.Translator
}
// NetRoot
private CS2JOption<IList<string>> optNetRoot = new CS2JOption<IList<string>>();
public CS2JOption<IList<string>> OptNetRoot {
private CS2JOptionStrings optNetRoot = new CS2JOptionStrings();
public CS2JOptionStrings OptNetRoot {
get
{
return optNetRoot;
@ -221,8 +240,8 @@ namespace Twiglet.CS2J.Translator
}
// ExNetRoot
private CS2JOption<IList<string>> optExNetRoot = new CS2JOption<IList<string>>();
public CS2JOption<IList<string>> OptExNetRoot {
private CS2JOptionStrings optExNetRoot = new CS2JOptionStrings();
public CS2JOptionStrings OptExNetRoot {
get
{
return optExNetRoot;
@ -240,8 +259,8 @@ namespace Twiglet.CS2J.Translator
}
// NetSchemaDir
private CS2JOption<IList<string>> optNetSchemaDir = new CS2JOption<IList<string>>();
public CS2JOption<IList<string>> OptNetSchemaDir {
private CS2JOptionStrings optNetSchemaDir = new CS2JOptionStrings();
public CS2JOptionStrings OptNetSchemaDir {
get
{
return optNetSchemaDir;
@ -259,8 +278,8 @@ namespace Twiglet.CS2J.Translator
}
// AppRoot
private CS2JOption<IList<string>> optAppRoot = new CS2JOption<IList<string>>();
public CS2JOption<IList<string>> OptAppRoot {
private CS2JOptionStrings optAppRoot = new CS2JOptionStrings();
public CS2JOptionStrings OptAppRoot {
get
{
return optAppRoot;
@ -278,8 +297,8 @@ namespace Twiglet.CS2J.Translator
}
// ExAppRoot
private CS2JOption<IList<string>> optExAppRoot = new CS2JOption<IList<string>>();
public CS2JOption<IList<string>> OptExAppRoot {
private CS2JOptionStrings optExAppRoot = new CS2JOptionStrings();
public CS2JOptionStrings OptExAppRoot {
get
{
return optExAppRoot;
@ -296,28 +315,47 @@ namespace Twiglet.CS2J.Translator
}
}
// Exclude
private CS2JOption<IList<string>> optExclude = new CS2JOption<IList<string>>();
public CS2JOption<IList<string>> OptExclude {
// CsDir
private CS2JOptionStrings optCsDir = new CS2JOptionStrings();
public CS2JOptionStrings OptCsDir {
get
{
return optExclude;
return optCsDir;
}
}
public IList<string> Exclude {
public IList<string> CsDir {
get
{
return optExclude.Value;
return optCsDir.Value;
}
set
{
optExclude.Value = value;
optCsDir.Value = value;
}
}
// ExCsDir
private CS2JOptionStrings optExCsDir = new CS2JOptionStrings();
public CS2JOptionStrings OptExCsDir {
get
{
return optExCsDir;
}
}
public IList<string> ExCsDir {
get
{
return optExCsDir.Value;
}
set
{
optExCsDir.Value = value;
}
}
// MacroDefines
private CS2JOption<IList<string>> optMacroDefines = new CS2JOption<IList<string>>();
public CS2JOption<IList<string>> OptMacroDefines {
private CS2JOptionStrings optMacroDefines = new CS2JOptionStrings();
public CS2JOptionStrings OptMacroDefines {
get
{
return optMacroDefines;
@ -335,8 +373,8 @@ namespace Twiglet.CS2J.Translator
}
// AltTranslations
private CS2JOption<IList<string>> optAltTranslations = new CS2JOption<IList<string>>();
public CS2JOption<IList<string>> OptAltTranslations {
private CS2JOptionStrings optAltTranslations = new CS2JOptionStrings();
public CS2JOptionStrings OptAltTranslations {
get
{
return optAltTranslations;
@ -717,48 +755,49 @@ namespace Twiglet.CS2J.Translator
public CS2JSettings ()
{
OptDisplayTokens.setDefault(false);
OptDisplayTokens.SetDefault(false);
// dump parse trees to stdout
OptDumpCSharp.setDefault(false);
OptDumpJavaSyntax.setDefault(false);
OptDumpJava.setDefault(false);
OptDumpCSharp.SetDefault(false);
OptDumpJavaSyntax.SetDefault(false);
OptDumpJava.SetDefault(false);
OptDumpXmls.setDefault(false);
OptDumpEnums.setDefault(false);
OptOutDir.setDefault(Directory.GetCurrentDirectory());
OptCheatDir.setDefault("");
OptNetRoot.setDefault(new List<string>());
OptExNetRoot.setDefault(new List<string>());
OptNetSchemaDir.setDefault(new List<string>());
OptAppRoot.setDefault(new List<string>());
OptExAppRoot.setDefault(new List<string>());
OptExclude.setDefault(new List<string>());
OptMacroDefines.setDefault(new List<string>());
OptAltTranslations.setDefault(new List<string>());
OptXmlDir.setDefault(Path.Combine(Directory.GetCurrentDirectory(), "tmpXMLs"));
OptEnumDir.setDefault(Path.Combine(Directory.GetCurrentDirectory(), "enums"));
OptKeyFile.setDefault(null);
OptVerbosity.setDefault(0);
OptDebugTemplateExtraction.setDefault(true);
OptDebugLevel.setDefault(1);
OptWarnings.setDefault(true);
OptWarningsFailedResolves.setDefault(false);
OptDumpXmls.SetDefault(false);
OptDumpEnums.SetDefault(false);
OptOutDir.SetDefault(Directory.GetCurrentDirectory());
OptCheatDir.SetDefault("");
OptNetRoot.SetDefault(new List<string>());
OptExNetRoot.SetDefault(new List<string>());
OptNetSchemaDir.SetDefault(new List<string>());
OptAppRoot.SetDefault(new List<string>());
OptExAppRoot.SetDefault(new List<string>());
OptCsDir.SetDefault(new List<string>());
OptExCsDir.SetDefault(new List<string>());
OptMacroDefines.SetDefault(new List<string>());
OptAltTranslations.SetDefault(new List<string>());
OptXmlDir.SetDefault(Path.Combine(Directory.GetCurrentDirectory(), "tmpXMLs"));
OptEnumDir.SetDefault(Path.Combine(Directory.GetCurrentDirectory(), "enums"));
OptKeyFile.SetDefault(null);
OptVerbosity.SetDefault(0);
OptDebugTemplateExtraction.SetDefault(true);
OptDebugLevel.SetDefault(1);
OptWarnings.SetDefault(true);
OptWarningsFailedResolves.SetDefault(false);
OptTranslatorKeepParens.setDefault(true);
OptTranslatorAddTimeStamp.setDefault(true);
OptTranslatorExceptionIsThrowable.setDefault(false);
OptTranslatorBlanketThrow.setDefault(true);
OptTranslatorMakeJavadocComments.setDefault(true);
OptTranslatorMakeJavaNamingConventions.setDefault(true);
OptTranslatorKeepParens.SetDefault(true);
OptTranslatorAddTimeStamp.SetDefault(true);
OptTranslatorExceptionIsThrowable.SetDefault(false);
OptTranslatorBlanketThrow.SetDefault(true);
OptTranslatorMakeJavadocComments.SetDefault(true);
OptTranslatorMakeJavaNamingConventions.SetDefault(true);
OptEnumsAsNumericConsts.setDefault(false);
OptUnsignedNumbersToSigned.setDefault(false);
OptUnsignedNumbersToBiggerSignedNumbers.setDefault(false);
OptEnumsAsNumericConsts.SetDefault(false);
OptUnsignedNumbersToSigned.SetDefault(false);
OptUnsignedNumbersToBiggerSignedNumbers.SetDefault(false);
OptExperimentalTransforms.setDefault(false);
OptExperimentalTransforms.SetDefault(false);
OptInternalIsJavaish.setDefault(false);
OptInternalIsJavaish.SetDefault(false);
}
}
}

View File

@ -11,8 +11,6 @@
<RootNamespace>CS2JTranslator</RootNamespace>
<AssemblyName>cs2j</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
@ -24,7 +22,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Commandlineparameters>--debug 5 -experimental-transforms=true -translator-timestamp-files=false -translator-keep-parens=false -netdir=/Users/keving/gitrepos/cs2j/CS2JLibrary/NetFramework/ -dumpxmls -xmldir=/Users/keving/tmp/xml/libomv -odir=/Users/keving/tmp/java/libomv/src -csdir=/Users/keving/Projects/libomv-0.8.3-source/Programs/VisualParamGenerator/ -excsdir=/Users/keving/Projects/libomv-0.8.3-source/Programs/VisualParamGenerator/template.cs</Commandlineparameters>
<Commandlineparameters>-config /Users/keving/tmp/secs2j.ini</Commandlineparameters>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
@ -97,6 +95,10 @@
<Project>{E6ACBB37-AF38-45E1-B399-0CEE63809A15}</Project>
<Name>NDesk.Options</Name>
</ProjectReference>
<ProjectReference Include="..\Nini\Nini.csproj">
<Project>{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}</Project>
<Name>Nini</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@ -0,0 +1,148 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.Collections;
namespace Nini.Config
{
/// <include file='AliasText.xml' path='//Class[@name="AliasText"]/docs/*' />
public class AliasText
{
#region Private variables
Hashtable intAlias = null;
Hashtable booleanAlias = null;
#endregion
#region Constructors
/// <include file='AliasText.xml' path='//Constructor[@name="AliasText"]/docs/*' />
public AliasText ()
{
intAlias = InsensitiveHashtable ();
booleanAlias = InsensitiveHashtable ();
DefaultAliasLoad ();
}
#endregion
#region Public methods
/// <include file='AliasText.xml' path='//Method[@name="AddAliasInt"]/docs/*' />
public void AddAlias (string key, string alias, int value)
{
if (intAlias.Contains (key)) {
Hashtable keys = (Hashtable)intAlias[key];
keys[alias] = value;
} else {
Hashtable keys = InsensitiveHashtable ();
keys[alias] = value;
intAlias.Add (key, keys);
}
}
/// <include file='AliasText.xml' path='//Method[@name="AddAliasBoolean"]/docs/*' />
public void AddAlias (string alias, bool value)
{
booleanAlias[alias] = value;
}
#if (NET_COMPACT_1_0)
#else
/// <include file='AliasText.xml' path='//Method[@name="AddAliasEnum"]/docs/*' />
public void AddAlias (string key, Enum enumAlias)
{
SetAliasTypes (key, enumAlias);
}
#endif
/// <include file='AliasText.xml' path='//Method[@name="ContainsBoolean"]/docs/*' />
public bool ContainsBoolean (string key)
{
return booleanAlias.Contains (key);
}
/// <include file='AliasText.xml' path='//Method[@name="ContainsInt"]/docs/*' />
public bool ContainsInt (string key, string alias)
{
bool result = false;
if (intAlias.Contains (key)) {
Hashtable keys = (Hashtable)intAlias[key];
result = (keys.Contains (alias));
}
return result;
}
/// <include file='AliasText.xml' path='//Method[@name="GetBoolean"]/docs/*' />
public bool GetBoolean (string key)
{
if (!booleanAlias.Contains (key)) {
throw new ArgumentException ("Alias does not exist for text");
}
return (bool)booleanAlias[key];
}
/// <include file='AliasText.xml' path='//Method[@name="GetInt"]/docs/*' />
public int GetInt (string key, string alias)
{
if (!intAlias.Contains (key)) {
throw new ArgumentException ("Alias does not exist for key");
}
Hashtable keys = (Hashtable)intAlias[key];
if (!keys.Contains (alias)) {
throw new ArgumentException ("Config value does not match a " +
"supplied alias");
}
return (int)keys[alias];
}
#endregion
#region Private methods
/// <summary>
/// Loads the default alias values.
/// </summary>
private void DefaultAliasLoad ()
{
AddAlias("true", true);
AddAlias("false", false);
}
#if (NET_COMPACT_1_0)
#else
/// <summary>
/// Extracts and sets the alias types from an enumeration.
/// </summary>
private void SetAliasTypes (string key, Enum enumAlias)
{
string[] names = Enum.GetNames (enumAlias.GetType ());
int[] values = (int[])Enum.GetValues (enumAlias.GetType ());
for (int i = 0; i < names.Length; i++)
{
AddAlias (key, names[i], values[i]);
}
}
#endif
/// <summary>
/// Returns a case insensitive hashtable.
/// </summary>
private Hashtable InsensitiveHashtable ()
{
return new Hashtable (CaseInsensitiveHashCodeProvider.Default,
CaseInsensitiveComparer.Default);
}
#endregion
}
}

View File

@ -0,0 +1,106 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.IO;
using System.Text;
using System.Collections;
using Nini.Util;
namespace Nini.Config
{
/// <include file='ArgvConfigSource.xml' path='//Class[@name="ArgvConfigSource"]/docs/*' />
public class ArgvConfigSource : ConfigSourceBase
{
#region Private variables
ArgvParser parser = null;
string[] arguments = null;
#endregion
#region Constructors
/// <include file='ArgvConfigSource.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public ArgvConfigSource (string[] arguments)
{
parser = new ArgvParser (arguments);
this.arguments = arguments;
}
#endregion
#region Public properties
#endregion
#region Public methods
/// <include file='ArgvConfigSource.xml' path='//Method[@name="Save"]/docs/*' />
public override void Save ()
{
throw new ArgumentException ("Source is read only");
}
/// <include file='ArgvConfigSource.xml' path='//Method[@name="Reload"]/docs/*' />
public override void Reload ()
{
throw new ArgumentException ("Source cannot be reloaded");
}
/// <include file='ArgvConfigSource.xml' path='//Method[@name="AddSwitch"]/docs/*' />
public void AddSwitch (string configName, string longName)
{
AddSwitch (configName, longName, null);
}
/// <include file='ArgvConfigSource.xml' path='//Method[@name="AddSwitchShort"]/docs/*' />
public void AddSwitch (string configName, string longName,
string shortName)
{
IConfig config = GetConfig (configName);
if (shortName != null &&
(shortName.Length < 1 || shortName.Length > 2)) {
throw new ArgumentException ("Short name may only be 1 or 2 characters");
}
// Look for the long name first
if (parser[longName] != null) {
config.Set (longName, parser[longName]);
} else if (shortName != null && parser[shortName] != null) {
config.Set (longName, parser[shortName]);
}
}
/// <include file='ArgvConfigSource.xml' path='//Method[@name="GetArguments"]/docs/*' />
public string[] GetArguments ()
{
string[] result = new string[this.arguments.Length];
Array.Copy (this.arguments, 0, result, 0, this.arguments.Length);
return result;
}
#endregion
#region Private methods
/// <summary>
/// Returns an IConfig. If it does not exist then it is added.
/// </summary>
private IConfig GetConfig (string name)
{
IConfig result = null;
if (this.Configs[name] == null) {
result = new ConfigBase (name, this);
this.Configs.Add (result);
} else {
result = this.Configs[name];
}
return result;
}
#endregion
}
}

View File

@ -0,0 +1,422 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.Collections;
using System.Globalization;
using Nini.Util;
namespace Nini.Config
{
#region ConfigKeyEventArgs class
/// <include file='ConfigKeyEventArgs.xml' path='//Delegate[@name="ConfigKeyEventHandler"]/docs/*' />
public delegate void ConfigKeyEventHandler (object sender, ConfigKeyEventArgs e);
/// <include file='ConfigEventArgs.xml' path='//Class[@name="ConfigEventArgs"]/docs/*' />
public class ConfigKeyEventArgs : EventArgs
{
string keyName = null;
string keyValue = null;
/// <include file='ConfigEventArgs.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public ConfigKeyEventArgs (string keyName, string keyValue)
{
this.keyName = keyName;
this.keyValue = keyValue;
}
/// <include file='ConfigEventArgs.xml' path='//Property[@name="KeyName"]/docs/*' />
public string KeyName
{
get { return keyName; }
}
/// <include file='ConfigEventArgs.xml' path='//Property[@name="KeyValue"]/docs/*' />
public string KeyValue
{
get { return keyValue; }
}
}
#endregion
/// <include file='IConfig.xml' path='//Interface[@name="IConfig"]/docs/*' />
public class ConfigBase : IConfig
{
#region Private variables
string configName = null;
IConfigSource configSource = null;
AliasText aliasText = null;
IFormatProvider format = NumberFormatInfo.CurrentInfo;
#endregion
#region Protected variables
protected OrderedList keys = new OrderedList ();
#endregion
#region Constructors
/// <include file='ConfigBase.xml' path='//Constructor[@name="ConfigBase"]/docs/*' />
public ConfigBase (string name, IConfigSource source)
{
configName = name;
configSource = source;
aliasText = new AliasText ();
}
#endregion
#region Public properties
/// <include file='IConfig.xml' path='//Property[@name="Name"]/docs/*' />
public string Name
{
get { return configName; }
set {
if (configName != value) {
Rename (value);
}
}
}
/// <include file='IConfig.xml' path='//Property[@name="ConfigSource"]/docs/*' />
public IConfigSource ConfigSource
{
get { return configSource; }
}
/// <include file='IConfig.xml' path='//Property[@name="Alias"]/docs/*' />
public AliasText Alias
{
get { return aliasText; }
}
#endregion
#region Public methods
/// <include file='IConfig.xml' path='//Method[@name="Contains"]/docs/*' />
public bool Contains (string key)
{
return (Get (key) != null);
}
/// <include file='IConfig.xml' path='//Method[@name="Get"]/docs/*' />
public virtual string Get (string key)
{
string result = null;
if (keys.Contains (key)) {
result = keys[key].ToString ();
}
return result;
}
/// <include file='IConfig.xml' path='//Method[@name="GetDefault"]/docs/*' />
public string Get (string key, string defaultValue)
{
string result = Get (key);
return (result == null) ? defaultValue : result;
}
/// <include file='IConfig.xml' path='//Method[@name="GetExpanded"]/docs/*' />
public string GetExpanded (string key)
{
return this.ConfigSource.GetExpanded(this, key);
}
/// <include file='IConfig.xml' path='//Method[@name="Get"]/docs/*' />
public string GetString (string key)
{
return Get (key);
}
/// <include file='IConfig.xml' path='//Method[@name="GetDefault"]/docs/*' />
public string GetString (string key, string defaultValue)
{
return Get (key, defaultValue);
}
/// <include file='IConfig.xml' path='//Method[@name="GetInt"]/docs/*' />
public int GetInt (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return Convert.ToInt32 (text, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetIntAlias"]/docs/*' />
public int GetInt (string key, bool fromAlias)
{
if (!fromAlias) {
return GetInt (key);
}
string result = Get (key);
if (result == null) {
throw new ArgumentException ("Value not found: " + key);
}
return GetIntAlias (key, result);
}
/// <include file='IConfig.xml' path='//Method[@name="GetIntDefault"]/docs/*' />
public int GetInt (string key, int defaultValue)
{
string result = Get (key);
return (result == null)
? defaultValue
: Convert.ToInt32 (result, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetIntDefaultAlias"]/docs/*' />
public int GetInt (string key, int defaultValue, bool fromAlias)
{
if (!fromAlias) {
return GetInt (key, defaultValue);
}
string result = Get (key);
return (result == null) ? defaultValue : GetIntAlias (key, result);
}
/// <include file='IConfig.xml' path='//Method[@name="GetLong"]/docs/*' />
public long GetLong (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return Convert.ToInt64 (text, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetLongDefault"]/docs/*' />
public long GetLong (string key, long defaultValue)
{
string result = Get (key);
return (result == null)
? defaultValue
: Convert.ToInt64 (result, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetBoolean"]/docs/*' />
public bool GetBoolean (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return GetBooleanAlias (text);
}
/// <include file='IConfig.xml' path='//Method[@name="GetBooleanDefault"]/docs/*' />
public bool GetBoolean (string key, bool defaultValue)
{
string text = Get (key);
return (text == null) ? defaultValue : GetBooleanAlias (text);
}
/// <include file='IConfig.xml' path='//Method[@name="GetFloat"]/docs/*' />
public float GetFloat (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return Convert.ToSingle (text, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetFloatDefault"]/docs/*' />
public float GetFloat (string key, float defaultValue)
{
string result = Get (key);
return (result == null)
? defaultValue
: Convert.ToSingle (result, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetDouble"]/docs/*' />
public double GetDouble (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return Convert.ToDouble (text, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetDoubleDefault"]/docs/*' />
public double GetDouble (string key, double defaultValue)
{
string result = Get (key);
return (result == null)
? defaultValue
: Convert.ToDouble (result, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetKeys"]/docs/*' />
public string[] GetKeys ()
{
string[] result = new string[keys.Keys.Count];
keys.Keys.CopyTo (result, 0);
return result;
}
/// <include file='IConfig.xml' path='//Method[@name="GetValues"]/docs/*' />
public string[] GetValues ()
{
string[] result = new string[keys.Values.Count];
keys.Values.CopyTo (result, 0);
return result;
}
/// <include file='ConfigBase.xml' path='//Method[@name="Add"]/docs/*' />
public void Add (string key, string value)
{
keys.Add (key, value);
}
/// <include file='IConfig.xml' path='//Method[@name="Set"]/docs/*' />
public virtual void Set (string key, object value)
{
if (value == null) {
throw new ArgumentNullException ("Value cannot be null");
}
if (Get (key) == null) {
this.Add (key, value.ToString ());
} else {
keys[key] = value.ToString ();
}
if (ConfigSource.AutoSave) {
ConfigSource.Save ();
}
OnKeySet (new ConfigKeyEventArgs (key, value.ToString ()));
}
/// <include file='IConfig.xml' path='//Method[@name="Remove"]/docs/*' />
public virtual void Remove (string key)
{
if (key == null) {
throw new ArgumentNullException ("Key cannot be null");
}
if (Get (key) != null) {
string keyValue = null;
if (KeySet != null) {
keyValue = Get (key);
}
keys.Remove (key);
OnKeyRemoved (new ConfigKeyEventArgs (key, keyValue));
}
}
#endregion
#region Public events
/// <include file='IConfig.xml' path='//Event[@name="KeySet"]/docs/*' />
public event ConfigKeyEventHandler KeySet;
/// <include file='IConfig.xml' path='//Event[@name="KeyRemoved"]/docs/*' />
public event ConfigKeyEventHandler KeyRemoved;
#endregion
#region Protected methods
/// <include file='ConfigBase.xml' path='//Method[@name="OnKeySet"]/docs/*' />
protected void OnKeySet (ConfigKeyEventArgs e)
{
if (KeySet != null) {
KeySet (this, e);
}
}
/// <include file='ConfigBase.xml' path='//Method[@name="OnKeyRemoved"]/docs/*' />
protected void OnKeyRemoved (ConfigKeyEventArgs e)
{
if (KeyRemoved != null) {
KeyRemoved (this, e);
}
}
#endregion
#region Private methods
/// <summary>
/// Renames the config to the new name.
/// </summary>
private void Rename (string name)
{
this.ConfigSource.Configs.Remove (this);
configName = name;
this.ConfigSource.Configs.Add (this);
}
/// <summary>
/// Returns the integer alias first from this IConfig then
/// the parent if there is none.
/// </summary>
private int GetIntAlias (string key, string alias)
{
int result = -1;
if (aliasText.ContainsInt (key, alias)) {
result = aliasText.GetInt (key, alias);
} else {
result = ConfigSource.Alias.GetInt (key, alias);
}
return result;
}
/// <summary>
/// Returns the boolean alias first from this IConfig then
/// the parent if there is none.
/// </summary>
private bool GetBooleanAlias (string key)
{
bool result = false;
if (aliasText.ContainsBoolean (key)) {
result = aliasText.GetBoolean (key);
} else {
if (ConfigSource.Alias.ContainsBoolean (key)) {
result = ConfigSource.Alias.GetBoolean (key);
} else {
throw new ArgumentException
("Alias value not found: " + key
+ ". Add it to the Alias property.");
}
}
return result;
}
#endregion
}
}

View File

@ -0,0 +1,264 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.Collections;
namespace Nini.Config
{
#region ConfigEventHandler class
/// <include file='ConfigEventArgs.xml' path='//Delegate[@name="ConfigEventHandler"]/docs/*' />
public delegate void ConfigEventHandler (object sender, ConfigEventArgs e);
/// <include file='ConfigEventArgs.xml' path='//Class[@name="ConfigEventArgs"]/docs/*' />
public class ConfigEventArgs : EventArgs
{
IConfig config = null;
/// <include file='ConfigEventArgs.xml' path='//Constructor[@name="ConstructorIConfig"]/docs/*' />
public ConfigEventArgs (IConfig config)
{
this.config = config;
}
/// <include file='ConfigEventArgs.xml' path='//Property[@name="Config"]/docs/*' />
public IConfig Config
{
get { return config; }
}
}
#endregion
/// <include file='ConfigCollection.xml' path='//Class[@name="ConfigCollection"]/docs/*' />
public class ConfigCollection : ICollection, IEnumerable, IList
{
#region Private variables
ArrayList configList = new ArrayList ();
ConfigSourceBase owner = null;
#endregion
#region Constructors
/// <include file='ConfigCollection.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public ConfigCollection (ConfigSourceBase owner)
{
this.owner = owner;
}
#endregion
#region Public properties
/// <include file='ConfigCollection.xml' path='//Property[@name="Count"]/docs/*' />
public int Count
{
get { return configList.Count; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="IsSynchronized"]/docs/*' />
public bool IsSynchronized
{
get { return false; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="SyncRoot"]/docs/*' />
public object SyncRoot
{
get { return this; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="ItemIndex"]/docs/*' />
public IConfig this[int index]
{
get { return (IConfig)configList[index]; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="ItemIndex"]/docs/*' />
object IList.this[int index]
{
get { return configList[index]; }
set { }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="ItemName"]/docs/*' />
public IConfig this[string configName]
{
get
{
IConfig result = null;
foreach (IConfig config in configList)
{
if (config.Name == configName) {
result = config;
break;
}
}
return result;
}
}
/// <include file='ConfigCollection.xml' path='//Property[@name="IsFixedSize"]/docs/*' />
public bool IsFixedSize
{
get { return false; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="IsReadOnly"]/docs/*' />
public bool IsReadOnly
{
get { return false; }
}
#endregion
#region Public methods
/// <include file='ConfigCollection.xml' path='//Method[@name="Add"]/docs/*' />
public void Add (IConfig config)
{
if (configList.Contains (config)) {
throw new ArgumentException ("IConfig already exists");
}
IConfig existingConfig = this[config.Name];
if (existingConfig != null) {
// Set all new keys
string[] keys = config.GetKeys ();
for (int i = 0; i < keys.Length; i++)
{
existingConfig.Set (keys[i], config.Get (keys[i]));
}
} else {
configList.Add (config);
OnConfigAdded (new ConfigEventArgs (config));
}
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Add"]/docs/*' />
int IList.Add (object config)
{
IConfig newConfig = config as IConfig;
if (newConfig == null) {
throw new Exception ("Must be an IConfig");
} else {
this.Add (newConfig);
return IndexOf (newConfig);
}
}
/// <include file='ConfigCollection.xml' path='//Method[@name="AddName"]/docs/*' />
public IConfig Add (string name)
{
ConfigBase result = null;
if (this[name] == null) {
result = new ConfigBase (name, owner);
configList.Add (result);
OnConfigAdded (new ConfigEventArgs (result));
} else {
throw new ArgumentException ("An IConfig of that name already exists");
}
return result;
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (IConfig config)
{
configList.Remove (config);
OnConfigRemoved (new ConfigEventArgs (config));
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (object config)
{
configList.Remove (config);
OnConfigRemoved (new ConfigEventArgs ((IConfig)config));
}
/// <include file='ConfigCollection.xml' path='//Method[@name="RemoveAt"]/docs/*' />
public void RemoveAt (int index)
{
IConfig config = (IConfig)configList[index];
configList.RemoveAt (index);
OnConfigRemoved (new ConfigEventArgs (config));
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Clear"]/docs/*' />
public void Clear ()
{
configList.Clear ();
}
/// <include file='ConfigCollection.xml' path='//Method[@name="GetEnumerator"]/docs/*' />
public IEnumerator GetEnumerator ()
{
return configList.GetEnumerator ();
}
/// <include file='ConfigCollection.xml' path='//Method[@name="CopyTo"]/docs/*' />
public void CopyTo (Array array, int index)
{
configList.CopyTo (array, index);
}
/// <include file='ConfigCollection.xml' path='//Method[@name="CopyToStrong"]/docs/*' />
public void CopyTo (IConfig[] array, int index)
{
((ICollection)configList).CopyTo (array, index);
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Contains"]/docs/*' />
public bool Contains (object config)
{
return configList.Contains (config);
}
/// <include file='ConfigCollection.xml' path='//Method[@name="IndexOf"]/docs/*' />
public int IndexOf (object config)
{
return configList.IndexOf (config);
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Insert"]/docs/*' />
public void Insert (int index, object config)
{
configList.Insert (index, config);
}
#endregion
#region Public events
/// <include file='ConfigCollection.xml' path='//Event[@name="ConfigAdded"]/docs/*' />
public event ConfigEventHandler ConfigAdded;
/// <include file='ConfigCollection.xml' path='//Event[@name="ConfigRemoved"]/docs/*' />
public event ConfigEventHandler ConfigRemoved;
#endregion
#region Protected methods
/// <include file='ConfigCollection.xml' path='//Method[@name="OnConfigAdded"]/docs/*' />
protected void OnConfigAdded (ConfigEventArgs e)
{
if (ConfigAdded != null) {
ConfigAdded (this, e);
}
}
/// <include file='ConfigCollection.xml' path='//Method[@name="OnConfigRemoved"]/docs/*' />
protected void OnConfigRemoved (ConfigEventArgs e)
{
if (ConfigRemoved != null) {
ConfigRemoved (this, e);
}
}
#endregion
#region Private methods
#endregion
}
}

View File

@ -0,0 +1,219 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.Text;
using System.Collections;
namespace Nini.Config
{
/// <include file='IConfigSource.xml' path='//Interface[@name="IConfigSource"]/docs/*' />
public abstract class ConfigSourceBase : IConfigSource
{
#region Private variables
ArrayList sourceList = new ArrayList ();
ConfigCollection configList = null;
bool autoSave = false;
AliasText alias = new AliasText ();
#endregion
#region Constructors
/// <include file='ConfigSourceBase.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public ConfigSourceBase ()
{
configList = new ConfigCollection (this);
}
#endregion
#region Public properties
/// <include file='IConfigSource.xml' path='//Property[@name="Configs"]/docs/*' />
public ConfigCollection Configs
{
get { return configList; }
}
/// <include file='IConfigSource.xml' path='//Property[@name="AutoSave"]/docs/*' />
public bool AutoSave
{
get { return autoSave; }
set { autoSave = value; }
}
/// <include file='IConfigSource.xml' path='//Property[@name="Alias"]/docs/*' />
public AliasText Alias
{
get { return alias; }
}
#endregion
#region Public methods
/// <include file='IConfigSource.xml' path='//Method[@name="Merge"]/docs/*' />
public void Merge (IConfigSource source)
{
if (!sourceList.Contains (source)) {
sourceList.Add (source);
}
foreach (IConfig config in source.Configs)
{
this.Configs.Add (config);
}
}
/// <include file='IConfigSource.xml' path='//Method[@name="AddConfig"]/docs/*' />
public virtual IConfig AddConfig (string name)
{
return configList.Add (name);
}
/// <include file='IConfigSource.xml' path='//Method[@name="GetExpanded"]/docs/*' />
public string GetExpanded (IConfig config, string key)
{
return Expand (config, key, false);
}
/// <include file='IConfigSource.xml' path='//Method[@name="Save"]/docs/*' />
public virtual void Save ()
{
OnSaved (new EventArgs ());
}
/// <include file='IConfigSource.xml' path='//Method[@name="Reload"]/docs/*' />
public virtual void Reload ()
{
OnReloaded (new EventArgs ());
}
/// <include file='IConfigSource.xml' path='//Method[@name="ExpandKeyValues"]/docs/*' />
public void ExpandKeyValues ()
{
string[] keys = null;
foreach (IConfig config in configList)
{
keys = config.GetKeys ();
for (int i = 0; i < keys.Length; i++)
{
Expand (config, keys[i], true);
}
}
}
/// <include file='IConfigSource.xml' path='//Method[@name="ReplaceKeyValues"]/docs/*' />
public void ReplaceKeyValues ()
{
ExpandKeyValues ();
}
#endregion
#region Public events
/// <include file='IConfigSource.xml' path='//Event[@name="Reloaded"]/docs/*' />
public event EventHandler Reloaded;
/// <include file='IConfigSource.xml' path='//Event[@name="Saved"]/docs/*' />
public event EventHandler Saved;
#endregion
#region Protected methods
/// <include file='ConfigSourceBase.xml' path='//Method[@name="OnReloaded"]/docs/*' />
protected void OnReloaded (EventArgs e)
{
if (Reloaded != null) {
Reloaded (this, e);
}
}
/// <include file='ConfigSourceBase.xml' path='//Method[@name="OnSaved"]/docs/*' />
protected void OnSaved (EventArgs e)
{
if (Saved != null) {
Saved (this, e);
}
}
#endregion
#region Private methods
/// <summary>
/// Expands key values from the given IConfig.
/// </summary>
private string Expand (IConfig config, string key, bool setValue)
{
string result = config.Get (key);
if (result == null) {
throw new ArgumentException (String.Format ("[{0}] not found in [{1}]",
key, config.Name));
}
while (true)
{
int startIndex = result.IndexOf ("${", 0);
if (startIndex == -1) {
break;
}
int endIndex = result.IndexOf ("}", startIndex + 2);
if (endIndex == -1) {
break;
}
string search = result.Substring (startIndex + 2,
endIndex - (startIndex + 2));
if (search == key) {
// Prevent infinite recursion
throw new ArgumentException
("Key cannot have a expand value of itself: " + key);
}
string replace = ExpandValue (config, search);
result = result.Replace("${" + search + "}", replace);
}
if (setValue) {
config.Set(key, result);
}
return result;
}
/// <summary>
/// Returns the replacement value of a config.
/// </summary>
private string ExpandValue (IConfig config, string search)
{
string result = null;
string[] replaces = search.Split ('|');
if (replaces.Length > 1) {
IConfig newConfig = this.Configs[replaces[0]];
if (newConfig == null) {
throw new ArgumentException ("Expand config not found: "
+ replaces[0]);
}
result = newConfig.Get (replaces[1]);
if (result == null) {
throw new ArgumentException ("Expand key not found: "
+ replaces[1]);
}
} else {
result = config.Get (search);
if (result == null) {
throw new ArgumentException ("Key not found: " + search);
}
}
return result;
}
#endregion
}
}

View File

@ -0,0 +1,562 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.IO;
using System.Xml;
using System.Reflection;
using System.Collections;
using System.Configuration;
using System.Collections.Specialized;
namespace Nini.Config
{
/// <include file='DotNetConfigSource.xml' path='//Class[@name="DotNetConfigSource"]/docs/*' />
public class DotNetConfigSource : ConfigSourceBase
{
#region Private variables
string[] sections = null;
XmlDocument configDoc = null;
string savePath = null;
#endregion
#region Constructors
/// <include file='DotNetConfigSource.xml' path='//Constructor[@name="ConstructorWeb"]/docs/*' />
public DotNetConfigSource (string[] sections)
{
this.sections = sections;
Load ();
}
/// <include file='DotNetConfigSource.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public DotNetConfigSource ()
{
configDoc = new XmlDocument ();
configDoc.LoadXml ("<configuration><configSections/></configuration>");
PerformLoad (configDoc);
}
/// <include file='DotNetConfigSource.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public DotNetConfigSource (string path)
{
Load (path);
}
/// <include file='DotNetConfigSource.xml' path='//Constructor[@name="ConstructorXmlReader"]/docs/*' />
public DotNetConfigSource (XmlReader reader)
{
Load (reader);
}
#endregion
#region Public properties
/// <include file='DotNetConfigSource.xml' path='//Property[@name="SavePath"]/docs/*' />
public string SavePath
{
get { return savePath; }
}
#endregion
#region Public methods
/// <include file='DotNetConfigSource.xml' path='//Method[@name="LoadPath"]/docs/*' />
public void Load (string path)
{
savePath = path;
configDoc = new XmlDocument ();
configDoc.Load (savePath);
PerformLoad (configDoc);
}
/// <include file='DotNetConfigSource.xml' path='//Method[@name="LoadXmlReader"]/docs/*' />
public void Load (XmlReader reader)
{
configDoc = new XmlDocument ();
configDoc.Load (reader);
PerformLoad (configDoc);
}
/// <include file='DotNetConfigSource.xml' path='//Method[@name="Save"]/docs/*' />
public override void Save ()
{
if (!IsSavable ()) {
throw new ArgumentException ("Source cannot be saved in this state");
}
MergeConfigsIntoDocument ();
configDoc.Save (savePath);
base.Save ();
}
/// <include file='DotNetConfigSource.xml' path='//Method[@name="SavePath"]/docs/*' />
public void Save (string path)
{
if (!IsSavable ()) {
throw new ArgumentException ("Source cannot be saved in this state");
}
savePath = path;
this.Save ();
}
/// <include file='DotNetConfigSource.xml' path='//Method[@name="SaveTextWriter"]/docs/*' />
public void Save (TextWriter writer)
{
if (!IsSavable ()) {
throw new ArgumentException ("Source cannot be saved in this state");
}
MergeConfigsIntoDocument ();
configDoc.Save (writer);
savePath = null;
OnSaved (new EventArgs ());
}
/// <include file='DotNetConfigSource.xml' path='//Method[@name="SaveStream"]/docs/*' />
public void Save (Stream stream)
{
if (!IsSavable ()) {
throw new ArgumentException ("Source cannot be saved in this state");
}
MergeConfigsIntoDocument ();
configDoc.Save (stream);
savePath = null;
OnSaved (new EventArgs ());
}
/// <include file='IConfigSource.xml' path='//Method[@name="Reload"]/docs/*' />
public override void Reload ()
{
if (savePath == null) {
throw new ArgumentException ("Error reloading: You must have "
+ "the loaded the source from a file");
}
configDoc = new XmlDocument ();
configDoc.Load (savePath);
MergeDocumentIntoConfigs ();
base.Reload ();
}
/// <include file='DotNetConfigSource.xml' path='//Method[@name="ToString"]/docs/*' />
public override string ToString ()
{
MergeConfigsIntoDocument ();
StringWriter writer = new StringWriter ();
configDoc.Save (writer);
return writer.ToString ();
}
#if (NET_COMPACT_1_0)
#else
/// <include file='DotNetConfigSource.xml' path='//Method[@name="GetFullConfigPath"]/docs/*' />
public static string GetFullConfigPath ()
{
return (Assembly.GetCallingAssembly().Location + ".config");
}
#endif
#endregion
#region Private methods
/// <summary>
/// Merges all of the configs from the config collection into the
/// XmlDocument.
/// </summary>
private void MergeConfigsIntoDocument ()
{
RemoveSections ();
foreach (IConfig config in this.Configs)
{
string[] keys = config.GetKeys ();
RemoveKeys (config.Name);
XmlNode node = GetChildElement (config.Name);
if (node == null) {
node = SectionNode (config.Name);
}
for (int i = 0; i < keys.Length; i++)
{
SetKey (node, keys[i], config.Get (keys[i]));
}
}
}
/// <summary>
/// Loads all collection classes.
/// </summary>
private void Load ()
{
#if (NET_COMPACT_1_0)
throw new NotSupportedException ("This loading method is not supported");
#else
this.Merge (this); // required for SaveAll
for (int i = 0; i < sections.Length; i++)
{
LoadCollection (sections[i], (NameValueCollection)ConfigurationSettings
.GetConfig (sections[i]));
}
#endif
}
/// <summary>
/// Loads all sections and keys.
/// </summary>
private void PerformLoad (XmlDocument document)
{
this.Configs.Clear ();
this.Merge (this); // required for SaveAll
if (document.DocumentElement.Name != "configuration") {
throw new ArgumentException ("Did not find configuration node");
}
LoadSections (document.DocumentElement);
}
/// <summary>
/// Loads all configuration sections.
/// </summary>
private void LoadSections (XmlNode rootNode)
{
LoadOtherSection (rootNode, "appSettings");
XmlNode sections = GetChildElement (rootNode, "configSections");
if (sections == null) {
// There is no configSections node so exit
return;
}
ConfigBase config = null;
foreach (XmlNode node in sections.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element
&& node.Name == "section") {
config = new ConfigBase
(node.Attributes["name"].Value, this);
this.Configs.Add (config);
LoadKeys (rootNode, config);
}
}
}
/// <summary>
/// Loads special sections that are not loaded in the configSections
/// node. This includes such sections such as appSettings.
/// </summary>
private void LoadOtherSection (XmlNode rootNode, string nodeName)
{
XmlNode section = GetChildElement (rootNode, nodeName);
ConfigBase config = null;
if (section != null) {
config = new ConfigBase (section.Name, this);
this.Configs.Add (config);
LoadKeys (rootNode, config);
}
}
/// <summary>
/// Loads all keys for a config.
/// </summary>
private void LoadKeys (XmlNode rootNode, ConfigBase config)
{
XmlNode section = GetChildElement (rootNode, config.Name);
foreach (XmlNode node in section.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element
&& node.Name == "add") {
config.Add (node.Attributes["key"].Value,
node.Attributes["value"].Value);
}
}
}
/// <summary>
/// Removes all XML sections that were removed as configs.
/// </summary>
private void RemoveSections ()
{
XmlAttribute attr = null;
XmlNode sections = GetChildElement ("configSections");
if (sections == null) {
// There is no configSections node so exit
return;
}
foreach (XmlNode node in sections.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element
&& node.Name == "section") {
attr = node.Attributes["name"];
if (attr != null) {
if (this.Configs[attr.Value] == null) {
// Removes the configSections section
node.ParentNode.RemoveChild (node);
// Removes the <SectionName> section
XmlNode dataNode = GetChildElement (attr.Value);
if (dataNode != null) {
configDoc.DocumentElement.RemoveChild (dataNode);
}
}
} else {
throw new ArgumentException ("Section name attribute not found");
}
}
}
}
/// <summary>
/// Removes all XML keys that were removed as config keys.
/// </summary>
private void RemoveKeys (string sectionName)
{
XmlNode node = GetChildElement (sectionName);
XmlAttribute keyName = null;
if (node != null) {
foreach (XmlNode key in node.ChildNodes)
{
if (key.NodeType == XmlNodeType.Element
&& key.Name == "add") {
keyName = key.Attributes["key"];
if (keyName != null) {
if (this.Configs[sectionName].Get (keyName.Value) == null) {
node.RemoveChild (key);
}
} else {
throw new ArgumentException ("Key attribute not found in node");
}
}
}
}
}
/// <summary>
/// Sets an XML key. If it does not exist then it is created.
/// </summary>
private void SetKey (XmlNode sectionNode, string key, string value)
{
XmlNode keyNode = GetKey (sectionNode, key);
if (keyNode == null) {
CreateKey (sectionNode, key, value);
} else {
keyNode.Attributes["value"].Value = value;
}
}
/// <summary>
/// Gets an XML key by it's name. Returns null if it does not exist.
/// </summary>
private XmlNode GetKey (XmlNode sectionNode, string keyName)
{
XmlNode result = null;
foreach (XmlNode node in sectionNode.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element
&& node.Name == "add"
&& node.Attributes["key"].Value == keyName) {
result = node;
break;
}
}
return result;
}
/// <summary>
/// Creates a key node and adds it to the collection at the end.
/// </summary>
private void CreateKey (XmlNode sectionNode, string key, string value)
{
XmlNode node = configDoc.CreateElement ("add");
XmlAttribute keyAttr = configDoc.CreateAttribute ("key");
XmlAttribute valueAttr = configDoc.CreateAttribute ("value");
keyAttr.Value = key;
valueAttr.Value = value;
node.Attributes.Append (keyAttr);
node.Attributes.Append (valueAttr);
sectionNode.AppendChild (node);
}
/// <summary>
/// Loads a collection class.
/// </summary>
private void LoadCollection (string name, NameValueCollection collection)
{
ConfigBase config = new ConfigBase (name, this);
if (collection == null) {
throw new ArgumentException ("Section was not found");
}
if (collection != null) {
for (int i = 0; i < collection.Count; i++)
{
config.Add (collection.Keys[i], collection[i]);
}
this.Configs.Add (config);
}
}
/// <summary>
/// Returns a new section node.
/// </summary>
private XmlNode SectionNode (string name)
{
// Add node for configSections node
XmlNode node = configDoc.CreateElement ("section");
XmlAttribute attr = configDoc.CreateAttribute ("name");
attr.Value = name;
node.Attributes.Append (attr);
attr = configDoc.CreateAttribute ("type");
attr.Value = "System.Configuration.NameValueSectionHandler";
node.Attributes.Append (attr);
XmlNode section = GetChildElement ("configSections");
section.AppendChild (node);
// Add node for configuration node
XmlNode result = configDoc.CreateElement (name);
configDoc.DocumentElement.AppendChild (result);
return result;
}
/// <summary>
/// Returns true if this instance is savable.
/// </summary>
private bool IsSavable ()
{
return (this.savePath != null
|| configDoc != null);
}
/// <summary>
/// Returns the single named child element.
/// </summary>
private XmlNode GetChildElement (XmlNode parentNode, string name)
{
XmlNode result = null;
foreach (XmlNode node in parentNode.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element
&& node.Name == name) {
result = node;
break;
}
}
return result;
}
/// <summary>
/// Returns a child element from the XmlDocument.DocumentElement.
/// </summary>
private XmlNode GetChildElement (string name)
{
return GetChildElement (configDoc.DocumentElement, name);
}
/// <summary>
/// Merges the XmlDocument into the Configs when the document is
/// reloaded.
/// </summary>
private void MergeDocumentIntoConfigs ()
{
// Remove all missing configs first
RemoveConfigs ();
XmlNode sections = GetChildElement ("configSections");
if (sections == null) {
// There is no configSections node so exit
return;
}
foreach (XmlNode node in sections.ChildNodes)
{
// Find all section nodes
if (node.NodeType == XmlNodeType.Element
&& node.Name == "section") {
string sectionName = node.Attributes["name"].Value;
IConfig config = this.Configs[sectionName];
if (config == null) {
// The section is new so add it
config = new ConfigBase (sectionName, this);
this.Configs.Add (config);
}
RemoveConfigKeys (config);
}
}
}
/// <summary>
/// Removes all configs that are not in the newly loaded XmlDocument.
/// </summary>
private void RemoveConfigs ()
{
IConfig config = null;
for (int i = this.Configs.Count - 1; i > -1; i--)
{
config = this.Configs[i];
// If the section is not present in the XmlDocument
if (GetChildElement (config.Name) == null) {
this.Configs.Remove (config);
}
}
}
/// <summary>
/// Removes all XML keys that were removed as config keys.
/// </summary>
private void RemoveConfigKeys (IConfig config)
{
XmlNode section = GetChildElement (config.Name);
// Remove old keys
string[] configKeys = config.GetKeys ();
foreach (string configKey in configKeys)
{
if (GetKey (section, configKey) == null) {
// Key doesn't exist, remove
config.Remove (configKey);
}
}
// Add or set all new keys
foreach (XmlNode node in section.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element
&& node.Name == "add") {
config.Set (node.Attributes["key"].Value,
node.Attributes["value"].Value);
}
}
}
#endregion
}
}

View File

@ -0,0 +1,99 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
namespace Nini.Config
{
/// <include file='IConfig.xml' path='//Interface[@name="IConfig"]/docs/*' />
public interface IConfig
{
/// <include file='IConfig.xml' path='//Property[@name="ConfigSource"]/docs/*' />
IConfigSource ConfigSource { get; }
/// <include file='IConfig.xml' path='//Property[@name="Name"]/docs/*' />
string Name { get; set; }
/// <include file='IConfig.xml' path='//Property[@name="Alias"]/docs/*' />
AliasText Alias { get; }
/// <include file='IConfig.xml' path='//Method[@name="Contains"]/docs/*' />
bool Contains (string key);
/// <include file='IConfig.xml' path='//Method[@name="Get"]/docs/*' />
string Get (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetDefault"]/docs/*' />
string Get (string key, string defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetExpanded"]/docs/*' />
string GetExpanded (string key);
/// <include file='IConfig.xml' path='//Method[@name="Get"]/docs/*' />
string GetString (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetDefault"]/docs/*' />
string GetString (string key, string defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetInt"]/docs/*' />
int GetInt (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetIntAlias"]/docs/*' />
int GetInt (string key, bool fromAlias);
/// <include file='IConfig.xml' path='//Method[@name="GetIntDefault"]/docs/*' />
int GetInt (string key, int defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetIntDefaultAlias"]/docs/*' />
int GetInt (string key, int defaultValue, bool fromAlias);
/// <include file='IConfig.xml' path='//Method[@name="GetLong"]/docs/*' />
long GetLong (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetLongDefault"]/docs/*' />
long GetLong (string key, long defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetBoolean"]/docs/*' />
bool GetBoolean (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetBooleanDefault"]/docs/*' />
bool GetBoolean (string key, bool defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetFloat"]/docs/*' />
float GetFloat (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetFloatDefault"]/docs/*' />
float GetFloat (string key, float defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetDouble"]/docs/*' />
double GetDouble (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetDoubleDefault"]/docs/*' />
double GetDouble (string key, double defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetKeys"]/docs/*' />
string[] GetKeys ();
/// <include file='IConfig.xml' path='//Method[@name="GetValues"]/docs/*' />
string[] GetValues ();
/// <include file='IConfig.xml' path='//Method[@name="Set"]/docs/*' />
void Set (string key, object value);
/// <include file='IConfig.xml' path='//Method[@name="Remove"]/docs/*' />
void Remove (string key);
/// <include file='IConfig.xml' path='//Event[@name="KeySet"]/docs/*' />
event ConfigKeyEventHandler KeySet;
/// <include file='IConfig.xml' path='//Event[@name="KeyRemoved"]/docs/*' />
event ConfigKeyEventHandler KeyRemoved;
}
}

View File

@ -0,0 +1,55 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.IO;
namespace Nini.Config
{
/// <include file='IConfigSource.xml' path='//Interface[@name="IConfigSource"]/docs/*' />
public interface IConfigSource
{
/// <include file='IConfigSource.xml' path='//Property[@name="Configs"]/docs/*' />
ConfigCollection Configs { get; }
/// <include file='IConfigSource.xml' path='//Property[@name="AutoSave"]/docs/*' />
bool AutoSave { get; set; }
/// <include file='IConfigSource.xml' path='//Property[@name="Alias"]/docs/*' />
AliasText Alias { get; }
/// <include file='IConfigSource.xml' path='//Method[@name="Merge"]/docs/*' />
void Merge (IConfigSource source);
/// <include file='IConfigSource.xml' path='//Method[@name="Save"]/docs/*' />
void Save ();
/// <include file='IConfigSource.xml' path='//Method[@name="Reload"]/docs/*' />
void Reload ();
/// <include file='IConfigSource.xml' path='//Method[@name="AddConfig"]/docs/*' />
IConfig AddConfig (string name);
/// <include file='IConfigSource.xml' path='//Method[@name="GetExpanded"]/docs/*' />
string GetExpanded (IConfig config, string key);
/// <include file='IConfigSource.xml' path='//Method[@name="ExpandKeyValues"]/docs/*' />
void ExpandKeyValues ();
/// <include file='IConfigSource.xml' path='//Method[@name="ReplaceKeyValues"]/docs/*' />
void ReplaceKeyValues ();
/// <include file='IConfigSource.xml' path='//Event[@name="Reloaded"]/docs/*' />
event EventHandler Reloaded;
/// <include file='IConfigSource.xml' path='//Event[@name="Saved"]/docs/*' />
event EventHandler Saved;
}
}

View File

@ -0,0 +1,90 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.Collections;
using System.Globalization;
using Nini.Util;
namespace Nini.Config
{
/// <include file='IniConfig.xml' path='//Class[@name="IniConfig"]/docs/*' />
public class IniConfig : ConfigBase
{
#region Private variables
IniConfigSource parent = null;
#endregion
#region Constructors
/// <include file='IniConfig.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniConfig (string name, IConfigSource source)
: base(name, source)
{
parent = (IniConfigSource)source;
}
#endregion
#region Public properties
#endregion
#region Public methods
/// <include file='IniConfig.xml' path='//Method[@name="Get"]/docs/*' />
public override string Get (string key)
{
if (!parent.CaseSensitive) {
key = CaseInsensitiveKeyName (key);
}
return base.Get (key);
}
/// <include file='IniConfig.xml' path='//Method[@name="Set"]/docs/*' />
public override void Set (string key, object value)
{
if (!parent.CaseSensitive) {
key = CaseInsensitiveKeyName (key);
}
base.Set (key, value);
}
/// <include file='IniConfig.xml' path='//Method[@name="Remove"]/docs/*' />
public override void Remove (string key)
{
if (!parent.CaseSensitive) {
key = CaseInsensitiveKeyName (key);
}
base.Remove (key);
}
#endregion
#region Private methods
/// <summary>
/// Returns the key name if the case insensitivity is turned on.
/// </summary>
private string CaseInsensitiveKeyName (string key)
{
string result = null;
string lowerKey = key.ToLower ();
foreach (string currentKey in keys.Keys)
{
if (currentKey.ToLower () == lowerKey) {
result = currentKey;
break;
}
}
return (result == null) ? key : result;
}
#endregion
}
}

View File

@ -0,0 +1,329 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.IO;
using System.Collections;
using Nini.Ini;
namespace Nini.Config
{
/// <include file='IniConfigSource.xml' path='//Class[@name="IniConfigSource"]/docs/*' />
public class IniConfigSource : ConfigSourceBase
{
#region Private variables
IniDocument iniDocument = null;
string savePath = null;
bool caseSensitive = true;
#endregion
#region Public properties
#endregion
#region Constructors
/// <include file='IniConfigSource.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniConfigSource ()
{
iniDocument = new IniDocument ();
}
/// <include file='IniConfigSource.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public IniConfigSource (string filePath)
{
Load (filePath);
}
/// <include file='IniConfigSource.xml' path='//Constructor[@name="ConstructorTextReader"]/docs/*' />
public IniConfigSource (TextReader reader)
{
Load (reader);
}
/// <include file='IniConfigSource.xml' path='//Constructor[@name="ConstructorIniDocument"]/docs/*' />
public IniConfigSource (IniDocument document)
{
Load (document);
}
/// <include file='IniConfigSource.xml' path='//Constructor[@name="ConstructorStream"]/docs/*' />
public IniConfigSource (Stream stream)
{
Load (stream);
}
#endregion
#region Public properties
/// <include file='IniConfigSource.xml' path='//Property[@name="CaseSensitive"]/docs/*' />
public bool CaseSensitive
{
get { return caseSensitive; }
set { caseSensitive = value; }
}
/// <include file='IniConfigSource.xml' path='//Property[@name="SavePath"]/docs/*' />
public string SavePath
{
get { return savePath; }
}
#endregion
#region Public methods
/// <include file='IniConfigSource.xml' path='//Method[@name="LoadPath"]/docs/*' />
public void Load (string filePath)
{
Load (new StreamReader (filePath));
this.savePath = filePath;
}
/// <include file='IniConfigSource.xml' path='//Method[@name="LoadTextReader"]/docs/*' />
public void Load (TextReader reader)
{
Load (new IniDocument (reader));
}
/// <include file='IniConfigSource.xml' path='//Method[@name="LoadIniDocument"]/docs/*' />
public void Load (IniDocument document)
{
this.Configs.Clear ();
this.Merge (this); // required for SaveAll
iniDocument = document;
Load ();
}
/// <include file='IniConfigSource.xml' path='//Method[@name="LoadStream"]/docs/*' />
public void Load (Stream stream)
{
Load (new StreamReader (stream));
}
/// <include file='IniConfigSource.xml' path='//Method[@name="Save"]/docs/*' />
public override void Save ()
{
if (!IsSavable ()) {
throw new ArgumentException ("Source cannot be saved in this state");
}
MergeConfigsIntoDocument ();
iniDocument.Save (this.savePath);
base.Save ();
}
/// <include file='IniConfigSource.xml' path='//Method[@name="SavePath"]/docs/*' />
public void Save (string path)
{
this.savePath = path;
this.Save ();
}
/// <include file='IniConfigSource.xml' path='//Method[@name="SaveTextWriter"]/docs/*' />
public void Save (TextWriter writer)
{
MergeConfigsIntoDocument ();
iniDocument.Save (writer);
savePath = null;
OnSaved (new EventArgs ());
}
/// <include file='IniConfigSource.xml' path='//Method[@name="SaveStream"]/docs/*' />
public void Save (Stream stream)
{
MergeConfigsIntoDocument ();
iniDocument.Save (stream);
savePath = null;
OnSaved (new EventArgs ());
}
/// <include file='IConfigSource.xml' path='//Method[@name="Reload"]/docs/*' />
public override void Reload ()
{
if (savePath == null) {
throw new ArgumentException ("Error reloading: You must have "
+ "the loaded the source from a file");
}
iniDocument = new IniDocument (savePath);
MergeDocumentIntoConfigs ();
base.Reload ();
}
/// <include file='IniConfigSource.xml' path='//Method[@name="ToString"]/docs/*' />
public override string ToString ()
{
MergeConfigsIntoDocument ();
StringWriter writer = new StringWriter ();
iniDocument.Save (writer);
return writer.ToString ();
}
#endregion
#region Private methods
/// <summary>
/// Merges all of the configs from the config collection into the
/// IniDocument before it is saved.
/// </summary>
private void MergeConfigsIntoDocument ()
{
RemoveSections ();
foreach (IConfig config in this.Configs)
{
string[] keys = config.GetKeys ();
// Create a new section if one doesn't exist
if (iniDocument.Sections[config.Name] == null) {
IniSection section = new IniSection (config.Name);
iniDocument.Sections.Add (section);
}
RemoveKeys (config.Name);
for (int i = 0; i < keys.Length; i++)
{
iniDocument.Sections[config.Name].Set (keys[i], config.Get (keys[i]));
}
}
}
/// <summary>
/// Removes all INI sections that were removed as configs.
/// </summary>
private void RemoveSections ()
{
IniSection section = null;
for (int i = 0; i < iniDocument.Sections.Count; i++)
{
section = iniDocument.Sections[i];
if (this.Configs[section.Name] == null) {
iniDocument.Sections.Remove (section.Name);
}
}
}
/// <summary>
/// Removes all INI keys that were removed as config keys.
/// </summary>
private void RemoveKeys (string sectionName)
{
IniSection section = iniDocument.Sections[sectionName];
if (section != null) {
foreach (string key in section.GetKeys ())
{
if (this.Configs[sectionName].Get (key) == null) {
section.Remove (key);
}
}
}
}
/// <summary>
/// Loads the configuration file.
/// </summary>
private void Load ()
{
IniConfig config = null;
IniSection section = null;
IniItem item = null;
for (int j = 0; j < iniDocument.Sections.Count; j++)
{
section = iniDocument.Sections[j];
config = new IniConfig (section.Name, this);
for (int i = 0; i < section.ItemCount; i++)
{
item = section.GetItem (i);
if (item.Type == IniType.Key) {
config.Add (item.Name, item.Value);
}
}
this.Configs.Add (config);
}
}
/// <summary>
/// Merges the IniDocument into the Configs when the document is
/// reloaded.
/// </summary>
private void MergeDocumentIntoConfigs ()
{
// Remove all missing configs first
RemoveConfigs ();
IniSection section = null;
for (int i = 0; i < iniDocument.Sections.Count; i++)
{
section = iniDocument.Sections[i];
IConfig config = this.Configs[section.Name];
if (config == null) {
// The section is new so add it
config = new ConfigBase (section.Name, this);
this.Configs.Add (config);
}
RemoveConfigKeys (config);
}
}
/// <summary>
/// Removes all configs that are not in the newly loaded INI doc.
/// </summary>
private void RemoveConfigs ()
{
IConfig config = null;
for (int i = this.Configs.Count - 1; i > -1; i--)
{
config = this.Configs[i];
// If the section is not present in the INI doc
if (iniDocument.Sections[config.Name] == null) {
this.Configs.Remove (config);
}
}
}
/// <summary>
/// Removes all INI keys that were removed as config keys.
/// </summary>
private void RemoveConfigKeys (IConfig config)
{
IniSection section = iniDocument.Sections[config.Name];
// Remove old keys
string[] configKeys = config.GetKeys ();
foreach (string configKey in configKeys)
{
if (!section.Contains (configKey)) {
// Key doesn't exist, remove
config.Remove (configKey);
}
}
// Add or set all new keys
string[] keys = section.GetKeys ();
for (int i = 0; i < keys.Length; i++)
{
string key = keys[i];
config.Set (key, section.GetItem (i).Value);
}
}
/// <summary>
/// Returns true if this instance is savable.
/// </summary>
private bool IsSavable ()
{
return (this.savePath != null);
}
#endregion
}
}

View File

@ -0,0 +1,280 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.IO;
using System.Collections;
using Microsoft.Win32;
using Nini.Ini;
namespace Nini.Config
{
#region RegistryRecurse enumeration
/// <include file='RegistryConfigSource.xml' path='//Enum[@name="RegistryRecurse"]/docs/*' />
public enum RegistryRecurse
{
/// <include file='RegistryConfigSource.xml' path='//Enum[@name="RegistryRecurse"]/Value[@name="None"]/docs/*' />
None,
/// <include file='RegistryConfigSource.xml' path='//Enum[@name="RegistryRecurse"]/Value[@name="Flattened"]/docs/*' />
Flattened,
/// <include file='RegistryConfigSource.xml' path='//Enum[@name="RegistryRecurse"]/Value[@name="Namespacing"]/docs/*' />
Namespacing
}
#endregion
/// <include file='RegistryConfigSource.xml' path='//Class[@name="RegistryConfigSource"]/docs/*' />
public class RegistryConfigSource : ConfigSourceBase
{
#region Private variables
RegistryKey defaultKey = null;
#endregion
#region Public properties
/// <include file='RegistryConfigSource.xml' path='//Property[@name="DefaultKey"]/docs/*' />
public RegistryKey DefaultKey
{
get { return defaultKey; }
set { defaultKey = value; }
}
#endregion
#region Constructors
#endregion
#region Public methods
/// <include file='RegistryConfigSource.xml' path='//Method[@name="AddConfig"]/docs/*' />
public override IConfig AddConfig (string name)
{
if (this.DefaultKey == null) {
throw new ApplicationException ("You must set DefaultKey");
}
return AddConfig (name, this.DefaultKey);
}
/// <include file='RegistryConfigSource.xml' path='//Method[@name="AddConfigKey"]/docs/*' />
public IConfig AddConfig (string name, RegistryKey key)
{
RegistryConfig result = new RegistryConfig (name, this);
result.Key = key;
result.ParentKey = true;
this.Configs.Add (result);
return result;
}
/// <include file='RegistryConfigSource.xml' path='//Method[@name="AddMapping"]/docs/*' />
public void AddMapping (RegistryKey registryKey, string path)
{
RegistryKey key = registryKey.OpenSubKey (path, true);
if (key == null) {
throw new ArgumentException ("The specified key does not exist");
}
LoadKeyValues (key, ShortKeyName (key));
}
/// <include file='RegistryConfigSource.xml' path='//Method[@name="AddMappingRecurse"]/docs/*' />
public void AddMapping (RegistryKey registryKey,
string path,
RegistryRecurse recurse)
{
RegistryKey key = registryKey.OpenSubKey (path, true);
if (key == null) {
throw new ArgumentException ("The specified key does not exist");
}
if (recurse == RegistryRecurse.Namespacing) {
LoadKeyValues (key, path);
} else {
LoadKeyValues (key, ShortKeyName (key));
}
string[] subKeys = key.GetSubKeyNames ();
for (int i = 0; i < subKeys.Length; i++)
{
switch (recurse)
{
case RegistryRecurse.None:
// no recursion
break;
case RegistryRecurse.Namespacing:
AddMapping (registryKey, path + "\\" + subKeys[i], recurse);
break;
case RegistryRecurse.Flattened:
AddMapping (key, subKeys[i], recurse);
break;
}
}
}
/// <include file='IConfigSource.xml' path='//Method[@name="Save"]/docs/*' />
public override void Save ()
{
MergeConfigsIntoDocument ();
for (int i = 0; i < this.Configs.Count; i++)
{
// New merged configs are not RegistryConfigs
if (this.Configs[i] is RegistryConfig) {
RegistryConfig config = (RegistryConfig)this.Configs[i];
string[] keys = config.GetKeys ();
for (int j = 0; j < keys.Length; j++)
{
config.Key.SetValue (keys[j], config.Get (keys[j]));
}
}
}
}
/// <include file='IConfigSource.xml' path='//Method[@name="Reload"]/docs/*' />
public override void Reload ()
{
ReloadKeys ();
}
#endregion
#region Private methods
/// <summary>
/// Loads all values from the registry key.
/// </summary>
private void LoadKeyValues (RegistryKey key, string keyName)
{
RegistryConfig config = new RegistryConfig (keyName, this);
config.Key = key;
string[] values = key.GetValueNames ();
foreach (string value in values)
{
config.Add (value, key.GetValue (value).ToString ());
}
this.Configs.Add (config);
}
/// <summary>
/// Merges all of the configs from the config collection into the
/// registry.
/// </summary>
private void MergeConfigsIntoDocument ()
{
foreach (IConfig config in this.Configs)
{
if (config is RegistryConfig) {
RegistryConfig registryConfig = (RegistryConfig)config;
if (registryConfig.ParentKey) {
registryConfig.Key =
registryConfig.Key.CreateSubKey (registryConfig.Name);
}
RemoveKeys (registryConfig);
string[] keys = config.GetKeys ();
for (int i = 0; i < keys.Length; i++)
{
registryConfig.Key.SetValue (keys[i], config.Get (keys[i]));
}
registryConfig.Key.Flush ();
}
}
}
/// <summary>
/// Reloads all keys.
/// </summary>
private void ReloadKeys ()
{
RegistryKey[] keys = new RegistryKey[this.Configs.Count];
for (int i = 0; i < keys.Length; i++)
{
keys[i] = ((RegistryConfig)this.Configs[i]).Key;
}
this.Configs.Clear ();
for (int i = 0; i < keys.Length; i++)
{
LoadKeyValues (keys[i], ShortKeyName (keys[i]));
}
}
/// <summary>
/// Removes all keys not present in the current config.
/// </summary>
private void RemoveKeys (RegistryConfig config)
{
foreach (string valueName in config.Key.GetValueNames ())
{
if (!config.Contains (valueName)) {
config.Key.DeleteValue (valueName);
}
}
}
/// <summary>
/// Returns the key name without the fully qualified path.
/// e.g. no HKEY_LOCAL_MACHINE\\MyKey, just MyKey
/// </summary>
private string ShortKeyName (RegistryKey key)
{
int index = key.Name.LastIndexOf ("\\");
return (index == -1) ? key.Name : key.Name.Substring (index + 1);
}
#region RegistryConfig class
/// <summary>
/// Registry Config class.
/// </summary>
private class RegistryConfig : ConfigBase
{
#region Private variables
RegistryKey key = null;
bool parentKey = false;
#endregion
#region Constructor
/// <summary>
/// Constructor.
/// </summary>
public RegistryConfig (string name, IConfigSource source)
: base (name, source)
{
}
#endregion
#region Public properties
/// <summary>
/// Gets or sets whether the key is a parent key.
/// </summary>
public bool ParentKey
{
get { return parentKey; }
set { parentKey = value; }
}
/// <summary>
/// Registry key for the Config.
/// </summary>
public RegistryKey Key
{
get { return key; }
set { key = value; }
}
#endregion
}
#endregion
#endregion
}
}

View File

@ -0,0 +1,428 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.IO;
using System.Xml;
using System.Collections;
namespace Nini.Config
{
/// <include file='XmlConfigSource.xml' path='//Class[@name="XmlConfigSource"]/docs/*' />
public class XmlConfigSource : ConfigSourceBase
{
#region Private variables
XmlDocument configDoc = null;
string savePath = null;
#endregion
#region Constructors
/// <include file='XmlConfigSource.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public XmlConfigSource ()
{
configDoc = new XmlDocument ();
configDoc.LoadXml ("<Nini/>");
PerformLoad (configDoc);
}
/// <include file='XmlConfigSource.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public XmlConfigSource (string path)
{
Load (path);
}
/// <include file='XmlConfigSource.xml' path='//Constructor[@name="ConstructorXmlReader"]/docs/*' />
public XmlConfigSource (XmlReader reader)
{
Load (reader);
}
#endregion
#region Public properties
/// <include file='XmlConfigSource.xml' path='//Property[@name="SavePath"]/docs/*' />
public string SavePath
{
get { return savePath; }
}
#endregion
#region Public methods
/// <include file='XmlConfigSource.xml' path='//Method[@name="LoadPath"]/docs/*' />
public void Load (string path)
{
savePath = path;
configDoc = new XmlDocument ();
configDoc.Load (path);
PerformLoad (configDoc);
}
/// <include file='XmlConfigSource.xml' path='//Method[@name="LoadXmlReader"]/docs/*' />
public void Load (XmlReader reader)
{
configDoc = new XmlDocument ();
configDoc.Load (reader);
PerformLoad (configDoc);
}
/// <include file='XmlConfigSource.xml' path='//Method[@name="Save"]/docs/*' />
public override void Save ()
{
if (!IsSavable ()) {
throw new ArgumentException ("Source cannot be saved in this state");
}
MergeConfigsIntoDocument ();
configDoc.Save (savePath);
base.Save ();
}
/// <include file='XmlConfigSource.xml' path='//Method[@name="SavePath"]/docs/*' />
public void Save (string path)
{
this.savePath = path;
this.Save ();
}
/// <include file='XmlConfigSource.xml' path='//Method[@name="SaveTextWriter"]/docs/*' />
public void Save (TextWriter writer)
{
MergeConfigsIntoDocument ();
configDoc.Save (writer);
savePath = null;
OnSaved (new EventArgs ());
}
/// <include file='XmlConfigSource.xml' path='//Method[@name="SaveStream"]/docs/*' />
public void Save (Stream stream)
{
MergeConfigsIntoDocument ();
configDoc.Save (stream);
savePath = null;
OnSaved (new EventArgs ());
}
/// <include file='IConfigSource.xml' path='//Method[@name="Reload"]/docs/*' />
public override void Reload ()
{
if (savePath == null) {
throw new ArgumentException ("Error reloading: You must have "
+ "the loaded the source from a file");
}
configDoc = new XmlDocument ();
configDoc.Load (savePath);
MergeDocumentIntoConfigs ();
base.Reload ();
}
/// <include file='XmlConfigSource.xml' path='//Method[@name="ToString"]/docs/*' />
public override string ToString ()
{
MergeConfigsIntoDocument ();
StringWriter writer = new StringWriter ();
configDoc.Save (writer);
return writer.ToString ();
}
#endregion
#region Private methods
/// <summary>
/// Merges all of the configs from the config collection into the
/// XmlDocument.
/// </summary>
private void MergeConfigsIntoDocument ()
{
RemoveSections ();
foreach (IConfig config in this.Configs)
{
string[] keys = config.GetKeys ();
XmlNode node = GetSectionByName (config.Name);
if (node == null) {
node = SectionNode (config.Name);
configDoc.DocumentElement.AppendChild (node);
}
RemoveKeys (config.Name);
for (int i = 0; i < keys.Length; i++)
{
SetKey (node, keys[i], config.Get (keys[i]));
}
}
}
/// <summary>
/// Removes all XML sections that were removed as configs.
/// </summary>
private void RemoveSections ()
{
XmlAttribute attr = null;
foreach (XmlNode node in configDoc.DocumentElement.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element
&& node.Name == "Section") {
attr = node.Attributes["Name"];
if (attr != null) {
if (this.Configs[attr.Value] == null) {
configDoc.DocumentElement.RemoveChild (node);
}
} else {
throw new ArgumentException ("Section name attribute not found");
}
}
}
}
/// <summary>
/// Removes all XML keys that were removed as config keys.
/// </summary>
private void RemoveKeys (string sectionName)
{
XmlNode sectionNode = GetSectionByName (sectionName);
XmlAttribute keyName = null;
if (sectionNode != null) {
foreach (XmlNode node in sectionNode.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element
&& node.Name == "Key") {
keyName = node.Attributes["Name"];
if (keyName != null) {
if (this.Configs[sectionName].Get (keyName.Value) == null) {
sectionNode.RemoveChild (node);
}
} else {
throw new ArgumentException ("Name attribute not found in key");
}
}
}
}
}
/// <summary>
/// Loads all sections and keys.
/// </summary>
private void PerformLoad (XmlDocument document)
{
this.Configs.Clear ();
this.Merge (this); // required for SaveAll
if (document.DocumentElement.Name != "Nini") {
throw new ArgumentException ("Did not find Nini XML root node");
}
LoadSections (document.DocumentElement);
}
/// <summary>
/// Loads all configuration sections.
/// </summary>
private void LoadSections (XmlNode rootNode)
{
ConfigBase config = null;
foreach (XmlNode child in rootNode.ChildNodes)
{
if (child.NodeType == XmlNodeType.Element
&& child.Name == "Section") {
config = new ConfigBase (child.Attributes["Name"].Value, this);
this.Configs.Add (config);
LoadKeys (child, config);
}
}
}
/// <summary>
/// Loads all keys for a config.
/// </summary>
private void LoadKeys (XmlNode node, ConfigBase config)
{
foreach (XmlNode child in node.ChildNodes)
{
if (child.NodeType == XmlNodeType.Element
&& child.Name == "Key") {
config.Add (child.Attributes["Name"].Value,
child.Attributes["Value"].Value);
}
}
}
/// <summary>
/// Sets an XML key. If it does not exist then it is created.
/// </summary>
private void SetKey (XmlNode sectionNode, string key, string value)
{
XmlNode node = GetKeyByName (sectionNode, key);
if (node == null) {
CreateKey (sectionNode, key, value);
} else {
node.Attributes["Value"].Value = value;
}
}
/// <summary>
/// Creates a key node and adds it to the collection at the end.
/// </summary>
private void CreateKey (XmlNode sectionNode, string key, string value)
{
XmlNode node = configDoc.CreateElement ("Key");
XmlAttribute keyAttr = configDoc.CreateAttribute ("Name");
XmlAttribute valueAttr = configDoc.CreateAttribute ("Value");
keyAttr.Value = key;
valueAttr.Value = value;
node.Attributes.Append (keyAttr);
node.Attributes.Append (valueAttr);
sectionNode.AppendChild (node);
}
/// <summary>
/// Returns a new section node.
/// </summary>
private XmlNode SectionNode (string name)
{
XmlNode result = configDoc.CreateElement ("Section");
XmlAttribute nameAttr = configDoc.CreateAttribute ("Name");
nameAttr.Value = name;
result.Attributes.Append (nameAttr);
return result;
}
/// <summary>
/// Returns a section node by name.
/// </summary>
private XmlNode GetSectionByName (string name)
{
XmlNode result = null;
foreach (XmlNode node in configDoc.DocumentElement.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element
&& node.Name == "Section"
&& node.Attributes["Name"].Value == name) {
result = node;
break;
}
}
return result;
}
/// <summary>
/// Returns a key node by name.
/// </summary>
private XmlNode GetKeyByName (XmlNode sectionNode, string name)
{
XmlNode result = null;
foreach (XmlNode node in sectionNode.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element
&& node.Name == "Key"
&& node.Attributes["Name"].Value == name) {
result = node;
break;
}
}
return result;
}
/// <summary>
/// Returns true if this instance is savable.
/// </summary>
private bool IsSavable ()
{
return (this.savePath != null
&& configDoc != null);
}
/// <summary>
/// Merges the XmlDocument into the Configs when the document is
/// reloaded.
/// </summary>
private void MergeDocumentIntoConfigs ()
{
// Remove all missing configs first
RemoveConfigs ();
foreach (XmlNode node in configDoc.DocumentElement.ChildNodes)
{
// If node is a section node
if (node.NodeType == XmlNodeType.Element
&& node.Name == "Section") {
string sectionName = node.Attributes["Name"].Value;
IConfig config = this.Configs[sectionName];
if (config == null) {
// The section is new so add it
config = new ConfigBase (sectionName, this);
this.Configs.Add (config);
}
RemoveConfigKeys (config);
}
}
}
/// <summary>
/// Removes all configs that are not in the newly loaded XmlDocument.
/// </summary>
private void RemoveConfigs ()
{
IConfig config = null;
for (int i = this.Configs.Count - 1; i > -1; i--)
{
config = this.Configs[i];
// If the section is not present in the XmlDocument
if (GetSectionByName (config.Name) == null) {
this.Configs.Remove (config);
}
}
}
/// <summary>
/// Removes all XML keys that were removed as config keys.
/// </summary>
private void RemoveConfigKeys (IConfig config)
{
XmlNode section = GetSectionByName (config.Name);
// Remove old keys
string[] configKeys = config.GetKeys ();
foreach (string configKey in configKeys)
{
if (GetKeyByName (section, configKey) == null) {
// Key doesn't exist, remove
config.Remove (configKey);
}
}
// Add or set all new keys
foreach (XmlNode node in section.ChildNodes)
{
// Loop through all key nodes and add to config
if (node.NodeType == XmlNodeType.Element
&& node.Name == "Key") {
config.Set (node.Attributes["Name"].Value,
node.Attributes["Value"].Value);
}
}
}
#endregion
}
}

View File

@ -0,0 +1,302 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.IO;
using System.Collections;
using Nini.Util;
namespace Nini.Ini
{
#region IniFileType enumeration
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/docs/*' />
public enum IniFileType
{
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="Standard"]/docs/*' />
Standard,
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="PythonStyle"]/docs/*' />
PythonStyle,
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="SambaStyle"]/docs/*' />
SambaStyle,
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="MysqlStyle"]/docs/*' />
MysqlStyle,
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="WindowsStyle"]/docs/*' />
WindowsStyle
}
#endregion
/// <include file='IniDocument.xml' path='//Class[@name="IniDocument"]/docs/*' />
public class IniDocument
{
#region Private variables
IniSectionCollection sections = new IniSectionCollection ();
ArrayList initialComment = new ArrayList ();
IniFileType fileType = IniFileType.Standard;
#endregion
#region Public properties
/// <include file='IniDocument.xml' path='//Property[@name="FileType"]/docs/*' />
public IniFileType FileType
{
get { return fileType; }
set { fileType = value; }
}
#endregion
#region Constructors
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public IniDocument (string filePath)
{
fileType = IniFileType.Standard;
Load (filePath);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorPathType"]/docs/*' />
public IniDocument (string filePath, IniFileType type)
{
fileType = type;
Load (filePath);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorTextReader"]/docs/*' />
public IniDocument (TextReader reader)
{
fileType = IniFileType.Standard;
Load (reader);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorTextReaderType"]/docs/*' />
public IniDocument (TextReader reader, IniFileType type)
{
fileType = type;
Load (reader);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorStream"]/docs/*' />
public IniDocument (Stream stream)
{
fileType = IniFileType.Standard;
Load (stream);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorStreamType"]/docs/*' />
public IniDocument (Stream stream, IniFileType type)
{
fileType = type;
Load (stream);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorIniReader"]/docs/*' />
public IniDocument (IniReader reader)
{
fileType = IniFileType.Standard;
Load (reader);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniDocument ()
{
}
#endregion
#region Public methods
/// <include file='IniDocument.xml' path='//Method[@name="LoadPath"]/docs/*' />
public void Load (string filePath)
{
Load (new StreamReader (filePath));
}
/// <include file='IniDocument.xml' path='//Method[@name="LoadTextReader"]/docs/*' />
public void Load (TextReader reader)
{
Load (GetIniReader (reader, fileType));
}
/// <include file='IniDocument.xml' path='//Method[@name="LoadStream"]/docs/*' />
public void Load (Stream stream)
{
Load (new StreamReader (stream));
}
/// <include file='IniDocument.xml' path='//Method[@name="LoadIniReader"]/docs/*' />
public void Load (IniReader reader)
{
LoadReader (reader);
}
/// <include file='IniSection.xml' path='//Property[@name="Comment"]/docs/*' />
public IniSectionCollection Sections
{
get { return sections; }
}
/// <include file='IniDocument.xml' path='//Method[@name="SaveTextWriter"]/docs/*' />
public void Save (TextWriter textWriter)
{
IniWriter writer = GetIniWriter (textWriter, fileType);
IniItem item = null;
IniSection section = null;
foreach (string comment in initialComment)
{
writer.WriteEmpty (comment);
}
for (int j = 0; j < sections.Count; j++)
{
section = sections[j];
writer.WriteSection (section.Name, section.Comment);
for (int i = 0; i < section.ItemCount; i++)
{
item = section.GetItem (i);
switch (item.Type)
{
case IniType.Key:
writer.WriteKey (item.Name, item.Value, item.Comment);
break;
case IniType.Empty:
writer.WriteEmpty (item.Comment);
break;
}
}
}
writer.Close ();
}
/// <include file='IniDocument.xml' path='//Method[@name="SavePath"]/docs/*' />
public void Save (string filePath)
{
StreamWriter writer = new StreamWriter (filePath);
Save (writer);
writer.Close ();
}
/// <include file='IniDocument.xml' path='//Method[@name="SaveStream"]/docs/*' />
public void Save (Stream stream)
{
Save (new StreamWriter (stream));
}
#endregion
#region Private methods
/// <summary>
/// Loads the file not saving comments.
/// </summary>
private void LoadReader (IniReader reader)
{
reader.IgnoreComments = false;
bool sectionFound = false;
IniSection section = null;
try {
while (reader.Read ())
{
switch (reader.Type)
{
case IniType.Empty:
if (!sectionFound) {
initialComment.Add (reader.Comment);
} else {
section.Set (reader.Comment);
}
break;
case IniType.Section:
sectionFound = true;
// If section already exists then overwrite it
if (sections[reader.Name] != null) {
sections.Remove (reader.Name);
}
section = new IniSection (reader.Name, reader.Comment);
sections.Add (section);
break;
case IniType.Key:
if (section.GetValue (reader.Name) == null) {
section.Set (reader.Name, reader.Value, reader.Comment);
}
break;
}
}
} catch (Exception ex) {
throw ex;
} finally {
// Always close the file
reader.Close ();
}
}
/// <summary>
/// Returns a proper INI reader depending upon the type parameter.
/// </summary>
private IniReader GetIniReader (TextReader reader, IniFileType type)
{
IniReader result = new IniReader (reader);
switch (type)
{
case IniFileType.Standard:
// do nothing
break;
case IniFileType.PythonStyle:
result.AcceptCommentAfterKey = false;
result.SetCommentDelimiters (new char[] { ';', '#' });
result.SetAssignDelimiters (new char[] { ':' });
break;
case IniFileType.SambaStyle:
result.AcceptCommentAfterKey = false;
result.SetCommentDelimiters (new char[] { ';', '#' });
result.LineContinuation = true;
break;
case IniFileType.MysqlStyle:
result.AcceptCommentAfterKey = false;
result.AcceptNoAssignmentOperator = true;
result.SetCommentDelimiters (new char[] { '#' });
result.SetAssignDelimiters (new char[] { ':', '=' });
break;
case IniFileType.WindowsStyle:
result.ConsumeAllKeyText = true;
break;
}
return result;
}
/// <summary>
/// Returns a proper IniWriter depending upon the type parameter.
/// </summary>
private IniWriter GetIniWriter (TextWriter reader, IniFileType type)
{
IniWriter result = new IniWriter (reader);
switch (type)
{
case IniFileType.Standard:
case IniFileType.WindowsStyle:
// do nothing
break;
case IniFileType.PythonStyle:
result.AssignDelimiter = ':';
result.CommentDelimiter = '#';
break;
case IniFileType.SambaStyle:
case IniFileType.MysqlStyle:
result.AssignDelimiter = '=';
result.CommentDelimiter = '#';
break;
}
return result;
}
#endregion
}
}

View File

@ -0,0 +1,121 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.Security;
using System.Globalization;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace Nini.Ini
{
/// <include file='IniException.xml' path='//Class[@name="IniException"]/docs/*' />
#if (NET_COMPACT_1_0)
#else
[Serializable]
#endif
public class IniException : SystemException /*, ISerializable */
{
#region Private variables
IniReader iniReader = null;
string message = "";
#endregion
#region Public properties
/// <include file='IniException.xml' path='//Property[@name="LinePosition"]/docs/*' />
public int LinePosition
{
get {
return (iniReader == null) ? 0 : iniReader.LinePosition;
}
}
/// <include file='IniException.xml' path='//Property[@name="LineNumber"]/docs/*' />
public int LineNumber
{
get {
return (iniReader == null) ? 0 : iniReader.LineNumber;
}
}
/// <include file='IniException.xml' path='//Property[@name="Message"]/docs/*' />
public override string Message
{
get {
if (iniReader == null) {
return base.Message;
}
return String.Format (CultureInfo.InvariantCulture, "{0} - Line: {1}, Position: {2}.",
message, this.LineNumber, this.LinePosition);
}
}
#endregion
#region Constructors
/// <include file='IniException.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniException ()
: base ()
{
this.message = "An error has occurred";
}
/// <include file='IniException.xml' path='//Constructor[@name="ConstructorException"]/docs/*' />
public IniException (string message, Exception exception)
: base (message, exception)
{
}
/// <include file='IniException.xml' path='//Constructor[@name="ConstructorMessage"]/docs/*' />
public IniException (string message)
: base (message)
{
this.message = message;
}
/// <include file='IniException.xml' path='//Constructor[@name="ConstructorTextReader"]/docs/*' />
internal IniException (IniReader reader, string message)
: this (message)
{
iniReader = reader;
this.message = message;
}
#if (NET_COMPACT_1_0)
#else
/// <include file='IniException.xml' path='//Constructor[@name="ConstructorSerialize"]/docs/*' />
protected IniException (SerializationInfo info, StreamingContext context)
: base (info, context)
{
}
#endif
#endregion
#region Public methods
#if (NET_COMPACT_1_0)
#else
/// <include file='IniException.xml' path='//Method[@name="GetObjectData"]/docs/*' />
[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
public override void GetObjectData (SerializationInfo info,
StreamingContext context)
{
base.GetObjectData (info, context);
if (iniReader != null) {
info.AddValue ("lineNumber", iniReader.LineNumber);
info.AddValue ("linePosition", iniReader.LinePosition);
}
}
#endif
#endregion
}
}

View File

@ -0,0 +1,54 @@
using System;
namespace Nini.Ini
{
/// <include file='IniItem.xml' path='//Class[@name="IniItem"]/docs/*' />
public class IniItem
{
#region Private variables
IniType iniType = IniType.Empty;
string iniName = "";
string iniValue = "";
string iniComment = null;
#endregion
#region Public properties
/// <include file='IniItem.xml' path='//Property[@name="Type"]/docs/*' />
public IniType Type
{
get { return iniType; }
set { iniType = value; }
}
/// <include file='IniItem.xml' path='//Property[@name="Value"]/docs/*' />
public string Value
{
get { return iniValue; }
set { iniValue = value; }
}
/// <include file='IniItem.xml' path='//Property[@name="Name"]/docs/*' />
public string Name
{
get { return iniName; }
}
/// <include file='IniItem.xml' path='//Property[@name="Comment"]/docs/*' />
public string Comment
{
get { return iniComment; }
set { iniComment = value; }
}
#endregion
/// <include file='IniItem.xml' path='//Constructor[@name="Constructor"]/docs/*' />
internal protected IniItem (string name, string value, IniType type, string comment)
{
iniName = name;
iniValue = value;
iniType = type;
iniComment = comment;
}
}
}

View File

@ -0,0 +1,652 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.IO;
using System.Text;
using System.Collections;
namespace Nini.Ini
{
#region IniReadState enumeration
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/docs/*' />
public enum IniReadState : int
{
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="Closed"]/docs/*' />
Closed,
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="EndOfFile"]/docs/*' />
EndOfFile,
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="Error"]/docs/*' />
Error,
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="Initial"]/docs/*' />
Initial,
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="Interactive"]/docs/*' />
Interactive
};
#endregion
#region IniType enumeration
/// <include file='IniReader.xml' path='//Enum[@name="IniType"]/docs/*' />
public enum IniType : int
{
/// <include file='IniReader.xml' path='//Enum[@name="IniType"]/Value[@name="Section"]/docs/*' />
Section,
/// <include file='IniReader.xml' path='//Enum[@name="IniType"]/Value[@name="Key"]/docs/*' />
Key,
/// <include file='IniReader.xml' path='//Enum[@name="IniType"]/Value[@name="Empty"]/docs/*' />
Empty
}
#endregion
/// <include file='IniReader.xml' path='//Class[@name="IniReader"]/docs/*' />
public class IniReader : IDisposable
{
#region Private variables
int lineNumber = 1;
int column = 1;
IniType iniType = IniType.Empty;
TextReader textReader = null;
bool ignoreComments = false;
StringBuilder name = new StringBuilder ();
StringBuilder value = new StringBuilder ();
StringBuilder comment = new StringBuilder ();
IniReadState readState = IniReadState.Initial;
bool hasComment = false;
bool disposed = false;
bool lineContinuation = false;
bool acceptCommentAfterKey = true;
bool acceptNoAssignmentOperator = false;
bool consumeAllKeyText = false;
char[] commentDelimiters = new char[] { ';' };
char[] assignDelimiters = new char[] { '=' };
#endregion
#region Public properties
/// <include file='IniReader.xml' path='//Property[@name="Name"]/docs/*' />
public string Name
{
get { return this.name.ToString (); }
}
/// <include file='IniReader.xml' path='//Property[@name="Value"]/docs/*' />
public string Value
{
get { return this.value.ToString (); }
}
/// <include file='IniReader.xml' path='//Property[@name="Type"]/docs/*' />
public IniType Type
{
get { return iniType; }
}
/// <include file='IniReader.xml' path='//Property[@name="Comment"]/docs/*' />
public string Comment
{
get { return (hasComment) ? this.comment.ToString () : null; }
}
/// <include file='IniReader.xml' path='//Property[@name="LineNumber"]/docs/*' />
public int LineNumber
{
get { return lineNumber; }
}
/// <include file='IniReader.xml' path='//Property[@name="LinePosition"]/docs/*' />
public int LinePosition
{
get { return column; }
}
/// <include file='IniReader.xml' path='//Property[@name="IgnoreComments"]/docs/*' />
public bool IgnoreComments
{
get { return ignoreComments; }
set { ignoreComments = value; }
}
/// <include file='IniReader.xml' path='//Property[@name="ReadState"]/docs/*' />
public IniReadState ReadState
{
get { return readState; }
}
/// <include file='IniReader.xml' path='//Property[@name="LineContinuation"]/docs/*' />
public bool LineContinuation
{
get { return lineContinuation; }
set { lineContinuation = value; }
}
/// <include file='IniReader.xml' path='//Property[@name="AcceptCommentAfterKey"]/docs/*' />
public bool AcceptCommentAfterKey
{
get { return acceptCommentAfterKey; }
set { acceptCommentAfterKey = value; }
}
/// <include file='IniReader.xml' path='//Property[@name="AcceptNoAssignmentOperator"]/docs/*' />
public bool AcceptNoAssignmentOperator
{
get { return acceptNoAssignmentOperator; }
set { acceptNoAssignmentOperator = value; }
}
/// <include file='IniReader.xml' path='//Property[@name="ConsumeAllKeyText"]/docs/*' />
public bool ConsumeAllKeyText
{
get { return consumeAllKeyText; }
set { consumeAllKeyText = value; }
}
#endregion
#region Constructors
/// <include file='IniReader.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public IniReader (string filePath)
{
textReader = new StreamReader (filePath);
}
/// <include file='IniReader.xml' path='//Constructor[@name="ConstructorTextReader"]/docs/*' />
public IniReader (TextReader reader)
{
textReader = reader;
}
/// <include file='IniReader.xml' path='//Constructor[@name="ConstructorStream"]/docs/*' />
public IniReader (Stream stream)
: this (new StreamReader (stream))
{
}
#endregion
#region Public methods
/// <include file='IniReader.xml' path='//Method[@name="Read"]/docs/*' />
public bool Read ()
{
bool result = false;
if (readState != IniReadState.EndOfFile
|| readState != IniReadState.Closed) {
readState = IniReadState.Interactive;
result = ReadNext ();
}
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="MoveToNextSection"]/docs/*' />
public bool MoveToNextSection ()
{
bool result = false;
while (true)
{
result = Read ();
if (iniType == IniType.Section || !result) {
break;
}
}
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="MoveToNextKey"]/docs/*' />
public bool MoveToNextKey ()
{
bool result = false;
while (true)
{
result = Read ();
if (iniType == IniType.Section) {
result = false;
break;
}
if (iniType == IniType.Key || !result) {
break;
}
}
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="Close"]/docs/*' />
public void Close ()
{
Reset ();
readState = IniReadState.Closed;
if (textReader != null) {
textReader.Close ();
}
}
/// <include file='IniReader.xml' path='//Method[@name="Dispose"]/docs/*' />
public void Dispose ()
{
Dispose (true);
}
/// <include file='IniReader.xml' path='//Method[@name="GetCommentDelimiters"]/docs/*' />
public char[] GetCommentDelimiters ()
{
char[] result = new char[commentDelimiters.Length];
Array.Copy (commentDelimiters, 0, result, 0, commentDelimiters.Length);
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="SetCommentDelimiters"]/docs/*' />
public void SetCommentDelimiters (char[] delimiters)
{
if (delimiters.Length < 1) {
throw new ArgumentException ("Must supply at least one delimiter");
}
commentDelimiters = delimiters;
}
/// <include file='IniReader.xml' path='//Method[@name="GetAssignDelimiters"]/docs/*' />
public char[] GetAssignDelimiters ()
{
char[] result = new char[assignDelimiters.Length];
Array.Copy (assignDelimiters, 0, result, 0, assignDelimiters.Length);
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="SetAssignDelimiters"]/docs/*' />
public void SetAssignDelimiters (char[] delimiters)
{
if (delimiters.Length < 1) {
throw new ArgumentException ("Must supply at least one delimiter");
}
assignDelimiters = delimiters;
}
#endregion
#region Protected methods
/// <include file='IniReader.xml' path='//Method[@name="DisposeBoolean"]/docs/*' />
protected virtual void Dispose (bool disposing)
{
if (!disposed) {
textReader.Close ();
disposed = true;
if (disposing) {
GC.SuppressFinalize (this);
}
}
}
#endregion
#region Private methods
/// <summary>
/// Destructor.
/// </summary>
~IniReader ()
{
Dispose (false);
}
/// <summary>
/// Resets all of the current INI line data.
/// </summary>
private void Reset ()
{
this.name.Remove (0, this.name.Length);
this.value.Remove (0, this.value.Length);
this.comment.Remove (0, this.comment.Length);
iniType = IniType.Empty;
hasComment = false;
}
/// <summary>
/// Reads the next INI line item.
/// </summary>
private bool ReadNext ()
{
bool result = true;
int ch = PeekChar ();
Reset ();
if (IsComment (ch)) {
iniType = IniType.Empty;
ReadChar (); // consume comment character
ReadComment ();
return result;
}
switch (ch)
{
case ' ':
case '\t':
case '\r':
SkipWhitespace ();
ReadNext ();
break;
case '\n':
ReadChar ();
break;
case '[':
ReadSection ();
break;
case -1:
readState = IniReadState.EndOfFile;
result = false;
break;
default:
ReadKey ();
break;
}
return result;
}
/// <summary>
/// Reads a comment. Must start after the comment delimiter.
/// </summary>
private void ReadComment ()
{
int ch = -1;
SkipWhitespace ();
hasComment = true;
do
{
ch = ReadChar ();
this.comment.Append ((char)ch);
} while (!EndOfLine (ch));
RemoveTrailingWhitespace (this.comment);
}
/// <summary>
/// Removes trailing whitespace from a StringBuilder.
/// </summary>
private void RemoveTrailingWhitespace (StringBuilder builder)
{
string temp = builder.ToString ();
builder.Remove (0, builder.Length);
builder.Append (temp.TrimEnd (null));
}
/// <summary>
/// Reads a key.
/// </summary>
private void ReadKey ()
{
int ch = -1;
iniType = IniType.Key;
while (true)
{
ch = PeekChar ();
if (IsAssign (ch)) {
ReadChar ();
break;
}
if (EndOfLine (ch)) {
if (acceptNoAssignmentOperator) {
break;
}
throw new IniException (this,
String.Format ("Expected assignment operator ({0})",
assignDelimiters[0]));
}
this.name.Append ((char)ReadChar ());
}
ReadKeyValue ();
SearchForComment ();
RemoveTrailingWhitespace (this.name);
}
/// <summary>
/// Reads the value of a key.
/// </summary>
private void ReadKeyValue ()
{
int ch = -1;
bool foundQuote = false;
int characters = 0;
SkipWhitespace ();
while (true)
{
ch = PeekChar ();
if (!IsWhitespace (ch)) {
characters++;
}
if (!this.ConsumeAllKeyText && ch == '"') {
ReadChar ();
if (!foundQuote && characters == 1) {
foundQuote = true;
continue;
} else {
break;
}
}
if (foundQuote && EndOfLine (ch)) {
throw new IniException (this, "Expected closing quote (\")");
}
// Handle line continuation
if (lineContinuation && ch == '\\')
{
StringBuilder buffer = new StringBuilder ();
buffer.Append ((char)ReadChar ()); // append '\'
while (PeekChar () != '\n' && IsWhitespace (PeekChar ()))
{
if (PeekChar () != '\r') {
buffer.Append ((char)ReadChar ());
} else {
ReadChar (); // consume '\r'
}
}
if (PeekChar () == '\n') {
// continue reading key value on next line
ReadChar ();
continue;
} else {
// Replace consumed characters
this.value.Append (buffer.ToString ());
}
}
if (!this.ConsumeAllKeyText) {
// If accepting comments then don't consume as key value
if (acceptCommentAfterKey && IsComment (ch) && !foundQuote) {
break;
}
}
// Always break at end of line
if (EndOfLine (ch)) {
break;
}
this.value.Append ((char)ReadChar ());
}
if (!foundQuote) {
RemoveTrailingWhitespace (this.value);
}
}
/// <summary>
/// Reads an INI section.
/// </summary>
private void ReadSection ()
{
int ch = -1;
iniType = IniType.Section;
ch = ReadChar (); // consume "["
while (true)
{
ch = PeekChar ();
if (ch == ']') {
break;
}
if (EndOfLine (ch)) {
throw new IniException (this, "Expected section end (])");
}
this.name.Append ((char)ReadChar ());
}
ConsumeToEnd (); // all after '[' is garbage
RemoveTrailingWhitespace (this.name);
}
/// <summary>
/// Looks for a comment.
/// </summary>
private void SearchForComment ()
{
int ch = ReadChar ();
while (!EndOfLine (ch))
{
if (IsComment (ch)) {
if (ignoreComments) {
ConsumeToEnd ();
} else {
ReadComment ();
}
break;
}
ch = ReadChar ();
}
}
/// <summary>
/// Consumes all data until the end of a line.
/// </summary>
private void ConsumeToEnd ()
{
int ch = -1;
do
{
ch = ReadChar ();
} while (!EndOfLine (ch));
}
/// <summary>
/// Returns and consumes the next character from the stream.
/// </summary>
private int ReadChar ()
{
int result = textReader.Read ();
if (result == '\n') {
lineNumber++;
column = 1;
} else {
column++;
}
return result;
}
/// <summary>
/// Returns the next upcoming character from the stream.
/// </summary>
private int PeekChar ()
{
return textReader.Peek ();
}
/// <summary>
/// Returns true if a comment character is found.
/// </summary>
private bool IsComment (int ch)
{
return HasCharacter (commentDelimiters, ch);
}
/// <summary>
/// Returns true if character is an assign character.
/// </summary>
private bool IsAssign (int ch)
{
return HasCharacter (assignDelimiters, ch);
}
/// <summary>
/// Returns true if the character is found in the given array.
/// </summary>
private bool HasCharacter (char[] characters, int ch)
{
bool result = false;
for (int i = 0; i < characters.Length; i++)
{
if (ch == characters[i])
{
result = true;
break;
}
}
return result;
}
/// <summary>
/// Returns true if a value is whitespace.
/// </summary>
private bool IsWhitespace (int ch)
{
return ch == 0x20 || ch == 0x9 || ch == 0xD || ch == 0xA;
}
/// <summary>
/// Skips all whitespace.
/// </summary>
private void SkipWhitespace ()
{
while (IsWhitespace (PeekChar ()))
{
if (EndOfLine (PeekChar ())) {
break;
}
ReadChar ();
}
}
/// <summary>
/// Returns true if an end of line is found. End of line
/// includes both an end of line or end of file.
/// </summary>
private bool EndOfLine (int ch)
{
return (ch == '\n' || ch == -1);
}
#endregion
}
}

View File

@ -0,0 +1,155 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.Collections;
using Nini.Util;
namespace Nini.Ini
{
/// <include file='IniSection.xml' path='//Class[@name="IniSection"]/docs/*' />
public class IniSection
{
#region Private variables
OrderedList configList = new OrderedList ();
string name = "";
string comment = null;
int commentCount = 0;
#endregion
#region Constructors
/// <include file='IniSection.xml' path='//Constructor[@name="ConstructorComment"]/docs/*' />
public IniSection (string name, string comment)
{
this.name = name;
this.comment = comment;
}
/// <include file='IniSection.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniSection (string name)
: this (name, null)
{
}
#endregion
#region Public properties
/// <include file='IniSection.xml' path='//Property[@name="Name"]/docs/*' />
public string Name
{
get { return name; }
}
/// <include file='IniSection.xml' path='//Property[@name="Comment"]/docs/*' />
public string Comment
{
get { return comment; }
}
/// <include file='IniSection.xml' path='//Property[@name="ItemCount"]/docs/*' />
public int ItemCount
{
get { return configList.Count; }
}
#endregion
#region Public methods
/// <include file='IniSection.xml' path='//Method[@name="GetValue"]/docs/*' />
public string GetValue (string key)
{
string result = null;
if (Contains (key)) {
IniItem item = (IniItem)configList[key];
result = item.Value;
}
return result;
}
/// <include file='IniSection.xml' path='//Method[@name="GetItem"]/docs/*' />
public IniItem GetItem (int index)
{
return (IniItem)configList[index];
}
/// <include file='IniSection.xml' path='//Method[@name="GetKeys"]/docs/*' />
public string[] GetKeys ()
{
ArrayList list = new ArrayList ();
IniItem item = null;
for (int i = 0; i < configList.Count; i++)
{
item = (IniItem)configList[i];
if (item.Type == IniType.Key) {
list.Add (item.Name);
}
}
string[] result = new string[list.Count];
list.CopyTo (result, 0);
return result;
}
/// <include file='IniSection.xml' path='//Method[@name="Contains"]/docs/*' />
public bool Contains (string key)
{
return (configList[key] != null);
}
/// <include file='IniSection.xml' path='//Method[@name="SetKeyComment"]/docs/*' />
public void Set (string key, string value, string comment)
{
IniItem item = null;
if (Contains (key)) {
item = (IniItem)configList[key];
item.Value = value;
item.Comment = comment;
} else {
item = new IniItem (key, value, IniType.Key, comment);
configList.Add (key, item);
}
}
/// <include file='IniSection.xml' path='//Method[@name="SetKey"]/docs/*' />
public void Set (string key, string value)
{
Set (key, value, null);
}
/// <include file='IniSection.xml' path='//Method[@name="SetComment"]/docs/*' />
public void Set (string comment)
{
string name = "#comment" + commentCount;
IniItem item = new IniItem (name, null,
IniType.Empty, comment);
configList.Add (name, item);
commentCount++;
}
/// <include file='IniSection.xml' path='//Method[@name="SetNoComment"]/docs/*' />
public void Set ()
{
Set (null);
}
/// <include file='IniSection.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (string key)
{
if (Contains (key)) {
configList.Remove (key);
}
}
#endregion
}
}

View File

@ -0,0 +1,95 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.Collections;
using Nini.Util;
namespace Nini.Ini
{
/// <include file='IniSectionCollection.xml' path='//Class[@name="IniSectionCollection"]/docs/*' />
public class IniSectionCollection : ICollection, IEnumerable
{
#region Private variables
OrderedList list = new OrderedList ();
#endregion
#region Public properties
/// <include file='IniSectionCollection.xml' path='//Property[@name="ItemIndex"]/docs/*' />
public IniSection this[int index]
{
get { return (IniSection)list[index]; }
}
/// <include file='IniSectionCollection.xml' path='//Property[@name="ItemName"]/docs/*' />
public IniSection this[string configName]
{
get { return (IniSection)list[configName]; }
}
/// <include file='IniSectionCollection.xml' path='//Property[@name="Count"]/docs/*' />
public int Count
{
get { return list.Count; }
}
/// <include file='IniSectionCollection.xml' path='//Property[@name="SyncRoot"]/docs/*' />
public object SyncRoot
{
get { return list.SyncRoot; }
}
/// <include file='IniSectionCollection.xml' path='//Property[@name="IsSynchronized"]/docs/*' />
public bool IsSynchronized
{
get { return list.IsSynchronized; }
}
#endregion
#region Public methods
/// <include file='IniSectionCollection.xml' path='//Method[@name="Add"]/docs/*' />
public void Add (IniSection section)
{
if (list.Contains (section)) {
throw new ArgumentException ("IniSection already exists");
}
list.Add (section.Name, section);
}
/// <include file='IniSectionCollection.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (string config)
{
list.Remove (config);
}
/// <include file='IniSectionCollection.xml' path='//Method[@name="CopyTo"]/docs/*' />
public void CopyTo (Array array, int index)
{
list.CopyTo (array, index);
}
/// <include file='IniSectionCollection.xml' path='//Method[@name="CopyToStrong"]/docs/*' />
public void CopyTo (IniSection[] array, int index)
{
((ICollection)list).CopyTo (array, index);
}
/// <include file='IniSectionCollection.xml' path='//Method[@name="GetEnumerator"]/docs/*' />
public IEnumerator GetEnumerator ()
{
return list.GetEnumerator ();
}
#endregion
#region Private methods
#endregion
}
}

View File

@ -0,0 +1,308 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
#endregion
using System;
using System.IO;
using System.Text;
namespace Nini.Ini
{
#region IniWriteState enumeration
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/docs/*' />
public enum IniWriteState : int
{
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/Value[@name="Start"]/docs/*' />
Start,
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/Value[@name="BeforeFirstSection"]/docs/*' />
BeforeFirstSection,
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/Value[@name="Section"]/docs/*' />
Section,
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/Value[@name="Closed"]/docs/*' />
Closed
};
#endregion
/// <include file='IniWriter.xml' path='//Class[@name="IniWriter"]/docs/*' />
public class IniWriter : IDisposable
{
#region Private variables
int indentation = 0;
bool useValueQuotes = false;
IniWriteState writeState = IniWriteState.Start;
char commentDelimiter = ';';
char assignDelimiter = '=';
TextWriter textWriter = null;
string eol = "\r\n";
StringBuilder indentationBuffer = new StringBuilder ();
Stream baseStream = null;
bool disposed = false;
#endregion
#region Public properties
/// <include file='IniWriter.xml' path='//Property[@name="Indentation"]/docs/*' />
public int Indentation
{
get { return indentation; }
set
{
if (value < 0)
throw new ArgumentException ("Negative values are illegal");
indentation = value;
indentationBuffer.Remove(0, indentationBuffer.Length);
for (int i = 0; i < value; i++)
indentationBuffer.Append (' ');
}
}
/// <include file='IniWriter.xml' path='//Property[@name="UseValueQuotes"]/docs/*' />
public bool UseValueQuotes
{
get { return useValueQuotes; }
set { useValueQuotes = value; }
}
/// <include file='IniWriter.xml' path='//Property[@name="WriteState"]/docs/*' />
public IniWriteState WriteState
{
get { return writeState; }
}
/// <include file='IniWriter.xml' path='//Property[@name="CommentDelimiter"]/docs/*' />
public char CommentDelimiter
{
get { return commentDelimiter; }
set { commentDelimiter = value; }
}
/// <include file='IniWriter.xml' path='//Property[@name="AssignDelimiter"]/docs/*' />
public char AssignDelimiter
{
get { return assignDelimiter; }
set { assignDelimiter = value; }
}
/// <include file='IniWriter.xml' path='//Property[@name="BaseStream"]/docs/*' />
public Stream BaseStream
{
get { return baseStream; }
}
#endregion
#region Constructors
/// <include file='IniWriter.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public IniWriter(string filePath)
: this (new FileStream (filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
}
/// <include file='IniWriter.xml' path='//Constructor[@name="ConstructorTextWriter"]/docs/*' />
public IniWriter (TextWriter writer)
{
textWriter = writer;
StreamWriter streamWriter = writer as StreamWriter;
if (streamWriter != null) {
baseStream = streamWriter.BaseStream;
}
}
/// <include file='IniWriter.xml' path='//Constructor[@name="ConstructorStream"]/docs/*' />
public IniWriter (Stream stream)
: this (new StreamWriter (stream))
{
}
#endregion
#region Public methods
/// <include file='IniWriter.xml' path='//Method[@name="Close"]/docs/*' />
public void Close ()
{
textWriter.Close ();
writeState = IniWriteState.Closed;
}
/// <include file='IniWriter.xml' path='//Method[@name="Flush"]/docs/*' />
public void Flush ()
{
textWriter.Flush ();
}
/// <include file='IniWriter.xml' path='//Method[@name="ToString"]/docs/*' />
public override string ToString ()
{
return textWriter.ToString ();
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteSection"]/docs/*' />
public void WriteSection (string section)
{
ValidateState ();
writeState = IniWriteState.Section;
WriteLine ("[" + section + "]");
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteSectionComment"]/docs/*' />
public void WriteSection (string section, string comment)
{
ValidateState ();
writeState = IniWriteState.Section;
WriteLine ("[" + section + "]" + Comment(comment));
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteKey"]/docs/*' />
public void WriteKey (string key, string value)
{
ValidateStateKey ();
WriteLine (key + " " + assignDelimiter + " " + GetKeyValue (value));
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteKeyComment"]/docs/*' />
public void WriteKey (string key, string value, string comment)
{
ValidateStateKey ();
WriteLine (key + " " + assignDelimiter + " " + GetKeyValue (value) + Comment (comment));
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteEmpty"]/docs/*' />
public void WriteEmpty ()
{
ValidateState ();
if (writeState == IniWriteState.Start) {
writeState = IniWriteState.BeforeFirstSection;
}
WriteLine ("");
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteEmptyComment"]/docs/*' />
public void WriteEmpty (string comment)
{
ValidateState ();
if (writeState == IniWriteState.Start) {
writeState = IniWriteState.BeforeFirstSection;
}
if (comment == null) {
WriteLine ("");
} else {
WriteLine (commentDelimiter + " " + comment);
}
}
/// <include file='IniWriter.xml' path='//Method[@name="Dispose"]/docs/*' />
public void Dispose ()
{
Dispose (true);
}
#endregion
#region Protected methods
/// <include file='IniWriter.xml' path='//Method[@name="DisposeBoolean"]/docs/*' />
protected virtual void Dispose (bool disposing)
{
if (!disposed)
{
textWriter.Close ();
baseStream.Close ();
disposed = true;
if (disposing)
{
GC.SuppressFinalize (this);
}
}
}
#endregion
#region Private methods
/// <summary>
/// Destructor.
/// </summary>
~IniWriter ()
{
Dispose (false);
}
/// <summary>
/// Returns the value of a key.
/// </summary>
private string GetKeyValue (string text)
{
string result;
if (useValueQuotes) {
result = MassageValue ('"' + text + '"');
} else {
result = MassageValue (text);
}
return result;
}
/// <summary>
/// Validates whether a key can be written.
/// </summary>
private void ValidateStateKey ()
{
ValidateState ();
switch (writeState)
{
case IniWriteState.BeforeFirstSection:
case IniWriteState.Start:
throw new InvalidOperationException ("The WriteState is not Section");
case IniWriteState.Closed:
throw new InvalidOperationException ("The writer is closed");
}
}
/// <summary>
/// Validates the state to determine if the item can be written.
/// </summary>
private void ValidateState ()
{
if (writeState == IniWriteState.Closed) {
throw new InvalidOperationException ("The writer is closed");
}
}
/// <summary>
/// Returns a formatted comment.
/// </summary>
private string Comment (string text)
{
return (text == null) ? "" : (" " + commentDelimiter + " " + text);
}
/// <summary>
/// Writes data to the writer.
/// </summary>
private void Write (string value)
{
textWriter.Write (indentationBuffer.ToString () + value);
}
/// <summary>
/// Writes a full line to the writer.
/// </summary>
private void WriteLine (string value)
{
Write (value + eol);
}
/// <summary>
/// Fixes the incoming value to prevent illegal characters from
/// hurting the integrity of the INI file.
/// </summary>
private string MassageValue (string text)
{
return text.Replace ("\n", "");
}
#endregion
}
}

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{CB5C2235-43B2-4B37-B866-D5D33F0E68B0}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>Nini</RootNamespace>
<AssemblyName>Nini</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.XML" />
</ItemGroup>
<ItemGroup>
<Compile Include="Config\AliasText.cs" />
<Compile Include="Config\ArgvConfigSource.cs" />
<Compile Include="Config\ConfigBase.cs" />
<Compile Include="Config\ConfigCollection.cs" />
<Compile Include="Config\ConfigSourceBase.cs" />
<Compile Include="Config\DotNetConfigSource.cs" />
<Compile Include="Config\IConfig.cs" />
<Compile Include="Config\IConfigSource.cs" />
<Compile Include="Config\IniConfig.cs" />
<Compile Include="Config\IniConfigSource.cs" />
<Compile Include="Config\RegistryConfigSource.cs" />
<Compile Include="Config\XmlConfigSource.cs" />
<Compile Include="Ini\IniDocument.cs" />
<Compile Include="Ini\IniException.cs" />
<Compile Include="Ini\IniItem.cs" />
<Compile Include="Ini\IniReader.cs" />
<Compile Include="Ini\IniSection.cs" />
<Compile Include="Ini\IniSectionCollection.cs" />
<Compile Include="Ini\IniWriter.cs" />
<Compile Include="Util\ArgvParser.cs" />
<Compile Include="Util\OrderedList.cs" />
<Compile Include="Util\OrderedListEnumerator.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,97 @@
#region Copyright
//
// Nini Configuration Project.
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
//
// This software is published under the terms of the MIT X11 license, a copy of
// which has been included with this distribution in the LICENSE.txt file.
//
// Original code written by: R. LOPES (GriffonRL)
// Article: http://thecodeproject.com/csharp/command_line.asp
#endregion
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
namespace Nini.Util
{
/// <include file='ArgvParser.xml' path='//Class[@name="ArgvParser"]/docs/*' />
public class ArgvParser
{
#region Private variables
StringDictionary parameters;
#endregion
#region Constructors
/// <include file='ArgvParser.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public ArgvParser(string args)
{
Regex Extractor = new Regex(@"(['""][^""]+['""])\s*|([^\s]+)\s*",
RegexOptions.Compiled);
MatchCollection matches;
string[] parts;
// Get matches (first string ignored because
// Environment.CommandLine starts with program filename)
matches = Extractor.Matches (args);
parts = new string[matches.Count - 1];
for (int i = 1; i < matches.Count; i++)
{
parts[i-1] = matches[i].Value.Trim ();
}
}
/// <include file='ArgvParser.xml' path='//Constructor[@name="ConstructorArray"]/docs/*' />
public ArgvParser (string[] args)
{
Extract (args);
}
#endregion
#region Public properties
/// <include file='ArgvParser.xml' path='//Property[@name="this"]/docs/*' />
public string this [string param]
{
get {
return parameters[param];
}
}
#endregion
#region Private methods
// Extract command line parameters and values stored in a string array
private void Extract(string[] args)
{
parameters = new StringDictionary();
Regex splitter = new Regex (@"^([/-]|--){1}(?<name>\w+)([:=])?(?<value>.+)?$",
RegexOptions.Compiled);
char[] trimChars = {'"','\''};
string parameter = null;
Match part;
// Valid parameters forms: {-,/,--}param{ , = ,:}((",')value(",'))
// Examples: -param1 value1 --param2 /param3:"Test-:-work"
// /param4 = happy -param5 '-- = nice = --'
foreach(string arg in args)
{
part = splitter.Match(arg);
if (!part.Success) {
// Found a value (for the last parameter found (space separator))
if (parameter != null) {
parameters[parameter] = arg.Trim (trimChars);
}
} else {
// Matched a name, optionally with inline value
parameter = part.Groups["name"].Value;
parameters.Add (parameter,
part.Groups["value"].Value.Trim (trimChars));
}
}
}
#endregion
}
}

View File

@ -0,0 +1,199 @@
using System;
using System.Collections;
namespace Nini.Util
{
//[Serializable]
/// <include file='OrderedList.xml' path='//Class[@name="OrderedList"]/docs/*' />
public class OrderedList : ICollection, IDictionary, IEnumerable
{
#region Private variables
Hashtable table = new Hashtable ();
ArrayList list = new ArrayList ();
#endregion
#region Public properties
/// <include file='OrderedList.xml' path='//Property[@name="Count"]/docs/*' />
public int Count
{
get { return list.Count; }
}
/// <include file='OrderedList.xml' path='//Property[@name="IsFixedSize"]/docs/*' />
public bool IsFixedSize
{
get { return false; }
}
/// <include file='OrderedList.xml' path='//Property[@name="IsReadOnly"]/docs/*' />
public bool IsReadOnly
{
get { return false; }
}
/// <include file='OrderedList.xml' path='//Property[@name="IsSynchronized"]/docs/*' />
public bool IsSynchronized
{
get { return false; }
}
/// <include file='OrderedList.xml' path='//Property[@name="ItemIndex"]/docs/*' />
public object this[int index]
{
get { return ((DictionaryEntry) list[index]).Value; }
set
{
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException ("index");
object key = ((DictionaryEntry) list[index]).Key;
list[index] = new DictionaryEntry (key, value);
table[key] = value;
}
}
/// <include file='OrderedList.xml' path='//Property[@name="ItemKey"]/docs/*' />
public object this[object key]
{
get { return table[key]; }
set
{
if (table.Contains (key))
{
table[key] = value;
table[IndexOf (key)] = new DictionaryEntry (key, value);
return;
}
Add (key, value);
}
}
/// <include file='OrderedList.xml' path='//Property[@name="Keys"]/docs/*' />
public ICollection Keys
{
get
{
ArrayList retList = new ArrayList ();
for (int i = 0; i < list.Count; i++)
{
retList.Add ( ((DictionaryEntry)list[i]).Key );
}
return retList;
}
}
/// <include file='OrderedList.xml' path='//Property[@name="Values"]/docs/*' />
public ICollection Values
{
get
{
ArrayList retList = new ArrayList ();
for (int i = 0; i < list.Count; i++)
{
retList.Add ( ((DictionaryEntry)list[i]).Value );
}
return retList;
}
}
/// <include file='OrderedList.xml' path='//Property[@name="SyncRoot"]/docs/*' />
public object SyncRoot
{
get { return this; }
}
#endregion
#region Public methods
/// <include file='OrderedList.xml' path='//Method[@name="Add"]/docs/*' />
public void Add (object key, object value)
{
table.Add (key, value);
list.Add (new DictionaryEntry (key, value));
}
/// <include file='OrderedList.xml' path='//Method[@name="Clear"]/docs/*' />
public void Clear ()
{
table.Clear ();
list.Clear ();
}
/// <include file='OrderedList.xml' path='//Method[@name="Contains"]/docs/*' />
public bool Contains (object key)
{
return table.Contains (key);
}
/// <include file='OrderedList.xml' path='//Method[@name="CopyTo"]/docs/*' />
public void CopyTo (Array array, int index)
{
table.CopyTo (array, index);
}
/// <include file='OrderedList.xml' path='//Method[@name="CopyToStrong"]/docs/*' />
public void CopyTo (DictionaryEntry[] array, int index)
{
table.CopyTo (array, index);
}
/// <include file='OrderedList.xml' path='//Method[@name="Insert"]/docs/*' />
public void Insert (int index, object key, object value)
{
if (index > Count)
throw new ArgumentOutOfRangeException ("index");
table.Add (key, value);
list.Insert (index, new DictionaryEntry (key, value));
}
/// <include file='OrderedList.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (object key)
{
table.Remove (key);
list.RemoveAt (IndexOf (key));
}
/// <include file='OrderedList.xml' path='//Method[@name="RemoveAt"]/docs/*' />
public void RemoveAt (int index)
{
if (index >= Count)
throw new ArgumentOutOfRangeException ("index");
table.Remove ( ((DictionaryEntry)list[index]).Key );
list.RemoveAt (index);
}
/// <include file='OrderedList.xml' path='//Method[@name="GetEnumerator"]/docs/*' />
public IEnumerator GetEnumerator ()
{
return new OrderedListEnumerator (list);
}
/// <include file='OrderedList.xml' path='//Method[@name="GetDictionaryEnumerator"]/docs/*' />
IDictionaryEnumerator IDictionary.GetEnumerator ()
{
return new OrderedListEnumerator (list);
}
/// <include file='OrderedList.xml' path='//Method[@name="GetIEnumerator"]/docs/*' />
IEnumerator IEnumerable.GetEnumerator ()
{
return new OrderedListEnumerator (list);
}
#endregion
#region Private variables
private int IndexOf (object key)
{
for (int i = 0; i < list.Count; i++)
{
if (((DictionaryEntry) list[i]).Key.Equals (key))
{
return i;
}
}
return -1;
}
#endregion
}
}

View File

@ -0,0 +1,86 @@
using System;
using System.Collections;
namespace Nini.Util
{
/// <include file='OrderedListEnumerator.xml' path='//Class[@name="OrderedListEnumerator"]/docs/*' />
public class OrderedListEnumerator : IDictionaryEnumerator
{
#region Private variables
int index = -1;
ArrayList list;
#endregion
#region Constructors
/// <summary>
/// Instantiates an ordered list enumerator with an ArrayList.
/// </summary>
internal OrderedListEnumerator (ArrayList arrayList)
{
list = arrayList;
}
#endregion
#region Public properties
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="Current"]/docs/*' />
object IEnumerator.Current
{
get
{
if (index < 0 || index >= list.Count)
throw new InvalidOperationException ();
return list[index];
}
}
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="CurrentStrong"]/docs/*' />
public DictionaryEntry Current
{
get
{
if (index < 0 || index >= list.Count)
throw new InvalidOperationException ();
return (DictionaryEntry)list[index];
}
}
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="Entry"]/docs/*' />
public DictionaryEntry Entry
{
get { return (DictionaryEntry) Current; }
}
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="Key"]/docs/*' />
public object Key
{
get { return Entry.Key; }
}
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="Value"]/docs/*' />
public object Value
{
get { return Entry.Value; }
}
#endregion
#region Public methods
/// <include file='OrderedListEnumerator.xml' path='//Method[@name="MoveNext"]/docs/*' />
public bool MoveNext ()
{
index++;
if (index >= list.Count)
return false;
return true;
}
/// <include file='OrderedListEnumerator.xml' path='//Method[@name="Reset"]/docs/*' />
public void Reset ()
{
index = -1;
}
#endregion
}
}