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