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