1 /*
2    Skins engine.
3    Reading and parse ini-files
4 
5    Copyright (C) 2009-2021
6    Free Software Foundation, Inc.
7 
8    Written by:
9    Slava Zanko <slavazanko@gmail.com>, 2009.
10 
11    This file is part of the Midnight Commander.
12 
13    The Midnight Commander is free software: you can redistribute it
14    and/or modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation, either version 3 of the License,
16    or (at your option) any later version.
17 
18    The Midnight Commander is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21    GNU General Public License for more details.
22 
23    You should have received a copy of the GNU General Public License
24    along with this program.  If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 #include <config.h>
28 
29 #include <string.h>
30 
31 #include "lib/global.h"         /* <glib.h> */
32 
33 #include "internal.h"
34 #include "lib/fileloc.h"
35 #include "lib/util.h"           /* exist_file() */
36 
37 /*** global variables ****************************************************************************/
38 
39 /*** file scope macro definitions ****************************************************************/
40 
41 /*** file scope type declarations ****************************************************************/
42 
43 /*** file scope variables ************************************************************************/
44 
45 /*** file scope functions ************************************************************************/
46 
47 /* --------------------------------------------------------------------------------------------- */
48 
49 static void
mc_skin_get_list_from_dir(const gchar * base_dir,GPtrArray * list)50 mc_skin_get_list_from_dir (const gchar * base_dir, GPtrArray * list)
51 {
52     gchar *name;
53     GDir *dir;
54 
55     name = g_build_filename (base_dir, MC_SKINS_DIR, (char *) NULL);
56     dir = g_dir_open (name, 0, NULL);
57     g_free (name);
58 
59     if (dir != NULL)
60     {
61         const gchar *cname;
62 
63         while ((cname = g_dir_read_name (dir)) != NULL)
64         {
65             gchar *sname;
66             size_t slen;
67             unsigned int i;
68 
69             slen = strlen (cname);
70             sname = g_strndup (cname, slen);
71 
72             if (slen > 4 && strcmp (sname + slen - 4, ".ini") == 0)
73                 sname[slen - 4] = '\0';
74 
75             for (i = 0; i < list->len; i++)
76                 if (strcmp (sname, g_ptr_array_index (list, i)) == 0)
77                     break;
78 
79             if (i < list->len)
80                 g_free (sname);
81             else
82                 g_ptr_array_add (list, sname);
83         }
84 
85         g_dir_close (dir);
86     }
87 }
88 
89 /* --------------------------------------------------------------------------------------------- */
90 
91 static int
string_array_comparator(gconstpointer a,gconstpointer b)92 string_array_comparator (gconstpointer a, gconstpointer b)
93 {
94     return strcmp (*(char *const *) a, *(char *const *) b);
95 }
96 
97 /* --------------------------------------------------------------------------------------------- */
98 
99 static gboolean
mc_skin_ini_file_load_search_in_dir(mc_skin_t * mc_skin,const gchar * base_dir)100 mc_skin_ini_file_load_search_in_dir (mc_skin_t * mc_skin, const gchar * base_dir)
101 {
102     char *file_name, *file_name2;
103 
104     file_name = g_build_filename (base_dir, MC_SKINS_DIR, mc_skin->name, (char *) NULL);
105     if (exist_file (file_name))
106     {
107         mc_skin->config = mc_config_init (file_name, TRUE);
108         g_free (file_name);
109         return (mc_skin->config != NULL);
110     }
111     g_free (file_name);
112 
113     file_name2 = g_strdup_printf ("%s.ini", mc_skin->name);
114     file_name = g_build_filename (base_dir, MC_SKINS_DIR, file_name2, (char *) NULL);
115     g_free (file_name2);
116 
117     if (exist_file (file_name))
118     {
119         mc_skin->config = mc_config_init (file_name, TRUE);
120         g_free (file_name);
121         return (mc_skin->config != NULL);
122     }
123     g_free (file_name);
124     return FALSE;
125 }
126 
127 /* --------------------------------------------------------------------------------------------- */
128 /*** public functions ****************************************************************************/
129 /* --------------------------------------------------------------------------------------------- */
130 
131 GPtrArray *
mc_skin_list(void)132 mc_skin_list (void)
133 {
134     GPtrArray *list;
135 
136     list = g_ptr_array_new ();
137     mc_skin_get_list_from_dir (mc_config_get_data_path (), list);
138     mc_skin_get_list_from_dir (mc_global.sysconfig_dir, list);
139     mc_skin_get_list_from_dir (mc_global.share_data_dir, list);
140     g_ptr_array_sort (list, (GCompareFunc) string_array_comparator);
141 
142     return list;
143 }
144 
145 /* --------------------------------------------------------------------------------------------- */
146 
147 gboolean
mc_skin_ini_file_load(mc_skin_t * mc_skin)148 mc_skin_ini_file_load (mc_skin_t * mc_skin)
149 {
150     char *file_name;
151 
152     file_name = g_path_get_basename (mc_skin->name);
153     if (file_name == NULL)
154         return FALSE;
155 
156     if (strcmp (file_name, mc_skin->name) != 0)
157     {
158         g_free (file_name);
159         if (!g_path_is_absolute (mc_skin->name))
160             return FALSE;
161         mc_skin->config = mc_config_init (mc_skin->name, TRUE);
162         return (mc_skin->config != NULL);
163     }
164     g_free (file_name);
165 
166     /* ${XDG_DATA_HOME}/mc/skins/ */
167     if (mc_skin_ini_file_load_search_in_dir (mc_skin, mc_config_get_data_path ()))
168         return TRUE;
169 
170     /* /etc/mc/skins/ */
171     if (mc_skin_ini_file_load_search_in_dir (mc_skin, mc_global.sysconfig_dir))
172         return TRUE;
173 
174     /* /usr/share/mc/skins/ */
175     return mc_skin_ini_file_load_search_in_dir (mc_skin, mc_global.share_data_dir);
176 }
177 
178 /* --------------------------------------------------------------------------------------------- */
179 
180 gboolean
mc_skin_ini_file_parse(mc_skin_t * mc_skin)181 mc_skin_ini_file_parse (mc_skin_t * mc_skin)
182 {
183     mc_skin->description =
184         mc_config_get_string (mc_skin->config, "skin", "description", "- no description -");
185     if (!mc_skin_color_parse_ini_file (mc_skin))
186         return FALSE;
187 
188     mc_skin_lines_parse_ini_file (mc_skin);
189     mc_skin->have_256_colors = mc_config_get_bool (mc_skin->config, "skin", "256colors", FALSE);
190     mc_skin->have_true_colors = mc_config_get_bool (mc_skin->config, "skin", "truecolors", FALSE);
191 
192     return TRUE;
193 }
194 
195 /* --------------------------------------------------------------------------------------------- */
196 
197 void
mc_skin_set_hardcoded_skin(mc_skin_t * mc_skin)198 mc_skin_set_hardcoded_skin (mc_skin_t * mc_skin)
199 {
200     mc_skin->config = mc_config_init (NULL, TRUE);
201 
202     mc_config_set_string (mc_skin->config, "skin", "description", "hardcoded skin");
203 
204     mc_skin_hardcoded_ugly_lines (mc_skin);
205     mc_skin_hardcoded_blackwhite_colors (mc_skin);
206 }
207 
208 /* --------------------------------------------------------------------------------------------- */
209