Add plugin deinitialization, configuration saving
[WebThing.git] / Config.cs
1 using System;
2 using System.IO;
3 using System.Collections;
4 using System.Collections.Generic;
5 using System.Text.RegularExpressions;
6
7 namespace bytex64.WebThing {
8     public class Config {
9         public static List<string> ConfigPath;
10         public static string ConfigPathOut = null;
11
12         public static Dictionary<string,string> Options;
13         public static Dictionary<string,Dictionary<string,string>> PluginOptions;
14         public static string[] Arguments;
15         public static List<string> Plugins;
16
17         private static HashSet<string> CommandLineOptions;
18         private static Regex item_re = new Regex(@"^(?:([\w.]+)\.)?(\w+)$");
19         private static Regex file_var_re = new Regex(@"^([\w.]+)\s*=\s*(.*)$");
20         private static Regex file_command_re = new Regex(@"^([\w]+)\s*(.*)$");
21
22         static Config() {
23             Options = new Dictionary<string,string>();
24             PluginOptions = new Dictionary<string,Dictionary<string,string>>();
25             CommandLineOptions = new HashSet<string>();
26             Plugins = new List<string>();
27
28             // Set up ConfigPath
29             IDictionary Env = Environment.GetEnvironmentVariables();
30             ConfigPath = new List<string>();
31             ConfigPath.Add("/etc/WebThing");
32             if (Env.Contains("HOME")) {
33                 string homepath = Env["HOME"] + "/.config/WebThing";
34                 ConfigPath.Add(homepath);
35                 if (Directory.Exists(homepath))
36                     ConfigPathOut = homepath;
37             }
38             string LocalAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
39             if (LocalAppData != "") {
40                 string homepath = LocalAppData + "/WebThing";
41                 ConfigPath.Add(homepath);
42                 if (Directory.Exists(homepath))
43                     ConfigPathOut = homepath;
44             }
45         }
46
47         private static void ParseOption(string key, string val) {
48             Match m = item_re.Match(key);
49             string plugin = m.Groups[1].Value;
50             string name = m.Groups[2].Value;
51             if (plugin.Length > 0) {   // Plugin Option
52                 if (!PluginOptions.ContainsKey(plugin))
53                     PluginOptions[plugin] = new Dictionary<string,string>();
54                 PluginOptions[plugin][name] = val;
55             } else {                   // Global Option
56                 switch(key) {
57                 case "Plugin":
58                 case "plugin":
59                     Plugins.Add(val);
60                     break;
61                 default:
62                     Options[key] = val;
63                     break;
64                 }
65             }
66         }
67
68         public static void DumpOptions() {
69             Console.WriteLine("Options:");
70             foreach (string key in Options.Keys)
71                 Console.WriteLine("   {0}\t{1}", key, Options[key]);
72
73             Console.WriteLine("Plugin Options:");
74             foreach (string plugin in PluginOptions.Keys) {
75                 Console.WriteLine("    {0}", plugin);
76                 foreach (string key in PluginOptions[plugin].Keys)
77                     Console.WriteLine("        {0}\t{1}", key, PluginOptions[plugin][key]);
78             }
79
80             Console.WriteLine("Arguments: {0}", String.Join(" ", Arguments));
81         }
82
83         public static void ParseCommandLine() {
84             Queue<string> q = new Queue<string>();
85             foreach (string s in System.Environment.GetCommandLineArgs()) {
86                 q.Enqueue(s);
87             }
88             q.Dequeue();   // Remove self argument
89
90             Regex SimpleOpt = new Regex(@"^-([\w.]+)(?:[:=](.*))?$");
91             Regex LongOpt   = new Regex(@"^--([\w.]+)$");
92             List<string> args = new List<string>();
93
94             while (q.Count > 0) {
95                 string opt = q.Dequeue();
96                 Match m;
97                    
98                 m = SimpleOpt.Match(opt);
99                 if (m.Success) {
100                     string key = m.Groups[1].Value;
101                     string val = m.Groups[2].Value;
102                     if (val.Length > 0) {
103                         ParseOption(key, val);
104                     } else {
105                         ParseOption(key, null);
106                     }
107                     CommandLineOptions.Add(key);
108                     continue;
109                 }
110
111                 m = LongOpt.Match(opt);
112                 if (m.Success) {
113                     string key = m.Groups[1].Value;
114                     if (q.Count > 0) {
115                         string val = q.Peek();
116                         if (!(SimpleOpt.IsMatch(val) || LongOpt.IsMatch(val))) {
117                             q.Dequeue();
118                             ParseOption(key, val);
119                         } else {
120                             ParseOption(key, null);
121                         }
122                     } else {
123                         ParseOption(key, null);
124                     }
125                     CommandLineOptions.Add(key);
126                     continue;
127                 }
128
129                 // else
130
131                 args.Add(opt);
132             }
133             Arguments = args.ToArray();
134         }
135
136         public static void Load() {
137             foreach (string path in ConfigPath) {
138                 if (!Directory.Exists(path)) continue;
139                 string[] ConfigFiles = Directory.GetFiles(path, "*.conf");
140                 foreach (string file in ConfigFiles) {
141                     LoadFile(file);
142                 }
143             }
144             if (Options.ContainsKey("config"))
145                 LoadFile(Options["config"]);
146         }
147
148         public static void LoadFile(string filename) {
149             TextReader f;
150             try {
151                 f = new StreamReader(filename);
152             } catch (FileNotFoundException) {
153                 Console.WriteLine("Could not open configuration file {0}", filename);
154                 return;
155             }
156
157             string line;
158             while ((line = f.ReadLine()) != null) {
159                 Match m;
160
161                 line = line.Trim();
162                 m = file_var_re.Match(line);
163                 if (m.Success) {
164                     string key = m.Groups[1].Value;
165                     if (!CommandLineOptions.Contains(key))
166                         ParseOption(key, m.Groups[2].Value);
167                     continue;
168                 }
169
170                 m = file_command_re.Match(line);
171                 if (m.Success) {
172                     string cmd = m.Groups[1].Value;
173                     switch(cmd) {
174                     case "Plugin":
175                     case "plugin":
176                         Plugins.Add(m.Groups[2].Value);
177                         break;
178                     default:
179                         Console.WriteLine("Unknown Command in {0}: {1}", filename, line);
180                         break;
181                     }
182                     continue;
183                 }
184             }
185
186             f.Close();
187         }
188
189         public static void SaveFile(string filename) {
190             TextWriter f;
191             try {
192                 f = new StreamWriter(filename);
193             } catch (IOException) {
194                 Console.WriteLine("Could not save configuration to {0}", filename);
195                 return;
196             }
197
198             foreach (string key in Options.Keys) {
199                 if (CommandLineOptions.Contains(key)) continue;
200                 f.WriteLine("{0} = {1}", key, Options[key]);
201             }
202
203             foreach (string plugin in PluginOptions.Keys) {
204                 foreach (string key in PluginOptions[plugin].Keys) {
205                     string pkey = String.Format("{0}.{1}", plugin, key);
206                     if (CommandLineOptions.Contains(pkey)) continue;
207                     f.WriteLine("{0} = {1}", pkey, PluginOptions[plugin][key]);
208                 }
209             }
210
211             f.Close();
212         }
213
214         public static void SaveFile(WebThingPlugin p, string filename) {
215             string plugin_name = p.GetType().FullName;
216             SaveFile(plugin_name, filename);
217         }
218
219         public static void SaveFile(string plugin_name, string filename) {
220             // TODO: Throw exception if plugin does not exist
221             TextWriter f = new StreamWriter(filename);
222
223             foreach (string key in PluginOptions[plugin_name].Keys) {
224                 f.WriteLine("{0}.{1} = {2}", plugin_name, key, PluginOptions[plugin_name][key]);
225             }
226
227             f.Close();
228         }
229     }
230 }