1 /* colors.c -- functions to control interface color */
2 
3 /*
4  * This file is part of CliFM
5  *
6  * Copyright (C) 2016-2021, L. Abramovich <johndoe.arch@outlook.com>
7  * All rights reserved.
8 
9  * CliFM is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * CliFM is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22  * MA 02110-1301, USA.
23 */
24 
25 #include "helpers.h"
26 
27 #include <stdio.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #ifdef __linux__
31 #include <sys/capability.h>
32 #endif
33 #include <dirent.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 #include "aux.h"
39 #include "checks.h"
40 #include "colors.h"
41 #include "listing.h"
42 #include "mime.h"
43 #include "misc.h"
44 #include "messages.h"
45 #include "file_operations.h"
46 
47 /* Retrieve the color corresponding to dir FILENAME with mode MODE */
48 char *
get_dir_color(const char * filename,const mode_t mode)49 get_dir_color(const char *filename, const mode_t mode)
50 {
51 	char *color = (char *)NULL;
52 	int sticky = 0;
53 	int is_oth_w = 0;
54 	if (mode & S_ISVTX)
55 		sticky = 1;
56 
57 	if (mode & S_IWOTH)
58 		is_oth_w = 1;
59 
60 	int files_dir = count_dir(filename, CPOP);
61 
62 	color = sticky ? (is_oth_w ? tw_c : st_c) : is_oth_w ? ow_c
63 		   : ((files_dir == 2 || files_dir == 0) ? ed_c : di_c);
64 
65 	return color;
66 }
67 
68 char *
get_file_color(const char * filename,const struct stat attr)69 get_file_color(const char *filename, const struct stat attr)
70 {
71 	char *color = (char *)NULL;
72 
73 #ifdef _LINUX_CAP
74 	cap_t cap;
75 #endif
76 	if (attr.st_mode & 04000) { /* SUID */
77 		color = su_c;
78 	} else if (attr.st_mode & 02000) { /* SGID */
79 		color = sg_c;
80 	}
81 #ifdef _LINUX_CAP
82 	else if (check_cap && (cap = cap_get_file(filename))) {
83 		color = ca_c;
84 		cap_free(cap);
85 	}
86 #endif
87 	else if ((attr.st_mode & 00100) /* Exec */
88 	|| (attr.st_mode & 00010) || (attr.st_mode & 00001)) {
89 		if (attr.st_size == 0)
90 			color = ee_c;
91 		else
92 			color = ex_c;
93 	} else if (attr.st_size == 0) {
94 		color = ef_c;
95 	} else if (attr.st_nlink > 1) { /* Multi-hardlink */
96 		color = mh_c;
97 	} else { /* Regular file */
98 		color = fi_c;
99 	}
100 
101 	return color;
102 }
103 
104 /* Returns a pointer to the corresponding color code for EXT, if some
105  * color was defined */
106 char *
get_ext_color(const char * ext)107 get_ext_color(const char *ext)
108 {
109 	if (!ext || !ext_colors_n)
110 		return (char *)NULL;
111 
112 	ext++;
113 
114 	int i = (int)ext_colors_n;
115 	while (--i >= 0) {
116 		if (!ext_colors[i] || !*ext_colors[i] || !ext_colors[i][2])
117 			continue;
118 
119 		char *p = (char *)ext,
120 			 *q = ext_colors[i];
121 		/* +2 because stored extensions have this form: *.ext */
122 		q += 2;
123 
124 		size_t match = 1;
125 		while (*p) {
126 			if (*p++ != *q++) {
127 				match = 0;
128 				break;
129 			}
130 		}
131 
132 		if (!match || *q != '=')
133 			continue;
134 		return ++q;
135 	}
136 
137 	return (char *)NULL;
138 }
139 
140 /* Check if STR has the format of a color code string (a number or a
141  * semicolon list (max 12 fields) of numbers of at most 3 digits each).
142  * Returns 1 if true and 0 if false. */
143 static int
is_color_code(const char * str)144 is_color_code(const char *str)
145 {
146 	if (!str || !*str)
147 		return 0;
148 
149 	size_t digits = 0, semicolon = 0;
150 
151 	while (*str) {
152 		if (*str >= '0' && *str <= '9') {
153 			digits++;
154 		} else if (*str == ';') {
155 			if (*(str + 1) == ';') /* Consecutive semicolons */
156 				return 0;
157 			digits = 0;
158 			semicolon++;
159 		} else if (*str != '\n') {
160 		/* Neither digit nor semicolon */
161 			return 0;
162 		}
163 		str++;
164 	}
165 
166 	/* No digits at all, ending semicolon, more than eleven fields, or
167 	 * more than three consecutive digits */
168 	if (!digits || digits > 3 || semicolon > 11)
169 		return 0;
170 
171 	/* At this point, we have a semicolon separated string of digits (3
172 	 * consecutive max) with at most 12 fields. The only thing not
173 	 * validated here are numbers themselves */
174 	return 1;
175 }
176 
177 /* Strip color lines from the config file (FiletypeColors, if mode is
178  * 't', and ExtColors, if mode is 'x') returning the same string
179  * containing only allowed characters */
180 static char *
strip_color_line(const char * str,char mode)181 strip_color_line(const char *str, char mode)
182 {
183 	if (!str || !*str)
184 		return (char *)NULL;
185 
186 	char *buf = (char *)xnmalloc(strlen(str) + 1, sizeof(char));
187 	size_t len = 0;
188 
189 	switch (mode) {
190 	case 't': /* di=01;31: */
191 		while (*str) {
192 			if ((*str >= '0' && *str <= '9') || (*str >= 'a' && *str <= 'z')
193 			|| *str == '=' || *str == ';' || *str == ':')
194 				buf[len++] = *str;
195 			str++;
196 		}
197 		break;
198 
199 	case 'x': /* *.tar=01;31: */
200 		while (*str) {
201 			if ((*str >= '0' && *str <= '9') || (*str >= 'a' && *str <= 'z')
202 			|| (*str >= 'A' && *str <= 'Z') || *str == '*' || *str == '.'
203 			|| *str == '=' || *str == ';' || *str == ':')
204 				buf[len++] = *str;
205 			str++;
206 		}
207 		break;
208 	}
209 
210 	if (!len || !*buf) {
211 		free(buf);
212 		return (char *)NULL;
213 	}
214 
215 	buf[len] = '\0';
216 	return buf;
217 }
218 
219 static void
reset_filetype_colors(void)220 reset_filetype_colors(void)
221 {
222 	*nd_c = '\0';
223 	*nf_c = '\0';
224 	*di_c = '\0';
225 	*ed_c = '\0';
226 	*ne_c = '\0';
227 	*ex_c = '\0';
228 	*ee_c = '\0';
229 	*bd_c = '\0';
230 	*ln_c = '\0';
231 	*mh_c = '\0';
232 	*or_c = '\0';
233 	*so_c = '\0';
234 	*pi_c = '\0';
235 	*cd_c = '\0';
236 	*fi_c = '\0';
237 	*ef_c = '\0';
238 	*su_c = '\0';
239 	*sg_c = '\0';
240 	*ca_c = '\0';
241 	*st_c = '\0';
242 	*tw_c = '\0';
243 	*ow_c = '\0';
244 	*no_c = '\0';
245 	*uf_c = '\0';
246 }
247 
248 static void
reset_iface_colors(void)249 reset_iface_colors(void)
250 {
251 	*hb_c = '\0';
252 	*hc_c = '\0';
253 	*hd_c = '\0';
254 	*he_c = '\0';
255 	*hn_c = '\0';
256 	*hp_c = '\0';
257 	*hq_c = '\0';
258 	*hr_c = '\0';
259 	*hs_c = '\0';
260 	*hv_c = '\0';
261 	*hw_c = '\0';
262 
263 	*sh_c = '\0';
264 	*sf_c = '\0';
265 	*sc_c = '\0';
266 	*sx_c = '\0';
267 	*sp_c = '\0';
268 
269 	*bm_c = '\0';
270 	*dl_c = '\0';
271 	*el_c = '\0';
272 	*mi_c = '\0';
273 	*tx_c = '\0';
274 	*df_c = '\0';
275 	*dc_c = '\0';
276 	*wc_c = '\0';
277 	*dh_c = '\0';
278 	*li_c = '\0';
279 	*li_cb = '\0';
280 	*ti_c = '\0';
281 	*em_c = '\0';
282 	*wm_c = '\0';
283 	*nm_c = '\0';
284 	*si_c = '\0';
285 	*ts_c = '\0';
286 	*wp_c = '\0';
287 
288 	*ws1_c = '\0';
289 	*ws2_c = '\0';
290 	*ws3_c = '\0';
291 	*ws4_c = '\0';
292 	*ws5_c = '\0';
293 	*ws6_c = '\0';
294 	*ws7_c = '\0';
295 	*ws8_c = '\0';
296 }
297 
298 int
cschemes_function(char ** args)299 cschemes_function(char **args)
300 {
301 	if (xargs.stealth_mode == 1) {
302 		fprintf(stderr, _("%s: The color schemes function is "
303 				  "disabled in stealth mode\nTIP: To change the current "
304 				  "color scheme use the following environment "
305 				  "variables: CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS, "
306 				  "and CLIFM_EXT_COLORS\n"), PROGRAM_NAME);
307 		return EXIT_FAILURE;
308 	}
309 
310 	if (!args)
311 		return EXIT_FAILURE;
312 
313 	if (!args[1]) {
314 		if (!cschemes_n) {
315 			printf(_("%s: No color schemes found\n"), PROGRAM_NAME);
316 			return EXIT_SUCCESS;
317 		}
318 		size_t i;
319 		for (i = 0; color_schemes[i]; i++) {
320 			if (cur_cscheme == color_schemes[i])
321 				printf("%s%s%s\n", mi_c, color_schemes[i], df_c);
322 			else
323 				printf("%s\n", color_schemes[i]);
324 		}
325 
326 		return EXIT_SUCCESS;
327 	}
328 
329 	if (*args[1] == '-' && strcmp(args[1], "--help") == 0) {
330 		puts(_(CS_USAGE));
331 		return EXIT_SUCCESS;
332 	}
333 
334 	if (*args[1] == 'e' && (!args[1][1] || strcmp(args[1], "edit") == 0)) {
335 		char file[PATH_MAX];
336 		snprintf(file, PATH_MAX - 1, "%s/%s.cfm", colors_dir, cur_cscheme);
337 		struct stat attr;
338 		if (stat(file, &attr) == -1) {
339 			if (data_dir) {
340 				snprintf(file, PATH_MAX - 1, "%s/%s/colors/%s.cfm",
341 						data_dir, PNL, cur_cscheme);
342 				if (access(file, W_OK) == -1) {
343 					fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME,
344 							file, strerror(errno));
345 					return EXIT_FAILURE;
346 				}
347 			} else {
348 				fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME,
349 						file, strerror(errno));
350 				return EXIT_FAILURE;
351 			}
352 		}
353 
354 		stat(file, &attr);
355 		time_t mtime_bfr = (time_t)attr.st_mtime;
356 
357 		open_in_foreground = 1;
358 		int ret = open_file(file);
359 		open_in_foreground = 0;
360 		if (ret != EXIT_FAILURE) {
361 			stat(file, &attr);
362 			if (mtime_bfr != (time_t)attr.st_mtime
363 			&& set_colors(cur_cscheme, 0) == EXIT_SUCCESS
364 			&& autols) {
365 				free_dirlist();
366 				list_dir();
367 			}
368 		}
369 
370 		return ret;
371 	}
372 
373 	if (*args[1] == 'n' && (!args[1][1] || strcmp(args[1], "name") == 0)) {
374 		printf(_("%s: current color scheme: %s\n"), PROGRAM_NAME,
375 		    cur_cscheme ? cur_cscheme : "?");
376 		return EXIT_SUCCESS;
377 	}
378 
379 	size_t i, cs_found = 0;
380 	for (i = 0; color_schemes[i]; i++) {
381 		if (*args[1] == *color_schemes[i]
382 		&& strcmp(args[1], color_schemes[i]) == 0) {
383 			cs_found = 1;
384 			if (set_colors(args[1], 0) == EXIT_SUCCESS) {
385 				cur_cscheme = color_schemes[i];
386 				switch_cscheme = 1;
387 
388 				if (autols) {
389 					free_dirlist();
390 					list_dir();
391 				}
392 
393 				switch_cscheme = 0;
394 				return EXIT_SUCCESS;
395 			}
396 		}
397 	}
398 
399 	if (!cs_found)
400 		fprintf(stderr, _("%s: No such color scheme\n"), PROGRAM_NAME);
401 
402 	return EXIT_FAILURE;
403 }
404 
405 static void
set_filetype_colors(char ** colors,const size_t words)406 set_filetype_colors(char **colors, const size_t words)
407 {
408 	int i = (int)words;
409 	while (--i >= 0) {
410 		if (*colors[i] == 'd' && strncmp(colors[i], "di=", 3) == 0) {
411 			if (!is_color_code(colors[i] + 3))
412 				*di_c = '\0';
413 			else
414 				snprintf(di_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
415 
416 		} else if (*colors[i] == 'n' && strncmp(colors[i], "nd=", 3) == 0) {
417 			if (!is_color_code(colors[i] + 3))
418 				*nd_c = '\0';
419 			else
420 				snprintf(nd_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
421 
422 		} else if (*colors[i] == 'e' && strncmp(colors[i], "ed=", 3) == 0) {
423 			if (!is_color_code(colors[i] + 3))
424 				*ed_c = '\0';
425 			else
426 				snprintf(ed_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
427 
428 		} else if (*colors[i] == 'n' && strncmp(colors[i], "ne=", 3) == 0) {
429 			if (!is_color_code(colors[i] + 3))
430 				*ne_c = '\0';
431 			else
432 				snprintf(ne_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
433 
434 		} else if (*colors[i] == 'f' && strncmp(colors[i], "fi=", 3) == 0) {
435 			if (!is_color_code(colors[i] + 3))
436 				*fi_c = '\0';
437 			else
438 				snprintf(fi_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
439 
440 		} else if (*colors[i] == 'e' && strncmp(colors[i], "ef=", 3) == 0) {
441 			if (!is_color_code(colors[i] + 3))
442 				*ef_c = '\0';
443 			else
444 				snprintf(ef_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
445 
446 		} else if (*colors[i] == 'n' && strncmp(colors[i], "nf=", 3) == 0) {
447 			if (!is_color_code(colors[i] + 3))
448 				*nf_c = '\0';
449 			else
450 				snprintf(nf_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
451 
452 		} else if (*colors[i] == 'l' && strncmp(colors[i], "ln=", 3) == 0) {
453 			if (!is_color_code(colors[i] + 3))
454 				*ln_c = '\0';
455 			else
456 				snprintf(ln_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
457 
458 		} else if (*colors[i] == 'o' && strncmp(colors[i], "or=", 3) == 0) {
459 			if (!is_color_code(colors[i] + 3))
460 				*or_c = '\0';
461 			else
462 				snprintf(or_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
463 
464 		} else if (*colors[i] == 'e' && strncmp(colors[i], "ex=", 3) == 0) {
465 			if (!is_color_code(colors[i] + 3))
466 				*ex_c = '\0';
467 			else
468 				snprintf(ex_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
469 
470 		} else if (*colors[i] == 'e' && strncmp(colors[i], "ee=", 3) == 0) {
471 			if (!is_color_code(colors[i] + 3))
472 				*ee_c = '\0';
473 			else
474 				snprintf(ee_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
475 
476 		} else if (*colors[i] == 'b' && strncmp(colors[i], "bd=", 3) == 0) {
477 			if (!is_color_code(colors[i] + 3))
478 				*bd_c = '\0';
479 			else
480 				snprintf(bd_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
481 
482 		} else if (*colors[i] == 'c' && strncmp(colors[i], "cd=", 3) == 0) {
483 			if (!is_color_code(colors[i] + 3))
484 				*cd_c = '\0';
485 			else
486 				snprintf(cd_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
487 
488 		} else if (*colors[i] == 'p' && strncmp(colors[i], "pi=", 3) == 0) {
489 			if (!is_color_code(colors[i] + 3))
490 				*pi_c = '\0';
491 			else
492 				snprintf(pi_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
493 
494 		} else if (*colors[i] == 's' && strncmp(colors[i], "so=", 3) == 0) {
495 			if (!is_color_code(colors[i] + 3))
496 				*so_c = '\0';
497 			else
498 				snprintf(so_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
499 
500 		} else if (*colors[i] == 's' && strncmp(colors[i], "su=", 3) == 0) {
501 			if (!is_color_code(colors[i] + 3))
502 				*su_c = '\0';
503 			else
504 				snprintf(su_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
505 
506 		} else if (*colors[i] == 's' && strncmp(colors[i], "sg=", 3) == 0) {
507 			if (!is_color_code(colors[i] + 3))
508 				*sg_c = '\0';
509 			else
510 				snprintf(sg_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
511 
512 		} else if (*colors[i] == 't' && strncmp(colors[i], "tw=", 3) == 0) {
513 			if (!is_color_code(colors[i] + 3))
514 				*tw_c = '\0';
515 			else
516 				snprintf(tw_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
517 
518 		} else if (*colors[i] == 's' && strncmp(colors[i], "st=", 3) == 0) {
519 			if (!is_color_code(colors[i] + 3))
520 				*st_c = '\0';
521 			else
522 				snprintf(st_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
523 
524 		} else if (*colors[i] == 'o' && strncmp(colors[i], "ow=", 3) == 0) {
525 			if (!is_color_code(colors[i] + 3))
526 				*ow_c = '\0';
527 			else
528 				snprintf(ow_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
529 
530 		} else if (*colors[i] == 'c' && strncmp(colors[i], "ca=", 3) == 0) {
531 			if (!is_color_code(colors[i] + 3))
532 				*ca_c = '\0';
533 			else
534 				snprintf(ca_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
535 
536 		} else if (*colors[i] == 'n' && strncmp(colors[i], "no=", 3) == 0) {
537 			if (!is_color_code(colors[i] + 3))
538 				*no_c = '\0';
539 			else
540 				snprintf(no_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
541 
542 		} else if (*colors[i] == 'm' && strncmp(colors[i], "mh=", 3) == 0) {
543 			if (!is_color_code(colors[i] + 3))
544 				*mh_c = '\0';
545 			else
546 				snprintf(mh_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
547 
548 		} else if (*colors[i] == 'u' && strncmp(colors[i], "uf=", 3) == 0) {
549 			if (!is_color_code(colors[i] + 3))
550 				*uf_c = '\0';
551 			else
552 				snprintf(uf_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
553 		}
554 
555 		free(colors[i]);
556 	}
557 }
558 
559 static void
set_iface_colors(char ** colors,const size_t words)560 set_iface_colors(char **colors, const size_t words)
561 {
562 	int i = (int)words;
563 	while (--i >= 0) {
564 		if (*colors[i] == 't' && strncmp(colors[i], "tx=", 3) == 0) {
565 			if (!is_color_code(colors[i] + 3))
566 				/* zero the corresponding variable as a flag for
567 				 * the check after this loop to prepare the
568 				 * variable to hold the default color */
569 				*tx_c = '\0';
570 			else
571 				snprintf(tx_c, MAX_COLOR, "\x1b[%sm", colors[i] + 3);
572 		}
573 
574 		else if (*colors[i] == 'w' && strncmp(colors[i], "ws1=", 4) == 0) {
575 			if (!is_color_code(colors[i] + 4))
576 				*ws1_c = '\0';
577 			else
578 				snprintf(ws1_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 4);
579 		}
580 		else if (*colors[i] == 'w' && strncmp(colors[i], "ws2=", 4) == 0) {
581 			if (!is_color_code(colors[i] + 4))
582 				*ws2_c = '\0';
583 			else
584 				snprintf(ws2_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 4);
585 		}
586 		else if (*colors[i] == 'w' && strncmp(colors[i], "ws3=", 4) == 0) {
587 			if (!is_color_code(colors[i] + 4))
588 				*ws3_c = '\0';
589 			else
590 				snprintf(ws3_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 4);
591 		}
592 
593 		else if (*colors[i] == 'w' && strncmp(colors[i], "ws4=", 4) == 0) {
594 			if (!is_color_code(colors[i] + 4))
595 				*ws4_c = '\0';
596 			else
597 				snprintf(ws4_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 4);
598 		}
599 
600 		else if (*colors[i] == 'w' && strncmp(colors[i], "ws5=", 4) == 0) {
601 			if (!is_color_code(colors[i] + 4))
602 				*ws5_c = '\0';
603 			else
604 				snprintf(ws5_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 4);
605 		}
606 
607 		else if (*colors[i] == 'w' && strncmp(colors[i], "ws6=", 4) == 0) {
608 			if (!is_color_code(colors[i] + 4))
609 				*ws6_c = '\0';
610 			else
611 				snprintf(ws6_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 4);
612 		}
613 
614 		else if (*colors[i] == 'w' && strncmp(colors[i], "ws7=", 4) == 0) {
615 			if (!is_color_code(colors[i] + 4))
616 				*ws7_c = '\0';
617 			else
618 				snprintf(ws7_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 4);
619 		}
620 
621 		else if (*colors[i] == 'w' && strncmp(colors[i], "ws8=", 4) == 0) {
622 			if (!is_color_code(colors[i] + 4))
623 				*ws8_c = '\0';
624 			else
625 				snprintf(ws8_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 4);
626 		}
627 
628 		else if (*colors[i] == 'h' && strncmp(colors[i], "hb=", 3) == 0) {
629 			if (!is_color_code(colors[i] + 3))
630 				*hb_c = '\0';
631 			else
632 				snprintf(hb_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
633 		}
634 
635 		else if (*colors[i] == 'h' && strncmp(colors[i], "hc=", 3) == 0) {
636 			if (!is_color_code(colors[i] + 3))
637 				*hc_c = '\0';
638 			else
639 				snprintf(hc_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
640 		}
641 
642 		else if (*colors[i] == 'h' && strncmp(colors[i], "hd=", 3) == 0) {
643 			if (!is_color_code(colors[i] + 3))
644 				*hd_c = '\0';
645 			else
646 				snprintf(hd_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
647 		}
648 
649 		else if (*colors[i] == 'h' && strncmp(colors[i], "he=", 3) == 0) {
650 			if (!is_color_code(colors[i] + 3))
651 				*he_c = '\0';
652 			else
653 				snprintf(he_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
654 		}
655 
656 		else if (*colors[i] == 'h' && strncmp(colors[i], "hn=", 3) == 0) {
657 			if (!is_color_code(colors[i] + 3))
658 				*hn_c = '\0';
659 			else
660 				snprintf(hn_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
661 		}
662 
663 		else if (*colors[i] == 'h' && strncmp(colors[i], "hp=", 3) == 0) {
664 			if (!is_color_code(colors[i] + 3))
665 				*hp_c = '\0';
666 			else
667 				snprintf(hp_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
668 		}
669 
670 		else if (*colors[i] == 'h' && strncmp(colors[i], "hq=", 3) == 0) {
671 			if (!is_color_code(colors[i] + 3))
672 				*hq_c = '\0';
673 			else
674 				snprintf(hq_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
675 		}
676 
677 		else if (*colors[i] == 'h' && strncmp(colors[i], "hr=", 3) == 0) {
678 			if (!is_color_code(colors[i] + 3))
679 				*hr_c = '\0';
680 			else
681 				snprintf(hr_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
682 		}
683 
684 		else if (*colors[i] == 'h' && strncmp(colors[i], "hs=", 3) == 0) {
685 			if (!is_color_code(colors[i] + 3))
686 				*hs_c = '\0';
687 			else
688 				snprintf(hs_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
689 		}
690 
691 		else if (*colors[i] == 'h' && strncmp(colors[i], "hv=", 3) == 0) {
692 			if (!is_color_code(colors[i] + 3))
693 				*hv_c = '\0';
694 			else
695 				snprintf(hv_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
696 		}
697 
698 		else if (*colors[i] == 'h' && strncmp(colors[i], "hw=", 3) == 0) {
699 			if (!is_color_code(colors[i] + 3))
700 				*hw_c = '\0';
701 			else
702 				snprintf(hw_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
703 		}
704 
705 		else if (*colors[i] == 's' && strncmp(colors[i], "sb=", 3) == 0) {
706 			if (!is_color_code(colors[i] + 3))
707 				*sb_c = '\0';
708 			else
709 				snprintf(sb_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
710 		}
711 
712 		else if (*colors[i] == 's' && strncmp(colors[i], "sc=", 3) == 0) {
713 			if (!is_color_code(colors[i] + 3))
714 				*sc_c = '\0';
715 			else
716 				snprintf(sc_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
717 		}
718 
719 		else if (*colors[i] == 's' && strncmp(colors[i], "sh=", 3) == 0) {
720 			if (!is_color_code(colors[i] + 3))
721 				*sh_c = '\0';
722 			else
723 				snprintf(sh_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
724 		}
725 
726 		else if (*colors[i] == 's' && strncmp(colors[i], "sf=", 3) == 0) {
727 			if (!is_color_code(colors[i] + 3))
728 				*sf_c = '\0';
729 			else
730 				snprintf(sf_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
731 		}
732 
733 		else if (*colors[i] == 's' && strncmp(colors[i], "sp=", 3) == 0) {
734 			if (!is_color_code(colors[i] + 3))
735 				*sp_c = '\0';
736 			else
737 				snprintf(sp_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
738 		}
739 
740 		else if (*colors[i] == 's' && strncmp(colors[i], "sx=", 3) == 0) {
741 			if (!is_color_code(colors[i] + 3))
742 				*sx_c = '\0';
743 			else
744 				snprintf(sx_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
745 		}
746 
747 		else if (*colors[i] == 'b' && strncmp(colors[i], "bm=", 3) == 0) {
748 			if (!is_color_code(colors[i] + 3))
749 				*bm_c = '\0';
750 			else
751 				snprintf(bm_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
752 		}
753 
754 		else if (*colors[i] == 'l' && strncmp(colors[i], "li=", 3) == 0) {
755 			if (!is_color_code(colors[i] + 3)) {
756 				*li_c = '\0';
757 				*li_cb = '\0';
758 			} else {
759 				snprintf(li_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 3);
760 				snprintf(li_cb, MAX_COLOR, "\x1b[%sm", colors[i] + 3);
761 			}
762 		}
763 
764 		else if (*colors[i] == 't' && strncmp(colors[i], "ti=", 3) == 0) {
765 			if (!is_color_code(colors[i] + 3))
766 				*ti_c = '\0';
767 			else
768 				snprintf(ti_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 3);
769 		}
770 
771 		else if (*colors[i] == 'e' && strncmp(colors[i], "em=", 3) == 0) {
772 			if (!is_color_code(colors[i] + 3))
773 				*em_c = '\0';
774 			else
775 				snprintf(em_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 3);
776 		}
777 
778 		else if (*colors[i] == 'w' && strncmp(colors[i], "wm=", 3) == 0) {
779 			if (!is_color_code(colors[i] + 3))
780 				*wm_c = '\0';
781 			else
782 				snprintf(wm_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 3);
783 		}
784 
785 		else if (*colors[i] == 'n' && strncmp(colors[i], "nm=", 3) == 0) {
786 			if (!is_color_code(colors[i] + 3))
787 				*nm_c = '\0';
788 			else
789 				snprintf(nm_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 3);
790 		}
791 
792 		else if (*colors[i] == 's' && strncmp(colors[i], "si=", 3) == 0) {
793 			if (!is_color_code(colors[i] + 3))
794 				*si_c = '\0';
795 			else
796 				snprintf(si_c, MAX_COLOR + 2, "\001\x1b[%sm\002", colors[i] + 3);
797 		}
798 
799 		else if (*colors[i] == 'e' && strncmp(colors[i], "el=", 3) == 0) {
800 			if (!is_color_code(colors[i] + 3))
801 				*el_c = '\0';
802 			else
803 				snprintf(el_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
804 		}
805 
806 		else if (*colors[i] == 'm' && strncmp(colors[i], "mi=", 3) == 0) {
807 			if (!is_color_code(colors[i] + 3))
808 				*mi_c = '\0';
809 			else
810 				snprintf(mi_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
811 		}
812 
813 		else if (*colors[i] == 'd' && strncmp(colors[i], "dl=", 3) == 0) {
814 			if (!is_color_code(colors[i] + 3))
815 				*dl_c = '\0';
816 			else
817 				snprintf(dl_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
818 		}
819 
820 		else if (*colors[i] == 'd' && strncmp(colors[i], "df=", 3) == 0) {
821 			if (!is_color_code(colors[i] + 3))
822 				*df_c = '\0';
823 			else
824 				snprintf(df_c, MAX_COLOR - 1, "\x1b[%s;49m", colors[i] + 3);
825 		}
826 
827 		else if (*colors[i] == 'd' && strncmp(colors[i], "dc=", 3) == 0) {
828 			if (!is_color_code(colors[i] + 3))
829 				*dc_c = '\0';
830 			else
831 				snprintf(dc_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
832 		}
833 
834 		else if (*colors[i] == 'w' && strncmp(colors[i], "wc=", 3) == 0) {
835 			if (!is_color_code(colors[i] + 3))
836 				*wc_c = '\0';
837 			else
838 				snprintf(wc_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
839 		}
840 
841 		else if (*colors[i] == 'd' && strncmp(colors[i], "dh=", 3) == 0) {
842 			if (!is_color_code(colors[i] + 3))
843 				*dh_c = '\0';
844 			else
845 				snprintf(dh_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
846 		}
847 
848 		else if (*colors[i] == 't' && strncmp(colors[i], "ts=", 3) == 0) {
849 			if (!is_color_code(colors[i] + 3))
850 				*ts_c = '\0';
851 			else
852 				snprintf(ts_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
853 		}
854 
855 		else if (*colors[i] == 'w' && strncmp(colors[i], "wp=", 3) == 0) {
856 			if (!is_color_code(colors[i] + 3))
857 				*wp_c = '\0';
858 			else
859 				snprintf(wp_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3);
860 		}
861 
862 		free(colors[i]);
863 	}
864 }
865 
866 static void
set_default_colors(void)867 set_default_colors(void)
868 {
869 	if (!*hb_c)
870 		strcpy(hb_c, DEF_HB_C);
871 	if (!*hc_c)
872 		strcpy(hc_c, DEF_HC_C);
873 	if (!*hd_c)
874 		strcpy(hd_c, DEF_HD_C);
875 	if (!*he_c)
876 		strcpy(he_c, DEF_HE_C);
877 	if (!*hn_c)
878 		strcpy(hn_c, DEF_HN_C);
879 	if (!*hp_c)
880 		strcpy(hp_c, DEF_HP_C);
881 	if (!*hq_c)
882 		strcpy(hq_c, DEF_HQ_C);
883 	if (!*hr_c)
884 		strcpy(hr_c, DEF_HR_C);
885 	if (!*hs_c)
886 		strcpy(hs_c, DEF_HS_C);
887 	if (!*hv_c)
888 		strcpy(hv_c, DEF_HV_C);
889 	if (!*hw_c)
890 		strcpy(hw_c, DEF_HW_C);
891 
892 	if (!*sb_c)
893 		strcpy(sb_c, DEF_SB_C);
894 	if (!*sc_c)
895 		strcpy(sc_c, DEF_SC_C);
896 	if (!*sh_c)
897 		strcpy(sh_c, DEF_SH_C);
898 	if (!*sf_c)
899 		strcpy(sf_c, DEF_SF_C);
900 	if (!*sx_c)
901 		strcpy(sx_c, DEF_SX_C);
902 	if (!*sp_c)
903 		strcpy(sp_c, DEF_SP_C);
904 
905 	if (!*el_c)
906 		strcpy(el_c, DEF_EL_C);
907 	if (!*mi_c)
908 		strcpy(mi_c, DEF_MI_C);
909 	if (!*dl_c)
910 		strcpy(dl_c, DEF_DL_C);
911 	if (!*df_c)
912 		strcpy(df_c, DEF_DF_C);
913 	if (!*dc_c)
914 		strcpy(dc_c, DEF_DC_C);
915 	if (!*wc_c)
916 		strcpy(wc_c, DEF_WC_C);
917 	if (!*dh_c)
918 		strcpy(dh_c, DEF_DH_C);
919 	if (!*tx_c)
920 		strcpy(tx_c, DEF_TX_C);
921 	if (!*li_c)
922 		strcpy(li_c, DEF_LI_C);
923 	if (!*li_cb)
924 		strcpy(li_cb, DEF_LI_CB);
925 	if (!*ti_c)
926 		strcpy(ti_c, DEF_TI_C);
927 	if (!*em_c)
928 		strcpy(em_c, DEF_EM_C);
929 	if (!*wm_c)
930 		strcpy(wm_c, DEF_WM_C);
931 	if (!*nm_c)
932 		strcpy(nm_c, DEF_NM_C);
933 	if (!*si_c)
934 		strcpy(si_c, DEF_SI_C);
935 	if (!*bm_c)
936 		strcpy(bm_c, DEF_BM_C);
937 	if (!*ts_c)
938 		strcpy(ts_c, DEF_TS_C);
939 	if (!*wp_c)
940 		strcpy(wp_c, DEF_WP_C);
941 
942 	if (!*ws1_c)
943 		strcpy(ws1_c, DEF_WS1_C);
944 	if (!*ws2_c)
945 		strcpy(ws2_c, DEF_WS2_C);
946 	if (!*ws3_c)
947 		strcpy(ws3_c, DEF_WS3_C);
948 	if (!*ws4_c)
949 		strcpy(ws4_c, DEF_WS4_C);
950 	if (!*ws5_c)
951 		strcpy(ws5_c, DEF_WS5_C);
952 	if (!*ws6_c)
953 		strcpy(ws6_c, DEF_WS6_C);
954 	if (!*ws7_c)
955 		strcpy(ws7_c, DEF_WS7_C);
956 	if (!*ws8_c)
957 		strcpy(ws8_c, DEF_WS8_C);
958 
959 	if (!*di_c)
960 		strcpy(di_c, DEF_DI_C);
961 	if (!*nd_c)
962 		strcpy(nd_c, DEF_ND_C);
963 	if (!*ed_c)
964 		strcpy(ed_c, DEF_ED_C);
965 	if (!*ne_c)
966 		strcpy(ne_c, DEF_NE_C);
967 	if (!*fi_c)
968 		strcpy(fi_c, DEF_FI_C);
969 	if (!*ef_c)
970 		strcpy(ef_c, DEF_EF_C);
971 	if (!*nf_c)
972 		strcpy(nf_c, DEF_NF_C);
973 	if (!*ln_c)
974 		strcpy(ln_c, DEF_LN_C);
975 	if (!*or_c)
976 		strcpy(or_c, DEF_OR_C);
977 	if (!*pi_c)
978 		strcpy(pi_c, DEF_PI_C);
979 	if (!*so_c)
980 		strcpy(so_c, DEF_SO_C);
981 	if (!*bd_c)
982 		strcpy(bd_c, DEF_BD_C);
983 	if (!*cd_c)
984 		strcpy(cd_c, DEF_CD_C);
985 	if (!*su_c)
986 		strcpy(su_c, DEF_SU_C);
987 	if (!*sg_c)
988 		strcpy(sg_c, DEF_SG_C);
989 	if (!*st_c)
990 		strcpy(st_c, DEF_ST_C);
991 	if (!*tw_c)
992 		strcpy(tw_c, DEF_TW_C);
993 	if (!*ow_c)
994 		strcpy(ow_c, DEF_OW_C);
995 	if (!*ex_c)
996 		strcpy(ex_c, DEF_EX_C);
997 	if (!*ee_c)
998 		strcpy(ee_c, DEF_EE_C);
999 	if (!*ca_c)
1000 		strcpy(ca_c, DEF_CA_C);
1001 	if (!*no_c)
1002 		strcpy(no_c, DEF_NO_C);
1003 	if (!*uf_c)
1004 		strcpy(uf_c, DEF_UF_C);
1005 	if (!*mh_c)
1006 		strcpy(mh_c, DEF_MH_C);
1007 #ifndef _NO_ICONS
1008 	if (!*dir_ico_c)
1009 		strcpy(dir_ico_c, DEF_DIR_ICO_C);
1010 #endif
1011 }
1012 
1013 static void
free_extension_colors(void)1014 free_extension_colors(void)
1015 {
1016 	int i = (int)ext_colors_n;
1017 	while (--i >= 0)
1018 		free(ext_colors[i]);
1019 	free(ext_colors);
1020 	ext_colors = (char **)NULL;
1021 	free(ext_colors_len);
1022 	ext_colors_n = 0;
1023 }
1024 
1025 /* Set a pointer to the current color scheme */
1026 static void
get_cur_colorscheme(const char * colorscheme)1027 get_cur_colorscheme(const char *colorscheme)
1028 {
1029 	char *def_cscheme = (char *)NULL;
1030 	int i = (int)cschemes_n;
1031 	while (--i >= 0) {
1032 		if (*colorscheme == *color_schemes[i]
1033 		&& strcmp(colorscheme, color_schemes[i]) == 0) {
1034 			cur_cscheme = color_schemes[i];
1035 			break;
1036 		}
1037 
1038 		if (*color_schemes[i] == 'd'
1039 		&& strcmp(color_schemes[i], "default") == 0)
1040 			def_cscheme = color_schemes[i];
1041 	}
1042 
1043 	if (!cur_cscheme) {
1044 		_err('w', PRINT_PROMPT, _("%s: %s: No such color scheme. "
1045 			"Falling back to default\n"),
1046 			PROGRAM_NAME, colorscheme);
1047 
1048 		if (def_cscheme)
1049 			cur_cscheme = def_cscheme;
1050 	}
1051 }
1052 /*
1053 static void
1054 get_env_colors(char **file, char **ext, char **iface)
1055 {
1056 	char *filecolors = (void *)file;
1057 	char *extcolors = (void *)ext;
1058 	char *ifacecolors = (void *)iface;
1059 
1060 	char *env_filecolors = getenv("CLIFM_FILE_COLORS");
1061 	char *env_extcolors = getenv("CLIFM_EXT_COLORS");
1062 	char *env_ifacecolors = getenv("CLIFM_IFACE_COLORS");
1063 
1064 	if (env_filecolors)
1065 		filecolors = savestring(env_filecolors, strlen(env_filecolors));
1066 
1067 	env_filecolors = (char *)NULL;
1068 	if (env_extcolors)
1069 		extcolors = savestring(env_extcolors, strlen(env_extcolors));
1070 
1071 	env_extcolors = (char *)NULL;
1072 	if (env_ifacecolors)
1073 		ifacecolors = savestring(env_ifacecolors, strlen(env_ifacecolors));
1074 
1075 	env_ifacecolors = (char *)NULL;
1076 } */
1077 
1078 /* Open the config file, get values for file type and extension colors
1079  * and copy these values into the corresponding variable. If some value
1080  * is not found, or if it's a wrong value, the default is set. */
1081 int
set_colors(const char * colorscheme,int env)1082 set_colors(const char *colorscheme, int env)
1083 {
1084 	char *filecolors = (char *)NULL,
1085 		 *extcolors = (char *)NULL,
1086 	     *ifacecolors = (char *)NULL;
1087 
1088 #ifndef _NO_ICONS
1089 	*dir_ico_c = '\0';
1090 #endif
1091 
1092 	if (colorscheme && *colorscheme && color_schemes)
1093 		get_cur_colorscheme(colorscheme);
1094 
1095 	/* env is true only when the function is called from main() */
1096 	if (env) {
1097 //		get_env_colors(&filecolors, &extcolors, &ifacecolors);
1098 //		printf("FC: %s\n", filecolors);
1099 		/* Try to get colors from environment variables */
1100 		char *env_filecolors = getenv("CLIFM_FILE_COLORS");
1101 		char *env_extcolors = getenv("CLIFM_EXT_COLORS");
1102 		char *env_ifacecolors = getenv("CLIFM_IFACE_COLORS");
1103 
1104 		if (env_filecolors)
1105 			filecolors = savestring(env_filecolors, strlen(env_filecolors));
1106 
1107 		env_filecolors = (char *)NULL;
1108 		if (env_extcolors)
1109 			extcolors = savestring(env_extcolors, strlen(env_extcolors));
1110 
1111 		env_extcolors = (char *)NULL;
1112 		if (env_ifacecolors)
1113 			ifacecolors = savestring(env_ifacecolors, strlen(env_ifacecolors));
1114 
1115 		env_ifacecolors = (char *)NULL;
1116 	}
1117 
1118 	if (xargs.stealth_mode != 1 && (!filecolors || !extcolors || !ifacecolors)) {
1119 		/* Get color lines, for both file types and extensions, from
1120 	 * COLORSCHEME file */
1121 		char colorscheme_file[PATH_MAX];
1122 		*colorscheme_file = '\0';
1123 		if (config_ok) {
1124 			snprintf(colorscheme_file, PATH_MAX - 1, "%s/%s.cfm", colors_dir,
1125 				colorscheme ? colorscheme : "default");
1126 		}
1127 
1128 		/* If not in local dir, check system data dir as well */
1129 		struct stat attr;
1130 		if (data_dir && (!*colorscheme_file || stat(colorscheme_file, &attr) == -1)) {
1131 			snprintf(colorscheme_file, PATH_MAX- 1, "%s/%s/colors/%s.cfm",
1132 				data_dir, PNL, colorscheme ? colorscheme : "default");
1133 		}
1134 
1135 		FILE *fp_colors = fopen(colorscheme_file, "r");
1136 		if (fp_colors) {
1137 
1138 			/* If called from the color scheme function, reset all
1139 			 * color values before proceeding */
1140 			if (!env) {
1141 				reset_filetype_colors();
1142 				reset_iface_colors();
1143 			}
1144 
1145 			char *line = (char *)NULL;
1146 			size_t line_size = 0;
1147 			ssize_t line_len = 0;
1148 			int file_type_found = 0,
1149 				ext_type_found = 0,
1150 #ifndef _NO_ICONS
1151 			    iface_found = 0,
1152 			    dir_icon_found = 0;
1153 #else
1154 			    iface_found = 0;
1155 #endif
1156 
1157 			while ((line_len = getline(&line, &line_size, fp_colors)) > 0) {
1158 				/* Interface colors */
1159 				if (!ifacecolors && *line == 'I'
1160 				&& strncmp(line, "InterfaceColors=", 16) == 0) {
1161 					iface_found = 1;
1162 					char *opt_str = strchr(line, '=');
1163 					if (!opt_str)
1164 						continue;
1165 
1166 					opt_str++;
1167 					char *color_line = strip_color_line(opt_str, 't');
1168 					if (!color_line)
1169 						continue;
1170 
1171 					ifacecolors = savestring(color_line, strlen(color_line));
1172 					free(color_line);
1173 				}
1174 
1175 				/* Filetype Colors */
1176 				if (!filecolors && *line == 'F'
1177 				&& strncmp(line, "FiletypeColors=", 15) == 0) {
1178 					file_type_found = 1;
1179 					char *opt_str = strchr(line, '=');
1180 					if (!opt_str)
1181 						continue;
1182 
1183 					opt_str++;
1184 
1185 					char *color_line = strip_color_line(opt_str, 't');
1186 					if (!color_line)
1187 						continue;
1188 
1189 					filecolors = savestring(color_line, strlen(color_line));
1190 					free(color_line);
1191 				}
1192 
1193 				/* File extension colors */
1194 				if (!extcolors && *line == 'E' && strncmp(line, "ExtColors=", 10) == 0) {
1195 					ext_type_found = 1;
1196 					char *opt_str = strchr(line, '=');
1197 					if (!opt_str)
1198 						continue;
1199 
1200 					opt_str++;
1201 					extcolors = savestring(opt_str, strlen(opt_str));
1202 /*					char *color_line = strip_color_line(opt_str, 'x');
1203 					if (!color_line)
1204 						continue;
1205 
1206 					extcolors = savestring(color_line, strlen(color_line));
1207 					free(color_line); */
1208 				}
1209 
1210 #ifndef _NO_ICONS
1211 				/* Dir icons Color */
1212 				if (*line == 'D' && strncmp(line, "DirIconsColor=", 14) == 0) {
1213 					dir_icon_found = 1;
1214 					char *opt_str = strchr(line, '=');
1215 					if (!opt_str)
1216 						continue;
1217 					if (!*(++opt_str))
1218 						continue;
1219 
1220 					if (*opt_str == '\'' || *opt_str == '"')
1221 						opt_str++;
1222 					if (!*opt_str)
1223 						continue;
1224 
1225 					int nl_removed = 0;
1226 					if (line[line_len - 1] == '\n') {
1227 						line[line_len - 1] = '\0';
1228 						nl_removed = 1;
1229 					}
1230 
1231 					int end_char = (int)line_len - 1;
1232 
1233 					if (nl_removed)
1234 						end_char--;
1235 
1236 					if (line[end_char] == '\'' || line[end_char] == '"')
1237 						line[end_char] = '\0';
1238 
1239 					sprintf(dir_ico_c, "\x1b[%sm", opt_str);
1240 				}
1241 #endif /* !_NO_ICONS */
1242 
1243 				if (file_type_found && ext_type_found
1244 #ifndef _NO_ICONS
1245 				&& iface_found && dir_icon_found)
1246 #else
1247 				&& iface_found)
1248 #endif
1249 					break;
1250 			}
1251 
1252 			free(line);
1253 			line = (char *)NULL;
1254 			fclose(fp_colors);
1255 		}
1256 
1257 		/* If fopen failed */
1258 		else {
1259 			if (!env) {
1260 				fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME,
1261 				    colorscheme_file, strerror(errno));
1262 				return EXIT_FAILURE;
1263 			} else {
1264 				_err('w', PRINT_PROMPT, _("%s: %s: No such color scheme. "
1265 					"Falling back to the default one\n"), PROGRAM_NAME,
1266 					colorscheme);
1267 			}
1268 		}
1269 	}
1270 
1271 			/* ##############################
1272 			 * #    FILE EXTENSION COLORS   #
1273 			 * ############################## */
1274 
1275 	/* Split the colors line into substrings (one per color) */
1276 
1277 	if (!extcolors) {
1278 		/* Unload current extension colors */
1279 		if (ext_colors_n)
1280 			free_extension_colors();
1281 	} else {
1282 		char *p = extcolors, *buf = (char *)NULL;
1283 		size_t len = 0;
1284 		int eol = 0;
1285 
1286 		if (ext_colors_n)
1287 			free_extension_colors();
1288 
1289 		while (!eol) {
1290 			switch (*p) {
1291 
1292 			case '\0': /* fallthrough */
1293 			case '\n': /* fallthrough */
1294 			case ':':
1295 				if (!buf)
1296 					break;
1297 				buf[len] = '\0';
1298 				ext_colors = (char **)xrealloc(ext_colors,
1299 				    (ext_colors_n + 1) * sizeof(char *));
1300 				ext_colors[ext_colors_n++] = savestring(buf, len);
1301 				*buf = '\0';
1302 
1303 				if (!*p)
1304 					eol = 1;
1305 
1306 				len = 0;
1307 				p++;
1308 				break;
1309 
1310 			default:
1311 				buf = (char *)xrealloc(buf, (len + 2) * sizeof(char));
1312 				buf[len++] = *(p++);
1313 				break;
1314 			}
1315 		}
1316 
1317 		p = (char *)NULL;
1318 		free(extcolors);
1319 		extcolors = (char *)NULL;
1320 
1321 		if (buf) {
1322 			free(buf);
1323 			buf = (char *)NULL;
1324 		}
1325 
1326 		if (ext_colors) {
1327 			ext_colors = (char **)xrealloc(ext_colors, (ext_colors_n + 1) * sizeof(char *));
1328 			ext_colors[ext_colors_n] = (char *)NULL;
1329 		}
1330 
1331 		/* Make sure we have valid color codes and store the length
1332 		 * of each stored extension: this length will be used later
1333 		 * when listing files */
1334 		ext_colors_len = (size_t *)xnmalloc(ext_colors_n, sizeof(size_t));
1335 
1336 		int i = (int)ext_colors_n;
1337 		while (--i >= 0) {
1338 			char *ret = strrchr(ext_colors[i], '=');
1339 			if (!ret || !*(++ret) || !is_color_code(ret)) {
1340 				*ext_colors[i] = '\0';
1341 				ext_colors_len[i] = 0;
1342 				continue;
1343 			}
1344 
1345 			size_t j, ext_len = 0;
1346 			for (j = 2; ext_colors[i][j] && ext_colors[i][j] != '='; j++)
1347 				ext_len++;
1348 
1349 			ext_colors_len[i] = ext_len;
1350 		}
1351 	}
1352 
1353 			/* ##############################
1354 			 * #      INTERFACE COLORS      #
1355 			 * ############################## */
1356 
1357 	if (!ifacecolors) {
1358 		/* Free and reset whatever value was loaded */
1359 		reset_iface_colors();
1360 	} else {
1361 		char *p = ifacecolors, *buf = (char *)NULL,
1362 		     **colors = (char **)NULL;
1363 		size_t len = 0, words = 0;
1364 		int eol = 0;
1365 
1366 		while (!eol) {
1367 			switch (*p) {
1368 
1369 			case '\0': /* fallthrough */
1370 			case '\n': /* fallthrough */
1371 			case ':':
1372 				if (!buf)
1373 					break;
1374 				buf[len] = '\0';
1375 				colors = (char **)xrealloc(colors, (words + 1) * sizeof(char *));
1376 				colors[words++] = savestring(buf, len);
1377 				*buf = '\0';
1378 
1379 				if (!*p)
1380 					eol = 1;
1381 
1382 				len = 0;
1383 				p++;
1384 				break;
1385 
1386 			default:
1387 				buf = (char *)xrealloc(buf, (len + 2) * sizeof(char));
1388 				buf[len++] = *(p++);
1389 				break;
1390 			}
1391 		}
1392 
1393 		p = (char *)NULL;
1394 		free(ifacecolors);
1395 		ifacecolors = (char *)NULL;
1396 
1397 		if (buf) {
1398 			free(buf);
1399 			buf = (char *)NULL;
1400 		}
1401 
1402 		if (colors) {
1403 			colors = (char **)xrealloc(colors, (words + 1) * sizeof(char *));
1404 			colors[words] = (char *)NULL;
1405 		}
1406 
1407 		set_iface_colors(colors, words);
1408 		free(colors);
1409 		colors = (char **)NULL;
1410 	}
1411 
1412 			/* ##############################
1413 			 * #       FILETYPE COLORS      #
1414 			 * ############################## */
1415 
1416 	if (!filecolors) {
1417 		reset_filetype_colors();
1418 	} else {
1419 		/* Split the colors line into substrings (one per color) */
1420 		char *p = filecolors, *buf = (char *)NULL, **colors = (char **)NULL;
1421 		size_t len = 0, words = 0;
1422 		int eol = 0;
1423 
1424 		while (!eol) {
1425 			switch (*p) {
1426 
1427 			case '\0': /* fallthrough */
1428 			case '\n': /* fallthrough */
1429 			case ':':
1430 				if (!buf)
1431 					break;
1432 				buf[len] = '\0';
1433 				colors = (char **)xrealloc(colors, (words + 1) * sizeof(char *));
1434 				colors[words++] = savestring(buf, len);
1435 				*buf = '\0';
1436 
1437 				if (!*p)
1438 					eol = 1;
1439 
1440 				len = 0;
1441 				p++;
1442 				break;
1443 
1444 			default:
1445 				buf = (char *)xrealloc(buf, (len + 2) * sizeof(char));
1446 				buf[len++] = *(p++);
1447 				break;
1448 			}
1449 		}
1450 
1451 		p = (char *)NULL;
1452 		free(filecolors);
1453 		filecolors = (char *)NULL;
1454 
1455 		if (buf) {
1456 			free(buf);
1457 			buf = (char *)NULL;
1458 		}
1459 
1460 		if (colors) {
1461 			colors = (char **)xrealloc(colors, (words + 1) * sizeof(char *));
1462 			colors[words] = (char *)NULL;
1463 		}
1464 
1465 		/* Set the color variables */
1466 		set_filetype_colors(colors, words);
1467 		free(colors);
1468 		colors = (char **)NULL;
1469 	}
1470 
1471 	/* If some color was not set or it was a wrong color code, set the
1472 	 * default */
1473 	set_default_colors();
1474 
1475 	return EXIT_SUCCESS;
1476 }
1477 
1478 /* Print ENTRY using color codes and I as ELN, right padding PAD
1479  * chars and terminating ENTRY with or without a new line char (NEW_LINE
1480  * 1 or 0 respectivelly) */
1481 void
colors_list(char * ent,const int i,const int pad,const int new_line)1482 colors_list(char *ent, const int i, const int pad, const int new_line)
1483 {
1484 	size_t i_digits = (size_t)DIGINUM(i);
1485 
1486 	/* Num (i) + space + null byte */
1487 	char *index = (char *)xnmalloc(i_digits + 2, sizeof(char));
1488 
1489 	if (i > 0) /* When listing files in CWD */
1490 		sprintf(index, "%d ", i);
1491 	else if (i == -1) /* ELN for entry could not be found */
1492 		sprintf(index, "? ");
1493 	else
1494 	/* When listing files NOT in CWD (called from search function and
1495 	 * first argument is a path: "/search_str /path") 'i' is zero. In
1496 	 * this case, no index should be printed at all */
1497 		index[0] = '\0';
1498 
1499 	struct stat file_attrib;
1500 	size_t elen = strlen(ent);
1501 	int rem_slash = 0;
1502 	/* Remove the ending slash: lstat() won't take a symlink to dir as
1503 	 * a symlink (but as a dir), if the file name ends with a slash */
1504 	if (ent[elen - 1] == '/') {
1505 		ent[elen - 1] = '\0';
1506 		rem_slash = 1;
1507 	}
1508 	int ret = lstat(ent, &file_attrib);
1509 	if (rem_slash)
1510 		ent[elen - 1] = '/';
1511 	if (ret == -1) {
1512 		fprintf(stderr, "%s%s%s%s%-*s%s%s", el_c, index, df_c,
1513 		    uf_c, pad, ent, df_c, new_line ? "\n" : "");
1514 		free(index);
1515 		return;
1516 	}
1517 
1518 	char *linkname = (char *)NULL;
1519 	char ext_color[MAX_COLOR] = "";
1520 	char *color = fi_c;
1521 
1522 #ifdef _LINUX_CAP
1523 	cap_t cap;
1524 #endif
1525 
1526 	switch (file_attrib.st_mode & S_IFMT) {
1527 
1528 	case S_IFREG:
1529 		if (!check_file_access(file_attrib)) {
1530 			color = nf_c;
1531 		} else if (file_attrib.st_mode & S_ISUID) { /* set uid file */
1532 			color = su_c;
1533 		} else if (file_attrib.st_mode & S_ISGID) { /* set gid file */
1534 			color = sg_c;
1535 		} else {
1536 #ifdef _LINUX_CAP
1537 			cap = cap_get_file(ent);
1538 			if (cap) {
1539 				color = ca_c;
1540 				cap_free(cap);
1541 			} else if (file_attrib.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
1542 #else
1543 			if (file_attrib.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
1544 #endif
1545 				if (file_attrib.st_size == 0)
1546 					color = ee_c;
1547 				else
1548 					color = ex_c;
1549 			} else if (file_attrib.st_size == 0) {
1550 				color = ef_c;
1551 			} else if (file_attrib.st_nlink > 1) {
1552 				color = mh_c;
1553 			} else {
1554 				char *ext = (strrchr(ent, '.'));
1555 				if (ext) {
1556 					char *extcolor = get_ext_color(ext);
1557 					if (extcolor) {
1558 						snprintf(ext_color, MAX_COLOR, "\x1b[%sm",
1559 						    extcolor);
1560 						color = ext_color;
1561 						extcolor = (char *)NULL;
1562 					}
1563 					ext = (char *)NULL;
1564 				}
1565 			}
1566 		}
1567 
1568 		break;
1569 
1570 	case S_IFDIR:
1571 		if (!check_file_access(file_attrib)) {
1572 			color = nd_c;
1573 		} else {
1574 			int is_oth_w = 0;
1575 
1576 			if (file_attrib.st_mode & S_IWOTH)
1577 				is_oth_w = 1;
1578 
1579 			int files_dir = count_dir(ent, NO_CPOP);
1580 
1581 			color = (file_attrib.st_mode & S_ISVTX) ? (is_oth_w
1582 					? tw_c : st_c) : (is_oth_w ? ow_c :
1583 					/* If folder is empty, it contains only "."
1584 					 * and ".." (2 elements). If not mounted (ex:
1585 					 * /media/usb) the result will be zero. */
1586 					(files_dir == 2 || files_dir == 0) ? ed_c : di_c);
1587 		}
1588 		break;
1589 
1590 	case S_IFLNK:
1591 		linkname = realpath(ent, NULL);
1592 		if (linkname) {
1593 			color = ln_c;
1594 			free(linkname);
1595 		} else {
1596 			color = or_c;
1597 		}
1598 		break;
1599 
1600 	case S_IFIFO: color = pi_c; break;
1601 	case S_IFBLK: color = bd_c; break;
1602 	case S_IFCHR: color = cd_c; break;
1603 	case S_IFSOCK: color = so_c; break;
1604 	/* In case all the above conditions are false... */
1605 	default: color = no_c; break;
1606 	}
1607 
1608 	printf("%s%s%s%s%s%s%s%-*s", el_c, index, df_c, color,
1609 	    ent + tab_offset, df_c, new_line ? "\n" : "", pad, "");
1610 	free(index);
1611 }
1612 
1613 size_t
1614 get_colorschemes(void)
1615 {
1616 	struct stat attr;
1617 	int schemes_total = 0;
1618 	struct dirent *ent;
1619 	DIR *dir_p;
1620 	size_t i = 0;
1621 
1622 	if (colors_dir && stat(colors_dir, &attr) == EXIT_SUCCESS) {
1623 		schemes_total = count_dir(colors_dir, NO_CPOP) - 2;
1624 		if (schemes_total) {
1625 			color_schemes = (char **)xrealloc(color_schemes,
1626 							((size_t)schemes_total + 2) * sizeof(char *));
1627 
1628 			/* count_dir already opened and read this directory succesfully,
1629 			 * so that we don't need to check opendir for errors */
1630 			dir_p = opendir(colors_dir);
1631 			while ((ent = readdir(dir_p)) != NULL) {
1632 				/* Skipp . and .. */
1633 				char *name = ent->d_name;
1634 				if (*name == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1635 					continue;
1636 
1637 				char *ret = strchr(name, '.');
1638 				/* If the file contains not dot, or if its extension is not
1639 				 * .cfm, or if it's just a hidden file named ".cfm", skip it */
1640 				if (!ret || strcmp(ret, ".cfm") != 0 || ret == name)
1641 					continue;
1642 
1643 				*ret = '\0';
1644 				color_schemes[i++] = savestring(name, strlen(name));
1645 			}
1646 
1647 			closedir(dir_p);
1648 			color_schemes[i] = (char *)NULL;
1649 		}
1650 	}
1651 
1652 	if (!data_dir)
1653 		return i;
1654 
1655 	char sys_colors_dir[PATH_MAX];
1656 	snprintf(sys_colors_dir, PATH_MAX - 1, "%s/%s/colors", data_dir, PNL);
1657 
1658 	if (stat(sys_colors_dir, &attr) == -1)
1659 		return i;
1660 
1661 	int total_tmp = schemes_total;
1662 	schemes_total += (count_dir(sys_colors_dir, NO_CPOP) - 2);
1663 
1664 	if (schemes_total <= total_tmp)
1665 		return i;
1666 
1667 	color_schemes = (char **)xrealloc(color_schemes,
1668 					((size_t)schemes_total + 2) * sizeof(char *));
1669 
1670 	size_t i_tmp = i;
1671 
1672 	dir_p = opendir(sys_colors_dir);
1673 	while ((ent = readdir(dir_p)) != NULL) {
1674 		/* Skipp . and .. */
1675 		char *name = ent->d_name;
1676 		if (*name == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1677 			continue;
1678 
1679 		char *ret = strchr(name, '.');
1680 		/* If the file contains not dot, or if its extension is not
1681 		 * .cfm, or if it's just a hidden file named ".cfm", skip it */
1682 		if (!ret || ret == name || strcmp(ret, ".cfm") != 0)
1683 			continue;
1684 
1685 		*ret = '\0';
1686 
1687 		size_t j;
1688 		int dup = 0;
1689 		for (j = 0; j < i_tmp; j++) {
1690 			if (*color_schemes[j] == *name && strcmp(name, color_schemes[j]) == 0) {
1691 				dup = 1;
1692 				break;
1693 			}
1694 		}
1695 
1696 		if (dup)
1697 			continue;
1698 
1699 		color_schemes[i++] = savestring(name, strlen(name));
1700 	}
1701 
1702 	closedir(dir_p);
1703 	color_schemes[i] = (char *)NULL;
1704 	return i;
1705 }
1706 
1707 /* List color codes for file types used by the program */
1708 void
1709 color_codes(void)
1710 {
1711 	if (!colorize) {
1712 		printf(_("%s: Currently running without colors\n"),
1713 		    PROGRAM_NAME);
1714 		return;
1715 	}
1716 
1717 	if (ext_colors_n)
1718 		printf(_("%sFile type colors%s\n\n"), BOLD, df_c);
1719 	printf(_(" %sfile name%s: Directory with no read permission (nd)\n"),
1720 	    nd_c, df_c);
1721 	printf(_(" %sfile name%s: File with no read permission (nf)\n"),
1722 	    nf_c, df_c);
1723 	printf(_(" %sfile name%s: Directory* (di)\n"), di_c, df_c);
1724 	printf(_(" %sfile name%s: EMPTY directory (ed)\n"), ed_c, df_c);
1725 	printf(_(" %sfile name%s: EMPTY directory with no read "
1726 		 "permission (ne)\n"),
1727 	    ne_c, df_c);
1728 	printf(_(" %sfile name%s: Executable file (ex)\n"), ex_c, df_c);
1729 	printf(_(" %sfile name%s: Empty executable file (ee)\n"), ee_c, df_c);
1730 	printf(_(" %sfile name%s: Block special file (bd)\n"), bd_c, df_c);
1731 	printf(_(" %sfile name%s: Symbolic link* (ln)\n"), ln_c, df_c);
1732 	printf(_(" %sfile name%s: Broken symbolic link (or)\n"), or_c, df_c);
1733 	printf(_(" %sfile name%s: Multi-hardlink (mh)\n"), mh_c, df_c);
1734 	printf(_(" %sfile name%s: Socket file (so)\n"), so_c, df_c);
1735 	printf(_(" %sfile name%s: Pipe or FIFO special file (pi)\n"), pi_c, df_c);
1736 	printf(_(" %sfile name%s: Character special file (cd)\n"), cd_c, df_c);
1737 	printf(_(" %sfile name%s: Regular file (fi)\n"), fi_c, df_c);
1738 	printf(_(" %sfile name%s: Empty (zero-lenght) file (ef)\n"), ef_c, df_c);
1739 	printf(_(" %sfile name%s: SUID file (su)\n"), su_c, df_c);
1740 	printf(_(" %sfile name%s: SGID file (sg)\n"), sg_c, df_c);
1741 	printf(_(" %sfile name%s: File with capabilities (ca)\n"), ca_c, df_c);
1742 	printf(_(" %sfile name%s: Sticky and NOT other-writable "
1743 		 "directory* (st)\n"),
1744 	    st_c, df_c);
1745 	printf(_(" %sfile name%s: Sticky and other-writable "
1746 		 "directory* (tw)\n"),
1747 	    tw_c, df_c);
1748 	printf(_(" %sfile name%s: Other-writable and NOT sticky "
1749 		 "directory* (ow)\n"),
1750 	    ow_c, df_c);
1751 	printf(_(" %sfile name%s: Unknown file type (no)\n"), no_c, df_c);
1752 	printf(_(" %sfile name%s: Unaccessible (non-stat'able) file "
1753 		 "(uf)\n"),
1754 	    uf_c, df_c);
1755 
1756 	printf(_("\n*The slash followed by a number (/xx) after directories "
1757 		 "or symbolic links to directories indicates the amount of "
1758 		 "files contained by the corresponding directory, excluding "
1759 		 "self (.) and parent (..) directories.\n"));
1760 	printf(_("\nThe value in parentheses is the code that is to be used "
1761 		 "to modify the color of the corresponding file type in the "
1762 		 "color scheme file (in the \"FiletypeColors\" line), "
1763 		 "using the same ANSI style color format used by dircolors. "
1764 		 "By default, %s uses only 8 colors, but you can use 256 "
1765 		 "and RGB colors as well.\n\n"), PROGRAM_NAME);
1766 
1767 	if (ext_colors_n) {
1768 		size_t i, j;
1769 		printf(_("%sExtension colors%s\n\n"), BOLD, df_c);
1770 		for (i = 0; i < ext_colors_n; i++) {
1771 			char *ret = strrchr(ext_colors[i], '=');
1772 			if (!ret)
1773 				continue;
1774 			printf(" \x1b[%sm", ret + 1);
1775 			for (j = 0; ext_colors[i][j] != '='; j++)
1776 				putchar(ext_colors[i][j]);
1777 			puts("\x1b[0m");
1778 		}
1779 		putchar('\n');
1780 	}
1781 }
1782