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