1 /* init.c -- functions controlling the program initialization */
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 <limits.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <getopt.h>
31 #include <pwd.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <sys/stat.h>
36 #include <termios.h>
37 #include <time.h>
38 #include <unistd.h>
39 #include <readline/readline.h>
40 #include <readline/history.h>
41 #ifdef __NetBSD__
42 #include <ctype.h>
43 #endif
44
45 #include "aux.h"
46 #include "checks.h"
47 #include "config.h"
48 #include "exec.h"
49 #include "init.h"
50 #include "mime.h"
51 #include "misc.h"
52 #include "navigation.h"
53 #include "sort.h"
54 #include "string.h"
55 #include "history.h"
56 #include "file_operations.h"
57 #include "autocmds.h"
58
59 //struct user_t user;
60
61 /*
62 * functions
63 */
64
65 int
get_sys_shell(void)66 get_sys_shell(void)
67 {
68 char l[PATH_MAX] = "";
69 ssize_t ret = readlinkat(AT_FDCWD, "/bin/sh", l, PATH_MAX);
70
71 if (!*l || ret == -1)
72 return SHELL_NONE;
73
74 char *s = (char *)NULL;
75 char *p = strrchr(l, '/');
76 if (p && *(++p))
77 s = p;
78 else
79 s = l;
80
81 if (*s == 'b' && strcmp(s, "bash") == 0)
82 return SHELL_BASH;
83 if (*s == 'd' && strcmp(s, "dash") == 0)
84 return SHELL_DASH;
85 if (*s == 'f' && strcmp(s, "fish") == 0)
86 return SHELL_FISH;
87 if (*s == 'z' && strcmp(s, "zsh") == 0)
88 return SHELL_ZSH;
89
90 return SHELL_NONE;
91 }
92
93 #ifndef _NO_GETTEXT
94 /* Initialize gettext for translations support */
95 int
init_gettext(void)96 init_gettext(void)
97 {
98 char locale_dir[PATH_MAX];
99 snprintf(locale_dir, PATH_MAX - 1, "%s/locale", data_dir
100 ? data_dir : "/usr/share");
101 bindtextdomain(PNL, locale_dir);
102 textdomain(PNL);
103 return EXIT_SUCCESS;
104
105 }
106 #endif
107
108 int
backup_argv(int argc,char ** argv)109 backup_argv(int argc, char **argv)
110 {
111 argc_bk = argc;
112 argv_bk = (char **)xnmalloc((size_t)argc + 1, sizeof(char *));
113
114 register int i = argc;
115 while (--i >= 0)
116 argv_bk[i] = savestring(argv[i], strlen(argv[i]));
117 argv_bk[argc] = (char *)NULL;
118
119 return EXIT_SUCCESS;
120 }
121
122 int
init_workspaces(void)123 init_workspaces(void)
124 {
125 ws = (struct ws_t *)xnmalloc(MAX_WS, sizeof(struct ws_t));
126 int i = MAX_WS;
127 while (--i >= 0) {
128 ws[i].path = (char *)NULL;
129 // ws[i].autocmd = 0;
130 // ws[i].num = 0;
131 }
132
133 return EXIT_SUCCESS;
134 }
135
136 int
get_home(void)137 get_home(void)
138 {
139 if (access(user.home, W_OK) == -1) {
140 /* If no user's home, or if it's not writable, there won't be
141 * any config nor trash directory. These flags are used to
142 * prevent functions from trying to access any of these
143 * directories */
144 home_ok = 0;
145 config_ok = 0;
146 #ifndef _NO_TRASH
147 trash_ok = 0;
148 #endif
149 /* Print message: trash, bookmarks, command logs, commands
150 * history and program messages won't be stored */
151 _err('e', PRINT_PROMPT, _("%s: Cannot access the home directory. "
152 "Trash, bookmarks, commands logs, and commands history are "
153 "disabled. Program messages and selected files won't be "
154 "persistent. Using default options\n"), PROGRAM_NAME);
155 return EXIT_FAILURE;
156 }
157
158 user_home_len = strlen(user.home);
159 return EXIT_SUCCESS;
160 }
161
162 int
init_history(void)163 init_history(void)
164 {
165 /* Limit the log files size */
166 check_file_size(log_file, max_log);
167 check_file_size(msg_log_file, max_log);
168
169 /* Get history */
170 struct stat attr;
171 if (stat(hist_file, &attr) == 0 && attr.st_size != 0) {
172 /* If the size condition is not included, and in case of a zero
173 * size file, read_history() produces malloc errors */
174 /* Recover history from the history file */
175 read_history(hist_file); /* This line adds more leaks to readline */
176 /* Limit the size of the history file to max_hist lines */
177 history_truncate_file(hist_file, max_hist);
178 } else {
179 /* If the history file doesn't exist, create it */
180 FILE *hist_fp = fopen(hist_file, "w+");
181 if (!hist_fp) {
182 _err('w', PRINT_PROMPT, "%s: fopen: '%s': %s\n",
183 PROGRAM_NAME, hist_file, strerror(errno));
184 } else {
185 /* To avoid malloc errors in read_history(), do not
186 * create an empty file */
187 fputs("edit\n", hist_fp);
188 /* There is no need to run read_history() here, since
189 * the history file is still empty */
190 fclose(hist_fp);
191 }
192 }
193
194 return EXIT_SUCCESS;
195 }
196
197 int
set_start_path(void)198 set_start_path(void)
199 {
200 /* Last path is overriden by positional parameters in the command line */
201 if (restore_last_path)
202 get_last_path();
203
204 if (cur_ws == UNSET)
205 cur_ws = DEF_CUR_WS;
206
207 if (cur_ws > MAX_WS - 1) {
208 cur_ws = DEF_CUR_WS;
209 _err('w', PRINT_PROMPT, _("%s: %zu: Invalid workspace."
210 "\nFalling back to workspace %zu\n"), PROGRAM_NAME,
211 cur_ws, cur_ws + 1);
212 }
213
214 /* If path was not set (neither in the config file nor via command
215 * line nor via the RestoreLastPath option), set the default (CWD),
216 * and if CWD is not set, use the user's home directory, and if the
217 * home cannot be found either, try the root directory, and if
218 * there's no access to the root dir either, exit.
219 * Bear in mind that if you launch CliFM through a terminal emulator,
220 * say xterm (xterm -e clifm), xterm will run a shell, say bash, and
221 * the shell will read its config file. Now, if this config file
222 * changes the CWD, this will be the CWD for CliFM */
223 if (!ws[cur_ws].path) {
224 char cwd[PATH_MAX] = "";
225 if (getcwd(cwd, sizeof(cwd)) == NULL) {}
226
227 if (!*cwd || strlen(cwd) == 0) {
228 if (user_home) {
229 ws[cur_ws].path = savestring(user_home, strlen(user_home));
230 } else {
231 if (access("/", R_OK | X_OK) == -1) {
232 fprintf(stderr, "%s: /: %s\n", PROGRAM_NAME,
233 strerror(errno));
234 exit(EXIT_FAILURE);
235 } else {
236 ws[cur_ws].path = savestring("/", 1);
237 }
238 }
239 } else {
240 ws[cur_ws].path = savestring(cwd, strlen(cwd));
241 }
242 }
243
244 /* Make path the CWD */
245 /* If chdir(path) fails, set path to cwd, list files and print the
246 * error message. If no access to CWD either, exit */
247 if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) {
248 _err('e', PRINT_PROMPT, "%s: chdir: '%s': %s\n", PROGRAM_NAME,
249 ws[cur_ws].path, strerror(errno));
250
251 char cwd[PATH_MAX] = "";
252 if (getcwd(cwd, sizeof(cwd)) == NULL) {
253 _err(0, NOPRINT_PROMPT, _("%s: Fatal error! Failed "
254 "retrieving current working directory\n"), PROGRAM_NAME);
255 exit(EXIT_FAILURE);
256 }
257
258 if (ws[cur_ws].path)
259 free(ws[cur_ws].path);
260 ws[cur_ws].path = savestring(cwd, strlen(cwd));
261 }
262
263 dir_changed = 1;
264
265 return EXIT_SUCCESS;
266 }
267
268 /* Get the system data directory (usually /usr/share) */
269 void
get_data_dir(void)270 get_data_dir(void)
271 {
272 /* First try standard values for DATADIR */
273 char *data_dirs[] = {
274 "/usr/share",
275 "/usr/local/share",
276 #if defined(__HAIKU__)
277 "/boot/system/non-packaged/data",
278 "/boot/system/data",
279 #endif
280 NULL };
281
282 struct stat attr;
283 size_t i;
284
285 for (i = 0; data_dirs[i]; i++) {
286 char tmp[PATH_MAX];
287 snprintf(tmp, PATH_MAX - 1, "%s/%s", data_dirs[i], PNL);
288 if (stat(tmp, &attr) == EXIT_SUCCESS) {
289 data_dir = (char *)xrealloc(data_dir, (strlen(data_dirs[i]) + 1)
290 * sizeof(char));
291 strcpy(data_dir, data_dirs[i]);
292 break;
293 }
294 }
295
296 /* if (data_dir)
297 return; */
298 return;
299
300 /* If not found, try to get DATADIR from executable's path */
301 /* data_dir = get_cmd_path(PNL);
302
303 if (!data_dir)
304 return;
305
306 size_t j = strlen(data_dir),
307 count = 0;
308
309 while (--j >= 0) {
310 if (data_dir[j] == '/')
311 count++;
312 if (count == 2) {
313 data_dir[j] = '\0';
314 break;
315 }
316 }
317
318 char tmp[PATH_MAX];
319 snprintf(tmp, PATH_MAX - 1, "%s/share/%s", data_dir, PNL);
320 if (stat(tmp, &attr) == EXIT_SUCCESS) {
321 snprintf(tmp, PATH_MAX - 1, "%s/share", data_dir);
322 data_dir = (char *)xrealloc(data_dir, (strlen(tmp) + 1) * sizeof(char));
323 strcpy(data_dir, tmp);
324 return;
325 } */
326 }
327
328 void
check_env_filter(void)329 check_env_filter(void)
330 {
331 if (_filter)
332 return;
333
334 char *p = getenv("CLIFM_FILTER");
335 if (!p)
336 return;
337
338 if (*p == '!') {
339 filter_rev = 1;
340 p++;
341 } else {
342 filter_rev = 0;
343 }
344
345 _filter = savestring(p, strlen(p));
346 }
347
348 char *
get_date(void)349 get_date(void)
350 {
351 time_t rawtime = time(NULL);
352 struct tm tm;
353 localtime_r(&rawtime, &tm);
354 size_t date_max = 128;
355
356 char *p = (char *)malloc((date_max + 1) * sizeof(char)), *date;
357 if (p) {
358 date = p;
359 p = (char *)NULL;
360 } else {
361 return (char *)NULL;
362 }
363
364 strftime(date, date_max, "%Y-%m-%dT%T%z", &tm);
365 return date;
366 }
367
368 static pid_t
get_own_pid(void)369 get_own_pid(void)
370 {
371 pid_t pid;
372
373 /* Get the process id */
374 pid = getpid();
375
376 if (pid < 0)
377 return 0;
378 return pid;
379 }
380
381 /* Returns pointer to user data struct, exits if not found */
382 struct user_t
get_user(void)383 get_user(void)
384 {
385 struct passwd *pw;
386 struct user_t tmp_user;
387
388 pw = getpwuid(geteuid());
389 if (!pw) {
390 _err('e', NOPRINT_PROMPT, _("%s: Cannot detect user data. Exiting early"),
391 PROGRAM_NAME);
392 exit(-1);
393 }
394
395 tmp_user.uid = pw->pw_uid;
396 tmp_user.gid = pw->pw_gid;
397 char *p = getenv("HOME");
398 if (!p)
399 tmp_user.home = savestring(pw->pw_dir, strlen(pw->pw_dir));
400 else
401 tmp_user.home = savestring(p, strlen(p));
402 tmp_user.name = savestring(pw->pw_name, strlen(pw->pw_name));
403 tmp_user.shell = savestring(pw->pw_shell, strlen(pw->pw_shell));
404
405 if (!tmp_user.home || !tmp_user.name || !tmp_user.shell) {
406 _err('e', NOPRINT_PROMPT, _("%s: Cannot detect user data. Exiting"),
407 PROGRAM_NAME);
408 exit(-1);
409 }
410
411 tmp_user.home_len = strlen(tmp_user.home);
412 return tmp_user;
413 }
414
415 /* Reconstruct the jump database from database file */
416 void
load_jumpdb(void)417 load_jumpdb(void)
418 {
419 if (xargs.no_dirjump == 1 || !config_ok || !config_dir)
420 return;
421
422 size_t dir_len = strlen(config_dir);
423 char *jump_file = (char *)xnmalloc(dir_len + 10, sizeof(char));
424 snprintf(jump_file, dir_len + 10, "%s/jump.cfm", config_dir);
425
426 int fd;
427 FILE *fp = open_fstream_r(jump_file, &fd);
428 if (!fp) {
429 free(jump_file);
430 return;
431 }
432
433 char tmp_line[PATH_MAX];
434 size_t jump_lines = 0;
435
436 while (fgets(tmp_line, (int)sizeof(tmp_line), fp)) {
437 if (*tmp_line != '\n' && *tmp_line >= '0' && *tmp_line <= '9')
438 jump_lines++;
439 }
440
441 if (!jump_lines) {
442 free(jump_file);
443 close_fstream(fp, fd);
444 return;
445 }
446
447 jump_db = (struct jump_t *)xnmalloc(jump_lines + 2, sizeof(struct jump_t));
448
449 fseek(fp, 0L, SEEK_SET);
450
451 size_t line_size = 0;
452 char *line = (char *)NULL;
453 ssize_t line_len = 0;
454
455 while ((line_len = getline(&line, &line_size, fp)) > 0) {
456 if (!*line || *line == '\n' || *line == '#')
457 continue;
458 if (*line == '@') {
459 if (line[line_len - 1] == '\n')
460 line[line_len - 1] = '\0';
461 if (is_number(line + 1))
462 jump_total_rank = atoi(line + 1);
463 continue;
464 }
465 if (*line < '0' || *line > '9')
466 continue;
467
468 if (line[line_len - 1] == '\n')
469 line[line_len - 1] = '\0';
470
471 char *tmp = strchr(line, ':');
472 if (!tmp)
473 continue;
474
475 *tmp = '\0';
476 if (!*(++tmp))
477 continue;
478
479 int visits = 1;
480
481 if (is_number(line))
482 visits = atoi(line);
483
484 char *tmpb = strchr(tmp, ':');
485 if (!tmpb)
486 continue;
487
488 *tmpb = '\0';
489
490 if (!*(++tmpb))
491 continue;
492
493 time_t first = 0;
494
495 if (is_number(tmp))
496 first = (time_t)atoi(tmp);
497
498 char *tmpc = strchr(tmpb, ':');
499 if (!tmpc)
500 continue;
501
502 *tmpc = '\0';
503
504 if (!*(++tmpc))
505 continue;
506
507 /* Purge the database from non-existent directories */
508 if (access(tmpc, F_OK) == -1)
509 continue;
510
511 jump_db[jump_n].visits = (size_t)visits;
512 jump_db[jump_n].first_visit = first;
513
514 if (is_number(tmpb))
515 jump_db[jump_n].last_visit = (time_t)atoi(tmpb);
516 else
517 jump_db[jump_n].last_visit = 0; /* UNIX Epoch */
518
519 jump_db[jump_n].keep = 0;
520 jump_db[jump_n].rank = 0;
521 jump_db[jump_n++].path = savestring(tmpc, strlen(tmpc));
522 }
523
524 close_fstream(fp, fd);
525 free(line);
526 free(jump_file);
527
528 if (!jump_n) {
529 free(jump_db);
530 jump_db = (struct jump_t *)NULL;
531 return;
532 }
533
534 jump_db[jump_n].path = (char *)NULL;
535 jump_db[jump_n].rank = 0;
536 jump_db[jump_n].keep = 0;
537 jump_db[jump_n].visits = 0;
538 jump_db[jump_n].first_visit = -1;
539 }
540
541 int
load_bookmarks(void)542 load_bookmarks(void)
543 {
544 if (create_bm_file() == EXIT_FAILURE)
545 return EXIT_FAILURE;
546
547 if (!bm_file)
548 return EXIT_FAILURE;
549
550 int fd;
551 FILE *fp = open_fstream_r(bm_file, &fd);
552 if (!fp)
553 return EXIT_FAILURE;
554
555 size_t bm_total = 0;
556 char tmp_line[256];
557 while (fgets(tmp_line, (int)sizeof(tmp_line), fp)) {
558 if (!*tmp_line || *tmp_line == '#' || *tmp_line == '\n')
559 continue;
560 bm_total++;
561 }
562
563 if (!bm_total) {
564 close_fstream(fp, fd);
565 return EXIT_SUCCESS;
566 }
567
568 fseek(fp, 0L, SEEK_SET);
569
570 bookmarks = (struct bookmarks_t *)xnmalloc(bm_total + 1,
571 sizeof(struct bookmarks_t));
572 size_t line_size = 0;
573 char *line = (char *)NULL;
574 ssize_t line_len = 0;
575
576 while ((line_len = getline(&line, &line_size, fp)) > 0) {
577 if (!*line || *line == '\n' || *line == '#')
578 continue;
579 if (line[line_len - 1] == '\n')
580 line[line_len - 1] = '\0';
581
582 /* Neither hotkey nor name, but only a path */
583 if (*line == '/') {
584 bookmarks[bm_n].shortcut = (char *)NULL;
585 bookmarks[bm_n].name = (char *)NULL;
586 bookmarks[bm_n++].path = savestring(line, strlen(line));
587 continue;
588 }
589
590 if (*line == '[') {
591 char *p = line;
592 p++;
593 char *tmp = strchr(line, ']');
594 if (!tmp) {
595 bookmarks[bm_n].shortcut = (char *)NULL;
596 bookmarks[bm_n].name = (char *)NULL;
597 bookmarks[bm_n++].path = (char *)NULL;
598 continue;
599 }
600
601 *tmp = '\0';
602
603 bookmarks[bm_n].shortcut = savestring(p, strlen(p));
604
605 tmp++;
606 p = tmp;
607 tmp = strchr(p, ':');
608
609 if (!tmp) {
610 bookmarks[bm_n].name = (char *)NULL;
611 if (*p)
612 bookmarks[bm_n++].path = savestring(p, strlen(p));
613 else
614 bookmarks[bm_n++].path = (char *)NULL;
615 continue;
616 }
617
618 *tmp = '\0';
619 bookmarks[bm_n].name = savestring(p, strlen(p));
620
621 if (!*(++tmp)) {
622 bookmarks[bm_n++].path = (char *)NULL;
623 continue;
624 }
625
626 bookmarks[bm_n++].path = savestring(tmp, strlen(tmp));
627 continue;
628 }
629
630 /* No shortcut. Let's try with name */
631 bookmarks[bm_n].shortcut = (char *)NULL;
632 char *tmp = strchr(line, ':');
633
634 /* No name either */
635 if (!tmp) {
636 bookmarks[bm_n].name = (char *)NULL;
637 bookmarks[bm_n++].path = (char *)NULL;
638 continue;
639 }
640
641 *tmp = '\0';
642 bookmarks[bm_n].name = savestring(line, strlen(line));
643
644 if (!*(++tmp)) {
645 bookmarks[bm_n++].path = (char *)NULL;
646 continue;
647 } else {
648 bookmarks[bm_n++].path = savestring(tmp, strlen(tmp));
649 }
650 }
651
652 free(line);
653 close_fstream(fp, fd);
654
655 if (!bm_n) {
656 free(bookmarks);
657 bookmarks = (struct bookmarks_t *)NULL;
658 return EXIT_SUCCESS;
659 }
660
661 /* bookmark_names array shouldn't exist: is only used for bookmark
662 * completion. xbookmarks[i].name should be used instead, but is
663 * currently not working */
664
665 size_t i, j = 0;
666 bookmark_names = (char **)xnmalloc(bm_n + 2, sizeof(char *));
667
668 for (i = 0; i < bm_n; i++) {
669 if (!bookmarks[i].name || !*bookmarks[i].name)
670 continue;
671 bookmark_names[j++] = savestring(bookmarks[i].name,
672 strlen(bookmarks[i].name));
673 }
674
675 bookmark_names[j] = (char *)NULL;
676 return EXIT_SUCCESS;
677 }
678
679 /* Store actions from the actions file into a struct */
680 int
load_actions(void)681 load_actions(void)
682 {
683 if (!config_ok)
684 return EXIT_FAILURE;
685
686 /* Free the actions struct array */
687 if (actions_n) {
688 int i = (int)actions_n;
689 while (--i >= 0) {
690 free(usr_actions[i].name);
691 free(usr_actions[i].value);
692 }
693
694 free(usr_actions);
695 usr_actions = (struct actions_t *)xnmalloc(1, sizeof(struct actions_t));
696 actions_n = 0;
697 }
698
699 /* Open the actions file */
700 int fd;
701 FILE *fp = open_fstream_r(actions_file, &fd);
702 if (!fp)
703 return EXIT_FAILURE;
704
705 size_t line_size = 0;
706 char *line = (char *)NULL;
707 ssize_t line_len = 0;
708
709 while ((line_len = getline(&line, &line_size, fp)) > 0) {
710 if (!line || !*line || *line == '#' || *line == '\n')
711 continue;
712 if (line[line_len - 1] == '\n')
713 line[line_len - 1] = '\0';
714
715 char *tmp = (char *)NULL;
716 tmp = strrchr(line, '=');
717 if (!tmp)
718 continue;
719
720 /* Now copy left and right value of each action into the
721 * actions struct */
722 usr_actions = xrealloc(usr_actions, (size_t)(actions_n + 1)
723 * sizeof(struct actions_t));
724 usr_actions[actions_n].value = savestring(tmp + 1, strlen(tmp + 1));
725 *tmp = '\0';
726 usr_actions[actions_n++].name = savestring(line, strlen(line));
727 }
728
729 free(line);
730 close_fstream(fp, fd);
731 return EXIT_SUCCESS;
732 }
733
734 static inline void
reset_remotes_values(const size_t i)735 reset_remotes_values(const size_t i)
736 {
737 remotes[i].name = (char *)NULL;
738 remotes[i].desc = (char *)NULL;
739 remotes[i].mountpoint = (char *)NULL;
740 remotes[i].mount_cmd = (char *)NULL;
741 remotes[i].unmount_cmd = (char *)NULL;
742 remotes[i].auto_unmount = 0;
743 remotes[i].auto_mount = 0;
744 remotes[i].mounted = 0;
745 }
746
747 /* Load remotes information from FILE */
748 int
load_remotes(void)749 load_remotes(void)
750 {
751 if (!remotes_file || !*remotes_file)
752 return EXIT_FAILURE;
753
754 int fd;
755 FILE *fp = open_fstream_r(remotes_file, &fd);
756 if (!fp) {
757 fprintf(stderr, "%s: %s\n", remotes_file, strerror(errno));
758 return EXIT_FAILURE;
759 }
760
761 size_t n = 0;
762 remotes = (struct remote_t *)xnmalloc(n + 1, sizeof(struct remote_t));
763 reset_remotes_values(n);
764
765 size_t line_sz = 0;
766 char *line = (char *)NULL;
767
768 while (getline(&line, &line_sz, fp) > 0) {
769 if (!*line || *line == '#' || *line == '\n')
770 continue;
771 if (*line == '[') {
772 if (remotes[n].name)
773 n++;
774 remotes = (struct remote_t *)xrealloc(
775 remotes, (n + 2) * sizeof(struct remote_t));
776 reset_remotes_values(n);
777
778 char *name = strbtw(line, '[', ']');
779 if (!name)
780 continue;
781 if (!*name) {
782 free(name);
783 name = (char *)NULL;
784 continue;
785 }
786 remotes[n].name = (char *)xrealloc(remotes[n].name,
787 (strlen(name) + 1) * sizeof(char));
788 strcpy(remotes[n].name, name);
789 free(name);
790 name = (char *)NULL;
791 }
792
793 if (!remotes[n].name)
794 continue;
795
796 char *ret = strchr(line, '=');
797 if (!ret)
798 continue;
799 if (!*(++ret))
800 continue;
801
802 size_t ret_len = strlen(ret);
803 if (ret[ret_len - 1] == '\n')
804 ret[--ret_len] = '\0';
805
806 char *deq_str = remove_quotes(ret);
807 if (deq_str)
808 ret = deq_str;
809
810 if (strncmp(line, "Comment=", 8) == 0) {
811 remotes[n].desc = (char *)xrealloc(remotes[n].desc,
812 (ret_len + 1) * sizeof(char));
813 strcpy(remotes[n].desc, ret);
814 } else if (strncmp(line, "Mountpoint=", 11) == 0) {
815 char *tmp = (char *)NULL;
816 if (*ret == '~')
817 tmp = tilde_expand(ret);
818 remotes[n].mountpoint = (char *)xrealloc(remotes[n].mountpoint,
819 ((tmp ? strlen(tmp) : ret_len) + 1)
820 * sizeof(char));
821 strcpy(remotes[n].mountpoint, tmp ? tmp : ret);
822 free(tmp);
823 if (count_dir(remotes[n].mountpoint, CPOP) > 2)
824 remotes[n].mounted = 1;
825 } else if (strncmp(line, "MountCmd=", 9) == 0) {
826 int replaced = 0;
827 if (remotes[n].mountpoint) {
828 char *rep = replace_substr(ret, "%m", remotes[n].mountpoint);
829 if (rep) {
830 remotes[n].mount_cmd = (char *)xrealloc(
831 remotes[n].mount_cmd,
832 (strlen(rep) + 1) * sizeof(char));
833 strcpy(remotes[n].mount_cmd, rep);
834 free(rep);
835 replaced = 1;
836 }
837 }
838
839 if (!replaced) {
840 remotes[n].mount_cmd = (char *)xrealloc(remotes[n].mount_cmd,
841 (ret_len + 1) * sizeof(char));
842 strcpy(remotes[n].mount_cmd, ret);
843 }
844 } else if (strncmp(line, "UnmountCmd=", 11) == 0) {
845 int replaced = 0;
846 if (remotes[n].mountpoint) {
847 char *rep = replace_substr(ret, "%m", remotes[n].mountpoint);
848 if (rep) {
849 remotes[n].unmount_cmd = (char *)xrealloc(
850 remotes[n].unmount_cmd,
851 (strlen(rep) + 1) * sizeof(char));
852 strcpy(remotes[n].unmount_cmd, rep);
853 free(rep);
854 replaced = 1;
855 }
856 }
857
858 if (!replaced) {
859 remotes[n].unmount_cmd = (char *)xrealloc(remotes[n].unmount_cmd,
860 (ret_len + 1) * sizeof(char));
861 strcpy(remotes[n].unmount_cmd, ret);
862 }
863 } else if (strncmp(line, "AutoUnmount=", 12) == 0) {
864 if (strcmp(ret, "true") == 0)
865 remotes[n].auto_unmount = 1;
866 } else if (strncmp(line, "AutoMount=", 10) == 0) {
867 if (strcmp(ret, "true") == 0)
868 remotes[n].auto_mount = 1;
869 }
870 }
871
872 free(line);
873 close_fstream(fp, fd);
874
875 if (remotes[n].name) {
876 ++n;
877 remotes[n].name = (char *)NULL;
878 }
879
880 remotes_n = n;
881 return EXIT_SUCCESS;
882 }
883
884 /* Opener function: open FILENAME and exit */
885 static void
open_reg_exit(char * filename)886 open_reg_exit(char *filename)
887 {
888 char *homedir = getenv("HOME");
889 if (!homedir) {
890 fprintf(stderr, "%s: Could not retrieve the home directory\n",
891 PROGRAM_NAME);
892 exit(EXIT_FAILURE);
893 }
894
895 tmp_dir = savestring(P_tmpdir, P_tmpdir_len);
896
897 size_t mime_file_len = strlen(homedir) + (alt_profile
898 ? strlen(alt_profile) : 7) + 38;
899 mime_file = (char *)xnmalloc(mime_file_len, sizeof(char));
900 sprintf(mime_file, "%s/.config/clifm/profiles/%s/mimelist.cfm",
901 homedir, alt_profile ? alt_profile : "default");
902
903 int ret = open_file(filename);
904 exit(ret);
905 }
906
907 /* Evaluate external arguments, if any, and change initial variables to
908 * its corresponding value */
909 void
external_arguments(int argc,char ** argv)910 external_arguments(int argc, char **argv)
911 {
912 /* Disable automatic error messages to be able to handle them
913 * myself via the '?' case in the switch */
914 opterr = optind = 0;
915
916 /* Link long (--option) and short options (-o) for the getopt_long
917 * function */
918 static struct option longopts[] = {
919 {"no-hidden", no_argument, 0, 'a'},
920 {"show-hidden", no_argument, 0, 'A'},
921 {"bookmarks-file", no_argument, 0, 'b'},
922 {"config-file", no_argument, 0, 'c'},
923 {"config-dir", required_argument, 0, 'D'},
924 {"no-eln", no_argument, 0, 'e'},
925 {"no-folders-first", no_argument, 0, 'f'},
926 {"folders-first", no_argument, 0, 'F'},
927 {"pager", no_argument, 0, 'g'},
928 {"no-pager", no_argument, 0, 'G'},
929 {"help", no_argument, 0, 'h'},
930 {"horizontal-list", no_argument, 0, 'H'},
931 {"no-case-sensitive", no_argument, 0, 'i'},
932 {"case-sensitive", no_argument, 0, 'I'},
933 {"keybindings-file", no_argument, 0, 'k'},
934 {"no-long-view", no_argument, 0, 'l'},
935 {"long-view", no_argument, 0, 'L'},
936 {"dirhist-map", no_argument, 0, 'm'},
937 {"no-autols", no_argument, 0, 'o'},
938 {"autols", no_argument, 0, 'O'},
939 {"path", required_argument, 0, 'p'},
940 {"profile", required_argument, 0, 'P'},
941 {"splash", no_argument, 0, 's'},
942 {"stealth-mode", no_argument, 0, 'S'},
943 {"unicode", no_argument, 0, 'U'},
944 {"no-unicode", no_argument, 0, 'u'},
945 {"version", no_argument, 0, 'v'},
946 {"workspace", required_argument, 0, 'w'},
947 {"no-ext-cmds", no_argument, 0, 'x'},
948 {"light-mode", no_argument, 0, 'y'},
949 {"sort", required_argument, 0, 'z'},
950
951 /* Only long options */
952 {"no-cd-auto", no_argument, 0, 0},
953 {"no-open-auto", no_argument, 0, 1},
954 {"no-restore-last-path", no_argument, 0, 2},
955 {"no-tips", no_argument, 0, 3},
956 {"disk-usage", no_argument, 0, 4},
957 {"no-classify", no_argument, 0, 6},
958 {"share-selbox", no_argument, 0, 7},
959 {"rl-vi-mode", no_argument, 0, 8},
960 {"max-dirhist", required_argument, 0, 9},
961 {"sort-reverse", no_argument, 0, 10},
962 {"no-files-counter", no_argument, 0, 11},
963 {"no-welcome-message", no_argument, 0, 12},
964 {"no-clear-screen", no_argument, 0, 13},
965 {"enable-logs", no_argument, 0, 15},
966 {"max-path", required_argument, 0, 16},
967 {"opener", required_argument, 0, 17},
968 {"expand-bookmarks", no_argument, 0, 18},
969 {"only-dirs", no_argument, 0, 19},
970 {"list-and-quit", no_argument, 0, 20},
971 {"color-scheme", required_argument, 0, 21},
972 {"cd-on-quit", no_argument, 0, 22},
973 {"no-dir-jumper", no_argument, 0, 23},
974 {"icons", no_argument, 0, 24},
975 {"icons-use-file-color", no_argument, 0, 25},
976 {"no-columns", no_argument, 0, 26},
977 {"no-colors", no_argument, 0, 27},
978 {"max-files", required_argument, 0, 28},
979 {"trash-as-rm", no_argument, 0, 29},
980 {"case-sens-dirjump", no_argument, 0, 30},
981 {"case-sens-path-comp", no_argument, 0, 31},
982 {"cwd-in-title", no_argument, 0, 32},
983 {"open", required_argument, 0, 33},
984 {"print-sel", no_argument, 0, 34},
985 {"no-suggestions", no_argument, 0, 35},
986 {"autojump", no_argument, 0, 36},
987 {"no-highlight", no_argument, 0, 37},
988 {"no-file-cap", no_argument, 0, 38},
989 {"no-file-ext", no_argument, 0, 39},
990 {"no-follow-symlink", no_argument, 0, 40},
991 {"control-d-exits", no_argument, 0, 41},
992 {"int-vars", no_argument, 0, 42},
993 {"fzftab", no_argument, 0, 43},
994 {"no-warning-prompt", no_argument, 0, 44},
995 {"mnt-udisks2", no_argument, 0, 45},
996 {0, 0, 0, 0}
997 };
998
999 /* Increment whenever a new (only) long option is added */
1000 int long_opts = 45;
1001 int optc;
1002 /* Variables to store arguments to options (-c, -p and -P) */
1003 char *path_value = (char *)NULL,
1004 *alt_profile_value = (char *)NULL,
1005 *alt_dir_value = (char *)NULL,
1006 *config_value = (char *)NULL,
1007 *kbinds_value = (char *)NULL,
1008 *bm_value = (char *)NULL;
1009
1010 while ((optc = getopt_long(argc, argv,
1011 "+aAb:c:D:efFgGhHiIk:lLmoOp:P:sSUuvw:xyz:", longopts,
1012 (int *)0)) != EOF) {
1013 /* ':' and '::' in the short options string means 'required' and
1014 * 'optional argument' respectivelly. Thus, 'p' and 'P' require
1015 * an argument here. The plus char (+) tells getopt to stop
1016 * processing at the first non-option (and non-argument) */
1017 switch (optc) {
1018
1019 case 0: xargs.autocd = autocd = 0; break;
1020 case 1: xargs.auto_open = auto_open = 0; break;
1021 case 2: xargs.restore_last_path = restore_last_path = 0; break;
1022 case 3: xargs.tips = tips = 0; break;
1023 case 4: xargs.disk_usage = disk_usage = 1; break;
1024
1025 case 6: xargs.classify = classify = 0; break;
1026 case 7: xargs.share_selbox = share_selbox = 1; break;
1027 case 8: xargs.rl_vi_mode = 1; break;
1028
1029 case 9: {
1030 if (!is_number(optarg))
1031 break;
1032 int opt_int = atoi(optarg);
1033 if (opt_int >= 0 && opt_int <= INT_MAX)
1034 xargs.max_dirhist = max_dirhist = opt_int;
1035 } break;
1036
1037 case 10: xargs.sort_reverse = sort_reverse = 1; break;
1038 case 11: xargs.files_counter = files_counter = 0; break;
1039 case 12: xargs.welcome_message = welcome_message = 0; break;
1040 case 13: xargs.clear_screen = clear_screen = 0; break;
1041
1042 case 15: xargs.logs = logs_enabled = 1; break;
1043
1044 case 16: {
1045 if (!is_number(optarg))
1046 break;
1047 int opt_int = atoi(optarg);
1048 if (opt_int >= 0 && opt_int <= INT_MAX)
1049 xargs.max_path = max_path = opt_int;
1050 } break;
1051
1052 case 17:
1053 if (*optarg == '~') {
1054 char *ep = tilde_expand(optarg);
1055 if (ep) {
1056 opener = savestring(ep, strlen(ep));
1057 free(ep);
1058 } else {
1059 _err('w', PRINT_PROMPT, _("%s: Error expanding tilde. "
1060 "Using default opener\n"), PROGRAM_NAME);
1061 }
1062 } else {
1063 opener = savestring(optarg, strlen(optarg));
1064 }
1065 break;
1066
1067 case 18: xargs.expand_bookmarks = expand_bookmarks = 1; break;
1068 case 19: xargs.only_dirs = only_dirs = 1; break;
1069 case 20: xargs.list_and_quit = 1; break;
1070 case 21: usr_cscheme = savestring(optarg, strlen(optarg)); break;
1071 case 22: xargs.cd_on_quit = cd_on_quit = 1; break;
1072 case 23: xargs.no_dirjump = 1; break;
1073 #ifndef _NO_ICONS
1074 case 24: xargs.icons = icons = 1; break;
1075 case 25:
1076 xargs.icons = icons = 1;
1077 xargs.icons_use_file_color = 1;
1078 break;
1079 #else
1080 case 24: /* fallthrough */
1081 case 25:
1082 fprintf(stderr, _("%s: icons: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE));
1083 exit(EXIT_FAILURE);
1084 #endif
1085 case 26:
1086 xargs.columns = 0;
1087 columned = 0;
1088 break;
1089
1090 case 27:
1091 xargs.colorize = 0;
1092 colorize = 0;
1093 #ifndef _NO_HIGHLIGHT
1094 xargs.highlight = highlight = 0;
1095 #endif
1096 break;
1097
1098 case 28:
1099 if (!is_number(optarg))
1100 break;
1101 int opt_int = atoi(optarg);
1102 if (opt_int >= 0 && opt_int <= INT_MAX)
1103 xargs.max_files = max_files = opt_int;
1104 break;
1105
1106 case 29:
1107 #ifndef _NO_TRASH
1108 xargs.trasrm = tr_as_rm = 1; break;
1109 #else
1110 fprintf(stderr, _("%s: trash: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE));
1111 exit(EXIT_FAILURE);
1112 #endif
1113 case 30: xargs.case_sens_dirjump = case_sens_dirjump = 1; break;
1114 case 31: xargs.case_sens_path_comp = case_sens_path_comp = 1; break;
1115 case 32: xargs.cwd_in_title = 1; break;
1116
1117 case 33: {
1118 struct stat attr;
1119 if (stat(optarg, &attr) == -1) {
1120 fprintf(stderr, "%s: %s: %s", PROGRAM_NAME, optarg,
1121 strerror(errno));
1122 exit(EXIT_FAILURE);
1123 }
1124
1125 if ((attr.st_mode & S_IFMT) != S_IFDIR) {
1126 open_reg_exit(optarg);
1127 } else {
1128 printf(_("%s: %s: Is a directory\n"), PROGRAM_NAME, optarg);
1129 exit(EXIT_FAILURE);
1130 }
1131
1132 /* flags |= START_PATH;
1133 path_value = optarg;
1134 xargs.path = 1; */
1135 } break;
1136
1137 case 34: xargs.printsel = 1; break;
1138 #ifndef _NO_SUGGESTIONS
1139 case 35: xargs.suggestions = suggestions = 0; break;
1140 #endif
1141 case 36: xargs.autojump = autojump = 0; break;
1142 #ifndef _NO_HIGHLIGHT
1143 case 37: xargs.highlight = highlight = 0; break;
1144 #else
1145 case 37:
1146 fprintf(stderr, _("%s: highlight: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE));
1147 exit(EXIT_FAILURE);
1148 #endif /* !_NO_HIGHLIGHT */
1149 case 38: xargs.check_cap = check_cap = 0; break;
1150 case 39: xargs.check_ext = check_ext = 0; break;
1151 case 40: xargs.follow_symlinks = follow_symlinks = 0; break;
1152 case 41: xargs.control_d_exits = control_d_exits = 1; break;
1153 case 42: xargs.int_vars = int_vars = 1; break;
1154 #ifndef _NO_FZF
1155 case 43: {
1156 char *p = get_cmd_path("fzf");
1157 if (p) {
1158 xargs.fzftab = 1;
1159 free(p);
1160 } else {
1161 _err('w', PRINT_PROMPT, _("%s: FZF not found. Falling back "
1162 "to standard TAB completion\n"), PROGRAM_NAME);
1163 }
1164 }
1165 break;
1166 #else
1167 case 43:
1168 fprintf(stderr, _("%s: fzftab: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE));
1169 exit(EXIT_FAILURE);
1170 #endif /* !_NO_FZF */
1171
1172 case 44: xargs.warning_prompt = warning_prompt = 0; break;
1173 case 45: xargs.mount_cmd = MNT_UDISKS2; break;
1174
1175 case 'a':
1176 flags &= ~HIDDEN; /* Remove HIDDEN from 'flags' */
1177 show_hidden = xargs.hidden = 0;
1178 break;
1179
1180 case 'A':
1181 flags |= HIDDEN; /* Add HIDDEN to 'flags' */
1182 show_hidden = xargs.hidden = 1;
1183 break;
1184
1185 case 'b':
1186 xargs.bm_file = 1;
1187 bm_value = optarg;
1188 break;
1189
1190 case 'c':
1191 xargs.config = 1;
1192 config_value = optarg;
1193 break;
1194
1195 case 'D': alt_dir_value = optarg; break;
1196 case 'e': xargs.noeln = no_eln = 1; break;
1197
1198 case 'f':
1199 flags &= ~FOLDERS_FIRST;
1200 list_folders_first = xargs.ffirst = 0;
1201 break;
1202
1203 case 'F':
1204 flags |= FOLDERS_FIRST;
1205 list_folders_first = xargs.ffirst = 1;
1206 break;
1207
1208 case 'g': pager = xargs.pager = 1; break;
1209 case 'G': pager = xargs.pager = 0; break;
1210
1211 case 'h':
1212 flags |= HELP;
1213 /* Do not display "Press any key to continue" */
1214 flags |= EXT_HELP;
1215 help_function();
1216 exit(EXIT_SUCCESS);
1217
1218 case 'H': xargs.horizontal_list = 1; listing_mode = HORLIST; break;
1219
1220 case 'i':
1221 flags &= ~CASE_SENS;
1222 case_sensitive = xargs.sensitive = 0;
1223 break;
1224
1225 case 'I':
1226 flags |= CASE_SENS;
1227 case_sensitive = xargs.sensitive = 1;
1228 break;
1229
1230 case 'k': kbinds_value = optarg; break;
1231 case 'l': long_view = xargs.longview = 0; break;
1232 case 'L': long_view = xargs.longview = 1; break;
1233 case 'm': dirhist_map = xargs.dirmap = 1; break;
1234
1235 case 'o':
1236 flags &= ~AUTOLS;
1237 autols = xargs.autols = 0;
1238 break;
1239
1240 case 'O':
1241 flags |= AUTOLS;
1242 autols = xargs.autols = 1;
1243 break;
1244
1245 case 'p':
1246 flags |= START_PATH;
1247 path_value = optarg;
1248 xargs.path = 1;
1249 break;
1250
1251 case 'P':
1252 flags |= ALT_PROFILE;
1253 alt_profile_value = optarg;
1254 break;
1255
1256 case 's':
1257 flags |= SPLASH;
1258 splash_screen = xargs.splash = 1;
1259 break;
1260
1261 case 'S': xargs.stealth_mode = 1; break;
1262 case 'u': unicode = xargs.unicode = 0; break;
1263 case 'U': unicode = xargs.unicode = 1; break;
1264
1265 case 'v':
1266 flags |= PRINT_VERSION;
1267 version_function();
1268 exit(EXIT_SUCCESS);
1269
1270 case 'w': {
1271 if (!is_number(optarg))
1272 break;
1273 int iopt = atoi(optarg);
1274
1275 if (iopt >= 0 && iopt <= MAX_WS)
1276 cur_ws = iopt - 1;
1277 } break;
1278
1279 case 'x': ext_cmd_ok = xargs.ext = 0; break;
1280 case 'y': light_mode = xargs.light = 1; break;
1281
1282 case 'z': {
1283 if (!is_number(optarg))
1284 break;
1285 int arg = atoi(optarg);
1286 if (arg < 0 || arg > SORT_TYPES)
1287 sort = 1;
1288 else
1289 sort = arg;
1290 xargs.sort = sort;
1291 } break;
1292
1293 case '?': /* If some unrecognized option was found... */
1294
1295 /* Options that requires an argument */
1296 /* Short options */
1297 switch (optopt) {
1298 case 'b': /* fallthrough */
1299 case 'c': /* fallthrough */
1300 case 'k': /* fallthrough */
1301 case 'p': /* fallthrough */
1302 case 'P': /* fallthrough */
1303 case 'w': /* fallthrough */
1304 case 'z':
1305 fprintf(stderr, _("%s: option requires an argument -- "
1306 "'%c'\nTry '%s --help' for more information.\n"),
1307 PROGRAM_NAME, optopt, PNL);
1308 exit(EXIT_FAILURE);
1309 }
1310
1311 /* Long options */
1312 if (optopt >= 0 && optopt <= long_opts) {
1313 fprintf(stderr, _("%s: unrecognized option '%s'\n"
1314 "Try '%s --help' for more information.\n"),
1315 PROGRAM_NAME, argv[optind - 1], PNL);
1316 exit(EXIT_FAILURE);
1317 }
1318
1319 /* If unknown option is printable... */
1320 if (isprint(optopt)) {
1321 fprintf(stderr, _("%s: unrecognized option '%c'\n"
1322 "Try '%s --help' for more information.\n"),
1323 PROGRAM_NAME, optopt, PNL);
1324 } else {
1325 fprintf(stderr, _("%s: unknown option character '\\%x'\n"),
1326 PROGRAM_NAME, (unsigned int)optopt);
1327 }
1328
1329 exit(EXIT_FAILURE);
1330
1331 default:
1332 break;
1333 }
1334 }
1335
1336 /* Positional parameters. If a directory, use it as CliFM starting
1337 * path. Otherwise, open the file with the associated application
1338 * and exit */
1339 int i = optind;
1340 if (argv[i]) {
1341 struct stat attr;
1342 char *_exp_path = tilde_expand(argv[i]);
1343 if (_exp_path) {
1344 if (stat(_exp_path, &attr) == -1) {
1345 fprintf(stderr, "%s: %s: %s", PROGRAM_NAME, _exp_path,
1346 strerror(errno));
1347 free(_exp_path);
1348 exit(EXIT_FAILURE);
1349 }
1350 free(_exp_path);
1351 } else {
1352 fprintf(stderr, _("%s: Error expanding tilde\n"), PROGRAM_NAME);
1353 exit(EXIT_FAILURE);
1354 }
1355
1356 if ((attr.st_mode & S_IFMT) != S_IFDIR)
1357 open_reg_exit(argv[i]);
1358
1359 flags |= START_PATH;
1360 path_value = argv[i];
1361 xargs.path = 1;
1362 }
1363
1364 if (bm_value) {
1365 char *bm_exp = (char *)NULL;
1366
1367 if (*bm_value == '~') {
1368 bm_exp = tilde_expand(bm_value);
1369 bm_value = bm_exp;
1370 }
1371
1372 if (access(bm_value, R_OK) == -1) {
1373 _err('e', PRINT_PROMPT, _("%s: %s: %s\n"
1374 "Falling back to the default bookmarks file\n"),
1375 PROGRAM_NAME, bm_value, strerror(errno));
1376 } else {
1377 alt_bm_file = savestring(bm_value, strlen(bm_value));
1378 _err('n', PRINT_PROMPT, _("%s: Loaded alternative "
1379 "bookmarks file\n"), PROGRAM_NAME);
1380 }
1381 }
1382
1383 if (alt_dir_value) {
1384 char *dir_exp = (char *)NULL;
1385
1386 if (*alt_dir_value == '~') {
1387 dir_exp = tilde_expand(alt_dir_value);
1388 alt_dir_value = dir_exp;
1389 }
1390
1391 int dir_ok = 1;
1392 struct stat attr;
1393 if (stat(alt_dir_value, &attr) == -1) {
1394 char *tmp_cmd[] = {"mkdir", "-p", alt_dir_value, NULL};
1395 int ret = launch_execve(tmp_cmd, FOREGROUND, E_NOSTDERR);
1396 if (ret != EXIT_SUCCESS) {
1397 _err('e', PRINT_PROMPT, _("%s: %s: Cannot create directory "
1398 "(error %d)\nFalling back to default configuration directory\n"),
1399 PROGRAM_NAME, alt_dir_value, ret);
1400 dir_ok = 0;
1401 }
1402 }
1403
1404 if (access(alt_dir_value, W_OK) == -1) {
1405 if (dir_ok) {
1406 _err('e', PRINT_PROMPT, _("%s: %s: %s\n"
1407 "Falling back to default configuration directory\n"),
1408 PROGRAM_NAME, alt_dir_value, strerror(errno));
1409 }
1410 } else {
1411 alt_config_dir = savestring(alt_dir_value, strlen(alt_dir_value));
1412 _err(0, PRINT_PROMPT, _("%s: %s: Using alternative "
1413 "configuration directory\n"), PROGRAM_NAME, alt_config_dir);
1414 }
1415
1416 if (dir_exp)
1417 free(dir_exp);
1418 }
1419
1420 if (kbinds_value) {
1421 char *kbinds_exp = (char *)NULL;
1422 if (*kbinds_value == '~') {
1423 kbinds_exp = tilde_expand(kbinds_value);
1424 kbinds_value = kbinds_exp;
1425 }
1426
1427 /* if (alt_kbinds_file) {
1428 free(alt_kbinds_file);
1429 alt_kbinds_file = (char *)NULL;
1430 } */
1431
1432 if (access(kbinds_value, R_OK) == -1) {
1433 _err('e', PRINT_PROMPT, _("%s: %s: %s\n"
1434 "Falling back to the default keybindings file\n"),
1435 PROGRAM_NAME, kbinds_value, strerror(errno));
1436 /* xargs.config = -1; */
1437 } else {
1438 alt_kbinds_file = savestring(kbinds_value, strlen(kbinds_value));
1439 _err('n', PRINT_PROMPT, _("%s: Loaded alternative "
1440 "keybindings file\n"), PROGRAM_NAME);
1441 }
1442
1443 if (kbinds_exp)
1444 free(kbinds_exp);
1445 }
1446
1447 if (xargs.config && config_value) {
1448 char *config_exp = (char *)NULL;
1449
1450 if (*config_value == '~') {
1451 config_exp = tilde_expand(config_value);
1452 config_value = config_exp;
1453 }
1454
1455 /* if (alt_config_file) {
1456 free(alt_config_file);
1457 alt_config_file = (char *)NULL;
1458 } */
1459
1460 if (access(config_value, R_OK) == -1) {
1461 _err('e', PRINT_PROMPT, _("%s: %s: %s\n"
1462 "Falling back to default\n"), PROGRAM_NAME,
1463 config_value, strerror(errno));
1464 xargs.config = -1;
1465 } else {
1466 alt_config_file = savestring(config_value, strlen(config_value));
1467 _err('n', PRINT_PROMPT, _("%s: Loaded alternative "
1468 "configuration file\n"), PROGRAM_NAME);
1469 }
1470
1471 if (config_exp)
1472 free(config_exp);
1473 }
1474
1475 if ((flags & START_PATH) && path_value) {
1476 char *path_exp = (char *)NULL;
1477 char path_tmp[PATH_MAX];
1478
1479 if (*path_value == '~') {
1480 path_exp = tilde_expand(path_value);
1481 xstrsncpy(path_tmp, path_exp, PATH_MAX);
1482 } else if (*path_value != '/') {
1483 snprintf(path_tmp, PATH_MAX - 1, "%s/%s", getenv("PWD"), path_value);
1484 } else {
1485 xstrsncpy(path_tmp, path_value, PATH_MAX);
1486 }
1487
1488 if (xchdir(path_tmp, SET_TITLE) == 0) {
1489 if (cur_ws == UNSET)
1490 cur_ws = DEF_CUR_WS;
1491 if (ws[cur_ws].path)
1492 free(ws[cur_ws].path);
1493
1494 ws[cur_ws].path = savestring(path_tmp, strlen(path_tmp));
1495 } else { /* Error changing directory */
1496 if (xargs.list_and_quit == 1) {
1497 fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME,
1498 path_tmp, strerror(errno));
1499 exit(EXIT_FAILURE);
1500 }
1501
1502 _err('w', PRINT_PROMPT, "%s: %s: %s\n", PROGRAM_NAME,
1503 path_tmp, strerror(errno));
1504 }
1505
1506 if (path_exp)
1507 free(path_exp);
1508 }
1509
1510 if ((flags & ALT_PROFILE) && alt_profile_value) {
1511 if (alt_profile)
1512 free(alt_profile);
1513 alt_profile = savestring(alt_profile_value, strlen(alt_profile_value));
1514 }
1515 }
1516
1517 void
unset_xargs(void)1518 unset_xargs(void)
1519 {
1520 xargs.auto_open = UNSET;
1521 xargs.autocd = UNSET;
1522 xargs.autojump = UNSET;
1523 xargs.autols= UNSET;
1524 xargs.bm_file = UNSET;
1525 xargs.case_sens_dirjump = UNSET;
1526 xargs.case_sens_path_comp = UNSET;
1527 xargs.check_cap = UNSET;
1528 xargs.check_ext = UNSET;
1529 xargs.cd_on_quit = UNSET;
1530 xargs.classify = UNSET;
1531 xargs.clear_screen = UNSET;
1532 xargs.color_scheme = UNSET;
1533 xargs.config = UNSET;
1534 xargs.control_d_exits = UNSET;
1535 xargs.cwd_in_title = UNSET;
1536 xargs.dirmap = UNSET;
1537 xargs.disk_usage = UNSET;
1538 xargs.expand_bookmarks = UNSET;
1539 xargs.ext = UNSET;
1540 xargs.ffirst = UNSET;
1541 xargs.files_counter = UNSET;
1542 xargs.follow_symlinks = UNSET;
1543 #ifndef _NO_FZF
1544 xargs.fzftab = UNSET;
1545 #endif
1546 xargs.hidden = UNSET;
1547 #ifndef _NO_HIGHLIGHT
1548 xargs.highlight = UNSET;
1549 #endif
1550 xargs.horizontal_list = UNSET;
1551 #ifndef _NO_ICONS
1552 xargs.icons = UNSET;
1553 xargs.icons_use_file_color = UNSET;
1554 #endif
1555 xargs.int_vars = UNSET;
1556 xargs.light = UNSET;
1557 xargs.list_and_quit = UNSET;
1558 xargs.logs = UNSET;
1559 xargs.longview = UNSET;
1560 xargs.max_dirhist = UNSET;
1561 xargs.max_path = UNSET;
1562 xargs.mount_cmd = UNSET;
1563 xargs.colorize = UNSET;
1564 xargs.columns = UNSET;
1565 xargs.no_dirjump = UNSET;
1566 xargs.noeln = UNSET;
1567 xargs.only_dirs = UNSET;
1568 xargs.path = UNSET;
1569 xargs.pager = UNSET;
1570 xargs.printsel = UNSET;
1571 xargs.restore_last_path = UNSET;
1572 xargs.rl_vi_mode = UNSET;
1573 xargs.sensitive = UNSET;
1574 xargs.share_selbox = UNSET;
1575 xargs.sort = UNSET;
1576 xargs.sort_reverse = UNSET;
1577 xargs.splash = UNSET;
1578 xargs.stealth_mode = UNSET;
1579 #ifndef _NO_SUGGESTIONS
1580 xargs.suggestions = UNSET;
1581 #endif
1582 xargs.tips = UNSET;
1583 #ifndef _NO_TRASH
1584 xargs.trasrm = UNSET;
1585 #endif
1586 xargs.unicode = UNSET;
1587 xargs.welcome_message = UNSET;
1588 xargs.warning_prompt = UNSET;
1589 }
1590
1591 /* Keep track of attributes of the shell. Make sure the shell is running
1592 * interactively as the foreground job before proceeding.
1593 * Taken from:
1594 * https://www.gnu.org/software/libc/manual/html_node/Initializing-the-Shell.html#Initializing-the-Shell
1595 * */
1596 void
init_shell(void)1597 init_shell(void)
1598 {
1599 /* If shell is not interactive */
1600 if (!isatty(STDIN_FILENO)) {
1601 handle_stdin();
1602 return;
1603 }
1604
1605 /* Loop until we are in the foreground */
1606 while (tcgetpgrp(STDIN_FILENO) != (own_pid = getpgrp()))
1607 kill(-own_pid, SIGTTIN);
1608
1609 /* Ignore interactive and job-control signals */
1610 set_signals_to_ignore();
1611 /* Put ourselves in our own process group */
1612 own_pid = get_own_pid();
1613
1614 if (flags & ROOT_USR) {
1615 /* Make the shell pgid (process group id) equal to its pid */
1616 /* Without the setpgid line below, the program cannot be run
1617 * with sudo, but it can be run nonetheless by the root user */
1618 if (setpgid(own_pid, own_pid) < 0) {
1619 _err(0, NOPRINT_PROMPT, "%s: setpgid: %s\n", PROGRAM_NAME,
1620 strerror(errno));
1621 exit(EXIT_FAILURE);
1622 }
1623 }
1624
1625 /* Grab control of the terminal */
1626 tcsetpgrp(STDIN_FILENO, own_pid);
1627 /* Save default terminal attributes for shell */
1628 tcgetattr(STDIN_FILENO, &shell_tmodes);
1629 return;
1630 }
1631
1632 /* Get current entries in the Selection Box, if any. */
1633 int
get_sel_files(void)1634 get_sel_files(void)
1635 {
1636 if (!selfile_ok || !config_ok || !sel_file)
1637 return EXIT_FAILURE;
1638
1639 /* First, clear the sel array, in case it was already used */
1640 if (sel_n > 0) {
1641 int i = (int)sel_n;
1642 while (--i >= 0)
1643 free(sel_elements[i]);
1644 }
1645
1646 /* free(sel_elements); */
1647
1648 sel_n = 0;
1649
1650 /* Open the tmp sel file and load its contents into the sel array */
1651 int fd;
1652 FILE *fp = open_fstream_r(sel_file, &fd);
1653 /* sel_elements = xcalloc(1, sizeof(char *)); */
1654 if (!fp)
1655 return EXIT_FAILURE;
1656
1657 struct stat a;
1658 /* Since this file contains only paths, we can be sure no line
1659 * length will be larger than PATH_MAX */
1660 char line[PATH_MAX] = "";
1661 while (fgets(line, (int)sizeof(line), fp)) {
1662 size_t len = strlen(line);
1663
1664 if (line[len - 1] == '\n')
1665 line[--len] = '\0';
1666
1667 /* Remove the ending slash: fstatat() won't take a symlink to dir as
1668 * a symlink (but as a dir), if the file name ends with a slash */
1669 if (line[len - 1] == '/')
1670 line[--len] = '\0';
1671
1672 if (!*line || *line == '#')
1673 continue;
1674
1675 sel_elements = (char **)xrealloc(sel_elements, (sel_n + 1) * sizeof(char *));
1676 sel_elements[sel_n] = savestring(line, len);
1677 /* Store device and inode number to identify later selected files
1678 * and mark them in the files list */
1679 if (fstatat(AT_FDCWD, line, &a, AT_SYMLINK_NOFOLLOW) != -1) {
1680 sel_devino = (struct devino_t *)xrealloc(sel_devino, (sel_n + 1) * sizeof(struct devino_t));
1681 sel_devino[sel_n].ino = a.st_ino;
1682 sel_devino[sel_n].dev = a.st_dev;
1683 }
1684 sel_n++;
1685 }
1686
1687 close_fstream(fp, fd);
1688 return EXIT_SUCCESS;
1689 }
1690
1691 size_t
get_cdpath(void)1692 get_cdpath(void)
1693 {
1694 char *p = getenv("CDPATH");
1695 if (!p || !*p)
1696 return 0;
1697
1698 char *t = savestring(p, strlen(p));
1699
1700 /* Get each path in CDPATH */
1701 size_t i, n = 0, len = 0;
1702 for (i = 0; t[i]; i++) {
1703 /* Store path in CDPATH in a tmp buffer */
1704 char buf[PATH_MAX];
1705 while (t[i] && t[i] != ':')
1706 buf[len++] = t[i++];
1707 buf[len] = '\0';
1708
1709 /* Make room in cdpaths for a new path */
1710 cdpaths = (char **)xrealloc(cdpaths, (n + 2) * sizeof(char *));
1711
1712 /* Dump the buffer into the global cdpaths array */
1713 cdpaths[n++] = savestring(buf, len);
1714
1715 len = 0;
1716 if (!t[i])
1717 break;
1718 }
1719
1720 cdpaths[n] = (char *)NULL;
1721
1722 free(t);
1723 return n;
1724 }
1725
1726 /* Store all paths in the PATH environment variable into a globally
1727 * declared array (paths) */
1728 size_t
get_path_env(void)1729 get_path_env(void)
1730 {
1731 size_t i = 0;
1732 /* Get the value of the PATH env variable */
1733 char *path_tmp = (char *)NULL;
1734 char *ptr = getenv("PATH");
1735 if (!ptr || !*ptr)
1736 return 0;
1737 path_tmp = savestring(ptr, strlen(ptr));
1738
1739 if (!path_tmp)
1740 return 0;
1741
1742 /* Get each path in PATH */
1743 size_t path_num = 0, length = 0;
1744 for (i = 0; path_tmp[i]; i++) {
1745 /* Store path in PATH in a tmp buffer */
1746 char buf[PATH_MAX];
1747 while (path_tmp[i] && path_tmp[i] != ':')
1748 buf[length++] = path_tmp[i++];
1749 buf[length] = '\0';
1750
1751 /* Make room in paths for a new path */
1752 paths = (char **)xrealloc(paths, (path_num + 1) * sizeof(char *));
1753
1754 /* Dump the buffer into the global paths array */
1755 paths[path_num] = savestring(buf, length);
1756
1757 path_num++;
1758 length = 0;
1759 if (!path_tmp[i])
1760 break;
1761 }
1762
1763 free(path_tmp);
1764 return path_num;
1765 }
1766
1767 /* Set PATH to last visited directory and CUR_WS to last used
1768 * workspace */
1769 int
get_last_path(void)1770 get_last_path(void)
1771 {
1772 if (!config_dir)
1773 return EXIT_FAILURE;
1774
1775 char *last_file = (char *)xnmalloc(strlen(config_dir) + 7, sizeof(char));
1776 sprintf(last_file, "%s/.last", config_dir);
1777
1778 int fd;
1779 FILE *fp = open_fstream_r(last_file, &fd);
1780 if (!fp) {
1781 free(last_file);
1782 return EXIT_FAILURE;
1783 }
1784
1785 /* size_t i;
1786 for (i = 0; i < MAX_WS; i++) {
1787
1788 if (ws[i].path) {
1789 free(ws[i].path);
1790 ws[i].path = (char *)NULL;
1791 }
1792 } */
1793
1794 char line[PATH_MAX] = "";
1795 while (fgets(line, (int)sizeof(line), fp)) {
1796 char *p = line;
1797 if (!*p || !strchr(p, '/'))
1798 continue;
1799 if (!strchr(p, ':'))
1800 continue;
1801
1802 size_t len = strlen(p);
1803 if (p[len - 1] == '\n')
1804 p[len - 1] = '\0';
1805
1806 int cur = 0;
1807 if (*p == '*') {
1808 if (!*(++p))
1809 continue;
1810 cur = 1;
1811 }
1812
1813 int ws_n = *p - '0';
1814 if (cur && cur_ws == UNSET)
1815 cur_ws = ws_n;
1816
1817 if (ws_n >= 0 && ws_n < MAX_WS && !ws[ws_n].path)
1818 ws[ws_n].path = savestring(p + 2, strlen(p + 2));
1819 }
1820
1821 close_fstream(fp, fd);
1822 free(last_file);
1823 return EXIT_SUCCESS;
1824 }
1825
1826 /* Restore pinned dir from file */
1827 int
load_pinned_dir(void)1828 load_pinned_dir(void)
1829 {
1830 if (!config_ok)
1831 return EXIT_FAILURE;
1832
1833 char *pin_file = (char *)xnmalloc(strlen(config_dir) + 6, sizeof(char));
1834 sprintf(pin_file, "%s/.pin", config_dir);
1835
1836 int fd;
1837 FILE *fp = open_fstream_r(pin_file, &fd);
1838 if (!fp) {
1839 free(pin_file);
1840 return EXIT_FAILURE;
1841 }
1842
1843 char line[PATH_MAX] = "";
1844 if (fgets(line, (int)sizeof(line), fp) == NULL) {
1845 free(pin_file);
1846 close_fstream(fp, fd);
1847 return EXIT_FAILURE;
1848 }
1849
1850 if (!*line || !strchr(line, '/')) {
1851 free(pin_file);
1852 close_fstream(fp, fd);
1853 return EXIT_FAILURE;
1854 }
1855
1856 if (pinned_dir) {
1857 free(pinned_dir);
1858 pinned_dir = (char *)NULL;
1859 }
1860
1861 pinned_dir = savestring(line, strlen(line));
1862 close_fstream(fp, fd);
1863 free(pin_file);
1864 return EXIT_SUCCESS;
1865 }
1866
1867 /* Get the list of files in PATH, plus CliFM internal commands, and send
1868 * them into an array to be read by my readline custom auto-complete
1869 * function (my_rl_completion) */
1870 void
get_path_programs(void)1871 get_path_programs(void)
1872 {
1873 int i, l = 0, total_cmd = 0;
1874 int *cmd_n = (int *)0;
1875 struct dirent ***commands_bin = (struct dirent ***)NULL;
1876
1877 if (ext_cmd_ok) {
1878 char cwd[PATH_MAX] = "";
1879 if (getcwd(cwd, sizeof(cwd)) == NULL) {}
1880
1881 commands_bin = (struct dirent ***)xnmalloc(
1882 path_n, sizeof(struct dirent));
1883 cmd_n = (int *)xnmalloc(path_n, sizeof(int));
1884
1885 i = (int)path_n;
1886 while (--i >= 0) {
1887 if (!paths[i] || !*paths[i] || xchdir(paths[i], NO_TITLE) == -1) {
1888 cmd_n[i] = 0;
1889 continue;
1890 }
1891
1892 cmd_n[i] = scandir(paths[i], &commands_bin[i],
1893 light_mode ? NULL : skip_nonexec, xalphasort);
1894 /* If paths[i] directory does not exist, scandir returns -1.
1895 * Fedora, for example, adds $HOME/bin and $HOME/.local/bin to
1896 * PATH disregarding if they exist or not. If paths[i] dir is
1897 * empty do not use it either */
1898 if (cmd_n[i] > 0)
1899 total_cmd += cmd_n[i];
1900 }
1901 xchdir(cwd, NO_TITLE);
1902 }
1903
1904 /* Add internal commands */
1905 size_t internal_cmd_n = 0;
1906 while (internal_cmds[internal_cmd_n])
1907 internal_cmd_n++;
1908
1909 bin_commands = (char **)xnmalloc((size_t)total_cmd + internal_cmd_n +
1910 aliases_n + actions_n + 2, sizeof(char *));
1911
1912 i = (int)internal_cmd_n;
1913 while (--i >= 0)
1914 bin_commands[l++] = savestring(internal_cmds[i],
1915 strlen(internal_cmds[i]));
1916
1917 /* Now add aliases, if any */
1918 if (aliases_n) {
1919 i = (int)aliases_n;
1920 while (--i >= 0) {
1921 bin_commands[l++] = savestring(aliases[i].name,
1922 strlen(aliases[i].name));
1923 }
1924 }
1925
1926 /* And user defined actions too, if any */
1927 if (actions_n) {
1928 i = (int)actions_n;
1929 while (--i >= 0) {
1930 bin_commands[l++] = savestring(usr_actions[i].name,
1931 strlen(usr_actions[i].name));
1932 }
1933 }
1934
1935 if (ext_cmd_ok && total_cmd) {
1936 /* And finally, add commands in PATH */
1937 i = (int)path_n;
1938 while (--i >= 0) {
1939 if (!cmd_n[i] || cmd_n[i] <= 0)
1940 continue;
1941
1942 int j = cmd_n[i];
1943 while (--j >= 0) {
1944 bin_commands[l++] = savestring(commands_bin[i][j]->d_name,
1945 strlen(commands_bin[i][j]->d_name));
1946 free(commands_bin[i][j]);
1947 }
1948
1949 free(commands_bin[i]);
1950 }
1951
1952 free(commands_bin);
1953 free(cmd_n);
1954 }
1955
1956 path_progsn = (size_t)l;
1957 bin_commands[l] = (char *)NULL;
1958 }
1959
1960 void
get_aliases(void)1961 get_aliases(void)
1962 {
1963 if (!config_ok)
1964 return;
1965
1966 int fd;
1967 FILE *fp = open_fstream_r(config_file, &fd);
1968 if (!fp) {
1969 _err('e', PRINT_PROMPT, "%s: alias: '%s': %s\n",
1970 PROGRAM_NAME, config_file, strerror(errno));
1971 return;
1972 }
1973
1974
1975 /* Free the aliases struct array */
1976 if (aliases_n) {
1977 int i = (int)aliases_n;
1978 while (--i >= 0) {
1979 free(aliases[i].name);
1980 free(aliases[i].cmd);
1981 }
1982
1983 free(aliases);
1984 aliases = (struct alias_t *)xnmalloc(1, sizeof(struct alias_t));
1985 aliases_n = 0;
1986 }
1987
1988 char *line = (char *)NULL;
1989 size_t line_size = 0;
1990
1991 while (getline(&line, &line_size, fp) > 0) {
1992 if (*line == 'a' && strncmp(line, "alias ", 6) == 0) {
1993 char *s = strchr(line, ' ');
1994 if (!s || !*(++s))
1995 continue;
1996 char *p = strchr(s, '=');
1997 if (!p || !*(p + 1))
1998 continue;
1999 *(p++) = '\0';
2000
2001 /* Skip duplicated aliases names */
2002 int i = (int)aliases_n, exists = 0;
2003 while (--i >= 0) {
2004 if (!aliases[i].name)
2005 continue;
2006 if (*s == *aliases[i].name && strcmp(s, aliases[i].name) == 0) {
2007 exists = 1;
2008 break;
2009 }
2010 }
2011 if (exists)
2012 continue;
2013
2014 aliases = (struct alias_t *)xrealloc(aliases, (aliases_n + 1)
2015 * sizeof(struct alias_t));
2016 aliases[aliases_n].name = savestring(s, strlen(s));
2017 if (*p == '\'')
2018 aliases[aliases_n++].cmd = strbtw(p, '\'', '\'');
2019 else if (*p == '"')
2020 aliases[aliases_n++].cmd = strbtw(p, '"', '"');
2021 }
2022 }
2023
2024 free(line);
2025 close_fstream(fp, fd);
2026 }
2027
2028 int
load_dirhist(void)2029 load_dirhist(void)
2030 {
2031 if (!config_ok)
2032 return EXIT_FAILURE;
2033
2034 int fd;
2035 FILE *fp = open_fstream_r(dirhist_file, &fd);
2036 if (!fp)
2037 return EXIT_FAILURE;
2038
2039 size_t dirs = 0;
2040
2041 char tmp_line[PATH_MAX];
2042 while (fgets(tmp_line, (int)sizeof(tmp_line), fp))
2043 dirs++;
2044
2045 if (!dirs) {
2046 close_fstream(fp, fd);
2047 return EXIT_SUCCESS;
2048 }
2049
2050 old_pwd = (char **)xnmalloc(dirs + 2, sizeof(char *));
2051
2052 fseek(fp, 0L, SEEK_SET);
2053
2054 size_t line_size = 0;
2055 char *line = (char *)NULL;
2056 ssize_t line_len = 0;
2057
2058 dirhist_total_index = 0;
2059
2060 while ((line_len = getline(&line, &line_size, fp)) > 0) {
2061 if (!line || !*line || *line == '\n')
2062 continue;
2063 if (line[line_len - 1] == '\n')
2064 line[line_len - 1] = '\0';
2065 old_pwd[dirhist_total_index] = (char *)xnmalloc((size_t)line_len + 1,
2066 sizeof(char));
2067 strcpy(old_pwd[dirhist_total_index++], line);
2068 }
2069
2070 close_fstream(fp, fd);
2071 old_pwd[dirhist_total_index] = (char *)NULL;
2072 free(line);
2073 dirhist_cur_index = dirhist_total_index - 1;
2074 return EXIT_SUCCESS;
2075 }
2076
2077 void
get_prompt_cmds(void)2078 get_prompt_cmds(void)
2079 {
2080 if (!config_ok)
2081 return;
2082
2083 int fd;
2084 FILE *fp = open_fstream_r(config_file, &fd);
2085 if (!fp) {
2086 _err('e', PRINT_PROMPT, "%s: prompt: '%s': %s\n",
2087 PROGRAM_NAME, config_file, strerror(errno));
2088 return;
2089 }
2090
2091 if (prompt_cmds_n) {
2092 size_t i;
2093 for (i = 0; i < prompt_cmds_n; i++)
2094 free(prompt_cmds[i]);
2095 free(prompt_cmds);
2096 prompt_cmds = (char **)NULL;
2097 prompt_cmds_n = 0;
2098 }
2099
2100 // int prompt_line_found = 0;
2101 char *line = (char *)NULL;
2102 size_t line_size = 0;
2103 ssize_t line_len = 0;
2104
2105 while ((line_len = getline(&line, &line_size, fp)) > 0) {
2106 if (*line != 'p' || strncmp(line, "promptcmd ", 10) != 0)
2107 continue;
2108 if (line[line_len - 1] == '\n')
2109 line[line_len - 1] = '\0';
2110 if (!(*line + 10))
2111 continue;
2112 prompt_cmds = (char **)xrealloc(prompt_cmds,
2113 (prompt_cmds_n + 1) * sizeof(char *));
2114 prompt_cmds[prompt_cmds_n++] = savestring(
2115 line + 10, (size_t)line_len - 10);
2116
2117 /* if (prompt_line_found) {
2118 if (strncmp(line, "#END OF PROMPT", 14) == 0)
2119 break;
2120 if (*line != '#') {
2121 prompt_cmds = (char **)xrealloc(prompt_cmds,
2122 (prompt_cmds_n + 1) * sizeof(char *));
2123 prompt_cmds[prompt_cmds_n++] = savestring(
2124 line, (size_t)line_len);
2125 }
2126 } else if (strncmp(line, "#PROMPT", 7) == 0) {
2127 prompt_line_found = 1;
2128 } */
2129 }
2130
2131 free(line);
2132 close_fstream(fp, fd);
2133 }
2134
2135 /* If some option was not set, set it to the default value */
2136 void
check_options(void)2137 check_options(void)
2138 {
2139 if (!usr_cscheme)
2140 usr_cscheme = savestring("default", 7);
2141
2142 if (!fzftab_options)
2143 fzftab_options = savestring(DEF_FZFTAB_OPTIONS, strlen(DEF_FZFTAB_OPTIONS));
2144
2145 if (!wprompt_str)
2146 wprompt_str = savestring(DEF_WPROMPT_STR, strlen(DEF_WPROMPT_STR));
2147
2148 /* Do no override command line options */
2149 if (xargs.cwd_in_title == UNSET)
2150 xargs.cwd_in_title = DEF_CWD_IN_TITLE;
2151
2152 /* if (xargs.mount_cmd == UNSET)
2153 xargs.mount_cmd = DEF_MOUNT_CMD; */
2154
2155 if (xargs.control_d_exits == UNSET)
2156 control_d_exits = DEF_CONTROL_D_EXITS;
2157
2158 if (elnpad == UNSET)
2159 elnpad = DEF_ELNPAD;
2160
2161 if (cp_cmd == UNSET)
2162 cp_cmd = DEF_CP_CMD;
2163
2164 if (check_cap == UNSET)
2165 check_cap = DEF_CHECK_CAP;
2166
2167 if (check_ext == UNSET)
2168 check_ext = DEF_CHECK_EXT;
2169
2170 if (follow_symlinks == UNSET)
2171 follow_symlinks = DEF_FOLLOW_SYMLINKS;
2172
2173 if (mv_cmd == UNSET)
2174 mv_cmd = DEF_MV_CMD;
2175
2176 if (min_name_trim == UNSET)
2177 min_name_trim = DEF_MIN_NAME_TRIM;
2178
2179 if (min_jump_rank == UNSET)
2180 min_jump_rank = DEF_MIN_JUMP_RANK;
2181
2182 if (max_jump_total_rank == UNSET)
2183 max_jump_total_rank = DEF_MAX_JUMP_TOTAL_RANK;
2184
2185 if (no_eln == UNSET) {
2186 if (xargs.noeln == UNSET)
2187 no_eln = DEF_NOELN;
2188 else
2189 no_eln = xargs.noeln;
2190 }
2191
2192 if (prompt_style == UNSET)
2193 prompt_style = DEF_PROMPT_STYLE;
2194
2195 #ifndef _NO_HIGHLIGHT
2196 if (highlight == UNSET) {
2197 if (xargs.highlight == UNSET)
2198 highlight = DEF_HIGHLIGHT;
2199 else
2200 highlight = xargs.highlight;
2201 }
2202 #endif
2203
2204 if (warning_prompt == UNSET) {
2205 if (xargs.warning_prompt == UNSET)
2206 warning_prompt = DEF_WARNING_PROMPT;
2207 else
2208 warning_prompt = xargs.warning_prompt;
2209 }
2210
2211 if (listing_mode == UNSET) {
2212 if (xargs.horizontal_list == UNSET)
2213 listing_mode = DEF_LISTING_MODE;
2214 else
2215 listing_mode = xargs.horizontal_list ? 1 : 0;
2216 }
2217
2218 #ifndef _NO_FZF
2219 if (fzftab == UNSET) {
2220 if (xargs.fzftab == UNSET)
2221 fzftab = DEF_FZFTAB;
2222 else
2223 fzftab = xargs.fzftab;
2224 }
2225 #endif
2226
2227 #ifndef _NO_ICONS
2228 if (icons == UNSET) {
2229 if (xargs.icons == UNSET)
2230 icons = DEF_ICONS;
2231 else
2232 icons = xargs.icons;
2233 }
2234 #endif
2235
2236 #ifndef _NO_SUGGESTIONS
2237 if (suggestions == UNSET) {
2238 if (xargs.suggestions == UNSET)
2239 suggestions = DEF_SUGGESTIONS;
2240 else
2241 suggestions = xargs.suggestions;
2242 }
2243
2244 if (!suggestion_strategy)
2245 suggestion_strategy = savestring(DEF_SUG_STRATEGY, SUG_STRATS);
2246
2247 if (suggest_filetype_color == UNSET)
2248 suggest_filetype_color = DEF_SUG_FILETYPE_COLOR;
2249 #endif
2250
2251 if (int_vars == UNSET) {
2252 if (xargs.int_vars == UNSET)
2253 int_vars = DEF_INT_VARS;
2254 else
2255 int_vars = xargs.int_vars;
2256 }
2257
2258 if (print_selfiles == UNSET) {
2259 if (xargs.printsel == UNSET)
2260 print_selfiles = DEF_PRINTSEL;
2261 else
2262 print_selfiles = xargs.printsel;
2263 }
2264
2265 if (max_printselfiles == UNSET)
2266 max_printselfiles = DEF_MAXPRINTSEL;
2267
2268 if (case_sensitive == UNSET) {
2269 if (xargs.sensitive == UNSET)
2270 case_sensitive = DEF_CASE_SENS_LIST;
2271 else
2272 case_sensitive = xargs.sensitive;
2273 }
2274
2275 if (case_sens_search == UNSET)
2276 case_sens_search = DEF_CASE_SENS_SEARCH;
2277
2278 if (case_sens_dirjump == UNSET) {
2279 if (xargs.case_sens_dirjump == UNSET)
2280 case_sens_dirjump = DEF_CASE_SENS_DIRJUMP;
2281 else
2282 case_sens_dirjump = xargs.case_sens_dirjump;
2283 }
2284
2285 if (case_sens_path_comp == UNSET) {
2286 if (xargs.case_sens_path_comp == UNSET)
2287 case_sens_path_comp = DEF_CASE_SENS_PATH_COMP;
2288 else
2289 case_sens_path_comp = xargs.case_sens_path_comp;
2290 }
2291
2292 #ifndef _NO_TRASH
2293 if (tr_as_rm == UNSET) {
2294 if (xargs.trasrm == UNSET)
2295 tr_as_rm = DEF_TRASRM;
2296 else
2297 tr_as_rm = xargs.trasrm;
2298 }
2299 #endif
2300
2301 if (xargs.stealth_mode == 1 && !opener)
2302 opener = savestring(FALLBACK_OPENER, strlen(FALLBACK_OPENER));
2303
2304 if (only_dirs == UNSET) {
2305 if (xargs.only_dirs == UNSET)
2306 only_dirs = DEF_ONLY_DIRS;
2307 else
2308 only_dirs = xargs.only_dirs;
2309 }
2310
2311 if (colorize == UNSET) {
2312 if (xargs.colorize == UNSET)
2313 colorize = DEF_COLORS;
2314 else
2315 colorize = xargs.colorize;
2316 }
2317
2318 if (expand_bookmarks == UNSET) {
2319 if (xargs.expand_bookmarks == UNSET)
2320 expand_bookmarks = DEF_EXPAND_BOOKMARKS;
2321 else
2322 expand_bookmarks = xargs.expand_bookmarks;
2323 }
2324
2325 if (splash_screen == UNSET) {
2326 if (xargs.splash == UNSET)
2327 splash_screen = DEF_SPLASH_SCREEN;
2328 else
2329 splash_screen = xargs.splash;
2330 }
2331
2332 if (welcome_message == UNSET) {
2333 if (xargs.welcome_message == UNSET)
2334 welcome_message = DEF_WELCOME_MESSAGE;
2335 else
2336 welcome_message = xargs.welcome_message;
2337 }
2338
2339 if (show_hidden == UNSET) {
2340 if (xargs.hidden == UNSET)
2341 show_hidden = DEF_SHOW_HIDDEN;
2342 else
2343 show_hidden = xargs.hidden;
2344 }
2345
2346 if (files_counter == UNSET) {
2347 if (xargs.files_counter == UNSET)
2348 files_counter = DEF_FILES_COUNTER;
2349 else
2350 files_counter = xargs.files_counter;
2351 }
2352
2353 if (long_view == UNSET) {
2354 if (xargs.longview == UNSET)
2355 long_view = DEF_LONG_VIEW;
2356 else
2357 long_view = xargs.longview;
2358 }
2359
2360 if (ext_cmd_ok == UNSET) {
2361 if (xargs.ext == UNSET)
2362 ext_cmd_ok = DEF_EXT_CMD_OK;
2363 else
2364 ext_cmd_ok = xargs.ext;
2365 }
2366
2367 if (pager == UNSET) {
2368 if (xargs.pager == UNSET)
2369 pager = DEF_PAGER;
2370 else
2371 pager = xargs.pager;
2372 }
2373
2374 if (max_dirhist == UNSET) {
2375 if (xargs.max_dirhist == UNSET)
2376 max_dirhist = DEF_MAX_DIRHIST;
2377 else
2378 max_dirhist = xargs.max_dirhist;
2379 }
2380
2381 if (clear_screen == UNSET) {
2382 if (xargs.clear_screen == UNSET)
2383 clear_screen = DEF_CLEAR_SCREEN;
2384 else
2385 clear_screen = xargs.clear_screen;
2386 }
2387
2388 if (list_folders_first == UNSET) {
2389 if (xargs.ffirst == UNSET)
2390 list_folders_first = DEF_LIST_FOLDERS_FIRST;
2391 else
2392 list_folders_first = xargs.ffirst;
2393 }
2394
2395 if (autols == UNSET) {
2396 if (xargs.autols == UNSET)
2397 autols = DEF_AUTOLS;
2398 else
2399 autols = xargs.autols;
2400 }
2401
2402 if (unicode == UNSET) {
2403 if (xargs.unicode == UNSET)
2404 unicode = DEF_UNICODE;
2405 else
2406 unicode = xargs.unicode;
2407 }
2408
2409 if (max_path == UNSET) {
2410 if (xargs.max_path == UNSET)
2411 max_path = DEF_MAX_PATH;
2412 else
2413 max_path = xargs.max_path;
2414 }
2415
2416 if (logs_enabled == UNSET) {
2417 if (xargs.logs == UNSET)
2418 logs_enabled = DEF_LOGS_ENABLED;
2419 else
2420 logs_enabled = xargs.logs;
2421 }
2422
2423 if (light_mode == UNSET) {
2424 if (xargs.light == UNSET)
2425 light_mode = DEF_LIGHT_MODE;
2426 else
2427 light_mode = xargs.light;
2428 }
2429
2430 if (classify == UNSET) {
2431 if (xargs.classify == UNSET)
2432 classify = DEF_CLASSIFY;
2433 else
2434 classify = xargs.classify;
2435 }
2436
2437 if (share_selbox == UNSET) {
2438 if (xargs.share_selbox == UNSET)
2439 share_selbox = DEF_SHARE_SELBOX;
2440 else
2441 share_selbox = xargs.share_selbox;
2442 }
2443
2444 if (sort == UNSET) {
2445 if (xargs.sort == UNSET)
2446 sort = DEF_SORT;
2447 else
2448 sort = xargs.sort;
2449 }
2450
2451 if (sort_reverse == UNSET) {
2452 if (xargs.sort_reverse == UNSET)
2453 sort_reverse = DEF_SORT_REVERSE;
2454 else
2455 sort_reverse = xargs.sort_reverse;
2456 }
2457
2458 if (tips == UNSET) {
2459 if (xargs.tips == UNSET)
2460 tips = DEF_TIPS;
2461 else
2462 tips = xargs.tips;
2463 }
2464
2465 if (autocd == UNSET) {
2466 if (xargs.autocd == UNSET)
2467 autocd = DEF_AUTOCD;
2468 else
2469 autocd = xargs.autocd;
2470 }
2471
2472 if (auto_open == UNSET) {
2473 if (xargs.auto_open == UNSET)
2474 auto_open = DEF_AUTO_OPEN;
2475 else
2476 auto_open = xargs.auto_open;
2477 }
2478
2479 if (autojump == UNSET) {
2480 if (xargs.autojump == UNSET)
2481 autojump = DEF_AUTOJUMP;
2482 else
2483 autojump = xargs.autojump;
2484 if (autojump == 1)
2485 autocd = 1;
2486 }
2487
2488 if (cd_on_quit == UNSET) {
2489 if (xargs.cd_on_quit == UNSET)
2490 cd_on_quit = DEF_CD_ON_QUIT;
2491 else
2492 cd_on_quit = xargs.cd_on_quit;
2493 }
2494
2495 if (dirhist_map == UNSET) {
2496 if (xargs.dirmap == UNSET)
2497 dirhist_map = DEF_DIRHIST_MAP;
2498 else
2499 dirhist_map = xargs.dirmap;
2500 }
2501
2502 if (disk_usage == UNSET) {
2503 if (xargs.disk_usage == UNSET)
2504 disk_usage = DEF_DISK_USAGE;
2505 else
2506 disk_usage = xargs.disk_usage;
2507 }
2508
2509 if (restore_last_path == UNSET) {
2510 if (xargs.restore_last_path == UNSET)
2511 restore_last_path = DEF_RESTORE_LAST_PATH;
2512 else
2513 restore_last_path = xargs.restore_last_path;
2514 }
2515
2516 /* if (!*div_line_char) {
2517 *div_line_char = DEF_DIV_LINE_CHAR;
2518 div_line_char[1] = '\0';
2519 } */
2520
2521 if (max_hist == UNSET)
2522 max_hist = DEF_MAX_HIST;
2523
2524 if (max_log == UNSET)
2525 max_log = DEF_MAX_LOG;
2526
2527 if (!user.shell) {
2528 struct user_t tmp_user = get_user();
2529 user.shell = tmp_user.shell;
2530
2531 /* We don't need these values of the user struct: free(d) them */
2532 free(tmp_user.name);
2533 free(tmp_user.home);
2534
2535 if (!user.shell)
2536 user.shell = savestring(FALLBACK_SHELL, strlen(FALLBACK_SHELL));
2537 }
2538
2539 if (!term)
2540 term = savestring(DEFAULT_TERM_CMD, strlen(DEFAULT_TERM_CMD));
2541
2542 if (!encoded_prompt)
2543 encoded_prompt = savestring(DEFAULT_PROMPT, strlen(DEFAULT_PROMPT));
2544
2545 /* Since in stealth mode we have no access to the config file, we
2546 * cannot use 'lira', since it relays on a file.
2547 * Set it thus to xdg-open, if not already set via command line */
2548 if (xargs.stealth_mode == 1 && !opener)
2549 opener = savestring(FALLBACK_OPENER, strlen(FALLBACK_OPENER));
2550
2551 reset_opts();
2552 }
2553