1 /*
2 roxterm - VTE/GTK terminal emulator with tabs
3 Copyright (C) 2004-2015 Tony Houghton <h@realh.co.uk>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20
21 #include "dynopts.h"
22 #include "optsfile.h"
23
24 #include <string.h>
25
26 struct DynamicOptions {
27 char *family;
28 GHashTable *profiles;
29 };
30
31
dynamic_options_get(const char * family)32 DynamicOptions *dynamic_options_get(const char *family)
33 {
34 static GHashTable *all_dynopts = NULL;
35 DynamicOptions *dynopts;
36
37 if (!all_dynopts)
38 all_dynopts = g_hash_table_new(g_str_hash, g_str_equal);
39
40 dynopts = g_hash_table_lookup(all_dynopts, family);
41 if (!dynopts)
42 {
43 dynopts = g_new(DynamicOptions, 1);
44 dynopts->family = g_strdup(family);
45 dynopts->profiles = g_hash_table_new(g_str_hash, g_str_equal);
46 g_hash_table_insert(all_dynopts, (gpointer) family, dynopts);
47 }
48 return dynopts;
49 }
50
dynamic_options_lookup(DynamicOptions * dynopts,const char * profile_name)51 Options *dynamic_options_lookup(DynamicOptions * dynopts,
52 const char *profile_name)
53 {
54 return g_hash_table_lookup(dynopts->profiles, profile_name);
55 }
56
dynamic_options_lookup_and_ref(DynamicOptions * dynopts,const char * profile_name,const char * group_name)57 Options *dynamic_options_lookup_and_ref(DynamicOptions * dynopts,
58 const char *profile_name, const char *group_name)
59 {
60 Options *options = g_hash_table_lookup(dynopts->profiles, profile_name);
61
62 if (!options)
63 {
64 char *leafname = g_build_filename(dynopts->family, profile_name,
65 NULL);
66
67 options = options_open(leafname, group_name);
68 g_hash_table_insert(dynopts->profiles, g_strdup(profile_name), options);
69 }
70 else
71 {
72 options_ref(options);
73 }
74 return options;
75 }
76
77 void
dynamic_options_forget(DynamicOptions * dynopts,const char * profile_name)78 dynamic_options_forget(DynamicOptions *dynopts, const char *profile_name)
79 {
80 g_hash_table_remove(dynopts->profiles, profile_name);
81 }
82
83 gboolean
dynamic_options_unref(DynamicOptions * dynopts,const char * profile_name)84 dynamic_options_unref(DynamicOptions * dynopts, const char *profile_name)
85 {
86 /* Use generic pointers for these to avoid breaking strict aliasing (see
87 * man gcc) */
88 gpointer options;
89 gpointer key;
90 gboolean lookup_ok = g_hash_table_lookup_extended(dynopts->profiles,
91 profile_name, &key, &options);
92
93 if (!lookup_ok)
94 return FALSE;
95
96 /* Have to check ref and remove from hash first in case options_unref
97 * frees profile_name */
98 if (((Options *) options)->ref == 1)
99 {
100 g_hash_table_remove(dynopts->profiles, profile_name);
101 g_free(key);
102 }
103 return options_unref(options);
104 }
105
dynopts_add_path_contents_to_list(GList * list,const char * path,const char * family,gboolean sorted)106 static GList *dynopts_add_path_contents_to_list(GList *list, const char *path,
107 const char *family, gboolean sorted)
108 {
109 GError *err = NULL;
110 char *dirname = g_build_filename(path, family, NULL);
111
112 if (g_file_test(dirname, G_FILE_TEST_IS_DIR))
113 {
114 GDir *dir = g_dir_open(dirname, 0, &err);
115
116 if (!dir || err)
117 {
118 g_warning("%s", err->message);
119 g_error_free(err);
120 }
121 else
122 {
123 const char *filename;
124
125 while ((filename = g_dir_read_name(dir)) != NULL)
126 {
127 GList *link;
128
129 for (link = list; link; link = g_list_next(link))
130 {
131 if (!strcmp(link->data, filename))
132 break;
133 }
134 if (!link)
135 {
136 char *pathname = g_build_filename(dirname, filename, NULL);
137
138 if (!g_file_test(pathname, G_FILE_TEST_IS_DIR))
139 list = g_list_append(list, g_strdup(filename));
140 g_free(pathname);
141 }
142 /* else duplicate */
143 }
144 g_dir_close(dir);
145 }
146 }
147 g_free(dirname);
148 if (sorted)
149 {
150 list = g_list_sort(list, (GCompareFunc) dynamic_options_strcmp);
151 }
152 return list;
153 }
154
dynamic_options_list_full(DynamicOptions * dynopts,gboolean sorted)155 char **dynamic_options_list_full(DynamicOptions *dynopts, gboolean sorted)
156 {
157 int i;
158 const char * const *paths = options_file_get_pathv();
159 char **strv;
160 guint nmemb;
161 guint n;
162 GList *list = g_list_append(NULL, g_strdup("Default"));
163 GList *link;
164
165 for (i = 0; paths[i]; ++i)
166 {
167 list = dynopts_add_path_contents_to_list(list, paths[i],
168 dynopts->family, sorted);
169 }
170
171 nmemb = g_list_length(list);
172 if (!nmemb)
173 return NULL;
174 strv = g_new(char *, nmemb + 1);
175 for (link = list, n = 0; link && n < nmemb; link = g_list_next(link), ++n)
176 strv[n] = link->data;
177 strv[n] = NULL;
178 g_list_free(list);
179
180 return strv;
181 }
182
dynamic_options_rename(DynamicOptions * dynopts,const char * old_name,const char * new_name)183 void dynamic_options_rename(DynamicOptions *dynopts,
184 const char *old_name, const char *new_name)
185 {
186 Options *opts = dynamic_options_lookup(dynopts, old_name);
187
188 g_return_if_fail(opts);
189 dynamic_options_forget(dynopts, old_name);
190 g_hash_table_insert(dynopts->profiles, g_strdup(new_name), opts);
191 }
192
dynamic_options_strcmp(const char * s1,const char * s2)193 int dynamic_options_strcmp(const char *s1, const char *s2)
194 {
195 char *u1, *u2;
196 int result;
197
198 if (!g_strcmp0(s1, "Default"))
199 return g_strcmp0(s2, "Default") ? -1 : 0;
200 else if (!g_strcmp0(s2, "Default"))
201 return 1;
202 u1 = s1 ? g_utf8_casefold(s1, -1) : g_strdup("");
203 u2 = s2 ? g_utf8_casefold(s2, -1) : g_strdup("");
204 result = g_utf8_collate(u1, u2);
205 g_free(u2);
206 g_free(u1);
207 return result;
208 }
209
210 /* vi:set sw=4 ts=4 noet cindent cino= */
211